From ed75530a6331da0dfa4633c289d36eada2a15690 Mon Sep 17 00:00:00 2001 From: mothcompute Date: Tue, 30 Jan 2024 11:24:04 -0800 Subject: [PATCH] initial commit --- .gitignore | 4 + README.md | 8 + it/.DS_Store | Bin 0 -> 6148 bytes it/.hgignore | 4 + it/DEBUG.INC | 107 + it/IT.ASM | 1147 +++ it/IT.EXE | Bin 0 -> 468905 bytes it/IT.MAP | 1554 ++++ it/ITMIDI.CFG | Bin 0 -> 4896 bytes it/IT_DISK.ASM | 10940 ++++++++++++++++++++++ it/IT_DISPL.ASM | 4485 +++++++++ it/IT_D_INF.INC | 1126 +++ it/IT_D_RI.INC | 771 ++ it/IT_D_RIS.INC | 1498 +++ it/IT_D_RM.INC | 2889 ++++++ it/IT_D_WM.INC | 1785 ++++ it/IT_EMS.ASM | 973 ++ it/IT_ERR.ASM | 168 + it/IT_F.ASM | 5950 ++++++++++++ it/IT_FOUR.ASM | 612 ++ it/IT_G.ASM | 1026 +++ it/IT_H.ASM | 1552 ++++ it/IT_I.ASM | 9023 ++++++++++++++++++ it/IT_K.ASM | 1812 ++++ it/IT_L.ASM | 559 ++ it/IT_M.ASM | 664 ++ it/IT_MDATA.ASM | 3652 ++++++++ it/IT_MMTSR.ASM | 1028 +++ it/IT_MOUSE.ASM | 1412 +++ it/IT_MSG.ASM | 1031 +++ it/IT_MUSIC.ASM | 7481 +++++++++++++++ it/IT_M_EFF.INC | 2945 ++++++ it/IT_NET.ASM | 2722 ++++++ it/IT_OBJ1.ASM | 8902 ++++++++++++++++++ it/IT_PE.ASM | 12312 +++++++++++++++++++++++++ it/IT_PE_V.INC | 140 + it/IT_S.ASM | 1685 ++++ it/IT_TIMER.INC | 90 + it/IT_TUTE.ASM | 519 ++ it/IT_VESA.ASM | 226 + it/InternalDocumentation/CHANNEL.TXT | 279 + it/InternalDocumentation/CONFIG.TXT | 54 + it/InternalDocumentation/MMTECH.TXT | 143 + it/InternalDocumentation/NETWORK.TXT | 126 + it/InternalDocumentation/OBJECT.TXT | 233 + it/Keyboard/BE.ASM | 637 ++ it/Keyboard/CA.ASM | 609 ++ it/Keyboard/CH.ASM | 620 ++ it/Keyboard/DE.ASM | 616 ++ it/Keyboard/DK.ASM | 616 ++ it/Keyboard/ES.ASM | 620 ++ it/Keyboard/FI.ASM | 618 ++ it/Keyboard/FR.ASM | 613 ++ it/Keyboard/IT.ASM | 588 ++ it/Keyboard/KEYBOARD.TXT | 12 + it/Keyboard/NO.ASM | 614 ++ it/Keyboard/PO.ASM | 610 ++ it/Keyboard/SE.ASM | 612 ++ it/Keyboard/UK.ASM | 596 ++ it/Keyboard/US.ASM | 598 ++ it/LICENSE.TXT | 25 + it/MAKEFILE.MAK | 9 + it/NETWORK.INC | 32 + it/Network/DEBUG.INC | 130 + it/Network/DRHEAD.INC | 19 + it/Network/EXECOM.COM | Bin 0 -> 1248 bytes it/Network/IPX.ASM | 3583 +++++++ it/Network/MIPX.BAT | 5 + it/Network/NETDRIVE.ASM | 47 + it/Network/REQPROC.INC | 32 + it/Network/USERNAME.INC | 6 + it/Network/VTABLE.INC | 10 + it/PE_TRANS.INC | 1703 ++++ it/README.md | 138 + it/ReleaseDocumentation/BUGS.TXT | 39 + it/ReleaseDocumentation/CONTRIB.TXT | 595 ++ it/ReleaseDocumentation/DRIVERS.TXT | 577 ++ it/ReleaseDocumentation/FILES.TXT | 33 + it/ReleaseDocumentation/FILE_ID.DIZ | 12 + it/ReleaseDocumentation/FILTERS.TXT | 143 + it/ReleaseDocumentation/HINTS.TXT | 572 ++ it/ReleaseDocumentation/IMPULSE.FAQ | 261 + it/ReleaseDocumentation/IT.TXT | 2199 +++++ it/ReleaseDocumentation/IT256.ICO | Bin 0 -> 2998 bytes it/ReleaseDocumentation/ITTECH.TXT | 901 ++ it/ReleaseDocumentation/ITVSOUND.TXT | 70 + it/ReleaseDocumentation/MIDI.TXT | 400 + it/ReleaseDocumentation/NETWORK.TXT | 71 + it/ReleaseDocumentation/README.TXT | 72 + it/ReleaseDocumentation/SUMMARY.TXT | 296 + it/ReleaseDocumentation/UPDATE.TXT | 592 ++ it/SWITCH.INC | 44 + it/SoundDrivers/AD1816.ASM | 2116 +++++ it/SoundDrivers/AMD3DI.MIX | 56 + it/SoundDrivers/AMD3DNI.MIX | 304 + it/SoundDrivers/AWE32B.ASM | 4310 +++++++++ it/SoundDrivers/AWE32DRV.ASM | 3961 ++++++++ it/SoundDrivers/BASE1.ASM | 2070 +++++ it/SoundDrivers/DEBUG.INC | 101 + it/SoundDrivers/DMA.INC | 113 + it/SoundDrivers/DMANAI.INC | 113 + it/SoundDrivers/DMASIRQ.INC | 116 + it/SoundDrivers/DRHEAD.INC | 8 + it/SoundDrivers/ENVIVO.ASM | 2300 +++++ it/SoundDrivers/EQUALIZE.INC | 161 + it/SoundDrivers/ES1688.ASM | 2265 +++++ it/SoundDrivers/ES1688MX.ASM | 1751 ++++ it/SoundDrivers/ES1868.ASM | 2328 +++++ it/SoundDrivers/ES1868MX.ASM | 1734 ++++ it/SoundDrivers/ES1869.ASM | 2328 +++++ it/SoundDrivers/ES1869MX.ASM | 1734 ++++ it/SoundDrivers/EWS64.ASM | 933 ++ it/SoundDrivers/EWSCODEC.ASM | 3016 ++++++ it/SoundDrivers/EWSCODMX.ASM | 2531 +++++ it/SoundDrivers/EXECOM.COM | Bin 0 -> 1248 bytes it/SoundDrivers/FOURIER.INC | 83 + it/SoundDrivers/FREQ.INC | 34 + it/SoundDrivers/GOLD16.ASM | 2328 +++++ it/SoundDrivers/GUS.INC | 2316 +++++ it/SoundDrivers/GUSDRV.ASM | 5 + it/SoundDrivers/GUSDRV2.ASM | 3 + it/SoundDrivers/GUSHIQ2.ASM | 5 + it/SoundDrivers/GUSHIQDR.ASM | 4 + it/SoundDrivers/GUSMAX.ASM | 2091 +++++ it/SoundDrivers/GUSMAXMX.ASM | 1589 ++++ it/SoundDrivers/GUSMIXDR.ASM | 2462 +++++ it/SoundDrivers/GUSNRAMP.INC | 27 + it/SoundDrivers/GUSNRIC.INC | 415 + it/SoundDrivers/GUSPNPM.ASM | 2270 +++++ it/SoundDrivers/GUSPNPMX.ASM | 1769 ++++ it/SoundDrivers/GUSRAMP.INC | 114 + it/SoundDrivers/GUSRIC.INC | 651 ++ it/SoundDrivers/IRQ.INC | 20 + it/SoundDrivers/IWCODEC.ASM | 2302 +++++ it/SoundDrivers/IWDRV.ASM | 2713 ++++++ it/SoundDrivers/IWDRV.MAP | 9 + it/SoundDrivers/K6MSAM.INC | 388 + it/SoundDrivers/K6TRANS.INC | 119 + it/SoundDrivers/LOADSAM.INC | 71 + it/SoundDrivers/LPT1DRV.ASM | 904 ++ it/SoundDrivers/LPT2DRV.ASM | 904 ++ it/SoundDrivers/M12BIT.INC | 49 + it/SoundDrivers/M12BIT.MIX | 813 ++ it/SoundDrivers/M12BITF.INC | 49 + it/SoundDrivers/M12BITF.MIX | 807 ++ it/SoundDrivers/M12BITI.INC | 49 + it/SoundDrivers/M12BITI.MIX | 866 ++ it/SoundDrivers/M12BITST.MIX | 832 ++ it/SoundDrivers/M16.ASM | 2275 +++++ it/SoundDrivers/M16.BAT | 5 + it/SoundDrivers/M32.ASM | 2271 +++++ it/SoundDrivers/M32.BAT | 5 + it/SoundDrivers/M32BIT.INC | 49 + it/SoundDrivers/M32BIT.MIX | 803 ++ it/SoundDrivers/M32BITFF.MIX | 6 + it/SoundDrivers/M32BITI.INC | 49 + it/SoundDrivers/M32BITI.MIX | 818 ++ it/SoundDrivers/M32BITM.INC | 11 + it/SoundDrivers/M32BITM.MIX | 502 + it/SoundDrivers/M32BITMF.INC | 12 + it/SoundDrivers/M32BITMF.MIX | 708 ++ it/SoundDrivers/M32BITMI.INC | 11 + it/SoundDrivers/M32BITMI.MIX | 686 ++ it/SoundDrivers/M32BITMV.INC | 12 + it/SoundDrivers/M32BITMV.MIX | 798 ++ it/SoundDrivers/M32ULTRA.INC | 49 + it/SoundDrivers/M32ULTRA.MIX | 770 ++ it/SoundDrivers/MAD.BAT | 5 + it/SoundDrivers/MAWE.BAT | 4 + it/SoundDrivers/MAWEB.BAT | 4 + it/SoundDrivers/MB.BAT | 6 + it/SoundDrivers/MES.BAT | 5 + it/SoundDrivers/MES1688.BAT | 5 + it/SoundDrivers/MES1688M.BAT | 5 + it/SoundDrivers/MES1788.BAT | 5 + it/SoundDrivers/MES1869.BAT | 5 + it/SoundDrivers/MES1869M.BAT | 5 + it/SoundDrivers/MESM.BAT | 5 + it/SoundDrivers/MEWS.BAT | 4 + it/SoundDrivers/MEWSC.BAT | 5 + it/SoundDrivers/MEWSCM.BAT | 5 + it/SoundDrivers/MG16.BAT | 5 + it/SoundDrivers/MGP.BAT | 4 + it/SoundDrivers/MGPM.BAT | 4 + it/SoundDrivers/MGUS.BAT | 4 + it/SoundDrivers/MGUS2.BAT | 4 + it/SoundDrivers/MGUSLO.BAT | 4 + it/SoundDrivers/MGUSMAX.BAT | 5 + it/SoundDrivers/MGUSMAXM.BAT | 5 + it/SoundDrivers/MGUSMIX.BAT | 4 + it/SoundDrivers/MIDDRV.ASM | 865 ++ it/SoundDrivers/MIDDRV2.ASM | 828 ++ it/SoundDrivers/MIDIDRV.ASM | 525 ++ it/SoundDrivers/MIW.BAT | 4 + it/SoundDrivers/MIX.INC | 1014 ++ it/SoundDrivers/MIXWAV.INC | 1065 +++ it/SoundDrivers/MLPT1.BAT | 4 + it/SoundDrivers/MLPT2.BAT | 4 + it/SoundDrivers/MMID.BAT | 4 + it/SoundDrivers/MMIDI.BAT | 4 + it/SoundDrivers/MMX.INC | 306 + it/SoundDrivers/MMXMSAM.INC | 388 + it/SoundDrivers/MMXTRANS.INC | 116 + it/SoundDrivers/MNOMIX.INC | 9 + it/SoundDrivers/MONO12B.INC | 17 + it/SoundDrivers/MONO12B.MIX | 188 + it/SoundDrivers/MONO12BI.INC | 17 + it/SoundDrivers/MONO12BI.MIX | 242 + it/SoundDrivers/MPAS.BAT | 4 + it/SoundDrivers/MPAS16.BAT | 4 + it/SoundDrivers/MPC.BAT | 4 + it/SoundDrivers/MSAM.BAT | 5 + it/SoundDrivers/MSB.BAT | 4 + it/SoundDrivers/MSB16.BAT | 5 + it/SoundDrivers/MSB16A.BAT | 5 + it/SoundDrivers/MSB16B.BAT | 4 + it/SoundDrivers/MSB16C.BAT | 4 + it/SoundDrivers/MSB16D.BAT | 4 + it/SoundDrivers/MSB16M.BAT | 5 + it/SoundDrivers/MSB16MB.BAT | 5 + it/SoundDrivers/MSB2.BAT | 4 + it/SoundDrivers/MSBPRO.BAT | 4 + it/SoundDrivers/MST97.BAT | 4 + it/SoundDrivers/MSTC.BAT | 5 + it/SoundDrivers/MSTCM.BAT | 4 + it/SoundDrivers/MSTP.BAT | 5 + it/SoundDrivers/MT.BAT | 5 + it/SoundDrivers/MV.BAT | 5 + it/SoundDrivers/MVIVO.BAT | 5 + it/SoundDrivers/MVM.BAT | 5 + it/SoundDrivers/MWAV.BAT | 4 + it/SoundDrivers/MWSS.BAT | 5 + it/SoundDrivers/MWSS2.BAT | 5 + it/SoundDrivers/NODEBUG.INC | 7 + it/SoundDrivers/NOISE.ASM | 2091 +++++ it/SoundDrivers/PAS16DRV.ASM | 1986 ++++ it/SoundDrivers/PASDRV.ASM | 1903 ++++ it/SoundDrivers/PCSPKDRV.ASM | 934 ++ it/SoundDrivers/PNP.INC | 224 + it/SoundDrivers/Q.INC | 34 + it/SoundDrivers/REQPROC.INC | 31 + it/SoundDrivers/SAM9407.ASM | 1008 ++ it/SoundDrivers/SB16B.ASM | 2001 ++++ it/SoundDrivers/SB16C.ASM | 1695 ++++ it/SoundDrivers/SB16D.ASM | 2665 ++++++ it/SoundDrivers/SB16DRV.ASM | 2672 ++++++ it/SoundDrivers/SB16DRV.MAP | 9 + it/SoundDrivers/SB16K6.ASM | 2287 +++++ it/SoundDrivers/SB16MMX.ASM | 2272 +++++ it/SoundDrivers/SB16MMXB.ASM | 2265 +++++ it/SoundDrivers/SB2DRV.ASM | 1421 +++ it/SoundDrivers/SBDRV.ASM | 1416 +++ it/SoundDrivers/SBMIDI.INC | 133 + it/SoundDrivers/SBPRODRV.ASM | 2009 ++++ it/SoundDrivers/SNDDRV.ASM | 283 + it/SoundDrivers/ST97.ASM | 866 ++ it/SoundDrivers/ST97CMMX.ASM | 2773 ++++++ it/SoundDrivers/ST97CODE.ASM | 3171 +++++++ it/SoundDrivers/ST97PNP.ASM | 2623 ++++++ it/SoundDrivers/TEST.ASM | 306 + it/SoundDrivers/VSND.ASM | 1281 +++ it/SoundDrivers/VSNDMMX.ASM | 1097 +++ it/SoundDrivers/VTABLE.INC | 11 + it/SoundDrivers/WAV.MIX | 1608 ++++ it/SoundDrivers/WAVDRV.ASM | 1601 ++++ it/SoundDrivers/WAVPRO.ASM | 853 ++ it/SoundDrivers/WSSDRV.ASM | 2175 +++++ it/SoundDrivers/WSSDRV2.ASM | 2268 +++++ it/Tutorial/IT_TUTORIAL.EXE | Bin 0 -> 95898 bytes it/Tutorial/TUTE.IT | Bin 0 -> 75997 bytes it/USERNAME.INC | 1 + it/VSound/Server/SERVER.C | 511 + it/VSound/VXD/DEBUG.INC | 1156 +++ it/VSound/VXD/MVSOUND.BAT | 3 + it/VSound/VXD/SHELL.INC | 139 + it/VSound/VXD/VMM.INC | 4074 ++++++++ it/VSound/VXD/VSOUND.ASM | 679 ++ it/VSound/VXD/VSOUND.DEF | 38 + it/WAVSWITC.INC | 22 + it/sch.it | Bin 0 -> 46472 bytes it/source.lst | 1 + mzload.c | 63 + r.bat | 1 + tasm/32RTM.EXE | Bin 0 -> 152108 bytes tasm/DPMI16BI.OVL | Bin 0 -> 50576 bytes tasm/DPMI32VM.OVL | Bin 0 -> 58376 bytes tasm/MAKE.EXE | Bin 0 -> 86016 bytes tasm/RTM.EXE | Bin 0 -> 120853 bytes tasm/TASM.EXE | Bin 0 -> 136018 bytes tasm/TLINK.EXE | Bin 0 -> 53414 bytes vm.c | 100 + 291 files changed, 248669 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 it/.DS_Store create mode 100644 it/.hgignore create mode 100644 it/DEBUG.INC create mode 100644 it/IT.ASM create mode 100644 it/IT.EXE create mode 100644 it/IT.MAP create mode 100644 it/ITMIDI.CFG create mode 100644 it/IT_DISK.ASM create mode 100644 it/IT_DISPL.ASM create mode 100644 it/IT_D_INF.INC create mode 100644 it/IT_D_RI.INC create mode 100644 it/IT_D_RIS.INC create mode 100644 it/IT_D_RM.INC create mode 100644 it/IT_D_WM.INC create mode 100644 it/IT_EMS.ASM create mode 100644 it/IT_ERR.ASM create mode 100644 it/IT_F.ASM create mode 100644 it/IT_FOUR.ASM create mode 100644 it/IT_G.ASM create mode 100644 it/IT_H.ASM create mode 100644 it/IT_I.ASM create mode 100644 it/IT_K.ASM create mode 100644 it/IT_L.ASM create mode 100644 it/IT_M.ASM create mode 100644 it/IT_MDATA.ASM create mode 100644 it/IT_MMTSR.ASM create mode 100644 it/IT_MOUSE.ASM create mode 100644 it/IT_MSG.ASM create mode 100644 it/IT_MUSIC.ASM create mode 100644 it/IT_M_EFF.INC create mode 100644 it/IT_NET.ASM create mode 100644 it/IT_OBJ1.ASM create mode 100644 it/IT_PE.ASM create mode 100644 it/IT_PE_V.INC create mode 100644 it/IT_S.ASM create mode 100644 it/IT_TIMER.INC create mode 100644 it/IT_TUTE.ASM create mode 100644 it/IT_VESA.ASM create mode 100644 it/InternalDocumentation/CHANNEL.TXT create mode 100644 it/InternalDocumentation/CONFIG.TXT create mode 100644 it/InternalDocumentation/MMTECH.TXT create mode 100644 it/InternalDocumentation/NETWORK.TXT create mode 100644 it/InternalDocumentation/OBJECT.TXT create mode 100644 it/Keyboard/BE.ASM create mode 100644 it/Keyboard/CA.ASM create mode 100644 it/Keyboard/CH.ASM create mode 100644 it/Keyboard/DE.ASM create mode 100644 it/Keyboard/DK.ASM create mode 100644 it/Keyboard/ES.ASM create mode 100644 it/Keyboard/FI.ASM create mode 100644 it/Keyboard/FR.ASM create mode 100644 it/Keyboard/IT.ASM create mode 100644 it/Keyboard/KEYBOARD.TXT create mode 100644 it/Keyboard/NO.ASM create mode 100644 it/Keyboard/PO.ASM create mode 100644 it/Keyboard/SE.ASM create mode 100644 it/Keyboard/UK.ASM create mode 100644 it/Keyboard/US.ASM create mode 100644 it/LICENSE.TXT create mode 100644 it/MAKEFILE.MAK create mode 100644 it/NETWORK.INC create mode 100644 it/Network/DEBUG.INC create mode 100644 it/Network/DRHEAD.INC create mode 100755 it/Network/EXECOM.COM create mode 100644 it/Network/IPX.ASM create mode 100755 it/Network/MIPX.BAT create mode 100644 it/Network/NETDRIVE.ASM create mode 100644 it/Network/REQPROC.INC create mode 100644 it/Network/USERNAME.INC create mode 100644 it/Network/VTABLE.INC create mode 100644 it/PE_TRANS.INC create mode 100644 it/README.md create mode 100644 it/ReleaseDocumentation/BUGS.TXT create mode 100644 it/ReleaseDocumentation/CONTRIB.TXT create mode 100644 it/ReleaseDocumentation/DRIVERS.TXT create mode 100644 it/ReleaseDocumentation/FILES.TXT create mode 100644 it/ReleaseDocumentation/FILE_ID.DIZ create mode 100644 it/ReleaseDocumentation/FILTERS.TXT create mode 100644 it/ReleaseDocumentation/HINTS.TXT create mode 100644 it/ReleaseDocumentation/IMPULSE.FAQ create mode 100644 it/ReleaseDocumentation/IT.TXT create mode 100644 it/ReleaseDocumentation/IT256.ICO create mode 100644 it/ReleaseDocumentation/ITTECH.TXT create mode 100644 it/ReleaseDocumentation/ITVSOUND.TXT create mode 100644 it/ReleaseDocumentation/MIDI.TXT create mode 100644 it/ReleaseDocumentation/NETWORK.TXT create mode 100644 it/ReleaseDocumentation/README.TXT create mode 100644 it/ReleaseDocumentation/SUMMARY.TXT create mode 100644 it/ReleaseDocumentation/UPDATE.TXT create mode 100644 it/SWITCH.INC create mode 100755 it/SoundDrivers/AD1816.ASM create mode 100755 it/SoundDrivers/AMD3DI.MIX create mode 100755 it/SoundDrivers/AMD3DNI.MIX create mode 100755 it/SoundDrivers/AWE32B.ASM create mode 100755 it/SoundDrivers/AWE32DRV.ASM create mode 100755 it/SoundDrivers/BASE1.ASM create mode 100755 it/SoundDrivers/DEBUG.INC create mode 100755 it/SoundDrivers/DMA.INC create mode 100755 it/SoundDrivers/DMANAI.INC create mode 100755 it/SoundDrivers/DMASIRQ.INC create mode 100755 it/SoundDrivers/DRHEAD.INC create mode 100755 it/SoundDrivers/ENVIVO.ASM create mode 100755 it/SoundDrivers/EQUALIZE.INC create mode 100755 it/SoundDrivers/ES1688.ASM create mode 100755 it/SoundDrivers/ES1688MX.ASM create mode 100755 it/SoundDrivers/ES1868.ASM create mode 100755 it/SoundDrivers/ES1868MX.ASM create mode 100755 it/SoundDrivers/ES1869.ASM create mode 100755 it/SoundDrivers/ES1869MX.ASM create mode 100755 it/SoundDrivers/EWS64.ASM create mode 100755 it/SoundDrivers/EWSCODEC.ASM create mode 100755 it/SoundDrivers/EWSCODMX.ASM create mode 100755 it/SoundDrivers/EXECOM.COM create mode 100755 it/SoundDrivers/FOURIER.INC create mode 100755 it/SoundDrivers/FREQ.INC create mode 100755 it/SoundDrivers/GOLD16.ASM create mode 100755 it/SoundDrivers/GUS.INC create mode 100755 it/SoundDrivers/GUSDRV.ASM create mode 100755 it/SoundDrivers/GUSDRV2.ASM create mode 100755 it/SoundDrivers/GUSHIQ2.ASM create mode 100755 it/SoundDrivers/GUSHIQDR.ASM create mode 100755 it/SoundDrivers/GUSMAX.ASM create mode 100755 it/SoundDrivers/GUSMAXMX.ASM create mode 100755 it/SoundDrivers/GUSMIXDR.ASM create mode 100755 it/SoundDrivers/GUSNRAMP.INC create mode 100755 it/SoundDrivers/GUSNRIC.INC create mode 100755 it/SoundDrivers/GUSPNPM.ASM create mode 100755 it/SoundDrivers/GUSPNPMX.ASM create mode 100755 it/SoundDrivers/GUSRAMP.INC create mode 100755 it/SoundDrivers/GUSRIC.INC create mode 100755 it/SoundDrivers/IRQ.INC create mode 100755 it/SoundDrivers/IWCODEC.ASM create mode 100755 it/SoundDrivers/IWDRV.ASM create mode 100644 it/SoundDrivers/IWDRV.MAP create mode 100755 it/SoundDrivers/K6MSAM.INC create mode 100755 it/SoundDrivers/K6TRANS.INC create mode 100755 it/SoundDrivers/LOADSAM.INC create mode 100755 it/SoundDrivers/LPT1DRV.ASM create mode 100755 it/SoundDrivers/LPT2DRV.ASM create mode 100755 it/SoundDrivers/M12BIT.INC create mode 100755 it/SoundDrivers/M12BIT.MIX create mode 100755 it/SoundDrivers/M12BITF.INC create mode 100755 it/SoundDrivers/M12BITF.MIX create mode 100755 it/SoundDrivers/M12BITI.INC create mode 100755 it/SoundDrivers/M12BITI.MIX create mode 100755 it/SoundDrivers/M12BITST.MIX create mode 100755 it/SoundDrivers/M16.ASM create mode 100755 it/SoundDrivers/M16.BAT create mode 100755 it/SoundDrivers/M32.ASM create mode 100755 it/SoundDrivers/M32.BAT create mode 100755 it/SoundDrivers/M32BIT.INC create mode 100755 it/SoundDrivers/M32BIT.MIX create mode 100755 it/SoundDrivers/M32BITFF.MIX create mode 100755 it/SoundDrivers/M32BITI.INC create mode 100755 it/SoundDrivers/M32BITI.MIX create mode 100755 it/SoundDrivers/M32BITM.INC create mode 100755 it/SoundDrivers/M32BITM.MIX create mode 100755 it/SoundDrivers/M32BITMF.INC create mode 100755 it/SoundDrivers/M32BITMF.MIX create mode 100755 it/SoundDrivers/M32BITMI.INC create mode 100755 it/SoundDrivers/M32BITMI.MIX create mode 100755 it/SoundDrivers/M32BITMV.INC create mode 100755 it/SoundDrivers/M32BITMV.MIX create mode 100755 it/SoundDrivers/M32ULTRA.INC create mode 100755 it/SoundDrivers/M32ULTRA.MIX create mode 100755 it/SoundDrivers/MAD.BAT create mode 100755 it/SoundDrivers/MAWE.BAT create mode 100755 it/SoundDrivers/MAWEB.BAT create mode 100755 it/SoundDrivers/MB.BAT create mode 100755 it/SoundDrivers/MES.BAT create mode 100755 it/SoundDrivers/MES1688.BAT create mode 100755 it/SoundDrivers/MES1688M.BAT create mode 100755 it/SoundDrivers/MES1788.BAT create mode 100755 it/SoundDrivers/MES1869.BAT create mode 100755 it/SoundDrivers/MES1869M.BAT create mode 100755 it/SoundDrivers/MESM.BAT create mode 100755 it/SoundDrivers/MEWS.BAT create mode 100755 it/SoundDrivers/MEWSC.BAT create mode 100755 it/SoundDrivers/MEWSCM.BAT create mode 100755 it/SoundDrivers/MG16.BAT create mode 100755 it/SoundDrivers/MGP.BAT create mode 100755 it/SoundDrivers/MGPM.BAT create mode 100755 it/SoundDrivers/MGUS.BAT create mode 100755 it/SoundDrivers/MGUS2.BAT create mode 100755 it/SoundDrivers/MGUSLO.BAT create mode 100755 it/SoundDrivers/MGUSMAX.BAT create mode 100755 it/SoundDrivers/MGUSMAXM.BAT create mode 100755 it/SoundDrivers/MGUSMIX.BAT create mode 100755 it/SoundDrivers/MIDDRV.ASM create mode 100755 it/SoundDrivers/MIDDRV2.ASM create mode 100755 it/SoundDrivers/MIDIDRV.ASM create mode 100755 it/SoundDrivers/MIW.BAT create mode 100755 it/SoundDrivers/MIX.INC create mode 100755 it/SoundDrivers/MIXWAV.INC create mode 100755 it/SoundDrivers/MLPT1.BAT create mode 100755 it/SoundDrivers/MLPT2.BAT create mode 100755 it/SoundDrivers/MMID.BAT create mode 100755 it/SoundDrivers/MMIDI.BAT create mode 100755 it/SoundDrivers/MMX.INC create mode 100755 it/SoundDrivers/MMXMSAM.INC create mode 100755 it/SoundDrivers/MMXTRANS.INC create mode 100755 it/SoundDrivers/MNOMIX.INC create mode 100755 it/SoundDrivers/MONO12B.INC create mode 100755 it/SoundDrivers/MONO12B.MIX create mode 100755 it/SoundDrivers/MONO12BI.INC create mode 100755 it/SoundDrivers/MONO12BI.MIX create mode 100755 it/SoundDrivers/MPAS.BAT create mode 100755 it/SoundDrivers/MPAS16.BAT create mode 100755 it/SoundDrivers/MPC.BAT create mode 100755 it/SoundDrivers/MSAM.BAT create mode 100755 it/SoundDrivers/MSB.BAT create mode 100755 it/SoundDrivers/MSB16.BAT create mode 100755 it/SoundDrivers/MSB16A.BAT create mode 100755 it/SoundDrivers/MSB16B.BAT create mode 100755 it/SoundDrivers/MSB16C.BAT create mode 100755 it/SoundDrivers/MSB16D.BAT create mode 100755 it/SoundDrivers/MSB16M.BAT create mode 100755 it/SoundDrivers/MSB16MB.BAT create mode 100755 it/SoundDrivers/MSB2.BAT create mode 100755 it/SoundDrivers/MSBPRO.BAT create mode 100755 it/SoundDrivers/MST97.BAT create mode 100755 it/SoundDrivers/MSTC.BAT create mode 100755 it/SoundDrivers/MSTCM.BAT create mode 100755 it/SoundDrivers/MSTP.BAT create mode 100755 it/SoundDrivers/MT.BAT create mode 100755 it/SoundDrivers/MV.BAT create mode 100755 it/SoundDrivers/MVIVO.BAT create mode 100755 it/SoundDrivers/MVM.BAT create mode 100755 it/SoundDrivers/MWAV.BAT create mode 100755 it/SoundDrivers/MWSS.BAT create mode 100755 it/SoundDrivers/MWSS2.BAT create mode 100755 it/SoundDrivers/NODEBUG.INC create mode 100755 it/SoundDrivers/NOISE.ASM create mode 100755 it/SoundDrivers/PAS16DRV.ASM create mode 100755 it/SoundDrivers/PASDRV.ASM create mode 100755 it/SoundDrivers/PCSPKDRV.ASM create mode 100755 it/SoundDrivers/PNP.INC create mode 100755 it/SoundDrivers/Q.INC create mode 100755 it/SoundDrivers/REQPROC.INC create mode 100755 it/SoundDrivers/SAM9407.ASM create mode 100755 it/SoundDrivers/SB16B.ASM create mode 100755 it/SoundDrivers/SB16C.ASM create mode 100755 it/SoundDrivers/SB16D.ASM create mode 100755 it/SoundDrivers/SB16DRV.ASM create mode 100644 it/SoundDrivers/SB16DRV.MAP create mode 100755 it/SoundDrivers/SB16K6.ASM create mode 100755 it/SoundDrivers/SB16MMX.ASM create mode 100755 it/SoundDrivers/SB16MMXB.ASM create mode 100755 it/SoundDrivers/SB2DRV.ASM create mode 100755 it/SoundDrivers/SBDRV.ASM create mode 100755 it/SoundDrivers/SBMIDI.INC create mode 100755 it/SoundDrivers/SBPRODRV.ASM create mode 100755 it/SoundDrivers/SNDDRV.ASM create mode 100755 it/SoundDrivers/ST97.ASM create mode 100755 it/SoundDrivers/ST97CMMX.ASM create mode 100755 it/SoundDrivers/ST97CODE.ASM create mode 100755 it/SoundDrivers/ST97PNP.ASM create mode 100755 it/SoundDrivers/TEST.ASM create mode 100755 it/SoundDrivers/VSND.ASM create mode 100755 it/SoundDrivers/VSNDMMX.ASM create mode 100755 it/SoundDrivers/VTABLE.INC create mode 100755 it/SoundDrivers/WAV.MIX create mode 100755 it/SoundDrivers/WAVDRV.ASM create mode 100755 it/SoundDrivers/WAVPRO.ASM create mode 100755 it/SoundDrivers/WSSDRV.ASM create mode 100755 it/SoundDrivers/WSSDRV2.ASM create mode 100644 it/Tutorial/IT_TUTORIAL.EXE create mode 100644 it/Tutorial/TUTE.IT create mode 100644 it/USERNAME.INC create mode 100644 it/VSound/Server/SERVER.C create mode 100644 it/VSound/VXD/DEBUG.INC create mode 100644 it/VSound/VXD/MVSOUND.BAT create mode 100644 it/VSound/VXD/SHELL.INC create mode 100644 it/VSound/VXD/VMM.INC create mode 100644 it/VSound/VXD/VSOUND.ASM create mode 100644 it/VSound/VXD/VSOUND.DEF create mode 100644 it/WAVSWITC.INC create mode 100644 it/sch.it create mode 100644 it/source.lst create mode 100644 mzload.c create mode 100644 r.bat create mode 100644 tasm/32RTM.EXE create mode 100644 tasm/DPMI16BI.OVL create mode 100644 tasm/DPMI32VM.OVL create mode 100644 tasm/MAKE.EXE create mode 100644 tasm/RTM.EXE create mode 100644 tasm/TASM.EXE create mode 100644 tasm/TLINK.EXE create mode 100644 vm.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ccbf44 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +it/*.OBJ +it/*.DRV +it/*/*.OBJ +it/*/*.DRV diff --git a/README.md b/README.md new file mode 100644 index 0000000..bb3083d --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# dos porting vm + +### le contenu + +- `*.c` - main source +- `r.bat` - configures dosbox path for building impulse tracker +- `it` - impulse tracker source. bsd license, cloned from https://github.com/herrnst/impulsetracker +- `tasm` - assembler required to build impulse tracker diff --git a/it/.DS_Store b/it/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..185c51196128fc84b9c6c2eee5862fc17e2fefd0 GIT binary patch literal 6148 zcmeHK&1%~~5T141R8C4zX$yf|_FC{ECN)WKs_PyL29<=;6h}g$UJzO%$u`9pbSv~R z`u`rKeTP0uZ<*O$hXgm*#)KJ|{bpxpcBOB{jurq!Z<2HXd;suJ2^%eJ{vk9@x*`qd zArxkg1o}{bf+?gc(d<}9259f@K?oWqki+HuE1-;L@fB%nYY&7p| z-t}5rC_7vJ{hhbrNYBD5swQPGD&Cl$O48WbgQyxU?N?f77j_gMt8_N>A3oQ46{$Qe zE~TEHs65fLo}T1Mc^caJPE=BjhW?{Lkxnsn5asEyDpjm9RlRSac&(woJD+zCyKUL& zK3TNo{OF+5mPZFq7YqM`=j}c2K709ky!iO(^OvvRzW@07%kGN657@{9hfDa4#;W`G%B2G*DXcVv0nYy6D-Xv_dJa5D_h`5;jV1BbOmb97)szmGKD zBqTwb?h=I3Vc@W~h$AS%rXt!@;jS3MrlViFxWHj;(WZkiE8{$FW#Mip!mN&dX~IDS z7P(~xn1QPdY}l?(_5a27_y4O&++zlqfm_9ZX!gT?4`0dE)|Ho|S}Re{P)R7Rws?_( jhAG7uOQm=h)d>0}8Hj" +; + +IF TRACEENABLED + +IF CREATENEWLOGFILE +FirstTime DB 0 +ENDIF + +LogFileName DB "Logfile.Txt", 0 + +; + +Proc WriteDebugFile + + PushA + Push DS + + Push CS + Pop DS + + Push CX + Mov DX, Offset LogFileName + +IF CREATENEWLOGFILE + + Cmp DS:FirstTime, 0 + JNE WriteDebugFile1 + + Mov AH, 3Ch + Xor CX, CX + Int 21h + JC WriteDebugFileEnd + + Mov DS:FirstTime, 1 + XChg AX, BX + Jmp WriteDebugFile2 + + WriteDebugFile1: + +ENDIF + Mov AX, 3D02h + Int 21h + JC WriteDebugFileEnd + + XChg AX, BX + + Mov AX, 4202h + Xor CX, CX + Xor DX, DX + Int 21h ; Move to end of file + +WriteDebugFile2: + Mov AH, 40h + Pop CX + Push CX + Mov DX, SI + Int 21h + + Mov AH, 3Eh + Int 21h + +WriteDebugFileEnd: + Pop CX + Pop DS + PopA + Ret + +EndP WriteDebugFile + +; + +Trace Macro LogMessage + Local X, Y + + PushF + Push CX + Push SI + Jmp Y + X: + DB LogMessage + DB 0Dh, 0Ah + Y: + Mov CX, Offset Y - Offset X + Mov SI, Offset X + Call WriteDebugFile + + Pop SI + Pop CX + PopF + + EndM + +; + +ELSE + +; + +Trace Macro LogMessage + EndM + +; + +ENDIF + diff --git a/it/IT.ASM b/it/IT.ASM new file mode 100644 index 0000000..e97cc5e --- /dev/null +++ b/it/IT.ASM @@ -0,0 +1,1147 @@ +;Ŀ +; Startup Module +; + + Jumps + .386P + +include switch.inc + +;Ŀ +; Externals +; + +Segment Object1 BYTE Public 'Data' + Extrn HelpKeyValue:Word, OrderKeyValue:Word +EndS + +Segment InfoLine BYTE Public 'Code' USE16 + Extrn ShowUsageTime:Byte +EndS + +Segment Disk BYTE Public 'Code' USE16 + Extrn DiskOptions:Byte +EndS + +Segment Screen BYTE Public 'Code' + Extrn CharacterGenerationOffset:Word + Extrn VGAFlags:Byte +EndS + +Segment Mouse BYTE Public 'Code' + Extrn MouseCharacterGenerationOffset:Word +EndS + +Segment Main DWORD Public 'Code' USE16 + Extrn ReleaseTimeSlice:Byte +EndS + + Extrn D_InitDisk:Far + Extrn D_UnInitDisk:Far + Extrn D_DisableFileColours:Far + + Extrn E_InitEMS:Far + Extrn E_UnInitEMS:Far + + Extrn Error_InitHandler:Far + Extrn Error_UnInitHandler:Far + + Extrn K_InitKeyBoard:Far + Extrn K_UnInitKeyBoard:Far + Extrn K_InstallKeyboardType:Far + Extrn K_RemoveKeyboardType:Far + + Extrn K_InstallDOSHandler:Far + Extrn K_UnInstallDOSHandler:Far + Extrn K_SwapKeyBoard:Far + + Extrn O1_AutoDetectList:Far + Extrn O1_ConfirmQuit:Far + Extrn O1_PatternEditList:Far + Extrn O1_CrashRecovery:Far + Extrn O1_KeyboardList:Far + + Extrn M_Object1List:Far + + Extrn S_InitScreen:Far + Extrn S_ClearScreen:Far + Extrn S_UnInitScreen:Far + Extrn S_SetDirectMode:Far + Extrn S_DrawString:Far + + Extrn Music_InitMusic:Far + Extrn Music_UnInitMusic:Far + + Extrn Music_SetLimit:Far + Extrn Music_SetSoundCard:Far + Extrn Music_SetDMA:Far + Extrn Music_SetIRQ:Far + Extrn Music_SetMixSpeed:Far + Extrn Music_SetAddress:Far + Extrn Music_ReverseChannels:Far + Extrn Music_PatternStorage:Far + Extrn Music_SetSoundCardDriver:Far + Extrn Music_Stop:Far + Extrn Music_AutoDetectSoundCard:Far + +IF NETWORKENABLED + Extrn Network_Shutdown:Far +ENDIF + + Extrn PE_InitPatternEdit:Far + Extrn PE_UnInitPatternEdit:Far + Extrn PECheckModified:Far + + Extrn D_RestorePreShellDirectory:Far + Extrn D_GetPreShellDirectory:Far + + Extrn MMTSR_InstallMMTSR:Far + Extrn MMTSR_UninstallMMTSR:Far + + Extrn InitMouse:Far, UnInitMouse:Far + Extrn CmdLineDisableMouse:Far + + Extrn InitTimerHandler:Far, UnInitTimerHandler:Far + +; + + Global Quit:Far, Refresh:Far + Global DOSShell:Far, GetEnvironment:Far + Global CrashRecovery:Far + + Public IsStartupKeyList + Public GetStartupKeyList + +; + +Segment StartUp BYTE Public 'Code' USE16 + Assume CS:StartUp, DS:Nothing, ES:Nothing + +CREATENEWLOGFILE EQU 1 +include debug.inc + +;Ŀ +; Variables +; + +StackSize = 1000h + +No386Msg DB "Sorry, Impulse Tracker requires a 386+ processor to run." + DB 13, 10, "$" +WindowsMsg DB "Microsoft Windows detected.", 13, 10, 10 + DB "Due to instabilities in Windows, it is highly recommended that you run", 13, 10 + DB "Impulse Tracker in DOS instead.", 13, 10, 10 + DB "Press any key to continue..." + DB "$" + +PSP DW ? + +LoadMMTSR DB 1 +Pause DB 0 +COMSPECFound DB 0 +COMSPEC DD 0 +Control DB 0 +CommandTail DB 1, 0, 13 + +FCB1 DB 0, 11 Dup (32), 52 Dup (0) +FCB2 DB 0, 11 Dup (32), 52 Dup (0) + +COMSPECString DB "COMSPEC" +DefaultShell DB "C:\COMMAND.COM", 0 +EXECData DW 0 ; Inherit same environment block + DW Offset CommandTail, Startup + DW Offset FCB1, Startup + DW Offset FCB2, Startup +ShellMsg DB "Type EXIT to return to Impulse Tracker$" + +IF SHOWREGISTERNAME +include wavswitc.inc +include username.inc +ENDIF + +Label CmdLineHelp Byte +IF SHOWVERSION + DB "Impulse Tracker 2.14, Copyright (C) 1995-2000 Jeffrey Lim", 13, 10 + DB 10 + DB " Usage: IT.EXE [Switches]", 13, 10 +ELSE + DB "Impulse Tracker, Copyright (C) 1995-2000 Jeffrey Lim", 13, 10 +IF SHOWREGISTERNAME + DB "Registered to: " + DB REGISTERNAME + DB 13, 10 +ENDIF +ENDIF + DB 10 + DB "Switches:", 13, 10 + DB " SFilename.Drv Select sound card driver", 13, 10 + DB " S#", 9, 9, " Quick select sound card", 13, 10 + DB 9, "S0: No sound card", 9, 9, " S9: Pro Audio Spectrum", 13, 10 + DB 9, "S1: PC Speaker", 9, 9, 9, "S10: Pro Audio Spectrum 16", 13, 10 + DB 9, "S2: Sound Blaster 1.xx", 9, 9, "S11: Windows Sound System", 13, 10 + DB 9, "S3: Sound Blaster 2.xx", 9, 9, "S12: ESS ES1868 AudioDrive", 13, 10 + DB 9, "S4: Sound Blaster Pro", 9, 9, "S13: EWS64 XL Codec", 13, 10 + DB 9, "S5: Sound Blaster 16", 9, 9, "S14: Ensoniq SoundscapeVIVO", 13, 10 + DB 9, "S6: Sound Blaster AWE 32", 9, "S19: Generic MPU401", 13, 10 + DB 9, "S7: Gravis UltraSound", 9, 9, "S20: Disk Writer (WAV)", 13, 10 + DB 9, "S8: AMD Interwave", 9, 9, "S21: Disk Writer (MID)", 13, 10 + DB 10 + DB " Axxx", 9, "Set Base Address of sound card (hexadecimal)", 13, 10 + DB " I###", 9, "Set IRQ of sound card (decimal)", 13, 10 + DB " D###", 9, "Set DMA of sound card (decimal)", 13, 10 + DB 10 + DB " M###", 9, "Set Mixspeed", 13, 10 + DB " L###", 9, "Limit number of channels (4-256)", 13, 10 + DB "$" + +MixErrorMsg DB "Error: Mixing speed invalid - setting ignored", 13, 10, "$" +AddressErrorMsg DB "Error: Base Address invalid - setting ignored", 13, 10, "$" +IRQErrorMsg DB "Error: IRQ number invalid - setting ignored", 13, 10, "$" +LimitErrorMsg DB "Error: Channel limit number invalid - setting ignored", 13, 10, "$" +ContinueMsg DB "Press any key to continue...$" + +StartupList DB 0 +StartupMode DB 0 ; Load? Or Load/Play? or Load/Save +StartupFileOffset DW 0 +StartupFileSegment DW 0 +StartupKeyListFunction DW Offset GetStartupKeyList1 + + ; CX,DX +StartupInformation DW 11Ch, 0 ; Enter + DW 1Ch, 0 ; Release Enter + DW 10Fh, 0 ; Tab + DW 10Fh, 0 ; Tab + DW 10Fh, 0 ; Tab + DW 90Eh, 127 ; Ctrl-Backspace + +ENDSTARTUPINFORMATION EQU $ + +SaveInformation DW 0, 0 ; Loading screen key-loss + DW 1FFh, 13h ; Ctrl-S + DW 0, 0 ; Saving screen key-loss + DW 1FFh, 11h ; Ctrl-Q + DW 1FFh, 'Y' ; 'Y' + +ENDSAVEINFORMATION EQU $ + +StartupQueueOffset DW Offset StartupInformation +StartupQueueEnd DW Offset ENDSTARTUPINFORMATION +StartupQueueNextFunction DW Offset GetStartupKeyList2 + +;Ŀ +; Functions +; + +Proc CapitaliseAL + + Cmp AL, 'a' + JB CapitaliseAL1 + + Cmp AL, 'z' + JA CapitaliseAL1 + + Add AL, 'A'-'a' + +CapitaliseAL1: + Ret + +EndP CapitaliseAL + +; + +Proc GetDecimalNumber ; Returns CX + + LodsB + Cmp AL, '0' + JB GetDecimalNumber1 + Cmp AL, '9' + JBE GetDecimalNumber2 + +GetDecimalNumber1: + StC + Ret + +GetDecimalNumber2: + Xor CX, CX + +GetDecimalNumber3: + Mov BL, AL + Sub BL, '0' + Xor BH, BH + Mov AX, 10 + Mul CX + Add AX, BX + Mov CX, AX + LodsB + And DX, DX + JNZ GetDecimalNumber1 + + Cmp AL, '0' + JB GetDecimalNumber4 + Cmp AL, '9' + JA GetDecimalNumber4 + Jmp GetDecimalNumber3 + +GetDecimalNumber4: + ClC + Ret + +EndP GetDecimalNumber + +; + +Proc Start + Assume DS:Nothing + +; 386 check. + + Trace "Impulse Tracker Startup" + + Push SP + Pop AX + Cmp AX, SP + JNE No386 + + PushF + Pop CX ; CX = Flags. + Mov AX, CX + Or AX, 0F000h + Push AX + PopF + PushF + Pop AX + And AX, 0F000h + JNZ Found386 + +No386: + Push CS + Pop DS + + Mov AH, 9 + Mov DX, Offset No386Msg + Int 21h + + Mov AX, 4C02h + Int 21h + +Found386: +; Push 0B800h ; DEBUG!!!!! +; Pop GS ; DEBUG!!!!! + + Push CX + PopF + + ClD + + Mov [CS:PSP], ES + + Mov AX, ES + Mov BX, SS + Sub BX, AX + Add BX, StackSize / 16 ; Add BX, + Mov AH, 4Ah ; Re-allocate memory + Int 21h + + ; Check for 386 here. + + ; Do command line stuff. + Mov SI, 81h ; DS:SI points to cmdtail + +CmdLine1: + Push ES + Pop DS + + LodsB + +CmdLine3: + Cmp AL, 0Dh + JE CmdLineEnd + And AL, AL + JZ CmdLineEnd + + Call CapitaliseAL + +CmdLine2: + Cmp AL, 'K' + JE KeyboardSwap + Cmp AL, 'F' + JE DisableColours + Cmp AL, 'C' + JE SetControl + Cmp AL, 'H' + JE ShowCmdLineHelp + Cmp AL, '?' + JE ShowCmdLineHelp + Cmp AL, 'S' + JE SetSoundCard1 + Cmp AL, 'D' + JE SetDMA1 + Cmp AL, 'M' + JE SetMixSpeed1 + Cmp AL, 'I' + JE SetIRQ1 + Cmp AL, 'A' + JE SetAddress1 + Cmp AL, 'V' + JE OverrideVGA + Cmp AL, 'L' + JE Limit1 + Cmp AL, 'R' + JE Reverse1 + Cmp AL, 'X' + JE DisableFeatures + Cmp AL, 'P' + JE PatternStorage + Cmp AL, 'T' + JE NoShowUsageTime + Cmp AL, 'W' + JE ConvertModule + + Jmp CmdLine1 + +NoShowUsageTime: + LodsB + Cmp AL, '1' + JNE NoReleaseTimeSlice + + Push DS + + Push InfoLine + Pop DS + Assume DS:InfoLine + + Mov [ShowUsageTime], 0 + + Pop DS + Jmp CmdLine1 + Assume DS:Nothing + +NoReleaseTimeSlice: + Cmp AL, '2' + JNE CmdLine3 + +NoReleaseTimeSlice2: + Push DS + + Push Main + Pop DS + Assume DS:Main + + Mov [ReleaseTimeSlice], 1 + + Pop DS + Jmp CmdLine1 + +PatternStorage: + LodsB + Sub AL, '0' + JC PatternStorageEnd + Cmp AL, 2 + JA PatternStorageEnd + Call Music_PatternStorage + Jmp CmdLine1 + +PatternStorageEnd: + Jmp CmdLine3 + +DisableFeatures: + LodsB + Cmp AL, '1' + JB CmdLine3 + JE DisableMMTSR + + Cmp AL, '3' + JB DisableMouse + JE DisableDetectDriveMap + + Cmp AL, '5' + JB DisableCacheFiles + Jmp CmdLine3 + +DisableMouse: + Call CmdLineDisableMouse + Jmp CmdLine1 + +DisableMMTSR: + Mov [LoadMMTSR], 0 + Jmp CmdLine1 + +DisableDetectDriveMap: + Push Disk + Pop DS + Assume DS:Disk + + Or [DiskOptions], 1 + Jmp CmdLine1 + Assume DS:Nothing + +DisableCacheFiles: + Push Disk + Pop DS + Assume DS:Disk + + Or [DiskOptions], 2 + Jmp CmdLine1 + Assume DS:Nothing + +KeyboardSwap: + Mov AX, Object1 + Mov DS, AX + Assume DS:Object1 + + Mov [HelpKeyValue], 157h + Mov [OrderKeyValue], 13Bh + + Jmp CmdLine1 + Assume DS:Nothing + +DisableColours: + Call D_DisableFileColours + Jmp CmdLine1 + +Reverse1: + Call Music_ReverseChannels + Jmp CmdLine1 + +OverrideVGA: + LodsB + + Mov CX, Screen + Mov DS, CX + Assume DS:Screen + + Cmp AL, '1' + JE OverrideVGA1 + Cmp AL, '2' + JE Matrox + Cmp AL, '3' + JE WaitforRetrace + Cmp AL, '4' + JE Retrace + Jmp CmdLine3 + +OverrideVGA1: + Or [VGAFlags], 1 + Jmp CmdLine1 + +WaitforRetrace: + Or [VGAFlags], 4 + Jmp CmdLine1 + +Retrace: + Or [VGAFlags], 2 + Jmp CmdLine1 + +Matrox: + Mov [CharacterGenerationOffset], 256*32 + + Mov AX, Mouse + Mov DS, AX + Assume DS:Mouse + Mov [MouseCharacterGenerationOffset], 256*32 + + Jmp CmdLine1 + Assume DS:Nothing + +SetControl: + Mov [CS:Control], 1 + Jmp CmdLine1 + +ShowCmdLineHelp: + Push CS + Pop DS + + Mov AH, 9 + Mov DX, Offset CmdLineHelp + Int 21h + + Mov AX, 4C00h + Int 21h + +SetSoundCard1: + Call GetDecimalNumber + JC SetSoundCardDriver + Cmp CX, 21 + JA SetSoundCard2 + + Push AX + Mov AX, CX + Call Music_SetSoundCard + Pop AX + +SetSoundCard2: + Jmp CmdLine3 + +SetSoundCardDriver: + Cmp AL, 32 + JBE CmdLine3 + + Dec SI + Call Music_SetSoundCardDriver + +SetSoundCardDriver1: + LodsB + Cmp AL, 32 + JA SetSoundCardDriver1 + + Mov Byte Ptr [SI-1], 0 + Cmp AL, 32 + JE CmdLine1 + Jmp CmdLineEnd + +ConvertModule: + Mov [CS:StartupList], 1 + Mov [CS:StartupFileOffset], SI + Mov [CS:StartupFileSegment], DS + Jmp SetSoundCardDriver1 + +SetDMA1: + LodsB + Cmp AL, '0' + JB CmdLine3 + Cmp AL, '7' + JA CmdLine3 + Sub AL, '0' + Call Music_SetDMA + Jmp CmdLine1 + +SetMixSpeed1: + Call GetDecimalNumber + JC SetMixSpeedError + Push AX + Call Music_SetMixSpeed + Pop AX + Jmp CmdLine3 + +SetMixSpeedError: + Push CS + Pop DS + Assume DS:StartUp + + Mov AH, 9 + Mov DX, Offset MixErrorMsg + Int 21h + + Mov [Pause], 1 + Jmp CmdLine1 + Assume DS:Nothing + +SetIRQ1: + Call GetDecimalNumber + JC IRQError + Cmp CX, 15 + JA IRQError + + Push AX + Call Music_SetIRQ + Pop AX + Jmp CmdLine3 + +IRQError: + Push CS + Pop DS + Assume DS:StartUp + + Mov AH, 9 + Mov DX, Offset IRQErrorMsg + Int 21h + + Mov [Pause], 1 + Jmp CmdLine1 + Assume DS:Nothing + + +SetAddress1: + LodsB + + Xor DX, DX + Mov CL, 4 + + Cmp AL, '0' + JB SetAddress2 + Cmp AL, '9' + JA SetAddress2 + Sub AL, '0' + Jmp SetAddress3 + +SetAddress2: + Call CapitaliseAL + + Cmp AL, 'A' + JB CmdLine2 + Cmp AL, 'F' + JA CmdLine2 + Sub AL, '@' + +SetAddress3: + Test DX, 0F000h + JNZ AddressError + + ShL DX, CL + Or DL, AL + + LodsB + Cmp AL, '0' + JB SetAddress4 + Cmp AL, '9' + JA SetAddress4 + Sub AL, '0' + Jmp SetAddress3 + +SetAddress4: + Call CapitaliseAL + Cmp AL, 'A' + JB SetAddress5 + Cmp AL, 'F' + JA SetAddress5 + + Sub AL, '@' + Jmp SetAddress3 + +SetAddress5: + Call Music_SetAddress + Jmp CmdLine3 + +AddressError: + Push CS + Pop DS + Assume DS:StartUp + + Mov AH, 9 + Mov DX, Offset AddressErrorMsg + Int 21h + + Mov [Pause], 1 + Jmp CmdLine1 + Assume DS:Nothing + +Limit1: + Call GetDecimalNumber + JC LimitError + Cmp CX, 256 + JA LimitError + Cmp CX, 4 + JB LimitError + + Push AX + Call Music_SetLimit + Pop AX + Jmp CmdLine3 + +LimitError: + Push CS + Pop DS + Assume DS:StartUp + + Mov AH, 9 + Mov DX, Offset LimitErrorMsg + Int 21h + + Mov [Pause], 1 + Jmp CmdLine1 + Assume DS:Nothing + + +CmdLineEnd: + Trace "Command Line Parsed" + + Push CS + Pop DS + Assume DS:StartUp + + Trace "Windows Detection" + + Mov AX, 1600h ; Windows detection. + Int 2Fh + Test AL, 7Fh + JZ Start1 + Cmp AL, 4 ; Windows 4.0+ ?? + JAE Start1 + + Mov AH, 9 + Mov DX, Offset WindowsMsg + Int 21h + + Xor AX, AX + Int 16h + +Start1: + ; Get Comspec + Cmp [Pause], 1 + JNE NoPause + + Mov DX, Offset ContinueMsg + Mov AH, 9 + Int 21h + + Xor AX, AX + Int 16h + +NoPause: + Trace "Retrieving Environment" + + Mov SI, Offset COMSPECString + Mov CX, 7 + Call GetEnvironment + JC Start2 + + Mov [COMSPECFound], 1 + Mov [Word Ptr COMSPEC], DI + Mov [Word Ptr COMSPEC+2], ES + +Start2: + Mov FS, [CS:PSP] + + Trace "Initialising Screen Module" + + Call S_InitScreen + + Trace "Initialising Disk Module" + + Call D_InitDisk + + Trace "Initialising Expanded Memory Module" + + Call E_InitEMS + + Trace "Initialising Music Module" + + Call Music_InitMusic + + Trace "Initialising Keyboard Module" + + Call K_InitKeyBoard + + Trace "Initialising Edit Module" + + Call PE_InitPatternEdit + + Trace "Initialising Custom Keyboard Layout" + + Call K_InstallKeyboardType + + Trace "Initialising Error Handler Module" + + Call Error_InitHandler + + Cmp [CS:LoadMMTSR], 0 + JE SkipMMTSR + + Trace "Initialising MMTSR Module" + + Call MMTSR_InstallMMTSR + +SkipMMTSR: + Trace "Initialising Mouse Module" + + Call InitMouse + + Call S_ClearScreen + + Trace "Initialising Timer Module" + + Call InitTimerHandler + + Trace "Initialising Soundcard" + + Call Music_AutoDetectSoundCard + + Trace "Entering Main Message Loop" + + Mov DI, Offset O1_AutoDetectList +; Mov DI, Offset O1_KeyboardList + Mov CX, 0FFFFh + Call M_Object1List + Jmp Quit1 + +Proc Quit Far + + Mov DI, Offset O1_ConfirmQuit + Mov CX, 3 + Call M_Object1List + + And DX, DX + JNZ Quit1 + + Mov AX, 1 + RetF + +Quit1: + Call PECheckModified + Call Music_Stop + +IF NETWORKENABLED + Call Network_Shutdown +ENDIF + + Call MMTSR_UninstallMMTSR + Call PE_UnInitPatternEdit + Call Music_UnInitMusic + Call UnInitMouse + Call S_UnInitScreen + Call E_UnInitEMS + Call K_UnInitKeyBoard + Call Error_UnInitHandler + Call D_UnInitDisk + Call K_RemoveKeyboardType + Call UnInitTimerHandler + + Mov AX, 4C00h + Int 21h + +EndP Quit + +EndP Start + +; + +Proc IsStartupKeyList Far + + Mov AL,CS:StartupList + + Ret + +EndP IsStartupKeyList + +; + +Proc GetStartupKeyList Far + + Jmp [CS:StartupKeyListFunction] + +GetStartupKeyList1: + Push SI + Mov SI, [CS:StartupQueueOffset] + + Mov CX, [CS:SI] + Mov DX, [CS:SI+2] + + Add SI, 4 + Mov [CS:StartupQueueOffset], SI + + Cmp SI, [CS:StartupQueueEnd] + + Pop SI + JB GetStartupKeyList1End + + Mov AX, [CS:StartupQueueNextFunction] + Mov [CS:StartupKeyListFunction], AX + +GetStartupKeyList1End: + Ret + +GetStartupKeyList2: + Push DS + Push SI + + LDS SI, [DWord Ptr CS:StartupFileOffset] + LodsB + + Mov [CS:StartupFileOffset], SI + + Pop SI + Pop DS + + Cmp AL, 32 + JE GetStartupKeyList2EndOfString + And AX, 0FFh + JZ GetStartupKeyList2EndOfString + + Mov DX, AX + Mov CX, 1FFh + + Ret + +GetStartupKeyList2EndOfString: + Mov [CS:StartupQueueOffset], Offset SaveInformation + Mov [CS:StartupQueueEnd], Offset ENDSAVEINFORMATION + Mov [CS:StartupQueueNextfunction], Offset GetStartupKeyList3 + Mov [CS:StartupKeyListFunction], Offset GetStartupKeyList1 + + Mov CX, 11Ch ; Enter + Mov DX, 0 + + Ret + +GetStartupKeyList3: ; Save module then quit + Xor CX, CX + Xor DX, DX + Mov [CS:StartupList], 0 + Ret + +EndP GetStartupKeyList + +; + +Proc CrashRecovery Far ; CtrlAltDel location. + + ClD + StI + + Call S_ClearScreen + Call S_InitScreen + Call D_InitDisk + Call InitMouse + + Mov DI, Offset O1_CrashRecovery + Mov CX, 0FFFFh + Call M_Object1List + + Mov DI, Offset O1_PatternEditList + Mov CX, 0FFFFh + Jmp M_Object1List + +EndP CrashRecovery + +; + +Proc GetEnvironment Far ; DS:SI points to string. + ; CX = length of string. + ; Returns ES:DI + + Mov ES, [CS:PSP] + Mov ES, [ES:2Ch] ; DS:00 points to environ. + Xor DI, DI + +GetEnvironment1: + Push DI + Push CX + Push SI + + RepE CmpSB + + Pop SI + Pop CX + Pop DI + + JE GetEnvironment3 ; From RepE + + Xor AL, AL + +GetEnvironment2: + ScasB + JNE GetEnvironment2 + + Cmp [Byte Ptr ES:DI], AL + JNE GetEnvironment1 + + StC + Ret + +GetEnvironment3: + Add DI, CX + Inc DI ; Skip past '=' + ClC + Ret + +EndP GetEnvironment + +; + +Proc Refresh Far + + Call D_GetPreShellDirectory + Call S_InitScreen + Call D_InitDisk + Call InitMouse + Call D_RestorePreShellDirectory + + Mov AX, 1 + Ret + +EndP Refresh + +; + +Proc DOSShell Far + + PushAD + Push DS + Push ES + + PushF + + Call D_GetPreShellDirectory + + Cmp [CS:Control], 0 + JNE DOSShell2 + + Call K_UnInitKeyBoard + Jmp DOSShell3 + +DOSShell2: + Call K_InstallDOSHandler +DOSShell3: + + Mov AX, 3 + Int 10h ; Clr screen. + + Call UnInitMouse + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:StartUp + + Mov AH, 9 + Mov DX, Offset ShellMsg + Int 21h + + Mov AX, 4B00h + Mov BX, Offset ExecData + Mov DX, Offset DefaultShell + Cmp [COMSPECFound], 0 + JE DOSShell1 + + LDS DX, [COMSPEC] + +DOSShell1: + ClI + Int 21h + Assume DS:Nothing + + PopF + + Call S_InitScreen + Call D_InitDisk + Call InitMouse + + Cmp [CS:Control], 0 + JNE DOSShell4 + + Call K_InitKeyBoard + Jmp DOSShell5 + +DOSShell4: + Call K_UnInstallDOSHandler + +DOSShell5: + Call D_RestorePreShellDirectory + + Pop ES + Pop DS + PopAD + + Mov AX, 1 + Ret + +EndP DOSShell + Assume DS:Nothing + +; + + +EndS + +;Ŀ +; Stack Segment +; + +Segment StackSeg PARA Stack 'Stack' +StackData DB StackSize Dup(?) +EndS + +; + +End Start diff --git a/it/IT.EXE b/it/IT.EXE new file mode 100644 index 0000000000000000000000000000000000000000..f34f4226859197a6c664291e0fcae26c7a445791 GIT binary patch literal 468905 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 JM;l*>6>hoy9)ZeprmyA0wrP;JjO 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 literal 0 HcmV?d00001 diff --git a/it/IT.MAP b/it/IT.MAP new file mode 100644 index 0000000..32609c4 --- /dev/null +++ b/it/IT.MAP @@ -0,0 +1,1554 @@ + + Start Stop Length Name Class + + 00000H 063DBH 063DCH OBJECT1 DATA + 063E0H 063E0H 00000H DISKDATA DATA + 163E0H 275BFH 111E0H SONGDATA DATA + 275C0H 36FBFH 0FA00H PATTERNDATA DATA + 36FC0H 3D01FH 06060H SCREENDATA DATA + 3D020H 3D34BH 0032CH INFOLINE CODE + 3D34CH 459B2H 08667H DISK CODE + 459B3H 466CBH 00D19H SCREEN CODE + 466D0H 475C6H 00EF7H MOUSE CODE + 475C8H 47936H 0036FH MAIN CODE + 47937H 484B9H 00B83H STARTUP CODE + 484BAH 4DE41H 05988H PATTERN CODE + 4DE44H 5B402H 0D5BFH MUSIC CODE + 5B403H 5B899H 00497H GLBL CODE + 5B89AH 5D736H 01E9DH INFOPAGE CODE + 5D738H 5DB2BH 003F4H EMS CODE + 5DB2CH 5DCDAH 001AFH ERROR CODE + 5DCDCH 61361H 03686H INST CODE + 61362H 6315BH 01DFAH FUNCTIONS CODE + 6315CH 654E3H 02388H HELP CODE + 654E4H 65FD0H 00AEDH KEYBOARD CODE + 65FE0H 6681DH 0083EH MMTSR CODE + 6681EH 68BB0H 02393H MESSAGE CODE + 68BB1H 68E26H 00276H VESA CODE + 68E30H 69E2FH 01000H STACKSEG STACK + + +Detailed map of segments + + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT.ASM ACBP=29 + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT_DISK.ASM ACBP=29 + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT_DISPL.ASM ACBP=28 + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT_EMS.ASM ACBP=29 + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT_F.ASM ACBP=29 + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT_G.ASM ACBP=28 + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT_H.ASM ACBP=29 + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT_I.ASM ACBP=29 + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT_M.ASM ACBP=28 + 0000:0000 0000 C=DATA S=OBJECT1 G=(none) M=IT_NET.ASM ACBP=29 + 0000:0000 63DC C=DATA S=OBJECT1 G=(none) M=IT_OBJ1.ASM ACBP=28 + 0000:63DC 0000 C=DATA S=OBJECT1 G=(none) M=IT_PE.ASM ACBP=29 + 0000:63DC 0000 C=DATA S=OBJECT1 G=(none) M=IT_FOUR.ASM ACBP=29 + 063E:0000 00010000 C=DATA S=DISKDATA G=(none) M=IT_DISK.ASM ACBP=6B + 163E:0000 0000 C=DATA S=DISKDATA G=(none) M=IT_I.ASM ACBP=69 + 163E:0000 0000 C=DATA S=DISKDATA G=(none) M=IT_NET.ASM ACBP=69 + 163E:0000 0000 C=DATA S=DISKDATA G=(none) M=IT_FOUR.ASM ACBP=69 + 163E:0000 0000 C=DATA S=SONGDATA G=(none) M=IT_MUSIC.ASM ACBP=69 + 163E:0000 0000 C=DATA S=SONGDATA G=(none) M=IT_NET.ASM ACBP=69 + 163E:0000 000111E0 C=DATA S=SONGDATA G=(none) M=IT_MDATA.ASM ACBP=68 + 275C:0000 FA00 C=DATA S=PATTERNDATA G=(none) M=IT_PE.ASM ACBP=69 + 36FC:0000 6060 C=DATA S=SCREENDATA G=(none) M=IT_S.ASM ACBP=69 + 3D02:0000 0000 C=CODE S=INFOLINE G=(none) M=IT.ASM ACBP=28 + 3D02:0000 032C C=CODE S=INFOLINE G=(none) M=IT_L.ASM ACBP=A8 + 3D34:000C 0000 C=CODE S=DISK G=(none) M=IT.ASM ACBP=28 + 3D34:000C 77B1 C=CODE S=DISK G=(none) M=IT_DISK.ASM ACBP=28 + 3D34:77BD 0000 C=CODE S=DISK G=(none) M=IT_F.ASM ACBP=29 + 3D34:77C0 0EB3 C=CODE S=DISK G=(none) M=IT_NET.ASM ACBP=A8 + 3D34:8673 0000 C=CODE S=DISK G=(none) M=IT_PE.ASM ACBP=29 + 459B:0003 0000 C=CODE S=SCREEN G=(none) M=IT.ASM ACBP=29 + 459B:0003 0000 C=CODE S=SCREEN G=(none) M=IT_F.ASM ACBP=29 + 459B:0003 0D19 C=CODE S=SCREEN G=(none) M=IT_S.ASM ACBP=28 + 466D:0000 0000 C=CODE S=MOUSE G=(none) M=IT.ASM ACBP=29 + 466D:0000 0000 C=CODE S=MOUSE G=(none) M=IT_S.ASM ACBP=29 + 466D:0000 0EF7 C=CODE S=MOUSE G=(none) M=IT_MOUSE.ASM ACBP=68 + 475C:0008 0000 C=CODE S=MAIN G=(none) M=IT.ASM ACBP=A8 + 475C:0008 036F C=CODE S=MAIN G=(none) M=IT_M.ASM ACBP=A8 + 4793:0007 0B83 C=CODE S=STARTUP G=(none) M=IT.ASM ACBP=28 + 484B:000A 0000 C=CODE S=PATTERN G=(none) M=IT_DISK.ASM ACBP=29 + 484B:000A 0000 C=CODE S=PATTERN G=(none) M=IT_DISPL.ASM ACBP=48 + 484B:000A 0000 C=CODE S=PATTERN G=(none) M=IT_F.ASM ACBP=29 + 484B:000A 0000 C=CODE S=PATTERN G=(none) M=IT_G.ASM ACBP=28 + 484B:000A 0000 C=CODE S=PATTERN G=(none) M=IT_I.ASM ACBP=29 + 484B:000A 0000 C=CODE S=PATTERN G=(none) M=IT_NET.ASM ACBP=28 + 484B:000A 5988 C=CODE S=PATTERN G=(none) M=IT_PE.ASM ACBP=48 + 4DE4:0004 0000 C=CODE S=MUSIC G=(none) M=IT_DISK.ASM ACBP=29 + 4DE4:0004 0000 C=CODE S=MUSIC G=(none) M=IT_F.ASM ACBP=29 + 4DE4:0004 D5BF C=CODE S=MUSIC G=(none) M=IT_MUSIC.ASM ACBP=A8 + 4DE4:D5C3 0000 C=CODE S=MUSIC G=(none) M=IT_NET.ASM ACBP=28 + 5B40:0003 0000 C=CODE S=GLBL G=(none) M=IT_DISPL.ASM ACBP=28 + 5B40:0003 0497 C=CODE S=GLBL G=(none) M=IT_G.ASM ACBP=28 + 5B40:049A 0000 C=CODE S=GLBL G=(none) M=IT_L.ASM ACBP=29 + 5B89:000A 1B7C C=CODE S=INFOPAGE G=(none) M=IT_DISPL.ASM ACBP=28 + 5B89:1B86 0321 C=CODE S=INFOPAGE G=(none) M=IT_FOUR.ASM ACBP=28 + 5D73:0008 03F4 C=CODE S=EMS G=(none) M=IT_EMS.ASM ACBP=48 + 5DB2:000C 01AF C=CODE S=ERROR G=(none) M=IT_ERR.ASM ACBP=28 + 5DCD:000C 0000 C=CODE S=INST G=(none) M=IT_F.ASM ACBP=29 + 5DCD:000C 0000 C=CODE S=INST G=(none) M=IT_G.ASM ACBP=28 + 5DCD:000C 3686 C=CODE S=INST G=(none) M=IT_I.ASM ACBP=48 + 5DCD:3692 0000 C=CODE S=INST G=(none) M=IT_PE.ASM ACBP=29 + 6136:0002 1DFA C=CODE S=FUNCTIONS G=(none) M=IT_F.ASM ACBP=28 + 6315:000C 2388 C=CODE S=HELP G=(none) M=IT_H.ASM ACBP=28 + 654E:0004 0AED C=CODE S=KEYBOARD G=(none) M=IT_K.ASM ACBP=28 + 65FE:0000 083E C=CODE S=MMTSR G=(none) M=IT_MMTSR.ASM ACBP=68 + 6681:000E 2393 C=CODE S=MESSAGE G=(none) M=IT_MSG.ASM ACBP=28 + 68BB:0001 0276 C=CODE S=VESA G=(none) M=IT_VESA.ASM ACBP=28 + 68E3:0000 1000 C=STACK S=STACKSEG G=(none) M=IT.ASM ACBP=75 + + Address Publics by Name + + 466D:00DCA ADDMOUSEQUEUE + 484B:002D8 AMPLIFICATION + 484B:00030 BASEOCTAVE + 484B:00D78 CENTRALISECURSOR + 459B:006A3 CHARACTERGENERATIONOFFSET + 3D02:00243 CLEARINFOLINE + 466D:00EDA CMDLINEDISABLEMOUSE + 484B:00D77 COMMANDTOVALUE + 4793:00A9F CRASHRECOVERY + 5B40:00003 CURRENTMODE + 4DE4:00352 CURRENTPATTERN + 3D34:00010 DISKDATAAREA + 3D34:00F34 DISKOPTIONS + 5B89:01881 DISPLAYMINUS + 5B89:01878 DISPLAYPLUS + 5B89:01A40 DISPLAYUPDATESCREEN + 5B89:01AAC DISPLAY_GETDISPLAYWINDOWDATA + 5B89:01B11 DISPLAY_SELECTDISPLAYLIST + 4793:00B0F DOSSHELL + 5B89:0179F DRAWDISPLAYDATA + 466D:00B86 DRAWMOUSE + 3D34:06753 D_CLEARFILENAME + 3D34:03466 D_CLEARFILESPECIFIER + 3D34:06403 idle D_DELETESAMPLEFILE + 3D34:0676E D_DISABLEFILECOLOURS + 3D34:016CD D_DRAWDIRECTORYWINDOW + 3D34:0173D D_DRAWDRIVEWINDOW + 3D34:014B0 D_DRAWFILEWINDOW + 3D34:069D1 D_DRAWLOADINSTRUMENT + 3D34:04355 D_DRAWLOADSAMPLEWINDOW + 3D34:0755A D_DRAWTIMER + 3D34:065AE D_DRAWWAVEFORM + 3D34:0741A D_GETFILENAME + 3D34:06768 D_GETFORMATTYPE + 3D34:0509B D_GETLOADSAMPLEVARS + 3D34:073FE D_GETPRESHELLDIRECTORY + 3D34:050AF D_GOTOSTARTINGDIRECTORY + 3D34:010A6 D_INITDISK + 3D34:0684F D_INITLOADINSTRUMENTS + 3D34:01469 D_INITLOADMODULE + 3D34:040E4 D_INITLOADSAMPLES + 3D34:04750 D_LIDRAWDRIVEWINDOW + 3D34:047A9 D_LIPOSTDRIVEWINDOW + 3D34:04787 D_LIPREDRIVEWINDOW + 3D34:02ADC D_LOAD669 + 3D34:0696A D_LOADINSTRUMENTNAMES + 3D34:02EC0 D_LOADIT + 3D34:02C3D D_LOADMOD + 3D34:0259C D_LOADMTM + 3D34:0283A D_LOADS3M + 3D34:05037 D_LOADSAMPLENAMES + 3D34:01858 D_LOADSONGNAMES + 3D34:0214E D_LOADXM + 3D34:06018 D_LSCHECKLOOPVALUES + 3D34:06049 D_LSCHECKSUSLOOPVALUES + 3D34:046C7 D_LSDRAWDRIVEWINDOW + 3D34:0473F D_LSPOSTDRIVEWINDOW + 3D34:0471B D_LSPREDRIVEWINDOW + 3D34:0344A D_NEWDIRECTORY + 3D34:033BB D_NEWSPECIFIER + 3D34:03321 D_POSTDIRECTORYWINDOW + 3D34:03399 D_POSTDRIVEWINDOW + 3D34:0322D D_POSTFILELOADWINDOW + 3D34:031EE D_POSTFILESAVEWINDOW + 3D34:03298 idle D_POSTFILEWINDOW + 3D34:06B4F D_POSTLOADINSTRUMENT + 3D34:0462D D_POSTLOADSAMPLEWINDOW + 3D34:033AA D_POSTSAVEDRIVEWINDOW + 3D34:074FC D_POSTTIMERLIST + 3D34:046B7 D_POSTVIEWSAMPLELIBRARY + 3D34:018C8 D_PREDIRECTORYWINDOW + 3D34:018EE D_PREDRIVEWINDOW + 3D34:01889 D_PREFILEWINDOW + 3D34:06B22 D_PRELOADINSTRUMENT + 3D34:045FE D_PRELOADSAMPLEWINDOW + 3D34:07420 D_RESETTIMER + 3D34:0740D D_RESTOREPRESHELLDIRECTORY + 3D34:050BA D_SAVEDIRECTORYCONFIGURATION + 3D34:062BC D_SAVEINSTRUMENT + 3D34:03617 D_SAVEIT + 3D34:0347B D_SAVEMODULE + 3D34:06166 D_SAVERAWSAMPLE + 3D34:03AD6 D_SAVES3M + 3D34:06100 D_SAVESAMPLE + 3D34:0607A D_SAVESONG + 3D34:0620D D_SAVEST3SAMPLE + 3D34:07416 D_SETDRIVEDIRECTORYFAR + 3D34:07451 D_SHOWTIME + 3D34:07712 D_SLOWINSTRUMENTSORT + 3D34:07670 D_SLOWSAMPLESORT + 3D34:01292 D_UNINITDISK + 3D34:06B60 D_VIEWINSTRUMENT + 0000:01016 EMSERRORVALUE + 0000:01014 EMSERRORVALUE2 + 0000:01012 EMSERRORVALUE3 + 0000:0100E EMSERRORVALUE4 + 0000:0100C EMSERRORVALUE5 + 0000:0100A EMSERRORVALUE6 + 0000:01008 EMSERRORVALUE7 + 0000:01010 EMSERRORVALUE8 + 5DB2:0018F ERROR_INITHANDLER + 5DB2:001AA ERROR_UNINITHANDLER + 5D73:001FD E_ALLOCATEBLOCKEMS + 5D73:00374 E_ALLOCATEEMS + 5D73:003BA E_EMSAVAILABLE + 5D73:001D5 E_GETEMSPAGEFRAME + 5D73:003F2 E_GETEMSVERSION + 5D73:000EB E_GETFREEEMS + 5D73:003F7 E_GETINTERNALEMSHANDLE + 5D73:0002A E_INITEMS + 5D73:001DA E_MAPALIGNEDBLOCKEMS + 5D73:00180 E_MAPAVAILABLEEMSMEMORY + 5D73:0019B E_MAPEMSMEMORY + 5D73:002E7 E_RELEASEBLOCKEMS + 5D73:00109 E_RELEASEEMS + 5D73:003DC E_RESTOREEMSPAGEFRAME + 5D73:003C1 E_SAVEEMSPAGEFRAME + 5D73:001C4 E_UNINITEMS + 484B:00D7B FASTVOLUMEAMPLIFICATION + 3D34:00066 FILENAME + 3D34:000C4 FILESPECIFIER + 484B:00D7D FLAGS + 466D:00EE2 FORCEMOUSERESTORE + 5B89:01C8A FOURIER_CHANGEPALETTE + 5B89:01B86 FOURIER_CREATETABLE + 5B89:01DA5 FOURIER_DRAWSCREEN + 5B89:01E96 FOURIER_IDLELIST + 5B89:01E9A FOURIER_POSTFUNCTION + 5B89:01DA2 FOURIER_PREDRAWSCREEN + 5B89:01D40 FOURIER_START + 5B89:01BB1 FOURIER_TRANSFORM + 6136:01C35 F_CALCULATELENGTH + 6136:00369 F_CALLFARFUNCTION + 6136:00363 F_CALLFARPOSTFUNCTION + 6136:0035F F_CALLFARPREFUNCTION + 6136:003E0 F_CHARACTERDEFINITIONS + 6136:0195C F_CONFIGBUTTONSETUP + 6136:01518 F_DRAW3NUM + 6136:01700 F_DRAW5NUM + 6136:0036D F_DRAWBOXOBJECT + 6136:00427 F_DRAWBUTTONOBJECT + 6136:018B8 F_DRAWHEADER + 6136:00D61 F_DRAWINFOLINE + 6136:008D6 F_DRAWSCALABLETHUMBBAR + 6136:0191D F_DRAWSMCCHANNELS + 6136:00F92 F_DRAWSTRINGINPUT + 6136:00383 F_DRAWTEXTOBJECT + 6136:0080B F_DRAWTHUMBBAR + 6136:01346 F_DRAWTOGGLE + 6136:01C4C F_DRIVERSCREEN + 6136:01D44 F_FILEDOSSHELL + 6136:01CF4 F_FILELOAD + 6136:01CE0 F_FILEMENU + 6136:01D06 F_FILENEW + 6136:01D5B F_FILEQUIT + 6136:01D32 F_FILESAVEAS + 6136:01D1B F_FILESAVECURRENT + 6136:010E1 F_GOTOEMPTYLIST + 6136:01B91 F_HELP + 6136:01BB7 F_INFOPAGE + 6136:00344 F_INSTRUMENTBUTTONHANDLER + 6136:01CAA F_INSTRUMENTLIBRARY + 6136:01C98 F_INSTRUMENTLIST + 6136:01C72 F_INSTRUMENTMENU + 6136:01B44 F_MAINMENU + 6136:01B84 F_MESSAGEEDITOR + 6136:01DB2 F_MIDI_DOWN + 6136:01DDC F_MIDI_PGDN + 6136:01DC4 F_MIDI_PGUP + 6136:01D99 F_MIDI_UP + 6136:01A9E F_NEWSONG + 6136:00341 F_NOTHING + 6136:01BA3 F_PLAYBACKMENU + 6136:01BFF F_PLAYMARK + 6136:01BED F_PLAYORDER + 6136:01BDB F_PLAYPATTERN + 6136:01BC9 F_PLAYSONG + 6136:015B1 F_POST3NUM + 6136:01798 F_POST5NUM + 6136:00505 F_POSTBUTTONOBJECT + 6136:003C8 F_POSTEXITOBJECT + 6136:00B22 F_POSTSCALABLETHUMBBAR + 6136:0102A F_POSTSTRINGINPUT + 6136:00B6E F_POSTTHUMBBAR + 6136:013EF F_POSTTOGGLE + 6136:01592 F_PRE3NUM + 6136:01779 F_PRE5NUM + 6136:004CC F_PREBUTTONOBJECT + 6136:00A71 F_PRESCALABLETHUMBBAR + 6136:01006 F_PRESTRINGINPUT + 6136:009BF F_PRETHUMBBAR + 6136:013BC F_PRETOGGLE + 6136:00DE8 F_REDRAWSCREEN + 6136:01C23 F_REINITSOUNDCARD + 6136:01CBC F_RELOADGRAVIS + 6136:01A96 F_RESET5NUMINPUTPOS + 6136:00DEC F_RETURN0 + 6136:00EDD F_RETURN1 + 6136:00DF9 F_RETURN192 + 6136:00DF2 F_RETURN64 + 6136:01CCE F_SAMPLELIBRARY + 6136:01C86 F_SAMPLELIST + 6136:01C5E F_SAMPLEMENU + 6136:01A86 F_SETAMIGA + 6136:019DF F_SETCONTROLINSTRUMENT + 6136:019CF F_SETCONTROLSAMPLE + 6136:003D8 F_SETDIRECTMODE + 6136:01A76 F_SETLINEAR + 6136:01A61 F_SETMONO + 6136:01A4C F_SETSTEREO + 6136:00DA6 F_SHOWCHANNELS + 6136:01D72 F_SHOWMIDIZXXINPUT + 6136:01C11 F_STOP + 6136:01B77 F_VIEWORDERPAN + 6136:01B5D F_VIEWPATTERN + 6136:01B6A F_VIEWVARIABLES + 4793:00ACB GETENVIRONMENT + 466D:00DC5 GETKEYBOARDLOCK + 4793:00A28 GETSTARTUPKEYLIST + 3D02:00326 GETTIMERCOUNTER + 5B40:00341 GLBL_ALT_F1 + 5B40:0034D GLBL_ALT_F2 + 5B40:00359 GLBL_ALT_F3 + 5B40:00365 GLBL_ALT_F4 + 5B40:00371 GLBL_ALT_F5 + 5B40:0037D GLBL_ALT_F6 + 5B40:00389 GLBL_ALT_F7 + 5B40:00395 GLBL_ALT_F8 + 5B40:0029A GLBL_CTRL_F1 + 5B40:002ED GLBL_CTRL_F12 + 5B40:002AD GLBL_CTRL_F3 + 5B40:002C5 GLBL_CTRL_F4 + 5B40:002DD GLBL_CTRL_F5 + 5B40:0048C GLBL_DRIVERSCREEN + 5B40:00231 GLBL_F10 + 5B40:00256 GLBL_F11 + 5B40:0025E GLBL_F11_2 + 5B40:00287 GLBL_F12 + 5B40:00069 GLBL_F2 + 5B40:00074 GLBL_F2_2 + 5B40:000DC GLBL_F3 + 5B40:000F4 GLBL_F4 + 5B40:00112 GLBL_F4_2 + 5B40:00132 GLBL_F5 + 5B40:00182 GLBL_F6 + 5B40:00208 GLBL_F8 + 5B40:00211 GLBL_F9 + 5B40:0033C GLBL_GETCURRENTMODE + 5B40:00300 GLBL_GETHEADERMODE + 5B40:003A1 GLBL_LEFTBRACE + 5B40:003C7 GLBL_LEFTSQUAREBRACKET + 5B40:001AF GLBL_LOADINSTRUMENT + 5B40:00197 GLBL_LOADSAMPLE + 5B40:00411 GLBL_RESTOREMODE + 5B40:003B4 GLBL_RIGHTBRACE + 5B40:003DA GLBL_RIGHTSQUAREBRACKET + 5B40:003ED GLBL_SAVEMODE + 5B40:00337 GLBL_SETCURRENTMODE + 5B40:001C7 GLBL_SHIFT_F1 + 5B40:001F2 GLBL_SHIFT_F6 + 5B40:001DA GLBL_SHIFT_F9 + 5B40:00479 GLBL_TIMERSCREEN + 0000:01E1D GLOBALKEYLIST + 0000:01E1E HELPKEYVALUE + 6315:0228C H_DRAWHELP + 6315:022FD H_HELP + 6315:0232F H_HELPDOWN + 6315:02377 H_HELPESC + 6315:0236D H_HELPPGDN + 6315:0235A H_HELPPGUP + 6315:0231F H_HELPUP + 6315:0238C H_SETHELPCONTEXT + 3D02:00227 IDLEUPDATEINFOLINE + 466D:00C8F INITMOUSE + 3D02:00110 INITTIMERHANDLER + 5DCD:0000C INSTRUMENTAMPLIFICATION + 3D34:00264 INSTRUMENTDIRECTORY + 5DCD:0013D INSTRUMENTEDIT + 5DCD:0000E INSTRUMENTSCREEN + 4793:00A23 ISSTARTUPKEYLIST + 5DCD:01AB6 I_AMPLIFYSAMPLE + 5DCD:01116 I_CALCULATEC5SPEED + 5DCD:019CF I_CENTERSAMPLE + 5DCD:00E8D I_CHECKLOOPVALUES + 5DCD:00ECB I_CHECKSUSLOOPVALUES + 5DCD:01372 idle I_CLEARSAMPLENAME + 5DCD:034BD I_CLEARTABLES + 5DCD:01174 I_CONVERTSAMPLE + 5DCD:028EF I_COPYINSTRUMENT + 5DCD:01320 I_CUTSAMPLE + 5DCD:0124F I_CUTSAMPLEBEFORELOOP + 5DCD:0353D I_DECREASEPLAYCHANNEL + 5DCD:01131 I_DELETEINSTRUMENT + 5DCD:010DE I_DELETESAMPLE + 5DCD:027C1 I_DOUBLESAMPLESPEED + 5DCD:029F5 I_DRAWENVELOPE + 5DCD:01F7A I_DRAWINSTRUMENTWINDOW + 5DCD:0233F I_DRAWNOTEWINDOW + 5DCD:035A1 I_DRAWPITCHPANCENTER + 5DCD:00A71 I_DRAWSAMPLELIST + 5DCD:00F09 I_DRAWWAVEFORM + 5DCD:02781 I_EXCHANGEINSTRUMENTS + 5DCD:015D7 I_EXCHANGESAMPLES + 5DCD:00987 I_GETINSTRUMENTOFFSET + 5DCD:00981 I_GETINSTRUMENTSCREEN + 5DCD:0368C I_GETPRESETENVELOPEOFFSET + 5DCD:0099A I_GETSAMPLEOFFSET + 5DCD:027E1 I_HALVESAMPLESPEED + 5DCD:03635 I_IDLEUPDATEENVELOPE + 5DCD:03522 I_INCREASEPLAYCHANNEL + 5DCD:033D6 I_INSTRUMENTLISTNOTEOFF + 5DCD:033A9 I_INSTRUMENTLISTSPACE + 5DCD:011DC I_INVERTSAMPLE + 5DCD:02B39 I_MAPENVELOPE + 5DCD:02157 I_PLAYNOTE + 5DCD:03505 I_PLAYSAMPLE + 5DCD:02A8D I_POSTENVELOPE + 5DCD:021EA I_POSTINSTRUMENTWINDOW + 5DCD:02437 I_POSTNOTEWINDOW + 5DCD:035E3 I_POSTPITCHPANCENTER + 5DCD:00BC3 I_POSTSAMPLELIST + 5DCD:02A85 I_PREENVELOPE + 5DCD:02035 I_PREINSTRUMENTWINDOW + 5DCD:023FB I_PRENOTEWINDOW + 5DCD:035D3 I_PREPITCHPANCENTER + 5DCD:00B68 I_PRESAMPLELIST + 5DCD:0111A I_PRINTC5FREQUENCY + 5DCD:0282E I_REPLACEINSTRUMENT + 5DCD:016A0 I_REPLACESAMPLE + 5DCD:0196A I_RESIZESAMPLE + 5DCD:01972 I_RESIZESAMPLENOINT + 5DCD:01BEE I_REVERSESAMPLE + 5DCD:03675 I_SAMPLEBUTTONHANDLER + 5DCD:00D5D I_SAMPLEDOWN + 5DCD:02813 I_SAMPLESPEEDSEMIDOWN + 5DCD:027F2 I_SAMPLESPEEDSEMIUP + 5DCD:00D7A I_SAMPLEUP + 5DCD:028A5 I_SCALEINSTRUMENTVOLUMES + 5DCD:0285B I_SCALESAMPLEVOLUMES + 5DCD:009C2 I_SELECTSCREEN + 5DCD:0343E I_SHOWINSTRUMENTPLAY + 5DCD:00E25 I_SHOWSAMPLEINFO + 5DCD:033F2 I_SHOWSAMPLEPLAY + 5DCD:02917 I_SWAPINSTRUMENTS + 5DCD:0161C I_SWAPSAMPLES + 5DCD:034CA I_TAGINSTRUMENT + 5DCD:034D1 I_TAGSAMPLE + 5DCD:03589 I_TOGGLEMULTICHANNEL + 5DCD:01DA6 I_TOGGLESAMPLEQUALITY + 5DCD:02966 I_UPDATEINSTRUMENT + 654E:00966 K_CLEARKEYBOARDQUEUE + 654E:009A6 K_DRAWTABLES + 654E:0070B K_GETKEY + 654E:005EA K_INITKEYBOARD + 654E:00693 K_INSTALLDOSHANDLER + 654E:00A46 K_INSTALLKEYBOARDTYPE + 654E:00977 K_ISANYKEYDOWN + 654E:0098F K_ISKEYDOWN + 654E:006D7 K_ISKEYWAITING + 654E:00A9B K_REMOVEKEYBOARDTYPE + 654E:00996 K_RESETKEYBOARDTABLES + 654E:00AAD K_SETSCROLLLOCK + 654E:00A23 K_SHOWMIDIINPUT + 654E:00651 K_UNINITKEYBOARD + 654E:006B3 K_UNINSTALLDOSHANDLER + 484B:00FEF LASTINSTRUMENT + 484B:00086 idle LASTKEYBOARD1 + 0000:02184 idle LOGOCHARACTER + 3D34:05FB5 LSWINDOW_DOWN + 3D34:05FA1 LSWINDOW_UP + 5DCD:00127 MAXNODE + 484B:00024 MAXROW + 484B:00D79 MIDIAMPLIFICATION + 654E:00AB6 MIDIBUFFEREMPTY + 484B:00D7A MIDICENTRALNOTE + 4DE4:09966 MIDIDATAAREA + 654E:00ABD MIDISEND + 5DCD:0207B MIDI_ALLOCATECHANNEL + 5DCD:020CD MIDI_CLEARTABLE + 5DCD:020C3 MIDI_FINDCHANNEL + 5DCD:020BB MIDI_GETCHANNEL + 5DCD:020E2 MIDI_NOTEOFF + 5DCD:0210F MIDI_PLAYNOTE + 5DCD:034D8 MIDI_PLAYSAMPLE + 484B:056C4 MIDI_SETINSTRUMENT + 65FE:00001 MMTSR_INSTALLMMTSR + 65FE:0006F MMTSR_UNINSTALLMMTSR + 484B:0060B MODIFIED + 466D:00E3D MOUSEADDEVENT + 466D:00000 MOUSECHARACTERGENERATIONOFFSET + 466D:00E61 MOUSECLEAREVENTS + 466D:00E73 MOUSEGETSTATUS + 466D:00DF5 MOUSEINPUT + 466D:00E6A MOUSEREMOVEEVENTS + 466D:00D9B MOUSERESTOREEVENTS + 466D:00D76 MOUSESAVEEVENTS + 466D:00CF1 MOUSESECONDSETDISABLE + 466D:00CEA MOUSESECONDSETENABLE + 466D:00D27 MOUSESETXY + 466D:00CF8 MOUSETOGGLE + 466D:00E86 MOUSEUPDATEDISABLE + 466D:00E7F MOUSEUPDATEENABLE + 6681:01FE5 MSG_DRAWMESSAGE + 6681:0237D MSG_GETMESSAGELENGTH + 6681:02392 MSG_GETMESSAGEOFFSET + 6681:020BE MSG_POSTMESSAGE + 6681:0208F MSG_PREMESSAGE + 6681:01FCB MSG_RESETMESSAGE + 484B:00034 MULTICHANNELINFO + 4DE4:0BDDD MUSIC_ALLOCATEPATTERN + 4DE4:0BEA5 MUSIC_ALLOCATESAMPLE + 4DE4:0D1D6 MUSIC_ASSIGNSAMPLETOINSTRUMENT + 4DE4:0C17E MUSIC_AUTODETECTSOUNDCARD + 4DE4:0C056 MUSIC_CLEARALLINSTRUMENTS + 4DE4:0C001 MUSIC_CLEARALLSAMPLENAMES + 4DE4:0C034 MUSIC_CLEARINSTRUMENT + 4DE4:0BFDE MUSIC_CLEARSAMPLENAME + 4DE4:0D165 MUSIC_DECREASESPEED + 4DE4:0D27F MUSIC_DECREASEVOLUME + 4DE4:0D3B5 MUSIC_GETDELAY + 4DE4:0D1C5 MUSIC_GETDISPLAYVARIABLES + 4DE4:0D3A0 MUSIC_GETDRIVERSCREEN + 4DE4:0D3A5 MUSIC_GETDRIVERVARIABLE + 4DE4:0D336 MUSIC_GETFREESOUNDCARDMEMORY + 4DE4:0CF8F MUSIC_GETHOSTCHANNELINFORMATIONTABLE + 4DE4:0C254 MUSIC_GETINSTRUMENTMODE + 4DE4:0D37C MUSIC_GETLASTCHANNEL + 4DE4:0D546 MUSIC_GETMIDIDATAAREA + 4DE4:0CBEC MUSIC_GETNUMBEROFINSTRUMENTS + 4DE4:0CBC4 MUSIC_GETNUMBEROFSAMPLES + 4DE4:0D33C MUSIC_GETNUMCHANNELS + 4DE4:0BD38 MUSIC_GETPATTERN + 4DE4:0D518 MUSIC_GETPATTERNLENGTH + 4DE4:0BD80 MUSIC_GETPATTERNLOCATION + 4DE4:0BD89 MUSIC_GETPATTERNLOCATIONNOCOUNT + 4DE4:0D341 MUSIC_GETPITCHTABLE + 4DE4:0CC9A MUSIC_GETPLAYMODE + 4DE4:0CCB2 MUSIC_GETPLAYMODE2 + 4DE4:0CC22 MUSIC_GETSAMPLELOCATION + 4DE4:0CF95 MUSIC_GETSLAVECHANNELINFORMATIONTABLE + 4DE4:0C082 MUSIC_GETSONGSEGMENT + 4DE4:0BC51 MUSIC_GETWAVEFORM + 4DE4:0D14C MUSIC_INCREASESPEED + 4DE4:0D263 MUSIC_INCREASEVOLUME + 4DE4:0D360 MUSIC_INITMIXTABLE + 4DE4:0BCAF MUSIC_INITMUSIC + 4DE4:0D115 MUSIC_INITMUTETABLE + 4DE4:0D134 MUSIC_INITSTEREO + 4DE4:0CD6D MUSIC_KBPLAYSONG + 4DE4:0CFCA MUSIC_LASTORDER + 4DE4:0CF9E MUSIC_NEXTORDER + 4DE4:0D35B MUSIC_PATTERNSTORAGE + 4DE4:0CEB7 MUSIC_PLAYNOTE + 4DE4:0CD2C MUSIC_PLAYPARTSONG + 4DE4:0CCCB MUSIC_PLAYPATTERN + 4DE4:0CF39 MUSIC_PLAYSAMPLE + 4DE4:0CCF5 MUSIC_PLAYSONG + 4DE4:0BC61 MUSIC_POLL + 4DE4:0D298 MUSIC_REGETLOOPINFORMATION + 4DE4:0BC9F MUSIC_REINITSOUNDCARD + 4DE4:0C023 MUSIC_RELEASEALLPATTERNS + 4DE4:0C012 MUSIC_RELEASEALLSAMPLES + 4DE4:0BCF4 MUSIC_RELEASEPATTERN + 4DE4:0BF62 MUSIC_RELEASESAMPLE + 4DE4:0D25C MUSIC_REVERSECHANNELS + 4DE4:0D51D MUSIC_SAVEMIDICONFIG + 4DE4:0D1BF MUSIC_SETADDRESS + 4DE4:0D1AC MUSIC_SETDMA + 4DE4:0D3AA MUSIC_SETDRIVERVARIABLE + 4DE4:0D006 MUSIC_SETGLOBALVOLUME + 4DE4:0D1B9 MUSIC_SETIRQ + 4DE4:0D256 MUSIC_SETLIMIT + 4DE4:0D1B3 MUSIC_SETMIXSPEED + 4DE4:0D3AF MUSIC_SETNEXTORDER + 4DE4:0D17E MUSIC_SETSOUNDCARD + 4DE4:0D1A1 MUSIC_SETSOUNDCARDDRIVER + 4DE4:0C232 MUSIC_SHOWAUTODETECTSOUNDCARD + 4DE4:0D4FA MUSIC_SHOWTIME + 4DE4:0D0B1 MUSIC_SOLOCHANNEL + 4DE4:0D2E5 MUSIC_SOUNDCARDLOADALLSAMPLES + 4DE4:0D2CE MUSIC_SOUNDCARDLOADSAMPLE + 4DE4:0CDC0 MUSIC_STOP + 4DE4:0D421 MUSIC_TIMESONG + 4DE4:0D079 MUSIC_TOGGLECHANNEL + 4DE4:0D54C MUSIC_TOGGLEORDERUPDATE + 4DE4:0D347 MUSIC_TOGGLEREVERSE + 4DE4:0D561 MUSIC_TOGGLESOLOINSTRUMENT + 4DE4:0D56C MUSIC_TOGGLESOLOSAMPLE + 4DE4:0C061 MUSIC_UNINITMUSIC + 4DE4:0D0AA MUSIC_UNMUTEALL + 4DE4:0CEAF MUSIC_UPDATEPATTERNOFFSET + 475C:000F1 M_FUNCTIONDIVIDER + 475C:00169 M_FUNCTIONHANDLER + 475C:00363 M_OBJECT1LIST + 475C:00360 M_OBJECT1LISTDEFAULT + 3D34:085C9 NETWORK_ADDWORDTOQUEUE + 3D34:07B02 NETWORK_DRAWDRIVERSCREEN + 3D34:07A63 NETWORK_DRIVERSCREEN + 3D34:08613 NETWORK_ENSURENONETWORK + 3D34:08496 NETWORK_FINISHEDSENDQUEUE + 3D34:0846A NETWORK_GETSENDQUEUE + 3D34:07D45 NETWORK_POLL + 3D34:07BD5 NETWORK_POSTDRIVERSCREEN + 3D34:07B7F NETWORK_PREDRIVERSCREEN + 3D34:084D6 NETWORK_QUEUESAMPLEDATA + 3D34:08647 NETWORK_SENDINSTRUMENTHEADER + 3D34:08630 NETWORK_SENDSAMPLEHEADER + 3D34:0865E NETWORK_SENDSONGDATAINFORMATION + 3D34:07D7B NETWORK_SHUTDOWN + 3D34:085EF NETWORK_UPDATEPATTERN + 3D34:085DA NETWORK_UPDATEPATTERNIFIDLE + 466D:00E78 NEWCHARACTERSET + 5DCD:00121 NEWSAMPLESIZE + 5DCD:00135 NODEHELD + 484B:00026 NUMBEROFROWS + 0000:00000 O1_AUTODETECTLIST + 0000:00325 O1_C5FREQUENCYLIST + 0000:0373C O1_CONFIGUREITLIST + 0000:05172 O1_CONFIGUREPALETTELIST + 0000:02608 O1_CONFIRMCLEARMESSAGE + 0000:024FA O1_CONFIRMCONVERT2LIST + 0000:024E8 O1_CONFIRMCONVERTLIST + 0000:025D2 O1_CONFIRMCUTSAMPLE + 0000:02566 O1_CONFIRMDELETE + 0000:02578 O1_CONFIRMDELETE2 + 0000:0258A O1_CONFIRMDELETE3 + 0000:025F6 O1_CONFIRMDELETEINSTRUMENT + 0000:025E4 O1_CONFIRMDELETESAMPLE + 0000:025C0 O1_CONFIRMDISCARDLIST + 0000:0261A O1_CONFIRMNOSAVE + 0000:02542 O1_CONFIRMOVERWRITELIST + 0000:028F1 O1_CONFIRMQUIT + 0000:025AE O1_CONFIRMRESAVELIST + 0000:0259C O1_CONFIRMSAVERENAMELIST + 0000:02EA5 O1_COPYINSTRUMENTLIST + 0000:00365 O1_CRASHRECOVERY + 0000:046A3 O1_DISPLAYLIST + 0000:05128 O1_EDITSAMPLENAME + 0000:0082E O1_EMPTYLIST + 0000:00335 O1_EMSWARNINGMESSAGE + 0000:0251E O1_ENABLEINSTRUMENTMODE + 0000:02EB7 O1_EXCHANGEINSTRUMENTLIST + 0000:02E4B O1_EXCHANGESAMPLELIST + 0000:04B7C O1_FILEMENU + 0000:063A5 O1_FOURIERDISPLAY + 0000:046B7 O1_FULLDISPLAYLIST + 0000:002CD O1_GETAMPLIST + 0000:002F9 O1_GETFASTAMPLIST + 0000:002E3 O1_GETINSTRUMENTAMPLIST + 0000:000BE O1_HELPLIST + 0000:02554 O1_INITIALISEINSTRUMENTLIST + 0000:02530 O1_INITINSTRUMENT + 0000:03BC6 O1_INSTRUMENTLISTGENERAL + 0000:041E0 O1_INSTRUMENTLISTPANNING + 0000:043B8 O1_INSTRUMENTLISTPITCH + 0000:03F23 O1_INSTRUMENTLISTVOLUME + 0000:05071 O1_INSTRUMENTMENU + 0000:03B06 O1_KEYBOARDLIST + 0000:007FE O1_LOAD669LIST + 0000:05A4C O1_LOADINSTRUMENTLIST + 0000:00816 O1_LOADITLIST + 0000:007E6 O1_LOADMODLIST + 0000:006FA O1_LOADMODULELIST + 0000:007CE O1_LOADMTMLIST + 0000:00758 O1_LOADNETWORKDRIVER + 0000:0079E O1_LOADS3MLIST + 0000:00373 O1_LOADSAMPLELIST + 0000:007B6 O1_LOADXMLIST + 0000:0026D O1_LONGMESSAGELIST + 0000:04942 O1_MAINMENU + 0000:05B2B O1_MESSAGELIST + 0000:05FBC O1_MIDISCREEN + 0000:00345 O1_NETWORKERRORLIST + 0000:04731 O1_NEWSONGLIST + 0000:002AD O1_NOBLOCKDATALIST + 0000:0022D O1_NOBLOCKMARKEDLIST + 0000:0001E O1_ORDERPANNINGLIST + 0000:0309C O1_ORDERVOLUMELIST + 0000:0024D O1_OUTOFMEMORYLIST + 0000:0027D O1_OUTOFSAMPLESLIST + 0000:0023D O1_OUTOFSOUNDCARDMEMORYLIST + 0000:0028D O1_OVERLAPBLOCKLIST + 0000:000D4 O1_PATTERNEDITLIST + 0000:0025D O1_PATTERNSIZEMISMATCHLIST + 0000:002BD O1_PATTERNTOOLONGLIST + 0000:000E8 O1_PECONFIGLIST + 0000:04D0F O1_PLAYBACKMENU + 0000:02E6F O1_REPLACEINSTRUMENTLIST + 0000:02E5D O1_REPLACESAMPLELIST + 0000:02EC9 O1_RESIZESAMPLELIST + 0000:0030F O1_SAMPLEAMPLIFICATIONLIST + 0000:0250C O1_SAMPLECENTERLIST + 0000:0068C O1_SAMPLELIST + 0000:04F87 O1_SAMPLEMENU + 0000:0076E O1_SAVEITLIST + 0000:00726 O1_SAVEMODULELIST + 0000:00786 O1_SAVES3MLIST + 0000:02903 O1_SELECTMULTICHANNEL + 0000:0011C O1_SETPATTERNLENGTH + 0000:06378 O1_SHOWTIME + 0000:062E4 O1_STEREOSAMPLELIST + 0000:02E93 O1_SWAPINSTRUMENTLIST + 0000:0029D O1_SWAPOUTOFRANGELIST + 0000:02E81 O1_SWAPSAMPLELIST + 0000:00355 O1_TEMPLATEERRORLIST + 0000:046EC O1_THUMBSTRINGLIST + 0000:0626C O1_TIMERLIST + 0000:028A2 O1_UNABLETOSAVELIST + 0000:05AF5 O1_UNDOLIST + 0000:05A7B O1_VIEWINSTRUMENTLIBRARY + 0000:003B9 O1_VIEWSAMPLELIBRARY + 484B:0001A ORDER + 0000:01E87 ORDERKEYVALUE + 459B:00028 PALETTEDEFS + 484B:0000A PATTERNDATAAREA + 484B:0087E PATTERNLENGTHEND + 484B:0087C PATTERNLENGTHSTART + 484B:0060C PATTERNMODIFIED + 484B:0001E PATTERNNUMBER + 484B:0087A PATTERNSETLENGTH + 484B:05625 PECHECKMODIFIED + 484B:02769 PEFUNCTION_DECREASEOCTAVE + 484B:05524 PEFUNCTION_DRAWUNDO + 484B:02779 PEFUNCTION_INCREASEOCTAVE + 484B:031B4 PEFUNCTION_OUTOFMEMORYMESSAGE + 484B:05577 PEFUNCTION_POSTUNDO + 484B:0555A PEFUNCTION_PREUNDO + 484B:03A6D PEFUNCTION_STORECURRENTPATTERN + 484B:05643 PERESETMODIFIED + 484B:054EB idle PE_CLEARUNDOBUFFER + 484B:01054 PE_CONVAX2NUM + 484B:0513F PE_DELETEINSTRUMENT + 484B:012E6 PE_DRAWORDERLIST + 484B:01673 PE_DRAWPATTERNEDIT + 484B:05372 PE_F7 + 484B:011E0 PE_FILLHEADER + 484B:012C9 PE_FILLSPEEDTEMPO + 484B:046A4 PE_GETCURRENTPATTERN + 484B:04FBC PE_GETLASTINSTRUMENT + 484B:0109C PE_GETMAXORDER + 484B:011B9 PE_GETMAXPATTERN + 484B:0543D PE_GETPATTERNCONFIGOFFSET + 484B:03A97 PE_GOTOPATTERN + 484B:015DB PE_INITPATTERNEDIT + 484B:0508C PE_INSERTINSTRUMENT + 484B:0597F PE_NEWPATTERN + 484B:013BA PE_POSTORDERLIST + 484B:01D00 PE_POSTPATTERNEDIT + 484B:01376 PE_PREORDERLIST + 484B:01B41 PE_PREPATTERNEDIT + 484B:0114E PE_RESETORDERPATTERN + 484B:05966 PE_RESTORECURRENTPATTERN + 484B:058FC PE_RESTOREMIDINOTE + 484B:05948 PE_SAVECURRENTPATTERN + 484B:02A4C PE_SETCOMMANDCURSOR + 484B:05940 PE_SETPATTERNMODIFIED + 484B:052FE PE_SHOWORDER + 484B:04FC4 PE_SWAPINSTRUMENTS + 484B:041C6 PE_TRANSLATE669PATTERN + 484B:058C0 PE_TRANSLATEMIDI + 484B:0414C PE_TRANSLATEMODPATTERN + 484B:040EC PE_TRANSLATEMTMPATTERN + 484B:042D9 PE_TRANSLATES3MPATTERN + 484B:03E98 PE_TRANSLATEXMPATTERN + 484B:015A4 PE_UNINITPATTERNEDIT + 484B:051ED PE_UPDATEINSTRUMENTS + 5B89:0184A POSTDISPLAYDATA + 4793:009C5 QUIT + 4793:00AF2 REFRESH + 475C:000F0 RELEASETIMESLICE + 466D:008C8 RESTOREMOUSE + 466D:00922 RESTOREMOUSEGRAPHICS + 484B:00CA8 ROWHILIGHT1 + 484B:00CA9 ROWHILIGHT2 + 5DCD:00145 SAMPLEAMPLIFICATION + 3D34:0021E SAMPLEDIRECTORY + 3D34:002AB SAMPLENAME + 5DCD:00011 SAMPLENUMBER + 5DCD:0011D SAMPLENUMBERINPUT + 3D02:0024E SETINFOLINE + 3D02:00264 SETINFOLINE2 + 466D:00DC0 SETKEYBOARDLOCK + 466D:00E8D SETMOUSECURSORTYPE + 3D02:000F8 SHOWUSAGETIME + 484B:00032 SKIPVALUE + 4DE4:09964 SONGDATAAREA + 3D34:001D8 SONGDIRECTORY + 3D02:00317 STARTCLOCK + 459B:00975 S_CLEARSCREEN + 459B:00CA5 S_DEFINEHIASCII + 459B:008B7 S_DEFINESMALLNUMBERS + 459B:00AA8 S_DIRECTDRAWSTRING + 459B:0098A S_DRAWBOX + 459B:00C62 S_DRAWSMALLBOX + 459B:00ABD S_DRAWSTRING + 459B:00BE2 S_GENERATECHARACTERS + 459B:00960 S_GETDESTINATION + 459B:00BD9 S_GETGENERATIONTABLEOFFSET + 459B:00C7E S_GETPALETTEOFFSET + 459B:00A99 S_HILIGHT + 459B:006B7 S_INITSCREEN + 459B:00CE5 S_INVERTCURSOR + 459B:00871 S_REDEFINECHARACTERS + 459B:0084B S_RESETSEQUENCER + 459B:0078C S_RESTORESCREEN + 459B:0076A S_SAVESCREEN + 459B:00A59 S_SETDIRECTMODE + 459B:007FD S_SETPALETTE + 459B:007F9 S_SETPALETTE2 + 459B:00825 S_SETSEQUENCER + 459B:0094F S_UNINITSCREEN + 459B:009F8 S_UPDATESCREEN + 459B:00C84 S_USEPRESETPALETTE + 6136:000D8 THUMBSTRINGENTER + 466D:00CE5 UNINITMOUSE + 3D02:0012C UNINITTIMERHANDLER + 3D02:00152 UPDATEINFOLINE + 5DCD:03671 UPDATEWAVEFORM + 68BB:00201 VESA_DETECT + 68BB:00244 idle VESA_GETINFO + 68BB:0025B VESA_SETBLOCK + 68BB:00221 VESA_SETMODE + 459B:006A5 VGAFLAGS + + Address Publics by Value + + 0000:063A5 O1_FOURIERDISPLAY + 0000:06378 O1_SHOWTIME + 0000:062E4 O1_STEREOSAMPLELIST + 0000:0626C O1_TIMERLIST + 0000:05FBC O1_MIDISCREEN + 0000:05B2B O1_MESSAGELIST + 0000:05AF5 O1_UNDOLIST + 0000:05A7B O1_VIEWINSTRUMENTLIBRARY + 0000:05A4C O1_LOADINSTRUMENTLIST + 0000:05172 O1_CONFIGUREPALETTELIST + 0000:05128 O1_EDITSAMPLENAME + 0000:05071 O1_INSTRUMENTMENU + 0000:04F87 O1_SAMPLEMENU + 0000:04D0F O1_PLAYBACKMENU + 0000:04B7C O1_FILEMENU + 0000:04942 O1_MAINMENU + 0000:04731 O1_NEWSONGLIST + 0000:046EC O1_THUMBSTRINGLIST + 0000:046B7 O1_FULLDISPLAYLIST + 0000:046A3 O1_DISPLAYLIST + 0000:043B8 O1_INSTRUMENTLISTPITCH + 0000:041E0 O1_INSTRUMENTLISTPANNING + 0000:03F23 O1_INSTRUMENTLISTVOLUME + 0000:03BC6 O1_INSTRUMENTLISTGENERAL + 0000:03B06 O1_KEYBOARDLIST + 0000:0373C O1_CONFIGUREITLIST + 0000:0309C O1_ORDERVOLUMELIST + 0000:02EC9 O1_RESIZESAMPLELIST + 0000:02EB7 O1_EXCHANGEINSTRUMENTLIST + 0000:02EA5 O1_COPYINSTRUMENTLIST + 0000:02E93 O1_SWAPINSTRUMENTLIST + 0000:02E81 O1_SWAPSAMPLELIST + 0000:02E6F O1_REPLACEINSTRUMENTLIST + 0000:02E5D O1_REPLACESAMPLELIST + 0000:02E4B O1_EXCHANGESAMPLELIST + 0000:02903 O1_SELECTMULTICHANNEL + 0000:028F1 O1_CONFIRMQUIT + 0000:028A2 O1_UNABLETOSAVELIST + 0000:0261A O1_CONFIRMNOSAVE + 0000:02608 O1_CONFIRMCLEARMESSAGE + 0000:025F6 O1_CONFIRMDELETEINSTRUMENT + 0000:025E4 O1_CONFIRMDELETESAMPLE + 0000:025D2 O1_CONFIRMCUTSAMPLE + 0000:025C0 O1_CONFIRMDISCARDLIST + 0000:025AE O1_CONFIRMRESAVELIST + 0000:0259C O1_CONFIRMSAVERENAMELIST + 0000:0258A O1_CONFIRMDELETE3 + 0000:02578 O1_CONFIRMDELETE2 + 0000:02566 O1_CONFIRMDELETE + 0000:02554 O1_INITIALISEINSTRUMENTLIST + 0000:02542 O1_CONFIRMOVERWRITELIST + 0000:02530 O1_INITINSTRUMENT + 0000:0251E O1_ENABLEINSTRUMENTMODE + 0000:0250C O1_SAMPLECENTERLIST + 0000:024FA O1_CONFIRMCONVERT2LIST + 0000:024E8 O1_CONFIRMCONVERTLIST + 0000:02184 idle LOGOCHARACTER + 0000:01E87 ORDERKEYVALUE + 0000:01E1E HELPKEYVALUE + 0000:01E1D GLOBALKEYLIST + 0000:01016 EMSERRORVALUE + 0000:01014 EMSERRORVALUE2 + 0000:01012 EMSERRORVALUE3 + 0000:01010 EMSERRORVALUE8 + 0000:0100E EMSERRORVALUE4 + 0000:0100C EMSERRORVALUE5 + 0000:0100A EMSERRORVALUE6 + 0000:01008 EMSERRORVALUE7 + 0000:0082E O1_EMPTYLIST + 0000:00816 O1_LOADITLIST + 0000:007FE O1_LOAD669LIST + 0000:007E6 O1_LOADMODLIST + 0000:007CE O1_LOADMTMLIST + 0000:007B6 O1_LOADXMLIST + 0000:0079E O1_LOADS3MLIST + 0000:00786 O1_SAVES3MLIST + 0000:0076E O1_SAVEITLIST + 0000:00758 O1_LOADNETWORKDRIVER + 0000:00726 O1_SAVEMODULELIST + 0000:006FA O1_LOADMODULELIST + 0000:0068C O1_SAMPLELIST + 0000:003B9 O1_VIEWSAMPLELIBRARY + 0000:00373 O1_LOADSAMPLELIST + 0000:00365 O1_CRASHRECOVERY + 0000:00355 O1_TEMPLATEERRORLIST + 0000:00345 O1_NETWORKERRORLIST + 0000:00335 O1_EMSWARNINGMESSAGE + 0000:00325 O1_C5FREQUENCYLIST + 0000:0030F O1_SAMPLEAMPLIFICATIONLIST + 0000:002F9 O1_GETFASTAMPLIST + 0000:002E3 O1_GETINSTRUMENTAMPLIST + 0000:002CD O1_GETAMPLIST + 0000:002BD O1_PATTERNTOOLONGLIST + 0000:002AD O1_NOBLOCKDATALIST + 0000:0029D O1_SWAPOUTOFRANGELIST + 0000:0028D O1_OVERLAPBLOCKLIST + 0000:0027D O1_OUTOFSAMPLESLIST + 0000:0026D O1_LONGMESSAGELIST + 0000:0025D O1_PATTERNSIZEMISMATCHLIST + 0000:0024D O1_OUTOFMEMORYLIST + 0000:0023D O1_OUTOFSOUNDCARDMEMORYLIST + 0000:0022D O1_NOBLOCKMARKEDLIST + 0000:0011C O1_SETPATTERNLENGTH + 0000:000E8 O1_PECONFIGLIST + 0000:000D4 O1_PATTERNEDITLIST + 0000:000BE O1_HELPLIST + 0000:0001E O1_ORDERPANNINGLIST + 0000:00000 O1_AUTODETECTLIST + 3D02:00326 GETTIMERCOUNTER + 3D02:00317 STARTCLOCK + 3D02:00264 SETINFOLINE2 + 3D02:0024E SETINFOLINE + 3D02:00243 CLEARINFOLINE + 3D02:00227 IDLEUPDATEINFOLINE + 3D02:00152 UPDATEINFOLINE + 3D02:0012C UNINITTIMERHANDLER + 3D02:00110 INITTIMERHANDLER + 3D02:000F8 SHOWUSAGETIME + 3D34:0865E NETWORK_SENDSONGDATAINFORMATION + 3D34:08647 NETWORK_SENDINSTRUMENTHEADER + 3D34:08630 NETWORK_SENDSAMPLEHEADER + 3D34:08613 NETWORK_ENSURENONETWORK + 3D34:085EF NETWORK_UPDATEPATTERN + 3D34:085DA NETWORK_UPDATEPATTERNIFIDLE + 3D34:085C9 NETWORK_ADDWORDTOQUEUE + 3D34:084D6 NETWORK_QUEUESAMPLEDATA + 3D34:08496 NETWORK_FINISHEDSENDQUEUE + 3D34:0846A NETWORK_GETSENDQUEUE + 3D34:07D7B NETWORK_SHUTDOWN + 3D34:07D45 NETWORK_POLL + 3D34:07BD5 NETWORK_POSTDRIVERSCREEN + 3D34:07B7F NETWORK_PREDRIVERSCREEN + 3D34:07B02 NETWORK_DRAWDRIVERSCREEN + 3D34:07A63 NETWORK_DRIVERSCREEN + 3D34:07712 D_SLOWINSTRUMENTSORT + 3D34:07670 D_SLOWSAMPLESORT + 3D34:0755A D_DRAWTIMER + 3D34:074FC D_POSTTIMERLIST + 3D34:07451 D_SHOWTIME + 3D34:07420 D_RESETTIMER + 3D34:0741A D_GETFILENAME + 3D34:07416 D_SETDRIVEDIRECTORYFAR + 3D34:0740D D_RESTOREPRESHELLDIRECTORY + 3D34:073FE D_GETPRESHELLDIRECTORY + 3D34:06B60 D_VIEWINSTRUMENT + 3D34:06B4F D_POSTLOADINSTRUMENT + 3D34:06B22 D_PRELOADINSTRUMENT + 3D34:069D1 D_DRAWLOADINSTRUMENT + 3D34:0696A D_LOADINSTRUMENTNAMES + 3D34:0684F D_INITLOADINSTRUMENTS + 3D34:0676E D_DISABLEFILECOLOURS + 3D34:06768 D_GETFORMATTYPE + 3D34:06753 D_CLEARFILENAME + 3D34:065AE D_DRAWWAVEFORM + 3D34:06403 idle D_DELETESAMPLEFILE + 3D34:062BC D_SAVEINSTRUMENT + 3D34:0620D D_SAVEST3SAMPLE + 3D34:06166 D_SAVERAWSAMPLE + 3D34:06100 D_SAVESAMPLE + 3D34:0607A D_SAVESONG + 3D34:06049 D_LSCHECKSUSLOOPVALUES + 3D34:06018 D_LSCHECKLOOPVALUES + 3D34:05FB5 LSWINDOW_DOWN + 3D34:05FA1 LSWINDOW_UP + 3D34:050BA D_SAVEDIRECTORYCONFIGURATION + 3D34:050AF D_GOTOSTARTINGDIRECTORY + 3D34:0509B D_GETLOADSAMPLEVARS + 3D34:05037 D_LOADSAMPLENAMES + 3D34:047A9 D_LIPOSTDRIVEWINDOW + 3D34:04787 D_LIPREDRIVEWINDOW + 3D34:04750 D_LIDRAWDRIVEWINDOW + 3D34:0473F D_LSPOSTDRIVEWINDOW + 3D34:0471B D_LSPREDRIVEWINDOW + 3D34:046C7 D_LSDRAWDRIVEWINDOW + 3D34:046B7 D_POSTVIEWSAMPLELIBRARY + 3D34:0462D D_POSTLOADSAMPLEWINDOW + 3D34:045FE D_PRELOADSAMPLEWINDOW + 3D34:04355 D_DRAWLOADSAMPLEWINDOW + 3D34:040E4 D_INITLOADSAMPLES + 3D34:03AD6 D_SAVES3M + 3D34:03617 D_SAVEIT + 3D34:0347B D_SAVEMODULE + 3D34:03466 D_CLEARFILESPECIFIER + 3D34:0344A D_NEWDIRECTORY + 3D34:033BB D_NEWSPECIFIER + 3D34:033AA D_POSTSAVEDRIVEWINDOW + 3D34:03399 D_POSTDRIVEWINDOW + 3D34:03321 D_POSTDIRECTORYWINDOW + 3D34:03298 idle D_POSTFILEWINDOW + 3D34:0322D D_POSTFILELOADWINDOW + 3D34:031EE D_POSTFILESAVEWINDOW + 3D34:02EC0 D_LOADIT + 3D34:02C3D D_LOADMOD + 3D34:02ADC D_LOAD669 + 3D34:0283A D_LOADS3M + 3D34:0259C D_LOADMTM + 3D34:0214E D_LOADXM + 3D34:018EE D_PREDRIVEWINDOW + 3D34:018C8 D_PREDIRECTORYWINDOW + 3D34:01889 D_PREFILEWINDOW + 3D34:01858 D_LOADSONGNAMES + 3D34:0173D D_DRAWDRIVEWINDOW + 3D34:016CD D_DRAWDIRECTORYWINDOW + 3D34:014B0 D_DRAWFILEWINDOW + 3D34:01469 D_INITLOADMODULE + 3D34:01292 D_UNINITDISK + 3D34:010A6 D_INITDISK + 3D34:00F34 DISKOPTIONS + 3D34:002AB SAMPLENAME + 3D34:00264 INSTRUMENTDIRECTORY + 3D34:0021E SAMPLEDIRECTORY + 3D34:001D8 SONGDIRECTORY + 3D34:000C4 FILESPECIFIER + 3D34:00066 FILENAME + 3D34:00010 DISKDATAAREA + 459B:00CE5 S_INVERTCURSOR + 459B:00CA5 S_DEFINEHIASCII + 459B:00C84 S_USEPRESETPALETTE + 459B:00C7E S_GETPALETTEOFFSET + 459B:00C62 S_DRAWSMALLBOX + 459B:00BE2 S_GENERATECHARACTERS + 459B:00BD9 S_GETGENERATIONTABLEOFFSET + 459B:00ABD S_DRAWSTRING + 459B:00AA8 S_DIRECTDRAWSTRING + 459B:00A99 S_HILIGHT + 459B:00A59 S_SETDIRECTMODE + 459B:009F8 S_UPDATESCREEN + 459B:0098A S_DRAWBOX + 459B:00975 S_CLEARSCREEN + 459B:00960 S_GETDESTINATION + 459B:0094F S_UNINITSCREEN + 459B:008B7 S_DEFINESMALLNUMBERS + 459B:00871 S_REDEFINECHARACTERS + 459B:0084B S_RESETSEQUENCER + 459B:00825 S_SETSEQUENCER + 459B:007FD S_SETPALETTE + 459B:007F9 S_SETPALETTE2 + 459B:0078C S_RESTORESCREEN + 459B:0076A S_SAVESCREEN + 459B:006B7 S_INITSCREEN + 459B:006A5 VGAFLAGS + 459B:006A3 CHARACTERGENERATIONOFFSET + 459B:00028 PALETTEDEFS + 466D:00EE2 FORCEMOUSERESTORE + 466D:00EDA CMDLINEDISABLEMOUSE + 466D:00E8D SETMOUSECURSORTYPE + 466D:00E86 MOUSEUPDATEDISABLE + 466D:00E7F MOUSEUPDATEENABLE + 466D:00E78 NEWCHARACTERSET + 466D:00E73 MOUSEGETSTATUS + 466D:00E6A MOUSEREMOVEEVENTS + 466D:00E61 MOUSECLEAREVENTS + 466D:00E3D MOUSEADDEVENT + 466D:00DF5 MOUSEINPUT + 466D:00DCA ADDMOUSEQUEUE + 466D:00DC5 GETKEYBOARDLOCK + 466D:00DC0 SETKEYBOARDLOCK + 466D:00D9B MOUSERESTOREEVENTS + 466D:00D76 MOUSESAVEEVENTS + 466D:00D27 MOUSESETXY + 466D:00CF8 MOUSETOGGLE + 466D:00CF1 MOUSESECONDSETDISABLE + 466D:00CEA MOUSESECONDSETENABLE + 466D:00CE5 UNINITMOUSE + 466D:00C8F INITMOUSE + 466D:00B86 DRAWMOUSE + 466D:00922 RESTOREMOUSEGRAPHICS + 466D:008C8 RESTOREMOUSE + 466D:00000 MOUSECHARACTERGENERATIONOFFSET + 475C:00363 M_OBJECT1LIST + 475C:00360 M_OBJECT1LISTDEFAULT + 475C:00169 M_FUNCTIONHANDLER + 475C:000F1 M_FUNCTIONDIVIDER + 475C:000F0 RELEASETIMESLICE + 4793:00B0F DOSSHELL + 4793:00AF2 REFRESH + 4793:00ACB GETENVIRONMENT + 4793:00A9F CRASHRECOVERY + 4793:00A28 GETSTARTUPKEYLIST + 4793:00A23 ISSTARTUPKEYLIST + 4793:009C5 QUIT + 484B:0597F PE_NEWPATTERN + 484B:05966 PE_RESTORECURRENTPATTERN + 484B:05948 PE_SAVECURRENTPATTERN + 484B:05940 PE_SETPATTERNMODIFIED + 484B:058FC PE_RESTOREMIDINOTE + 484B:058C0 PE_TRANSLATEMIDI + 484B:056C4 MIDI_SETINSTRUMENT + 484B:05643 PERESETMODIFIED + 484B:05625 PECHECKMODIFIED + 484B:05577 PEFUNCTION_POSTUNDO + 484B:0555A PEFUNCTION_PREUNDO + 484B:05524 PEFUNCTION_DRAWUNDO + 484B:054EB idle PE_CLEARUNDOBUFFER + 484B:0543D PE_GETPATTERNCONFIGOFFSET + 484B:05372 PE_F7 + 484B:052FE PE_SHOWORDER + 484B:051ED PE_UPDATEINSTRUMENTS + 484B:0513F PE_DELETEINSTRUMENT + 484B:0508C PE_INSERTINSTRUMENT + 484B:04FC4 PE_SWAPINSTRUMENTS + 484B:04FBC PE_GETLASTINSTRUMENT + 484B:046A4 PE_GETCURRENTPATTERN + 484B:042D9 PE_TRANSLATES3MPATTERN + 484B:041C6 PE_TRANSLATE669PATTERN + 484B:0414C PE_TRANSLATEMODPATTERN + 484B:040EC PE_TRANSLATEMTMPATTERN + 484B:03E98 PE_TRANSLATEXMPATTERN + 484B:03A97 PE_GOTOPATTERN + 484B:03A6D PEFUNCTION_STORECURRENTPATTERN + 484B:031B4 PEFUNCTION_OUTOFMEMORYMESSAGE + 484B:02A4C PE_SETCOMMANDCURSOR + 484B:02779 PEFUNCTION_INCREASEOCTAVE + 484B:02769 PEFUNCTION_DECREASEOCTAVE + 484B:01D00 PE_POSTPATTERNEDIT + 484B:01B41 PE_PREPATTERNEDIT + 484B:01673 PE_DRAWPATTERNEDIT + 484B:015DB PE_INITPATTERNEDIT + 484B:015A4 PE_UNINITPATTERNEDIT + 484B:013BA PE_POSTORDERLIST + 484B:01376 PE_PREORDERLIST + 484B:012E6 PE_DRAWORDERLIST + 484B:012C9 PE_FILLSPEEDTEMPO + 484B:011E0 PE_FILLHEADER + 484B:011B9 PE_GETMAXPATTERN + 484B:0114E PE_RESETORDERPATTERN + 484B:0109C PE_GETMAXORDER + 484B:01054 PE_CONVAX2NUM + 484B:00FEF LASTINSTRUMENT + 484B:00D7D FLAGS + 484B:00D7B FASTVOLUMEAMPLIFICATION + 484B:00D7A MIDICENTRALNOTE + 484B:00D79 MIDIAMPLIFICATION + 484B:00D78 CENTRALISECURSOR + 484B:00D77 COMMANDTOVALUE + 484B:00CA9 ROWHILIGHT2 + 484B:00CA8 ROWHILIGHT1 + 484B:0087E PATTERNLENGTHEND + 484B:0087C PATTERNLENGTHSTART + 484B:0087A PATTERNSETLENGTH + 484B:0060C PATTERNMODIFIED + 484B:0060B MODIFIED + 484B:002D8 AMPLIFICATION + 484B:00086 idle LASTKEYBOARD1 + 484B:00034 MULTICHANNELINFO + 484B:00032 SKIPVALUE + 484B:00030 BASEOCTAVE + 484B:00026 NUMBEROFROWS + 484B:00024 MAXROW + 484B:0001E PATTERNNUMBER + 484B:0001A ORDER + 484B:0000A PATTERNDATAAREA + 4DE4:0D56C MUSIC_TOGGLESOLOSAMPLE + 4DE4:0D561 MUSIC_TOGGLESOLOINSTRUMENT + 4DE4:0D54C MUSIC_TOGGLEORDERUPDATE + 4DE4:0D546 MUSIC_GETMIDIDATAAREA + 4DE4:0D51D MUSIC_SAVEMIDICONFIG + 4DE4:0D518 MUSIC_GETPATTERNLENGTH + 4DE4:0D4FA MUSIC_SHOWTIME + 4DE4:0D421 MUSIC_TIMESONG + 4DE4:0D3B5 MUSIC_GETDELAY + 4DE4:0D3AF MUSIC_SETNEXTORDER + 4DE4:0D3AA MUSIC_SETDRIVERVARIABLE + 4DE4:0D3A5 MUSIC_GETDRIVERVARIABLE + 4DE4:0D3A0 MUSIC_GETDRIVERSCREEN + 4DE4:0D37C MUSIC_GETLASTCHANNEL + 4DE4:0D360 MUSIC_INITMIXTABLE + 4DE4:0D35B MUSIC_PATTERNSTORAGE + 4DE4:0D347 MUSIC_TOGGLEREVERSE + 4DE4:0D341 MUSIC_GETPITCHTABLE + 4DE4:0D33C MUSIC_GETNUMCHANNELS + 4DE4:0D336 MUSIC_GETFREESOUNDCARDMEMORY + 4DE4:0D2E5 MUSIC_SOUNDCARDLOADALLSAMPLES + 4DE4:0D2CE MUSIC_SOUNDCARDLOADSAMPLE + 4DE4:0D298 MUSIC_REGETLOOPINFORMATION + 4DE4:0D27F MUSIC_DECREASEVOLUME + 4DE4:0D263 MUSIC_INCREASEVOLUME + 4DE4:0D25C MUSIC_REVERSECHANNELS + 4DE4:0D256 MUSIC_SETLIMIT + 4DE4:0D1D6 MUSIC_ASSIGNSAMPLETOINSTRUMENT + 4DE4:0D1C5 MUSIC_GETDISPLAYVARIABLES + 4DE4:0D1BF MUSIC_SETADDRESS + 4DE4:0D1B9 MUSIC_SETIRQ + 4DE4:0D1B3 MUSIC_SETMIXSPEED + 4DE4:0D1AC MUSIC_SETDMA + 4DE4:0D1A1 MUSIC_SETSOUNDCARDDRIVER + 4DE4:0D17E MUSIC_SETSOUNDCARD + 4DE4:0D165 MUSIC_DECREASESPEED + 4DE4:0D14C MUSIC_INCREASESPEED + 4DE4:0D134 MUSIC_INITSTEREO + 4DE4:0D115 MUSIC_INITMUTETABLE + 4DE4:0D0B1 MUSIC_SOLOCHANNEL + 4DE4:0D0AA MUSIC_UNMUTEALL + 4DE4:0D079 MUSIC_TOGGLECHANNEL + 4DE4:0D006 MUSIC_SETGLOBALVOLUME + 4DE4:0CFCA MUSIC_LASTORDER + 4DE4:0CF9E MUSIC_NEXTORDER + 4DE4:0CF95 MUSIC_GETSLAVECHANNELINFORMATIONTABLE + 4DE4:0CF8F MUSIC_GETHOSTCHANNELINFORMATIONTABLE + 4DE4:0CF39 MUSIC_PLAYSAMPLE + 4DE4:0CEB7 MUSIC_PLAYNOTE + 4DE4:0CEAF MUSIC_UPDATEPATTERNOFFSET + 4DE4:0CDC0 MUSIC_STOP + 4DE4:0CD6D MUSIC_KBPLAYSONG + 4DE4:0CD2C MUSIC_PLAYPARTSONG + 4DE4:0CCF5 MUSIC_PLAYSONG + 4DE4:0CCCB MUSIC_PLAYPATTERN + 4DE4:0CCB2 MUSIC_GETPLAYMODE2 + 4DE4:0CC9A MUSIC_GETPLAYMODE + 4DE4:0CC22 MUSIC_GETSAMPLELOCATION + 4DE4:0CBEC MUSIC_GETNUMBEROFINSTRUMENTS + 4DE4:0CBC4 MUSIC_GETNUMBEROFSAMPLES + 4DE4:0C254 MUSIC_GETINSTRUMENTMODE + 4DE4:0C232 MUSIC_SHOWAUTODETECTSOUNDCARD + 4DE4:0C17E MUSIC_AUTODETECTSOUNDCARD + 4DE4:0C082 MUSIC_GETSONGSEGMENT + 4DE4:0C061 MUSIC_UNINITMUSIC + 4DE4:0C056 MUSIC_CLEARALLINSTRUMENTS + 4DE4:0C034 MUSIC_CLEARINSTRUMENT + 4DE4:0C023 MUSIC_RELEASEALLPATTERNS + 4DE4:0C012 MUSIC_RELEASEALLSAMPLES + 4DE4:0C001 MUSIC_CLEARALLSAMPLENAMES + 4DE4:0BFDE MUSIC_CLEARSAMPLENAME + 4DE4:0BF62 MUSIC_RELEASESAMPLE + 4DE4:0BEA5 MUSIC_ALLOCATESAMPLE + 4DE4:0BDDD MUSIC_ALLOCATEPATTERN + 4DE4:0BD89 MUSIC_GETPATTERNLOCATIONNOCOUNT + 4DE4:0BD80 MUSIC_GETPATTERNLOCATION + 4DE4:0BD38 MUSIC_GETPATTERN + 4DE4:0BCF4 MUSIC_RELEASEPATTERN + 4DE4:0BCAF MUSIC_INITMUSIC + 4DE4:0BC9F MUSIC_REINITSOUNDCARD + 4DE4:0BC61 MUSIC_POLL + 4DE4:0BC51 MUSIC_GETWAVEFORM + 4DE4:09966 MIDIDATAAREA + 4DE4:09964 SONGDATAAREA + 4DE4:00352 CURRENTPATTERN + 5B40:0048C GLBL_DRIVERSCREEN + 5B40:00479 GLBL_TIMERSCREEN + 5B40:00411 GLBL_RESTOREMODE + 5B40:003ED GLBL_SAVEMODE + 5B40:003DA GLBL_RIGHTSQUAREBRACKET + 5B40:003C7 GLBL_LEFTSQUAREBRACKET + 5B40:003B4 GLBL_RIGHTBRACE + 5B40:003A1 GLBL_LEFTBRACE + 5B40:00395 GLBL_ALT_F8 + 5B40:00389 GLBL_ALT_F7 + 5B40:0037D GLBL_ALT_F6 + 5B40:00371 GLBL_ALT_F5 + 5B40:00365 GLBL_ALT_F4 + 5B40:00359 GLBL_ALT_F3 + 5B40:0034D GLBL_ALT_F2 + 5B40:00341 GLBL_ALT_F1 + 5B40:0033C GLBL_GETCURRENTMODE + 5B40:00337 GLBL_SETCURRENTMODE + 5B40:00300 GLBL_GETHEADERMODE + 5B40:002ED GLBL_CTRL_F12 + 5B40:002DD GLBL_CTRL_F5 + 5B40:002C5 GLBL_CTRL_F4 + 5B40:002AD GLBL_CTRL_F3 + 5B40:0029A GLBL_CTRL_F1 + 5B40:00287 GLBL_F12 + 5B40:0025E GLBL_F11_2 + 5B40:00256 GLBL_F11 + 5B40:00231 GLBL_F10 + 5B40:00211 GLBL_F9 + 5B40:00208 GLBL_F8 + 5B40:001F2 GLBL_SHIFT_F6 + 5B40:001DA GLBL_SHIFT_F9 + 5B40:001C7 GLBL_SHIFT_F1 + 5B40:001AF GLBL_LOADINSTRUMENT + 5B40:00197 GLBL_LOADSAMPLE + 5B40:00182 GLBL_F6 + 5B40:00132 GLBL_F5 + 5B40:00112 GLBL_F4_2 + 5B40:000F4 GLBL_F4 + 5B40:000DC GLBL_F3 + 5B40:00074 GLBL_F2_2 + 5B40:00069 GLBL_F2 + 5B40:00003 CURRENTMODE + 5B89:01E9A FOURIER_POSTFUNCTION + 5B89:01E96 FOURIER_IDLELIST + 5B89:01DA5 FOURIER_DRAWSCREEN + 5B89:01DA2 FOURIER_PREDRAWSCREEN + 5B89:01D40 FOURIER_START + 5B89:01C8A FOURIER_CHANGEPALETTE + 5B89:01BB1 FOURIER_TRANSFORM + 5B89:01B86 FOURIER_CREATETABLE + 5B89:01B11 DISPLAY_SELECTDISPLAYLIST + 5B89:01AAC DISPLAY_GETDISPLAYWINDOWDATA + 5B89:01A40 DISPLAYUPDATESCREEN + 5B89:01881 DISPLAYMINUS + 5B89:01878 DISPLAYPLUS + 5B89:0184A POSTDISPLAYDATA + 5B89:0179F DRAWDISPLAYDATA + 5D73:003F7 E_GETINTERNALEMSHANDLE + 5D73:003F2 E_GETEMSVERSION + 5D73:003DC E_RESTOREEMSPAGEFRAME + 5D73:003C1 E_SAVEEMSPAGEFRAME + 5D73:003BA E_EMSAVAILABLE + 5D73:00374 E_ALLOCATEEMS + 5D73:002E7 E_RELEASEBLOCKEMS + 5D73:001FD E_ALLOCATEBLOCKEMS + 5D73:001DA E_MAPALIGNEDBLOCKEMS + 5D73:001D5 E_GETEMSPAGEFRAME + 5D73:001C4 E_UNINITEMS + 5D73:0019B E_MAPEMSMEMORY + 5D73:00180 E_MAPAVAILABLEEMSMEMORY + 5D73:00109 E_RELEASEEMS + 5D73:000EB E_GETFREEEMS + 5D73:0002A E_INITEMS + 5DB2:001AA ERROR_UNINITHANDLER + 5DB2:0018F ERROR_INITHANDLER + 5DCD:0368C I_GETPRESETENVELOPEOFFSET + 5DCD:03675 I_SAMPLEBUTTONHANDLER + 5DCD:03671 UPDATEWAVEFORM + 5DCD:03635 I_IDLEUPDATEENVELOPE + 5DCD:035E3 I_POSTPITCHPANCENTER + 5DCD:035D3 I_PREPITCHPANCENTER + 5DCD:035A1 I_DRAWPITCHPANCENTER + 5DCD:03589 I_TOGGLEMULTICHANNEL + 5DCD:0353D I_DECREASEPLAYCHANNEL + 5DCD:03522 I_INCREASEPLAYCHANNEL + 5DCD:03505 I_PLAYSAMPLE + 5DCD:034D8 MIDI_PLAYSAMPLE + 5DCD:034D1 I_TAGSAMPLE + 5DCD:034CA I_TAGINSTRUMENT + 5DCD:034BD I_CLEARTABLES + 5DCD:0343E I_SHOWINSTRUMENTPLAY + 5DCD:033F2 I_SHOWSAMPLEPLAY + 5DCD:033D6 I_INSTRUMENTLISTNOTEOFF + 5DCD:033A9 I_INSTRUMENTLISTSPACE + 5DCD:02B39 I_MAPENVELOPE + 5DCD:02A8D I_POSTENVELOPE + 5DCD:02A85 I_PREENVELOPE + 5DCD:029F5 I_DRAWENVELOPE + 5DCD:02966 I_UPDATEINSTRUMENT + 5DCD:02917 I_SWAPINSTRUMENTS + 5DCD:028EF I_COPYINSTRUMENT + 5DCD:028A5 I_SCALEINSTRUMENTVOLUMES + 5DCD:0285B I_SCALESAMPLEVOLUMES + 5DCD:0282E I_REPLACEINSTRUMENT + 5DCD:02813 I_SAMPLESPEEDSEMIDOWN + 5DCD:027F2 I_SAMPLESPEEDSEMIUP + 5DCD:027E1 I_HALVESAMPLESPEED + 5DCD:027C1 I_DOUBLESAMPLESPEED + 5DCD:02781 I_EXCHANGEINSTRUMENTS + 5DCD:02437 I_POSTNOTEWINDOW + 5DCD:023FB I_PRENOTEWINDOW + 5DCD:0233F I_DRAWNOTEWINDOW + 5DCD:021EA I_POSTINSTRUMENTWINDOW + 5DCD:02157 I_PLAYNOTE + 5DCD:0210F MIDI_PLAYNOTE + 5DCD:020E2 MIDI_NOTEOFF + 5DCD:020CD MIDI_CLEARTABLE + 5DCD:020C3 MIDI_FINDCHANNEL + 5DCD:020BB MIDI_GETCHANNEL + 5DCD:0207B MIDI_ALLOCATECHANNEL + 5DCD:02035 I_PREINSTRUMENTWINDOW + 5DCD:01F7A I_DRAWINSTRUMENTWINDOW + 5DCD:01DA6 I_TOGGLESAMPLEQUALITY + 5DCD:01BEE I_REVERSESAMPLE + 5DCD:01AB6 I_AMPLIFYSAMPLE + 5DCD:019CF I_CENTERSAMPLE + 5DCD:01972 I_RESIZESAMPLENOINT + 5DCD:0196A I_RESIZESAMPLE + 5DCD:016A0 I_REPLACESAMPLE + 5DCD:0161C I_SWAPSAMPLES + 5DCD:015D7 I_EXCHANGESAMPLES + 5DCD:01372 idle I_CLEARSAMPLENAME + 5DCD:01320 I_CUTSAMPLE + 5DCD:0124F I_CUTSAMPLEBEFORELOOP + 5DCD:011DC I_INVERTSAMPLE + 5DCD:01174 I_CONVERTSAMPLE + 5DCD:01131 I_DELETEINSTRUMENT + 5DCD:0111A I_PRINTC5FREQUENCY + 5DCD:01116 I_CALCULATEC5SPEED + 5DCD:010DE I_DELETESAMPLE + 5DCD:00F09 I_DRAWWAVEFORM + 5DCD:00ECB I_CHECKSUSLOOPVALUES + 5DCD:00E8D I_CHECKLOOPVALUES + 5DCD:00E25 I_SHOWSAMPLEINFO + 5DCD:00D7A I_SAMPLEUP + 5DCD:00D5D I_SAMPLEDOWN + 5DCD:00BC3 I_POSTSAMPLELIST + 5DCD:00B68 I_PRESAMPLELIST + 5DCD:00A71 I_DRAWSAMPLELIST + 5DCD:009C2 I_SELECTSCREEN + 5DCD:0099A I_GETSAMPLEOFFSET + 5DCD:00987 I_GETINSTRUMENTOFFSET + 5DCD:00981 I_GETINSTRUMENTSCREEN + 5DCD:00145 SAMPLEAMPLIFICATION + 5DCD:0013D INSTRUMENTEDIT + 5DCD:00135 NODEHELD + 5DCD:00127 MAXNODE + 5DCD:00121 NEWSAMPLESIZE + 5DCD:0011D SAMPLENUMBERINPUT + 5DCD:00011 SAMPLENUMBER + 5DCD:0000E INSTRUMENTSCREEN + 5DCD:0000C INSTRUMENTAMPLIFICATION + 6136:01DDC F_MIDI_PGDN + 6136:01DC4 F_MIDI_PGUP + 6136:01DB2 F_MIDI_DOWN + 6136:01D99 F_MIDI_UP + 6136:01D72 F_SHOWMIDIZXXINPUT + 6136:01D5B F_FILEQUIT + 6136:01D44 F_FILEDOSSHELL + 6136:01D32 F_FILESAVEAS + 6136:01D1B F_FILESAVECURRENT + 6136:01D06 F_FILENEW + 6136:01CF4 F_FILELOAD + 6136:01CE0 F_FILEMENU + 6136:01CCE F_SAMPLELIBRARY + 6136:01CBC F_RELOADGRAVIS + 6136:01CAA F_INSTRUMENTLIBRARY + 6136:01C98 F_INSTRUMENTLIST + 6136:01C86 F_SAMPLELIST + 6136:01C72 F_INSTRUMENTMENU + 6136:01C5E F_SAMPLEMENU + 6136:01C4C F_DRIVERSCREEN + 6136:01C35 F_CALCULATELENGTH + 6136:01C23 F_REINITSOUNDCARD + 6136:01C11 F_STOP + 6136:01BFF F_PLAYMARK + 6136:01BED F_PLAYORDER + 6136:01BDB F_PLAYPATTERN + 6136:01BC9 F_PLAYSONG + 6136:01BB7 F_INFOPAGE + 6136:01BA3 F_PLAYBACKMENU + 6136:01B91 F_HELP + 6136:01B84 F_MESSAGEEDITOR + 6136:01B77 F_VIEWORDERPAN + 6136:01B6A F_VIEWVARIABLES + 6136:01B5D F_VIEWPATTERN + 6136:01B44 F_MAINMENU + 6136:01A9E F_NEWSONG + 6136:01A96 F_RESET5NUMINPUTPOS + 6136:01A86 F_SETAMIGA + 6136:01A76 F_SETLINEAR + 6136:01A61 F_SETMONO + 6136:01A4C F_SETSTEREO + 6136:019DF F_SETCONTROLINSTRUMENT + 6136:019CF F_SETCONTROLSAMPLE + 6136:0195C F_CONFIGBUTTONSETUP + 6136:0191D F_DRAWSMCCHANNELS + 6136:018B8 F_DRAWHEADER + 6136:01798 F_POST5NUM + 6136:01779 F_PRE5NUM + 6136:01700 F_DRAW5NUM + 6136:015B1 F_POST3NUM + 6136:01592 F_PRE3NUM + 6136:01518 F_DRAW3NUM + 6136:013EF F_POSTTOGGLE + 6136:013BC F_PRETOGGLE + 6136:01346 F_DRAWTOGGLE + 6136:010E1 F_GOTOEMPTYLIST + 6136:0102A F_POSTSTRINGINPUT + 6136:01006 F_PRESTRINGINPUT + 6136:00F92 F_DRAWSTRINGINPUT + 6136:00EDD F_RETURN1 + 6136:00DF9 F_RETURN192 + 6136:00DF2 F_RETURN64 + 6136:00DEC F_RETURN0 + 6136:00DE8 F_REDRAWSCREEN + 6136:00DA6 F_SHOWCHANNELS + 6136:00D61 F_DRAWINFOLINE + 6136:00B6E F_POSTTHUMBBAR + 6136:00B22 F_POSTSCALABLETHUMBBAR + 6136:00A71 F_PRESCALABLETHUMBBAR + 6136:009BF F_PRETHUMBBAR + 6136:008D6 F_DRAWSCALABLETHUMBBAR + 6136:0080B F_DRAWTHUMBBAR + 6136:00505 F_POSTBUTTONOBJECT + 6136:004CC F_PREBUTTONOBJECT + 6136:00427 F_DRAWBUTTONOBJECT + 6136:003E0 F_CHARACTERDEFINITIONS + 6136:003D8 F_SETDIRECTMODE + 6136:003C8 F_POSTEXITOBJECT + 6136:00383 F_DRAWTEXTOBJECT + 6136:0036D F_DRAWBOXOBJECT + 6136:00369 F_CALLFARFUNCTION + 6136:00363 F_CALLFARPOSTFUNCTION + 6136:0035F F_CALLFARPREFUNCTION + 6136:00344 F_INSTRUMENTBUTTONHANDLER + 6136:00341 F_NOTHING + 6136:000D8 THUMBSTRINGENTER + 6315:0238C H_SETHELPCONTEXT + 6315:02377 H_HELPESC + 6315:0236D H_HELPPGDN + 6315:0235A H_HELPPGUP + 6315:0232F H_HELPDOWN + 6315:0231F H_HELPUP + 6315:022FD H_HELP + 6315:0228C H_DRAWHELP + 654E:00ABD MIDISEND + 654E:00AB6 MIDIBUFFEREMPTY + 654E:00AAD K_SETSCROLLLOCK + 654E:00A9B K_REMOVEKEYBOARDTYPE + 654E:00A46 K_INSTALLKEYBOARDTYPE + 654E:00A23 K_SHOWMIDIINPUT + 654E:009A6 K_DRAWTABLES + 654E:00996 K_RESETKEYBOARDTABLES + 654E:0098F K_ISKEYDOWN + 654E:00977 K_ISANYKEYDOWN + 654E:00966 K_CLEARKEYBOARDQUEUE + 654E:0070B K_GETKEY + 654E:006D7 K_ISKEYWAITING + 654E:006B3 K_UNINSTALLDOSHANDLER + 654E:00693 K_INSTALLDOSHANDLER + 654E:00651 K_UNINITKEYBOARD + 654E:005EA K_INITKEYBOARD + 65FE:0006F MMTSR_UNINSTALLMMTSR + 65FE:00001 MMTSR_INSTALLMMTSR + 6681:02392 MSG_GETMESSAGEOFFSET + 6681:0237D MSG_GETMESSAGELENGTH + 6681:020BE MSG_POSTMESSAGE + 6681:0208F MSG_PREMESSAGE + 6681:01FE5 MSG_DRAWMESSAGE + 6681:01FCB MSG_RESETMESSAGE + 68BB:0025B VESA_SETBLOCK + 68BB:00244 idle VESA_GETINFO + 68BB:00221 VESA_SETMODE + 68BB:00201 VESA_DETECT + +Program entry point at 4793:0637 + diff --git a/it/ITMIDI.CFG b/it/ITMIDI.CFG new file mode 100644 index 0000000000000000000000000000000000000000..52da1e18e4122306ab26a8a9a29bd661dbb167e7 GIT binary patch literal 4896 zcmeH_yA6Oa3LiXbV*ZzaLKlI_fm*D0B_yPD4_!0Ou@N3{V sz;A$`fS-Wh0>1@*2mH?Uy}feI0xZA+EWiRRzyd750xZA+Eby-aCzO084gdfE literal 0 HcmV?d00001 diff --git a/it/IT_DISK.ASM b/it/IT_DISK.ASM new file mode 100644 index 0000000..50ceec8 --- /dev/null +++ b/it/IT_DISK.ASM @@ -0,0 +1,10940 @@ +;Ŀ +; Disk Module +; + +include switch.inc +include network.inc + + Jumps + .386 + +;Ŀ +; Externals +; + +Segment Object1 BYTE Public 'Data' +EndS + +Segment Pattern BYTE Public 'Code' + Extrn BaseOctave:Byte + Extrn RowHilight1:Byte + Extrn RowHilight2:Byte +EndS + +Segment Pattern BYTE Public 'Code' + Extrn PatternDataArea:Word +EndS + +Segment Music BYTE Public 'Code' +EndS + + Extrn Display_GetDisplayWindowData:Far + + Extrn E_UnInitEMS:Far + Extrn E_MapEMSMemory:Far + Extrn E_GetEMSPageFrame:Far + + Extrn Glbl_F3:Far + Extrn Glbl_F4:Far + + Extrn I_GetSampleOffset:Far + Extrn I_GetInstrumentOffset:Far + Extrn I_ClearTables:Far + Extrn I_GetPresetEnvelopeOffset:Far + + Extrn K_UnInitKeyBoard:Far + Extrn K_IsAnyKeyDown:Far + Extrn K_ClearKeyBoardQueue:Far + Extrn K_GetKey:Far + + Extrn M_FunctionDivider:Far + Extrn M_Object1List:Far + + Extrn Music_PlayNote:Far + Extrn Music_PlaySample:Far + Extrn Music_ReleaseAllPatterns:Far + Extrn Music_ReleaseAllSamples:Far + Extrn Music_ReleaseSample:Far + Extrn Music_GetSongSegment:Far + Extrn Music_AllocateSample:Far + Extrn Music_ClearAllSampleNames:Far + Extrn Music_GetNumberOfSamples:Far + Extrn Music_GetNumberOfInstruments:Far + Extrn Music_GetPattern:Far + Extrn Music_AllocatePattern:Far + Extrn Music_AllocateSample:Far + Extrn Music_GetSampleLocation:Far + Extrn Music_ClearAllInstruments:Far + Extrn Music_GetInstrumentMode:Far + Extrn Music_AssignSampleToInstrument:Far + Extrn Music_SoundCardLoadSample:Far + Extrn Music_SoundCardLoadAllSamples:Far + Extrn Music_GetPitchTable:Far + Extrn Music_GetMIDIDataArea:Far + + Extrn Music_Stop:Far + Extrn Msg_ResetMessage:Far + Extrn Msg_GetMessageOffset:Far + Extrn Msg_GetMessageLength:Far + +IF TUTORIAL +ELSE + Extrn O1_LoadS3MList:Far + Extrn O1_LoadXMList:Far + Extrn O1_LoadMODList:Far + Extrn O1_LoadMTMList:Far + Extrn O1_Load669List:Far + Extrn O1_LoadITList:Far +ENDIF + Extrn O1_ConfirmOverWriteList:Far + Extrn O1_UnableToSaveList:Far + Extrn O1_SaveITList:Far + Extrn O1_SaveS3MList:Far + Extrn O1_ConfirmDelete:Far ; Updates Song name loader. + Extrn O1_ConfirmDelete2:Far + Extrn O1_ConfirmDelete3:Far + Extrn O1_ConfirmSaveRenameList:Far + Extrn O1_ConfirmResaveList:Far + Extrn O1_ConfirmDiscardList:Far + Extrn O1_InitInstrument:Far + Extrn O1_EditSampleName:Far + Extrn O1_OutOfSamplesList:Far + Extrn O1_EnableInstrumentMode:Far + Extrn O1_StereoSampleList:Far + + Extrn PE_TranslateXMPattern:Far + Extrn PE_Translate669Pattern:Far + Extrn PE_TranslateS3MPattern:Far + Extrn PE_TranslateMTMPattern:Far + Extrn PE_TranslateMODPattern:Far + Extrn PE_ResetOrderPattern:Far + Extrn PE_UnInitPatternEdit:Far + Extrn PEFunction_OutOfMemoryMessage:Far + Extrn PECheckModified:Far + Extrn PEResetModified:Far + Extrn PE_GetMaxPattern:Far + Extrn PE_ConvAX2Num:Far + Extrn PE_GetLastInstrument:Far + Extrn PE_GetPatternConfigOffset:Far + Extrn PE_SaveCurrentPattern:Far + Extrn PE_RestoreCurrentPattern:Far + + Extrn S_UnInitScreen:Far + Extrn S_GetDestination:Far + Extrn S_DrawString:Far + Extrn S_SaveScreen:Far + Extrn S_RestoreScreen:Far + Extrn S_GetGenerationTableOffset:Far + Extrn S_GenerateCharacters:Far + Extrn S_RedefineCharacters:Far + Extrn S_GetPaletteOffset:Far + Extrn S_SetPalette:Far + + Extrn SetInfoLine:Far + Extrn ClearInfoLine:Far + + Extrn Glbl_SetCurrentMode:Far + Extrn Glbl_F10:Far + + Extrn GetKeyboardLock:Far, GetTimerCounter:Far + Extrn MouseUpdateEnable:Far, MouseUpdateDisable:Far + +;Ŀ +; Globals +; + + Global D_GetFileName:Far + Global D_SetDriveDirectoryFar:Far + + Global D_RestorePreShellDirectory:Far + Global D_GetPreShellDirectory:Far + + Global D_SaveInstrument:Far + Global D_ClearFileName:Far + + Global D_GetFormatType:Far + + Global D_LSCheckLoopValues:Far + Global D_LSCheckSusLoopValues:Far + + Global D_SaveSong:Far + + Global D_InitDisk:Far + Global D_UnInitDisk:Far + Global D_InitLoadModule:Far + Global D_InitLoadSamples:Far + Global D_LoadSampleNames:Far + Global D_NewSpecifier:Far + Global D_NewDirectory:Far + Global D_SaveIT:Far + Global D_DrawWaveForm:Far + + Global D_InitLoadInstruments:Far + Global D_DrawLoadInstrument:Far + Global D_PreLoadInstrument:Far + Global D_PostLoadInstrument:Far + Global D_LoadInstrumentNames:Far + Global D_ViewInstrument:Far + Global D_SlowSampleSort:Far + Global D_SlowInstrumentSort:Far + + Global D_SaveS3M:Far + + Global D_SaveDirectoryConfiguration:Far + Global D_DisableFileColours:Far + + Global D_GetLoadSampleVars:Far + + Global D_DrawLoadSampleWindow:Far + Global D_PreLoadSampleWindow:Far + Global D_PostLoadSampleWindow:Far + Global D_PostViewSampleLibrary:Far + + Global D_LSDrawDriveWindow:Far + Global D_LSPreDriveWindow:Far + Global D_LSPostDriveWindow:Far + + Global D_LIDrawDriveWindow:Far + Global D_LIPreDriveWindow:Far + Global D_LIPostDriveWindow:Far + + Global D_DeleteSampleFile:Far + + Global D_PostSaveDriveWindow:Far + + Global D_ClearFileSpecifier:Far + Global D_LoadSongNames:Far + Global D_DrawFileWindow:Far + Global D_DrawDirectoryWindow:Far + Global D_DrawDriveWindow:Far + Global D_PreFileWindow:Far + Global D_PostFileWindow:Far + Global D_PreDirectoryWindow:Far + Global D_PostDirectoryWindow:Far + Global D_PreDriveWindow:Far + Global D_PostDriveWindow:Far + Global D_PostFileLoadWindow:Far + Global D_PostFileSaveWindow:Far + Global D_SaveModule:Far + + Global FileSpecifier:Byte + Global SongDirectory:Byte + Global SampleDirectory:Byte + Global InstrumentDirectory:Byte + Global FileName:Byte + + Global D_SaveSample:Far + Global D_SaveRawSample:Far + Global D_SaveST3Sample:Far + + Global D_GotoStartingDirectory:Far + + Global LSWindow_Up:Far + Global LSWindow_Down:Far + + Global DiskDataArea:Word + Global SampleName:Byte + Global DiskOptions:Byte + + Public D_Resettimer + Public D_ShowTime + +IF TIMERSCREEN + Public D_DrawTimer + Public D_PostTimerList +ENDIF + +IF TUTORIAL + Public SamplesInModule + Public InSampleFileName +ELSE + Public D_LoadS3M + Public D_LoadMTM + Public D_LoadMOD + Public D_Load669 + Public D_LoadIT + Public D_LoadXM +ENDIF + +; + +Segment Disk BYTE Public 'Code' USE16 + Assume CS:Disk, DS:Nothing + +CREATENEWLOGFILE EQU 0 +include debug.inc + +;Ŀ +; Variables +; + +SampleInMemory DW 0FFFFh +NoSaveError DB 0 +Specific DB 0 +DiskDataArea DW DiskData + +OldCacheTime DD 0 + +Time DW 0 +Date DW 0 +LoadDate DW 0 +LoadTime DW 0 +DrivesAvail DB 27 Dup (0) +UnusedSamples DW 0 + +InitialInstruments DW 0 ; +NumInstruments DW 0 ; Order important! +InstrumentCachefileVersion DW TRACKERVERSION ; + +LoadInstrumentNameCount DW 0 +TopInstrument DW 0 +CurrentInstrument DW 0 + +LoadSongNameCount DW 0 +LoadSampleNameCount DW 0 +CurrentSample DW 0 + +NumSamples DW 0 ; Order important! +SampleCachefileVersion DW TRACKERVERSION ; + +TopSample DW 0 +CurrentDrive DB 0 +NumDrives DB 0 +TopDrive DB 0 +NumEntries DW 0 +NumFiles DW 0 +NumFileInfo DW 0 +NumDirectories DW 0 +TopDirectory DW 0 +CurrentDirectory DW 0 +CurrentFile DW 0 +TopFile DW 0 +FileName DB 0 + DB 13 Dup (0) +SaveFileName DB 0 + DB 79 Dup (0) +FileSpecifier DB 0 + DB 64 Dup (0) +StartingDrive DB 0 +StartingDirectory DB 70 Dup (0) + +PreShellDirectory DB 70 Dup (0) +DOSDirectory DB 70 Dup (0) + +SongDirectory DB 0 + DB 69 Dup (0) +SampleDirectory DB 0 + DB 69 Dup (0) +InstrumentDirectory DB 0 + DB 69 Dup (0) +CountryTableConfig DB 0 + +SampleName DB 0 + DB 26 Dup (0) + +MODNumberOfChannels DB 0 +MODNumberOfInstruments DB 0 +MODNumberOfOrders DB 0 +MODOrderOffset DW 0 +MODPatternOffset DW 0 +LastKey DW 0 + +SampleCacheFileComplete DB 0 +InstrumentCacheFileComplete DB 0 + +Resolution DB 0 + +FileTempSpecifier DB 70 Dup (0) +CurrentSearchPos DB 0 +Search DB 13 Dup (0) + +InstrumentTable DB 100 Dup (0) + +InstrumentLoaderTable Label Word + DW Offset LoadITInstrument ; 3 + DW Offset LoadXIInstrument ; 4 + DW Offset LoadInITInstrument ; 5 + DW Offset LoadInXMInstrument ; 6 + DW 0 ; 7 + DW Offset LoadITInModuleInstrument ; 8 + DW Offset LoadXMInModuleInstrument ; 9 + +InstrumentLoader DW 0 +InSampleFileName DB 13 Dup (0) +InSampleDateTime DD 0 +InSampleFormat DB 0 ; Do *NOT* change order +InSampleChannels DB 0 ; Do *NOT* change order + +InInstrumentFileName DB 13 Dup (0) +InInstrumentFormat DB 0 + +ExitLibraryDirectory Label + DB "IMPS. ", 0, 0, 0, 0 + DB 8 Dup(154), "Directory", 8 Dup(154), 0, 0, 0 + DW 0, 0, 0, 0, 0, 0, 0, 0 + DW 0, 0, 0, 0, 0, 0, 0, 0 + DW 0, 0, 0, 0 + DB 1 + +ExitInstrumentLibraryDirectory Label + DB 1, ". ", 0 + DB 8 Dup(154), "Directory", 8 Dup(154), 0 ; Instrument name + DW 0, 0 ; NoSamples, FileSize + DD 0 ; File offset + +AllFilesMask DB "*.*", 0 +FileSpecifierDefault DB "*.IT, *.XM, *.S3M, *.MTM, *.669, *.MOD", 0 +DriveMsg DB "Drive X:" +NoFilesMsg DB "No files.", 0 +NoDirsMsg DB "No dirs.", 0 +WAVEfmtID DB "WAVEfmt ", 0, 0, 1, 0 +XIIdentification DB "Extended Instrument: " +XMIdentification DB "Extended Module: " +TXWAVEIdentification DB "LM8953", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +GUSPATIdentification DB "GF1PATCH110", 0, "ID#000002", 0 ; 22 bytes + +OpenErrorMsg DB "Error opening file.", 0 + +HeaderMsg DB "File Header", 0 +SampleMsg DB "Sample ", 0FDh, 'D', 0 +SHLoadMsg DB "Sample Header ", 0FDh, 'D', 0 +InstrumentMsg DB "Instrument ", 0FDh, 'D', 0 +PatternMsg DB "Pattern ", 0FDh, 'D', 0 +TrackMsg DB "Channel ", 0FDh, 'D ', 13 + DB "Track ", 0FDh, 'D ', 0 +CompleteMsg DB "Done", 0 +InstrumentHeaderMsg DB "Instrument Headers", 0 +SampleHeaderMsg DB "Sample Headers", 0 +Quality8Msg DB "8 Bit", 0 +Quality16Msg DB "16 Bit", 0 +Quality8StereoMsg DB "8 Bit Stereo", 0 +Quality16StereoMsg DB "16 Bit Stereo", 0 +LengthMsg DB 0FDh, 'L', 0 +DirectoryMsg DB 8 Dup(154), "Directory", 8 Dup(154), 0 +LibraryMsg DB 9 Dup(154), "Library", 9 Dup(154), 0 +FontFileName DB "FONT.CFG", 0 +ConfigFileName DB "IT.CFG", 0 +ST3CacheFileName DB "########.ST3", 0 +SampleCacheFileName DB "CACHE.ITS", 0 +InstrumentCacheFileName DB "CACHE.ITI", 0 +SaveFormat DB DEFAULTFORMAT +SaveFormatError DB 0 ; This will get erased whenever the + ; saveformat changes. +SamplesInModule DB 0 +InstrumentsInModule DB 0 +FileColours DB 1 + +NoteData DB 0FFh, 0, 0FFh, 0, 0 + +CheckDataArea DB 96 Dup(0) +KeyBoardTable DW 12Ch, 0, 11Fh, 1, 12Dh, 2, 120h, 3, 12Eh, 4 + DW 12Fh, 5, 122h, 6, 130h, 7, 123h, 8, 131h, 9 + DW 124h, 10, 132h, 11, 110h, 12, 103h, 13, 111h, 14 + DW 104h, 15, 112h, 16, 113h, 17, 106h, 18, 114h, 19 + DW 107h, 20, 115h, 21, 108h, 22, 116h, 23, 117h, 24 + DW 10Ah, 25, 118h, 26, 10Bh, 27, 119h, 28, 0FFFFh +SampleCheck DW 0FFFFh + +MonthNames Label + DW Offset Empty + DW Offset January + DW Offset February + DW Offset March + DW Offset April + DW Offset May + DW Offset June + DW Offset July + DW Offset August + DW Offset September + DW Offset October + DW Offset November + DW Offset December + DW Offset Empty + DW Offset Empty + DW Offset Empty + +January DB "January", 0 +February DB "February", 0 +March DB "March", 0 +April DB "April", 0 +May DB "May", 0 +June DB "June", 0 +July DB "July", 0 +August DB "August", 0 +September DB "September", 0 +October DB "October", 0 +November DB "November", 0 +December DB "December" +Empty DB 0 + +TimerData DW 0 +NumTimerData DW 0 +TopTimerData DW 0 + +SampleFormatNames Label + DW Offset Unchecked ; 0 + DW Offset DirectoryFormat + DW Offset ITSampleFormat + DW Offset STSampleFormat + DW Offset UnknownSampleFormat + DW Offset WAV8BitFormat + DW Offset XMSample + DW Offset WAV16BitFormat + DW Offset XMSample + DW Offset PTMSample + DW Offset MTMSample + DW Offset C669Sample + DW Offset FARSample + DW Offset TXWaveSample ; 13 + DW Offset MODSample + DW Offset KRZSample ; 15 + DW Offset PATFormat + DW Offset IFFFormat ; 17 + DW 0, 0 + DW 0, 0, 0, 0 + DW 0, 0, 0, 0 + DW 0, 0, 0, 0 + DW Offset ST3Module ; 20h + DW Offset ITModule + DW Offset XMModule + DW Offset PTMModule + DW Offset MTMModule + DW Offset C669Module + DW Offset FARModule + DW Offset MODModule1 + DW Offset XMModule + DW Offset KRZFormat ; 29h + DW Offset PATFormat + +LoadSamplesInModuleTable Label Word + DW Offset LoadS3MSamplesInModule + DW Offset LoadITSamplesInModule + DW Offset LoadXMSamplesInModule + DW Offset LoadPTMSamplesInModule + DW Offset LoadMTMSamplesInModule + DW Offset Load669SamplesInModule + DW Offset LoadFARSamplesInModule + DW Offset LoadMODSamplesInModule + DW Offset LoadMODSamplesInModule + DW Offset LoadKRZSamples + DW Offset LoadPATSamples +; DW Offset LoadULTSamplesInModule + +FormatNames Label + DW Offset Unchecked ; 0 + DW Offset UnknownFormat ; 1 + DW Offset ITFormat2_0 ; 2 + DW Offset ITFormat? ; 3 + DW Offset ST3Format ; 4 + DW Offset XMModule ; 5 + DW Offset C669Module ; 6 + DW Offset CompressedITModule ; 7 + DW 0 + DW Offset MODFormat ; 9 + DW Offset Protracker ; 10 + DW Offset Channel4 ; 11 + DW Offset Channel6 ; 12 + DW Offset Channel8 ; 13 + DW Offset StarTrekker4 ; 14 + DW Offset StarTrekker8 ; 15 + DW Offset OldMod ; 16 + DW Offset ChannelXX ; 17 + DW Offset MultiTrackerModule ; 18 + +PanningPositions DB 0, 4, 9, 13, 17, 21, 26, 30 + DB 34, 38, 43, 47, 51, 55, 60, 64 +MODChannelTable DB 4, 4, 4, 6, 8, 4, 8, 4 +FineTuneTable DW 8363, 8413, 8463, 8529 + DW 8581, 8651, 8723, 8757 + DW 7895, 7941, 7985, 8046 + DW 8107, 8169, 8232, 8280 + +DirectoryFormat DB "Directory", 0 +ITSampleFormat DB "Impulse Tracker Sample", 0 +STSampleFormat DB "Scream Tracker Sample", 0 +UnknownSampleFormat DB "Unknown sample format", 0 +WAV8BitFormat DB "8 Bit WAV Format", 0 +WAV16BitFormat DB "16 Bit WAV Format", 0 +XMSample DB "Fast Tracker 2 Sample", 0 +PTMSample DB "Poly Tracker Sample", 0 +MTMSample DB "Multi Tracker Sample", 0 +C669Sample DB "Composer 669 Sample", 0 +FARSample DB "Farandole Sample", 0 +; ULTSample DB "Ultra Tracker Sample", 0 +TXWaveSample DB "TX Wave Sample", 0 +MODSample DB "MOD Sample", 0 +KRZSample DB "KRZ Sample", 0 + +ST3Module DB "Scream Tracker 3 Module", 0 +ITModule DB "Impulse Tracker Module", 0 +XMModule DB "Fast Tracker 2 Module", 0 +PTMModule DB "Poly Tracker Module", 0 +MTMModule DB "Multi Tracker Module", 0 +C669Module DB "Composer 669 Module", 0 +FARModule DB "Farandole Module", 0 +MODModule1 DB "MOD Format", 0 +; ULTModule DB "Ultra Tracker Module", 0 +KRZFormat DB "Kurzweil Synth File", 0 +PATFormat DB "Gravis UltraSound Patch", 0 +IFFFormat DB "AIFF Sample", 0 + +Unchecked DB "Unchecked", 0 +UnknownFormat DB "Unknown module format", 0 +CompressedITModule DB "Compressed " +ITFormat2_0 DB "Impulse Tracker", 0 +ITFormat? DB "Impulse Tracker ?.??", 0 +ST3Format DB "Scream Tracker 3", 0 +MODFormat DB "Amiga-NewTracker", 0 +ProTracker DB "Amiga-ProTracker", 0 +StarTrekker4 DB "4 Channel Startrekker", 0 +StarTrekker8 DB "8 Channel Startrekker", 0 +Channel4 DB "4 Channel MOD", 0 +Channel6 DB "6 Channel MOD", 0 +Channel8 DB "8 Channel MOD", 0 +OldMod DB "Old Amiga-MOD format ? ", 0 +ChannelXX DB 0FDh, "D Channel MOD", 0 +MultiTrackerModule DB "MultiTracker Module", 0 + +ITInstrumentSavedMsg DB "Instrument saved (instrument ", 0FDh, "D)", 0 +InstrumentErrorMsg DB "Error: Instrument ", 0FDh, "D NOT saved! (No Filename?)", 0 +ITSampleSavedMsg DB "Impulse Tracker sample saved (sample ", 0FDh, "D)", 0 +ST3SampleSavedMsg DB "Scream Tracker sample saved (sample ", 0FDh, "D)", 0 +IF SAVESAMPLEWAV +RawSampleSavedMsg DB "WAV Sample saved (sample ", 0FDh, "D)", 0 +ELSE +RawSampleSavedMsg DB "RAW Sample saved (sample ", 0FDh, "D)", 0 +ENDIF +SampleErrorMsg DB "Error: Sample ", 0FDh, "D NOT saved! (No Filename?)", 0 +InitInstrumentMsg DB "Sample assigned to Instrument ", 0FDh, "D", 0 +InitInstrumentErrorMsg DB "Error: No available Instruments!", 0 + +TooManyPatternsMsg DB "Warning: Only 100 patterns supported in S3M format", 0 +ChannelVolumeErrorMsg DB "Warning: Channel volumes unsupported in S3M format", 0 +LinearSlideMsg DB "Warning: Linear slides unsupported in S3M format", 0 +LoopMsg DB "Warning: Sustain and Ping Pong loops unsupported in S3M format", 0 +SampleVolumeMsg DB "Warning: Sample volumes unsupported in S3M format", 0 +SampleVibratoMsg DB "Warning: Sample vibrato unsupported in S3M format", 0 +ST3InstrumentErrorMsg DB "Warning: Instrument functions unsupported in S3M format", 0 +PatternLengthMsg DB "Warning: Pattern lengths other than 64 rows unsupported in S3M format", 0 +ChannelErrorMsg DB "Warning: Data outside 16 channels unsupported in S3M format", 0 +NoteRangeMsg DB "Warning: Notes outside the range C-1 to B-8 are unsupported in S3M format", 0 +PanningErrorMsg DB "Warning: Extended volume column effects are unsupported in S3M format", 0 + +InstrumentLibrary DB 154, 154, "Module", 154, 154, 0 +InstrumentNoSample DB "No Samples", 0 +InstrumentSingleSample DB "1 Sample", 0 +InstrumentSeveralSamples DB 0FDh, "D Samples", 0 +InstrumentUnknownSamples DB "???", 0 +FileSizeMsg DB 0FDh, "Dk", 0 +FreeSampleMsg DB "Available", 13 + DB "Samples: ", 0FDh, 'D', 0 + +IF SAVESAMPLEWAV + WAVEFileHeader DB "RIFF" + WAVEFileSize DD 0 + WAVEFileHeader2 DB "WAVEfmt " + WAVEFileHeaderLength DD 10h + WAVEFileID DW 1 + WAVEChannels DW 1 + WAVEMixSpeed DD 44100 ; Default to CD quality + WAVEBytesPerSecond DD 0 + WAVEBytesPerSample DW 2 + WAVEBits DW 16 + WAVEHeader3 DB "data" + WAVEDataSize DD 0 +ENDIF + +DiskOptions DB 0 +EditTimer DD 0 + +CDRomStartDrive DB 0 ; The first CDRom Drive letter +CDRomEndDrive DB 0 ; The drive AFTER the last cdrom + +FileWindowKeys Label + + DB 0 + DW 1C8h ; Up arrow + DW FileWindow_Up + + DB 0 + DW 1D0h ; Down arrow + DW FileWindow_Down + + DB 0 + DW 1C9h ; PgUp + DW FileWindow_PgUp + + DB 0 + DW 1D1h ; PgDn + DW FileWindow_PgDn + + DB 0 + DW 1C7h ; Home + DW FileWindow_Home + + DB 0 + DW 1CFh ; End + DW FileWindow_End + + DB 4 + DW 10Fh ; Shift Tab + DW FileWindow_ShiftTab + + DB 0 + DW 10Fh ; Tab + DW FileWindow_Right + + DB 0 + DW 1CDh ; Right arrow + DW FileWindow_Right + + DB 0 + DW 1CBh ; Left arrow + DW FileWindow_Left + + DB 0 + DW 1D3h ; Delete + DW FileWindow_DeleteFile + + DB 0FFh + +DirectoryWindowKeys Label + + DB 0 + DW 1C8h + DW DirectoryWindow_Up + + DB 0 + DW 1D0h + DW DirectoryWindow_Down + + DB 0 + DW 1C9h ; PgUp + DW DirectoryWindow_PgUp + + DB 0 + DW 1D1h ; PgDn + DW DirectoryWindow_PgDn + + DB 0 + DW 1C7h ; Home + DW DirectoryWindow_Home + + DB 0 + DW 1CFh ; End + DW DirectoryWindow_End + + DB 4 + DW 10Fh ; Shift Tab + DW DirectoryWindow_Left + + DB 0 + DW 10Fh ; Tab + DW FileWindow_Left ; Same object num + + DB 0 + DW 1CDh ; Right arrow + DW FileWindow_Left + + DB 0 + DW 1CBh ; Left arrow + DW DirectoryWindow_Left + + DB 0 + DW 11Ch ; Enter + DW DirectoryWindow_Enter + + DB 0FFh + +DriveWindowKeys Label + + DB 0 + DW 1C8h + DW DriveWindow_Up + + DB 0 + DW 1D0h + DW DriveWindow_Down + + DB 4 + DW 10Fh ; Shift-Tab + DW FileWindow_Right + + DB 0 + DW 10Fh ; Tab + DW DriveWindow_Tab + + DB 0 + DW 1CDh ; Right arrow + DW DirectoryWindow_Left + + DB 0 + DW 1CBh ; Left arrow + DW FileWindow_Right + + DB 0 + DW 11Ch ; Enter + DW DriveWindow_Enter + + DB 0FFh + +SaveDriveWindowKeys Label + + DB 0 + DW 1C8h + DW DriveWindow_Up + + DB 0 + DW 1D0h + DW DriveWindow_Down + + DB 4 + DW 10Fh ; Shift-Tab + DW FileWindow_Right + + DB 0 + DW 10Fh ; Tab + DW SaveDriveWindow_Tab + + DB 0 + DW 1CDh ; Right arrow + DW SaveDriveWindow_Tab + + DB 0 + DW 1CBh ; Left arrow + DW FileWindow_Right + + DB 0 + DW 11Ch ; Enter + DW DriveWindow_Enter + + DB 0FFh + +LSDriveWindowKeys Label + + DB 0 + DW 1C8h + DW DriveWindow_Up + + DB 0 + DW 1D0h + DW DriveWindow_Down + + DB 4 + DW 10Fh ; Shift-Tab + DW DriveWindow_Tab ; goto object number 15 + + DB 0 + DW 10Fh ; Tab + DW LSDriveWindow_Right + + DB 0 + DW 1CDh ; Right arrow + DW LSDriveWindow_Right + + DB 0 + DW 1CBh ; Left arrow + DW DriveWindow_Tab + + DB 0 + DW 11Ch ; Enter + DW LS_DriveWindow_Enter + + DB 0FFh + +LIDriveWindowKeys Label + + DB 0 + DW 1C8h + DW DriveWindow_Up + + DB 0 + DW 1D0h + DW DriveWindow_Down + + DB 0 + DW 1CBh ; Left arrow + DW LIDriveWindow_Tab + + DB 0 + DW 10Fh ; Tab + DW LIDriveWindow_Tab + + DB 0 + DW 11Ch ; Enter + DW LI_DriveWindow_Enter + + DB 0FFh + +LoadInstrumentKeys Label + DB 0 + DW 11Ch ; Enter + DW LIWindow_Enter + +ViewInstrumentKeys Label + DB 0 + DW 1C8h + DW LIWindow_Up + + DB 0 + DW 1D0h + DW LIWindow_Down + + DB 0 + DW 1C9h ; PgUp + DW LIWindow_PgUp + + DB 0 + DW 1D1h ; PgDn + DW LIWindow_PgDn + + DB 0 + DW 1C7h ; Home + DW LIWindow_Home + + DB 0 + DW 1CFh ; End + DW LIWindow_End + + DB 0 + DW 1D3h ; Delete + DW D_DeleteInstrumentFile + + DB 0 + DW 11Ch ; Enter + DW LIViewWindow_Enter + + DB 0 + DW 1CDh ; Right arrow + DW LIViewWindow_Tab + + DB 0 + DW 10Fh ; Tab + DW LIViewWindow_Tab + + DB 0FFh + +LSWindowKeys Label + DB 0 + DW 11Ch ; Enter + DW LSWindow_Enter + +LSViewWindowKeys Label + DB 0 + DW 139h + DW LSWindow_Space ; Edit sample name + + DB 0 + DW 1C8h + DW LSWindow_Up + + DB 0 + DW 1D0h + DW LSWindow_Down + + DB 0 + DW 1C9h ; PgUp + DW LSWindow_PgUp + + DB 0 + DW 1D1h ; PgDn + DW LSWindow_PgDn + + DB 0 + DW 1C7h ; Home + DW LSWindow_Home + + DB 0 + DW 1CFh ; End + DW LSWindow_End + + DB 0 + DW 1CDh ; Right arrow + DW FileWindow_ShiftTab + + DB 0 + DW 10Fh ; Tab + DW FileWindow_ShiftTab ; Object 16 + + DB 0 + DW 1D3h ; Delete + DW D_DeleteSampleFile + + DB 0 + DW 11Ch ; Enter + DW LSViewWindow_Enter + + DB 0FFh + + + +;Ŀ +; Functions +; + +Proc D_InitDisk Far + + Push DS + + Push CS + Pop DS + Assume DS:Disk + ; Get date/time for CACHE.IT file + + Trace " - Finding CDROM Drives" + + Mov AX, 1500h + Xor BX, BX + Int 2Fh + Cmp AL, 0FFh + JNE D_InitDiskNoCDROM + Test BX, BX + JZ D_InitDiskNoCDROM + + Add CL, 'A' + Mov CDRomStartDrive, CL + Add CX, BX + Mov CDRomEndDrive, CL + +D_InitDiskNoCDROM: + Trace " - Determining main directory" + + Mov SI, Offset DOSDirectory + Call D_GetDriveDirectory + + Trace " - Initialising cache file parameters" + + Mov AH, 2Ah + Int 21h ; Get Date + Mov AX, CX ; Now to get date in yyyyyyym mmmddddd + Sub AX, 1980 + ShL AX, 9 ; Year + Or AL, DL ; Day + Xor DL, DL + ShR DX, 3 + Or AX, DX ; Month + Mov Date, AX + + Mov AH, 2Ch + Int 21h ; Get time + Mov AX, CX ; Now to get time in hhhhhmmm mmmsssss + ShL AL, 2 ; AX = ...hhhhh mmmmmm.. + ShL AX, 3 ; AX = hhhhhmmm mmm..... + ShR DH, 1 ; DH = ...sssss + Or AL, DH + Mov Time, AX + + Cmp StartingDirectory, 0 + JNE D_InitDisk2 + + Trace " - Determining available drives" + +D_InitDisk1: + Mov AH, 19h + Int 21h + + Mov StartingDrive, AL + + Mov CX, 26 + Xor BX, BX + Xor SI, SI + +D_InitDisk3: + Mov DL, BL + Mov AH, 0Eh + Int 21h + + Mov AH, 19h + Int 21h + Cmp AL, BL + JNE D_InitDisk4 + + Cmp BL, StartingDrive + JNE D_InitDisk9 + + Mov AX, SI + Mov CurrentDrive, AL + +D_InitDisk9: + Test DiskOptions, 1 + JNZ D_InitDisk10 + + Mov AX, 440Eh ; This code was to prevent + ; A and B drives being shown + ; on older DOS systems when + ; only one drive was present. + ; For some reason, it crashes + ; one in a thousand computers. + ; hence the option /x3 + Push BX + Xor BL, BL + Int 21h + + Pop BX + JC D_InitDisk10 + And AL, AL + JZ D_InitDisk10 + Dec AX + Cmp AL, BL + JNE D_InitDisk4 + +D_InitDisk10: + Mov [DrivesAvail+SI], BL + Inc SI + +D_InitDisk4: + Inc BX + Loop D_InitDisk3 + + Mov BX, SI + Mov NumDrives, BL + + Mov DL, StartingDrive + Mov AH, 0Eh + Int 21h + +D_GetStartingDirectory1: ; FS=PSP. + Push CS + Pop ES + + Mov DI, Offset StartingDirectory + + Mov DS, [FS:2Ch] ; Environment thingy. + Xor SI, SI + Mov CX, 7FFFh + +D_GetStartingDirectory2: + Cmp Word Ptr [SI], 0 + JE D_GetStartingDirectory3 + + Inc SI + Loop D_GetStartingDirectory2 + + Jmp D_GetStartingDirectoryEnd + +D_GetStartingDirectory3: ; DS:SI points to 0... + Add SI, 4 + Push SI ; Now to work out count. + + Xor DX, DX + Mov CX, 1 + +D_GetStartingDirectory4: + LodsB + And AL, AL + JZ D_GetStartingDirectory5 + + Inc DX + + Cmp AL, '\' + JNE D_GetStartingDirectory4 + + Mov CX, DX + Jmp D_GetStartingDirectory4 + +D_GetStartingDirectory5: + Pop SI + + Dec CX + Rep MovsB + Xor AL, AL + StosB + +D_GetStartingDirectoryEnd: + Push CS + Pop DS + + Mov SI, Offset StartingDirectory + Call D_SetDriveDirectory + + Mov DI, Offset SongDirectory + Cmp Byte Ptr [DI], 0 + JNE D_InitDisk11 + + Push SI + +D_InitDisk5: + LodsB + And AL, AL + JZ D_InitDisk6 + + StosB + Jmp D_InitDisk5 + +D_InitDisk6: + Cmp Byte Ptr [ES:DI-1], '\' + JNE D_InitDisk15 + + Dec DI + +D_InitDisk15: + Mov AX, '\' + 256*'S' + StosW + Xor AL, AL + StosB + + Pop SI + +D_InitDisk11: + Mov DI, Offset SampleDirectory + Cmp Byte Ptr [DI], 0 + JNE D_InitDisk12 + +D_InitDisk7: + LodsB + And AL, AL + JZ D_InitDisk8 + + StosB + Jmp D_InitDisk7 + +D_InitDisk8: + Cmp Byte Ptr [ES:DI-1], '\' + JNE D_InitDisk16 + + Dec DI + +D_InitDisk16: + Mov AX, '\' + 256*'I' + StosW + Xor AL, AL + StosB + +D_InitDisk12: + Mov DI, Offset InstrumentDirectory + Cmp Byte Ptr [DI], 0 + JNE D_InitDisk13 + + Mov SI, Offset SampleDirectory + Mov CX, 70 + Rep MovsB + + Mov SI, Offset SongDirectory + Call D_SetDriveDirectory + Mov SI, Offset SampleDirectory + Call D_SetDriveDirectory + Mov SI, Offset InstrumentDirectory + Call D_SetDriveDirectory + +D_InitDisk13: + Push CS + Pop DS + + Mov SI, Offset StartingDirectory + Call D_SetDriveDirectory + + Trace " - Loading configuration file" + + Mov AX, 3D00h ; Get config. + Mov DX, Offset ConfigFileName + Int 21h + JC D_InitDisk2 + + Mov BX, AX ; BX = file handle + + Trace " - Processing configuration file" + + Mov AH, 3Fh + Mov CX, 211 ; Load Directories+Keyboard + Mov DX, Offset SongDirectory + Int 21h ; Read config file.. + + Call S_GetPaletteOffset ; Read palette stuff. + Mov AH, 3Fh + Mov CX, 3*16 + Int 21h + + Call S_SetPalette + + Call Display_GetDisplayWindowData + Mov AH, 3Fh + Mov CX, 50 + Int 21h + + Call PE_GetPatternConfigOffset + Mov AH, 3Fh + Mov CX, 218 + Int 21h + + Call I_GetPresetEnvelopeOffset + Mov AH, 3Fh + Mov CX, 810 + Int 21h + + Mov AH, 3Eh ; Close file. + Int 21h + +D_InitDisk2: ; Load font data.. and set it. + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset StartingDirectory + Call D_SetDriveDirectory + + Mov AX, 3D00h + Mov DX, Offset FontFileName + Int 21h + JC D_NoFontFile + + Trace " - Loading custom font file" + + Call S_GetGenerationTableOffset + Push ES + Pop DS + Mov DX, DI + + Mov BX, AX + Mov AH, 3Fh + Mov CX, 2048 + Int 21h + JC D_BadFontRead + Cmp AX, CX + JNE D_BadFontRead + + Trace " - Initialising custom font file" + + Push BX + + Mov SI, DX + Xor AX, AX + Mov BX, 256 + Call S_RedefineCharacters + + Pop BX + +D_BadFontRead: + Mov AH, 3Eh + Int 21h + +D_NoFontFile: + Push CS + Pop DS + + Call CheckTimerData + + Pop DS + Ret + +EndP D_InitDisk + Assume DS:Nothing + +; + +Proc D_UnInitDisk Far + + Push CS + Pop DS + Assume DS:Disk + + Mov AX, DiskDataArea + Test AX, AX + JZ D_UnInitDisk1 + + Mov ES, AX + Mov AH, 49h + Int 21h + + +D_UnInitDisk1: + Call ReleaseTimerData + Mov SI, Offset DOSDirectory + Call D_SetDriveDirectory + + Ret + +EndP D_UnInitDisk + Assume DS:Nothing + +; + +Proc D_GetDriveDirectory ; DS:SI points to buffer + + Push AX + Push DX + Push SI + + Mov AH, 19h + Int 21h + + Add AL, 'A' + Mov [SI], AL + Mov Word Ptr [SI+1], ':' + 256*'\' + Add SI, 3 + Mov AH, 47h + Xor DX, DX + Int 21h + + Pop SI + Pop DX + Pop AX + + Ret + +EndP D_GetDriveDirectory + +; + +Proc D_SetDriveDirectory ; DS:SI points to dir. + + Push AX + Push BX + Push DX + + Xor DX, DX + + Cmp Byte Ptr [SI+1], ':' + JNE D_SetDriveDirectory2 + + Mov DL, [SI] + Cmp DL, 'a' + JB D_SetDriveDirectory1 + Cmp DL, 'z' + JA D_SetDriveDirectory1 + + Add DL, 'A'-'a' + +D_SetDriveDirectory1: + Sub DL, 'A' + Cmp DL, 25 ; Drive > 'Z'?? + JA D_SetDriveDirectory4 + + Mov AX, 440Eh + Mov BL, DL + Inc BX + Int 21h + JC D_SetDriveDirectory3 + And AL, AL + JZ D_SetDriveDirectory3 + + Mov AX, 440Fh + Int 21h + +D_SetDriveDirectory3: + Mov AH, 0Eh + Int 21h ; This causes hanging on re-run!!! + +D_SetDriveDirectory4: + Mov DX, 2 + +D_SetDriveDirectory2: + Add DX, SI + Mov AH, 3Bh + Int 21h + + Call D_GetDriveDirectory + + Pop DX + Pop BX + Pop AX + Ret + +EndP D_SetDriveDirectory + +; + +Proc D_LoadFileNames + + Mov ES, CS:DiskDataArea + Xor DI, DI + Xor AX, AX + Mov CX, 32768 + Rep StosW + + Push CS + Push CS + + Pop DS + Pop ES + Assume DS:Disk + + Mov NumFileInfo, 0 + Mov NumEntries, 0 + Mov CurrentDirectory, 0 + + Mov SI, Offset FileSpecifier + +D_LoadFileNames1: + Mov DI, Offset FileTempSpecifier + +D_LoadFileNames2: + LodsB + And AL, AL + JZ D_LoadFileNames3 + + Cmp AL, ',' + JE D_LoadFileNames3 + + Cmp AL, ' ' + JE D_LoadFileNames2 + + StosB + Jmp D_LoadFileNames2 + +D_LoadFileNames3: + Xor AL, AL + StosB ; ES:DI points to file name. + + Push DS + Push SI + Push ES + Push DI + + Xor BL, BL + Mov CX, 6 ; Hidden/System/Normal files + Mov DX, Offset FileTempSpecifier + Call D_LoadFileNames4 + + Pop DI + Pop ES + Pop SI + Pop DS + + Cmp Byte Ptr [DS:SI-1], 0 + JNE D_LoadFileNames1 + + Mov AX, NumEntries + Mov NumFiles, AX + Cmp CurrentFile, AX + JB D_LoadFileNameUpdateCurrentFile + + Mov CurrentFile, 0 + +D_LoadFileNameUpdateCurrentFile: + Mov DX, Offset AllFilesMask + Mov CX, 10h ; Directories + Mov BX, CX + Call D_LoadFileNames4 + + Mov AX, NumEntries + Sub AX, NumFiles + Mov NumDirectories, AX + + Ret + +D_LoadFileNames4: + Push DX + + Mov DS, DiskDataArea + Assume DS:Nothing + + Mov DX, 60000 + Mov AH, 1Ah + Int 21h ; Shift DTA address.. + + Push CS + Pop DS + Assume DS:Disk + + Mov AH, 4Eh + Pop DX + Int 21h + +D_LoadFileNames5: + JC D_LoadFileNames6 + ; A file is found.... + Cmp NumEntries, 1000 + JAE D_LoadFileNames6 + + Mov AX, 50 + Mul NumEntries + Add AX, 2000 + Mov DI, AX + Mov CX, 21 + + Mov DS, DiskDataArea + Assume DS:Nothing + + Mov SI, 60000+16h + + Cmp Word Ptr [DS:60000+1Eh], '.' + JNE D_LoadFileNames9 + + Mov Byte Ptr [DS:60000+1Eh], '\' + +D_LoadFileNames9: + And BL, BL + JZ D_LoadFileNames7 + + Test [SI-1], BL + JZ D_LoadFileNames8 + +D_LoadFileNames7: + Push DS + Pop ES + Rep MovsB + + Inc CS:NumEntries + +D_LoadFileNames8: + Push CS + Pop DS + Mov AH, 4Fh + Int 21h + Jmp D_LoadFileNames5 + +D_LoadFileNames6: + RetN + +EndP D_LoadFileNames + Assume DS:Nothing + +; + +Proc D_SortRoutine + + Mov DS, DiskDataArea + Push DS + Pop ES + + Mov SI, CX ; Start + + ; OK, so SI = current, + ; CX/DX = range + +D_SortRoutine2: + Cmp SI, DX + JAE D_SortRoutine1 + + Push DX + Push SI + + Push CX + Push DX + + Mov AX, 50 + Mul SI + Add AX, 2000 + Mov SI, AX + + Mov AX, 50 + Mul CX + Add AX, 2000 + Mov DI, AX + + Xor BX, BX + Pop DX + + Cmp Word Ptr [SI+8], '\' + JE D_SortRoutine4 + +D_SortRoutine3: + Cmp CX, DX + JAE D_SortRoutine4 + + Cmp Word Ptr [DI+8], '\' + JE D_SortRoutine6 + + Push CX + Push SI + Push DI + + Add SI, 8 + Add DI, 8 + Mov CX, 13 + + RepE CmpsB + + Pop DI + Pop SI + Pop CX + + JB D_SortRoutine5 + JA D_SortRoutine6 + Cmp DI, SI + JBE D_SortRoutine5 + +D_SortRoutine6: + Inc BX + +D_SortRoutine5: + Inc CX + Add DI, 50 + + Jmp D_SortRoutine3 + +D_SortRoutine4: + Pop CX + Add BX, CX + Add BX, BX + Mov [BX], SI + + Pop SI + Pop DX + Inc SI + Jmp D_SortRoutine2 + +D_SortRoutine1: + Ret + +EndP D_SortRoutine + +; + +Proc D_SortFileNames + + Xor CX, CX + Mov DX, CS:NumFiles + Call D_SortRoutine + + Ret + +EndP D_SortFileNames + +; + +Proc D_SortDirNames + + Mov CX, CS:NumFiles + Mov DX, CX + Add DX, CS:NumDirectories + Call D_SortRoutine + + Ret + +EndP D_SortDirNames + +; + +Proc D_InitLoadModule Far + + Push DS + Push ES + Push DI + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:Disk + + Mov SI, Offset FileSpecifierDefault + Mov DI, Offset FileSpecifier + Mov CX, 65 + Rep MovsB + + Pop DI + Pop ES + Pop DS + Assume DS:Nothing + +Proc D_InitLoadModule2 Far + + Cmp CS:FileSpecifier, 0 + JE D_InitLoadModule + + Push DS + Push ES + Push DI + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:Disk + + Mov DI, Offset CurrentSearchPos + Mov CX, 14 + Xor AL, AL + Rep StosB + + Mov LoadSongNameCount, 0 + + Mov SI, Offset SongDirectory + Call D_SetDriveDirectory ; DS:SI points to cur dir. + + Call D_LoadFileNames + Call D_SortFileNames + Call D_SortDirNames + + Pop DI + Pop ES + Pop DS + Ret + +EndP D_InitLoadModule2 + +EndP D_InitLoadModule + Assume DS:Nothing + +; + +Proc D_DrawFileWindow Far ; Layout of filenames in memory + ; Start at offset 2000 + ; Pointers to filenames at 0 + + Push CS + Pop DS + Assume DS:Disk + + Call S_GetDestination + + Mov AX, TopFile + Mov BX, CurrentFile + Cmp AX, BX + JBE D_DrawFileWindow1 + + Mov AX, BX + +D_DrawFileWindow1: + LEA CX, [EAX+30] + Cmp CX, BX + JA D_DrawFileWindow2 + + LEA AX, [BX-30] + +D_DrawFileWindow2: + Mov TopFile, AX + Mov BX, AX ; BX = filenum + + Mov DS, DiskDataArea + Assume DS:Nothing + + Mov DI, (3+13*80)*2 + Mov CX, 31 + + +D_DrawFileWindow3: + LEA SI, [EBX+EBX] + Mov SI, [SI] + + Push DI + + Cmp BX, NumFiles + JAE D_DrawFileWindow4 + + Push SI + Push DI + + Mov AH, 2 + Cmp CS:FileColours, 0 + JE D_DrawFileWindow28 + + Mov AH, 6 ; Not checked colour + Mov AL, [SI+23] + + Test AL, AL + JE D_DrawFileWindow28 + + Mov AH, 7 ; Not known colour + Cmp AL, 1 + JE D_DrawFileWindow28 + + Mov AH, 3 ; Impulse Tracker colour + Cmp AL, 3 + JBE D_DrawFileWindow28 + Cmp AL, 7 + JE D_DrawFileWindow28 + + Mov AH, 5 ; Scream Tracker colour + Cmp AL, 8 + JBE D_DrawFileWindow28 + + Mov AH, 2 ; MOD/MTM colour + +D_DrawFileWindow28: + Push CX + + Add SI, 8 + Mov CX, 12 + +D_DrawFileWindow6: + LodsB + StosW + + And AL, AL + LoopNZ D_DrawFileWindow6 + +; JCXZ D_DrawFileWindow30 + + Xor AL, AL + Rep StosW + + Pop CX + +; D_DrawFileWindow30: + Pop DI + Pop SI + +D_DrawFileWindow4: + Add DI, 24 + Add SI, 25 + + Mov AX, 2A8h + StosW + + Cmp BX, NumFiles + JAE D_DrawFileWindow9 + + Mov AH, 2 ; Song name.. + Mov DX, 25 + + Add AH, CS:FileColours + +D_DrawFileWindow5: + LodsB + Cmp AL, 226 + JB D_DrawFileCharFilter + + Mov AL, ' ' + +D_DrawFileCharFilter: + StosW + + Dec DX + JNZ D_DrawFileWindow5 + +D_DrawFileWindow9: + Pop DI + Add DI, 160 + Inc BX + + Loop D_DrawFileWindow3 + + Push CS + Pop DS + Assume DS:Disk + + Cmp NumFiles, 0 + JE D_DrawFileWindow7 + + Jmp D_DrawFileWindow11 + +D_DrawFileWindow7: + Mov SI, Offset NoFilesMsg + Mov DI, (3+13*80)*2 + Mov AH, 7 + Mov CX, 9 + +D_DrawFileWindow8: + LodsB + StosW + + Loop D_DrawFileWindow8 + +D_DrawFileWindow11: +; Push CS ; Not necessary +; Pop DS + + Mov SI, Offset Search + Mov DI, (51+37*80)*2 + Mov CX, 13 + Mov AH, 5 + +D_DrawFileWindow10: + LodsB + StosW + + Loop D_DrawFileWindow10 + + Cmp NumFiles, 0 + JNE D_DrawFileWindow12 + + Ret + +D_DrawFileWindow12: + Mov BX, CurrentFile + Add BX, BX + + Mov DS, DiskDataArea + Assume DS:Nothing + + Mov BX, [BX] + Mov SI, [BX+23] + Mov AL, [BX+22] + Mov DI, (51+40*80)*2 + + Push CS + Pop DS + Assume DS:Disk + + Add SI, SI + Mov SI, [FormatNames+SI] + Cmp SI, Offset ChannelXX + JNE D_DrawFileWindow29 + + Xor AH, AH + Push AX ; Number of channels for MOD + + Mov AH, 5 + Call S_DrawString + Pop AX ; Add SP, 2 + + Jmp D_DrawFileWindow14 + +D_DrawFileWindow29: + Mov AH, 5 + +D_DrawFileWindow13: + LodsB + And AL, AL + JZ D_DrawFileWindow14 + + StosW + Jmp D_DrawFileWindow13 + +D_DrawFileWindow14: + Mov DS, DS:DiskDataArea + Assume DS:Nothing + + Mov DX, [BX+6] + Mov AX, [BX+4] + Cmp DX, 10000 + + JAE D_DrawFileWindow15 + + Mov DI, (51+41*80)*2 + + Mov CX, 10000 + Div CX ; DX = remainder. AX = main. + + Mov BP, AX + + Mov CX, 4 + Mov SI, 10 + Mov AX, DX + +D_DrawFileWindow16: + Xor DX, DX + Div SI + Add DL, '0' + Push DX + + Loop D_DrawFileWindow16 + + Mov AX, BP + + Mov CX, 5 + +D_DrawFileWindow17: + Xor DX, DX + Div SI + Add DL, '0' + Push DX + + Loop D_DrawFileWindow17 + + Mov CX, 9 + +D_DrawFileWindow18: + Pop AX + Mov AH, 5 + StosW + Loop D_DrawFileWindow18 + +D_DrawFileWindow15: ; OK, time for a date :) + Mov DX, [DS:BX] ; DX = time + Mov BX, [DS:BX+2] ; BX = date + + Push CS + Pop DS + Assume DS:Disk + + Mov DI, (51+42*80)*2 + Mov AX, BX + ShR AX, 5 + And AX, 0Fh + LEA SI, [EAX+EAX] + Mov SI, [MonthNames+SI] + + Mov AH, 5 + +D_DrawFileWindow19: + LodsB + StosW + And AL, AL + JNZ D_DrawFileWindow19 + + Mov AL, BL + And AX, 31 + Mov CH, 10 + Div CH + And AL, AL + JZ D_DrawFileWindow20 + + Push AX + Add AL, '0' + Mov AH, 5 + StosW + + Pop AX + +D_DrawFileWindow20: + Mov AL, AH + Add AL, '0' + Mov AH, 5 + StosW + + Mov AL, ',' + StosW + + Mov AL, ' ' + StosW + + Push DX + Mov AL, BH + ShR AX, 1 + And AX, 7Fh + Add AX, 1980 + Mov DX, 0FFFFh + Push DX + + Mov SI, 10 + +D_DrawFileWindow21: + Xor DX, DX + Div SI + Add DL, '0' + Push DX + + And AX, AX + JNZ D_DrawFileWindow21 + +D_DrawFileWindow22: + Pop AX + Cmp AX, 0FFFFh + JE D_DrawFileWindow23 + + Mov AH, 5 + StosW + + Jmp D_DrawFileWindow22 + +D_DrawFileWindow23: + Pop DX + Mov DI, (51+43*80)*2 + + Mov AX, DX + ShR AX, 11 + + Xor BL, BL ; if BL = 0, then am, otherwise + ; pm.. + Cmp AX, 12 + JB D_DrawFileWindow24 + + Inc BX + Sub AX, 12 + +D_DrawFileWindow24: + And AX, AX + JNZ D_DrawFileWindow25 + + Add AX, 12 + +D_DrawFileWindow25: + Mov BH, 10 + Div BH + And AL, AL + JZ D_DrawfileWindow26 + + Push AX + Add AL, '0' + Mov AH, 5 + StosW + + Pop AX + +D_DrawFileWindow26: + Mov AL, AH + Add AL, '0' + Mov AH, 5 + StosW + + Mov AL, ':' + StosW + + Mov AX, DX + ShR AX, 5 + And AX, 63 + + Div BH + Mov BH, AH + + Add AL, '0' + Mov AH, 5 + StosW + + Mov AL, BH + Add AL, '0' + StosW + + Mov AL, 'a' + And BL, BL + JZ D_DrawFileWindow27 + + Mov AL, 'p' + +D_DrawFileWindow27: + StosW + Mov AL, 'm' + StosW + + Ret + +EndP D_DrawFileWindow + Assume DS:Nothing + +; + +Proc D_DrawDirectoryWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Call S_GetDestination + + Mov AX, TopDirectory + Mov BX, CurrentDirectory + Cmp AX, BX + JBE D_DrawDirectoryWindow1 + + Mov AX, BX + +D_DrawDirectoryWindow1: + LEA CX, [EAX+20] + Cmp CX, BX + JA D_DrawDirectoryWindow2 + + LEA AX, [BX-20] + +D_DrawDirectoryWindow2: + Mov TopDirectory, AX + Mov BX, AX + + Mov CX, 21 + Mov DI, (44+13*80)*2 + + Mov DS, DiskDataArea + Assume DS:Nothing + +D_DrawDirectoryWindow3: + Cmp BX, CS:NumDirectories + JAE D_DrawDirectoryWindow4 + + Mov SI, BX + Add SI, CS:NumFiles + Add SI, SI + Mov SI, [SI] + + Push DI + + Add SI, 8 + Mov AH, 5 + +D_DrawDirectoryWindow5: + LodsB + And AL, AL + JZ D_DrawDirectoryWindow8 + + StosW + Jmp D_DrawDirectoryWindow5 + +D_DrawDirectoryWindow8: + Pop DI + Add DI, 160 + Inc BX + + Loop D_DrawDirectoryWindow3 + +D_DrawDirectoryWindow4: + Push CS + Pop DS + Assume DS:Disk + + Cmp NumDirectories, 0 + JE D_DrawDirectoryWindow6 + + Ret + +D_DrawDirectoryWindow6: + Mov SI, Offset NoDirsMsg + Mov DI, (44+13*80)*2 + Mov AH, 7 + Mov CX, 8 + +D_DrawDirectoryWindow7: + LodsB + StosW + + Loop D_DrawDirectoryWindow7 + + Ret + +EndP D_DrawDirectoryWindow + Assume DS:Nothing + +; + +Proc D_DrawDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Call S_GetDestination + + Mov AL, TopDrive + Mov BL, CurrentDrive + Cmp AL, BL + JBE D_DrawDriveWindow1 + + Mov AL, BL + +D_DrawDriveWindow1: + Mov CL, AL + Add CL, 20 + Cmp CL, BL + JA D_DrawDriveWindow2 + + Mov AL, BL + Sub AL, 20 + +D_DrawDriveWindow2: + Mov TopDrive, AL + Mov BL, AL + Mov CX, 21 + + Mov DI, (59+13*80)*2 + Xor BH, BH + +D_DrawDriveWindow3: + Cmp BL, NumDrives + JAE D_DrawDriveWindow5 + + Push DI + + Mov AL, [DrivesAvail+BX] + Add AL, 'A' + Mov SI, Offset DriveMsg + Mov [SI+6], AL + + Mov AH, 5 + Mov DX, 8 + +D_DrawDriveWindow4: + LodsB + StosW + + Dec DX + JNZ D_DrawDriveWindow4 + + Pop DI + Add DI, 160 + Inc BX + Loop D_DrawDriveWindow3 + +D_DrawDriveWindow5: + Ret + +EndP D_DrawDriveWindow + Assume DS:Nothing + +; + +Proc D_LoadFileHeader ; Given DS:SI = filename + + Push BP + + Xor BP, BP ; BP = 0 (no MMTSR) + + Mov AX, 4370h + Int 21h ; MMTSR installation check. + + Cmp EAX, 4352697Ah + JNE D_LoadFileHeader2 + + Mov AX, 4372h + Int 21h ; Disable MMTSR + + Inc BP + +D_LoadFileHeader2: + Mov DX, SI + Mov AX, 3D00h + Int 21h ; Open File + JC D_LoadFileHeader1 + + Mov BX, AX ; BX = file handle + + Push DS + Pop ES + Mov DI, 60000 + Mov CX, 5536 + Xor AL, AL + Rep StosB ; Clear data area first... + + Mov AH, 3Fh + Mov CX, 5536 + Mov DX, 60000 + Int 21h + PushF + + JC D_LoadFileHeader5 + Test BP, BP + JZ D_LoadFileHeader5 + + Cmp DWord Ptr [DS:60000], 'CRiz' + JNE D_LoadFileHeader5 + + Cmp DWord Ptr [DS:60004], 'aiNO' + JNE D_LoadFileHeader5 + ; OK.. have a MMCMPed file. + Mov AX, 4200h + Mov DX, [DS:60018] + Mov CX, [DS:60020] + Int 21h + + Mov AH, 3Fh + Mov CX, 4 + Mov DX, 60000 + Int 21h + Cmp AX, CX + JNE D_LoadFileHeader5 + + Mov AX, 4200h + Mov DX, [DS:60000] + Mov CX, [DS:60002] + Int 21h ; Seek to offset in file. + + Mov AH, 3Fh + Mov CX, 28 + Mov DX, 60000 + Int 21h + Cmp AX, CX + JNE D_LoadFileHeader5 + + Mov AX, [DS:60014] + ShR AX, 4 + And AL, 7 + JNZ D_LoadFileHeader5 + + PopF + Mov AH, 3Fh + Mov CX, 5536 + Mov DX, 60000 + Int 21h + PushF + +D_LoadFileHeader5: + Mov AH, 3Eh ; Close file + Int 21h + +D_LoadFileHeader4: + Test BP, BP + JZ D_LoadFileHeader3 + ; Reenable MMTSR + Mov AX, 4371h + Int 21h + +D_LoadFileHeader3: + PopF + + Pop BP + StI ; For problems with MMTSR + Ret + +D_LoadFileHeader1: + StC + PushF + Jmp D_LoadFileHeader4 + +EndP D_LoadFileHeader + +; + +Proc D_LoadModuleHeader + + Mov DS, DiskDataArea + Assume DS:Nothing + + Add BX, BX + Mov SI, [BX] + Add SI, 8 + + Call D_LoadFileHeader + + Ret + +EndP D_LoadModuleHeader + +; + +Proc D_LoadSongNames Far ; Part of idle list. + + Call K_IsAnyKeyDown + And AL, AL + JNZ D_LoadSongNames2 + + Call GetKeyboardLock + And AL, AL + JNZ D_LoadSongNames2 + + Push CS + Pop DS + Assume DS:Disk + + Mov BX, LoadSongNameCount + Cmp BX, NumFiles + JB D_LoadSongNames1 + +D_LoadSongNames2: + Xor AX, AX ; No redraw screen. + Ret + +D_LoadSongNames1: + Inc LoadSongNameCount + + Call D_LoadModuleHeader + JC D_LoadSongNames3 + + Call D_GetSongNameModuleType + +D_LoadSongNames3: + + Mov AX, 1 ; Signify redraw screen + Ret + +EndP D_LoadSongNames + +; + +Proc D_PreFileWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov AX, CurrentFile + Sub AX, TopFile + Add AX, 13 + Mov BX, 160 + Mul BX + + Call S_GetDestination + + LEA DI, [EAX+6] + Mov CX, 38 + +D_PreFileWindow1: + Mov AX, [ES:DI] + Cmp CX, 26 + +; Cmp AL, 168 + JNE D_PreFileWindow2 + + Mov AH, 32h + Jmp D_PreFileWindow3 + +D_PreFileWindow2: + Mov AH, 30h + +D_PreFileWindow3: + StosW + + Loop D_PreFileWindow1 + + Mov DI, (51+37*80)*2 + Xor AH, AH + Mov AL, CurrentSearchPos + LEA DI, [EDI+EAX*2+1] + Mov AL, 60h + StosB + + Ret + +EndP D_PreFileWindow + Assume DS:Nothing + +; + +Proc D_PreDirectoryWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov AX, CurrentDirectory + Sub AX, TopDirectory + Add AX, 13 + Mov BX, 160 + Mul BX + + Call S_GetDestination + + LEA DI, [EAX+88] + + Mov CX, 12 + +D_PreDirectoryWindow1: + Mov AX, [ES:DI] + Mov AH, 30h + StosW + + Loop D_PreDirectoryWindow1 + + Ret + +EndP D_PreDirectoryWindow + Assume DS:Nothing + +; + +Proc D_PreDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov AL, CurrentDrive + Sub AL, TopDrive + Add AL, 13 + Mov AH, 160 + Mul AH + + Call S_GetDestination + LEA DI, [EAX+118] + Mov CX, 8 + +D_PreDriveWindow1: + Mov AX, [ES:DI] + Mov AH, 30h + StosW + + Loop D_PreDriveWindow1 + + Ret + +EndP D_PreDriveWindow + Assume DS:Nothing + +; + +Proc D_LoadFileOpenErrorMsg Far + + Mov DI, (4+16*80)*2 + Mov AH, 4 + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset OpenErrorMsg + + Call S_DrawString + + Mov AX, 1 + Ret + +EndP D_LoadFileOpenErrorMsg + Assume DS:Nothing + +; + +Proc D_Decompress16BitData + +; Register usage: +; BX = LastValue +; CH = Bitdepth +; CL = 16-Bitdepth, 0 for Bitdepth > 16 +; DL = Bitsread +; DH = scratch + + PushAD + Mov BP, CX + Mov CX, 1100h + ShR BP, 1 + Xor DX, DX + Xor BX, BX + +D_Decompress16BitData1: + Push CX + + Mov EAX, [SI] + Mov CL, DL + ShR EAX, CL + + Add DL, CH + Mov CX, DX + ShR CX, 3 + Add SI, CX + And DL, 7 + + Pop CX + + Cmp CH, 6 + JA D_Decompress16BitA + + ShL EAX, CL + Cmp AX, 8000h + JE D_Decompress16BitDepthChange1 + +D_Decompress16BitD: + SAR AX, CL + +D_Decompress16BitC: + Add BX, AX + Mov [ES:DI], BX + ScasW +; Add DI, 2 + + Dec BP + JNZ D_Decompress16BitData1 + + PopAD + Ret + +D_Decompress16BitDepthChange1: + ShR EAX, 16 + And AL, 15 + + Inc AX + +; Advance bits + Add DL, 4 + +D_Decompress16BitDepthChange3: + Cmp AL, CH + SBB AL, 0FFh + Mov CL, 16 + Mov CH, AL + Sub CL, AL + AdC CL, 0 + + Jmp D_Decompress16BitData1 + +D_Decompress16BitA: + Cmp CH, 16 + JA D_Decompress16BitB + + Push DX + Mov DX, 0FFFFh + ShR DX, CL + And AX, DX + ShR DX, 1 + Add DX, 8 + Cmp AX, DX + JA D_Decompress16BitE + Sub DX, 16 + Cmp AX, DX + JBE D_Decompress16BitE + + Sub AX, DX + Pop DX + Jmp D_Decompress16BitDepthChange3 + +D_Decompress16BitE: + Pop DX + ShL AX, CL + Jmp D_Decompress16BitD + +D_Decompress16BitB: + Test EAX, 10000h + JZ D_Decompress16BitC + + Mov CL, 16 + Inc AX + + Sub CL, AL + Mov CH, AL + + Jmp D_Decompress16BitData1 + +EndP D_Decompress16BitData + +; + +Proc D_Decompress8BitData ; DS:SI = source + ; ES:DI = destination + ; CX = count. + + PushA + Mov BP, CX ; BP = counter; + + Mov BX, 900h + Xor CX, CX + Xor DX, DX + +; Register usage: +; BH = Bitdepth +; BL = lastvalue +; CL = 8-bitdepth, undefined for bitdepth > 8 +; CH = Bitsread + +; DX = scratch + +D_Decompress8BitData1: + Push CX + Mov AX, [SI] + Mov CL, CH + +; Get bits loaded into AX properly. + ShR AX, CL + Pop CX + +; Advance SI as necessary. + Add CH, BH + Mov DL, CH + And CH, 7 + ShR DL, 3 + Add SI, DX + + Cmp BH, 6 + JA D_Decompress8BitA + + ShL AX, CL + + Cmp AL, 80h + JE D_Decompress8BitDepthChange1 + +D_Decompress8BitWriteData2: + SAR AL, CL + +D_Decompress8BitWriteData: + Add BL, AL + Mov [ES:DI], BL + + Inc DI + Dec BP + + JNZ D_Decompress8BitData1 + PopA + Ret + +D_Decompress8BitDepthChange1: + Mov AL, AH + Add CH, 3 + + And AL, 7 + Mov DL, CH + + And CH, 7 + ShR DL, 3 + + Add SI, DX + Jmp D_Decompress8BitD + +D_Decompress8BitA: + Cmp BH, 8 + JA D_Decompress8BitC + JE D_Decompress8BitB + + ShL AL, 1 + Cmp AL, 78h + JB D_Decompress8BitWriteData2 + Cmp AL, 86h + JA D_Decompress8BitWriteData2 + + ShR AL, 1 + Sub AL, 3Ch + Jmp D_Decompress8BitD + +D_Decompress8BitB: + Cmp AL, 7Ch + JB D_Decompress8BitWriteData + Cmp AL, 83h + JA D_Decompress8BitWriteData + + Sub AL, 7Ch + +D_Decompress8BitD: + Mov CL, 8 + Inc AX + + Cmp AL, BH + SBB AL, 0FFh + Mov BH, AL + Sub CL, AL + AdC CL, 0 + + Jmp D_Decompress8BitData1 + +D_Decompress8BitC: ; 9 bit representation + And AX, 1FFh + + Test AX, 100h + JZ D_Decompress8BitWriteData + + Jmp D_Decompress8BitD + +EndP D_Decompress8BitData + +; + +TempData DW 0 +DisableStereoMenu DB 0 + +Proc D_LoadSampleData ; DS:SI points to sample header + ; AX = sample number (0 based) + + Push DS + Push ES + PushAD + + Mov EDX, [DS:SI+30h] + And EDX, EDX + JZ D_NoLoadSample + + Mov CL, [SI+12h] + Mov BP, [SI+2Eh] + + And Byte Ptr [SI+12h], Not 0Ch + Mov Byte Ptr [SI+2Eh], 1 + And BP, 0FFh + + ShL BP, 1 + Mov CH, CL + And CX, 802h + ShL CH, 4 + ShR CL, 1 + Or BP, CX ; BP flags: + ; 1: 16 bit + ; 2: Convert unsigned->signed + ; 4: Swap bytes + ; 8: Delta values. + ; 16: Byte delta values + ; 32: 12-bit sample. + ; 64: Stereo prompt. + ; 8000h: Compressed. + + Xor SI, SI + + Test BP, 1 + JZ D_LoadSampleData5 + + Add EDX, EDX + +D_LoadSampleData5: + Test BP, 64 + JZ D_LoadSampleDataNotStereo + + Cmp CS:DisableStereoMenu, 0 + JNE D_NoStereoMenu + + PushAD + Push DS ES + + Mov DI, Offset O1_StereoSampleList + Mov CX, 0FFFFh + Call M_Object1List + + Mov CS:TempData, DX + + Pop ES DS + PopAD + + Or BP, CS:TempData ; 64 = left + ; 64+128 = right +D_NoStereoMenu: + Add EDX, EDX + +D_LoadSampleDataNotStereo: + Call Music_AllocateSample ; AX = sample no. + ; EDX = length. + ; returns ES:DI. + Inc AX + + Mov EDI, EDX + + Mov DX, ES + Test DX, DX + JZ D_LoadSampleData1 + + Push DS + + Xor CX, CX ; Start with page 0 + +D_LoadSampleData3: + Push AX ; AX = sample no. + Push CX ; CH = page no. + Push EDI ; EDI = bytes remaining + ; SI = delta accumulator + ; BX = file pointer + + Push SI + Call Music_GetSampleLocation + Mov DX, SI + Pop SI + + Mov ECX, 32768 + Cmp EDI, ECX + JA D_LoadSampleData4 + + Mov CX, DI + +D_LoadSampleData4: + Test BP, 32 ; 12 bit format? + JZ NotTX12BitSampleA + + And ECX, 0FFFFh + LEA ECX, [ECX*2+ECX] + Add ECX, 3 + ShR ECX, 2 ; ECX = bytes to read. + +NotTX12BitSampleA: + +; DS:DX point to buffer. For compressed samples, use +; patterndata area. + + Test BP, BP + JNS LoadCompressedSample1 + + Push DS + Push CX + Push DX + + Mov DX, Pattern + Mov DS, DX + Assume DS:Pattern + + Mov DS, Word Ptr [PatternDataArea] + Assume DS:Nothing + + Xor DX, DX + Mov CX, 2 + Mov AH, 3Fh + Int 21h + Mov CX, [DS:0] ; Bytes to read. + Xor DX, DX ; Compressed chunk. + +LoadCompressedSample1: + + Mov AH, 3Fh + Int 21h + +; Now to decompress samples, if required. + + Test BP, BP + JNS LoadCompressedSample3 + + Pop DI + Pop CX + Pop ES + Xor SI, SI + + Test BP, 1 + JNZ LoadCompressedSample2 + + Call D_Decompress8BitData ; 8 bit decode. + Jmp LoadCompressedSample4 + +LoadCompressedSample2: ; 16 bit decode + Call D_Decompress16BitData + +LoadCompressedSample4: + Push ES + Pop DS + + Xor SI, SI + Jmp SecondDelta + +LoadCompressedSample3: + Test BP, 32 ; 12-bit sample? + JZ NotTX12BitSampleB + ; CX = number of bytes read. + ; = 3*2 number of sample read + Push SI + Push DX + + Add AX, 2 + Mov CX, 3 + Div CX + Mov CX, AX + Pop DX + + LEA SI, [EAX*2+EAX] ; SI = AX * 3 + LEA DI, [EAX*4+EDX] + Add SI, DX + + Test CX, CX + JZ ConvertTXSample2 + + Push CX + +ConvertTXSample1: + Sub SI, 3 + Sub DI, 4 + + Mov AX, [SI+1] + ShL AL, 4 + ShL EAX, 16 + Mov AH, [SI] + Mov AL, [SI+1] + And AL, 0F0h + Mov [DI], EAX + + Loop ConvertTXSample1 + + Pop CX + Pop SI + ShL CX, 1 + Jmp D_LoadSampleData10 + +ConvertTXSample2: + Pop SI + Jmp D_LoadSampleData6 + +NotTX12BitSampleB: + Mov CX, AX ; CX = number of bytes read + +SecondDelta: + Test BP, 1 ; 16 bit? + JZ D_LoadSampleData10 + + ShR CX, 1 + +D_LoadSampleData10: + Mov AX, BP + And AX, 5 ; 16 bit and BSwap? + Cmp AX, 5 + JNE D_LoadSampleData11 + + Push CX + Mov DI, DX + +D_LoadSampleData12: + Mov AX, [DI] + XChg AH, AL + Mov [DI], AX + ScasW +; Add DI, 2 + Loop D_LoadSampleData12 + + Pop CX + +D_LoadSampleData11: + Test BP, 24 ; Delta values? + JZ D_LoadSampleData8 + + Push CX + Mov AX, SI + Mov DI, DX + + Test BP, 1 ; 8 bit sample? + JZ D_LoadSampleData9 + + Test BP, 16 ; Byte enforced? + JZ D_LoadSampleData7 + + Add CX, CX + Jmp D_LoadSampleData9 + +D_LoadSampleData7: ; 16 bit delta + Add AX, [DI] + Mov [DI], AX + +; Add DI, 2 + ScasW + Loop D_LoadSampleData7 + + Mov SI, AX + Pop CX + + Jmp D_LoadSampleData8 + +D_LoadSampleData9: ; 8 bit delta + Add AH, [DI] + Mov [DI], AH + Inc DI + Loop D_LoadSampleData9 + + Mov SI, AX + Pop CX + +D_LoadSampleData8: + Test BP, 2 ; unsigned->signed? + JNZ D_LoadSampleData6 + + Push CX + Mov DI, DX + + Test BP, 1 + JNZ D_LoadSampleData14 + +D_LoadSampleData13: ; 8 bit + Xor Byte Ptr [DI], 80h + Inc DI + Loop D_LoadSampleData13 + + Pop CX + + Jmp D_LoadSampleData6 + +D_LoadSampleData14: ; 16 bit.. + Xor Word Ptr [DI], 8000h +; Add DI, 2 + ScasW + Loop D_LoadSampleData14 + + Pop CX + +D_LoadSampleData6: + Test BP, 64 ; Stereo? + JZ D_LoadSampleDataNoStereo + + Push SI ES + + Push DS + Pop ES + + Mov SI, DX + Mov DI, DX + + ShR CX, 1 + JZ D_LoadSampleDataEndStereo + + Test BP, 1 ; 8/16 bit? + JNZ D_LoadSampleDataStereo16BitStart + + Test BP, 128 + JZ D_LoadSampleDataStereo8Bit + + Inc SI + +D_LoadSampleDataStereo8Bit: + MovsB + Inc SI + Loop D_LoadSampleDataStereo8Bit + Jmp D_LoadSampleDataEndStereo + +D_LoadSampleDataStereo16BitStart: + Test BP, 128 + JZ D_LoadSampledataStereo16Bit + + LodsW + +D_LoadSampleDataStereo16Bit: + MovsW + LodsW + Loop D_LoadSampleDataStereo16Bit + +D_LoadSampleDataEndStereo: + Pop ES SI + + Pop EDI + Pop CX + Pop AX + + Inc CH + Jmp D_LoadSampleDataNextChain + +D_LoadSampleDataNoStereo: + Pop EDI + Pop CX + Pop AX + + Add CH, 2 + +D_LoadSampleDataNextChain: + Sub EDI, 32768 + JA D_LoadSampleData3 + + Pop DS + +D_NoLoadSample: + ClC + + PopAD + Pop ES + Pop DS + Ret + +D_LoadSampleData1: + PopAD + PushAD + + Mov AX, 4201h ; Advance file ptr. + Mov DX, [DS:SI+30h] + Mov CX, [DS:SI+32h] + Int 21h + + Call PEFunction_OutOfMemoryMessage + + PopAD + Pop ES + Pop DS + + StC + Ret + +EndP D_LoadSampleData + +; + +Proc ConvertWriteData ; DS:DX points to data + ; BP = 1, convert, BP = 2, 16-bit + ; CX = number of bytes + + PushF + + Push AX + Push CX + Push SI + + Mov AX, 1 + Test BP, 2 + JZ ConvertWriteDataLoop1 + + Inc AX + Inc SI + ShR CX, 1 + +ConvertWriteDataLoop1: + JCXZ ConvertWriteDataLoop3 + +ConvertWriteDataLoop2: + Xor Byte Ptr [SI], 80h + Add SI, AX + Loop ConvertWriteDataLoop2 + +ConvertWriteDataLoop3: + Pop SI + Pop CX + Pop AX + +ConvertWriteData1: + PopF + Ret + +EndP ConvertWriteData + +; + +Proc D_SaveSampleDataConvert ; AX = sample number (1 based) + + PushAD + Push DS + Push ES + + Xor BP, BP + + Call Music_GetSampleLocation + Mov EDI, ECX + JZ D_SaveSampleDataConvert5 + + Add EDI, EDI + Or BP, 2 + +D_SaveSampleDataConvert5: + Xor CX, CX ; Start with page 0 + +D_SaveSampleDataConvert3: + Push AX ; AX = sample no. + Push CX ; CX = page no. + + Call Music_GetSampleLocation + Mov DX, SI + + Mov ECX, 32768 + Cmp EDI, ECX + JA D_SaveSampleDataConvert4 + + Mov CX, DI + +D_SaveSampleDataConvert4: + ClI + + Call ConvertWriteData + Call D_SaveBlock + Call ConvertWriteData + + StI + + Pop CX + Pop AX + + JC D_SaveSampleDataConvert2 + + Add CH, 2 + Sub EDI, 32768 + JA D_SaveSampleDataConvert3 + + DB 85h ; ClC +D_SaveSampleDataConvert2: + StC + Pop ES + Pop DS + PopAD + Ret + +EndP D_SaveSampleDataConvert + +; + +Proc WriteBits ; CH = bits to write + ; CL = current bit. + ; BX = data. + ; ES:DI = output buffer. + ; EAX = buffer + ; BP = scratch + + Push CX + + Mov EBP, 1 + Mov CL, CH + ShL EBP, CL + Dec EBP + And EBX, EBP + + Pop CX + ShL EBX, CL + Add CL, CH + Or EAX, EBX + +D_WriteBits1: + Cmp CL, 8 + JB D_WriteBits2 + + StosB + ShR EAX, 8 + Sub CL, 8 + Jmp D_WriteBits1 + +D_WriteBits2: + Ret + +EndP WriteBits + +; + +; Data layout: +; DiskDataArea:16384 = deltas +; PatternDataArea:16384 = bittable +; PatternDataArea:0 = bufferlength +; PatternDataArea:2 = outputbuffer + +Proc D_SaveSampleDataCompressed ; AX = sample number, 1 based. + + PushAD + Push DS + Push ES + + Xor BP, BP + + Call Music_GetSampleLocation + Mov EDI, ECX + JZ D_SaveSampleDataCompressed5 + + Add EDI, EDI + Inc BP + +D_SaveSampleDataCompressed5: + Xor CX, CX ; Start with page 0 + +D_SaveSampleDataCompressed3: + Push AX ; AX = sample no. + Push CX ; CX = page no. + Push EDI + + Call Music_GetSampleLocation + + Mov ECX, 32768 + Cmp EDI, ECX + JA D_SaveSampleDataCompressed4 + + Mov CX, DI + +D_SaveSampleDataCompressed4: + Test BP, 1 + JZ D_SaveSampleCompressed8BitSample + + ShR CX, 1 + +D_SaveSampleCompressed8BitSample: +; DS:SI = sample location +; Calculate delats first. + Push BX + Push BP + Push CX + + Mov ES, CS:DiskDataArea + Mov DI, 16384 ; Offset in DiskDataArea + +IF DDCOMPRESS + Mov DX, 1 + + Cmp CS:SaveFormat, 3 + JNE D_SaveFormatNot215 + + Inc DX + +D_SaveFormatNot215: + +ENDIF + +D_CalculateDeltas: + Xor AH, AH ; AH = lastdata. + + Test BP, 1 + JZ D_Calculate8BitDeltas + + Xor BX, BX + +D_Calculate16BitDeltas: + LodsW + Sub AX, BX + Mov BX, [SI-2] + StosW + Loop D_Calculate16BitDeltas + + Jmp D_CalculateDeltaEnd + +D_Calculate8BitDeltas: + LodsB + Sub AL, AH + Mov AH, [SI-1] + StosB + Loop D_Calculate8BitDeltas + +D_CalculateDeltaEnd: + +IF DDCOMPRESS + Mov DI, 16384 + Pop CX + Push ES + Mov SI, DI + Pop DS + Push CX + + Dec DX + JNZ D_CalculateDeltas + + Push Pattern + Pop ES + Assume ES:Pattern + Mov ES, PatternDataArea + Assume ES:Nothing + +ELSE + + Pop CX + +; Now to create bittable. + + Push ES + Pop DS + + Push Pattern + Pop ES + Assume ES:Pattern + Mov ES, PatternDataArea + Assume ES:Nothing + + Push CX + + Mov SI, 16384 + Mov DI, SI +ENDIF + + Mov BH, 40 + Test BP, 1 + JZ D_GenerateBitTable1 + + Xor AX, AX + +D_Generate16BitTable1: + Mov BL, [SI+1] + Mov BH, 41 + Mov AL, [BX] + Mov DL, AL + And DL, 7 + Mov BL, [SI] + Add BH, DL + ShR AL, 3 + Add SI, 2 + Add AL, [BX] + StosW + + Loop D_Generate16BitTable1 + Pop CX + +; Minimise 16-bit table + Push ES + Pop DS + Mov Byte Ptr [DS:16382], 17 ; Starting boundary of 17. + Mov DL, 1 ; Scan for 1 bit first. + +D_Minimise16BitTable1: + Push CX + Xor AX, AX ; AX = consecutive values. + Mov SI, 16384 + +D_Minimise16BitTable2: + Test AX, AX + JNZ D_Minimise16BitTable3 + +; Not in consecutive sequence. + Cmp DL, [SI] + JNE D_Minimise16BitTableEnd + Mov DI, SI ; First value + +D_Minimise16BitTable4: + Inc AX + Jmp D_Minimise16BitTableEnd + +D_Minimise16BitTable3: + Cmp DL, [SI] + JE D_Minimise16BitTable4 + +; OK.. outside of bittable + Cmp AX, 33 + JA D_Minimise16BitTable5 + + Mov BL, [SI] + Mov BH, [DI-2] + + Cmp BL, BH + JBE D_Minimise16BitTable6 + + XChg BL, BH + +D_Minimise16BitTable6: + Cmp BL, DL + JA D_Minimise16BitTable7 + XChg BL, BH + + Cmp BL, DL + JB D_Minimise16BitTable5 + +D_Minimise16BitTable7: ; BL = minbits. + Push CX + Push DX + + Mov CH, BL + Mov DH, BL ; DH = minbits. + + Cmp AX, 1 + JE D_Minimise16BitTableForce + + Cmp BL, 5 + JA D_Minimise16BitTable8 + + Add BL, 4 + +D_Minimise16BitTable8: + Cmp BH, 5 + JA D_Minimise16BitTable9 + + Add BL, 4 + +D_Minimise16BitTable9: + Mov CL, CH + And BX, 0FFh ; BX = bits to effect conversion + + Cmp AX, BX + JA D_Minimise16BitTable13 + + And CX, 0FFh ; CX = minbits. + + Sub CL, DL + Push DX + Mul CX ; DX:AX = bits saved. + Pop CX + Test DX, DX + JNZ D_Minimise16BitTable13 + Cmp AX, BX + JA D_Minimise16BitTable13 + +D_Minimise16BitTableForce: +; Have to change values from DI -> SI with minbits. + Mov AL, CH + Mov CX, SI + Sub CX, DI + ShR CX, 1 + Rep StosW + +D_Minimise16BitTable13: + Pop DX + Pop CX + +D_Minimise16BitTable5: + Xor AX, AX + +D_Minimise16BitTableEnd: + Add SI, 2 + Loop D_Minimise16BitTable2 + + Pop CX + + And DX, 0FFh + Inc DX + Cmp DX, 17 + JB D_Minimise16BitTable1 + +; Now to dump bits to buffer. + + Mov DX, CX + Mov DS, CS:DiskDataArea + Xor EAX, EAX + Mov DI, 2 + Mov SI, 16384 + Mov CX, 1100h + +; Convert 16 Bit Buffer. + +D_Convert16BitBuffer1: + Cmp CH, [ES:SI] ; BitsToWrite = BitTable? + JE D_Convert16BitBufferEnd + +; Need to change base + Cmp CH, 6 + JA D_Convert16BitBuffer2 + + Push CX + Mov BX, 1 + Mov CL, CH + Dec CL + ShL BX, CL + Pop CX + Call WriteBits + + Mov BL, [ES:SI] + Cmp CH, BL + SBB BL, 1 + Mov CH, 4 + Call WriteBits + Jmp D_Convert16BitBufferDepthChange + +D_Convert16BitBuffer2: + Cmp CH, 16 + JA D_Convert16BitBuffer3 + + Push CX + Mov EBX, 1 + Mov CL, CH + Dec CL + ShL EBX, CL + Sub BX, 9 + Add BL, [ES:SI] + AdC BH, 0 + Pop CX + + Cmp CH, [ES:SI] + SBB BL, 0 + Call WriteBits + Jmp D_Convert16BitBufferDepthChange + +D_Convert16BitBuffer3: + Mov EBX, 100FFh + Add BL, [ES:SI] + Call WriteBits + +D_Convert16BitBufferDepthChange: + Mov CH, [ES:SI] + +D_Convert16BitBufferEnd: + MovZX EBX, Word Ptr [SI] + Call WriteBits + + Add SI, 2 + Dec DX + JNZ D_Convert16BitBuffer1 + + Jmp D_ConvertBitsFinished + + +D_GenerateBitTable1: + Mov BL, [SI] + Inc SI + Mov AL, [BX] + StosB + Loop D_GenerateBitTable1 + +D_GenerateBitTableDone: + +; OK bit table is generated. + Pop CX + +; Have to minimise bit table (in patterndataarea) + + + Push ES + Pop DS + Mov Byte Ptr [DS:16383], 9 ; Starting boundary of 9. + Mov DL, 1 ; Scan for 1 bit first. + +D_MinimiseBitTable1: + Push CX + Xor AX, AX ; AX = consecutive values. + Mov SI, 16384 + +D_MinimiseBitTable2: + Test AX, AX + JNZ D_MinimiseBitTable3 + +; Not in consecutive sequence. + Cmp DL, [SI] + JNE D_MinimiseBitTableEnd + Mov DI, SI ; First value + +D_MinimiseBitTable4: + Inc AX + Jmp D_MinimiseBitTableEnd + +D_MinimiseBitTable3: + Cmp DL, [SI] + JE D_MinimiseBitTable4 + +; OK.. outside of bittable + Cmp AX, 17 + JA D_MinimiseBitTable5 + + Mov BL, [SI] + Mov BH, [DI-1] + + Cmp BL, BH + JBE D_MinimiseBitTable6 + + XChg BL, BH + +D_MinimiseBitTable6: + Cmp BL, DL + JA D_MinimiseBitTable7 + XChg BL, BH + + Cmp BL, DL + JB D_MinimiseBitTable5 + +D_MinimiseBitTable7: ; BL = minbits. + Push CX + Push DX + + Mov DH, BL ; DH = minbits. + Mov CH, BL + + Cmp AX, 1 + JE D_MinimiseBitTableForce + + Cmp BL, 5 + JA D_MinimiseBitTable8 + + Add BL, 3 + +D_MinimiseBitTable8: + Cmp BH, 5 + JA D_MinimiseBitTable9 + + Add BL, 3 + +D_MinimiseBitTable9: + Mov CL, CH ; CL = minbits. + And BX, 0FFh ; BX = bits to effect conversion + + Cmp AX, BX + JA D_MinimiseBitTable13 + + And CX, 0FFh ; CX = minbits. + + Sub CL, DL + Push DX + Mul CX ; DX:AX = bits saved. + Pop CX + Test DX, DX + JNZ D_MinimiseBitTable13 + Cmp AX, BX + JA D_MinimiseBitTable13 + +; Have to change values from DI -> SI with minbits. +D_MinimiseBitTableForce: + Mov AL, CH + Mov CX, SI + Sub CX, DI + Rep StosB + +D_MinimiseBitTable13: + Pop DX + Pop CX + +D_MinimiseBitTable5: + Xor AX, AX + +D_MinimiseBitTableEnd: + Inc SI + Loop D_MinimiseBitTable2 + + Pop CX + + And DX, 0FFh + Inc DX + Cmp DX, 9 + JB D_MinimiseBitTable1 + +; Now to dump bits to buffer. + + Mov DX, CX + Mov DS, CS:DiskDataArea + Xor EAX, EAX + Mov DI, 2 + Mov SI, 16384 + Mov CX, 900h + +D_ConvertBitBuffer1: ; CL = current bit + ; CH = bitstowrite + ; AX = output buffer + ; DX = bytes to process + ; SI = DS:source/ES:bittable + ; DI = destination + + Cmp CH, [ES:SI] ; BitsToWrite = BitTable? + JE D_ConvertBitBufferEnd + +; Need to change base + Cmp CH, 6 + JA D_ConvertBitBuffer2 + + Push CX + Mov BX, 1 + Mov CL, CH + Dec CL + ShL BX, CL + Pop CX + Call WriteBits + + Mov BL, [ES:SI] + Cmp CH, BL + SBB BL, 1 + Mov CH, 3 + Call WriteBits + Jmp D_ConvertBitBufferDepthChange + +D_ConvertBitBuffer2: + Cmp CH, 8 + JA D_ConvertBitBuffer3 + + Push CX + Mov BX, 1 + Mov CL, CH + Dec CL + ShL BX, CL + Sub BL, 5 + Add BL, [ES:SI] + Pop CX + + Cmp CH, [ES:SI] + SBB BL, 0 + Call WriteBits + Jmp D_ConvertBitBufferDepthChange + +D_ConvertBitBuffer3: + Mov BX, 1FFh + Add BL, [ES:SI] + Call WriteBits + +D_ConvertBitBufferDepthChange: + Mov CH, [ES:SI] + +D_ConvertBitBufferEnd: + MovZX BX, Byte Ptr [SI] + Call WriteBits + + Inc SI + Dec DX + JNZ D_ConvertBitBuffer1 + +D_ConvertBitsFinished: + Xor CH, CH + Add CL, 7 + ShR CL, 3 + Rep StosB ; Write 0 or 1 bytes. + +; DI = end of block = size; + + Pop BP + Pop BX + + Mov CX, DI + Sub DI, 2 + + Push ES + Pop DS + + Mov [DS:0], DI + + Xor DX, DX + Call D_SaveBlock + + Pop EDI + Pop CX + Pop AX + + JC D_SaveSampleDataCompressed2 + + Add CH, 2 + Sub EDI, 32768 + JA D_SaveSampleDataCompressed3 + + DB 85h +D_SaveSampleDataCompressed2: + StC + Pop ES + Pop DS + PopAD + Ret + +EndP D_SaveSampleDataCompressed + +; + +Proc D_SaveSampleData ; AX = sample number (1 based) + + PushAD + Push DS + Push ES + + Call Music_GetSampleLocation + Mov EDI, ECX + JZ D_SaveSampleData1 + + Add EDI, EDI + +D_SaveSampleData1: + Xor CX, CX ; Start with page 0 + +D_SaveSampleData3: + Push AX ; AX = sample no. + Push CX ; CX = page no. + + Call Music_GetSampleLocation + Mov DX, SI + + Mov ECX, 32768 + Cmp EDI, ECX + JA D_SaveSampleData4 + + Mov CX, DI + +D_SaveSampleData4: + Call D_SaveBlock + Pop CX + Pop AX + JC D_SaveSampleData2 + + Add CH, 2 + Sub EDI, 32768 + JA D_SaveSampleData3 + + DB 85h +D_SaveSampleData2: + StC + Pop ES + Pop DS + PopAD + + Ret + +EndP D_SaveSampleData + +; + +include it_timer.inc +include it_d_rm.inc + +; + +Proc D_CheckOverWrite ; DS:DX points to filename + ; Returns Carry set if not ok + + Mov CX, 6 + Mov AH, 4Eh + Int 21h + JC D_CheckOverWrite1 ; File doesn't exist. + + ; File Already exists... + + Push BX + Push DS + Push SI + + Mov DI, Offset O1_ConfirmOverWriteList + Mov CX, 4 + Call M_Object1List + ; DX = 0 -> don't overwrite + ; DX = 1 -> overwrite + Pop SI + Pop DS + Pop BX + + Test DX, DX + JZ D_CheckOverWrite2 + +D_CheckOverWrite1: + DB 85h + +D_CheckOverWrite2: + StC + Ret + + +EndP D_CheckOverWrite + +; + +Proc D_PostFileSaveWindow Far + +; Cmp DX, 13 + Cmp CX, 11Ch + JNE D_PostFileWindow + ; Save file routines. + Mov DS, CS:DiskDataArea + Mov SI, CurrentFile + Add SI, SI + Mov SI, [SI] + Add SI, 8 ; Filename + Mov DI, Offset SaveFileName + + Push CS + Pop ES + +D_PostFileSaveWindow1: + LodsB + StosB + And AL, AL + JNZ D_PostFileSaveWindow1 + +D_PostFileSaveWindow2: + Push CS + Pop DS + Assume DS:Disk + + Mov DX, Offset SaveFileName + Call D_CheckOverWrite + JNC D_PostFileSaveWindow3 ; OK to write! + + Mov AX, 1 + Ret + +D_PostFileSaveWindow3: + Cmp SaveFormat, 1 + JE D_PostFileSaveWindow4 + + Jmp D_SaveFileITModule + +D_PostFileSaveWindow4: + Jmp D_SaveFileS3MModule + +EndP D_PostFileSaveWindow + Assume DS:Nothing + +; + +Proc D_PostFileLoadWindow Far + +; Cmp DX, 13 + Cmp CX, 11Ch + JNE D_PostFileWindow + ; Load file routines. + +D_PostFileLoadWindowLink: + EnsureNoNetwork + + Call PECheckModified + + Call Music_Stop + + Mov BX, CS:CurrentFile + Call D_LoadModuleHeader + JC D_PostFileLoadWindow1 + + Push DI + Call D_GetSongNameModuleType + Pop DI + +IF TUTORIAL +ELSE + Mov BX, CS:CurrentFile + Add BX, BX + Mov BX, [BX] + Mov AX, [BX+23] + + Cmp AX, 1 + JBE D_PostFileLoadWindow1 + + Cmp AX, 3 + JB D_LoadFileImpulseModule + JE D_PostFileLoadWindow1 + + Cmp AX, 5 + JB D_LoadFileS3MModule + JE D_LoadFileXMModule + + Cmp AX, 7 + JB D_LoadFile669Module + JE D_LoadFileImpulseModule + + Cmp AX, 8 + JBE D_PostFileLoadWindow1 + + Cmp AX, 17 + JBE D_LoadFileMODModule + + Cmp AX, 18 + JE D_LoadFileMTMModule +ENDIF + +D_PostFileLoadWindow1: + Mov AX, 1 + Ret + +EndP D_PostFileLoadWindow + +; + +Proc D_PostFileWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset FileWindowKeys + Call M_FunctionDivider + JC D_PostFileWindow1 + + Jmp [SI] + +D_PostFileWindow1: + Cmp CX, 10Eh + JNE D_PostFileWindow15 + +D_PostFileWindowBackspace: + Mov BL, CurrentSearchPos + Test BL, BL + JZ D_PostFileWindow14 + + Dec BX + Xor BH, BH + Mov [Search+BX], 0 + Mov CurrentSearchPos, BL + +D_PostFileWindow14: + Mov AX, 1 + Ret + +D_PostFileWindow15: + Test CL, CL + JZ D_PostFileWindow20 + Cmp DL, 33 + JB D_PostFileWindow20 + + Cmp CurrentSearchPos, 13 + JAE D_PostFileWindow17 + + Cmp DL, 'a' + JB D_PostFileWindow16 + + Cmp DL, 'z' + JA D_PostFileWindow16 + + Sub DL, 32 + +D_PostFileWindow16: + Mov BL, CurrentSearchPos + Xor BH, BH + Mov [Search+BX], DL + + Inc CurrentSearchPos + ; Now do the search. + Xor DX, DX + + Mov ES, DiskDataArea + +D_PostFileWindow18: + Cmp DX, NumFiles + JAE D_PostFileWindow17 + + Mov BX, DX + Add BX, BX + Mov DI, [ES:BX] + Add DI, 8 + Mov SI, Offset Search + Mov CX, 13 + +D_PostFileWindow21: + Cmp Byte Ptr [DS:SI], 0 + JE D_PostFileWindow19 + + CmpsB + JE D_PostFileWindow21 + + Inc DX + Jmp D_PostFileWindow18 + +D_PostFileWindow19: + Mov CurrentFile, DX + +D_PostFileWindow17: + Mov AX, 1 + Ret + +D_PostFileWindow20: + Xor AX, AX + Ret + +EndP D_PostFileWindow + Assume DS:Nothing + +; + +Proc D_PostDirectoryWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset DirectoryWindowKeys + Call M_FunctionDivider + JC D_PostDirectoryWindow1 + + Jmp [SI] + +D_PostDirectoryWindow1: + Cmp CX, 10Eh + JNE D_PostDirectoryWindow15 + + Jmp D_PostFileWindowBackspace + +D_PostDirectoryWindow15: + Test CL, CL + JZ D_PostDirectoryWindow20 + Cmp DL, 33 + JB D_PostDirectoryWindow20 + + Cmp CurrentSearchPos, 13 + JAE D_PostDirectoryWindow17 + + Cmp DL, 'a' + JB D_PostDirectoryWindow16 + + Cmp DL, 'z' + JA D_PostDirectoryWindow16 + + Sub DL, 32 + +D_PostDirectoryWindow16: + Mov BL, CurrentSearchPos + Xor BH, BH + Mov [Search+BX], DL + + Inc CurrentSearchPos + ; Now do the search. + Xor DX, DX + + Mov ES, DiskDataArea + +D_PostDirectoryWindow18: + Cmp DX, NumDirectories + JAE D_PostFileWindow17 + + Mov BX, DX + Add BX, NumFiles + Add BX, BX + Mov DI, [ES:BX] + Add DI, 8 + Mov SI, Offset Search + Mov CX, 13 + +D_PostDirectoryWindow21: + Cmp Byte Ptr [DS:SI], 0 + JE D_PostDirectoryWindow19 + + CmpsB + JE D_PostDirectoryWindow21 + + Inc DX + Jmp D_PostDirectoryWindow18 + +D_PostDirectoryWindow19: + Mov CurrentDirectory, DX + +D_PostDirectoryWindow17: + Mov AX, 1 + Ret + +D_PostDirectoryWindow20: + Xor AX, AX + Ret + +EndP D_PostDirectoryWindow + Assume DS:Nothing + +; + +Proc D_PostDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset DriveWindowKeys + Call M_FunctionDivider + JC D_PostDriveWindow1 + + Jmp [SI] + +D_PostDriveWindow1: + Xor AX, AX + Ret + +EndP D_PostDriveWindow + Assume DS:Nothing + +; + +Proc D_PostSaveDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset SaveDriveWindowKeys + Call M_FunctionDivider + JC D_PostSaveDriveWindow1 + + Jmp [SI] + +D_PostSaveDriveWindow1: + Xor AX, AX + Ret + +EndP D_PostSaveDriveWindow + Assume DS:Nothing + +; + +Proc D_NewSpecifier Far + + Push CS + Pop DS + Assume DS:Disk + + Xor BX, BX + Mov SI, Offset FileSpecifier + Mov Specific, 1 + +D_NewSpecifier3: + LodsB + And AL, AL + JZ D_NewSpecifier4 + + Cmp AL, '\' + JE D_NewSpecifier10 + Cmp AL, ':' + JE D_NewSpecifier10 + + Jmp D_NewSpecifier3 + +D_NewSpecifier10: + Mov BX, SI + Jmp D_NewSpecifier3 + +D_NewSpecifier4: + And BX, BX + JZ D_NewSpecifier5 + + Push ES + Push DI + + Push CS + Pop ES + + Mov SI, Offset FileSpecifier + Mov DI, Offset SongDirectory + +D_NewSpecifier7: + MovsB + Cmp SI, BX + JB D_NewSpecifier7 + + Xor AL, AL + Cmp Byte Ptr [DI-1], '\' + JNE D_NewSpecifier11 + + Dec DI + +D_NewSpecifier11: + StosB + + Mov DI, Offset FileSpecifier + +D_NewSpecifier6: + LodsB + StosB + And AL, AL + JNZ D_NewSpecifier6 + + Cmp DI, Offset FileSpecifier+1 + JNE D_NewSpecifier14 + + Mov Specific, 0 + +D_NewSpecifier14: + Pop DI + Pop ES + + +D_NewSpecifier5: + Mov CurrentFile, 0 + Call D_InitLoadModule2 + +D_NewSpecifier12: + Cmp NumFiles, 0 + JE D_NewSpecifier1 + + Mov Word Ptr [ES:DI], 12 + +D_NewSpecifier1: + Cmp Specific, 1 + JNE D_NewSpecifier2 + + Cmp NumFiles, 1 + JNE D_NewSpecifier2 + + Mov SI, Offset FileSpecifier + +D_NewSpecifier8: + LodsB + And AL, AL + JZ D_NewSpecifier9 + + Cmp AL, '*' + JE D_NewSpecifier2 + Cmp AL, '?' + JE D_NewSpecifier2 + Jmp D_NewSpecifier8 + +D_NewSpecifier9: + Jmp D_PostFileLoadWindowLink + +D_NewSpecifier2: + + Mov AX, 1 + Ret + +EndP D_NewSpecifier + Assume DS:Nothing + +; + +Proc D_NewDirectory Far + +; Mov SI, Offset SongDirectory +; Push CS +; Pop DS +; +; Call S_SetDriveDirectory + + Mov CurrentFile, 0 + Call D_InitLoadModule + + Cmp NumFiles, 0 + JE D_NewDirectory1 + + Mov Word Ptr [ES:DI], 12 + +D_NewDirectory1: + Mov AX, 1 + Ret + +EndP D_NewDirectory + +; + +Proc D_ClearFileSpecifier Far + + Push ES + Push DI + Push AX + Push CX + + Push CS + Pop ES + Mov DI, Offset FileSpecifier + Xor AX, AX + Mov CX, 65 + Rep StosB + + Pop CX + Pop AX + Pop DI + Pop ES + + Ret + +EndP D_ClearFileSpecifier + +; + +Proc D_SaveModule Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset FileSpecifier + Cmp Byte Ptr [SI], 0 + JNE D_SaveModule9 + + Call D_NewSpecifier + Call D_ClearFileSpecifier + + Mov AX, 1 + Ret + +D_SaveModule9: + Push CS + Pop ES + Xor BX, BX + +D_SaveModule1: + LodsB + And AL, AL + JZ D_SaveModule3 + + Cmp AL, '?' + JE D_NewSpecifier + Cmp AL, '*' + JE D_NewSpecifier + Cmp AL, ':' + JE D_SaveModule2 + Cmp AL, '\' + JE D_SaveModule2 + + Jmp D_SaveModule1 + +D_SaveModule2: + Mov BX, SI + Jmp D_SaveModule1 + +D_SaveModule3: + And BX, BX + JZ D_SaveModule7 + + Mov SI, Offset FileSpecifier + Mov DI, Offset SongDirectory + +D_SaveModule4: + MovsB + Cmp SI, BX + JB D_SaveModule4 + + Xor AL, AL + Cmp Byte Ptr [DI-1], '\' + JNE D_SaveModule5 + + Dec DI + +D_SaveModule5: + StosB + + Mov DI, Offset FileSpecifier + +D_SaveModule6: + LodsB + StosB + And AL, AL + JNZ D_SaveModule6 + +D_SaveModule7: ; Time to save a module. + Mov DI, Offset SaveFileName + Mov SI, Offset FileSpecifier + +D_SaveModule8: + LodsB + StosB + And AL, AL + JNZ D_SaveModule8 + + ; FileName contains file to + ; save + Mov SI, Offset SongDirectory + Call D_SetDriveDirectory + + Mov SI, Offset SaveFileName + Xor BX, BX + +D_SaveModule10: + LodsB + Cmp AL, '.' + JNE D_SaveModule11 + + Mov BX, SI + +D_SaveModule11: + And AL, AL + JNZ D_SaveModule10 + + And BX, BX + JNZ D_SaveModule12 + + Cmp SaveFormat, 1 + JE D_SaveModule13 + + Mov Word Ptr [SI-1], 'I.' + Mov Word Ptr [SI+1], 'T' + Jmp D_PostFileSaveWindow2 + +D_SaveModule13: + Mov Word Ptr [SI-1], 'S.' + Mov Word Ptr [SI+1], 'M3' + Mov Byte Ptr [SI+3], 0 + +D_SaveModule12: + Jmp D_PostFileSaveWindow2 +; Jmp D_SaveFileITModule + +EndP D_SaveModule + Assume DS:Nothing + +; + +Proc D_NoSaveMessage Far + + Call S_SaveScreen + + Mov DI, Offset O1_UnableToSaveList + Mov CX, 2 + Call M_Object1List + + Call S_RestoreScreen + + Mov AX, 1 + Ret + +EndP D_NoSaveMessage + +; + +Proc D_SaveBlock ; DS:DX points to buffer + ; BX = file handle + ; CX = number of bytes + + JCXZ D_SaveBlock3 + + Cmp CS:NoSaveError, 1 + JE D_SaveBlock2 + + Mov AH, 40h + Int 21h + JC D_SaveBlock1 + Cmp CX, AX + JNE D_SaveBlock1 + +D_SaveBlock3: + Ret + +D_SaveBlock2: + Mov AX, CX + StC + Ret + +D_SaveBlock1: + PushAD + Push DS + Push ES + + Call D_NoSaveMessage + + Pop ES + Pop DS + PopAD + + Mov CS:NoSaveError, 1 + StC + + Ret + +EndP D_SaveBlock + +; + +Proc D_DeleteIfError ; DS:DX = filename + + PushF + + Cmp CS:NoSaveError, 0 + JE D_DeleteIfError1 + + PushA + + Mov AH, 41h + Int 21h + + PopA + +D_DeleteIfError1: + PopF + Ret + +EndP D_DeleteIfError + +; + +Proc D_UpdateFileName + + Push CS + Push CS + Pop DS + Pop ES + + Mov SI, Offset SaveFileName + Mov DI, Offset FileName + ; Scan through file name first. + Mov BX, SI + +D_UpdateFileName1: + LodsB + And AL, AL + JZ D_UpdateFileName2 + + Cmp AL, ':' + JE D_UpdateFileName3 + Cmp AL, '\' + JNE D_UpdateFileName1 + +D_UpdateFileName3: + Mov BX, SI + Jmp D_UpdateFileName1 + +D_UpdateFileName2: + Mov SI, BX + Add BX, 8 + +D_UpdateFileName4: + LodsB + StosB + + Cmp AL, '.' + JE D_UpdateFileName5 + + And AL, AL + JZ D_UpdateFileNameEnd + + Cmp SI, BX + JBE D_UpdateFileName4 + +D_UpdateFileName5: + Mov BX, SI + Add BX, 3 + +D_UpdateFileName6: + LodsB + StosB + + And AL, AL + JZ D_UpdateFileNameEnd + + Cmp SI, BX + JBE D_UpdateFileName6 + +D_UpdateFileNameEnd: + Ret + +EndP D_UpdateFileName + +; + +include it_d_wm.inc + +; + +Proc D_InitLoadSamples Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset SampleDirectory + Call D_SetDriveDirectory ; DS:SI points to cur dir. + + Cmp SamplesInModule, 0 + JE D_InitLoadSamples4 + + Jmp LSWindow_EnterLoadInSampleData + +D_InitLoadSamples4: + Mov LoadSampleNameCount, 0 + Mov NumSamples, 0 + Mov SampleInMemory, 0FFFFh + Mov SampleCheck, 0FFFFh + Mov SampleCacheFileComplete, 0 + + ; First attempt to delete + ; ST3's cache file.. + Mov DX, Offset ST3CacheFileName + Mov AH, 41h + Int 21h + + ; First check for cache file. + Mov OldCacheTime, 0 + + Mov AX, 3D00h ; Open file.. + Mov DX, Offset SampleCacheFileName + Int 21h + JC D_InitLoadSamples1 ; Can't open file? + + Mov BX, AX + + Mov AH, 3Fh + Mov CX, 4 ; Integer containing number + ; of sample entries... + Mov DS, DiskDataArea + Assume DS:Nothing + + Xor DX, DX + Int 21h + JC D_InitLoadSamples3 + Cmp AX, CX + JNE D_InitLoadSamples3 + + Mov AL, [CS:SampleDirectory] ; AL = drive letter + Cmp AL, [CS:CDRomStartDrive] + JL SampleVersionCheck + Cmp AL, [CS:CDRomEndDrive] + JGE SampleVersionCheck + + Cmp Word Ptr [DS:2], 211h + JB D_InitLoadSamples3 + Cmp Word Ptr [DS:2], TRACKERVERSION + JBE D_InitLoadSampleCacheFileOK + +SampleVersionCheck: + Cmp Word Ptr [DS:2], TRACKERVERSION + JNE D_InitLoadSamples3 + +VersionCheckEnd: + Mov AX, 5700h ; Get file date&time. + Int 21h + + Mov Word Ptr [OldCacheTime], CX + Mov Word Ptr [OldCachetime+2], DX + + Cmp CX, Time ; Check time and date + JNE D_InitLoadSamplesOldCache ; for 'currentness' + Cmp DX, Date + JNE D_InitLoadSamplesOldCache + ; OK.. let's load... + +D_InitLoadSampleCacheFileOK: + Mov SI, [DS:0] ; Number of samples. + Mov AX, 96 + Mul SI + Mov CX, AX ; Bytes to read. + + Mov AH, 3Fh ; Load again. + Xor DX, DX ; In case of internal malfunc. + Int 21h + JC D_InitLoadSamples3 + Cmp AX, CX + JNE D_InitLoadSamples3 + + Mov AH, 3Eh ; Close file. + Int 21h + + Push CS + Pop DS + Assume DS:Disk + + Mov LoadSampleNameCount, SI + Mov NumSamples, SI + Mov SampleCacheFileComplete, 1 + + Jmp D_InitLoadSamples2 + +D_InitLoadSamplesOldCache: + PushA + Push DS + + Call D_GetNumFiles ; Returns number of files + ; and directories, + ; carry if newer file exists. + Pop DS + JC D_InitLoadSamples5 + + Cmp AX, [DS:0] + + PopA + + JNE D_InitLoadSamples3 + + Call Far Ptr D_InitLoadSampleCacheFileOK + + Call D_SaveSampleCacheFile ; Resave it with new date + + Ret + +D_InitLoadSamples5: + PopA + +D_InitLoadSamples3: + Mov AH, 3Eh ; Close file. + Int 21h + + Push CS + Pop DS + Assume DS:Disk + + Call DeleteSampleCacheFile + +D_InitLoadSamples1: + Call D_LoadSampleFiles + +D_InitLoadSamples2: + Ret + +EndP D_InitLoadSamples + Assume DS:Nothing + +; + +Proc DeleteSampleCacheFile + + Push DS + + Push CS + Pop DS + + Mov AH, 41h + Mov DX, Offset SampleCacheFileName + Int 21h + + Pop DS + + Ret + +EndP DeleteSampleCachefile + +; + +Proc DeleteInstrumentCacheFile + + Push DS + + Push CS + Pop DS + + Mov AH, 41h + Mov DX, Offset InstrumentCacheFileName + Int 21h + + Pop DS + + Ret + +EndP DeleteInstrumentCachefile + +; + +Proc D_GetNumFiles ; DS = DiskDaraArea + + Mov DS, CS:DiskDataArea + + Mov DX, 64000 ; Set DTA to DS:64000 + Mov AH, 1Ah + Int 21h + + Push CS + Pop DS + + Mov DX, Offset AllFilesMask + Mov CX, 10h + Mov AH, 4Eh + Int 21h + + Mov DS, CS:DiskDataArea + JC D_GetNumFilesError + + Xor AX, AX ; No samples/directories to + ; start off with. + +D_GetNumFiles1: + Test Byte Ptr [DS:64000+15h], 10h + JZ D_GetNumFiles2 + + Mov EDX, DWord Ptr [CS:OldCacheTime] + Cmp [DS:64000+16h], EDX ; Newer file? + JA D_GetNumFilesError + + Inc AX + +D_GetNumFiles2: + Push AX + Mov AH, 4Fh + Int 21h + Pop AX + JNC D_GetNumFiles1 + ; Directories done.. files now + Push AX + + Push CS + Pop DS + Mov DX, Offset AllFilesMask + Xor CX, CX + Mov AH, 4Eh + Int 21h + + Mov DS, CS:DiskDataArea + + Pop AX + JC D_GetNumFilesFinished + + Push CS + Pop ES + +D_GetNumFiles3: + Mov SI, 64000+1Eh + Mov DI, Offset SampleCacheFileName + Mov CX, 9 + RepE CmpsB + JE D_GetNumFiles4 + + Mov SI, 64000+1Eh + Mov DI, Offset InstrumentCacheFileName + Mov CX, 9 + RepE CmpsB + JE D_GetNumFiles4 + + Mov EDX, DWord Ptr [CS:OldCacheTime] + Cmp [DS:64000+16h], EDX ; Newer file? + JA D_GetNumFilesError + +D_GetNumFiles4: + Inc AX + + Push AX + Mov AH, 4Fh + Int 21h + Pop AX + JNC D_GetNumfiles3 + + Dec AX + +D_GetNumFilesFinished: + ClC + Ret + +D_GetNumFilesError: + Xor AX, AX + StC + Ret + + +EndP D_GetNumFiles + +; + +Proc D_LoadSampleFiles + + Mov DS, CS:DiskDataArea + Push DS + Pop ES + + Xor DI, DI + Xor AX, AX + Mov CX, 32768 + Rep StosW + + Mov DX, 64000 + Mov AH, 1Ah + Int 21h ; Shift DTA address.. + ; to DiskDataArea:64000 + + Xor DI, DI + + Push CS + Pop DS + Mov DX, Offset AllFilesMask + Mov CX, 10h + Mov AH, 4Eh + Int 21h + + Mov DS, CS:DiskDataArea + Push DS + Pop ES + + JC D_LoadSampleFiles2 + +D_LoadSampleFiles1: ; A directory was found! + Test Byte Ptr [DS:64000+15h], 10h + JZ D_LoadSampleFiles5 ; Check that it IS a directory + + Cmp Word Ptr [DS:64000+1Eh], '.' + JNE D_LoadSampleFilesNoRoot + + Mov Byte Ptr [DS:64000+1Eh], '\' + +D_LoadSampleFilesNoRoot: + Mov DL, 1 + Call Near Ptr D_LoadSampleFiles6 + + Inc CS:NumSamples + Inc CS:LoadSampleNameCount + + Cmp CS:NumSamples, 620 + JAE D_LoadSampleFiles4 + +D_LoadSampleFiles5: + Mov AH, 4Fh + Int 21h + JNC D_LoadSampleFiles1 + +D_LoadSampleFiles2: ; Directories done.. samples now + Push CS + Pop DS + Mov DX, Offset AllFilesMask + Xor CX, CX + Mov AH, 4Eh + Int 21h + + Mov DS, CS:DiskDataArea + Push DS + Pop ES + + JC D_LoadSampleFiles4 + +D_LoadSampleFiles3: + Mov DL, 0 + Call Near Ptr D_LoadSampleFiles6 + + Inc CS:NumSamples + Cmp CS:NumSamples, 620 + JAE D_LoadSampleFiles4 + +D_LoadSampleFilesNext: + Mov AH, 4Fh + Int 21h + JNC D_LoadSampleFiles3 + +D_LoadSampleFiles4: ; End! + + Ret + +D_LoadSampleFiles6: ; Get name/size/date/time. + Add DI, 4 + Mov SI, 64000+1Eh + Mov CX, 13 + Rep MovsB + + Cmp DL, 1 + JNE D_LoadSampleFiles7 + + Xor AX, AX + StosB + StosW + + Push DS + Push CS + Pop DS + Mov SI, Offset DirectoryMsg + Mov CX, 25 + Rep MovsB + + Pop DS + + Mov CX, 35 + Jmp D_LoadSampleFiles8 + +D_LoadSampleFiles7: + Mov CX, 63 + +D_LoadSampleFiles8: + Xor AL, AL + Rep StosB + + Mov EAX, [DS:64000+1Ah] + StosD + Mov AX, [DS:64000+18h] + StosW + Mov AX, [DS:64000+16h] + StosW + Mov AL, DL + StosB + Mov CX, 7 + Xor AL, AL + Rep StosB + + RetN + +EndP D_LoadSampleFiles + +; + +Proc D_DrawLoadSampleWindow Far ; Has to handle + ; 1) Sample list + ; 2) Sample info box + ; 3) WaveForm stuff + + + Cmp CS:NumSamples, 0 + JNE D_DrawLoadSampleWindow4 + + Push CS + Pop DS + + Call S_GetDestination + Mov DI, (6+13*80)*2 ; (6, 13) + Mov SI, Offset NoFilesMsg + + Mov AH, 5 + Call S_DrawString + + Ret + +D_DrawLoadSampleWindow4: + Mov BX, CS:CurrentSample + Mov AX, 96 + Mul BX + Mov SI, AX + Mov ES, CS:DiskDataArea + + Cmp Byte Ptr [ES:SI+88], 0 + JNE D_DrawLoadSampleWindow28 + + Push SI + + Call D_LoadSampleHeader + Call D_GetSampleInfo + + Pop SI + +D_DrawLoadSampleWindow28: + Mov BX, CS:CurrentSample + Cmp BX, CS:SampleCheck + JE D_DrawLoadSampleWindow31 + + Mov CS:SampleCheck, BX + Push CS + Pop ES + Mov DI, Offset CheckDataArea + Mov DS, CS:DiskDataArea + Mov CX, 96 + Rep MovsB + +D_DrawLoadSampleWindow31: + Push CS + Pop DS + Assume DS:Disk + + Call S_GetDestination + + Mov AX, TopSample + Mov BX, CurrentSample + Cmp AX, BX + JBE D_DrawLoadSampleWindow1 + + Mov AX, BX + +D_DrawLoadSampleWindow1: + LEA CX, [EAX+34] + Cmp CX, BX + JA D_DrawLoadSampleWindow2 + + LEA AX, [BX-34] + +D_DrawLoadSampleWindow2: + Mov TopSample, AX + Mov BX, AX + + Push AX + + Mov DI, (31+13*80)*2 + Mov CX, 35 + Mov AX, 2A8h + +D_DrawLoadSampleWindow5: ; Divider... + StosW + Add DI, 158 + Loop D_DrawLoadSampleWindow5 + + Pop AX + + Mov DX, NumSamples + ; Put numbers of screen first. + Mov DI, (2+13*80)*2 ; (2,13) + Mov CX, 2000h+35 ; Colour and loop count. + +D_DrawLoadSampleWindow3: + Inc AX + Push DI + + Call PE_ConvAX2Num + + Pop DI + Add DI, 160 + Cmp AX, DX ; DX = NumSamples + JAE D_DrawLoadSampleWindow9 + + Dec CL + JNZ D_DrawLoadSampleWindow3 + +D_DrawLoadSampleWindow9: + Mov DS, DiskDataArea + Assume DS:Nothing + Mov AX, 96 + Mul BX + Mov SI, AX ; SI = offset of first sample. + + Mov DX, 35 ; DX = Number of rows to show. + ; BX = sample num + + Mov DI, (6+13*80)*2 + +D_DrawLoadSampleWindow6: + Push BX + Push DX + Push SI + Push DI + ; Colour.... + Mov AL, [DS:SI+88] ; AL = type. 0 = not loaded. + ; 1=dir + ; 2=it sample + ; 3=scrm sample. + ; 4=unknown + ; 5=8 bit mono wave + Mov AH, 6 + Cmp AL, 1 + JB D_DrawLoadSampleWindow7 + + Mov AH, 5 + JE D_DrawLoadSampleWindow7 + + Mov AH, 3 + Cmp AL, 4 + JNE D_DrawLoadSampleWindow7 + + Mov AH, 2 + +D_DrawLoadSampleWindow7: ; AH = colour. + Push SI + + Add SI, 14h + + Mov CX, 25 + +D_DrawLoadSampleWindow50: + LodsB + + Cmp AL, 226 + JB D_DrawLoadSampleCharFilter + + Mov AL, ' ' + +D_DrawLoadSampleCharFilter: + StosW + Loop D_DrawLoadSampleWindow50 + + Xor AL, AL + Rep StosW + + Pop SI + +; Add DI, 2 + ScasW + Add SI, 4 + + Mov CX, 12 + +D_DrawLoadSampleWindow51: + LodsB + StosW + And AL, AL + LoopNZ D_DrawLoadSampleWindow51 + + Xor AL, AL + Rep StosW + + Pop DI + Pop SI + Pop DX + Pop BX + + Add SI, 96 ; Advance to next sample. + Add DI, 160 ; Advance to next line on screen + + Inc BX + Cmp BX, CS:NumSamples + JAE D_DrawLoadSampleWindow8 + + Dec DX + JNZ D_DrawLoadSampleWindow6 + +D_DrawLoadSampleWindow8: ; Length + Mov AX, 96 + Mul CS:CurrentSample + + Mov SI, AX + + Push DS + Push SI + + Push DWord Ptr [DS:SI+30h] + + Test Byte Ptr [DS:SI+2Eh], 32 ; Stereo? + JZ D_DrawLoadSampleWindowNoStereo + + Test Byte Ptr [DS:SI+12h], 2 + Mov SI, Offset Quality8StereoMsg + + Push CS + Pop DS + JZ D_DrawLoadSampleWindowBitMsg + + Mov SI, Offset Quality16StereoMsg + Jmp D_DrawLoadSampleWindowBitMsg + +D_DrawLoadSampleWindowNoStereo: + Test Byte Ptr [DS:SI+12h], 2 + Mov SI, Offset Quality8Msg + + Push CS + Pop DS + JZ D_DrawLoadSampleWindowBitMsg + + Mov SI, Offset Quality16Msg + +D_DrawLoadSampleWindowBitMsg: + Mov DI, (21*80+64)*2 + Mov AH, 2 + Call S_DrawString + + Mov SI, Offset LengthMsg + Mov DI, (22*80+64)*2 + Call S_DrawString + Pop EAX + + Pop SI + Pop DS + +D_DrawLoadSampleWindow30: + ; Now for infobox. + Mov BL, [DS:SI+88] ; BL = type. + Push DS + Push SI + + Push CS + Pop DS + Xor BH, BH + Add BX, BX + Mov SI, [SampleFormatNames+BX] + Mov DI, (53+44*80)*2 + Mov AH, 5 + Call S_DrawString + + Pop SI + Pop DS + + Push SI + + Mov DX, [DS:SI+82] + Mov AX, [DS:SI+80] + Cmp DX, 10000 + + JAE D_DrawLoadSampleWindow13 + + Mov DI, (53+45*80)*2 + + Mov CX, 10000 + Div CX ; DX = remainder. AX = main. + + Mov BP, AX + + Mov CX, 4 + Mov SI, 10 + Mov AX, DX + +D_DrawLoadSampleWindow10: + Xor DX, DX + Div SI + Add DL, '0' + Push DX + + Loop D_DrawLoadSampleWindow10 + + Mov AX, BP + + Mov CX, 5 + +D_DrawLoadSampleWindow11: + Xor DX, DX + Div SI + Add DL, '0' + Push DX + + Loop D_DrawLoadSampleWindow11 + + Mov CX, 9 + +D_DrawLoadSampleWindow12: + Pop AX + Mov AH, 5 + StosW + Loop D_DrawLoadSampleWindow12 + +D_DrawLoadSampleWindow13: + Pop SI + + Mov DX, [DS:SI+86] ; DX = time + Mov BX, [DS:SI+84] ; BX = date + + Push CS + Pop DS + + Mov DI, (53+46*80)*2 + Mov AX, BX + ShR AX, 5 + And AX, 0Fh + Mov SI, AX + Add SI, SI + Mov SI, [MonthNames+SI] + + Mov AH, 5 + +D_DrawLoadSampleWindow19: + LodsB + StosW + And AL, AL + JNZ D_DrawLoadSampleWindow19 + + Mov AL, BL + And AX, 31 + Mov CH, 10 + Div CH + And AL, AL + JZ D_DrawLoadSampleWindow20 + + Push AX + Add AL, '0' + Mov AH, 5 + StosW + + Pop AX + +D_DrawLoadSampleWindow20: + Mov AL, AH + Add AL, '0' + Mov AH, 5 + StosW + + Mov AL, ',' + StosW + + Mov AL, ' ' + StosW + + Push DX + Mov AL, BH + ShR AX, 1 + And AX, 7Fh + Add AX, 1980 + Mov DX, 0FFFFh + Push DX + + Mov SI, 10 + +D_DrawLoadSampleWindow21: + Xor DX, DX + Div SI + Add DL, '0' + Push DX + + And AX, AX + JNZ D_DrawLoadSampleWindow21 + +D_DrawLoadSampleWindow22: + Pop AX + Cmp AX, 0FFFFh + JE D_DrawLoadSampleWindow23 + + Mov AH, 5 + StosW + + Jmp D_DrawLoadSampleWindow22 + +D_DrawLoadSampleWindow23: + Pop DX + Mov DI, (53+47*80)*2 + + Mov AX, DX + ShR AX, 11 + + Xor BL, BL ; if BL = 0, then am, otherwise + ; pm.. + Cmp AX, 12 + JB D_DrawLoadSampleWindow24 + + Inc BX + Sub AX, 12 + +D_DrawLoadSampleWindow24: + And AX, AX + JNZ D_DrawLoadSampleWindow25 + + Add AX, 12 + +D_DrawLoadSampleWindow25: + Mov BH, 10 + Div BH + And AL, AL + JZ D_DrawLoadSampleWindow26 + + Push AX + Add AL, '0' + Mov AH, 5 + StosW + + Pop AX + +D_DrawLoadSampleWindow26: + Mov AL, AH + Add AL, '0' + Mov AH, 5 + StosW + + Mov AL, ':' + StosW + + Mov AX, DX + ShR AX, 5 + And AX, 63 + + Div BH + Mov BH, AH + + Add AL, '0' + Mov AH, 5 + StosW + + Mov AL, BH + Add AL, '0' + StosW + + Mov AL, 'a' + And BL, BL + JZ D_DrawLoadSampleWindow27 + + Mov AL, 'p' + +D_DrawLoadSampleWindow27: + StosW + Mov AL, 'm' + StosW + + Push CS ; Wave form shit.. + Pop DS + Assume DS:Disk + + Mov AX, CurrentSample + Cmp AX, SampleInMemory + JNE D_DrawLoadSampleWindow54 + + Mov DI, (46+25*80)*2 + Mov DX, 4 + Mov AX, 0D00h + +D_DrawLoadSampleWindow55: + Mov CX, 31 + +D_DrawLoadSampleWindow56: + StosW + Inc AX + Loop D_DrawLoadSampleWindow56 + + Add DI, 160-31*2 + Dec DX + JNZ D_DrawLoadSampleWindow55 + +D_DrawLoadSampleWindow54: + Ret + +EndP D_DrawLoadSampleWindow + Assume DS:Nothing + +; + +Proc D_PreLoadSampleWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov AX, CurrentSample + Sub AX, TopSample + Add AX, 13 + Mov BX, 160 + Mul BX + + Call S_GetDestination + + LEA DI, [EAX+12] + Mov CX, 38 + +D_PreLoadSample1: + Mov AX, [ES:DI] + Cmp CX, 13 + + JNE D_PreLoadSample2 + + Mov AH, 32h + Jmp D_PreLoadSample3 + +D_PreLoadSample2: + Mov AH, 30h + +D_PreLoadSample3: + StosW + + Loop D_PreLoadSample1 + + Ret + +EndP D_PreLoadSampleWindow + +; + +Proc D_PostLoadSampleWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset LSWindowKeys + Call M_FunctionDivider + JC D_PostLoadSampleWindow1 + + Jmp [SI] + +D_PostLoadSampleWindow1: ; Time to check for play keys. + Mov SI, Offset KeyBoardTable + Test CH, Not 1 + JNZ D_PostLoadSampleWindow3 + + Cmp CX, LastKey + JE D_PostLoadSampleWindow3 + + Mov LastKey, CX + +D_PostLoadSampleWindow2: + LodsW + Cmp AX, 0FFFFh + JE D_PostLoadSampleWindow3 + + Mov BX, AX + LodsW + + Cmp BL, CL + JNE D_PostLoadSampleWindow2 + ; Note to play... + ; AX = notemod. + And CH, CH + JZ D_PostLoadSampleWindow5 + + + Mov BX, AX + + Mov CX, Pattern + Mov DS, CX + Assume DS:Pattern + + Mov AL, 12 + Mul BaseOctave + + Push CS + Pop DS + Assume DS:Disk + + Add AX, BX + Cmp AX, 119 + JA D_PostLoadSampleWindow4 ; If note > B-9... don't play! + + Push AX + + Mov AX, 96 + Mul CurrentSample + Mov SI, AX + + Mov DisableStereoMenu, 1 + + Mov DS, DiskDataArea + Mov AX, 99 + Call LoadSample + + Mov CS:DisableStereoMenu, 0 + + Pop AX + JC D_PostLoadSampleWindow4 + + ; AX = note. Ins = 99. + Mov AH, 100 + Xor CX, CX + Call Music_PlaySample + Jmp D_PostLoadSampleWindow4 + +D_PostLoadSampleWindow5: + Xor AX, AX + Mov SI, Offset NoteData + Mov DH, 32 + Call Music_PlayNote + +D_PostLoadSampleWindow4: + Mov AX, 1 + Ret + +D_PostLoadSampleWindow3: + Xor AX, AX + Ret + +EndP D_PostLoadSampleWindow + Assume DS:Nothing + +; + +Proc D_PostViewSampleLibrary Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset LSViewWindowKeys + Call M_FunctionDivider + JC D_PostLoadSampleWindow1 + + Jmp [SI] + +EndP D_PostViewSampleLibrary + +; + +Proc D_LSDrawDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Call S_GetDestination + + Mov AL, TopDrive + Mov BL, CurrentDrive + Cmp AL, BL + JBE D_LSDrawDriveWindow1 + + Mov AL, BL + +D_LSDrawDriveWindow1: + Mov CL, AL + Add CL, 9 + Cmp CL, BL + JA D_LSDrawDriveWindow2 + + Mov AL, BL + Sub AL, 9 + +D_LSDrawDriveWindow2: + Mov TopDrive, AL + Mov BL, AL + Mov CX, 10 + + Mov DI, (46+13*80)*2 + Xor BH, BH + +D_LSDrawDriveWindow3: + Cmp BL, NumDrives + JAE D_LSDrawDriveWindow5 + + Push DI + + Mov AL, [DrivesAvail+BX] + Add AL, 'A' + Mov SI, Offset DriveMsg + Mov [SI+6], AL + + Mov AH, 5 + Mov DX, 8 + +D_LSDrawDriveWindow4: + LodsB + StosW + + Dec DX + JNZ D_LSDrawDriveWindow4 + + Pop DI + Add DI, 160 + Inc BX + Loop D_LSDrawDriveWindow3 + +D_LSDrawDriveWindow5: + Ret + +EndP D_LSDrawDriveWindow + Assume DS:Nothing + +; + +Proc D_LSPreDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov AL, CurrentDrive + Sub AL, TopDrive + Add AL, 13 + Mov AH, 160 + Mul AH + + Call S_GetDestination + LEA DI, [EAX+92] + Mov CX, 8 + +D_LSPreDriveWindow1: + Mov AX, [ES:DI] + Mov AH, 30h + StosW + + Loop D_LSPreDriveWindow1 + + Ret + +EndP D_LSPreDriveWindow + Assume DS:Nothing + +; + +Proc D_LSPostDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset LSDriveWindowKeys + Call M_FunctionDivider + JC D_LSPostDriveWindow1 + + Jmp [SI] + +D_LSPostDriveWindow1: + Xor AX, AX + Ret + +EndP D_LSPostDriveWindow + Assume DS:Nothing + +; + +Proc D_LIDrawDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Call S_GetDestination + + Xor AL, AL + Xor BX, BX + + Mov CX, 32 + + Mov DI, (64+16*80)*2 + +D_LIDrawDriveWindow3: + Cmp BL, NumDrives + JAE D_LIDrawDriveWindow5 + + Push DI + + Mov AL, [DrivesAvail+BX] + Add AL, 'A' + Mov SI, Offset DriveMsg + Mov [SI+6], AL + + Mov AH, 5 + Mov DX, 8 + +D_LIDrawDriveWindow4: + LodsB + StosW + + Dec DX + JNZ D_LIDrawDriveWindow4 + + Pop DI + Add DI, 160 + Inc BX + Loop D_LIDrawDriveWindow3 + +D_LIDrawDriveWindow5: + Ret + +EndP D_LIDrawDriveWindow + Assume DS:Nothing + +; + +Proc D_LIPreDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov AL, CurrentDrive + Add AL, 16 + Mov AH, 160 + Mul AH + Mov DI, AX + + Call S_GetDestination + Add DI, 64*2 + Mov CX, 8 + +D_LIPreDriveWindow1: + Mov AX, [ES:DI] + Mov AH, 30h + StosW + + Loop D_LIPreDriveWindow1 + + Ret + +EndP D_LIPreDriveWindow + Assume DS:Nothing + +; + +Proc D_LIPostDriveWindow Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset LIDriveWindowKeys + Call M_FunctionDivider + JC D_LIPostDriveWindow1 + + Jmp [SI] + +D_LIPostDriveWindow1: + Xor AX, AX + Ret + +EndP D_LIPostDriveWindow + Assume DS:Nothing + +; + +Proc D_LoadSampleHeader ; Given BX = sample number. + + Push BX + + Mov DS, DiskDataArea + Assume DS:Nothing + + Mov AX, 96 + Mul BX + LEA SI, [EAX+4] + + Call D_LoadFileHeader + + Pop BX + + Ret + +EndP D_LoadSampleHeader + +; + +Proc D_LoadInstrumentHeader ; Given BX = instrument num + + Push BX + + Mov DS, DiskDataArea + Assume DS:Nothing + + Mov AX, 48 + Mul BX + Mov SI, AX + Inc SI + + Call D_LoadFileHeader + + Pop BX + + Ret + +EndP D_LoadInstrumentHeader + +; + +include it_d_inf.inc + +; + +Proc D_SaveSampleCacheFile ; Assumes DS=Disk + + Push CS + Pop DS + + Assume DS:Disk + + Test DiskOptions, 2 + JNZ D_SaveSampleCacheFile1 + + Cmp SamplesInModule, 0 + JNE D_SaveSampleCacheFile1 + + Mov AH, 3Ch ; create file. + Xor CX, CX ; normal file + Mov DX, Offset SampleCacheFileName + Int 21h + JC D_SaveSampleCacheFile1 + + Mov BX, AX ; BX = file handle + + Mov AH, 40h ; Write to file + Mov CX, 4 ; Word size + Mov DX, Offset NumSamples + Int 21h + + Mov AX, 96 + Mul NumSamples + Mov CX, AX ; CX = num bytes to write. + Mov AH, 40h + Xor DX, DX + Mov DS, DiskDataArea + Assume DS:Nothing + Int 21h ; Write cache file! + + ; Set date and time... + Mov AX, 5701h + Mov CX, CS:Time + Mov DX, CS:Date + Int 21h + + Mov AH, 3Eh ; Close file handle + Int 21h + + Push CS + Pop DS + Assume DS:Disk + +D_SaveSampleCacheFile1: + Mov SampleCacheFileComplete, 1 + + Ret + +EndP D_SaveSampleCacheFile + Assume DS:Nothing + +; + +Proc D_SaveInstrumentCacheFile ; Assumes DS=Disk + + Push CS + Pop DS + Assume DS:Disk + + Test DiskOptions, 2 + JNZ D_SaveInstrumentCacheFile1 + + Mov AH, 3Ch ; create file. + Xor CX, CX ; normal file + Mov DX, Offset InstrumentCacheFileName + Int 21h + JC D_SaveInstrumentCacheFile1 + + Mov BX, AX ; BX = file handle + + Mov AH, 40h ; Write to file + Mov CX, 6 ; Word size + Mov DX, Offset InitialInstruments + Int 21h + + Mov AX, 48 + Mul NumInstruments + Mov CX, AX ; CX = num bytes to write. + Mov AH, 40h + Xor DX, DX + Mov DS, DiskDataArea + Assume DS:Nothing + + Int 21h ; Write cache file! + + ; Set date and time... + Mov AX, 5701h + Mov CX, CS:Time + Mov DX, CS:Date + Int 21h + + Mov AH, 3Eh ; Close file handle + Int 21h + + Push CS + Pop DS + Assume DS:Disk + +D_SaveInstrumentCacheFile1: + Mov InstrumentCacheFileComplete, 1 + + Ret + +EndP D_SaveInstrumentCacheFile + Assume DS:Nothing + +; + +Proc D_LoadSampleNames Far + + Push CS + Pop DS + Assume DS:Disk + + Cmp SampleCacheFileComplete, 1 + JNE D_LoadSampleNames2 + +D_LoadSampleNames6: + Xor AX, AX ; No redraw screen. + Ret + +D_LoadSampleNames2: + Mov BX, LoadSampleNameCount + Cmp BX, NumSamples + JAE D_LoadSampleNames5 + +D_LoadSampleNames1: + Call K_IsAnyKeyDown + And AL, AL + JNZ D_LoadSampleNames6 + + Call GetKeyboardLock + And AL, AL + JNZ D_LoadSampleNames6 + + Mov AX, 96 + Mul BX + Mov SI, AX + Mov ES, DiskDataArea + Cmp Byte Ptr [ES:SI+88], 0 + JNE D_LoadSampleNames3 + + Call D_LoadSampleHeader + JC D_LoadSampleNames3 + + Call D_GetSampleInfo ; BX = sample number + +D_LoadSampleNames3: + Push CS + Pop DS + Assume DS:Disk + + Inc LoadSampleNameCount + Mov BX, LoadSampleNameCount + Cmp BX, NumSamples + JNE D_LoadSampleNames4 + ; Save cache file.. + +D_LoadSampleNames5: + Call D_SaveSampleCacheFile + Cmp CurrentSample, 0 + JNE D_LoadSampleNames4 + Call D_SlowSampleSort + +D_LoadSampleNames4: + Mov AX, 1 ; Signify redraw screen + Ret + +EndP D_LoadSampleNames + Assume DS:Nothing + +; + +Proc D_GetLoadSampleVars Far ; Returns SI with offset of + + Push AX + Push DX + + Mov AX, 96 + Mul CS:CurrentSample + Mov SI, AX + Mov DS, CS:DiskDataArea + + Pop DX + Pop AX + + Ret + +EndP D_GetLoadSampleVars + +; + +Proc D_GotoStartingDirectory Far + + Push DS + Push CS + Pop DS + + Mov SI, Offset StartingDirectory + Call D_SetDriveDirectory + Pop DS + + Ret + +EndP D_GotoStartingDirectory + +; + +Proc D_SaveDirectoryConfiguration Far + + Push CS + Pop DS + Assume DS:Disk + + Mov NoSaveError, 0 + Mov CountryTableConfig, 0 + + Mov SI, Offset StartingDirectory + Call D_SetDriveDirectory + + Mov AH, 3Ch + Xor CX, CX + Mov DX, Offset ConfigFileName + Int 21h + JC D_SaveDirectoryConfiguration1 + + Mov BX, AX + + Mov CX, 211 + Mov DX, Offset SongDirectory + Call D_SaveBlock + + Call S_GetPaletteOffset ; Into DS:DX + Mov CX, 3*16 + Call D_SaveBlock + + Call Display_GetDisplayWindowData + Mov CX, 50 + Call D_SaveBlock + + Call PE_GetPatternConfigOffset + Mov CX, 218 + Call D_SaveBlock + + Call I_GetPresetEnvelopeOffset + Mov CX, 810 + Call D_SaveBlock + + Mov AH, 3Eh + Int 21h + +D_SaveDirectoryConfiguration1: + Mov AX, 1 + Ret + +EndP D_SaveDirectoryConfiguration + Assume DS:Nothing + +; + +Proc FileWindow_Up Far + + Assume DS:Disk + + Mov AX, CurrentFile + And AX, AX + JZ FileWindow_Up1 + + Dec CurrentFile + +FileWindow_Up1: + Mov AX, 1 + Ret + +EndP FileWindow_Up + Assume DS:Nothing + +; + +Proc FileWindow_Down Far + + Assume DS:Disk + + Mov AX, CurrentFile + Inc AX + Cmp AX, NumFiles + JAE FileWindow_Down1 + + Inc CurrentFile + +FileWindow_Down1: + Mov AX, 1 + Ret + +EndP FileWindow_Down + Assume DS:Nothing + +; + +Proc FileWindow_PgUp Far + + Assume DS:Disk + + Mov AX, CurrentFile + Sub AX, 31 + JNC FileWindow_PgUp1 + + Xor AX, AX + +FileWindow_PgUp1: + Mov CurrentFile, AX + + Mov AX, 1 + Ret + +EndP FileWindow_PgUp + Assume DS:Nothing + +; + +Proc FileWindow_PgDn Far + + Assume DS:Disk + + Mov AX, CurrentFile + Add AX, 31 + Cmp AX, NumFiles + JB FileWindow_PgDn1 + + Mov AX, NumFiles + And AX, AX + JZ FileWindow_PgDn1 + + Dec AX + +FileWindow_PgDn1: + Mov CurrentFile, AX + + Mov AX, 1 + Ret + +EndP FileWindow_PgDn + Assume DS:Nothing + +; + +Proc FileWindow_Right Far + + Assume DS:Disk + + Mov Word Ptr [ES:DI], 13 + + Mov AX, 1 + Ret + +EndP FileWindow_Right + Assume DS:Nothing + +; + +Proc FileWindow_Left Far + + Assume DS:Disk + + Mov Word Ptr [ES:DI], 14 + + Mov AX, 1 + Ret + +EndP FileWindow_Left + Assume DS:Nothing + +; + +Proc FileWindow_ShiftTab Far + + Assume DS:Disk + + Mov Word Ptr [ES:DI], 16 + + Mov AX, 1 + Ret + +EndP FileWindow_ShiftTab + Assume DS:Nothing + +; + +Proc FileWindow_Home Far + + Assume DS:Disk + + Mov CurrentFile, 0 + + Mov AX, 1 + Ret + +EndP FileWindow_Home + Assume DS:Nothing + +; + +Proc FileWindow_End Far + + Assume DS:Disk + + Mov AX, NumFiles + Dec AX + JS FileWindow_End1 + + Mov CurrentFile, AX + +FileWindow_End1: + Mov AX, 1 + Ret + +EndP FileWindow_End + Assume DS:Nothing + +; + +Proc FileWindow_DeleteFile Far + + Assume DS:Disk + + Cmp NumFiles, 0 + JE FileWindow_DeleteFile26 + + Mov DI, Offset O1_ConfirmDelete + Mov CX, 4 + Call M_Object1List + And DX, DX + JNZ FileWindow_DeleteFile24 + + Mov AX, 1 + Ret + +FileWindow_DeleteFile24: ; Time to kill the sucker... + Mov DS, CS:DiskDataArea + Mov BX, CS:CurrentFile + Assume DS:Nothing + + Add BX, BX + Mov DX, [BX] + Add DX, 8 ; DS:BX points to thingo. + Mov AH, 41h + Int 21h + JC FileWindow_DeleteFile26 + + Push DS + Pop ES + + Push CS + Pop DS + Assume DS:Disk + + Mov DI, CurrentFile + Mov CX, DI + Add DI, DI + Mov BX, NumFiles + Add BX, NumDirectories + +FileWindow_DeleteFile27: + Mov AX, [ES:DI+2] + StosW + Inc CX + Cmp CX, BX + JBE FileWindow_DeleteFile27 + + Mov AX, NumFiles + Mov BX, CurrentFile + Dec AX + And AX, AX + JZ FileWindow_DeleteFile29 + + Cmp BX, AX + JB FileWindow_DeleteFile28 + + Mov BX, AX + Dec BX + Jmp FileWindow_DeleteFile28 + +FileWindow_DeleteFile29: + Mov BX, AX + +FileWindow_DeleteFile28: + Mov NumFiles, AX + Mov CurrentFile, BX + Dec LoadSongNameCount + +FileWindow_DeleteFile26: + Mov AX, 1 + Ret + +EndP FileWindow_DeleteFile + Assume DS:Nothing + +; + +Proc DirectoryWindow_Up Far + + Assume DS:Disk + + Mov AX, CurrentDirectory + And AX, AX + JZ DirectoryWindow_Up1 + + Dec CurrentDirectory + +DirectoryWindow_Up1: + Mov AX, 1 + Ret + +EndP DirectoryWindow_Up + +; + +Proc DirectoryWindow_Down Far + + Assume DS:Disk + + Mov AX, CurrentDirectory + Inc AX + Cmp AX, NumDirectories + JAE DirectoryWindow_Down1 + + Inc CurrentDirectory + +DirectoryWindow_Down1: + Mov AX, 1 + Ret + +EndP DirectoryWindow_Down + +; + +Proc DirectoryWindow_PgUp Far + + Assume DS:Disk + + Mov AX, CurrentDirectory + Sub AX, 21 + JC DirectoryWindow_Home + + Mov CurrentDirectory, AX + + Mov AX, 1 + Ret + +EndP DirectoryWindow_PgUp + +; + +Proc DirectoryWindow_PgDn Far + + Assume DS:Disk + + Mov AX, CurrentDirectory + Add AX, 21 + Cmp AX, NumDirectories + JAE DirectoryWindow_End + + Mov CurrentDirectory, AX + + Mov AX, 1 + Ret + +EndP DirectoryWindow_PgDn + +; + +Proc DirectoryWindow_Home Far + + Assume DS:Disk + + Mov CurrentDirectory, 0 + + Mov AX, 1 + Ret + +EndP DirectoryWindow_Home + +; + +Proc DirectoryWindow_End Far + + Assume DS:Disk + + Mov AX, NumDirectories + Dec AX + JS DirectoryWindow_End1 + + Mov CurrentDirectory, AX + +DirectoryWindow_End1: + Mov AX, 1 + Ret + +EndP DirectoryWindow_End + +; + +Proc DirectoryWindow_Left Far + + Assume DS:Disk + + Mov Word Ptr [ES:DI], 12 + + Mov AX, 1 + Ret + +EndP DirectoryWindow_Left + +; + +Proc DirectoryWindow_Enter Far + + Assume DS:Disk + + Cmp NumDirectories, 0 + JE DirectoryWindow_Enter2 + + Mov BX, CurrentDirectory + Add BX, NumFiles + + Mov DS, DiskDataArea + Assume DS:Nothing + + Add BX, BX + Mov DX, [BX] + Add DX, 8 + Mov AH, 3Bh + Int 21h + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset SongDirectory + Call D_GetDriveDirectory + + Call D_InitLoadModule + + Mov CurrentFile, 0 + Mov AX, 12 + Cmp NumFiles, 0 + JNE DirectoryWindow_Enter1 + + Mov AX, 13 + +DirectoryWindow_Enter1: + StosW +; Mov [ES:DI], AX + + Mov AX, 1 + Ret + +DirectoryWindow_Enter2: + Xor AX, AX + Ret + +EndP DirectoryWindow_Enter + +; + +Proc DriveWindow_Up Far + + Assume DS:Disk + + Mov AL, CurrentDrive + And AL, AL + JZ DriveWindow_Up1 + + Dec CurrentDrive + +DriveWindow_Up1: + Mov AX, 1 + Ret + +EndP DriveWindow_Up + Assume DS:Nothing + +; + +Proc DriveWindow_Down Far + + Assume DS:Disk + + Mov AL, CurrentDrive + Inc AX + Cmp AL, NumDrives + JAE DriveWindow_Down1 + + Inc CurrentDrive + +DriveWindow_Down1: + Mov AX, 1 + Ret + +EndP DriveWindow_Down + Assume DS:Nothing + +; + +Proc DriveWindow_Tab Far + + Assume DS:Disk + + Mov Word Ptr [ES:DI], 15 + + Mov AX, 1 + Ret + +EndP DriveWindow_Tab + Assume DS:Nothing + +; + +Proc LIDriveWindow_Tab Far + + Assume DS:Disk + + Mov Word Ptr [ES:DI], 5 + + Mov AX, 1 + Ret + +EndP LIDriveWindow_Tab + Assume DS:Nothing + +; + +Proc SaveDriveWindow_Tab Far + + Assume DS:Disk + + Mov Word Ptr [ES:DI], 18 + + Mov AX, 1 + Ret + +EndP SaveDriveWindow_Tab + Assume DS:Nothing + +; + +Proc DriveWindow_Enter Far + + Assume DS:Disk + + Mov BL, CurrentDrive + Xor BH, BH + Mov DL, [DrivesAvail+BX] + Mov AH, 0Eh + Int 21h + + Mov SI, Offset SongDirectory + Call D_GetDriveDirectory + + Call D_InitLoadModule + + Mov CurrentFile, 0 + Mov AX, 12 + Cmp NumFiles, 0 + JNE DriveWindow_Enter1 + + Mov AX, 13 + Cmp NumDirectories, 0 + JNE DriveWindow_Enter1 + + Mov AX, 14 + +DriveWindow_Enter1: + StosW +; Mov [ES:DI], AX + + Mov AX, 1 + Ret + +EndP DriveWindow_Enter + Assume DS:Nothing + +; + +Proc LS_DriveWindow_Enter Far + + Assume DS:Disk + + Mov BL, CurrentDrive + Xor BH, BH + Mov DL, [DrivesAvail+BX] + Mov AH, 0Eh + Int 21h + + Mov SI, Offset SampleDirectory + Call D_GetDriveDirectory + + Mov CurrentSample, 0 + Push ES + Push DI + Call D_InitLoadSamples + Pop DI + Pop ES + + Mov Word Ptr [ES:DI], 15 ; Sample list + + Mov AX, 1 + Ret + +EndP LS_DriveWindow_Enter + +; + +Proc LI_DriveWindow_Enter Far + + Assume DS:Disk + + Mov BL, CurrentDrive + Xor BH, BH + Mov DL, [DrivesAvail+BX] + Mov AH, 0Eh + Int 21h + + Mov SI, Offset InstrumentDirectory + Call D_GetDriveDirectory + + Mov CurrentInstrument, 0 + Push ES + Push DI + Call D_InitLoadInstruments + Pop DI + Pop ES + + Mov Word Ptr [ES:DI], 5 ; Sample list + + Mov AX, 1 + Ret + +EndP LI_DriveWindow_Enter + +; + +Proc LSDriveWindow_Right Far + + Mov Word Ptr [ES:DI], 17 + + Mov AX, 1 + Ret + +EndP LSDriveWindow_Right + +; + +Proc LoadSample ; AX = Sample number + ; DS:SI points to sample header. + Call PE_SaveCurrentPattern + + Push AX + + Cmp AX, 99 + JNE LoadSample4 + + Mov DX, CS:CurrentSample + Cmp DX, CS:SampleInMemory + JE LoadSample3 + +LoadSample4: + Mov EDX, [DS:SI+30h] + And EDX, EDX + JZ LoadSample6 + Test Byte Ptr [DS:SI+12h], 1 + JZ LoadSample6 + + Call Music_Stop + + Push AX + + Mov AX, 3D00h + Mov DX, SI + Add DX, 4 + Int 21h + JC LoadSample8 + + Mov BX, AX ; BX = File Handle + Mov AX, 4200h + Mov CX, [DS:SI+4Ah] + Mov DX, [DS:SI+48h] + Int 21h ; Move File Ptr. + + Pop AX ; AX = sample number. + + Push SI ; Load sample into memory first. + + Call D_LoadSampleData + + PushF + + Mov AH, 3Eh + Int 21h ; Close file. + + PopF + Pop SI + + JC LoadSample2 + +LoadSample3: + Pop BX + Mov DX, BX + + Add BX, BX + Call Music_GetSongSegment + Mov ES, AX + Mov DI, [ES:BX+64912] ; ES:DI points to instrument + + Mov CX, 48h + Rep MovsB + Add SI, 4 + Add DI, 4 + MovsW + MovsW + + Cmp DX, 99 + JNE LoadSample5 + + Mov AX, [Word Ptr CS:CheckDataArea+2Eh] + Mov [DS:SI-50h+2Eh], AX + Mov AL, [CS:CheckDataArea+12h] + Mov [DS:SI-50h+12h], AL + + Mov AX, CS:CurrentSample + Cmp AX, CS:SampleInMemory + JE LoadSample7 + + Mov CS:SampleInMemory, AX + + Call D_DrawWaveForm + +LoadSample5: + Mov AX, DX + Inc AX + Call Music_SoundCardLoadSample + +LoadSample7: + ClC + Jmp LoadSample1 + Ret + +LoadSample2: + Mov CS:SampleInMemory, 0FFFFh + Jmp LoadSample6 + +LoadSample8: + Pop AX + +LoadSample6: + Pop AX + StC + +LoadSample1: + PushF + Call PE_RestoreCurrentPattern + PopF + Ret + +EndP LoadSample + +; + +include it_d_ris.inc + +; + +Proc LSViewWindow_Enter Far + + Assume DS:Disk + + Cmp NumSamples, 0 + JE LSViewWindow_Enter1 + + Mov AX, 96 + Mul CurrentSample + Mov SI, AX + Assume DS:Nothing + + Mov DS, DiskDataArea + Mov DL, [DS:SI+88] + Cmp DL, 1 + JE LSViewWindow_Enter1 + + Cmp DL, 20h + JAE LSViewWindow_Enter2 + + Mov AX, 1 + Ret + +EndP LSViewWindow_Enter + +; + +Proc LSWindow_Enter Far + + Assume DS:Disk + + Cmp NumSamples, 0 + JE LSWindow_Enter2 + + Mov AX, 96 + Mul CurrentSample + Mov SI, AX + Assume DS:Nothing + + Mov DS, DiskDataArea + Mov DX, [DS:SI+88] ; Also get DH = InsampleChannels + Cmp DL, 1 + JNE LSWindow_Enter1 + +LSViewWindow_Enter1: + Push DS + Push SI + + Push CS + Pop DS + Mov SI, Offset SampleDirectory + Call D_SetDriveDirectory + + Pop SI + Pop DS + + Add SI, 4 + Call D_SetDriveDirectory + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset SampleDirectory + Call D_GetDriveDirectory + +LSWindow_EnterInModuleError: + Mov SamplesInModule, 0 + Call D_InitLoadSamples + Assume DS:Nothing + Mov CS:CurrentSample, 0 + + Mov AX, 1 + Ret + +LSWindow_Enter1: ; Load sample into sample list. + Cmp DL, 20h + JB LSWindow_EnterSample + +LSViewWindow_Enter2: + Sub DL, 20h + Mov Word Ptr CS:InSampleFormat, DX + Mov EAX, [SI+54h] + Mov CS:InSampleDateTime, EAX + + Add SI, 4 + ; Copy module name across + Push CS + Pop ES + Mov DI, Offset InSampleFileName + Mov CX, 13 + Rep MovsB + ; Open file + Push CS + Pop DS + Assume DS:Disk + + Mov CurrentSample, 0 + +LSWindow_EnterLoadInSampleData: + Mov DX, Offset InSampleFileName + Mov AX, 3D00h + Int 21h + JC LSWindow_EnterInModuleError + + Mov BX, AX + + Mov SI, Word Ptr InSampleFormat + And SI, 0FFh + Add SI, SI + + Mov NumSamples, 1 + + Mov DS, DiskDataArea + Assume DS:Nothing + + Push DS + Pop ES + + Call [CS:LoadSamplesInModuleTable+SI] + + ; Close module + Mov AH, 3Eh + Int 21h + + ; Setup first 'directory' + + Push CS + Pop DS + Assume DS:Disk + + Xor DI, DI + Mov SI, Offset ExitLibraryDirectory + Mov CX, 89 + Rep MovsB + + Mov EAX, InSampleDateTime + Mov [ES:DI-5], EAX + Mov SampleCacheFileComplete, 1 + Mov SamplesInModule, 1 + Mov SampleInMemory, 0FFFFh + Mov SampleCheck, 0FFFFh + + Mov AX, NumSamples + Mov LoadSampleNameCount, AX + + Mov AX, 1 + Ret + + Assume DS:Nothing + +LSWindow_EnterSample: + Call Music_Stop + + Mov AX, [Word Ptr CS:CheckDataArea+2Eh] + Mov [SI+2Eh], AX + ; prompt whether to initialise + ; instrument + ; 1) Only when no sample was + ; previously present + ; 2) When instrument mode is + ; on. + Mov AX, 99 ; Release sample! + Call Music_ReleaseSample + + Xor DX, DX ; Assume don't call. + + Call Music_GetInstrumentMode + JZ LSWindow_Enter4 ; Sample mode! + + ; Instrument mode + + ; Check whether previous sample + ; existed. + Push DS + Push SI + + Mov CX, 4 ; Assume Not OK + + Call I_GetSampleOffset ; DS:BX points to sample. + Test Byte Ptr [BX+12h], 1 + JNZ LSWindow_Enter5 + + Mov CX, 3 ; Assume OK. + +LSWindow_Enter5: + Mov DI, Offset O1_InitInstrument + Call M_Object1List + ; DX contains init flag. + Pop SI + Pop DS + +LSWindow_Enter4: + Push DX + + Call PE_GetLastInstrument + Mov AX, BX + Push AX + Call LoadSample + Pop CX + Xor DX, DX + +IF NETWORKENABLED + NetworkSendSample + Call Network_QueueSampleData +ENDIF + + Pop DX + + Test DX, DX + JZ LSWindow_Enter7 + + Call PE_GetLastInstrument ; BX = sample number + Call Music_AssignSampleToInstrument + + Push CS + Pop DS + Mov SI, Offset InitInstrumentErrorMsg + JC LSWindow_Enter6 + + Mov SI, Offset InitInstrumentMsg + +LSWindow_Enter6: + Call SetInfoLine + +LSWindow_Enter7: + Jmp Glbl_F3 + +LSWindow_Enter2: + Mov AX, 1 + Ret + +EndP LSWindow_Enter + Assume DS:Nothing + +; + +Proc LSWindow_Space Far + + Assume DS:Disk + + Cmp NumSamples, 0 + JE LSViewWindow_Enter1 + + Mov AX, 96 + Mul CurrentSample + LEA SI, [EAX+14h] + Assume DS:Nothing + + Push SI + + Mov DS, DiskDataArea + + Push CS + Pop ES + Mov DI, Offset SampleName + + Mov CX, 26 + Mov BX, DI + +LSWindow_Space1: + LodsB + And AL, AL + JNZ LS_WindowSpace2 + + Mov AL, ' ' + Jmp LS_WindowSpace3 + +LS_WindowSpace2: + Cmp AL, ' ' + JE LS_WindowSpace3 + + Mov BX, DI + Inc BX + +LS_WindowSpace3: + StosB + Loop LSWindow_Space1 + + Mov Byte Ptr [ES:BX], 0 + + + Mov DI, Offset O1_EditSampleName + Mov CX, 3 + Call M_Object1List + + Pop DI ; DI contains offset of sample + + And DX, DX + JZ LS_WindowSpace4 + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset SampleName + Mov CX, 26 + Mov ES, DiskDataArea + Rep MovsB + +LS_WindowSpace4: + Mov AX, 1 + Ret + +EndP LSWindow_Space + +; + +Proc LSWindow_Up Far + + Call CheckSampleModified + JC LSWindow_Up1 + + Assume DS:Disk + + Mov AX, CurrentSample + And AX, AX + JZ LSWindow_Up1 + + Dec CurrentSample + +LSWindow_Up1: + Mov AX, 1 + Ret + +EndP LSWindow_Up + Assume DS:Nothing + +; + +Proc LSWindow_Down Far + + Call CheckSampleModified + JC LSWindow_Down1 + + Assume DS:Disk + + Mov AX, CurrentSample + + Inc AX + Cmp AX, NumSamples + JAE LSWindow_Down1 + + Mov CurrentSample, AX + +LSWindow_Down1: + Mov AX, 1 + Ret + +EndP LSWindow_Down + Assume DS:Nothing + +; + +Proc LSWindow_PgUp Far + + Call CheckSampleModified + JC LSWindow_PgUp1 + + Assume DS:Disk + + Mov AX, CurrentSample + + Sub AX, 35 + JC LSWindow_Home + + Mov CurrentSample, AX + +LSWindow_PgUp1: + Mov AX, 1 + Ret + +EndP LSWindow_PgUp + Assume DS:Nothing + +; + +Proc LSWindow_PgDn Far + + Call CheckSampleModified + JC LSWindow_PgDn1 + + Assume DS:Disk + + Mov AX, CurrentSample + + Add AX, 35 + Cmp AX, NumSamples + JAE LSWindow_End + + Mov CurrentSample, AX + +LSWindow_PgDn1: + Mov AX, 1 + Ret + +EndP LSWindow_PgDn + Assume DS:Nothing + +; + +Proc LSWindow_Home Far + + Call CheckSampleModified + JC LSWindow_Home1 + + Assume DS:Disk + + Mov CurrentSample, 0 + +LSWindow_Home1: + Mov AX, 1 + Ret + +EndP LSWindow_Home + Assume DS:Nothing + +; + +Proc LSWindow_End Far + + Call CheckSampleModified + JC LSWindow_End1 + + Assume DS:Disk + + Mov AX, NumSamples + + Dec AX + JS LSWindow_End1 + + Mov CurrentSample, AX + +LSWindow_End1: + Mov AX, 1 + Ret + +EndP LSWindow_End + Assume DS:Nothing + +; + +Proc D_LSCheckLoopValues Far + + Call D_GetLoadSampleVars ; DS:SI points to thing + + Mov BX, SI + + Mov EAX, [BX+30h] + Cmp EAX, [BX+34h] + JA D_LSCheckLoopValues3 + + Mov [BX+34h], EAX + +D_LSCheckLoopValues3: + Cmp EAX, [BX+38h] + JAE D_LSCheckLoopValues2 + + Mov [BX+38h], EAX + +D_LSCheckLoopValues2: + Mov EAX, [BX+38h] + Cmp EAX, [BX+34h] + JA D_LSCheckLoopValues1 + + And Byte Ptr [BX+12h], NOT 00010000b + +D_LSCheckLoopValues1: + Call D_DrawWaveForm + + Ret + +EndP D_LSCheckLoopValues + +; + +Proc D_LSCheckSusLoopValues Far + + Call D_GetLoadSampleVars ; DS:SI points to thing + + Mov BX, SI + + Mov EAX, [BX+30h] + Cmp EAX, [BX+40h] + JA D_LSCheckSusLoopValues3 + + Mov [BX+40h], EAX + +D_LSCheckSusLoopValues3: + Cmp EAX, [BX+44h] + JAE D_LSCheckSusLoopValues2 + + Mov [BX+44h], EAX + +D_LSCheckSusLoopValues2: + Mov EAX, [BX+44h] + Cmp EAX, [BX+40h] + JA D_LSCheckLoopValues1 + + And Byte Ptr [BX+12h], NOT 00100000b + +D_LSCheckSusLoopValues1: + Call D_DrawWaveForm + + Ret + +EndP D_LSCheckSusLoopValues + +; + +Proc D_SaveSong Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset SongDirectory + Call D_SetDriveDirectory ; DS:SI points to cur dir. + + Cmp Byte Ptr [FileName], 0 + JNE D_SaveSong2 + + Jmp Glbl_F10 + +D_SaveSong2: +; Call D_CheckOverWrite +; JC D_SaveSong1 + + Push CS +; Push CS +; Pop DS + Pop ES + + Mov SI, Offset FileName + Mov DI, Offset SaveFileName + Mov CX, 14 + +D_SaveSong3: + LodsB + StosB + Cmp AL, '.' + LoopNE D_SaveSong3 + JNE D_SaveSong4 + + Cmp SaveFormat, 1 + JE D_SaveSong5 + + Mov AX, 'TI' + StosW + Xor AX, AX + StosB + Jmp D_SaveSong4 + +D_SaveSong5: + Mov AX, '3S' + StosW + Mov AX, 'M' + StosW + +D_SaveSong4: + Xor AL, AL + Call Glbl_SetCurrentMode + + Cmp SaveFormat, 1 + JE D_SaveFileS3MModule + Jmp D_SaveFileITModule + +EndP D_SaveSong + Assume DS:Nothing + +; + +Proc D_PreSaveSample + + Push CS + Pop DS + Assume DS:Disk + + Mov NoSaveError, 0 + + Mov SI, Offset SampleDirectory + Call D_SetDriveDirectory + + Call PE_GetLastInstrument + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + + Mov SI, BX + Add SI, SI + Mov SI, [DS:64912+SI] ; SI points to sample. + Inc BX + + ; Check if sample exists + Test Byte Ptr [SI+12h], 1 + JZ D_PreSaveSample1 + + Call DeleteSampleCacheFile + + LEA DX, [SI+4] + + Call D_CheckOverWrite + Ret + +D_PreSaveSample1: + StC + Ret + +EndP D_PreSaveSample + +; + +Proc D_SaveSample Far + + Call D_PreSaveSample + JC D_SaveSample2 + +Proc D_SaveSampleInternal Far + ; OK to save. DS:SI points to + ; structure, BX = sample num + Mov ES, CS:DiskDataArea + Xor DI, DI + Mov CX, 80 + Rep MovsB + Mov Byte Ptr [ES:2Eh], 1 + Mov DWord Ptr [ES:48h], 80 + + Push ES + Pop DS + + Mov AH, 3Ch + Xor CX, CX + Mov DX, 4 + Int 21h ; Open file. + JC D_SaveSample2 + + Push BX ; BX = sample number + Mov BX, AX ; BX = file handle + + Mov AH, 40h + Mov CX, 80 + Xor DX, DX + Int 21h ; Save header. + + Pop AX ; AX = sample number + Push AX + + Call D_SaveSampleData + PushF + + Mov AH, 3Eh + Int 21h ; Close file + + PopF + Pop BX ; AX = sample number + JC D_SaveSample2 + + Push CS + Pop DS + Mov AX, BX + Mov SI, Offset ITSampleSavedMsg + Call SetInfoLine + + Jmp D_SaveSampleEnd + +D_SaveSample2: + Push CS + Pop DS + Mov AX, BX + Mov SI, Offset SampleErrorMsg + Call SetInfoLine + +D_SaveSampleEnd: + Mov AX, 1 + Ret + +EndP D_SaveSampleInternal + +EndP D_SaveSample + +; + +Proc D_SaveRawSample Far + Assume DS:Disk + + Call D_PreSaveSample ; DS:SI points to structure + JC D_SaveRawSample2 + Assume DS:Nothing + +IF SAVESAMPLEWAV + Mov DWord Ptr [CS:WaveBytesPerSample], 80001h + Mov ECX, [SI+3Ch] ; C5Speed + Mov [CS:WAVEMixSpeed], ECX + Mov EAX, [SI+30h] ; Length + Test Byte Ptr [SI+12h], 2 + JZ D_SaveWAVHeader1 + + Add EAX, EAX + Add ECX, ECX + Mov DWord Ptr [CS:WaveBytesPerSample], 100002h + +D_SaveWAVHeader1: + Mov [CS:WAVEDataSize], EAX + Mov [CS:WAVEBytesPerSecond], ECX +ENDIF + Push DS + Push SI + + Mov AX, BX ; AX = sample number. + Xor CX, CX + Call Music_GetSampleLocation ; ES:DI points to sample. + + Mov DI, SI + Push DS + Pop ES + + Pop SI + Pop DS + + PushF + + Mov AH, 3Ch + Xor CX, CX + LEA DX, [SI+4] + Int 21h + JC D_SaveRawSample3 + +IF SAVESAMPLEWAV + PushA + Push DS + + Push CS + Pop DS + + Mov BX, AX + Mov AH, 40h + Mov DX, Offset WAVEFileHeader + Mov CX, 2Ch + Int 21h + + Pop DS + PopA +ENDIF + + PopF + Push BX + XChg AX, BX ; BX = file handle, AX = sample + ; number + JZ D_SaveRawSample1 ; 8 bit, write as unsigned + + Call D_SaveSampleData + PushF + Jmp D_SaveRawSample4 + +D_SaveRawSample1: + Call D_SaveSampleDataConvert + PushF + +D_SaveRawSample4: + Mov AH, 3Eh + Int 21h ; Close file. + + PopF + Pop BX ; BX = Sample number + + JC D_SaveRawSample2 + + Push CS + Pop DS + Assume DS:Disk + + Mov AX, BX + Mov SI, Offset RawSampleSavedMsg + Call SetInfoLine + + ClC + Jmp D_SaveRawSampleEnd + +D_SaveRawSample3: + PopF + +D_SaveRawSample2: + Push CS + Pop DS + Mov AX, BX + Mov SI, Offset SampleErrorMsg + Call SetInfoLine + StC + +D_SaveRawSampleEnd: + Mov AX, 1 + Ret + +EndP D_SaveRawSample + +; + +Proc D_SaveST3Sample Far + + Call D_PreSaveSample + JC D_SaveST3Sample2 + + ; OK to save. DS:SI points to + ; structure, BX = sample num + Mov ES, CS:DiskDataArea + Xor DI, DI + Mov AL, 1 + StosB + Push SI + Mov CX, 13 + Add SI, 4 + Rep MovsB + Pop SI + Mov AX, 5 + StosW ; FileName + + Mov EAX, [DS:SI+30h] ; LoopStart + StosD + + Mov EAX, [DS:SI+34h] ; LoopBeg + StosD + + Mov EAX, [DS:SI+38h] ; LoopEnd + StosD + + Xor AX, AX + Mov AL, Byte Ptr [DS:SI+13h] + StosW ; Volume + + Mov AH, [DS:SI+12h] + Mov AL, AH + And AX, 1002h + ShR AH, 4 + ShL AL, 1 + Or AH, AL + Xor AL, AL + StosW ; Flags & Pack + + Mov EAX, [DS:SI+3Ch] + StosD + + Mov CX, 6 + Xor AX, AX + Rep StosW + + Add SI, 14h + Mov CX, 25 + Rep MovsB + Xor AX, AX + StosB + StosW + + Mov EAX, 'SRCS' + StosD + + Push ES + Pop DS + + Mov AH, 3Ch + Xor CX, CX + Mov DX, 1 + Int 21h ; Open file. + JC D_SaveST3Sample2 + + Push BX ; BX = sample number + Mov BX, AX ; BX = file handle + + Mov AH, 40h + Mov CX, 80 + Xor DX, DX + Int 21h ; Save header. + + Pop AX ; AX = sample number + Push AX + + Call D_SaveSampleDataConvert + + PushF + + Mov AH, 3Eh + Int 21h ; Close file + + PopF + Pop BX + + JC D_SaveST3Sample2 + + Push CS + Pop DS + Mov AX, BX + Mov SI, Offset ST3SampleSavedMsg + Call SetInfoLine + + Jmp D_SaveST3SampleEnd + +D_SaveST3Sample2: + Push CS + Pop DS + Mov AX, BX + Mov SI, Offset SampleErrorMsg + Call SetInfoLine + +D_SaveST3SampleEnd: + Mov AX, 1 + Ret + +EndP D_SaveST3Sample + +; + +Proc D_SaveInstrument Far + + Push CS + Pop DS + Assume DS:Disk + + Mov NoSaveError, 0 + + Mov SI, Offset InstrumentDirectory + Call D_SetDriveDirectory + + Call PE_GetLastInstrument + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + + Mov SI, BX + Add SI, SI + Mov SI, [DS:64712+SI] ; SI points to instrument + + Call DeleteInstrumentCacheFile + +; Mov DX, SI +; Add DX, 4 + LEA DX, [SI+4] + + Call D_CheckOverWrite + JC D_SaveInstrumentError + + ; DS:SI still points to ins. + ; Clear InstrumentTable setup table. + Push CS + Pop ES + Mov DI, Offset InstrumentTable + Xor AX, AX + Mov CX, 50 + Rep StosW ; OK.. table clear. + + ; Now step through instrument + ; list and get sample numbers. + Push DS + Push SI + + Add SI, 40h + Mov CX, 120 + Xor BX, BX + +D_SaveInstrument1: + LodsW + Mov BL, AH ; BL = sample number. + Mov [CS:InstrumentTable+BX], 1 + Loop D_SaveInstrument1 + + ; OK. Instrument table contains + ; 1s for every sample used... + ; Now to re-translate it. + Push CS + Pop DS + Assume DS:Disk + + Mov AH, 0 + Mov CX, 99 + Mov SI, Offset InstrumentTable + Mov Byte Ptr [SI], 0 + +D_SaveInstrument2: + Cmp Byte Ptr [SI], 0 + JE D_SaveInstrument3 + + Inc AH + Mov [SI], AH + +D_SaveInstrument3: + Inc SI + Loop D_SaveInstrument2 + ; AH = number of samples.. + ; Now let's copy it to the Diskdata. + + Pop SI + Pop DS + Assume DS:Nothing + + Mov ES, CS:DiskDataArea + Xor DI, DI + Mov CX, 554/2 + + Rep MovsW + + Push ES + Pop DS + Assume DS:Nothing + + Mov [DS:1Eh], AH ; AH = number of samples. + Mov Word Ptr [DS:1Ch], TRACKERVERSION + + ; Now to translate + Mov DI, 41h +; Xor BX, BX + Mov CX, 120 + +D_SaveInstrument4: + Mov BL, [DI] + Mov AL, [CS:InstrumentTable+BX] + StosB + Inc DI + + Loop D_SaveInstrument4 + ; headerfilesize=554(instrumentheader)+ + ; 80*AH. + Mov AL, 80 + Mul AH + Add AX, 554 ; AX = header size. + + Push AX + + Mov DX, AX + Xor CX, CX ; CX:DX = posn in file. + + Call Music_GetSongSegment + Mov DS, AX + Mov DI, 554 ; DI = posn in header. + Xor BX, BX + +D_SaveInstrument5: ; Loop to get samples into header. + Cmp [CS:InstrumentTable+BX], 0 + JE D_SaveInstrument6 + + Mov SI, BX + Add SI, SI + Mov SI, [DS:64912+SI-2] ; DS:SI points to sample. + + Push CX ; Move the header... + Mov CX, 40 + Rep MovsW + Pop CX + + Mov [ES:DI-80+48h], DX ; File pointer. + Mov [ES:DI-80+4Ah], CX + + Mov AL, [ES:DI-80+12h] + Test AL, 1 + JZ D_SaveInstrument6 + + Add DX, [ES:DI-80+30h] + AdC CX, [ES:DI-80+32h] + + Test AL, 2 + JZ D_SaveInstrument6 + + Add DX, [ES:DI-80+30h] + AdC CX, [ES:DI-80+32h] + +D_SaveInstrument6: + Inc BX + Cmp BX, 100 + JB D_SaveInstrument5 + + Push ES + Pop DS ; Lets open the file! + Mov DX, 4 + + Mov AH, 3Ch ; Open file! + Xor CX, CX ; Normal attributes + Int 21h + + Pop CX ; CX = header size + + JC D_SaveInstrumentError + + Mov BX, AX ; BX = file handle... + + Xor DX, DX + Call D_SaveBlock ; OK.. header's written.. now save + ; individual samples... + Mov DI, 1 + +D_SaveInstrument7: + Cmp [CS:InstrumentTable+DI], 0 + JE D_SaveInstrument8 + + Mov AX, DI + + Call D_SaveSampleData + +D_SaveInstrument8: + Inc DI + Cmp DI, 100 + JBE D_SaveInstrument7 + + Mov AH, 3Eh + Int 21h + Jmp D_SaveInstrumentOK + +D_SaveInstrumentError: + Push CS + Pop DS + + Call PE_GetLastInstrument + Mov AX, BX + Inc AX + Mov SI, Offset InstrumentErrorMsg + Call SetInfoLine + + Jmp D_SaveInstrumentEnd + +D_SaveInstrumentOK: + Push CS + Pop DS + + Call PE_GetLastInstrument + Mov AX, BX + Inc AX + Mov SI, Offset ITInstrumentSavedMsg + Call SetInfoLine + +D_SaveInstrumentEnd: + Mov AX, 1 + Ret + +EndP D_SaveInstrument + Assume DS:Nothing + +; + +Proc D_DeleteSampleFile Far + + Push CS + Pop DS + Assume DS:Disk + + Cmp NumSamples, 0 + JE D_DeleteSampleFile1 + Cmp SamplesInModule, 0 + JNE D_DeleteSampleFile1 + + Mov AX, 96 + Mul CurrentSample + Mov SI, AX + Mov DS, DiskDataArea + Assume DS:Nothing + Cmp Byte Ptr [DS:SI+58h], 1 + JBE D_DeleteSampleFile1 ; Don't delete dirs! +; Cmp Byte Ptr [DS:SI+58h], 20h +; JAE D_DeleteSampleFile1 + + Push DS + Push SI + + Mov DI, Offset O1_ConfirmDelete2 + Mov CX, 4 + Call M_Object1List + + Pop SI + Pop DS + + And DX, DX ; OK to delete? + JZ D_DeleteSampleFile1 + + ; Delete file.... + LEA DX, [SI+4] + Mov AH, 41h + Int 21h + JC D_DeleteSampleFile1 + + Push CS + Pop DS + Assume DS:Disk + + Mov DI, SI + Add SI, 96 + + Mov CX, NumSamples ; Wipe from list.. + Mov BX, CurrentSample + Sub CX, BX + + Mov AX, 96 + Mul CX + Mov CX, AX + + Push DS + + Mov DS, DiskDataArea + Push DS + Pop ES + + Rep MovsB + + Pop DS + + Mov SampleInMemory, 0FFFFh + Mov SampleCheck, 0FFFFh + + Dec NumSamples + JZ D_DeleteSampleFile2 + + Cmp BX, NumSamples + JB D_DeleteSampleFile2 + + Mov BX, NumSamples + Dec BX + Mov CurrentSample, BX + +D_DeleteSampleFile2: + Cmp SampleCacheFileComplete, 1 + JNE D_DeleteSampleFile1 + + Call D_SaveSampleCacheFile + +D_DeleteSampleFile1: + Mov AX, 1 + Ret + +EndP D_DeleteSampleFile + Assume DS:Nothing + +; + +Proc CheckSampleModified + + Push CS + Pop DS + Assume DS:Disk + + Cmp SamplesInModule, 0 + JNE CheckSampleModified1 + + Mov AX, 96 + Mul CurrentSample + + Mov ES, DiskDataArea + Mov DI, AX + Mov DL, [ES:DI+88] + Cmp DL, 1 + JBE CheckSampleModified1 + Cmp DL, 20h + JAE CheckSampleModified1 + + Mov SI, Offset CheckDataArea + + Mov CX, 12h + RepE CmpSB + JNE CheckSampleModified7 + Inc SI + Inc DI + Mov CX, 50h-12h-1 + RepE CmpsB + JE CheckSampleModified1 + Mov CX, 80 + RepE CmpsB + + ; Check whether file name changed... +CheckSampleModified7: + Mov DI, AX + Mov SI, Offset CheckDataArea+4 + Add DI, 4 + + Mov CX, 13 + RepE CmpsB + JE CheckSampleModified3 + +CheckSampleModified2: ; Sample name different. + Mov DI, Offset O1_ConfirmSaveRenameList + Mov CX, 3 + Call M_Object1List + ; DX = 0 -> don't save + ; DX = 1 -> save + And DX, DX + JZ CheckSampleModified4 + + ; Load Sample + Push CS + Pop DS + + Mov SI, Offset CheckDataArea + Mov AX, 99 + Call LoadSample ; Load sample into slot 100! + JC CheckSampleModified5 + ; Save sample + Mov AX, 96 + Mul CS:CurrentSample + Mov SI, AX + Mov DS, CS:DiskDataArea + Mov BX, 100 ; DS:SI points to block + Push DS + Push SI + Call D_SaveSampleInternal + Pop SI + Pop DS + JC CheckSampleModified6 + ; Delete old sample + + Push CS + Pop DS + Mov DX, Offset CheckDataArea+4 + Mov AH, 41h + Int 21h ; Delete file + + ; Now update sample data... + + Call DeleteSampleCacheFile + Call D_InitLoadSamples + + Jmp CheckSampleModified1 ; Return OK! + +CheckSampleModified3: ; Sample name the same. + Mov DI, Offset O1_ConfirmResaveList + Mov CX, 3 + Call M_Object1List + ; DX = 0 -> don't save + ; DX = 1 -> save + And DX, DX + JZ CheckSampleModified4 + + ; Load Sample + Push CS + Pop DS + + Mov SI, Offset CheckDataArea + Mov AX, 99 + Call LoadSample ; Load sample into slot 100! + JC CheckSampleModified5 + + ; Save Sample + Mov AX, 96 + Mul CS:CurrentSample + Mov SI, AX + Mov DS, CS:DiskDataArea + Mov BX, 100 ; DS:SI points to block + Push DS + Push SI + Call D_SaveSampleInternal + Pop SI + Pop DS + JC CheckSampleModified6 + ; Now update sample data... + Call DeleteSampleCacheFile + Call D_InitLoadSamples + + Jmp CheckSampleModified1 + +CheckSampleModified4: ; Prompt to discard changes.. + Mov DI, Offset O1_ConfirmDiscardList + Mov CX, 4 + Call M_Object1List + ; DX = 0 -> don't discard + ; DX = 1 -> discard + And DX, DX + JZ CheckSampleModified5 + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset CheckDataArea + Mov ES, DS:DiskDataArea + Mov AX, 96 + Mul CurrentSample + Mov DI, AX + Mov CX, 80 + Rep MovsB + + Jmp CheckSampleModified1 + +CheckSampleModified6: + Call DeleteSampleCacheFile + Call D_InitLoadSamples + +CheckSampleModified5: + Push CS + Pop DS + + StC + Ret + +CheckSampleModified1: + Push CS + Pop DS + + ClC + Ret + +EndP CheckSampleModified + Assume DS:Nothing + +; + +Proc D_DrawWaveForm Far + + PushAD + Push DS + Push ES + + Call S_GetGenerationTableOffset + Push DI + Mov CX, 248*32 + Xor AL, AL + Rep StosB + Pop DI + + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation ; Gets DS:SI and CX + JC D_DrawWaveFormEnd + +; Push AX ; AX = instrument num + ; DS:SI = waveform, CX = length + ; ES:DI = charactergenerationtable + + SetNZ CS:Resolution + JZ D_DrawWaveForm8Bit + + Add ECX, ECX + Inc SI + +D_DrawWaveForm8Bit: + + Mov EAX, ECX + Mov ECX, 248 + Xor EDX, EDX + Div ECX ; AX = major shift. DX = minor shift. + + Mov EBX, EAX + Xor EAX, EAX + Div ECX + + Mov EDX, EAX + Xor EAX, EAX + + Mov EBP, ESI + +D_DrawWaveForm6: + Add EAX, EDX + AdC EBP, EBX + Push EAX + Push EBX + Push ECX + Push EDX + + Mov CL, [SI] + Mov CH, CL + + Mov BX, 1 + Add BL, CS:Resolution + +D_DrawWaveForm10: + Cmp ESI, EBP + JAE D_DrawWaveForm7 + + Mov AL, [SI] + Add SI, BX + JC D_DrawWaveFormUpdateLocation + +D_DrawWaveFormResume: + Cmp AL, CL + JL D_DrawWaveForm8 + + Cmp AL, CH + JLE D_DrawWaveForm10 + + Mov CH, AL + Jmp D_DrawWaveForm10 + +D_DrawWaveFormUpdateLocation: + Add ESI, 10000h + Int 3 + Jmp D_DrawWaveFormResume + +D_DrawWaveForm8: + Mov CL, AL + Jmp D_DrawWaveForm10 + +D_DrawWaveForm7: ; CL = min, CH = max. + Mov AX, CX + SAR AH, 1 + SAR AL, 1 + Add AX, 202h + SAR AL, 2 + SAR AH, 2 + + Xor CH, CH + Mov CL, AH + Sub CL, AL ; CX = iterations. + Inc CX + + Mov AL, 16 + Sub AL, AH + Cmp AL, 32 + JNE D_DrawWaveForm13 + + Mov AL, 31 + +D_DrawWaveForm13: + Mov AH, 31*8 + Mul AH + Mov BX, AX + +D_DrawWaveForm11: + Mov Byte Ptr [ES:DI+BX], 1 + Add BX, 248 + Loop D_DrawWaveForm11 + +D_DrawWaveForm12: + Pop EDX + Pop ECX + Pop EBX + Pop EAX + Inc DI + Loop D_DrawWaveForm6 + + ; Get Sample header offset. +; Call Music_GetSongSegment +; Mov DS, AX +; Pop SI +; Dec SI +; Add SI, SI +; Mov SI, [64912+SI] + Mov AX, 96 + Mul CS:CurrentSample + Mov DS, CS:DiskDataArea + Mov SI, AX + + + Mov EBX, [DS:SI+30h] + Test Byte Ptr [DS:SI+12h], 10h + JZ D_DrawWaveForm14 + + Mov ECX, EBX + ShR ECX, 1 + + Mov EAX, 247 + Mul DWord Ptr [DS:SI+34h] + Add EAX, ECX + AdC EDX, 0 + Div EBX + + Push EAX ; AX = loop start. + + Mov EAX, 247 + Mul DWord Ptr [DS:SI+38h] + Add EAX, ECX + AdC EDX, 0 + Div EBX + Mov EDX, EAX + Pop EAX ; DX = loop end (0-175) + ; AX = loop start (0-175) + + Call S_GetGenerationTableOffset + ; ES:DI + Add DI, AX + Sub DX, AX + Dec DX + Mov CX, 32 + Mov AH, 1 + +D_DrawSampleWaveFormLoop1: + Push DI + + Xor AL, AL + Test AH, 2 + JZ D_DrawSampleWaveFormLoop2 + + Inc AX + +D_DrawSampleWaveFormLoop2: + StosB + Add DI, DX + StosB + + Pop DI + Add DI, 248 + Inc AH + Loop D_DrawSampleWaveFormLoop1 + +D_DrawWaveForm14: + Test Byte Ptr [DS:SI+12h], 20h + JZ D_DrawWaveFormEnd + + Mov ECX, EBX + ShR ECX, 1 + + Mov EAX, 247 + Mul DWord Ptr [DS:SI+40h] + Add EAX, ECX + AdC EDX, 0 + Div EBX + + Push EAX ; AX = loop start. + + Mov EAX, 247 + Mul DWord Ptr [DS:SI+44h] + Add EAX, ECX + AdC EDX, 0 + Div EBX + Mov EDX, EAX + Pop EAX ; DX = loop end (0-175) + ; AX = loop start (0-175) + + Call S_GetGenerationTableOffset + ; ES:DI + Add DI, AX + Sub DX, AX + Dec DX + Mov CX, 32 + Mov AL, 1 + +D_DrawSampleWaveFormSusLoop1: + Push DI + + StosB + Add DI, DX + StosB + + Pop DI + Add DI, 248 + Xor AL, 1 + Loop D_DrawSampleWaveFormSusLoop1 + +D_DrawWaveFormEnd: + Mov AX, 0 + Mov BX, 31 + Mov CX, 4 + Call S_GenerateCharacters + + Pop ES + Pop DS + PopAD + + Ret + +EndP D_DrawWaveForm + +; + +Proc D_ClearFileName Far + + Push AX + Push CX + Push ES + Push DI + + Mov DI, Offset FileName + Push CS + Pop ES + Mov CX, 7 + Xor AX, AX + Rep StosW + + Pop DI + Pop ES + Pop CX + Pop AX + Ret + +EndP D_ClearFileName + +; + +Proc D_GetFormatType Far + + Push CS + Pop ES + Mov DI, Offset SaveFormat + + Ret + +EndP D_GetFormatType + +; + +Proc D_DisableFileColours Far + + Mov CS:FileColours, 0 + + Ret + +EndP D_DisableFileColours + +; + +Proc D_LoadInstrumentFiles + + Mov DS, CS:DiskDataArea + Push DS + Pop ES + + Xor DI, DI + Xor AX, AX + Mov CX, 32768 + Rep StosW + + Mov DX, 64000 + Mov AH, 1Ah + Int 21h ; Shift DTA address.. + ; to DiskDataArea:64000 + + Xor DI, DI + + Push CS + Pop DS + Mov DX, Offset AllFilesMask + Mov CX, 10h + Mov AH, 4Eh + Int 21h + + Mov DS, CS:DiskDataArea + Push DS + Pop ES + + JC D_LoadInstrumentFiles2 + +D_LoadInstrumentFiles1: ; A directory was found! + Test Byte Ptr [DS:64000+15h], 10h + JZ D_LoadInstrumentFiles5 ; Check that it IS a directory + + Cmp Word Ptr [DS:64000+1Eh], '.' + JNE D_LoadInstrumentFilesNoRoot + + Mov Byte Ptr [DS:64000+1Eh], '\' + +D_LoadInstrumentFilesNoRoot: + Mov DL, 1 + Call Near Ptr D_LoadInstrumentFiles6 + + Inc CS:NumInstruments + Inc CS:LoadInstrumentNameCount + + Cmp CS:NumInstruments, 999 + JAE D_LoadInstrumentFiles4 + +D_LoadInstrumentFiles5: + Mov AH, 4Fh + Int 21h + JNC D_LoadInstrumentFiles1 + +D_LoadInstrumentFiles2: ; Directories done.. samples now + Push CS + Pop DS + Mov DX, Offset AllFilesMask + Xor CX, CX + Mov AH, 4Eh + Int 21h + + Mov DS, CS:DiskDataArea + Push DS + Pop ES + + JC D_LoadInstrumentFiles4 + +D_LoadInstrumentFiles3: +; Push DI +; +; Mov SI, Offset InstrumentCacheFileName +; Mov DI, 64000+1Eh +; Mov CX, 9 +; Rep SegCS CmpsB +; Pop DI +; JE D_LoadInstrumentFilesNext + + Mov DL, 0 + Call Near Ptr D_LoadInstrumentFiles6 + + Inc CS:NumInstruments + Cmp CS:NumInstruments, 999 + JAE D_LoadInstrumentFiles4 + +D_LoadInstrumentFilesNext: + Mov AH, 4Fh + Int 21h + JNC D_LoadInstrumentFiles3 + +D_LoadInstrumentFiles4: ; End! + Mov AX, CS:NumInstruments + Mov CS:InitialInstruments, AX + + Ret + +D_LoadInstrumentFiles6: ; Get name/size/date/time. + Mov AL, DL + StosB + + Mov SI, 64000+1Eh + Mov CX, 14 ; Name.. + Rep MovsB + + Cmp DL, 1 + JNE D_LoadInstrumentFiles7 + + Push DS + Push CS + Pop DS + Mov SI, Offset DirectoryMsg + Mov CX, 25 + Rep MovsB + + Pop DS + + Xor AX, AX + Mov CX, 4 + Rep StosW + + RetN + +D_LoadInstrumentFiles7: + Xor AX, AX + Mov CX, 27 + Rep StosB ; No instrumentname, NOS = 0. + + Mov AX, [DS:64000+1Ah] ; File Size.. + Mov DX, [DS:64000+1Ch] + + SHRD AX, DX, 10 + ShR DX, 10 + JZ D_LoadInstrumentFiles8 + + Mov AX, 0FFFFh + +D_LoadInstrumentFiles8: + StosW + + Xor EAX, EAX ; Offset + StosD + + RetN + +EndP D_LoadInstrumentFiles + +; + +Proc D_InitLoadInstruments Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset InstrumentDirectory + Call D_SetDriveDirectory ; DS:SI points to cur dir. + + Call Music_GetSongSegment + Mov DS, AX + + Mov CX, 99 + Mov BX, [DS:64912] ; BX = offset to first + ; sample. + + Mov DX, CX ; DX = counter. + Add BX, 12h + +D_InitLoadInstruments4: + Mov AL, [BX] + ShR AL, 1 + SBB DX, 0 + + Add BX, 80 + Loop D_InitLoadInstruments4 + + Push CS + Pop DS + Assume DS:Disk + + Mov UnusedSamples, DX + + Cmp InstrumentsInModule, 0 + JE D_InitLoadInstruments5 + + Jmp LIWindow_EnterLoadInInstrumentData + +D_InitLoadInstruments5: + Mov LoadInstrumentNameCount, 0 + Mov NumInstruments, 0 + Mov InstrumentCacheFileComplete, 0 + + Mov SI, Offset InstrumentDirectory + Call D_SetDriveDirectory ; DS:SI points to cur dir. + + Mov [OldCacheTime], 0 + + Mov AX, 3D00h ; Open file.. + Mov DX, Offset InstrumentCacheFileName + Int 21h + JC D_InitLoadInstrument1 ; Can't open file? + + Mov BX, AX + + Mov AH, 3Fh + Mov CX, 6 ; 2 integers containing number + ; of sample entries... + ; 3rd word = Version check + Mov DS, DiskDataArea + Assume DS:Nothing + + Xor DX, DX + Int 21h + JC D_InitLoadInstrument3 + Cmp AX, CX + JNE D_InitLoadInstrument3 + + Mov AL, [CS:InstrumentDirectory] ; AL = drive letter + Cmp AL, [CS:CDRomStartDrive] + JL InstrumentVersionCheck + Cmp AL, [CS:CDRomEndDrive] + JGE InstrumentVersionCheck + + Cmp Word Ptr [DS:4], 211h + JB D_InitLoadInstrument3 + Cmp Word Ptr [DS:4], TRACKERVERSION + JBE D_InitLoadInstrumentsCacheOK + +InstrumentVersionCheck: + Cmp Word Ptr [DS:4], TRACKERVERSION + JNE D_InitLoadInstrument3 + +InstrumentVersionCheckEnd: + Mov AX, 5700h ; Get file date&time. + Int 21h + + Mov Word Ptr [OldCacheTime], CX + Mov Word Ptr [OldCacheTime+2], DX + + Cmp CX, Time ; Check time and date + JNE D_InitLoadInstrumentOldCache ; for 'currentness' + Cmp DX, Date + JNE D_InitLoadInstrumentOldCache + ; OK.. let's load... + +D_InitLoadInstrumentsCacheOK: + Mov AX, [DS:0] + Mov CS:InitialInstruments, AX + + Mov SI, [DS:2] ; Number of samples. + Mov AX, 48 + Mul SI + Mov CX, AX ; Bytes to read. + + Mov AH, 3Fh ; Load again. + Xor DX, DX ; In case of internal malfunc. + Int 21h + JC D_InitLoadInstrument3 + Cmp AX, CX + JNE D_InitLoadInstrument3 + + Mov AH, 3Eh ; Close file. + Int 21h + + Push CS + Pop DS + Assume DS:Disk + + Mov LoadInstrumentNameCount, SI + Mov NumInstruments, SI + Mov InstrumentCacheFileComplete, 1 + + Jmp D_InitLoadInstrument2 + +D_InitLoadInstrumentOldCache: + PushA + Push DS + + Call D_GetNumFiles + + Pop DS + JC D_InitLoadInstrument5 + + Cmp AX, [DS:0] + + PopA + JNE D_InitLoadInstrument3 + + Call Far Ptr D_InitLoadInstrumentsCacheOK + + Call D_SaveInstrumentCacheFile ; Resave it with new date + + Ret + +D_InitLoadInstrument5: + PopA + +D_InitLoadInstrument3: + Mov AH, 3Eh ; Close file. + Int 21h + + Push CS + Pop DS + Assume DS:Disk + + Call DeleteInstrumentCacheFile + +D_InitLoadInstrument1: + Call D_LoadInstrumentFiles + +D_InitLoadInstrument2: + Ret + +EndP D_InitLoadInstruments + +; + +Proc D_LoadInstrumentNames Far + + Push CS + Pop DS + Assume DS:Disk + + Cmp InstrumentCacheFileComplete, 1 + JNE D_LoadInstrumentNames2 + +D_LoadInstrumentNames6: + Xor AX, AX ; No redraw screen. + Ret + +D_LoadInstrumentNames2: + Mov BX, LoadInstrumentNameCount + Cmp BX, NumInstruments + JAE D_LoadInstrumentNames5 + +D_LoadInstrumentNames1: + Call K_IsAnyKeyDown + And AL, AL + JNZ D_LoadInstrumentNames6 + + Call GetKeyboardLock + And AL, AL + JNZ D_LoadInstrumentNames6 + + Mov AX, 48 + Mul BX + Mov SI, AX + Mov ES, DiskDataArea + Cmp Byte Ptr [ES:SI], 0 + JNE D_LoadInstrumentNames3 + + Call D_LoadInstrumentHeader + JC D_LoadInstrumentNames3 + + Call D_GetInstrumentInfo ; BX = sample number + Push CS + Pop DS + JC D_LoadInstrumentNames7 + +D_LoadInstrumentNames3: + Push CS + Pop DS + Assume DS:Disk + + Inc LoadInstrumentNameCount + +D_LoadInstrumentNames7: + Mov BX, LoadInstrumentNameCount + Cmp BX, NumInstruments + JNE D_LoadInstrumentNames4 + ; Save cache file.. + +D_LoadInstrumentNames5: + Call D_SaveInstrumentCacheFile + Cmp CurrentInstrument, 0 + JNE D_LoadInstrumentNames4 + Call D_SlowInstrumentSort + +D_LoadInstrumentNames4: + Mov AX, 1 ; Signify redraw screen + Ret + +EndP D_LoadInstrumentNames + +; + +Proc D_DrawLoadInstrument Far + + Cmp CS:NumInstruments, 0 + JNE D_DrawLoadInstrumentPresent + + Jmp D_DrawLoadInstrumentEnd + +D_DrawLoadInstrumentPresent: + Mov BX, CS:CurrentInstrument + Mov AX, 48 + Mul BX + Mov SI, AX + Mov ES, CS:DiskDataArea + + Cmp Byte Ptr [ES:SI], 0 + JNE D_DrawLoadInstrumentWindow28 + + Call D_LoadInstrumentHeader + Call D_GetInstrumentInfo + JC D_DrawLoadInstrument + +D_DrawLoadInstrumentWindow28: + Call S_GetDestination + + Push CS + Pop DS + Assume DS:Disk + + Mov AX, TopInstrument + Mov BX, CurrentInstrument + Cmp AX, BX + JBE D_DrawLoadInstrument1 + + Mov AX, BX + +D_DrawLoadInstrument1: + LEa CX, [EAX+34] + Cmp CX, BX + JA D_DrawLoadInstrument2 + + LEA AX, [BX-34] + +D_DrawLoadInstrument2: + Mov TopInstrument, AX + + Mov DS, DiskDataArea + Assume DS:Nothing + + Mov DI, (2+13*80)*2 + Mov CX, 35 + +D_DrawLoadInstrument3: + Push AX + Push CX + Push DI + + Cmp AX, CS:NumInstruments + JB D_DrawLoadInstrument4 + + Mov AX, 2A8h + Add DI, 58 + StosW + Add DI, 24 + StosW + +D_DrawLoadInstrument10: + Add DI, 20 + StosW + + Jmp D_DrawLoadInstrument5 + +D_DrawLoadInstrument4: + Inc AX + Mov CH, 20h + Call PE_ConvAX2Num + Dec AX + + Add DI, 8 + Mov BX, 48 + Mul BX + Mov SI, AX ; SI = offset in diskdata.. + ; Name first.. + + Mov DL, [SI] + ; DL = type. 0 = unchecked + ; 1 = directory + ; 2 = unknown + ; 3 = ITI. + Mov AH, 6 + Cmp DL, 1 + JB D_DrawLoadInstrument6 + + Mov AH, 5 + JE D_DrawLoadInstrument6 + + Mov AH, 7 + Cmp DL, 2 + JE D_DrawLoadInstrument6 + + Mov AH, 3 + +D_DrawLoadInstrument6: + Mov DH, AH ; DH = col. + Mov CX, 25 ; Instrument Name + Add SI, 15 + +D_DrawLoadInstrument7: + LodsB + + Cmp AL, 226 + JB D_DrawLoadInstrumentCharFilter + + Mov AL, ' ' + +D_DrawLoadInstrumentCharFilter: + StosW + Loop D_DrawLoadInstrument7 + + Mov AX, 2A8h + StosW ; Divider 1. + + Mov AH, DH + ; File name... + Sub SI, 39 + Mov CX, 12 + +D_DrawLoadInstrument8: + LodsB + StosW + And AL, AL + LoopNZ D_DrawLoadInstrument8 + + Add DI, CX + Add DI, CX + + Mov AX, 2A8h + StosW ; Divider 2. + + Cmp DL, 3 + JB D_DrawLoadInstrument10 + + LEA SI, [ESI+ECX+27] + LodsW ; AX = number of samples. + + Push DS + Push SI + Push DI + Push AX + + Cmp Byte Ptr [SI-42], 8 + + Push CS + Pop DS + + Mov SI, Offset InstrumentLibrary + JAE D_DrawLoadInstrument9 + + Mov SI, Offset InstrumentNoSample + Cmp AX, 1 + JB D_DrawLoadInstrument9 + + Mov SI, Offset InstrumentSingleSample + JE D_DrawLoadInstrument9 + + Mov SI, Offset InstrumentSeveralSamples + Cmp AX, 0FFFFh + JNE D_DrawLoadInstrument9 + + Mov SI, Offset InstrumentUnknownSamples + +D_DrawLoadInstrument9: + Mov AH, DH + Call S_DrawString + + Pop AX + Pop DI + Pop SI + Pop DS + + Mov AX, 2A8h + Add DI, 20 + StosW ; Divider.. now file size... + + LodsW ; AX = file size. + + Push DS + + Push CS + Pop DS + Mov SI, Offset FileSizeMsg + + Push AX + Mov AH, DH + Call S_DrawString + + Pop AX + + Pop DS + +D_DrawLoadInstrument5: + Pop DI + Pop CX + Pop AX + + Inc AX + + Add DI, 160 + Loop D_DrawLoadInstrument3 + + Push CS + Pop DS + Jmp D_DrawLoadInstrumentEnd2 + +D_DrawLoadInstrumentEnd: + Push CS + Pop DS + Assume DS:Disk + + Mov DI, (6+13*80)*2 ; (6, 13) + Mov SI, Offset NoFilesMsg + + Mov AH, 5 + Call S_DrawString + +D_DrawLoadInstrumentEnd2: ; Put Unused Sample msg. + Mov AX, UnusedSamples + Push AX + + Mov SI, Offset FreeSampleMsg + Mov DI, (64+13*80)*2 + Mov AH, 20h + + Call S_DrawString + + Pop AX + + Ret + +EndP D_DrawLoadInstrument + Assume DS:Nothing + +; + +Proc D_PreLoadInstrument Far + + Push CS + Pop DS + Assume DS:Disk + + Mov AX, CurrentInstrument + Sub AX, TopInstrument + Add AX, 13 + Mov BX, 160 + Mul BX + + Call S_GetDestination + + LEA DI, [EAX+12] + Mov CX, 56 + +D_PreLoadInstrument1: + Mov AX, [ES:DI] + + Mov AH, 32h + + Cmp AL, 0A8h + JE D_PreLoadInstrument3 + +D_PreLoadInstrument2: + Mov AH, 30h + +D_PreLoadInstrument3: + StosW + + Loop D_PreLoadInstrument1 + + Ret + + Ret + +EndP D_PreLoadInstrument + +; + +Proc D_PostLoadInstrument Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset LoadInstrumentKeys + Call M_FunctionDivider + JC D_PostLoadInstrument1 + + Jmp [SI] + +D_PostLoadInstrument1: + Xor AX, AX + Ret + +EndP D_PostLoadInstrument + +; + +Proc D_ViewInstrument Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset ViewInstrumentKeys + Call M_FunctionDivider + JC D_ViewInstrument1 + + Jmp [SI] + +D_ViewInstrument1: + Xor AX, AX + Ret + +EndP D_ViewInstrument + +; + +Proc LIWindow_Up Far + + Assume DS:Disk + + Mov AX, CurrentInstrument + And AX, AX + JZ LIWindow_Up1 + + Dec CurrentInstrument + +LIWindow_Up1: + Mov AX, 1 + Ret + +EndP LIWindow_Up + Assume DS:Nothing + +; + +Proc LIWindow_Down Far + + Assume DS:Disk + + Mov AX, CurrentInstrument + + Inc AX + Cmp AX, NumInstruments + JAE LIWindow_Down1 + + Mov CurrentInstrument, AX + +LIWindow_Down1: + Mov AX, 1 + Ret + +EndP LIWindow_Down + Assume DS:Nothing + +; + +Proc LIWindow_PgUp Far + + Assume DS:Disk + + Mov AX, CurrentInstrument + + Sub AX, 35 + JC LIWindow_Home + + Mov CurrentInstrument, AX + +LIWindow_PgUp1: + Mov AX, 1 + Ret + +EndP LIWindow_PgUp + Assume DS:Nothing + +; + +Proc LIWindow_PgDn Far + + Assume DS:Disk + + Mov AX, CurrentInstrument + + Add AX, 35 + Cmp AX, NumInstruments + JAE LIWindow_End + + Mov CurrentInstrument, AX + +LIWindow_PgDn1: + Mov AX, 1 + Ret + +EndP LIWindow_PgDn + Assume DS:Nothing + +; + +Proc LIWindow_Home Far + + Assume DS:Disk + Mov CurrentInstrument, 0 + + Mov AX, 1 + Ret + +EndP LIWindow_Home + Assume DS:Nothing + +; + +Proc LIWindow_End Far + + Assume DS:Disk + + Mov AX, NumInstruments + + Dec AX + JS LIWindow_End1 + + Mov CurrentInstrument, AX + +LIWindow_End1: + Mov AX, 1 + Ret + +EndP LIWindow_End + Assume DS:Nothing + +; + +Proc LIViewWindow_Tab Far + + Mov Word Ptr [ES:DI], 7 + + Mov AX, 1 + Ret + +EndP LIViewWindow_Tab + +; + +include it_d_ri.inc + +; + +Proc LIViewWindow_Enter Far + + Assume DS:Disk + + Cmp NumInstruments, 0 + JE LIViewWindow_Enter2 + + Mov AX, 48 + Mul CurrentInstrument + Mov SI, AX + Assume DS:Nothing + + Mov DS, DiskDataArea + Mov DL, [DS:SI] + Cmp DL, 1 + JE LIViewWindow_Enter1 + Cmp DL, 8 + JAE LIWindow_InInstrument1 + +LIViewWindow_Enter2: + Mov AX, 1 + Ret + +EndP LIViewWindow_Enter + Assume DS:Nothing + +; + +Proc LIWindow_Enter Far + + Assume DS:Disk + + Cmp NumInstruments, 0 + JE LIWindow_Enter4 + + Mov AX, 48 + Mul CurrentInstrument + Mov SI, AX + Assume DS:Nothing + + Mov DS, DiskDataArea + Mov DL, [DS:SI] + Cmp DL, 1 + JNE LIWindow_Enter1 + +LIViewWindow_Enter1: + Push DS + Push SI + + Push CS + Pop DS + Mov SI, Offset InstrumentDirectory + Call D_SetDriveDirectory + + Pop SI + Pop DS + + Inc SI + Call D_SetDriveDirectory + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset InstrumentDirectory + Call D_GetDriveDirectory + +LIWindow_EnterInModuleError: + Mov InstrumentsInModule, 0 + Call D_InitLoadInstruments + Assume DS:Nothing + + Mov CS:CurrentInstrument, 0 + +LIWindow_Enter4: + Mov AX, 1 + Ret + +LIWindow_Enter1: ; Load sample into sample list. + Cmp DL, 8 + JAE LIWindow_InInstrument1 + Cmp DL, 3 + JAE LIWindow_Enter2 + + Xor AX, AX + Ret + +LIWindow_InInstrument1: + Mov CS:InInstrumentFormat, DL + + Inc SI + ; Copy module name across + Push CS + Pop ES + Mov DI, Offset InInstrumentFileName + Mov CX, 13 + Rep MovsB + ; Open file + Push CS + Pop DS + Assume DS:Disk + + Mov CurrentInstrument, 0 + +LIWindow_EnterLoadInInstrumentData: + Mov DX, Offset InInstrumentFileName + Mov AX, 3D00h + Int 21h + JC LIWindow_EnterInModuleError + + Mov BX, AX + + Mov SI, Word Ptr InInstrumentFormat + And SI, 0FFh + Add SI, SI + + Mov NumInstruments, 1 + + Mov DS, DiskDataArea + Assume DS:Nothing + + Push DS + Pop ES + + Call [CS:InstrumentLoaderTable+SI-6] + + ; Close module + Mov AH, 3Eh + Int 21h + + ; Setup first 'directory' + + Push CS + Pop DS + Assume DS:Disk + + Xor DI, DI + Mov SI, Offset ExitInstrumentLibraryDirectory + Mov CX, 48 + Rep MovsB + + Mov InstrumentCacheFileComplete, 1 + Mov InstrumentsInModule, 1 + + Mov AX, NumInstruments + Mov LoadInstrumentNameCount, AX + + Mov AX, 1 + Ret + Assume DS:Nothing + +LIWindow_Enter2: + Mov EAX, [SI+44] + Mov CS:LoadInstrumentOffset, EAX + Mov AX, [SI+40] + Mov CS:NumInstrumentSamples, AX + + And DX, 0FFh + Sub DX, 3 + Add DX, DX + Mov BX, DX + Mov AX, [CS:InstrumentLoaderTable+BX] + Mov [CS:InstrumentLoader], AX + + Mov AX, [SI+40] + Cmp AX, UnusedSamples + JBE LIWindow_Enter5 + + Mov CX, 0FFFFh + Mov DI, Offset O1_OutOfSamplesList + Call M_Object1List + Jmp LIWindow_Enter4 + +LIWindow_Enter5: ; OK.. enough 'sample space'.. + Call Music_Stop + + ; Clean out all old samples... + ; 1. Clean out table + ; 2. Set all samples used in inst to 1 + ; 3. Step through all insts and set + ; samples to 0 + ; 4. Delete all samples with 1. + Push CS ; Step 1. + Pop ES + Mov DI, Offset InstrumentTable + Mov CX, 50 + Xor AX, AX + Rep StosW ; Step 1. Done. + + Push DS + Push SI + + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + + + Call PE_GetLastInstrument + Mov DX, BX ; DX = instrument, 0 based + Add BX, BX + Mov SI, [DS:64712+BX] + Add SI, 40h + Mov CX, 120 + +ClearSamples1: + LodsW ; AH = sample. AL = note + Mov BL, AH + Mov [CS:InstrumentTable+BX], 1 + Loop Clearsamples1 + + Xor BX, BX + +ClearSamples2: + Cmp BX, DX + JE ClearSamples3 + + Mov SI, BX + Add SI, SI + Mov SI, [DS:64712+SI] + Add SI, 41h + Mov CX, 120 + +ClearSamples4: + LodsW + And AX, 0FFh + Mov DI, AX + Mov [CS:InstrumentTable+DI], 0 + Loop ClearSamples4 + +ClearSamples3: + Inc BX + Cmp BL, 99 + JB ClearSamples2 + + Xor DI, DI + +ClearSamples5: + Cmp [CS:InstrumentTable+DI+1], 0 + JE ClearSamples6 + + Mov AX, DI + Call Music_ReleaseSample + +ClearSamples6: + Inc DI + Cmp DI, 99 + JB ClearSamples5 + + Pop DX + Pop DS + ; Process. + ; 1. Reset instrument-sample table. + ; 2. Read all sample headers into mem. + ; 3. Load each sample/sample header. + ; 4. Store instrument header. + + Push CS ; Step 1. + Pop ES + Mov DI, Offset InstrumentTable + Mov CX, 50 + Xor AX, AX + Rep StosW ; Step 1. Done. + + ; OK. to do step 2. + ; a) Open file. + ; b) if error.. skip! + ; c) Load file. + + Inc DX + Mov AX, 3D00h ; Open file.. +; Mov DX, SI +; Inc DX ; DS:DX points to file name + Int 21h + + JNC LIWindow_Enter6 + + Mov AX, 1 + Ret + +LIWindow_Enter6: + Mov BX, AX ; BX = file handle. + + ; Load instrument data into DS:64000 + ; Step 3. Go through each sample. + Call [CS:InstrumentLoader] + + Call Music_GetSongSegment + Mov ES, AX + + Mov CL, [DS:64000+1Eh] + And CX, 0FFh + JZ LIWindow_Enter10 + + Push CX + + Mov DI, [ES:64912] + Add DI, 12h-80 + Xor SI, SI + Xor AX, AX + +LIWindow_Enter8: ; Figure out instrument translation + ; table first. + Inc AX + Add DI, 80 + Test Byte Ptr [ES:DI], 1 ; Sample present? + JNZ LIWindow_Enter8 + + Inc SI + Mov [CS:InstrumentTable+SI], AL + + Loop LIWindow_Enter8 + + Pop CX + + Xor SI, SI ; SI = pointer to first sample. + Mov DI, 1 ; DI = untranslated sample number. + +LIWindow_Enter9: + Push CX ; Have to load EACH sample... + Push DS + Push SI + Push ES + Push DI + + Mov DL, [CS:InstrumentTable+DI] + Xor DH, DH ; DX = translated sample number. + Dec DX + + Mov DI, DX + Add DI, DI ; DI = 2*samplenumber + Mov DI, [ES:64912+DI] ; ES:DI points to sample in mem. + + Mov CX, 48h/2 + Rep MovsW + Xor AX, AX + StosW ; Sample pointer data. + StosW + Add SI, 4 + MovsW + MovsW ; OK.. sample header transferred.. + ; Need to load sample data?? + Mov Word Ptr [ES:DI-80+2Eh], 1 + +IF NETWORKENABLED + Mov AL, NETWORK_SAMPLEHEADEROBJECT + Mov AH, DL + Call Network_AddWordToQueue +ENDIF + Test Byte Ptr [SI-80+12h], 1 + JZ LIWindow_Enter11 ; No! + + Push DX + Push DX + + Mov AX, 4200h + Mov CX, [SI-80+4Ah] + Mov DX, [SI-80+48h] + Int 21h ; Move pointer... + + Pop AX + Sub SI, 80 + Call PE_SaveCurrentPattern + Call D_LoadSampleData + Call PE_RestoreCurrentPattern + + Pop CX + +IF NETWORKENABLED + Xor DX, DX + Call Network_QueueSampleData +; Mov AL, NETWORK_SAMPLEHEADEROBJECT +; Mov AH, DL +; Call Network_AddWordToQueue +ENDIF + + + Jmp LIWindow_Enter11 + +LIWindow_Enter12: + Call PEFunction_OutOfMemoryMessage + +LIWindow_Enter11: + Pop DI + Pop ES + Pop SI + Pop DS + Pop CX + + Inc DI + Add SI, 80 + + Loop LIWindow_Enter9 + +LIWindow_Enter10: ; Now to copy instrument... + Mov AH, 3Eh + Int 21h ; Close file first. + + Call I_GetInstrumentOffset + ; DS:BX points to instrument + ; DS:64000 points to loaded instrument + ; so copy everything, but update the + ; sample numbers.. + Mov DI, BX + Push DS + Pop ES + + Mov DS, CS:DiskDataArea + + + Mov SI, 64000 + Mov CX, 40h/2 + Rep MovsW + + Mov CX, 120 + Xor BX, BX + +LIWindow_Enter7: + MovsB ; Note transferred. + LodsB + Mov BL, AL + Mov AL, [CS:InstrumentTable+BX] + StosB + Loop LIWindow_Enter7 + + Mov CX, 250/2 + Rep MovsW + + Call Music_SoundCardLoadAllSamples + + Call Music_GetInstrumentMode + JNZ LIWindow_Enter13 + + Mov CX, 3 + Mov DI, Offset O1_EnableInstrumentMode + Call M_Object1List + Test DX, DX + + JZ LIWindow_Enter13 + + Call Music_GetSongSegment + Mov DS, AX + Or Byte Ptr [DS:2Ch], 4 + +IF NETWORKENABLED + Mov CX, 1 + Mov DX, 2Ch + Call Network_SendSongDataInformation +ENDIF + +LIWindow_Enter13: + NetworkSendInstrument + Jmp Glbl_F4 + +EndP LIWindow_Enter + Assume DS:Nothing + +; + +Proc D_DeleteInstrumentFile Far + + Push CS + Pop DS + Assume DS:Disk + + Cmp NumInstruments, 0 + JE D_DeleteInstrumentFile1 + Cmp InstrumentsInModule, 0 + JNE D_DeleteInstrumentFile1 + + Mov AX, 48 + Mul CurrentInstrument + Mov SI, AX + Mov DS, DiskDataArea + Assume DS:Nothing + Cmp Byte Ptr [DS:SI], 1 + JBE D_DeleteInstrumentFile1 ; Don't delete dirs! + Cmp Byte Ptr [DS:SI], 8 + JAE D_DeleteInstrumentFile1 + + Push DS + Push SI + + Mov DI, Offset O1_ConfirmDelete3 + Mov CX, 4 + Call M_Object1List + + Pop SI + Pop DS + + And DX, DX ; OK to delete? + JZ D_DeleteInstrumentFile1 + + ; Delete file.... + Mov DX, SI + Inc DX + Mov AH, 41h + Int 21h + JC D_DeleteInstrumentFile1 + + Push CS + Pop DS + Assume DS:Disk + + Mov DI, SI + Add SI, 48 + + Mov CX, NumInstruments + Mov BX, CurrentInstrument + Sub CX, BX + + Mov AX, 48 + Mul CX + Mov CX, AX + + Push DS + + Mov DS, DiskDataArea + Push DS + Pop ES + + Rep MovsB + + Pop DS + + Dec NumInstruments + JZ D_DeleteInstrumentFile2 + + Cmp BX, NumInstruments + JB D_DeleteInstrumentFile2 + + Mov BX, NumInstruments + Dec BX + Mov CurrentInstrument, BX + Dec LoadInstrumentNameCount + +D_DeleteInstrumentFile2: + Cmp InstrumentCacheFileComplete, 1 + JNE D_DeleteInstrumentFile1 + + Call D_SaveInstrumentCacheFile + +D_DeleteInstrumentFile1: + Mov AX, 1 + Ret + +EndP D_DeleteInstrumentFile + Assume DS:Nothing + +; + +Proc D_GetPreShellDirectory Far + + Push CS + Pop DS + Mov SI, Offset PreShellDirectory + + Call D_GetDriveDirectory + + Mov SI, Offset DOSDirectory + Call D_SetDriveDirectory + + + Ret + +EndP D_GetPreShellDirectory + +; + +Proc D_RestorePreShellDirectory Far + + Push CS + Pop DS + Mov SI, Offset PreShellDirectory + + Call D_SetDriveDirectory + + Ret + +EndP D_RestorePreShellDirectory + +; + +Proc D_SetDriveDirectoryFar Far + + Call D_SetDriveDirectory + Ret + +EndP D_SetDriveDirectoryFar + +; + +Proc D_GetFileName Far + + Push CS + Pop DS + Mov SI, Offset FileName + + Ret + +EndP D_GetFileName + +; + +Proc D_ResetTimer Far + + Push DS + + Push CS + Pop DS + Assume DS:Disk + + Call GetTimerCounter + Mov [EditTimer], EAX + Call ReleaseTimerData + + Call CheckTimerData + + Pop DS + Ret + +EndP D_ResetTimer + Assume DS:Nothing + +; + +Hours DB "0000:" +Minutes DB "00:" +Seconds DB "00", 0 + +RemainingDateMsg DB " ", 0FDh, "D, ", 0FDh, "D", 0 + +Time2Msg DB 0FDh, "D:00", 0 +TotalTime DD 0 + +Proc D_ShowTime Far + + Push CS + Pop DS + Assume DS:Disk + + Mov EDX, 3600 + Mul EDX + ShRD EAX, EDX, 16 + ShR EDX, 16 + JNZ D_ShowTimeEnd + ; EAX = number of seconds + Mov EBX, 60 + Div EBX ; EAX = minutes, EDX = seconds + + Push EDX + Xor EDX, EDX + Div EBX ; EAX = hours, EDX = minutes + + Pop ECX + Push AX ; Hours on stack, CX = seconds, DX = min + Mov BL, 10 + + Mov AX, DX + Div BL + Add AX, 3030h + Mov [Word Ptr Minutes], AX + + Mov AX, CX + Div BL + Add AX, 3030h + Mov [Word Ptr Seconds], AX + + Pop AX ; AX = hours. + Cmp AH, BL + JAE D_ShowTimeEnd + + Div BL + Add AH, '0' + Mov [Byte Ptr Hours+3], AH + Xor AH, AH + + Div BL + Add AH, '0' + Mov [Byte Ptr Hours+2], AH + Xor AH, AH + + Div BL + Add AH, '0' + Mov [Byte Ptr Hours+1], AH + Xor AH, AH + + Div BL + Add AH, '0' + Mov [Byte Ptr Hours+0], AH + Xor AH, AH + + Xor BX, BX + Mov SI, Offset Hours + +D_ShowTime1: + Cmp Byte Ptr [SI+BX], '0' + JNE D_ShowTime2 + Mov Byte Ptr [SI+BX], ' ' + Inc BX + Cmp BX, 3 + JB D_ShowTime1 + +D_ShowTime2: + Mov AH, 20h + Call S_DrawString + +D_ShowTimeEnd: + Ret + +EndP D_ShowTime + Assume DS:Nothing + +; + +IF TIMERSCREEN + +TimerListKeys Label + + DB 0 + DW 1C8h ; Up arrow + DW D_TimerListUp + + DB 0 + DW 1D0h ; Down arrow + DW D_TimerListDown + + DB 0 + DW 1C9h ; PgUp + DW D_TimerListPgUp + + DB 0 + DW 1D1h ; PgDn + DW D_TimerListPgDn + + DB 0 + DW 0D29h ; Left Ctrl, Right Shift + '`' + DW D_ReleaseTimer + + DB 0 + DW 4529h + DW D_ToggleShowTimes + + DB 0FFh + +; + +Proc D_PostTimerList Far + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset TimerListKeys + Call M_FunctionDivider + JC D_PostTimerList1 + + Jmp [SI] + +D_PostTimerList1: + Xor AX, AX + + Ret + +EndP D_PostTimerList + +; + +Proc D_TimerListUp Far + Assume DS:Disk + + Sub TopTimerData, 1 + AdC TopTimerData, 0 + + Mov AX, 1 + Ret + +EndP D_TimerListUp + Assume DS:Nothing + +; + +Proc D_TimerListDown Far + Assume DS:Disk + + Mov AX, TopTimerData + Cmp AX, NumTimerData + JAE D_TimerListDown1 + + Inc AX + Mov TopTimerData, AX + +D_TimerListDown1: + Mov AX, 1 + Ret + +EndP D_TimerListDown + Assume DS:Nothing + +; + +Proc D_TimerListPgUp Far + Assume DS:Disk + + Sub TopTimerData, 28 + JNC D_TimerListPgUp1 + + Mov TopTimerData, 0 + +D_TimerListPgUp1: + Mov AX, 1 + Ret + +EndP D_TimerListPgUp + Assume DS:Nothing + +; + +Proc D_TimerListPgDn Far + Assume DS:Disk + + Mov AX, TopTimerData + Add AX, 28 + Cmp AX, NumTimerData + JB D_TimerListPgDn1 + + Mov AX, NumTimerData + Sub AX, 1 + AdC AX, 0 + +D_TimerListPgDn1: + Mov TopTimerData, AX + + Mov AX, 1 + Ret + +EndP D_TimerListPgDn + Assume DS:Nothing + +; + +ShowTimes DB 0 + +Proc D_DrawTimer Far + + Call Music_GetSongSegment + Mov ES, AX + + Mov EAX, [ES:3Ch] + Mov DI, (18+13*80)*2 + Call D_ShowTime + + Call GetTimerCounter + Sub EAX, [CS:EditTimer] + Mov DI, (18+14*80)*2 + Push EAX + Call D_ShowTime + + Pop EAX + Mov DI, (18+16*80)*2 + Add EAX, [ES:3Ch] + Call D_ShowTime + + Test ShowTimes, 1 + JZ D_DrawTimerEnd + + Assume DS:Disk + + Mov CX, 28 + Mov SI, TopTimerData + Mov AX, TimerData + Test AX, AX + JZ D_DrawTimerEnd + Mov ES, AX + Mov AX, SI + ShL SI, 3 + Mov DI, (4+20*80)*2 + + Mov BX, 4 + Mov TotalTime, 0 + +D_DrawTimer2: + Cmp BX, SI + JA D_DrawTimer1 + + Mov EDX, [ES:BX] + Add TotalTime, EDX + Add BX, 8 + Jmp D_DrawTimer2 + +D_DrawTimer1: + Cmp AX, NumTimerData + JAE D_DrawTimerEnd + PushA + ; Data formats: yyyyyyym mmmddddd + ; hhhhhmmm mmmsssss + SegES LodsD + + Push SI + Push DI + ; AX = yyyyyyym mmmddddd + Mov BX, AX + ShR AX, 9 + Add AX, 1980 + Push AX ; Year + Mov AX, BX + And AX, 1Fh + Push AX + + ShR BX, 5 + And BX, 0Fh + Add BX, BX + + Mov SI, [MonthNames+BX] + Mov AH, 20h + Call S_DrawString + + Mov SI, Offset RemainingDateMsg + Call S_DrawString + + Pop AX ; Clean up stack + Pop AX + + Pop DI + Add DI, 50 + Push DI + + ; time + ShR EAX, 21 ; AX = hhh hhmmmmmm + Mov BX, AX + ShR BX, 6 + Push BX + Mov BL, 10 + And AX, 3Fh + Div BL + Add AX, '00' + Mov Word Ptr [Time2Msg+3], AX ; Minutes done. + + Mov SI, Offset Time2Msg + Mov AH, 20h + Call S_DrawString + Pop AX + + Pop DI + Pop SI + + Add DI, 30 + SegES LodSD + Add TotalTime, EAX + Call D_ShowTime + + Add DI, 20 + + Mov EAX, TotalTime + Call D_ShowTime + + PopA + Add SI, 8 + Add DI, 160 + Inc AX + Loop D_DrawTimer1 + +D_DrawTimerEnd: + Xor AX, AX + Ret + +EndP D_DrawTimer + +ENDIF + +; + +Proc D_ReleaseTimer Far + + Call ReleaseTimerData + Inc AX + Ret + +EndP D_ReleaseTimer + +; + +IF TIMERSCREEN + +Proc D_ToggleShowTimes Far + Assume DS:Disk + + Xor ShowTimes, 1 + + Mov AX, 1 + Ret + +EndP D_ToggleShowTimes + Assume DS:Nothing + +ENDIF + +; +; + +Proc D_SlowSampleSort Far + + Push CS + Pop DS + Assume DS:Disk + +IF SORTENABLED + Cmp SamplesInModule, 1 + JE D_SlowSampleSortExit + Cmp SampleCacheFileComplete, 1 + JNE D_SlowSampleSortExit + Mov CX, NumSamples + + Mov SampleInMemory, 0FFFFh + Mov SampleCheck, 0FFFFh + + Mov ES, DiskDataArea + Push ES + Pop DS + Assume DS:Nothing + + Xor SI, SI + + Cmp Word Ptr [SI+4], '\' + JNE SlowSampleSortNoSort1 + + Add SI, 60h + Dec CX + +SlowSampleSortNoSort1: + Cmp Word Ptr [SI+4], '..' + JNE SlowSampleSortNoSort2 + + Add SI, 60h + Dec CX + +SlowSampleSortNoSort2: + Cmp CX, 0 + JLE D_SlowSampleSortExit + +SlowSampleSortLoop1: + Push CX + Push SI + + Mov AL, [SI+5Ah] + Mov DX, SI ; DX = destination of SI + Mov DI, SI + Mov BX, CX + +SlowSampleSortLoop2: + +; SI = current lowest. + +; Sort priority: 0 = directory +; 1 = library +; 2 = recognised +; 3 = unknown + + Cmp AL, [DI+5Ah] + JB D_CompareSamples2 + JA D_CompareSamples1 + + Push SI + Push DI + + Mov CX, 13 + Add SI, 4 + Add DI, 4 + RepE CmpSB + Pop DI + Pop SI + + JBE D_CompareSamples2 + +D_CompareSamples1: + Mov AL, [DI+5Ah] + Mov SI, DI + +D_CompareSamples2: + Add DI, 60h + + Dec BX + JNZ SlowSampleSortLoop2 + + Cmp SI, DX + JE D_CompareSamplesNoSwap + + + Push DI + Mov CX, 24 + Rep MovsD + + LEA DI, [SI-60h] + Mov SI, DX + Mov CX, 24 + Rep MovsD + + Pop SI + Mov DI, DX + Mov CX, 24 + Rep MovsD + +D_CompareSamplesNoSwap: + Pop SI + Pop CX + + Add SI, 60h + + Dec CX + JNZ SlowSampleSortLoop1 + + Call D_SaveSampleCacheFile ; Resave it with new date + +D_SlowSampleSortExit: + +ENDIF + + Mov AX, 1 + Ret + +EndP D_SlowSampleSort + +; + +Proc D_SlowInstrumentSort Far + + Push CS + Pop DS + Assume DS:Disk + +IF SORTENABLED + Cmp InstrumentsInModule, 1 + JE D_SlowInstrumentSortExit + Cmp InstrumentCacheFileComplete, 1 + JNE D_SlowInstrumentSortExit + Mov CX, NumInstruments + + Mov ES, DiskDataArea + Push ES + Pop DS + Assume DS:Nothing + + Xor SI, SI + + Cmp Word Ptr [SI+1], '\' + JNE SlowInstrumentSortNoSort1 + + Add SI, 30h + Dec CX + +SlowInstrumentSortNoSort1: + Cmp Word Ptr [SI+1], '..' + JNE SlowInstrumentSortNoSort2 + + Add SI, 30h + Dec CX + +SlowInstrumentSortNoSort2: + Cmp CX, 0 + JLE D_SlowInstrumentSortExit + +SlowInstrumentSortLoop1: + Push CX + Push SI + + Mov AL, [SI] + Mov DX, SI ; DX = destination of SI + Mov DI, SI + Mov BX, CX + +SlowInstrumentSortLoop2: + Mov AH, [DI] + +; SI = current lowest. + + Cmp AL, 1 + JNE SlowInstrumentSort3 + Cmp AH, 1 + JE SlowInstrumentFilename + Jmp D_CompareInstruments2 + +SlowInstrumentsort3: + Cmp AH, 1 + JE D_CompareInstruments1 + + Test AL, 8 + JZ SlowInstrumentSort4 + Test AH, 8 + JNZ SlowInstrumentFileName + Jmp D_CompareInstruments2 + +SlowInstrumentsort4: + Test AH, 8 + JNZ D_CompareInstruments1 + +SlowInstrumentFilename: + Push SI + Push DI + + Mov CX, 13 + Inc SI + Inc DI + RepE CmpSB + Pop DI + Pop SI + + JBE D_CompareInstruments2 + +D_CompareInstruments1: + Mov AL, AH + Mov SI, DI + +D_CompareInstruments2: + Add DI, 30h + + Dec BX + JNZ SlowInstrumentSortLoop2 + + Cmp SI, DX + JE D_CompareInstrumentsNoSwap + + Push DI + Mov CX, 12 + Rep MovsD + + LEA DI, [SI-30h] + Mov SI, DX + Mov CX, 12 + Rep MovsD + + Pop SI + Mov DI, DX + Mov CX, 12 + Rep MovsD + +D_CompareInstrumentsNoSwap: + Pop SI + Pop CX + + Add SI, 30h + + Dec CX + JNZ SlowInstrumentSortLoop1 + + Call D_SaveInstrumentCacheFile ; Resave it with new date + +D_SlowInstrumentSortExit: + +ENDIF + + Mov AX, 1 + Ret + +EndP D_SlowInstrumentSort + +; + +Segment DiskData PARA Public 'Data' + DB 65536 Dup (0) +EndS + +; + +EndS + +; + +End diff --git a/it/IT_DISPL.ASM b/it/IT_DISPL.ASM new file mode 100644 index 0000000..4c32729 --- /dev/null +++ b/it/IT_DISPL.ASM @@ -0,0 +1,4485 @@ +;Ŀ +; Display Module!! +; + + Jumps + .386 + +include switch.inc + +;Ŀ +; Externals +; + +Segment Pattern WORD Public 'Code' USE16 + Extrn Order:Word +EndS + +Segment Object1 BYTE Public 'Data' USE16 +EndS + +Segment Glbl BYTE Public 'Code' USE16 + Extrn CurrentMode:Byte +EndS + +IF SPECTRUMANALYSER + Extrn Fourier_Start:Far +ENDIF + Extrn S_GetDestination:Far + Extrn S_DrawBox:Far + Extrn S_DrawString:Far + Extrn Music_GetOutputWaveform:Far + Extrn Music_GetInstrumentMode:Far + Extrn Music_GetSongSegment:Far + Extrn Music_GetSampleLocation:Far + Extrn Music_GetHostChannelInformationTable:Far + Extrn Music_GetSlaveChannelInformationTable:Far + Extrn Music_NextOrder:Far + Extrn Music_LastOrder:Far + Extrn Music_GetPlayMode:Far + Extrn Music_GetPlayMode2:Far + Extrn Music_GetPattern:Far + Extrn Music_ToggleChannel:Far + Extrn Music_SoloChannel:Far + Extrn Music_GetDisplayVariables:Far + Extrn Music_InitStereo:Far +; Extrn Music_UpdateSampleLocation:Far + Extrn Music_Poll:Far + Extrn Music_ToggleReverse:Far + Extrn Music_GetLastChannel:far + Extrn Music_GetPatternLength:Far + + Extrn M_FunctionDivider:Far + +IF NETWORKENABLED + Extrn Network_Poll:Far +ENDIF + + Extrn O1_DisplayList, O1_FullDisplayList + + Extrn PE_GetCurrentPattern:Far + Extrn PE_ConvAX2Num:Far + + Extrn PE_GotoPattern:Far + + Extrn SetInfoLine:Far + +;Ŀ +; Globals +; + + Global DisplayPlus:Far + Global DisplayMinus:Far + Global DrawDisplayData:Far + Global PostDisplayData:Far + Global DisplayUpdateScreen:Far + Global Display_GetDisplayWindowData:Far + Global Display_SelectDisplayList:Far + +; + +Segment InfoPage BYTE Public 'Code' USE16 + Assume CS:InfoPage, DS:InfoPage + +;Ŀ +; Variables +; + +SLAVECHANNELSIZE EQU 128 +HOSTCHANNELSIZE EQU 80 + +PLAYMETHODS EQU 11 +DOTSDISPLAY EQU 9 + +CurrentChannel DW 0 +;CurrentSample DW 0 +;CurrentInstrument DW 0 +DisplayMode DW 0 + +DrawTrackData DW 0 ; Function to call to draw track + +DataArray DB 320 Dup (0) +DataDecode DB 384 Dup (0) +DecodeOffset DW ? ; Offset is -1 if no pat +DecodeSegment DW ? + +DecodePattern DW ? +DecodeRow DW ? +DecodeMaxRow DW ? + +PatternArrayNumber DW ? +PatternMaxRow DW ? +PatternSegment DW ? + +Channel5Msg DB " Channel xx ", 0 +Channel8Msg DB " xx ", 0 +Channel18Msg DB "xx", 0 +NoteTable DB "C-C#D-D#E-F-F#G-G#A-A#B-" +Note2Table DB "cCdDefFgGaAb" +LeftMsg DB "Left " +RightMsg DB " Right" +SurroundMsg DB "Surround " +NNAMsg DB "Cut", 0 + DB "Con", 0 + DB "Off", 0 + DB "Fde", 0 +VirtualMsg DB "NNA", 0FEh, 21h, 148, 0FEh, 12h, "Tot", 0 +DetailsMsg DB "Frequency", 0FEh, 21h, 148, 148, 0FEh, 12h + DB "Position", 0FEh, 21h, 148, 148, 0FEh, 12h + DB "Smp", 0FEh, 21h, 152, 153, 0FEh, 12h + DB "FVl", 0FEh, 21h, 148, 0FEh, 12h + DB "Vl", 0FEh, 21h, 148, 0FEh, 12h + DB "CV", 0FEh, 21h, 148, 0FEh, 12h + DB "SV", 0FEh, 21h, 148, 0FEh, 12h + DB "VE", 0FEh, 21h, 148, 0FEh, 12h + DB "Fde", 0FEh, 21h, 148, 0FEh, 12h + DB "Pn", 0FEh, 21h, 148, 0FEh, 12h + DB "PE", 0 + + +RestoreData DB 0 + +DisplayWindows Label ; Structure is 1 word + DW 0 ; 1 word, method + DB 0 ; 1 byte, top channel (+2) +; DB 1 +; DW 31 +; DW 160 + + DB 12 ; 1 byte, top line (+3) + DW 20 ; 1 word length of window (+4) + DW 12*80*2 ; 1 word offset to top left (+6) + + DW 8 + DB 0 + DB 32 + DW 3 + DW 32*80*2 + + DW 5 + DB 0 + DB 35 + DW 15 + DW 35*80*2 + + DW 11 Dup (0) + DB 0 +FullScreen DB 0 + +NumWindows DW 3 ; This cannot be moved!!! +CurrentWindow DW 0 +ProcessWindow DW 0 + +PlayMode DW 0 +CurrentRow DW 0 +CurrentPattern DW 0 +CurrentOrder DW 0 + +LastRow DW 0 +LastPattern DW 0 +LastOrder DW 0 + +WaveformLength DW 0 +Velocity DB 0 +Instrument DB 0 + +Comment ~ +Correlation Label Byte + DB 255, 254, 252, 249, 245, 240, 234, 227 + DB 219, 210, 210, 199, 187, 174, 160, 145 + + DB 129, 112, 94, 75, 55, 34, 12, 0 + DB 0, 0, 0, 0, 0, 0, 0, 0 +~ + +Destination DW 0 + +VariablesMsg DB "Active Channels: ", 0FDh, "D (", 0FDh, "D)", 13 + DB " Global Volume: ", 0FDh, "D", 0 + +StereoEnabledMsg DB "Stereo Enabled", 0 +StereoDisabledMsg DB "Stereo Disabled", 0 +VelocityMsg DB "Using velocity bars", 0 +VolumeMsg DB "Using volume bars", 0 +InstrumentMsg DB "Using Instrument names", 0 +SampleMsg DB "Using Sample names", 0 + +DisplayDataModes Label + DW Offset Display_HostChannel + DW Offset Display_5Channel + DW Offset Display_8Channel + DW Offset Display_10Channel + DW Offset Display_18Channel + DW Offset Display_24Channel + DW Offset Display_36Channel + DW Offset Display_64Channel + DW Offset Display_Variables + DW Offset Display_NoteDots +; DW Offset Display_SampleDots + DW Offset Display_Details + +DisplayListKeys Label + DB 0 ; Up arrow + DW 1C8h + DW Offset DisplayUp + + DB 0 + DW 1CBh ; Left arrow + DW Offset DisplayUp + + DB 0 + DW 1D0h ; Down arrow + DW Offset DisplayDown + + DB 0 + DW 1CDh ; Right arrow + DW Offset DisplayDown + + DB 2 + DW 1C8h + DW Offset DisplayAltUp + + DB 2 + DW 1D0h + DW Offset DisplayAltDown + + DB 0 + DW 1C7h + DW Offset DisplayHome + + DB 0 + DW 1CFh + DW Offset DisplayEnd + +; DB 0 +; DW 14Ah ; Grey minus + DB 1 + DW '-' + DW Offset DisplayMinus + +; DB 0 +; DW 14Eh ; Grey Plus + DB 1 + DW '+' + DW Offset DisplayPlus + + DB 0 + DW 1D2h ; Insert + DW Offset DisplayInsert + + DB 0 + DW 1D3h ; Delete + DW Offset DisplayDelete + + DB 0 ; PgUp + DW 1C9h + DW Offset DisplayPageUp + + DB 0 ; PgDn + DW 1D1h + DW Offset DisplayPageDown + + DB 0 ; Tab + DW 10Fh + DW Offset DisplayNext + + DB 1 ; Shifttab + DW 0F00h + DW Offset DisplayPrevious + + DB 2 ; Alt + DW 143h ; F9 + DW Offset DisplayToggleChannel + + DB 5 + DW 'Q' + DW Offset DisplayToggleChannel + + DB 2 ; Alt + DW 144h ; F10 + DW Offset DisplaySoloChannel + + DB 1 ; Alt 'R' + DW 1300h + DW Offset DisplayToggleReverse + + DB 1 ; Alt... + DW 1F00h ; 'S' + DW Offset DisplayToggleStereo + + DB 5 + DW 'S' + DW Offset DisplaySoloChannel + + DB 5 + DW 'G' + DW Offset Display_GotoPattern + + DB 5 + DW 'V' + DW Offset DisplayToggleVelocity + + DB 5 + DW 'I' + DW Offset DisplayToggleInstrument + + DB 1 + DW ' ' + DW Offset Display_SpaceBar + + DB 1 + DW 6 ; Ctrl F + DW Offset Display_FullScreen + +IF SPECTRUMANALYSER + DB 2 ; Alt.. + DW 158h ; F12 + DW Offset Display_FourierStart +ENDIF + + DB 0FFh ; End of list + +;Ŀ +; Functions +; + +Proc GetChannelColour ; Gets AH + + Push DS + Push BX + Call Music_GetSongSegment + Mov DS, AX + And BX, 0FFh + Test Byte Ptr [DS:BX+40h], 80h + Pop BX + Pop DS + JNZ GetChannelColour1 + + ; Non-muted colours. + Mov AH, 13h + Cmp BL, DL + JE GetChannelColourEnd + + Mov AH, 12h + + Mov BH, Byte Ptr ProcessWindow + Cmp BH, Byte Ptr CurrentWindow + JE GetChannelColourEnd + + Mov AH, 10h + Ret + +GetChannelColour1: ; Muted colours + Mov AH, 16h + + Cmp BL, DL + JE GetChannelColourEnd + + Mov AH, 11h + +GetChannelColourEnd: + Ret + +EndP GetChannelColour + +; + +Proc DrawChannelNumbers + + Mov CH, 0Ah + Mov CL, [CS:BP+4] + Sub CL, 2 + Mov DI, [CS:BP+6] + Add DI, (2+1*80)*2 + + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + +Display_HostChannel3: + Push CX + Push DI + + Mov AX, BX + Inc AX + Div CH + + Add AX, 3030h + + Mov DH, AH + + Mov AH, 23h + Cmp DL, BL + JE Display_HostChannel4 + + Test Byte Ptr [BX+40h], 80h + JNZ Display_HostChannel21 + + Mov AH, 21h + Mov CX, ProcessWindow + Cmp CX, CurrentWindow + JE Display_HostChannel4 + + Mov AH, 20h + Jmp Display_HostChannel32 + +Display_HostChannel4: + Test Byte Ptr [BX+40h], 80h + JZ Display_HostChannel32 + + Mov AH, 26h + +Display_HostChannel32: + StosW + Mov AL, DH + StosW + +Display_HostChannel21: + Inc BX + + Pop DI + Pop CX + Add DI, 160 + + Dec CL + JNZ Display_HostChannel3 + + Ret + +EndP DrawChannelNumbers + +; + +Proc DrawHexAL + + Cmp AL, 10 + SBB AL, 69h + DAS + + StosW + Ret + +EndP DrawHexAL + +; + +Proc Display_HostChannel + ; Draw boxes first. + Assume DS:InfoPage + + Mov ES, Destination + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Push AX + Push 29 + Add AX, [CS:BP+4] + Dec AX + Push AX + Push 27 + Call S_DrawBox + + Mov SI, SP + Mov Byte Ptr [SS:SI+4], 62 + Mov Byte Ptr [SS:SI+8], 30 + Call S_DrawBox + + Push DS + Call Music_GetSongSegment + Mov DS, AX + Test Byte Ptr [DS:2Ch], 1 + Pop DS + JZ Display_HostChannel27 + + Mov Byte Ptr [SS:SI+4], 73 + Mov Byte Ptr [SS:SI+8], 63 + Call S_DrawBox + +Display_HostChannel27: + Add SP, 10 + + Mov DX, CurrentChannel + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_HostChannel1 + + Mov BX, DX + +Display_HostChannel1: + LEA CX, [EDX+3] + Sub CX, [CS:BP+4] + Cmp BX, CX + JGE Display_HostChannel2 + + Mov BX, CX + +Display_HostChannel2: + Mov CX, 66 + Sub CX, [CS:BP+4] + Cmp BX, CX + JLE Display_HostChannel22 + + Mov BX, 65 + Sub BX, [CS:BP+4] + +Display_HostChannel22: + Mov [CS:BP+2], BL ; BL = top channel + + Call DrawChannelNumbers + + Mov AL, 80 ; HostChannelSize + Mul Byte Ptr [CS:BP+2] + Call Music_GetHostChannelInformationTable + Assume DS:Nothing + Add SI, AX + Mov DI, [CS:BP+6] + Add DI, (31+1*80)*2 + Mov CX, [CS:BP+4] + Sub CX, 2 + +Display_HostChannel5: ; Show vol and sample. + Push CX + Push DI + + Test Byte Ptr [SI], 4 + JZ Display_HostChannel6 + + Mov BX, [SI+24h] ; DS:BX = slave channel + + ; OK get sample number +; Mov AL, [SI+20h] + + Push DI + + Push SI + Push DS + + Push DI + + MovZX AX, Byte Ptr [BX+36h] + Inc AX + Mov DH, 10 + Div DH + Add AX, 3030h ; '0'+'0' + Cmp AL, '9' + JBE SampleNumRange1 + + Mov AX, '--' + +SampleNumRange1: + Mov DL, AH + Mov AH, 6 + StosW + Mov AL, DL + StosW + + Call Music_GetInstrumentMode + JZ Display_HostChannel23 + + MovZX AX, Byte Ptr [BX+33h] ; Instrument number + Cmp AL, 0FFh + JE Display_HostChannel23 + + Div DH + Add AX, 3030h + Mov DX, AX + + Mov AX, 6*256+'/' + StosW + + Mov AL, DL + StosW + Mov AL, DH + StosW + +Display_HostChannel23: + Mov AX, 7*256+':' + Test Byte Ptr [BX], 4 ; Note off??? + JNZ Display_HostChannel31 + + Mov AH, 6 + +Display_HostChannel31: + Cmp Byte Ptr [BX+20h], 0 + JNE Display_HostChannel7 + + Mov AH, 4 + +Display_HostChannel7: + StosW + MovZX AX, Byte Ptr [BX+36h] + Add AX, AX + Mov SI, AX + Mov DX, [BX+30h] + + Call Music_GetSongSegment + Mov DS, AX + + Mov SI, [DS:SI+64912] + Add SI, 14h + + Mov AH, 6 + Mov CX, 25 + + Test Byte Ptr [DS:2Ch], 4 ; Instrument mode? + JZ Display_HostChannel8 + Cmp CS:Instrument, 0 + JE Display_HostChannel8 + + LEA SI, [EDX+20h] + +Display_HostChannel8: + LodsB + Cmp AL, 226 + JB AvoidMouse1 + + Mov AL, ' ' + +AvoidMouse1: + StosW + Loop Display_HostChannel8 + + ; Show string... + ; Now show panning if applic + Pop DI + + Test Byte Ptr [DS:2Ch], 1 ; Stereo + JZ Display_HostChannel24 + + Pop DS + Pop SI + + Push SI + Push DS + + Add DI, 33*2 + ; Show panning. + MovZX AX, Byte Ptr [BX+25h] +; Mov AL, [DS:SI+2Eh] + Cmp AL, 100 + JE Display_HostChannel25 +; Test AL, 80h ; Should never occur +; JNZ Display_HostChannel24 + + And AL, AL + JZ Display_HostChannel29 + Cmp AL, 64 + JE Display_HostChannel30 + + ; Show thumb bar sorta thing. + Inc AX + Mov DX, AX + ShR DX, 3 + Add DX, DX + Add DI, DX + And AX, 7 + Add AX, 155 + Mov AH, 2 + StosW + + Cmp AL, 157 + JBE Display_HostChannel24 + Add AL, 5 + StosW + + Jmp Display_HostChannel24 + +Display_HostChannel29: + Mov SI, Offset LeftMsg + Jmp Display_HostChannel28 + +Display_HostChannel30: + Mov SI, Offset RightMsg + Jmp Display_HostChannel28 + +Display_HostChannel25: + Mov SI, Offset SurroundMsg + +Display_HostChannel28: + Push CS + Pop DS + Mov CX, 9 + Mov AH, 2 + +Display_HostChannel26: + LodsB + StosW + Loop Display_HostChannel26 + +Display_HostChannel24: + Pop DS + Push DS + + Mov AL, 255 + Cmp CS:Velocity, 0 + JNZ Display_HostChannel10 + Cmp Byte Ptr [BX+36h], 100 + JE Display_HostChannel10 + +; Test Byte Ptr [BX+1], 8 +; JNZ Display_HostChannel18 ; Don't display volume + + Mov EDX, [BX+2Ch] ; Initial offset. + Mov ECX, [BX+4Ch] ; Final offset + + And EDX, EDX + JNS Display_HostChannelPP1 + + Xor EDX, EDX + +Display_HostChannelPP1: + And ECX, ECX + JNS Display_HostChannelPP2 + + Xor ECX, ECX + +Display_HostChannelPP2: + Cmp Byte Ptr [BX+0Ah], 8 + JB Display_HostChannel9 ; No loop + +Comment ~ + Mov AL, [BX+0Bh] + And AL, 7Fh + Cmp AL, 2 + JB NoSampleLoop + + Mov ECX, [BX+40h] + Mov EDX, [BX+44h] + Jmp Display_HostChannel20 + +NoSampleLoop: + Cmp Byte Ptr [BX+0Ah], 8 +~ + JE Display_HostChannel19 ; Normal loop + + ; Ping pong! + Cmp ECX, EDX + JA Display_HostChannel9 + XChg ECX, EDX + Jmp Display_HostChannel9 + +Display_HostChannel19: ; Forwards loop! + Cmp ECX, EDX + JAE Display_HostChannel9 + Mov ECX, [BX+44h] + +Display_HostChannel9: + Sub ECX, EDX + JBE Display_HostChannel18 + +Display_HostChannel20: + Test Byte Ptr [BX+18h], 2 + PushF + JZ Display_HCNoDouble + + Add ECX, ECX + Add EDX, EDX + +Display_HCNoDouble: + MovZX AX, Byte Ptr [BX+36h] + Inc AX + + Push ECX + Xor CX, CX + Call Music_GetSampleLocation + Pop ECX + Add ESI, EDX + + PopF + Push BX + Mov BX, 1 + JZ Display_HostChannel8Bit + + Xor DX, DX + ShR ECX, 1 + JZ Display_HostChannelError + Or ESI, 1 + Inc BX + +Display_HostChannel8Bit: + Int 3 + + Mov DL, [SI] + Mov DH, DL ; DL = min, DH = max. + +Display_HostChannel11: + Mov AL, [SI] + Add SI, BX + JC Display_HostChannelNewSegment + +Display_HostChannelResume: + Cmp DH, AL + JL Display_HostChannel12 + + Cmp DL, AL + JG Display_HostChannel13 + +Display_HostChannel14: + Loop Display_HostChannel11 + + Pop BX + + Mov AL, DH + Sub AL, DL + Jmp Display_HostChannel10 + +Display_HostChannel13: + Mov DL, AL + Jmp Display_HostChannel14 + +Display_HostChannel12: + Mov DH, AL + Jmp Display_HostChannel14 + +Display_HostChannelNewSegment: + Add ESI, 10000h + Int 3 + Jmp Display_HostChannelResume + +Display_HostChannelError: + Pop BX + +Display_HostChannel18: ; AL = volume. + Mov AL, 0 + +Display_HostChannel10: ; AL = volume. + Pop DS + Pop SI + + Mul Byte Ptr [BX+20h] ; Final volume! + ShR AH, 1 + AdC AH, 0 ; AH = volume to show. + + Pop DI + Sub DI, 26*2 ; ES:DI points to vol deposit + Mov DH, AH + And DH, 7 + ShR AH, 3 + Mov CL, AH + + Mov AH, 5 + + Test Word Ptr [BX], 800h + JZ Display_HostChannelNotMuted + + Mov AH, 1 + +Display_HostChannelNotMuted: + And CL, CL + JZ Display_HostChannel16 + +Display_HostChannel15: + Mov AL, 176 + StosW + Mov AL, 179 + StosW + Mov AL, 182 + StosW + + Dec CL + JNZ Display_HostChannel15 + +Display_HostChannel16: ; DH contains remainder. + And DH, DH + JZ Display_HostChannel6 + + Cmp DH, 3 + JBE Display_HostChannel17 + + Mov AL, 176 + StosW + + Cmp DH, 5 + JBE Display_HostChannel17 + + Mov AL, 179 + Inc DH + StosW + +Display_HostChannel17: + Mov AL, 173 + Add AL, DH + StosW + +Display_HostChannel6: + Pop DI + Pop CX + Add DI, 160 + Add SI, HOSTCHANNELSIZE + Loop Display_HostChannel5 + + Ret + +EndP Display_HostChannel + Assume DS:Nothing + +; + +Proc Draw10Num + + Mov CX, 10 + Mov EBP, 10 + +Draw10Num1: + Xor EDX, EDX + Div EBP + + Add DX, '0'+2*256 + Sub DI, 2 + Mov [ES:DI], DX + + And EAX, EAX + + LoopNZ Draw10Num1 + + Add CX, CX + Sub DI, CX + + Ret + +EndP Draw10Num + +; + +Proc Draw2Num + + Xor AH, AH + Mov DL, 10 + Div DL + Add AX, 3030h + Mov DL, AH + Mov AH, 2 + StosW + Mov AL, DL + StosW + + ScasW +; Add DI, 2 + + Ret + +EndP Draw2Num + +; + +Proc Draw3Num + + Cmp AH, 10 + JB Draw3Num1 + + Xor AX, AX + +Draw3Num1: + Mov DL, 10 + Div DL + Mov DH, AH + Xor AH, AH + Div DL + Add AX, 3030h + Mov DL, AH + Mov AH, 2 + StosW + Mov AL, DL + StosW + Mov AL, DH + Add AL, 30h + StosW + + ScasW +; Add DI, 2 + + Ret + +EndP Draw3Num + +; + +Proc Display_Details + ; Draw boxes first. + Assume DS:InfoPage + + Mov ES, Destination + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Inc AX + Push AX + Push 30 + Add AX, [CS:BP+4] + Sub AX, 2 + Push AX + Push 27 + Call S_DrawBox + + Mov SI, SP + Mov Byte Ptr [SS:SI+4], 57 + Mov Byte Ptr [SS:SI+8], 31 + Call S_DrawBox + + Push DS + Call Music_GetSongSegment + Mov DS, AX + Test Byte Ptr [DS:2Ch], 4 + Pop DS + JZ Display_Details27 + + Mov Byte Ptr [SS:SI+4], 66 + Mov Byte Ptr [SS:SI+8], 58 + Call S_DrawBox + + Mov DI, [CS:BP+6] + Add DI, 118+160 + Mov SI, Offset VirtualMsg + Mov AH, 12h + Call S_DrawString + +Display_Details27: + Mov DI, [CS:BP+6] + Add DI, 12+160 + Mov SI, Offset DetailsMsg + Mov AH, 12h + Call S_DrawString + + Add SP, 10 + + Mov DX, CurrentChannel + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_Details1 + + Mov BX, DX + +Display_Details1: + LEA CX, [EDX+4] + Sub CX, [CS:BP+4] + Cmp BX, CX + JGE Display_Details2 + + Mov BX, CX + +Display_Details2: + Mov CX, 67 + Sub CX, [CS:BP+4] + Cmp BX, CX + JL Display_Details22 + + Mov BX, 67 + Sub BX, [CS:BP+4] + +Display_Details22: + Mov [CS:BP+2], BL ; BL = top channel + + Mov CH, 0Ah + Mov CL, [CS:BP+4] + Sub CL, 3 + Mov DI, [CS:BP+6] + Add DI, (2+2*80)*2 + + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + +Display_Details3: + Push CX + Push DI + + Mov AX, BX + Inc AX + Div CH + + Add AX, '00' + + Mov DH, AH + + Mov AH, 23h + Cmp DL, BL + JE Display_Details4 + + Test Byte Ptr [BX+40h], 80h + JNZ Display_Details21 + + Mov AH, 21h + Mov CX, ProcessWindow + Cmp CX, CurrentWindow + JE Display_Details4 + + Mov AH, 20h + Jmp Display_Details32 + +Display_Details4: + Test Byte Ptr [BX+40h], 80h + JZ Display_Details32 + + Mov AH, 26h + +Display_Details32: + StosW + Mov AL, DH + StosW + +Display_Details21: + Inc BX + + Pop DI + Pop CX + Add DI, 160 + + Dec CL + JNZ Display_Details3 + + Mov AL, 80 ; HostChannelSize + Mul Byte Ptr [CS:BP+2] + Call Music_GetHostChannelInformationTable + Assume DS:Nothing + Add SI, AX + Mov DI, [CS:BP+6] + Add DI, (15+2*80)*2 + Mov CX, [CS:BP+4] + Sub CX, 3 + +Display_Details5: ; Show vol and sample. + Push CX + Push SI + Push DI + + ; Draw in divisions. + Mov AX, 2A8h + Mov Word Ptr [ES:DI], AX + Mov Word Ptr [ES:DI+22], AX + Mov Word Ptr [ES:DI+40], AX + Mov Word Ptr [ES:DI+46], AX + Mov Word Ptr [ES:DI+52], AX + Mov Word Ptr [ES:DI+58], AX + Mov Word Ptr [ES:DI+64], AX + Mov Word Ptr [ES:DI+72], AX + Mov Word Ptr [ES:DI+78], AX + + ClI + + Test Byte Ptr [SI], 4 + JNZ Display_Details6 + + Add DI, 88 + + Jmp Display_Details72 + +Display_Details6: + Mov BX, [SI+24h] ; DS:BX points to virtual channel. + Mov EAX, [BX+10h] + Call Draw10Num + + Add DI, 42 + Mov EAX, [BX+4Ch] + Call Draw10Num + + Add DI, 22 + Xor AH, AH + Mov AL, [BX+36h] + Inc AX ; Sample.. + Call Draw3Num + +; Add DI, 2 + ScasW + Xor AH, AH + Mov AL, [BX+20h] ; Final vol + Call Draw3Num + + Mov AL, [BX+21h] ; Vol + Call Draw2Num + + Mov AL, [BX+23h] ; CV + Call Draw2Num + + Mov AL, [BX+24h] ; SV + ShR AL, 1 + Call Draw2Num + + Mov AL, [BX+52h] ; VE + Call Draw2Num + + Mov AX, [BX+26h] ; Fade + ShR AX, 1 + Call Draw3Num + + Mov AL, [BX+25h] ; Pan + Cmp AL, 100 + JE Display_Details13 + + Call Draw2Num + + Jmp Display_Details7 + +Display_Details13: + Mov AX, 'S'+2*256 + StosW + Mov AL, 'u' + StosW +; Add DI, 2 + ScasW + +Display_Details7: + Mov AL, [BX+62h] ; PE + Add AL, 32 + Call Draw2Num + +; Add DI, 2 + ScasW + +Display_Details72: + Push DS + Call Music_GetSongSegment + Mov DS, AX + Test Byte Ptr [DS:2Ch], 4 + Pop DS + JZ Display_Details8 + + Mov Word Ptr [ES:DI+6], 2A8h + + Test Byte Ptr [SI], 4 + JNZ Display_Details9 + + Mov AX, '-'+2*256 + StosW + StosW + StosW + + Jmp Display_Details10 + +Display_Details9: + Push SI + + Mov SI, [BX+3Bh] ; NNA + And SI, 0FFh + ShL SI, 2 + Mov AH, 2 + Mov AL, [CS:NNAMsg+SI] + StosW + Mov AL, [CS:NNAMsg+SI+1] + StosW + Mov AL, [CS:NNAMsg+SI+2] + StosW + + Pop SI + +Display_Details10: ; Time to count channels. + Mov AH, [SI+20h] + +; Add DI, 2 + ScasW + Call Music_GetSlaveChannelInformationTable + + Xor AL, AL ; AL = count. + +Display_Details11: + Mov DL, [SI+3Ah] + And DL, 7Fh + Cmp AH, DL + JNE Display_Details12 + + Test Byte Ptr [SI], 1 + JZ Display_Details12 + + Inc AX + +Display_Details12: + Add SI, SLAVECHANNELSIZE + Loop Display_Details11 + + Xor AH, AH + Call Draw3Num + +Display_Details8: + StI + + Pop DI + Pop SI + Pop CX + Add DI, 160 + Add SI, HOSTCHANNELSIZE + Loop Display_Details5 + + Ret + +EndP Display_Details + Assume DS:Nothing + +; + +Proc LoadNextData ; Returns DS:SI to data. (unpacked) + Assume DS:InfoPage + + Mov BX, DecodePattern + Cmp BX, PatternArrayNumber + JE LoadNextData1 + + Push DI + + Push CS + Pop ES + Mov DI, Offset DataArray + Mov CX, 64 + +LoadNextData3: + Mov AX, 0FDh + StosW + Mov AL, 0FFh + StosB + Xor AL, AL + StosW + Loop LoadNextData3 + + Cmp BX, 0FFFFh + JNE LoadNextData2 + + Pop DI + Mov SI, Offset DataArray + Ret + +LoadNextData2: + ; OK... time to decode. + Mov SI, DecodeOffset + Mov DS, DecodeSegment + Assume DS:Nothing + +LoadNextData4: + LodsB + And AL, AL + JZ LoadNextData5 + + Mov DL, AL + And AL, 7Fh + Dec AX + Mov DH, AL + + Mov AH, 6 + Mul AH + Mov BX, AX + Add BX, Offset DataDecode + + Mov AL, 5 + Mul DH + Mov DI, AX + Add DI, Offset DataArray + + Mov AH, [CS:BX] + Test DL, 80h + JZ LoadNextData6 + + LodsB + Mov AH, AL + Mov [CS:BX], AL + +LoadNextData6: + Test AH, 1 + JZ LoadNextData7 + + LodsB + Mov [CS:BX+1], AL + Jmp LoadNextData8 + +LoadNextData7: + Test AH, 10h + JZ LoadNextData9 + + Mov AL, [CS:BX+1] + +LoadNextData8: + Mov [CS:DI], AL ; Note + +LoadNextData9: + Test AH, 2 + JZ LoadNextData10 + + LodsB + Mov [CS:BX+2], AL + Jmp LoadNextData11 + +LoadNextData10: + Test AH, 20h + JZ LoadNextData12 + + Mov AL, [CS:BX+2] + +LoadNextData11: + Mov [CS:DI+1], AL ; Instrument + +LoadNextData12: + Test AH, 4 + JZ LoadNextData13 + + LodsB + Mov [CS:BX+3], AL + Jmp LoadNextData14 + +LoadNextData13: + Test AH, 40h + JZ LoadNextData15 + + Mov AL, [CS:BX+3] + +LoadNextData14: + Mov [CS:DI+2], AL ; Volume + +LoadNextData15: + Test AH, 8 + JZ LoadNextData16 + + LodsW + Mov [CS:BX+4], AX + Mov [CS:DI+3], AX + Jmp LoadNextData4 + +LoadNextData16: + Test AH, 80h + JZ LoadNextData4 + + Mov AX, [CS:BX+4] + Mov [CS:DI+3], AX + Jmp LoadNextData4 + +LoadNextData5: + Push CS + Pop DS + Assume DS:InfoPage + + Mov DecodeOffset, SI + + Mov SI, Offset DataArray + + Pop DI + Ret + +LoadNextData1: + Mov SI, DecodeOffset + Add DecodeOffset, 320 + Mov DS, PatternSegment + Assume DS:Nothing + + Ret + +EndP LoadNextData + +; + +Proc GotoRow ; DS:SI points to data. + + Push CX + + + Mov CX, CS:DecodeRow + Inc CX + +GotoRow1: + Dec CX + JZ GotoRow2 + +GotoRow3: + LodsB + And AL, AL + JZ GotoRow1 + + Mov DL, AL + And AL, 7Fh + Dec AX + Mov AH, 6 + Mul AH + Mov BX, AX + Add BX, Offset DataDecode + + Mov DH, [CS:BX] ; Mask. + Test DL, 80h + JZ GotoRow4 + + LodsB + Mov DH, AL + Mov [CS:BX], AL ; Mask + +GotoRow4: + Test DH, 1 + JZ GotoRow5 + + LodsB + Mov [CS:BX+1], AL ; Note + +GotoRow5: + Test DH, 2 + JZ GotoRow6 + + LodsB + Mov [CS:BX+2], AL ; Instrument + +GotoRow6: + Test DH, 4 + JZ GotoRow7 ; Volume + + LodsB + Mov [CS:BX+3], AL + +GotoRow7: + Test DH, 8 + JZ GotoRow3 + + LodsW + Mov [CS:BX+4], AX + Jmp GotoRow3 + +GotoRow2: + Mov CS:DecodeSegment, DS + Mov CS:DecodeOffset, SI + + Pop CX + Ret + +EndP GotoRow + +; + +Proc GetBeforeRows ; Returns + ; CX = number of rows to show. + ; the row numbers are handled. + ; Initialises DataSegment, + ; DataOffset and Array. + Assume DS:InfoPage + + Xor CX, CX + Mov BX, CurrentRow + Mov AX, [CS:BP+4] + Sub AX, 4 + ShR AX, 1 + Sub BX, AX + JC GetBeforeRows2 + + Ret ; No rows to show! + +GetBeforeRows2: + Mov CX, BX + Neg CX ; CX = num of rows to show + + Cmp PlayMode, 1 + JE GetBeforeRows1 + ; Song.. + Mov BX, CurrentOrder + Test BX, BX + JZ GetBeforeRows3 + + Call Music_GetSongSegment + Mov ES, AX + MovZX AX, Byte Ptr [ES:BX+100h-1] + Cmp AL, 199 + JBE GetBeforeRows4 + +GetBeforeRows3: + Mov DecodePattern, 0FFFFh + Ret + +GetBeforeRows1: ; Pattern... + Mov AX, CurrentPattern + +GetBeforeRows4: + Mov DecodePattern, AX ; Now find offset. + Cmp AX, PatternArrayNumber ; CX = num rows to show + JNE GetBeforeRows5 + + Mov BX, PatternMaxRow + Sub BX, CX + Mov DecodeRow, BX + Mov AX, 320 + Mul BX + Mov DecodeOffset, AX + Jmp GetBeforeRows6 + +GetBeforeRows5: + Call Music_GetPattern + Assume DS:Nothing + LodsW + LodsW + ; AX = rows. + Sub AX, CX + Mov CS:DecodeRow, AX + Add SI, 4 + Call GotoRow + +GetBeforeRows6: ; Put numbers on screen. + Push CS + Pop DS + + JCXZ GetBeforeRows9 + + Push CX + Push DI + +GetBeforeRows7: + Mov AX, DecodeRow + Mov ES, Destination + +GetBeforeRows8: + Push CX + + Mov CH, 20h + Call PE_ConvAX2Num + + Pop CX + Inc AX + Add DI, 160 + Loop GetBeforeRows8 + + Pop DI + Pop CX + +GetBeforeRows9: + Ret + +EndP GetBeforeRows + +; + +Proc GetAfterRows ; Returns + Assume DS:InfoPage + + Xor CX, CX + Mov BX, DecodeMaxRow + Mov AX, [CS:BP+4] + Sub AX, 3 + Mov DX, AX + Dec AX + ShR AX, 1 + Sub DX, AX + Add DX, CurrentRow + + Sub BX, DX + JC GetAfterRows2 + + Ret ; No rows to show! + +GetAfterRows2: + Mov CX, BX + Neg CX + + Cmp PlayMode, 1 + JE GetAfterRows1 + + ; Song.. + Mov BX, CurrentOrder + Cmp BX, 255 + JAE GetAfterRows3 + + Call Music_GetSongSegment + Mov ES, AX + MovZX AX, Byte Ptr [ES:BX+101h] + Cmp AL, 199 + JBE GetAfterRows4 + +GetAfterRows3: + Mov DecodePattern, 0FFFFh + Ret + +GetAfterRows1: ; Pattern... + Mov AX, CurrentPattern + +GetAfterRows4: + Mov DecodePattern, AX ; Now find offset. + Mov DecodeRow, 0 + + Cmp AX, PatternArrayNumber ; CX = num rows to show + JNE GetAfterRows5 + + Mov DecodeOffset, 0 + Jmp GetAfterRows6 + +GetAfterRows5: + Call Music_GetPattern + Assume DS:Nothing + Add SI, 8 + Mov CS:DecodeSegment, DS + + Push CS + Pop DS + Assume DS:InfoPage + + Mov DecodeOffset, SI + +GetAfterRows6: ; Put numbers on screen. + JCXZ GetAfterRows9 + + Push CX + Push DI + +GetAfterRows7: + Mov AX, DecodeRow + Mov ES, Destination + +GetAfterRows8: + Push CX + + Mov CH, 20h + Call PE_ConvAX2Num + + Pop CX + Inc AX + Add DI, 160 + Loop GetAfterRows8 + + Pop DI + Pop CX + +GetAfterRows9: + Ret + +EndP GetAfterRows + +; + +Proc GetCurrentPatternRows ; Returns CX = number of rows to show. + Assume DS:InfoPage + + Mov BX, CurrentRow + Mov AX, [CS:BP+4] + Sub AX, 3 + + Mov CX, AX + Dec AX + ShR AX, 1 + Sub CX, AX + + Add CX, BX ; CX = final row. + Sub BX, AX + JNC GetCurrentPatternRows2 + + Xor BX, BX + ; BX = starting row. + +GetCurrentPatternRows2: + Mov AX, CurrentPattern + + Mov DecodeRow, BX + Mov DecodePattern, AX ; Now find offset. + Cmp AX, PatternArrayNumber ; BX = starting row, CX = final row. + JNE GetCurrentPatternRows5 + + Mov AX, PatternMaxRow + Mov DecodeMaxRow, AX + Cmp CX, AX + JBE GetCurrentPatternRows1 + + Mov CX, AX + +GetCurrentPatternRows1: + Mov AX, 320 + Mul BX + Mov DecodeOffset, AX + Sub CX, BX ; CX = number of rows. + Jmp GetCurrentPatternRows6 + +GetCurrentPatternRows5: + Call Music_GetPattern + Assume DS:Nothing + LodsW + LodsW + ; AX = number of rows. + Mov DecodeMaxRow, AX + + Cmp CX, AX + JBE GetCurrentPatternRows3 + + Mov CX, AX + +GetCurrentPatternRows3: + Sub CX, BX + Add SI, 4 + Call GotoRow + +GetCurrentPatternRows6: ; Put numbers on screen. + Push CS + Pop DS + + Push CX + Push DI + +GetCurrentPatternRows7: + Mov AX, DecodeRow + Mov ES, Destination + +GetCurrentPatternRows8: + Push CX + + Mov CH, 20h + Call PE_ConvAX2Num + + Pop CX + Inc AX + Add DI, 160 + Loop GetCurrentPatternRows8 + + Pop DI + Pop CX + Ret + +EndP GetCurrentPatternRows + +; + +Proc DrawHilightBar + + Mov DI, [CS:BP+6] + Mov AX, [CS:BP+4] + ShR AX, 1 + Mov AH, 160 + Mul AH + Add DI, AX + Add DI, 11 + +DrawHilightBar1: + Or Byte Ptr [ES:DI], 0E0h +; Add DI, 2 + ScasW + Dec CX + JNZ DrawHilightBar1 + + Ret + +EndP DrawHilightBar + +; + +Proc DisplayTrackData + + Cmp PlayMode, 0 + JNE DisplayTrackData1 + + Pop AX ; Pull off return address + Ret + +DisplayTrackData1: + ; Check if row is OK. + + ; Now check for early block + + Mov DI, [CS:BP+6] + Add DI, (1+2*80)*2 + + Call GetBeforeRows + JCXZ DisplayTrackData3 + +DisplayTrackData2: + Push CX + Push DI + Push DS + + Call LoadNextData ; Gets DS:SI + Call [CS:DrawTrackData] + + Pop DS + Pop DI + Pop CX + Add DI, 160 + Dec CX + JNZ DisplayTrackData2 + +DisplayTrackData3: + Call GetCurrentPatternRows + +DisplayTrackData4: + Push CX + Push DI + Push DS + + Call LoadNextData ; Gets DS:SI + Call [CS:DrawTrackData] + + Pop DS + Pop DI + Pop CX + Add DI, 160 + Dec CX + JNZ DisplayTrackData4 + + Call GetAfterRows + JCXZ DisplayTrackData6 + +DisplayTrackData5: + Push CX + Push DI + Push DS + + Call LoadNextData ; Gets DS:SI + Call [CS:DrawTrackData] + + Pop DS + Pop DI + Pop CX + Add DI, 160 + Dec CX + JNZ DisplayTrackData5 + +DisplayTrackData6: + Ret + +EndP DisplayTrackData + +; + +Proc Show5Channel + + Mov AL, [CS:BP+2] + Mov AH, 5 + Mul AH + Add SI, AX ; DS:SI points to stuff. + + Mov CX, 0A05h + Mov ES, Destination + Add DI, 8 + +Show5Channel1: + LodsB + Cmp AL, 119 + JBE Show5Channel2 + + Mov AH, AL + Mov AL, 205 + + Cmp AH, 0FFh + JE Show5Channel3 + + Mov AL, '^' + Cmp AH, 0FEh + JE Show5Channel3 + + Mov AL, 173 ; '.' + +Show5Channel3: + Mov AH, 6 + StosW + StosW + StosW + Jmp Show5Channel4 + +Show5Channel2: ; Show note. + AAM 12 + ; AL = octave + ; AH = note. + Mov DX, AX + MovZX BX, AL + Add BX, BX + Mov AH, 6 + Mov AL, [CS:BX+NoteTable] + StosW + Mov AL, [CS:BX+NoteTable+1] + StosW + Mov AL, DH + Add AL, 30h + StosW + +Show5Channel4: ; Show ins. +; Add DI, 2 + ScasW + LodsB + + Test AL, AL + JZ Show5Channel5 + + Xor AH, AH + Div CH + Add AX, 3030h + Mov DL, AH + Mov AH, 6 + StosW + Mov AL, DL + StosW + + Jmp Show5Channel6 + +Show5Channel5: + Mov AL, 173 + StosW + StosW + +Show5Channel6: ; show vol +; Add DI, 2 + ScasW + LodsB + Cmp AL, 0FFh + JE Show5Channel7 + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC Show5ChannelNoVEffect + + Test AL, 80h + JZ Show5ChannelVEffect + + Add AH, 60 + +Show5ChannelVEffect: + Mov AL, AH + Xor AH, AH + Div CH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov DL, AH + Mov AH, 6 + StosW + Mov AL, DL + StosW + + Jmp Show5Channel8 + +Show5ChannelNoVEffect: + Mov DL, 6 + Test AL, 80h + JZ Show5Channel10 + + Mov DL, 2 + And AL, 7Fh + +Show5Channel10: + Xor AH, AH + Div CH + Add AX, 3030h + XChg DL, AH + StosW + Mov AL, DL + StosW + + Mov AH, 6 + Jmp Show5Channel8 + +Show5Channel7: + Mov AL, 173 + StosW + StosW + +Show5Channel8: +; Add DI, 2 + ScasW + LodsB + And AL, AL + JNZ Show5Channel9 + + Mov AL, '.'-'@' + +Show5Channel9: + Add AL, '@' + StosW ; Command + + LodsB ; Commandvalue. + Mov AH, AL + And AX, 0FF0h + Mov DL, AH + ShR AL, 4 + + Mov AH, 6 + Call DrawHexAL + + Mov AL, DL + Call DrawHexAL + + Dec CL + JZ Show5ChannelEnd + + Mov AX, 2A8h + StosW + + Jmp Show5Channel1 + +Show5ChannelEnd: + Ret + +EndP Show5Channel + +; + +Proc Display_5Channel + Assume DS:InfoPage + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Inc AX + Push AX + Push 74 + Add AX, [CS:BP+4] + Sub AL, 2 + Push AX + Push 27 + Call S_DrawBox + + Add SP, 10 + ; Fill in text. + ; check boundaries. + Mov DX, CurrentChannel + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_5Channel2 + + Mov BX, DX + +Display_5Channel2: + Mov CX, DX + Sub CX, 4 + Cmp BX, CX + JGE Display_5Channel3 + + Mov BX, CX + +Display_5Channel3: + Cmp BX, 59 + JB Display_5Channel11 + + Mov BX, 59 + +Display_5Channel11: + Mov [CS:BP+2], BL ; top channel. + ; Now do channel msgs. + + Mov CX, 0A05h + Mov DI, [CS:BP+6] + Add DI, (5+1*80)*2 + Mov SI, Offset Channel5Msg + +Display_5Channel4: + MovZX AX, BL + Inc AX + Div CH + Add AX, 3030h + Mov [SI+9], AX + + Call GetChannelColour + Call S_DrawString + + Add DI, 4 + + Inc BX + Dec CL + JNZ Display_5Channel4 + + Mov [CS:DrawTrackData], Offset Show5Channel + Call DisplayTrackData + Mov CX, 69 + Call DrawHilightBar + + Ret + +EndP Display_5Channel + Assume DS:Nothing + +; + +Proc Show8Channel + + Mov AL, [CS:BP+2] + Mov AH, 5 + Mul AH + Add SI, AX ; DS:SI points to stuff. + + Mov CX, 0A08h + Mov ES, Destination + Add DI, 8 + +Show8Channel1: + LodsW + Cmp AL, 119 + JBE Show8Channel2 + + Mov AH, AL + Mov AL, 205 + + Cmp AH, 0FFh + JE Show8Channel3 + + Mov AL, '^' + Cmp AH, 0FEh + JE Show8Channel3 + + Mov AL, 173 ; '.' + +Show8Channel3: + Mov AH, 6 + StosW + StosW + StosW + Jmp Show8Channel4 + +Show8Channel2: ; Show note. + AAM 12 + + Mov DX, AX + MovZX BX, AL + Add BX, BX + Mov AH, 6 + Mov AL, [CS:BX+NoteTable] + StosW + Mov AL, [CS:BX+NoteTable+1] + StosW + Mov AL, DH + Add AL, 30h + StosW + +Show8Channel4: ; Show vol. + LodsB + Cmp AL, 0FFh + JE Show8Channel5 + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC Show8ChannelNoVEffect + + Test AL, 80h + JZ Show8ChannelVEffect + + Add AH, 60 + +Show8ChannelVEffect: + Mov AL, AH + Xor AH, AH + Div CH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov DL, AH + Mov AH, 2 + StosW + Mov AL, DL + StosW + + Jmp Show8Channel6 + +Show8ChannelNoVEffect: + Mov DL, 2 + Test AL, 80h + JZ Show8Channel10 + + Dec DL + And AL, 7Fh + +Show8Channel10: + Xor AH, AH + Div CH + Add AX, 3030h + XChg DL, AH + StosW + Mov AL, DL + StosW + + Jmp Show8Channel6 + +Show8Channel5: + Add DI, 4 + +Show8Channel6: + LodsB + And AL, AL + JNZ Show8Channel9 + + Mov AL, '.'-'@' + +Show8Channel9: + Add AL, '@' + Mov AH, 6 + StosW ; Command + + LodsB ; Commandvalue. + Mov AH, AL + And AX, 0FF0h + Mov DL, AH + ShR AL, 4 + + Mov AH, 6 + Call DrawHexAL + + Mov AL, DL + Call DrawHexAL + + Dec CL + JZ Show8ChannelEnd + + Mov AX, 2A8h + StosW + + Jmp Show8Channel1 + +Show8ChannelEnd: + Ret + +EndP Show8Channel + +; + +Proc Display_8Channel + Assume DS:InfoPage + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Inc AX + Push AX + Push 76 + Add AX, [CS:BP+4] + Sub AL, 2 + Push AX + Push 27 + Call S_DrawBox + + Add SP, 10 + ; Fill in text. + ; check boundaries. + Mov DX, CurrentChannel + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_8Channel2 + + Mov BX, DX + +Display_8Channel2: + Mov CX, DX + Sub CX, 7 + Cmp BX, CX + JGE Display_8Channel3 + + Mov BX, CX + +Display_8Channel3: + Cmp BX, 56 + JB Display_8Channel11 + + Mov BX, 56 + +Display_8Channel11: + Mov [CS:BP+2], BL ; top channel. + ; Now do channel msgs. + + Mov CX, 0A08h + Mov DI, [CS:BP+6] + Add DI, (6+1*80)*2 + Mov SI, Offset Channel8Msg + +Display_8Channel4: + MovZX AX, BL + Inc AX + Div CH + Add AX, 3030h + Mov [SI+2], AX + + Call GetChannelColour + Call S_DrawString + + Add DI, 6 + + Inc BX + Dec CL + JNZ Display_8Channel4 + + Mov [CS:DrawTrackData], Offset Show8Channel + Call DisplayTrackData + Mov CX, 71 + Call DrawHilightBar + + Ret + +EndP Display_8Channel + Assume DS:Nothing + +; + +Proc Show10Channel + + Mov AL, [CS:BP+2] + Mov AH, 5 + Mul AH + Add SI, AX ; DS:SI points to stuff. + + Mov CX, 0A0Ah + Mov ES, Destination + Add DI, 8 + +Show10Channel1: + LodsB + Cmp AL, 119 + JBE Show10Channel2 + + Mov AH, AL + Mov AL, 205 + + Cmp AH, 0FFh + JE Show10Channel3 + + Mov AL, '^' + Cmp AH, 0FEh + JE Show10Channel3 + + Mov AL, 173 ; '.' + +Show10Channel3: + Mov AH, 6 + StosW + StosW + StosW + Jmp Show10Channel4 + +Show10Channel2: ; Show note. + AAM 12 + ; AL = octave + ; AH = note. + Mov DX, AX + MovZX BX, AL + Add BX, BX + Mov AH, 6 + Mov AL, [CS:BX+NoteTable] + StosW + Mov AL, [CS:BX+NoteTable+1] + StosW + Mov AL, DH + Add AL, 30h + StosW + +Show10Channel4: ; Show Instrument + LodsB ; AL = instrument + And AX, 0FFh + JZ Show10Channel5 ; No instrument? + Div CH + + ; AL = tens, AH = units + ShL AL, 4 + Or AL, AH + Mov AH, 0Ah + + StosW ; Instrument done. + Jmp Show10Channel6 + +Show10Channel5: + Mov AX, 184+200h + StosW + +Show10Channel6: ; Show volume + LodsB ; AL = volume + + Cmp AL, 0FFh + JE Show10Channel7 + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC ViewAllSmallNoVEffect + + Test AL, 80h + JZ ViewAllSmallVEffect1 + + Mov AL, AH + Add AL, 226 + Mov AH, 6 + StosW + Jmp Show10Channel8 + +ViewAllSmallVEffect1: + Mov AL, AH + AAM + Add AH, 0Ah + ShL AH, 4 + Or AL, AH + Mov AH, 12 + StosW +Comment ~ + Mov AL, AH + Mov AH, 0 + Div CH + ; AL = effect, AH = num + Add AL, 0Ah + ShL AL, 4 + Or AL, AH + Mov AH, 12 + StosW +~ + Jmp Show10Channel8 + +ViewAllSmallNoVEffect: +; Xor AH, AH + Mov DL, 12 ; Volume + Test AL, AL + JNS Show10Channel9 + + Mov DL, 9 + And AL, 7Fh + +Show10Channel9: +; Div CH + AAM + + ; AL = tens, AH = units + ShL AH, 4 + Or AL, AH + Mov AH, DL + + StosW + Jmp Show10Channel8 + +Show10Channel7: ; No volume + Mov AX, 184+600h + StosW + +Show10Channel8: ; Show volume + LodsB + Test AL, AL + JNZ Show10Channel10 + + Add AL, '.'-'@' + +Show10Channel10: + Add AL, '@' + Mov AH, 2 + StosW ; Command + + Mov AH, 0Ah + LodsB ; Commandvalue. + StosW + + Dec CL + JNZ Show10Channel1 + + Ret + +EndP Show10Channel + +; + +Proc Display_10Channel + Assume DS:InfoPage + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Inc AX + Push AX + Push 75 + Add AX, [CS:BP+4] + Sub AL, 2 + Push AX + Push 27 + Call S_DrawBox + + Add SP, 10 + ; Fill in text. + ; check boundaries. + Mov DX, CurrentChannel + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_10Channel2 + + Mov BX, DX + +Display_10Channel2: + Mov CX, DX + Sub CX, 9 + Cmp BX, CX + JGE Display_10Channel3 + + Mov BX, CX + +Display_10Channel3: + Cmp BX, 54 + JB Display_10Channel11 + + Mov BX, 54 + +Display_10Channel11: + Mov [CS:BP+2], BL ; top channel. + ; Now do channel msgs. + + Mov CX, 0A0Ah + Mov DI, [CS:BP+6] + Add DI, (5+1*80)*2 + Mov SI, Offset Channel8Msg + +Display_10Channel4: + MovZX AX, BL + Inc AX + Div CH + Add AX, 3030h + Mov [SI+2], AX + + Call GetChannelColour + Call S_DrawString + +; Add DI, 2 + ScasW + + Inc BX + Dec CL + JNZ Display_10Channel4 + + Mov [CS:DrawTrackData], Offset Show10Channel + Call DisplayTrackData + Mov CX, 70 + Call DrawHilightBar + + Ret + +EndP Display_10Channel + Assume DS:Nothing + +; + +Proc Process3CharacterRow + + Push SI + + LodsW + Cmp AX, 0FDh + JE Show18Channel4 + + Cmp AL, 0FDh + JE Show18Channel3 + JB Show18Channel2 + + Mov AH, AL + Mov AL, 205 + + Cmp AH, 0FFh + JE Show18Channel8 + + Mov AL, '^' + Cmp AH, 0FEh + JE Show18Channel8 + + Mov AL, 173 ; '.' + +Show18Channel8: + Mov AH, 6 + StosW + StosW + StosW + Jmp Show18Channel7 + +Show18Channel2: + AAM 12 + + Mov DX, AX + MovZX BX, AL + Add BX, BX + Mov AH, 6 + Mov AL, [CS:BX+NoteTable] + StosW + Mov AL, [CS:BX+NoteTable+1] + StosW + Mov AL, DH + Add AL, 30h + StosW + + Jmp Show18Channel7 + +Show18Channel3: + MovZX AX, AH + Div CH + Add AX, 3030h + Mov DL, AH + Mov AH, 6 +; Add DI, 2 + ScasW + StosW + Mov AL, DL + StosW + Jmp Show18Channel7 + +Show18Channel4: + LodsW + Cmp AX, 0FFh + JE Show18Channel6 + + Cmp AL, 0FFh + JE Show18Channel5 + +; Add DI, 2 + ScasW + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC Show18ChannelNoVEffect + + Test AL, 80h + JZ Show18ChannelVEffect + + Add AH, 60 + +Show18ChannelVEffect: + Mov AL, AH + Xor AH, AH + Div CH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov DL, AH + Mov AH, 2 + StosW + Mov AL, DL + StosW + + Jmp Show18Channel7 + +Show18ChannelNoVEffect: + Mov DL, 2 + Test AL, 80h + JZ Show18Channel9 + + Dec DX + And AL, 7Fh + +Show18Channel9: + Xor AH, AH ; Volume + Div CH + Add AX, 3030h + XChg DL, AH + StosW + Mov AL, DL + StosW + + Jmp Show18Channel7 + +Show18Channel5: + Mov AL, AH + Add AL, '@' + Mov AH, 2 + StosW + + LodsB ; Commandvalue. + Mov AH, AL + And AX, 0FF0h + Mov DL, AH + ShR AL, 4 + + Mov AH, 2 + Call DrawHexAL + + Mov AL, DL + Call DrawHexAL + Jmp Show18Channel7 + +Show18Channel6: + Mov AX, 173+256*6 + StosW + StosW + StosW + +Show18Channel7: + Pop SI + Add SI, 5 + + Ret + +EndP Process3CharacterRow + +; + +Proc Show18Channel + + Mov AL, [CS:BP+2] + Mov AH, 5 + Mul AH + Add SI, AX ; DS:SI points to stuff. + + Mov CX, 0A12h + Mov ES, Destination + Add DI, 8 + +Show18Channel1: + Call Process3CharacterRow + Dec CL + JZ Show18ChannelEnd + + Mov AX, 2A8h + StosW + + Jmp Show18Channel1 + +Show18ChannelEnd: + Ret + +EndP Show18Channel + +; + +Proc Display_18Channel + Assume DS:InfoPage + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Inc AX + Push AX + Push 76 + Add AX, [CS:BP+4] + Sub AL, 2 + Push AX + Push 27 + Call S_DrawBox + + Add SP, 10 + ; Fill in text. + ; check boundaries. + Mov DX, CurrentChannel + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_18Channel2 + + Mov BX, DX + +Display_18Channel2: + Mov CX, DX + Sub CX, 17 + Cmp BX, CX + JGE Display_18Channel3 + + Mov BX, CX + +Display_18Channel3: + Cmp BX, 46 + JB Display_18Channel11 + + Mov BX, 46 + +Display_18Channel11: + Mov [CS:BP+2], BL ; top channel. + ; Now do channel msgs. + + Mov CX, 0A12h + Mov DI, [CS:BP+6] + Add DI, (6+1*80)*2 + Mov SI, Offset Channel18Msg + +Display_18Channel4: + MovZX AX, BL + Inc AX + Div CH + Add AX, 3030h + Mov [SI], AX + + Call GetChannelColour + Call S_DrawString + + Add DI, 4 + + Inc BX + Dec CL + JNZ Display_18Channel4 + + Mov [CS:DrawTrackData], Offset Show18Channel + Call DisplayTrackData + Mov CX, 71 + Call DrawHilightBar + + Ret + +EndP Display_18Channel + Assume DS:Nothing + +; + +Proc Show24Channel + + Mov AL, [CS:BP+2] + Mov AH, 5 + Mul AH + Add SI, AX ; DS:SI points to stuff. + + Mov CX, 0A18h + Mov ES, Destination + Add DI, 8 + +Show24Channel1: + Call Process3CharacterRow + + Dec CL + JNZ Show24Channel1 + + Ret + +EndP Show24Channel + +; + +Proc Display_24Channel + Assume DS:InfoPage + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Inc AX + Push AX + Push 77 + Add AX, [CS:BP+4] + Sub AL, 2 + Push AX + Push 27 + Call S_DrawBox + + Add SP, 10 + ; Fill in text. + ; check boundaries. + Mov DX, CurrentChannel + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_24Channel2 + + Mov BX, DX + +Display_24Channel2: + Mov CX, DX + Sub CX, 23 + Cmp BX, CX + JGE Display_24Channel3 + + Mov BX, CX + +Display_24Channel3: + Cmp BX, 40 + JB Display_24Channel11 + + Mov BX, 40 + +Display_24Channel11: + Mov [CS:BP+2], BL ; top channel. + ; Now do channel msgs. + + Mov CX, 0A18h + Mov DI, [CS:BP+6] + Add DI, (6+1*80)*2 + Mov SI, Offset Channel18Msg + +Display_24Channel4: + MovZX AX, BL + Inc AX + Div CH + Add AX, 3030h + Mov [SI], AX + + Call GetChannelColour + Call S_DrawString + +; Add DI, 2 + ScasW + + Inc BX + Dec CL + JNZ Display_24Channel4 + + Mov [CS:DrawTrackData], Offset Show24Channel + Call DisplayTrackData + Mov CX, 72 + Call DrawHilightBar + + Ret + +EndP Display_24Channel + Assume DS:Nothing + +; + +Proc Show36Channel + + Mov AL, [CS:BP+2] + Mov AH, 5 + Mul AH + Add SI, AX ; DS:SI points to stuff. + + Mov CX, 0A24h + Mov ES, Destination + Add DI, 8 + +Show36Channel1: + LodsW + + Cmp AX, 0FDh + JE Show36Channel4 + + Add SI, 3 + + Cmp AL, 0FDh + JE Show36Channel3 + JB Show36Channel2 + + Mov AH, AL + Mov AL, 205 + + Cmp AH, 0FFh + JE Show36Channel8 + + Mov AL, '^' + Cmp AH, 0FEh + JE Show36Channel8 + + Mov AL, 173 ; '.' + +Show36Channel8: + Mov AH, 6 + StosW + StosW + Jmp Show36Channel7 + +Show36Channel2: + AAM 12 + Mov BX, Offset Note2Table + SegCS XLatB + Mov DL, AH + Mov AH, 6 + StosW + + Mov AL, DL + Add AL, 30h + StosW + + Jmp Show36Channel7 + +Show36Channel3: + MovZX AX, AH + Div CH + Add AX, 3030h + Mov DL, AH + Mov AH, 6 + StosW + Mov AL, DL + StosW + + Jmp Show36Channel7 + +Show36Channel4: + LodsW + Cmp AX, 0FFh + JE Show36Channel6 + + Cmp AL, 0FFh + JE Show36Channel5 + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC Show36ChannelNoVEffect + + Test AL, 80h + JZ Show36ChannelVEffect + + Add AH, 60 + +Show36ChannelVEffect: + Mov AL, AH + Xor AH, AH + Div CH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov DL, AH + Mov AH, 2 + StosW + Mov AL, DL + StosW + + Jmp Show36ChannelEndVolume + +Show36ChannelNoVEffect: + Mov DL, 2 + Test AL, 80h + JZ Show36Channel10 + + And AL, 7Fh + Dec DX + +Show36Channel10: + + Xor AH, AH ; Volume + Div CH + Add AX, 3030h + XChg DL, AH + StosW + Mov AL, DL + StosW + +Show36ChannelEndVolume: + Inc SI + Jmp Show36Channel7 + +Show36Channel5: + Mov AL, AH + Add AL, '@' + Mov AH, 2 + StosW + LodsB + Mov AH, 0Ah + StosW + + Jmp Show36Channel7 + +Show36Channel6: + Mov AX, 173+256*6 + StosW + StosW + Inc SI + +Show36Channel7: + Dec CL + JNZ Show36Channel9 + + Ret + +Show36Channel9: + Jmp Show36Channel1 + +EndP Show36Channel + +; + +Proc Display_36Channel + Assume DS:InfoPage + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Inc AX + Push AX + Push 77 + Add AX, [CS:BP+4] + Sub AL, 2 + Push AX + Push 27 + Call S_DrawBox + + Add SP, 10 + ; Fill in text. + ; check boundaries. + Mov DX, CurrentChannel + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_36Channel2 + + Mov BX, DX + +Display_36Channel2: + Mov CX, DX + Sub CX, 35 + Cmp BX, CX + JGE Display_36Channel3 + + Mov BX, CX + +Display_36Channel3: + Cmp BX, 28 + JB Display_36Channel11 + + Mov BX, 28 + +Display_36Channel11: + Mov [CS:BP+2], BL ; top channel. + ; Now do channel msgs. + + Mov CX, 0A24h + Mov DI, [CS:BP+6] + Add DI, (5+1*80)*2 + Mov SI, Offset Channel18Msg + +Display_36Channel4: + MovZX AX, BL + Inc AX + Div CH + Add AX, 3030h + Mov [SI], AX + + Call GetChannelColour + Call S_DrawString + + Inc BX + Dec CL + JNZ Display_36Channel4 + + Mov [CS:DrawTrackData], Offset Show36Channel + Call DisplayTrackData + Mov CX, 72 + Call DrawHilightBar + + Ret + +EndP Display_36Channel + Assume DS:Nothing + +; + +Proc Show64Channel + ; DS:SI points to stuff. + + Mov CX, 64 + Mov ES, Destination + Add DI, 8 + +Show64Channel1: + LodsW + + Cmp AX, 0FDh + JE Show64Channel4 + + Add SI, 3 + + Cmp AL, 0FDh + JE Show64Channel3 + JB Show64Channel2 + + Mov AH, AL + Mov AL, 205 + + Cmp AH, 0FFh + JE Show64Channel8 + + Mov AL, '^' + Cmp AH, 0FEh + JE Show64Channel8 + + Mov AL, 173 ; '.' + +Show64Channel8: + Mov AH, 6 + StosW + Jmp Show64Channel7 + +Show64Channel2: + AAM 12 + Mov BX, Offset Note2Table + SegCS XLatB + Mov AH, 6 + + StosW + Jmp Show64Channel7 + +Show64Channel3: + Mov AL, AH + AAM + ShL AH, 4 + Or AL, AH + + Mov AH, 10 + StosW + Jmp Show64Channel7 + +Show64Channel4: + LodsW + Inc SI + + Cmp AL, 0FFh + JE Show64Channel6 + + Mov DL, AL + And AX, 07Fh + + Cmp AL, 64 + JA Show64Channel6 + + AAM + ShL AH, 4 + Or AL, AH + + Mov AH, 12 + Test DL, 80h + JZ Show64ChannelVolumePan + + Mov AH, 9 + +Show64ChannelVolumePan: + StosW + + Jmp Show64Channel7 + +Show64Channel6: + Mov AX, 173+256*6 + StosW + +Show64Channel7: + Dec CX + JNZ Show64Channel9 + + Mov CX, 9 + Mov AX, 173+256*6 + Rep StosW + Ret + +Show64Channel9: + Jmp Show64Channel1 + +EndP Show64Channel + +; + +Proc Display_64Channel + Assume DS:InfoPage + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Inc AX + Push AX + Push 78 + Add AX, [CS:BP+4] + Sub AL, 2 + Push AX + Push 27 + Call S_DrawBox + + Add SP, 10 + ; Now do channel msgs. + + Mov CX, 0A40h + Mov DI, [CS:BP+6] + Add DI, (5+1*80)*2 + Mov SI, Offset Channel18Msg + Xor BX, BX + Mov DL, Byte Ptr CurrentChannel + +Display_64Channel4: + MovZX AX, BL + Inc AX + Div CH + + ShL AL, 4 + Or AL, AH + Mov DH, AL + Call GetChannelColour + Or AH, 8 + Mov AL, DH + StosW + + Inc BX + Dec CL + JNZ Display_64Channel4 + + Mov AX, 1000h + Mov CX, 9 + Rep StosW + + Mov Byte Ptr [CS:BP+2], 0 + + Mov [CS:DrawTrackData], Offset Show64Channel + Call DisplayTrackData + Mov CX, 73 + Call DrawHilightBar + + Ret + +EndP Display_64Channel + Assume DS:Nothing + +; + +Proc Display_Variables + + Mov DI, [CS:BP+6] + Add DI, (2+1*80)*2 + + Call Music_GetSlaveChannelInformationTable + ; DS:SI points to tables + ; CX = numchannels. + Xor DX, DX ; DX = counter of + ; currently act. + ; channels. + Xor BX, BX + + +Display_Variables1: + Cmp Word Ptr [SI+38h], 0 + JE Display_Variables2 + + Inc BX + +Display_Variables2: + Mov AX, [SI] +; Test AH, 8 +; JNZ Display_Variables4 + + And AX, 1 + Add DX, AX + +Display_Variables4: + Add SI, SLAVECHANNELSIZE + Loop Display_Variables1 + + Push BX + Call Music_GetDisplayVariables ; AX = Current Speed + ; BX = current tempo + ; CX = global volume + ; DX = active channels + Pop BX + Push CX + Push BX + Push DX + + Push CS + Pop DS + + Mov AH, 20h + Mov AL, Byte Ptr CurrentWindow + Cmp AL, Byte Ptr ProcessWindow + JNE Display_Variables3 + + Mov AH, 23h + +Display_Variables3: + Mov SI, Offset VariablesMsg + Call S_DrawString + + Add SP, 6 + + Ret + +EndP Display_Variables + +; + +Proc Display_NoteDots ; Draw boxes first. + Assume DS:InfoPage + + Mov ES, Destination + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Push AX + Push 78 + Add AX, [CS:BP+4] + Dec AX + Push AX + Push 27 + Call S_DrawBox + Add SP, 10 + + Mov DX, CurrentChannel + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_Dots1 + + Mov BX, DX + +Display_Dots1: + LEA CX, [EDX+3] + Sub CX, [CS:BP+4] + Cmp BX, CX + JGE Display_Dots2 + + Mov BX, CX + +Display_Dots2: + Mov CX, 66 + Sub CX, [CS:BP+4] + Cmp BX, CX + JLE Display_Dots3 + + Mov BX, 65 + Sub BX, [CS:BP+4] + +Display_Dots3: + Mov [CS:BP+2], BL ; BL = top channel + + Call DrawChannelNumbers + + Mov DX, [CS:BP+4] + Sub DX, 2 + Mov BL, [CS:BP+2] ; BL = channel + Mov DI, [CS:BP+6] + Add DI, (5+1*80)*2 + +Display_Dots4: + Push DI + + Push CS + Pop ES + Mov DI, Offset DataArray + Mov AX, 600h + 193 + Mov CX, 73 + Rep StosW ; DataArray cleared. + + ; OK.. loop to find channel usage. + Call Music_GetSlaveChannelInformationTable + ; Return DS:SI, CX +Display_Dots5: +; Cmp Word Ptr [SI+38h], 0 +; JE Display_Dots8 + + Test Byte Ptr [SI], 1 + JZ Display_Dots6 + + Mov AL, [SI+3Ah] + And AX, 7Fh + Cmp AL, BL + JNE Display_Dots6 ; Nope.. not the same channel + + Mov AL, [SI+32h] + Sub AL, 30 + JC Display_Dots6 + Cmp AL, 73 + JAE Display_Dots6 + + LEA DI, [DataArray+EAX+EAX] + Mov AL, [SI+20h] + Mov AH, [SI+36h] + Cmp AH, 100 + JNE Display_DotsNOMIDI + + Mov AH, [SI+33h] + +Display_DotsNoMIDI: + And AH, 3 + Add AL, 7 + ShR AL, 4 + AdC AX, 200h+193 + Test Word Ptr [SI], 800h + JZ Display_Dots7 + + Mov AH, 1 ; 6 + +Display_Dots7: + Test Byte Ptr [SI+3Ah], 80h + JZ Display_Dots9 + + Cmp Byte Ptr [CS:DI], AL + JA Display_Dots6 +Display_Dots9: + + Mov [CS:DI], AX + +Display_Dots6: + Add SI, SLAVECHANNELSIZE + + Dec CX + JNZ Display_Dots5 + +Display_Dots8: +; Dump to screen buffer. + + Pop DI + + Push CS + Pop DS + Mov SI, Offset DataArray + Mov ES, Destination + + Mov CX, 73 + Rep MovsW + + Add DI, 160-146 + + Inc BL + Dec DX + JNZ Display_Dots4 + + Ret + +EndP Display_NoteDots + +; + +Comment ~ + +Proc Display_SampleDots ; Draw boxes first. + Assume DS:InfoPage + + Mov ES, Destination + + Mov AX, 4 ; left + Push AX + Mov AL, [CS:BP+3] + Push AX + Push 78 + Add AX, [CS:BP+4] + Dec AX + Push AX + Push 27 + Call S_DrawBox + Add SP, 10 + + Mov DX, CurrentSample + MovZX BX, Byte Ptr [CS:BP+2] + Cmp DX, BX + JAE Display_SampleDots1 + + Mov BX, DX + +Display_SampleDots1: + LEA CX, [EDX+3] + Sub CX, [CS:BP+4] + Cmp BX, CX + JGE Display_SampleDots2 + + Mov BX, CX + +Display_SampleDots2: + Mov CX, 66 + Sub CX, [CS:BP+4] + Cmp BX, CX + JLE Display_SampleDots3 + + Mov BX, 65 + Sub BX, [CS:BP+4] + +Display_SampleDots3: + Mov [CS:BP+2], BL ; BL = top channel + + Mov CL, [CS:BP+4] + Mov CH, 0Ah + Sub CL, 2 + Mov DI, [CS:BP+6] + Add DI, (2+1*80)*2 + +Display_SampleDotsNumbers1: ; BX = top number, CL = count + Inc BX + Mov AX, BX + Div CH + Add AX, 3030h + Mov DH, AH + Mov AH, 21h + StosW + Mov AL, DH + StosW + Add DI, 160-4 + Dec CL + JNZ Display_SampleDotsNumbers1 + + Mov DX, [CS:BP+4] + Sub DX, 2 + Mov BL, [CS:BP+2] ; BL = sample + Mov DI, [CS:BP+6] + Add DI, (5+1*80)*2 + +Display_SampleDots4: + Push DI + + Push CS + Pop ES + Mov DI, Offset DataArray + Mov AX, 600h + 193 + Mov CX, 73 + Rep StosW ; DataArray cleared. + + ; OK.. loop to find channel usage. + Call Music_GetSlaveChannelInformationTable + ; Return DS:SI, CX +Display_SampleDots5: + Test Byte Ptr [SI], 1 + JZ Display_SampleDots6 + + Mov AL, [SI+36h] + Cmp AL, BL + JNE Display_SampleDots6 ; Nope.. not the same channel + + MovZX AX, Byte Ptr [SI+32h] + Sub AL, 30 + JC Display_SampleDots6 + Cmp AL, 73 + JAE Display_SampleDots6 + + LEA DI, [DataArray+EAX+EAX] + Mov AL, [SI+20h] ; Volume + Mov AH, [SI+33h] ; Instrument + + And AH, 3 + Add AL, 7 + ShR AL, 4 + AdC AX, 200h+193 + Test Word Ptr [SI], 800h + JZ Display_SampleDots7 + + Mov AH, 1 ; 6 ; Muted + +Display_SampleDots7: + Cmp Byte Ptr [CS:DI], AL + JA Display_SampleDots6 + +Display_SampleDots9: + Mov [CS:DI], AX + +Display_SampleDots6: + Add SI, SLAVECHANNELSIZE + + Dec CX + JNZ Display_SampleDots5 + +Display_SampleDots8: +; Dump to screen buffer. + + Pop DI + + Push CS + Pop DS + Mov SI, Offset DataArray + Mov ES, Destination + + Mov CX, 73 + Rep MovsW + + Add DI, 160-146 + + Inc BL + Dec DX + JNZ Display_SampleDots4 + + + Ret + +EndP Display_SampleDots + +~ + +; + +Proc DrawDisplayData Far + + Call PE_GetCurrentPattern + Mov CS:PatternSegment, DS + + Push CS + Pop DS + Assume DS:InfoPage + + Call S_GetDestination + Mov Destination, ES + + Mov PatternArrayNumber, AX + Mov PatternMaxRow, BX + + Call Music_GetPlayMode + Mov PlayMode, AX + Mov CurrentRow, BX + Mov CurrentPattern, CX + Mov CurrentOrder, DX + + Xor BP, BP + + Cmp CX, PatternArrayNumber + JNE DrawDisplayData1 + + Call Music_GetPatternLength + Mov PatternMaxRow, AX + +DrawDisplayData1: + Push CS + Pop DS + Assume DS:InfoPage + + Push BP + + Mov ProcessWindow, BP + + ShL BP, 3 + Add BP, Offset DisplayWindows + Mov SI, [CS:BP] + + Xor AL, AL + + Cmp FullScreen, 0 + JNE DisplayDataFull + + Cmp BP, Offset DisplayWindows + JE DisplayData2 + +DisplayDataFull: + Test SI, SI + JZ DisplayData2 + Cmp SI, DOTSDISPLAY + JE DisplayData2 + + Inc AX + + Dec Byte Ptr [CS:BP+3] ; Starting row + Inc Word Ptr [CS:BP+4] ; Length of window + Sub Word Ptr [CS:BP+6], 160 ; Offset + +DisplayData2: + Mov [RestoreData], AL + + Add SI, SI + Call [DisplayDataModes+SI] + + Push CS + Pop DS + + Cmp [RestoreData], 0 + JE DisplayData3 + + Pop BX + Push BX + + ShL BX, 3 + Add BX, Offset DisplayWindows + + Inc Byte Ptr [BX+3] + Dec Word Ptr [BX+4] + Add Word Ptr [BX+6], 160 + +DisplayData3: + Pop BP + Inc BP + Cmp BP, NumWindows + JB DrawDisplayData1 + + Mov AX, 1 + Ret + +EndP DrawDisplayData + Assume DS:Nothing + +; + +Proc PostDisplayData Far + + Push CS + Pop DS + Assume DS:InfoPage + + Mov SI, Offset DisplayListKeys + Call M_FunctionDivider + JC PostDisplayData1 + + Jmp [SI] + +PostDisplayData1: + Xor AX, AX + Ret + +EndP PostDisplayData + +; + +Proc DisplayUp Far + Assume DS:InfoPage + + Mov AX, 1 + + Sub CurrentChannel, AX + AdC CurrentChannel, 0 + + Ret + +EndP DisplayUp + Assume DS:Nothing + +; + +Proc DisplayDown Far + Assume DS:InfoPage + + Mov AX, CurrentChannel + Inc AX + Cmp AX, 64 + JAE DisplayDown1 + + Mov CurrentChannel, AX + +DisplayDown1: + Mov AX, 1 + Ret + +EndP DisplayDown + Assume DS:Nothing + +; + +Proc DisplayPlus Far + + Call Music_NextOrder + + Mov AX, 1 + Ret + +EndP DisplayPlus + +; + +Proc DisplayMinus Far + + Call Music_LastOrder + + Mov AX, 1 + Ret + +EndP DisplayMinus + +; + +Proc DisplayInsert Far + Assume DS:InfoPage + + Cmp NumWindows, 5 + JAE DisplayInsert1 + + Push DS + Pop ES + + Mov AX, 8 + Mul Byte Ptr CurrentWindow ; AX = offset + Mov SI, Offset DisplayWindows + Add SI, AX + + Cmp Word Ptr [SI+4], 6 ; Length of window + JBE DisplayInsert1 + + Push SI + + Mov AX, 8 + Mul Byte Ptr NumWindows + Mov SI, Offset DisplayWindows + Add SI, AX + Mov DI, SI + Sub SI, 8 + + Mov DX, NumWindows + Sub DX, CurrentWindow + +DisplayInsert2: + Mov CX, 4 + Rep MovsW + + Sub SI, 16 + Sub DI, 16 + Dec DX + JNZ DisplayInsert2 + + Pop SI ; SI points to cur win + ; now to resize.. + Mov AX, [SI+4] ; AX = length of win + ShR AX, 1 + AdC AX, 0 + + Mov [SI+4], AX ; halve length. + Sub [SI+8+4], AX ; second one also + Add AL, [SI+3] ; Add top line + Mov [SI+8+3], AL + Mov AH, 160 + Mul AH + Mov [SI+8+6], AX + + Inc NumWindows + +DisplayInsert1: + Mov AX, 1 + Ret + +EndP DisplayInsert + Assume DS:Nothing + +; + +Proc DisplayDelete Far + Assume DS:InfoPage + + Cmp NumWindows, 1 + JBE DisplayDelete1 + + Mov AX, 8 + Mul Byte Ptr CurrentWindow ; AX = offset + Mov SI, Offset DisplayWindows + Add SI, AX + Mov DI, SI + + Mov BX, [SI+4] ; Length of deleted win + Push SI + + Add SI, 8 + + Push DS + Pop ES + + Mov DX, NumWindows + Sub DX, CurrentWindow + +DisplayDelete2: + Mov CX, 4 + Rep MovsW + + Dec DX + JNZ DisplayDelete2 + + Pop SI + ; Now to recombine. + + Dec NumWindows + + Mov AX, CurrentWindow + Cmp AX, NumWindows + JB DisplayDelete3 + + Dec CurrentWindow ; Combine with earlier. + Add [SI-8+4], BX + Jmp DisplayDelete1 + +DisplayDelete3: ; Combine with next + Add [SI+4], BX + Mov AL, [SI+3] + Sub AL, BL + Mov [SI+3], AL + Mov AH, 160 + Mul AH + Mov [SI+6], AX + +DisplayDelete1: + Mov AX, 1 + Ret + +EndP DisplayDelete + Assume DS:Nothing + +; + +Proc DisplayNext Far + Assume DS:InfoPage + + Mov AX, CurrentWindow + Inc AX + Cmp AX, NumWindows + JB DisplayNext1 + + Xor AX, AX + +DisplayNext1: + Mov CurrentWindow, AX + + Mov AX, 1 + Ret + +EndP DisplayNext + Assume DS:Nothing + +; + +Proc DisplayPrevious Far + + Mov AX, CurrentWindow + And AX, AX + JZ DisplayPrevious1 + + Dec AX + Mov CurrentWindow, AX + +DisplayPrevious1: + Mov AX, 1 + Ret + +EndP DisplayPrevious + +; + +Proc DisplayAltUp Far + Assume DS:InfoPage + + Mov BX, 3 + + Mov AX, CurrentWindow + Sub AX, 1 + AdC BX, 0 + Add AX, 2 + + Cmp AX, NumWindows + JAE DisplayAltUp1 + + Mov AH, 8 + Mul AH + Mov SI, Offset DisplayWindows + Add SI, AX + + Cmp Word Ptr [SI-8+4], BX + JBE DisplayAltUp1 + + Inc Word Ptr [SI+4] + Dec Word Ptr [SI-8+4] + Dec Byte Ptr [SI+3] + Sub Word Ptr [SI+6], 160 + +DisplayAltUp1: + Mov AX, 1 + Ret + +EndP DisplayAltUp + Assume DS:Nothing + +; + +Proc DisplayAltDown Far + Assume DS:InfoPage + + Mov AX, CurrentWindow + Inc AX + Cmp AX, NumWindows + JAE DisplayAltDown1 + + Mov AH, 8 + Mul AH + Mov SI, Offset DisplayWindows + Add SI, AX + + Cmp Word Ptr [SI+4], 3 + JBE DisplayAltDown1 + + Inc Word Ptr [SI-8+4] + Dec Word Ptr [SI+4] + Inc Byte Ptr [SI+3] + Add Word Ptr [SI+6], 160 + +DisplayAltDown1: + Mov AX, 1 + Ret + +EndP DisplayAltDown + Assume DS:Nothing + +; + +Proc DisplayPageUp Far + Assume DS:InfoPage + + Mov AX, CurrentWindow + Mov AH, 8 + Mul AH + Mov SI, Offset DisplayWindows + Add SI, AX + + Mov AX, [SI] + And AX, AX + JNZ DisplayPageUp1 + + Mov AX, PLAYMETHODS + +DisplayPageUp1: + Dec AX + Mov [SI], AX + + Mov AX, 1 + Ret + +EndP DisplayPageUp + Assume DS:Nothing + +; + +Proc DisplayPageDown Far + Assume DS:InfoPage + + Mov AX, CurrentWindow + Mov AH, 8 + Mul AH + Mov SI, Offset DisplayWindows + Add SI, AX + + Mov AX, [SI] + Inc AX + Cmp AX, PLAYMETHODS + JB DisplayPageDown1 + + Xor AX, AX + +DisplayPageDown1: + Mov [SI], AX + + Mov AX, 1 + Ret + +EndP DisplayPageDown + Assume DS:Nothing + +; + +Proc DisplayHome Far + Assume DS:InfoPage + + Mov CurrentChannel, 0 + + Mov AX, 1 + Ret + +EndP DisplayHome + Assume DS:Nothing + +; + +Proc DisplayEnd Far + Assume DS:InfoPage + + Call Music_GetLastChannel + Mov CurrentChannel, AX + + Mov AX, 1 + Ret + +EndP DisplayEnd + Assume DS:Nothing + +; + +Proc DisplayToggleChannel Far + + Mov AX, CurrentChannel + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP DisplayToggleChannel + +; + +Proc DisplaySoloChannel Far + + Mov AX, CurrentChannel + Call Music_SoloChannel + + Mov AX, 1 + Ret + +EndP DisplaySoloChannel + +; + +OldEBX DD 0 +OldECX DD 0 + +Proc DisplayUpdateScreen Far + +IF NETWORKENABLED + Call Network_Poll + + Test AX, AX + JNZ DisplayUpdateScreen1 +ENDIF + + Call Music_Poll + Call Music_GetPlayMode2 + + Test AX, AX + JZ DisplayUpdateScreen3 ; Play mode 0 - update screen + + Cmp CS:OldEBX, EBX + JNE DisplayUpdateScreen2 + + Cmp CS:OldECX, ECX + JNE DisplayUpdateScreen2 + + Xor AX, AX + Ret + +DisplayUpdateScreen3: + Mov EBX, -1 + Mov ECX, EBX + +DisplayUpdateScreen2: + Mov CS:OldEBX, EBX + Mov CS:OldECX, ECX + +DisplayUpdateScreen1: + Mov AX, 1 + Ret + +EndP DisplayUpdateScreen + +; + +Proc DisplayToggleStereo Far + Assume DS:InfoPage + + Call Music_GetSongSegment + Mov ES, AX + + Mov AL, [ES:2Ch] + Xor AL, 1 + Mov [ES:2Ch], AL + + Mov SI, Offset StereoEnabledMsg + Test AL, 1 + JNZ DisplayToggleStereo1 + + Mov SI, Offset StereoDisabledMsg + +DisplayToggleStereo1: + Call SetInfoLine + Call Music_InitStereo + + Mov AX, 1 + Ret + +EndP DisplayToggleStereo + Assume DS:Nothing + +; + +Proc Display_GetDisplayWindowData Far + + Push CS + Pop DS + Assume DS:InfoPage + + Mov DX, Offset DisplayWindows + + Ret + +EndP DIsplay_GetDisplayWindowData + +; + +Proc Display_GotoPattern Far + + Call Music_GetPlayMode + Cmp AX, 1 + JB Display_GotoPattern1 + JE Display_GotoPattern2 + + Push Pattern + Pop DS + Assume DS:Pattern + + Mov Order, DX + +Display_GotoPattern2: + Mov AX, CX + ; BX = current row + Mov CX, CS:CurrentChannel + + Jmp PE_GotoPattern + +Display_GotoPattern1: + Xor AX, AX + Ret + +EndP Display_GotoPattern + Assume DS:Nothing + +; + +Proc Display_SpaceBar Far + Assume DS:InfoPage + + Call DisplayToggleChannel + Jmp DisplayDown + +EndP Display_SpaceBar + +; + +Proc DisplayToggleVelocity Far + + Mov SI, Offset VolumeMsg + Xor Byte Ptr Velocity, 1 + JZ DisplayToggleVelocity1 + + Mov SI, Offset VelocityMsg + +DisplayToggleVelocity1: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP DisplayToggleVelocity + +; + +Proc DisplayToggleInstrument Far + + Mov SI, Offset SampleMsg + Xor Byte Ptr Instrument, 1 + JZ DisplayToggleInstrument1 + + Mov SI, Offset InstrumentMsg + +DisplayToggleInstrument1: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP DisplayToggleInstrument + +; + +Proc DisplayToggleReverse Far + + Call Music_ToggleReverse + + Mov AX, 1 + Ret + +EndP DisplayToggleReverse + +; + +Proc Display_SelectDisplayList Far + + Cmp CS:FullScreen, 1 + JZ Display_FullScreen3 + Jmp Display_FullScreen4 + +EndP Display_SelectDisplayList + +; + +Proc Display_FullScreen Far + + Cmp NumWindows, 1 + JE Display_FullScreen1 + + Mov AX, 1 + Ret + +Display_FullScreen1: + Push Glbl + Pop ES + Assume ES:Glbl + Mov ES:CurrentMode, 5 + Assume ES:Nothing + + Xor FullScreen, 1 + + JZ Display_FullScreen2 + + Mov Byte Ptr [DisplayWindows+3], 1 + Mov DWord Ptr [DisplayWindows+4], 160*10000h+49 + +Display_FullScreen3: + Push Glbl + Pop ES + Assume ES:Glbl + Mov ES:CurrentMode, 200 + Assume ES:Nothing + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + + Mov DX, Offset O1_FullDisplayList + Ret + +Display_FullScreen2: + Mov Byte Ptr [DisplayWindows+3], 12 + Mov DWord Ptr [DisplayWindows+4], 12*80*2*65536+38 + +Display_FullScreen4: + Push Glbl + Pop ES + Assume ES:Glbl + Mov ES:CurrentMode, 5 + Assume ES:Nothing + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + + Mov DX, Offset O1_DisplayList + Ret + +EndP Display_FullScreen + +; + +IF SPECTRUMANALYSER + +Proc Display_FourierStart Far + + Jmp Fourier_Start + +EndP Display_FourierStart + +ENDIF + +; + +EndS + +; + +End diff --git a/it/IT_D_INF.INC b/it/IT_D_INF.INC new file mode 100644 index 0000000..4c2e52a --- /dev/null +++ b/it/IT_D_INF.INC @@ -0,0 +1,1126 @@ + + +Proc D_GetSongNameModuleType + + LEA DI, [SI+17] ; ES:DI points to deposit point. + Sub SI, 8 + + Cmp DWord Ptr [DS:60000], 'MPMI' + JNE D_GetSongNameModuleType1 + + Mov DX, [DS:60000+2Ah] + Mov AX, 3 + + Cmp DX, TRACKERVERSION + JA D_GSNMTImpulse1 + + Dec AX + Cmp DX, 214h + JB D_GSNMTImpulse1 + + Mov AX, 7 + +D_GSNMTImpulse1: + Mov Word Ptr [SI+23], AX + + Mov SI, 60004 + Mov CX, 25 + Rep MovsB + + Ret + +D_GetSongNameModuleType1: +; Cmp Word Ptr [DS:60028], 101Ah +; JNE D_GetSongNameModuleType2 + + Cmp DWord Ptr [DS:60044], 'MRCS' + JNE D_GetSongNameModuleType2 + + Mov Word Ptr [SI+23], 4 + + Mov SI, 60000 + Mov CX, 25 + Rep MovsB + + Ret + +D_GetSongNameModuleType2: + Push SI ES DI + + Push CS + Pop ES + Mov SI, 60000 + Mov DI, Offset XMIdentification + Mov CX, 17 + RepE CmpsB + + Pop DI ES SI + JNE D_GetSongNameModuleTypeNotXM + + Mov Word Ptr [SI+23], 5 ; XM + + Mov SI, 60000+17 + Mov CX, 20 + Rep MovsB + Xor AX, AX +; Mov CX, 5 +; Rep StosB + Ret + +D_GetSongNameModuleTypeNotXM: + Mov AX, [DS:60000] + Cmp AX, 'fi' + JE D_GetSongNameModuleType669 + Cmp AX, 'NJ' + JNE D_GetSongNameModuleTypeNot669 + +D_GetSongNameModuleType669: ; We have a 669 module! + Mov Word Ptr [SI+23], 6 ; 669 + Mov SI, 60000+2 + Mov CX, 25 + Rep MovsB + Ret + +D_GetSongNameModuleTypeNot669: + Mov EAX, [DS:61080] + + Cmp EAX, '.K.M' + JNE D_GetSongNameModuleType3 + + Mov Word Ptr [SI+23], 9 + Jmp D_GSNMTMod + +D_GetSongNameModuleType3: + Cmp EAX, '!K!M' + JNE D_GetSongNameModuleType4 + + Mov Word Ptr [SI+23], 10 + Jmp D_GSNMTMod + +D_GetSongNameModuleType4: + Cmp EAX, 'NHC4' + JNE D_GetSongNameModuleType5 + + Mov Word Ptr [SI+23], 11 + Jmp D_GSNMTMod + +D_GetSongNameModuleType5: + Cmp EAX, 'NHC6' + JNE D_GetSongNameModuleType6 + + Mov Word Ptr [SI+23], 12 + Jmp D_GSNMTMod + +D_GetSongNameModuleType6: + Cmp EAX, 'NHC8' + JNE D_GetSongNameModuleType11 + + Mov Word Ptr [SI+23], 13 + Jmp D_GSNMTMod + +D_GetSongNameModuleType11: + Cmp Word Ptr [DS:61082], 'HC' + JNE D_GetSongNameModuleType7 + Cmp AL, '0' + JB D_GetSongNameModuleType7 + Cmp AL, '9' + JA D_GetSongNameModuleType7 + Cmp AH, '0' + JB D_GetSongNameModuleType7 + Cmp AH, '9' + JA D_GetSongNameModuleType7 + + ; Generic MOD type. + Sub AX, '00' + Mov BL, AH + Mov AH, 10 + Mul AH + Add BL, AL + Mov Word Ptr [SI+23], 17 + Mov Byte Ptr [SI+22], BL + + Jmp D_GSNMTMod + + +D_GetSongNameModuleType7: + Cmp EAX, '4TLF' + JNE D_GetSongNameModuleType8 + + Mov Word Ptr [SI+23], 14 + Jmp D_GSNMTMod + +D_GetSongNameModuleType8: +; Cmp EAX, '8TLF' +; JNE D_GetSongNameModuleType9 +; +; Mov Word Ptr [SI+23], 15 +; Jmp D_GSNMTMod +; +; D_GetSongNameModuleType9: + Cmp Byte Ptr [DS:60000+471], 78h + JNE D_GetSongNameModuleType10 + + Mov Word Ptr [SI+23], 16 + Jmp D_GSNMTMod + +D_GetSongNameModuleType10: + Cmp Word Ptr [DS:60000], 'M'+256*'T' + JNE D_GetSongNameModuleType12 + Cmp Byte Ptr [DS:60002], 'M' + JNE D_GetSongNameModuleType12 + + Mov Word Ptr [SI+23], 18 + + Mov SI, 60004 + Mov CX, 20 + Rep MovsB + Mov CX, 5 + Xor AL, AL + Rep StosB + +D_GetSongNameModuleType12: + Mov Word Ptr [SI+23], 1 + + Ret + +D_GSNMTMod: + Mov SI, 60000 + Mov CX, 20 + Rep MovsB + Xor AX, AX + StosW + StosW + StosB + + Ret + +EndP D_GetSongNameModuleType + +; + +Proc D_GetInstrumentInfo ; Instrument layout + ; 48 bytes per instrument. + ; Offset 0 = type of file. + ; 0 = Unchecked + ; 1 = Directory + ; 2 = Unrecognised + ; 3 = ITI + ; 4 = XI + ; 8 = .IT + ; 9 = .XM + ; Offset 1 = file name + ; 15->40 is the instrument name, + ; 40 = No. Samples + ; 42 = File size. + ; 44 = file offset (DWord) + + Mov AX, 48 + Mul BX + Mov DI, AX + + Mov DS, CS:DiskDataArea + Mov SI, 60000 + + ; Check for XM + Push CS + Pop ES + +; Comment ~ + + Push DI + Mov DI, Offset XMIdentification + Mov CX, 17 + RepE CmpSB + Pop DI + + Mov AL, 9 + JE D_InModuleInstrument ; XM module found? + + Mov SI, 60000 + + Cmp DWord Ptr [SI], 'MPMI' ; Impulse Tracker module? + JNE D_GetInstrumentInfoNotIT + Cmp Word Ptr [SI+22h], 0 + JE D_GetInstrumentInfoNotIT + Test Byte Ptr [SI+2Ch], 4 ; Instrument mode? + JZ D_GetInstrumentInfoNotIT + + Mov AL, 8 + +D_InModuleInstrument: + Push DS + Pop ES + + StosB + Add DI, 14 + Push CS + Pop DS + Mov SI, Offset LibraryMsg + Mov CX, 25 + Rep MovsB + Xor AX, AX + + Ret + +D_GetInstrumentInfoNotIT: +; ~ + + Cmp DWord Ptr [SI], 'IPMI' + JNE D_GetInstrumentInfo1 + + Push DS + Pop ES + Mov Byte Ptr [DI], 3 + + Mov AL, [SI+1Eh] + Xor AH, AH + + Add DI, 15 + Add SI, 20h + Mov CX, 25 + Rep MovsB + + StosW ; NOS. + + ClC + Ret + +D_GetInstrumentInfo1: ; Check for XI + Push DI + + Mov DI, Offset XIIdentification + Mov CX, 21 + RepE CmpsB + + Pop DI + JNE D_GetInstrumentInfo2 + +D_GetInstrumentInfoXI: + Push DS + Pop ES + + Mov Byte Ptr [DI], 4 ; XI + Add DI, 15 + Mov CX, 22 + Rep MovsB + Xor AX, AX + StosW + StosB + Mov AX, [DS:60000+128h] ; AX = number of samples + StosW ; NoS + Ret + +D_GetInstrumentInfo2: + Push DS + Pop ES + + Mov SI, DI + Mov CX, 48 + Mov AX, CS:NumInstruments + Sub AX, BX + Add SI, CX + Mul CX + Mov CX, AX + Rep MovsB + + Push CS + Pop DS + Assume DS:Disk + + Dec NumInstruments + + Mov AX, CurrentInstrument + Cmp AX, NumInstruments + JAE D_GetInstrumentInfo3 + + Cmp AX, BX + JBE D_GetInstrumentInfoEnd + +D_GetInstrumentInfo3: + Sub AX, 1 + AdC AX, 0 + +D_GetInstrumentInfoEnd: + Mov CurrentInstrument, AX + + StC + Ret + +EndP D_GetInstrumentInfo + +; + +Proc D_GetSampleInfo ; BX = sample num. + + Mov AX, 96 + Mul BX + Mov DI, AX + Mov BX, AX + Mov DS, CS:DiskDataArea + Mov SI, 60000 + Push DS + Pop ES ; ES:DI points to sample block + ; DS:SI points to header + + Mov Byte Ptr [BX+90], 2 ; Recognised sample default. + + Cmp DWord Ptr [DS:60000], 'SPMI' + JE D_GetSampleInfo1 ; Possibly a IT sample. + Cmp DWord Ptr [DS:60000+4Ch], 'SRCS' + JE D_GetSampleInfo4 + Cmp DWord Ptr [DS:60000], 'FFIR' + JE D_GetSampleInfo8 ; AIFF? + Cmp DWord Ptr [DS:60000], 'MROF' + JE D_GetSampleInfo13 + + Mov AL, 21h + Cmp DWord Ptr [DS:60000], 'MPMI' + JE D_GetSampleInfoModuleTypes1 + + Mov AL, 23h + Cmp DWord Ptr [DS:60000+44], 'FMTP' + JE D_GetSampleInfoModuleTypes1 + + Inc AX ; AL = 24h + Mov ECX, [DS:60000] + And ECX, 0FFFFFFh + Cmp ECX, 'M'*10000h+'T'*100h+'M' + JE D_GetSampleInfoModuleTypes1 + + Inc AX ; AL = 25h + Cmp Word Ptr [DS:60000], 'fi' + JE D_GetSampleInfoModuleTypes1 + Cmp Word Ptr [DS:60000], 'NJ' + JE D_GetSampleInfoModuleTypes1 + + Inc AX ; AL = 26h + Cmp DWord Ptr [DS:60000], 'RAF' + JE D_GetSampleInfoModuleTypes1 + + Mov ECX, [DS:60000+1080] + Mov AX, 427h ; MOD Module + 4 channels + Cmp ECX, '.K.M' + JE D_GetSampleInfoModuleTypes1 + Cmp ECX, '!K!M' + JE D_GetSampleInfoModuleTypes1 + Cmp ECX, '4TLF' + JE D_GetSampleInfoModuleTypes1 + Cmp ECX, 'NHC4' + JE D_GetSampleInfoModuleTypes1 + + Mov AH, 6 ; 6 Channel + Cmp ECX, 'NHC6' + JE D_GetSampleInfoModuleTypes1 + + Mov AH, 8 + Cmp ECX, 'NHC8' + JE D_GetSampleInfoModuleTypes1 + Cmp ECX, '8TLF' + JE D_GetSampleInfoModuleTypes1 + + Cmp Word Ptr [DS:61082], 'HC' + JNE D_GetSampleInfoS3M + + Sub CX, '00' + Cmp CL, 9 + JA D_GetSampleInfoS3M + Cmp CH, 9 + JA D_GetSampleInfoS3M + Mov AL, 10 + Mul CL + Add AL, CH + Mov AH, AL + Mov AL, 28h + Jmp D_GetSampleInfoModuleTypes1 + +D_GetSampleInfoS3M: + Cmp DWord Ptr [DS:60000+2Ch], 'MRCS' + JNE D_GetSampleInfoModuleTypes3 + + Mov AL, 20h ; ST3? + Jmp D_GetSampleInfoModuleTypes1 +; Cmp Word Ptr [DS:60000+1Ch], 101Ah +; JE D_GetSampleInfoModuleTypes1 +; Jmp D_GetSampleInfoModuleTypes3 + +D_GetSampleInfoModuleTypes3: ; KRZ + Cmp DWord Ptr [DS:60000], 'MARP' + JNE D_GetSampleInfoNotKRZ + + Cmp Word Ptr [DS:60000+32], 0FFFFh + JNE D_GetSampleInfoNotKRZ + + ; Check filename for .KRZ + + LEA SI, [BX+4] + Mov CX, 9 + +D_CheckKRZFileName: + Cmp Byte Ptr [SI], 0 + JE D_GetSampleInfoNotKRZ + + Cmp DWord Ptr [SI], 'ZRK.' + JE D_FoundKRZ + + Inc SI + Loop D_CheckKRZFileName + Jmp D_GetSampleInfoNotKRZ + +D_FoundKRZ: + Mov AL, 29h + Jmp D_GetSampleInfoModuleTypes1 + +D_GetSampleInfoNotKRZ: ; FT2 check + Push SI + Push ES + Push DI + + Push CS + Pop ES + Mov DI, Offset GUSPATIdentification + Mov CX, 22 + RepE CmpsB + + Pop DI + Pop ES + Pop SI + JNE D_GetSampleInfoNotPAT + + Cmp Byte Ptr [DS:60000+198], 1 + JE G_GetSampleInfoPAT + + Mov AL, 2Ah + Jmp D_GetSampleInfoModuleTypes1 + +G_GetSampleInfoPAT: + Mov Byte Ptr [BX+88], 16 + + Mov EAX, 'SPMI' + StosD + Mov SI, DI + Add DI, 13 + Mov AL, 64 + StosB ; Global vol = 64 + + Mov AX, 4001h ; sample present + Mov DL, [DS:60000+239+55] ; modes + + Test DL, 1 ; 8/16 bit + JZ GetSampleInfoPATSamples2 + + Or AL, 2 + +GetSampleInfoPATSamples2: + Test DL, 4 ; Looping enabled? + JZ GetSampleInfoPATSamples3 + + Or AL, 10h + +GetSampleInfoPATSamples3: + Test DL, 8 ; Ping pong loops? + JZ GetSampleInfoPATSamples4 + + Or AL, 40h + +GetSampleInfoPATSamples4: + StosW ; OK.. now for name. + + Mov SI, 60000+131 + Mov CX, 16 + +GetSampleInfoPATSamples5: + LodsB + Test AL, AL + JZ GetSampleInfoPATSamples6 + StosB + Loop GetSampleInfoPATSamples5 + + Xor AL, AL + +GetSampleInfoPATSamples6: + Add CX, 10 + Rep StosB + + ; Convert, default pan + + Mov AH, 32 + Mov AL, [DS:60000+239+55] + And AL, 2 + ShR AL, 1 + Xor AL, 1 + StosW + + ; Length. + + Mov DL, [DS:60000+239+55] + + Mov EAX, [DS:60000+239+16] ; LoopEnd -> FileSize + Mov [DI+20h], EAX ; File size + Call StorePATLength + + Mov EAX, [DS:60000+239+12] ; LoopBeg + Call StorePATLength + Mov EAX, [DS:60000+239+16] ; LoopEnd + Call StorePATLength + + Mov AX, [DS:60000+239+20] + And EAX, 0FFFFh + +Comment ~ + Push ES DI + + Call Music_GetPitchTable ; Returns ES:DI + Mov BP, [DS:60000+239+56] + And BP, 0FFh + ShL BP, 2 + Mul DWord Ptr [ES:DI+BP] + SHRD EAX, EDX, 16 + + Pop DI ES +~ + StosD ; C5Spd + + Xor EAX, EAX + StosD + StosD + + Mov EAX, 14Fh + StosD + + Xor AX, AX + StosW + StosW + + Ret + + +D_GetSampleInfoNotPAT: + Push SI + Push ES + Push DI + + Push CS + Pop ES + Mov DI, Offset XMIdentification + Mov CX, 17 + RepE CmpsB + + Pop DI + Pop ES + Pop SI + JNE TXWaveSampleIdentification + + Mov AL, 22h ; FT2 + +D_GetSampleInfoModuleTypes1: + Mov Word Ptr [BX+88], AX + Mov Byte Ptr [BX+90], 1 + + Push DS + + Push CS + Pop DS + + Mov SI, Offset LibraryMsg + LEA DI, [BX+14h] + Mov CX, 26/2 + Rep MovsW + + Pop DS + Ret + +TXWaveSampleIdentification: + Push SI + Push ES + Push DI + + Push CS + Pop ES + Mov DI, Offset TXWaveIdentification + Mov CX, 16 + RepE CmpSB + + Pop DI + Pop ES + Pop SI + ; OK.. have a TX Wave. + ; Now to transfer data. + JNE D_GetSampleInfo2 + + Mov AL, [DS:60000+16h] + And AL, 7Fh + Cmp AL, 49h + JNE D_GetSampleInfo2 + + Mov Byte Ptr [BX+88], 13 + + Mov EAX, 'SPMI' + StosD + Mov SI, DI + Add DI, 13 + Mov AL, 64 + StosB ; Global vol = 64 + + Mov AX, 64*256+1+2 ; Flag = sample + 16 bit + ; Default volume = 64 + Cmp Byte Ptr [DS:60000+16h], 049h + JNE D_GetTXInfo3 + + Or AL, 10h ; Loop forwards + +D_GetTXInfo3: + StosW + + Mov CX, 13 + +D_GetTXInfo1: + LodsB + Test AL, AL + JZ D_GetTXInfo2 + + StosB + Loop D_GetTXInfo1 + +D_GetTXInfo2: + Xor AL, AL + Rep StosB + + Mov CX, 13 + Rep StosB + ; Length... + Mov AX, 16+1 ; TX Wave, signed + StosW + + Mov EDX, [DS:60000+18h] + Mov ECX, [DS:60000+1Bh] + And EDX, 1FFFFh ; Attack length + And ECX, 1FFFFh ; Loop Length + + Mov EAX, ECX + Add EAX, EDX ; Length + StosD + Mov EAX, EDX ; LoopStart + StosD + Add EAX, ECX ; LoopEnd + StosD + + Mov EAX, 33000 ; Freq + Cmp Byte Ptr [DS:60000+17h], 2 + JB D_GetTXInfo4 + + Mov AX, 50000 + JE D_GetTXInfo4 + + Mov AX, 16000 + +D_GetTXInfo4: + StosD ; Frequency + Xor EAX, EAX + StosD + StosD + Mov AX, 20h + StosD + Xor AX, AX + StosD + + Ret + +D_GetSampleInfo2: + Mov DWord Ptr [BX+88], 30004h ; Unknown Type + + Mov EAX, 'SPMI' + StosD + Mov SI, DI + Add DI, 13 + Mov AL, 64 + StosB ; Global vol = 64 + Mov AL, 1 + StosB ; Flag = sample. + Mov AL, 64 + StosB ; Default vol = 64. + + Mov CX, 13 + +D_GetSampleInfo6: + LodsB + Test AL, AL + JZ D_GetSampleInfo7 + + StosB + Loop D_GetSampleInfo6 + +D_GetSampleInfo7: + Xor AL, AL + Rep StosB + + Mov CX, 15 + Rep StosB + ; Length... + Mov EAX, 4177910 + + Cmp EAX, [BX+80] + JB D_GetSampleInfo3 + + Mov EAX, [BX+80] + +D_GetSampleInfo3: + StosD + Xor AX, AX + StosW + StosW + StosW + StosW + Mov AX, 8363 + StosW + Xor AX, AX + Mov CX, 9 + Rep StosW + + Ret + +D_GetSampleInfo1: + Mov Byte Ptr [BX+88], 2 + + Mov CX, 4 + Rep MovsB + Add SI, 12 + Add DI, 12 + Mov CX, 64 + Rep MovsB + + Ret + +D_GetSampleInfo4: + Mov Byte Ptr [BX+88], 3 ; Scrm + + Mov EAX, 'SPMI' + StosD + + Add DI, 13 + Mov AL, 64 + StosB + + Mov AL, 1 + Mov CL, [DS:60000+1Fh] + Mov CH, CL + + And CL, 1 + ShL CL, 4 + Or AL, CL ; Loop... + + And CH, 4 + ShR CH, 1 + Or AL, CH ; 16 bit. + +D_GetSampleInfo5: + StosB + Mov AL, [DS:60000+1Ch] + StosB + Mov SI, 60000+30h + Mov CX, 25 + Rep MovsB + Xor AX, AX + StosB + StosW ; Name done... now for length + + Mov EAX, [DS:60000+10h] + StosD + Mov EAX, [DS:60000+14h] + StosD + Mov EAX, [DS:60000+18h] + StosD + Mov EAX, [DS:60000+20h] ; C5Spd + StosD + Xor AX, AX + StosW + StosW + StosW + StosW + ; Now for sample pointer. + Mov CL, 4 + Mov AX, [DS:60000+0Eh] + Mov DL, [DS:60000+0Fh] + Mov DH, [DS:60000+0Dh] + ShL AX, CL + ShR DX, CL + StosW ; Sample pointer in file. + Mov AX, DX + StosW + + Xor AX, AX ; Vibrato info + StosW + StosW + + Ret + +D_GetSampleInfo8: ; WAV Identification + Push SI + Push DI + Push DS + + Push CS + Pop DS + Mov SI, Offset WAVEfmtID + Mov DI, 60008 + Mov CX, 8 + RepE CmpsB + JNE NotWAV + + Add DI, 2 + Mov CX, 4 + RepE CmpsB + +NotWAV: + Pop DS + + JNE D_GetSampleInfo9 + + Mov BP, 60000+18h + Add BP, [DS:60000+10h] + Mov CX, 3 ; Only allow 3 blocks + +CheckNextWAVE: + Cmp DWord Ptr [DS:BP-4], 'atad' + JE D_GetSampleWaveFound + + Mov AX, [DS:BP] + Add AX, 8 + Add BP, AX + JC D_GetSampleInfo9 + + Loop CheckNextWAVE + Jmp D_GetSampleInfo9 + +D_GetSampleWaveFound: + Mov DL, [DS:60000+22h] ; DL = number of bits. + Mov DH, 1 + Cmp DL, 8 + JE D_GetSampleInfo9 + + Mov DH, 3 + Cmp DL, 16 + +D_GetSampleInfo9: + Pop DI + Pop SI + JNE D_GetSampleInfo2 + ; We have a WAV file! + Cmp Word Ptr [DS:60000+16h], 2 + JNE D_GetSampleWAVStereo + + Or DH, 4 + +D_GetSampleWAVStereo: + Mov AL, DH + And AL, 3 + Add AL, 4 + Mov Byte Ptr [BX+88], AL ; 5 = 8 bit, 7 = 16 bit. + + Mov EAX, 'SPMI' + StosD + + Mov SI, DI + Add DI, 13 + Mov AL, 64 + StosB ; Global vol = 64 + Mov AL, DH + StosB ; Flag = sample. + Mov AL, 64 + StosB ; Default vol = 64. + + Mov CX, 13 + +D_GetSampleInfo10: + LodsB + And AL, AL + JZ D_GetSampleInfo11 + + StosB + Loop D_GetSampleInfo10 + +D_GetSampleInfo11: + Xor AX, AX + Add CX, 13 + Rep StosB + + Mov AL, DH + And AL, 4 ; stereo? + ShL AL, 3 + + Test DH, 2 + JZ D_GetSampleInfo19 + + Inc AX + +D_GetSampleInfo19: + StosW ; Sample format + + Mov EAX, 4177910 ; Length + + Cmp EAX, [DS:BP] + JB D_GetSampleInfo12 + + Mov EAX, [DS:BP] + +D_GetSampleInfo12: + Test DH, 2 + JZ D_GetSampleInfo18 + + ShR EAX, 1 + +D_GetSampleInfo18: + Test DH, 4 + JZ D_GetSampleWAVStereo2 + + ShR EAX, 1 + +D_GetSampleWAVStereo2: + StosD + + Xor AX, AX + StosW + StosW + StosW + StosW + + Mov AX, [DS:60000+18h] ; Frequency + StosW + Xor AX, AX + Mov CX, 5 + Rep StosW + Mov AX, BP + Add AX, 4-60000 +; Mov AX, 2Ch + StosW + Xor AX, AX + StosW + StosW + StosW + + Ret + +D_GetSampleInfo13: ; AIFF Identification + Mov AL, 3 + Cmp DWord Ptr [DS:60000+8], 'VS61' + JE D_GetSampleInfoIFF + + Mov AL, 1 + Cmp DWord Ptr [DS:60000+8], 'XVS8' + JNE D_GetSampleInfo2 + +D_GetSampleInfoIFF: + Mov Byte Ptr [BX+88], 17 ; AIFF format. + Mov Byte Ptr [BX+12h], AL + Mov SI, 60000 + 0Ch + +D_GetSampleInfoIFF1: + Cmp DWord Ptr [DS:SI], 'EMAN' + JE D_GetSampleInfoIFFName + + Cmp DWord Ptr [DS:SI], 'RDHV' + JE D_GetSampleInfoIFFHeader + + Cmp DWord Ptr [DS:SI], 'YDOB' + JNE D_IFFHeaderNext + + ; Body. + Mov DWord Ptr [DI], 'SPMI' + Mov Byte Ptr [DI+11h], 64 ; Global volume + Mov Byte Ptr [DI+13h], 64 ; Default volume + Mov Word Ptr [DI+2Eh], 1 ; Sign conversion + + Add DI, 30h + Mov AX, [SI+06h] ; Size + Mov DX, [SI+04h] + Call Near Ptr D_GetSampleInfoBSwap + StosD + Xor EAX, EAX + Add DI, 0Ch + StosD + StosD + StosD + StosD + + Add SI, 8-60000 + Mov [BX+48h], SI + + Ret + +D_GetSampleInfoIFFName: + Push SI + Push DI + + Mov CX, [SI+6] + XChg CL, CH + Cmp CX, 25 + JBE D_GetSampleInfoIFFName1 + + Mov CX, 25 + +D_GetSampleInfoIFFName1: + Add SI, 8 + Add DI, 14h + Rep MovsB + +D_IFFHeaderEnd: + Pop DI + Pop SI + +D_IFFHeaderNext: + Mov AX, [SI+6] + XChg AL, AH + Add AX, 8 + Add SI, AX + JC D_GetSampleInfo2 + + Jmp D_GetSampleInfoIFF1 + +D_GetSampleInfoIFFHeader: + Push SI + Push DI + + Add DI, 34h + + Mov AX, [SI+0Eh] ; Loop start + Mov DX, [SI+0Ch] + Call Near Ptr D_GetSampleInfoBSwap + StosD + + Push EAX + Mov AX, [SI+12h] ; Loop end + Mov DX, [SI+10h] + Call Near Ptr D_GetSampleInfoBSwap + Test EAX, EAX + JZ D_GetSampleInfoIFFHeader1 + + Or Byte Ptr [BX+12h], 16 + +D_GetSampleInfoIFFHeader1: + Pop EDX + Add EAX, EDX + StosD + + Xor EAX, EAX + Mov AX, [SI+14h] + XChg AL, AH + StosD + + Jmp D_IFFHeaderEnd + +D_GetSampleInfoBSwap: + XChg DH, AL + XChg DL, AH + + ShL EAX, 16 + Mov AX, DX + + Test Byte Ptr [BX+12h], 2 + JZ D_GetSampleInfo17 + + ShR EAX, 1 ; Halve length for 16-bit samples. + +D_GetSampleInfo17: + RetN + +EndP D_GetSampleInfo + diff --git a/it/IT_D_RI.INC b/it/IT_D_RI.INC new file mode 100644 index 0000000..f4376ba --- /dev/null +++ b/it/IT_D_RI.INC @@ -0,0 +1,771 @@ +; +; +; Load Instrument module +; +; Instrument in .ITI format has to be placed at DS:64000 +; Sample headers have to be placed at DS:0 +; +; +; + +Proc LoadITInstrument + + Mov DX, 64000 + Mov CX, 554 ; Length of instrument header + Mov AH, 3Fh + Int 21h + + Cmp Word Ptr [DS:64000+1Ch], 200h + JAE LoadITInstrument1 + + Mov SI, DX + Call ConvertOldInstrument + +LoadITInstrument1: + Mov AX, [DS:64000+1Eh] ; AX = number of samples + Mov DX, 80 + Mul DX ; Clears DX, AX = size in bytes + Mov CX, AX + +; Xor DX, DX +; Mov CX, DI + JCXZ LoadITInstrument2 + + Mov AH, 3Fh + Int 21h ; All sample headers are loaded too. + ; Step 2 done. + +LoadITInstrument2: + Ret + +EndP LoadITInstrument + +; + +InstrumentNameOffset DW 0 +XISampleOffset DD 0 + +; + +Proc LoadXIInstrument ; Must preserve DS, BX + + Push DS + Pop ES + + Mov DX, 63000 + Mov CX, 298 ; Length of instrument header + Mov AH, 3Fh + Int 21h + + Mov AX, [DS:63000+296] ; NoS + Mov CS:NumInstrumentSamples, AX + Mov CS:InstrumentNameOffset, 63000+21 + Mov CS:XISampleOffset, 298 + + ; Now to transfer data across + ; to 64000 in ITI format +LoadXIChain: + Mov DI, 64000 + Mov EAX, 'IPMI' ; Header + StosD + + Xor AX, AX + Mov CX, 8 + Rep StosW ; Filename, NNA, DCA, DCT + + Mov AX, [DS:63000+272] + Add AX, 15 + ShR AX, 5 + Cmp AX, 256 + JB LoadXIInstrumentFdOut + + Mov AX, 256 + +LoadXIInstrumentFdOut: + StosW ; Fadeout + + Mov AX, 60*256 + StosW ; PPC and PPS + Mov AX, 128+32*256 + StosW ; GBV and DfP + Xor AX, AX + StosW + StosW + Mov AX, CS:NumInstrumentSamples + StosW + Xor AX, AX + + Mov SI, CS:InstrumentNameOffset + Mov CX, 22/2 + Rep MovsW + Mov CX, 5 + Rep StosW ; Clear up end of inst name + + ; Translation table + Mov CX, 12 ; First 12 entries empty + Xor AX, AX + +LoadXIInstrument1: + StosW + Inc AX + Loop LoadXIInstrument1 + + Mov SI, 63000+66 + Mov CX, 96 + +LoadXIInstrument2: + Mov AH, [SI] + Inc AH + StosW + + Inc AX + Inc SI + Loop LoadXIInstrument2 + + Mov CX, 12 ; Last 12 entries empty + Xor AH, AH + +LoadXIInstrument3: + StosW + Inc AX + Loop LoadXIInstrument3 + + ; Now for volume envelope + Mov AL, [DS:63000+266] ; Flags + Mov CL, AL + Mov AH, AL + And AX, 402h + ShR AH, 1 + ShL AL, 1 + Or AL, AH + And CL, 1 + Or AL, CL + + Mov AH, [DS:63000+258] ; No of vol env nodes + Cmp AH, 12 + JB NumXIVolNodes1 + + Mov AH, 12 + +NumXIVolNodes1: + StosW + Mov AX, [DS:63000+261] ; Vol loop start+end + StosW + Mov AL, [DS:63000+260] ; Vol Sustain point + Mov AH, AL + StosW + + ; OK. now process volume env points + Mov CX, 12 + +LoadXIInstrument4: + Mov AL, [SI+2] + Cmp AL, 64 + JB LoadXICheckVolBound1 + + Mov AL, 64 + +LoadXICheckVolBound1: + StosB + MovsW + LodsW + Loop LoadXIInstrument4 + + Mov CX, 13*3+1 + Xor AX, AX + Rep StosB + + ; Now for panning envelope + +LoadXIInstrument5: + Mov AL, [DS:63000+267] ; Flags + Mov CL, AL + Mov AH, AL + And AX, 402h + ShR AH, 1 + ShL AL, 1 + Or AL, AH + And CL, 1 + Or AL, CL + + Mov AH, [DS:63000+259] ; No of pan env nodes + Cmp AH, 12 + JB NumXIPanNodes1 + + Mov AH, 12 + +NumXIPanNodes1: + StosW + Mov AX, [DS:63000+264] ; Pan loop start+end + StosW + Mov AL, [DS:63000+263] ; Pan Sustain point + Mov AH, AL + StosW + + ; OK. now process panning env points + Mov CX, 12 + Xor AH, AH + +LoadXIInstrument6: + Mov AL, [SI+2] + Cmp AL, 64 + JB LoadXICheckPanBound + + Mov AL, 64 + +LoadXICheckPanBound: + Sub AL, 32 + StosB + MovsW + LodsW ; Add SI, 2 + Loop LoadXIInstrument6 + + Mov CX, 13*3+1 + Xor AX, AX + Rep StosB + + ; Now for pitch envelope + Mov AX, 2*256 ; 2 node points + StosW + Xor AX, AX + StosW + StosW + + ; First node is 0, 0, second node is 0, 99 + StosW + StosW + Mov AX, 99 + StosW + + Mov CX, 75-6 + Xor AX, AX + Rep StosB + + Cmp Byte Ptr [DS:64000+131h], 2 + JAE LoadXIInstrumentVolEnvelopeCheck1 + + Mov Byte Ptr [DS:64000+131h], 2 + Mov Word Ptr [DS:64000+136h], 64 + Mov Word Ptr [DS:64000+138h], 64*256 + Mov Word Ptr [DS:64000+13Ah], 100 + +LoadXIInstrumentVolEnvelopeCheck1: + + Cmp Byte Ptr [DS:64000+183h], 2 + JAE LoadXIInstrumentPanEnvelopeCheck1 + + Mov Byte Ptr [DS:64000+183h], 2 + Xor AX, AX + Mov [DS:64000+188h], AX + Mov [DS:64000+18Ah], AX + Mov Word Ptr [DS:64000+18Ch], 100 + +LoadXIInstrumentPanEnvelopeCheck1: + + ; OK. instrument done. + ; Now have to load samples + ; Bytes to load = 40*NoS + Mov AX, 40 + Mul Word Ptr [DS:64000+1Eh] + Mov CX, AX + + Mov DX, 62000 + Mov AH, 3Fh + Int 21h + + Mov EDX, CS:XISampleOffset ; EDX = offset in file + Add DX, CX + + Xor DI, DI + Mov SI, 62000 + Mov CX, [DS:64000+1Eh] + +LoadXISample1: + Push CX + + Mov EAX, 'SPMI' + StosD + Xor AX, AX + Mov CX, 6 + Rep StosW + Mov AX, 64*256 + StosW + ; Flg +LoadXISample2: + Mov AH, [SI+12] ; Default volume + Mov AL, 0 + Cmp DWord Ptr [SI], 0 ; Length = 0? + JE LoadXISample4 + + Mov AL, 1 + + Mov CL, [SI+14] + Test CL, 10h + JZ LoadXISample3 + + Or AL, 2 ; 16-bit sample + +LoadXISample3: + And CL, 3 + JZ LoadXISample4 ; No loop + ; CL = 1 or 2 + Cmp DWord Ptr [SI+8], 1 + JBE LoadXISample4 + + Or AL, 10h ; Loop + Dec CX + ShL CL, 6 + Or AL, CL + +LoadXISample4: + StosW + + Push SI + ; Copy sample name + Add SI, 18 + Mov CX, 22/2 + Rep MovsW + Xor AX, AX + StosW + StosW + + Pop SI + ; Conversion flags, default pan + Mov AL, 5 + Mov AH, [SI+15] ; Pan + ShR AH, 2 + AdC AH, 80h + StosW + + Mov EAX, [SI] + Call LoadXISample5 + Mov EAX, [SI+4] + Call LoadXISample5 + Mov EAX, [SI+4] + Add EAX, [SI+8] + Call LoadXISample5 + + ; C5speed.. + Push ES + Push DI + + Call Music_GetPitchTable ; Returns ES:DI + Mov AL, [SI+16] ; Relative note number + Add AL, 60 ; AL = note multiplier + And AX, 0FFh + ShL AX, 2 + Add DI, AX + Mov ECX, [ES:DI] + + Mov AL, [SI+13] ; Finetune, -128->+127 + SAR AL, 4 ; Finetune = -8->+7 + And AX, 0Fh + Add AX, AX + Mov DI, AX + MovZX EAX, [CS:FineTuneTable+DI] + + Pop DI + Pop ES + + Push EDX + + Mul ECX + ShRD EAX, EDX, 16 + Pop EDX + StosD ; C5freq + + Xor AX, AX + StosW + StosW + StosW + StosW + + Mov EAX, EDX + Add EDX, [SI] + StosD + Xor AX, AX + StosW + StosW + + Pop CX + Add SI, 40 + Loop LoadXISample1 + + Ret + +LoadXISample5: + Cmp EAX, 4177910 + JB LoadXISample6 + + Mov EAX, 4177910 +LoadXISample6: + Test Byte Ptr [SI+14], 10h + JZ LoadXISample7 + + ShR EAX, 1 + +LoadXISample7: + StosD + RetN + +EndP LoadXIInstrument + +; + +Proc LoadInITInstrument + + Mov AH, 3Fh + Mov CX, 2000 + Mov DX, 62000 + Int 21h ; Read header into 62000 + + Mov AX, 4200h + Mov CX, Word Ptr [CS:LoadInstrumentOffset+2] + Mov DX, Word Ptr [CS:LoadInstrumentOffset] + Int 21h ; Goto location + + Mov AH, 3Fh ; Load instrument data + Mov CX, 554 + Mov DX, 64000 + Int 21h + + Cmp Word Ptr [DS:62000+2Ah], 200h + JAE LoadInITInstrument1 + + Mov SI, 64000 + Call ConvertOldInstrument + +LoadInITInstrument1: ; Convert Note table and load + ; Sample headers. + Mov SI, 64000+41h + Xor CX, CX + +LoadInITInstrument2: + Mov DI, [SI] + And DI, 0FFh ; DI = sample number + JZ LoadInITInstrument3 + Cmp DI, [DS:62000+24h] ; Sample exists? + JA LoadInITInstrument3 + Cmp Byte Ptr [CS:InstrumentTable+DI], 0 + JNE LoadInITInstrument3 + + Inc CX ; CL = sample number + Mov [CS:InstrumentTable+DI], CL + + Push SI + Push CX + + Add DI, [DS:62000+22h] + ShL DI, 2 + Add DI, [DS:62000+20h] + Add DI, 62000+0C0h-4 ; Samples are 0 based, not 1 + + Mov AX, 4200h ; Move to offset of sample + Mov CX, [DI+2] + Mov DX, [DI] + Int 21h + + Pop AX + Push AX + + Dec AX + Mov CX, 80 + Mul CX + Mov DX, AX + + Mov AH, 3Fh + Int 21h ; Load sample header. + + Pop CX + Pop SI + +LoadInITInstrument3: + Add SI, 2 + Cmp SI, 64000+41h+120*2 + JB LoadInITInstrument2 + + Mov [DS:64000+1Eh], CX + + ; Process translation table + Mov SI, 64000+41h + +LoadInITInstrument4: + Mov DI, [SI] + And DI, 0FFh + Mov AL, [CS:InstrumentTable+DI] + Mov [SI], AL + + Add SI, 2 + Cmp SI, 64000+41h+120*2 + JB LoadInITInstrument4 + + Mov DI, Offset InstrumentTable + Xor AX, AX + Mov CX, 50 + Rep StosW + + Ret + +EndP LoadInITInstrument + +; + +Proc LoadInXMInstrument + + Mov AX, 4200h + Mov CX, Word Ptr [CS:LoadInstrumentOffset+2] + Mov DX, Word Ptr [CS:LoadInstrumentOffset] + Int 21h ; Goto location + + Mov AH, 3Fh + Mov CX, 4 + Mov DX, 63000 + Int 21h + + Mov AH, 3Fh + Mov CX, [DS:63000] + Sub CX, 4 + Mov DX, 63033+4 + Int 21h + + Mov AX, [DS:63033+27] + Mov CS:NumInstrumentSamples, AX + Mov CS:InstrumentNameOffset, 63033+4 + + Mov AX, 4201h + Xor CX, CX + Xor DX, DX + Int 21h ; DX:AX = fileoffset + + Mov Word Ptr [CS:XISampleOffset], AX + Mov Word Ptr [CS:XISampleOffset+2], DX + + Push DS + Pop ES + + Jmp LoadXIChain + +EndP LoadInXMInstrument + +; + +Proc TransferInstrumentName + + Mov AX, 48 + Mul CS:NumInstruments + Inc CS:NumInstruments + + Mov DI, AX + + Push DS + + Push CS + Pop DS + + Mov AL, CL + StosB + Mov SI, Offset InInstrumentFileName + Mov CX, 14 + Rep MovsB + Mov EAX, LoadInstrumentOffset + Mov [ES:DI+44-15], EAX + + Pop DS + + Ret + +EndP TransferInstrumentName + +; + +; 'InstrumentTable' scratchpad + +LoadInstrumentOffset DD 0 +NumInstrumentSamples DW 0 + +Proc LoadITInModuleInstrument + + Mov AH, 3Fh + Mov CX, 2000 + Mov DX, 63000 + Int 21h + + Xor BP, BP + + Push ES + + Push CS ; Clear InstrumentTable + Pop ES + + Mov DI, Offset InstrumentTable + Mov CX, 100 + Xor AL, AL + Rep StosB + + Pop ES + +LoadITInModuleInstrument1: + Cmp BP, [DS:63000+22h] ; InsNum + JB LoadITInmoduleInstrument2 + + Ret + +LoadITInModuleInstrument2: + Mov SI, BP + ShL SI, 2 + + Inc BP + + Add SI, [DS:63000+20h] + Add SI, 63000+0C0h + + Mov AX, 4200h ; Move file pointer. + Mov CX, [SI+2] + Mov DX, [SI] + + Mov Word Ptr [CS:LoadInstrumentOffset], DX + Mov Word Ptr [CS:LoadInstrumentOffset+2], CX + + Int 21h + + Mov AH, 3Fh + Mov CX, 554 + Mov DX, 62000 + Int 21h + + Mov SI, 62000+41h + +LoadITInModuleInstrument3: + LodsW + And AX, 0FFh + Mov DI, AX + + Cmp AL, 100 + JAE LoadITInModuleInstrument5 + + Mov [CS:InstrumentTable+DI], 1 + +LoadITInModuleInstrument5: + Cmp SI, 62000+41h+120*2 + JB LoadITInModuleInstrument3 + + ; Now to count samples + ; and clear table. + Mov DI, 99 + Xor DX, DX ; DX = number of samples. + +LoadITInModuleInstrument4: + Cmp Byte Ptr [CS:InstrumentTable+DI], 1 + JNE LoadITInModuleInstrument6 + + Inc DX + Mov Byte Ptr [CS:InstrumentTable+DI], 0 + +LoadITInModuleInstrument6: + Dec DI + JNZ LoadITInModuleInstrument4 + + Test DX, DX + JZ LoadITInModuleInstrument1 + + Push DX + + Mov CL, 5 ; In-Module .IT Instrument + Call TransferInstrumentName + + Mov SI, 62000+20h + Mov CX, 25 + Rep MovsB + + Pop AX + StosW + Xor AX, AX + StosW + + Jmp LoadITInModuleInstrument1 + +EndP LoadITInModuleInstrument + +; + +Proc LoadXMInModuleInstrument + + Call LoadXMHeader ; Reads to first instrument + + Xor BP, BP + +LoadXMInModuleInstrument1: + Cmp BP, [DS:64000+72] + JB LoadXMInModuleInstrument2 + + Ret + +LoadXMInModuleInstrument2: + Inc BP + + Mov AX, 4201h + Xor CX, CX + Xor DX, DX + Int 21h ; Get current file location + + Mov Word Ptr [CS:LoadInstrumentOffset], AX + Mov Word Ptr [CS:LoadInstrumentOffset+2], DX + + Mov AH, 3Fh + Mov CX, 4 + Mov DX, 63000 + Int 21h ; Read instrument size field + + Mov AH, 3Fh + Mov CX, [DS:63000] + Sub CX, 4 + Mov DX, 63004 + Int 21h + + Mov AX, [DS:63000+27] ; Number of samples + Test AX, AX + JZ LoadXMInModuleInstrument1 + + Mov CX, 40 + Mul CX + Mov CX, AX + Mov AH, 3Fh + Mov DX, 62000 + Int 21h ; OK sample headers read + ; into DS:62000 + + Mov CL, 6 ; In-Module .XM Instrument + Call TransferInstrumentName + + Mov SI, 63004 + Mov CX, 22 + Rep MovsB + Xor AX, AX + StosB + StosW + + Mov AX, [DS:63000+27] + Mov CX, AX + StosW + Xor AX, AX + StosW + + Xor EDX, EDX + Mov SI, 62000 + +LoadXMInModuleInstrument3: + Add EDX, [SI] + Add SI, 40 + + Dec CX + JNZ LoadXMInModuleInstrument3 + + SHLD ECX, EDX, 16 + Mov AX, 4201h + Int 21h + ; Advance file pointers.. + Jmp LoadXMInModuleInstrument1 + +EndP LoadXMInModuleInstrument + +; diff --git a/it/IT_D_RIS.INC b/it/IT_D_RIS.INC new file mode 100644 index 0000000..9759404 --- /dev/null +++ b/it/IT_D_RIS.INC @@ -0,0 +1,1498 @@ +; +; +; In-Module sample loaders have to place the information at Sample*96 bytes +; in ITS format into DiskDataArea. Provided with: +; BX = file handle, File at header section. +; DS, ES = DiskDataArea +; +; Variables to update: +; NumSamples (initialised to 1 before the call) +; +; Variables to use: +; InSampleDateTime (DWord) +; CS:InSampleFileName (13 bytes) +; +; + +Proc SoftBSWAP ; EAX, returns EAX + + Push EDX + + SHLD EDX, EAX, 16 ; DX:AX contains value. + XChg DH, AL + XChg DL, AH ; DX:AX in proper order now + ShL EAX, 16 + SHRD EAX, EDX, 16 + + Pop EDX + Ret + +EndP SoftBSWAP + +; + +Proc TransferFileName + + Mov EAX, 'SPMI' + StosD + + Push DS + + Push CS + Pop DS + Assume DS:Disk + + Mov EAX, InSampleDateTime + + Mov SI, Offset InSampleFileName + Mov CX, 13 + Rep MovsB + + Pop DS + Assume DS:Nothing + + Mov [DI+54h-11h], EAX ; Date. + + Ret + +EndP TransferFileName + +; + +Proc LoadMODSamplesInModule + + Mov AH, 3Fh + Mov CX, 1084 + Mov DX, 63000 + Int 21h + + Xor CX, CX + Mov SI, 63952 + Mov AX, 07F00h + + +LoadMODSamplesInModule1: + LodsB + Cmp CL, AL + JAE LoadMODSamplesInModule2 + + Mov CL, AL + +LoadMODSamplesInModule2: + Dec AH + JNZ LoadMODSamplesInModule1 + + Inc CX ; CX = number of patterns to + ; load + + Mov AL, CS:InSampleChannels + Mul CL ; AX = Chan * patterns + + And EAX, 0FFFFh + ShL EAX, 8 + Add EAX, 1084 + Mov EBP, EAX ; EBP = location of first sample + + Mov SI, 63020 ; First sample + Mov CX, 31 + +LoadMODSamplesInModule3: + Push CX + Push SI + + Mov CX, [SI+22] + XChg CH, CL + Cmp CX, 1 + JBE LoadMODSamplesInModule4 + + ; OK.. have a sample + Mov AX, 96 + Mul CS:NumSamples + Mov DI, AX + + Inc CS:NumSamples + + Mov Byte Ptr [DI+88], 14 + Push SI + Call TransferFileName + Pop SI + + Mov AL, 64 + StosB + + Mov AH, [SI+25] ; Default volume + Mov AL, 1 + + Mov CX, [DS:SI+28] + XChg CH, CL + Cmp CX, 1 + JBE LoadMODSamplesInModule5 + + Or AL, 16 + +LoadMODSamplesInModule5: + StosW + + Mov CX, 22 + Rep MovsB + Xor EAX, EAX + StosD + + Mov AX, 32*256+1 ; Convert signed->Unsigned + StosW ; Default pan of 32 + + Mov AX, [SI] + XChg AH, AL + Add EAX, EAX + Mov [DI+20h], EAX ; File size + StosD ; Sample length + + Push EAX + + MovZX EAX, Word Ptr [SI+4] + XChg AH, AL + Add EAX, EAX + StosD ; Loop begin + + MovZX ECX, Word Ptr [SI+6] + XChg CH, CL + Add ECX, ECX + Add EAX, ECX + StosD ; Loop end + + Mov AL, [SI+2] + And AX, 15 + Mov SI, AX + Add SI, SI + Mov AX, [CS:FineTuneTable+SI] + StosW + Xor AX, AX + Mov CX, 5 + Rep StosW + + Mov EAX, EBP + StosD + Xor EAX, EAX + StosD + + Pop EAX + Add EBP, EAX + +LoadMODSamplesInModule4: + Pop SI + Pop CX + + Add SI, 30 + Loop LoadMODSamplesInModule3 + + Ret + +EndP LoadMODSamplesInModule + +; + +Proc LoadS3MSamplesInModule + + Mov AH, 3Fh + Mov CX, 2000 + Mov DX, 63000 + Int 21h + + Xor BP, BP + +LoadS3MSamplesInModule1: + Cmp BP, [DS:63000+22h] + JB LoadS3MSamplesInModule2 + + Ret + +LoadS3MSamplesInModule2: + Mov SI, BP + Add SI, SI + Add SI, [DS:63000+20h] + Inc BP + + Mov DX, [DS:63000+SI+60h] + Mov CX, DX + ShR CX, 12 + ShL DX, 4 + Mov AX, 4200h + Int 21h + ; Move to location + Mov DX, 62000 + Mov AH, 3Fh + Mov CX, 80h + Int 21h + + Cmp Byte Ptr [DS:62000], 1 + JNE LoadS3MSamplesInModule1 + Cmp DWord Ptr [DS:62000+10h], 0 + JE LoadS3MSamplesInModule1 + + Mov AX, 96 + Mul CS:NumSamples + Mov DI, AX + + Mov Byte Ptr [DI+88], 3 + Call TransferFileName + + Mov AL, 64 + StosB + + Mov AL, [DS:62000+1Fh] ; Flag + Mov AH, AL + And AX, 401h + ShR AH, 1 + ShL AL, 4 + Or AL, AH + Or AL, 1 + Mov AH, [DS:62000+1Ch] ; Default volume + StosW + + Mov SI, 62000+30h + Mov CX, 25 + Rep MovsB + Xor AX, AX + StosW + Mov AL, 32 + StosB + + ; Length + Mov EAX, [DS:62000+10h] + StosD + Test Byte Ptr [DS:62000+1Fh], 4 + JZ LoadS3MSamplesInModule3 + + Add EAX, EAX + +LoadS3MSamplesInModule3: + Mov [DI+20h-4], EAX ; File size + + Mov EAX, [DS:62000+14h] + StosD + Mov EAX, [DS:62000+18h] + StosD + Mov EAX, [DS:62000+20h] + StosD + Xor AX, AX + StosW + StosW + StosW + StosW + ; Sample pointer.. + Mov AL, [DS:62000+0Dh] + ShL EAX, 16 + Mov AX, [DS:62000+0Eh] + ShL EAX, 4 + StosD + Xor AX, AX + StosW + StosW + + Inc CS:NumSamples + Jmp LoadS3MSamplesInModule1 + +EndP LoadS3MSamplesInModule + +; + +Proc LoadFARSamplesInModule + + Mov AH, 3Fh + Mov CX, 98 + Mov DX, 63000 + Int 21h + + Mov AX, 4201h + Xor CX, CX + Mov DX, [DS:63000+96] + Int 21h ; Removes song message + + Mov AH, 3Fh + Mov CX, 869-98 + Mov DX, 63000+98 + Int 21h + +; Xor CX, CX +; Mov CL, [DS:63000+354] ; CX = number of patterns + + Mov CX, 256 + +Comment ~ + + Xor CX, CX + Mov CL, [DS:63000+355] + Mov SI, 63000+98 + Xor AH, AH + ; Have to find CX from order list, apparently... + +LoadFARSamplesInModule7: + LodsB + Cmp AL, 0FFh + JE LoadFARSamplesInModule8 + Cmp AL, AH + JB LoadFARSamplesInModule8 + + Mov AH, AL + +LoadFARSamplesInModule8: + Loop LoadFARSamplesInModule7 + + Mov CL, AH + Inc CX + + ~ + + Mov SI, 63000+357 + Xor AX, AX + Xor DX, DX + +LoadFARSamplesInModule1: + Add AX, [SI] + AdC DX, 0 + Add SI, 2 + Loop LoadFARSamplesInModule1 + + ; DX:AX = length of patterns. + Mov CX, DX + Mov DX, AX + Mov AX, 4201h + Int 21h ; OK.. skipped past patterns. + + Mov AH, 3Fh + Mov CX, 8 + Mov DX, 64000 + Int 21h ; Read sample map. + + ; Determine number of samples... + Xor SI, SI ; SI = number of samples + + Mov EDX, [DS:64004] + Mov EAX, [DS:64000] + Mov CX, 64 + +LoadFARSamplesInModule2: + Test AL, 1 + JZ LoadFARSamplesInModule3 + + Inc SI + +LoadFARSamplesInModule3: + ShR EDX, 1 + RCR EAX, 1 + Loop LoadFARSamplesInModule2 + ; OK.. SI = number of samples.. + Mov [DS:65000], SI + + Mov AX, 48 + Mul SI + Mov SI, AX ; SI = number of bytes for sample header + + Mov AX, 4201h + Xor CX, CX + Xor DX, DX + Int 21h + ; DX:AX = position in file. + Add AX, SI + AdC DX, 0 ; DX:AX = position in file of first sam + + Xor BP, BP + +LoadFARSamplesInModule4: + Cmp BP, [DS:65000] + JB LoadFARSamplesInModule5 + + Ret + +LoadFARSamplesInModule5: + Inc BP + + Mov DX, 62000 + Mov AH, 3Fh + Mov CX, 48 + Int 21h + + Cmp DWord Ptr [DS:62000+32], 0 + JE LoadFARSamplesInModule4 + + Mov AX, 96 + Mul CS:NumSamples + Mov DI, AX + + Mov Byte Ptr [DI+88], 12 ; FAR sample + Call TransferFileName + + Mov AL, 64 + StosB ; Global volume + + Mov AX, [DS:62000+46] ; 8/16 bit in bit 0 + ; loop in bit 3 of AH + And AX, 801h + ShL AX, 1 + Or AL, AH + Or AL, 1 + Mov DL, AL + Mov AH, 64 + StosW + + Mov SI, 62000 + Mov CX, 25 + +LoadFARSamplesInModule6: + LodsB + StosB + Test AL, AL + LoopNZ LoadFarSamplesInModule6 + + Xor AL, AL + Inc CX + Rep StosB + Mov AX, 1+32*256 + StosW + + Mov EAX, [DS:62000+32] + Mov [DI+20h], EAX ; File size + Call LoadPTMSamplesInModule4 + Mov EAX, [DS:62000+38] ; Begin + Call LoadPTMSamplesInModule4 + Mov EAX, [DS:62000+42] ; End + Call LoadPTMSamplesInModule4 + + Mov AX, 8363 + StosW + Xor AX, AX + Mov CX, 5 + Rep StosW + + ; Get current position in file + Mov AX, 4201h + Xor CX, CX + Xor DX, DX + Int 21h + StosW + Mov AX, DX + StosW + + Xor AX, AX + StosW + StosW + + Mov AX, 4201h + Mov CX, [DS:62000+34] + Mov DX, [DS:62000+32] + Int 21h + + Cmp DWord Ptr [DS:62000+32], 1 + JBE LoadFARSamplesInModule4 + + Inc CS:NumSamples + Jmp LoadFARSamplesInModule4 + +EndP LoadFARSamplesInModule + +; + +Proc LoadMTMSamplesInModule + + Mov AH, 3Fh + Mov CX, 66 ; Read header + Mov DX, 63000 + Int 21h + + ; Sample pos = LastsamplePos+Length + ; So.. setup first sample with no length + Mov AH, 64 + Mov AL, [DS:63000+26] + Inc AX + Mul AH + Mov CX, AX ; CX = 64*(LastPatternSaved+1) + + Mov AL, 37 + Mul Byte Ptr [DS:63000+30] ; NOS + Add CX, AX ; CX = NOS*37+64*(LastPatternSaved+1) + Add CX, [DS:63000+28] + Add CX, 194 ; CX = 194+NOS*37+Lngth of comment+... + + Mov AX, 192 + Mul Word Ptr [DS:63000+24] ; Tracks saved + + Add AX, CX + AdC DX, 0 + + Mov [DS:48h], AX + Mov [DS:4Ah], DX + + Mov DWord Ptr [DS:30h], 0 + + Mov Byte Ptr [DS:63000+31], 0 + Xor BP, BP + +LoadMTMSamplesInModule1: + Cmp BP, [DS:63000+30] + JB LoadMTMSamplesInModule2 + + Ret + +LoadMTMSamplesInModule2: + Inc BP + + Mov DX, 62000 + Mov AH, 3Fh + Mov CX, 37 + Int 21h + + Cmp DWord Ptr [DS:62000+22], 0 + JE LoadMTMSamplesInModule1 + + Mov AX, 96 + Mul CS:NumSamples + Mov DI, AX + + Mov Byte Ptr [DI+88], 10 ; MTM sample + Call TransferFileName + + Mov AL, 64 + StosB ; Global volume + + Mov AL, 1 + + Mov ECX, [DS:62000+30] + Sub ECX, [DS:62000+26] + + Cmp ECX, 2 + JLE LoadMTMSamplesInModule3 + + Mov AL, 11h ; Loop + sample. + +LoadMTMSamplesInModule3: + Mov AH, [DS:62000+35] + StosW + ; Sample name now.. + Mov SI, 62000 + Mov CX, 22 + +LoadMTMSamplesInModule4: + LodsB + StosB + Test AL, AL + LoopNZ LoadMTMSamplesInModule4 + + Xor AX, AX + Add CX, 4 + Rep StosB + + Mov AH, 32 + StosW + + Mov EAX, [DS:62000+22] + Mov [DI+20h], EAX + StosD + Mov EAX, [DS:62000+26] + StosD + Mov EAX, [DS:62000+30] + StosD + + Mov AL, [DS:62000+34] + And AX, 0Fh + Mov SI, AX + Add SI, SI + Mov AX, [CS:FineTuneTable+SI] + StosW + Xor AX, AX + Mov CX, 5 + Rep StosW + + ; Sample pointer... + Mov EAX, [DI-96] ; Last sample pointer + Add EAX, [DI-96-18h] ; Last sample length + StosD + + Xor AX, AX + StosW + StosW + + Inc CS:NumSamples + Jmp LoadMTMSamplesInModule1 + +EndP LoadMTMSamplesInModule + +; + +Comment ~ + +Proc LoadULTSamplesInModule + + Mov AH, 3Fh + Mov CX, 48 ; Read 48 bytes. + Mov DX, 63000 + Int 21h + + Xor DH, DH + Mov DL, [DS:63000+47] + ShL DX, 5 ; CX = CX * 32 + Xor CX, CX + Mov AX, 4201h + Int 21h ; Seek.. + + Mov AH, 3Fh + Mov CX, 1 + Mov DX, 63000+48 + Int 21h ; Read 1 byte.. + Mov Byte Ptr [DS:63000+49], 0 + + Ret + +EndP LoadULTSamplesInModule + + ~ + +; + +Proc Load669SamplesInModule + + Mov AH, 3Fh + Mov CX, 1F1h + Mov DX, 63000 + Int 21h + + Mov AL, 19h + Mul Byte Ptr [DS:63000+6Eh] + Mov CX, AX + Add CX, 1F1h + + Mov AL, [DS:63000+6Fh] + Xor AH, AH + Mov DX, 600h + Mul DX + + Add AX, CX + AdC DX, 0 + + Mov [DS:48h], AX + Mov [DS:4Ah], DX + + Mov DWord Ptr [DS:30h], 0 + + Mov Byte Ptr [DS:63000+6Fh], 0 + Xor BP, BP + +Load669SamplesInModule1: + Cmp BP, [DS:63000+6Eh] + JB Load669SamplesInModule2 + + Ret + +Load669SamplesInModule2: + Inc BP + + Mov AH, 3Fh + Mov CX, 19h + Mov DX, 62000 + Int 21h + + Cmp DWord Ptr [DS:62000+13], 0 + JE Load669SamplesInModule1 + + Mov AX, 96 + Mul CS:NumSamples + Mov DI, AX + + Mov Byte Ptr [DI+88], 11 ; 669 sample + Call TransferFileName + + Mov AL, 64 + StosB ; Global volume + + Mov AL, 1 + + Mov ECX, [DS:62000+21] + Cmp ECX, [DS:62000+13] + JA Load669SamplesInModule3 + + Mov AL, 11h ; Loop + sample. + +Load669SamplesInModule3: + Mov DL, AL + Mov AH, 64 + StosW + + ; Sample name + Mov SI, 62000 + Mov CX, 13 + Rep MovsB + + Xor AX, AX + Mov CX, 13 + Rep StosB + + Mov AH, 32 + StosW + + Mov SI, 62000+13 + LodsD + Mov [DI+20h], EAX + StosD + MovsD + Test DL, 10h + JZ Load669SamplesInModule4 + + MovsD + Jmp Load669SamplesInModule5 + +Load669SamplesInModule4: + Xor AX, AX + StosW + StosW + +Load669SamplesInModule5: + Mov AX, 8363 + StosW + Xor AX, AX + Mov CX, 5 + Rep StosW + + ; Sample pointer... + Mov EAX, [DI-96] ; Last sample pointer + Add EAX, [DI-96-18h] ; Last sample length + StosD + + Xor AX, AX + StosW + StosW + + Inc CS:NumSamples + Jmp Load669SamplesInModule1 + +EndP Load669SamplesInModule + + +; + +Proc LoadPTMSamplesInModule + + Mov AH, 3Fh + Mov CX, 608 ; Read 608 bytes. + Mov DX, 63000 + Int 21h + + Xor BP, BP + +LoadPTMSamplesInModule1: + Cmp BP, [DS:63000+34] + JB LoadPTMSamplesInModule2 + + Ret + +LoadPTMSamplesInModule2: + Inc BP + + Mov DX, 62000 + Mov AH, 3Fh + Mov CX, 80 + Int 21h + + Mov AL, [DS:62000] + And AL, 3 + Cmp AL, 1 + JNE LoadPTMSamplesInModule1 + Cmp DWord Ptr [DS:62000+22], 0 + JE LoadPTMSamplesInModule1 + + Mov AX, 96 + Mul CS:NumSamples + Mov DI, AX + + Mov Byte Ptr [DI+88], 9 ; PTM sample + Call TransferFileName + + Mov AL, 64 + StosB ; Global volume + + Mov CL, [DS:62000] ; AL, Bit 0-1 = sample + ; Bit 2 = loop + ; Bit 3 = loop dirn + ; Bit 4 = 8/16 bit + Mov AL, CL + Mov AH, CL + And AX, 1004h + ShL AL, 2 + And CL, 8 + ShR AH, 3 + ShL CL, 3 + Or AL, AH + Or AL, CL + Or AL, 1 + Mov DL, AL + Mov AH, [DS:62000+13] ; Default volume + StosW ; Flag + default volume + + Mov SI, 62000+30h ; Sample name + Mov CX, 25 + Rep MovsB + Xor AX, AX + StosB + + Mov AX, 9+32*256 ; Conversion flag + default pan + StosW + + ; Length + Mov EAX, [DS:62000+22] + Mov [DI+20h], EAX ; File size + Call LoadPTMSamplesInModule4 + Mov EAX, [DS:62000+26] ; Begin + Call LoadPTMSamplesInModule4 + Mov EAX, [DS:62000+30] ; End + Call LoadPTMSamplesInModule4 + Xor EAX, EAX + Mov AX, [DS:62000+14] ; C5Freq + StosD + Xor AX, AX + StosW + StosW + StosW + StosW + ; Sample pointer.. + Mov EAX, [DS:62000+18] + StosD + Xor AX, AX + StosW + StosW + + Inc CS:NumSamples + Jmp LoadPTMSamplesInModule1 + +LoadPTMSamplesInModule4: + Test DL, 2 + JZ LoadPTMSamplesInModule5 + + ShR EAX, 1 + +LoadPTMSamplesInModule5: + StosD + RetN + +EndP LoadPTMSamplesInModule + +; + +Proc LoadITSamplesInModule ; DS, ES = DiskDataArea + + Mov AH, 3Fh + Mov CX, 2000 + Mov DX, 63000 + Int 21h ; Loaded module + + Xor BP, BP ; DX = number of samples + +LoadITSamplesInModule1: + Cmp BP, [DS:63000+24h] ; Num Samples + JB LoadITSamplesInModule2 + + Ret + +LoadITSamplesInModule2: + Mov SI, [DS:63000+22h] + Add SI, BP + ShL SI, 2 ; DX = (NumInstrument+NumSamples)*4 + Add SI, [DS:63000+20h] + Inc BP + + Mov DX, [DS:63000+SI+0C0h] + Mov CX, [DS:63000+SI+0C0h+2] + + Mov AX, 4200h + Int 21h + ; OK. file pointer moved to sample header. + ; Memory region to copy it to is BP*96 + + Mov AX, 96 + Mul CS:NumSamples + + Mov DX, AX + Mov DI, DX + Mov AH, 3Fh + Mov CX, 80 + Int 21h + + Mov CL, [DI+12h] + Test CL, 1 + JZ LoadITSamplesInModule1 + + Mov EAX, [DI+30h] ; Length + Test CL, 2 + JZ LoadITSamplesInModule3 + + Add EAX, EAX + +LoadITSamplesInModule3: + Mov [DI+50h], EAX + + Mov Byte Ptr [DI+88], 2 + Call TransferFileName + + Inc CS:NumSamples + Jmp LoadITSamplesInModule1 + +EndP LoadITSamplesInModule + +; + +Proc LoadXMHeader + + Mov AH, 3Fh + Mov CX, 74 + Mov DX, 64000 + Int 21h ; Loaded module + + Mov AX, 4200h ; Seek to position from start of module + Mov DX, [DS:64000+60] + Mov CX, [DS:64000+62] + Add DX, 60 + Int 21h + + Xor BP, BP ; BP = pattern counter + ; At first pattern +LoadXMSamplesInModule1: + Cmp BP, [DS:64000+70] ; Number of patterns + JAE LoadXMSamplesInModule2 + + ; Load 4 bytes. + Mov AH, 3Fh + Mov CX, 9 ; Read standard header + Mov DX, 63000 + Int 21h + + Mov AX, 4201h + Xor CX, CX + Mov DX, [DS:63000] + Add DX, [DS:63000+7] + Sub DX, 9 + Int 21h + + Inc BP + Jmp LoadXMSamplesInModule1 + +LoadXMSamplesInModule2: ; OK.. at first instrument + + Ret + +EndP LoadXMHeader + +; + +Proc LoadXMSamplesInModule + + Call LoadXMHeader + + Xor BP, BP + +LoadXMSamplesInModule3: + Cmp BP, [DS:64000+72] + JB LoadXMSamplesInModule4 + + Ret + +LoadXMSamplesInModule4: + Inc BP + + Mov AH, 3Fh + Mov CX, 4 + Mov DX, 63000 + Int 21h ; Read instrument size field + + Mov AH, 3Fh + Mov CX, [DS:63000] + Sub CX, 4 + Mov DX, 63004 + Int 21h + + Mov AX, [DS:63000+27] ; Number of samples + Test AX, AX + JZ LoadXMSamplesInModule3 + + ; Bytes to read = AX*40 + Mov CX, 40 + Mul CX + Mov CX, AX + Mov AH, 3Fh + Mov DX, 62000 + Int 21h ; OK sample headers read + ; into DS:62000 + + Push BP + Xor BP, BP + Xor EDX, EDX ; EDX = number of bytes to adv + +LoadXMSamplesInModule5: + Cmp BP, [DS:63000+27] ; Number of samples + JB LoadXMSamplesInModule6 + + SHLD ECX, EDX, 16 + Mov AX, 4201h + Int 21h ; Advance file pointer + + Pop BP + Jmp LoadXMSamplesInModule3 + +LoadXMSamplesInModule6: + Push EDX + + Mov AX, 40 + Mul BP + Mov SI, AX + Add SI, 62000 + + Pop EDX + Inc BP + + Cmp DWord Ptr [DS:SI], 0 ; Sample length = 0?? + JE LoadXMSamplesInModule5 + + Push EDX + + Mov AX, 96 + Mul CS:NumSamples + Mov DI, AX + + Push SI + + Mov Byte Ptr [DI+88], 8 + Call TransferFileName + + Mov AL, 64 + StosB + + Pop SI + + Mov AH, [SI+12] ; Default volume + Mov AL, 1 + + Mov CL, [SI+14] + Test CL, 10h + JZ LoadXMSamplesInModule7 + + Or AL, 2 ; 16-bit sample + +LoadXMSamplesInModule7: + And CL, 3 + JZ LoadXMSamplesInModule8 ; No loop + ; CL = 1 or 2 + + Cmp DWord Ptr [SI+8], 1 + JBE LoadXMSamplesInModule8 + + Or AL, 10h ; Loop + Dec CX + ShL CL, 6 + Or AL, CL + +LoadXMSamplesInModule8: + StosW + + Push SI + ; Sample name + Add SI, 18 + Mov CX, 22/2 + Rep MovsW + + Pop SI + + Xor AX, AX ; Cleanup + conversion flags + StosW + StosW + Mov AH, [SI+15] ; Default pan + ShR AH, 2 + AdC AH, 80h + Mov AL, 5 ; Delta values, signed + StosW + + Mov EAX, [SI] + Mov [DI+20h], EAX ; File size + Call LoadXISample5 + Mov EAX, [SI+4] + Call LoadXISample5 + Mov EAX, [SI+4] + Add EAX, [SI+8] + Call LoadXISample5 + + ; C5speed.. + Push ES + Push DI + + Call Music_GetPitchTable ; Returns ES:DI + Mov AL, [SI+16] ; Relative note number + Add AL, 60 ; AL = note multiplier + And AX, 0FFh + ShL AX, 2 + Add DI, AX + Mov ECX, [ES:DI] + + Mov AL, [SI+13] ; Finetune, -128->+127 + SAR AL, 4 ; Finetune = -8->+7 + And AX, 0Fh + Add AX, AX + Mov DI, AX + MovZX EAX, [CS:FineTuneTable+DI] + + Pop DI + Pop ES + + Mul ECX + ShRD EAX, EDX, 16 + StosD ; C5freq + + Xor AX, AX + StosW + StosW + StosW + StosW + ; Now position + Mov AX, 4201h + Xor CX, CX + Xor DX, DX + Int 21h ; Returns file position in DX:AX + + Push AX + ShRD EAX, EDX, 16 + Pop AX + Pop EDX + Add EAX, EDX + StosD + Xor AX, AX + StosW + StosW + + Add EDX, [DS:SI] + Inc CS:NumSamples + Jmp LoadXMSamplesInModule5 + +EndP LoadXMSamplesInModule + +; + +KRZSampleOffset DD 0 +KRZSampleStartingOffset DD 0 +KRZFileOffset DD 0 + +Proc LoadKRZSamples + + Mov AH, 3Fh + Mov CX, 32 + Mov DX, 64000 + Int 21h + + Mov CS:KRZFileOffset, 32 + + Mov EAX, [DS:64000+4] ; Sample start offset + Call SoftBSWAP + + Mov CS:KRZSampleOffset, EAX + Mov CS:KRZSampleStartingOffset, EAX + +LoadKRZSamples1: + Mov EDX, CS:KRZFileOffset + Cmp EDX, CS:KRZSampleStartingOffset + JB LoadKRZSamples2 + + Ret + +LoadKRZSamples2: + Mov AX, 4200h ; Move to location in file + SHLD ECX, EDX, 16 + Int 21h + + Mov AH, 3Fh + Mov CX, 1000 + Mov DX, 64000 + Int 21h ; Load .KRZ object + + Mov AX, [DS:64000+6] ; Block size + XChg AH, AL + Add AX, 7 + And EAX, 0FFFCh + Add CS:KRZFileOffset, EAX + + Mov AX, [DS:64000+4] ; Sample object? + Cmp AL, 98h + JB LoadKRZSamples1 + Cmp AL, 9Bh + JA LoadKRZSamples1 + + Push BX + + Mov AX, 96 + Mul CS:NumSamples + Mov DI, AX + + Mov Byte Ptr [DI+88], 15 ; KRZ sample. + Call TransferFileName + + Mov AL, 64 ; Global volume + StosB + + Mov BX, [DS:64000+8] + XChg BH, BL + Add BX, 64000+20 + + ; BX points to start of + ; KRZSampleHdr + + Mov AX, 4003h ; Flags + Default volume + ; sample present, 16-bit + Mov DL, [BX+1] + + Test DL, 2 ; Bidir loop? + JZ LoadKRZSamples5 + + Or AL, 0C0h ; Ping pong + +LoadKRZSamples5: + Test DL, 80h ; Loop off? + JNZ LoadKRZSamples6 + + Mov ECX, [BX+16] + Cmp ECX, [BX+20] + JE LoadKRZSamples6 + + Or AL, 10h ; Loop on. + +LoadKRZSamples6: + StosW ; Flags + DFV done. + +; Sample name. + + Mov SI, 64000+10 + Mov CX, 26 + +LoadKRZSamples3: + LodsB + Test AL, AL + JZ LoadKRZSamples4 + StosB + Loop LoadKRZSamples3 + + Xor AL, AL + +LoadKRZSamples4: + Rep StosB + + Mov AX, 1+2+32*256 + StosW ; Signed sample, default pan = 32 + + ; Length + Mov EAX, [BX+8] + Call SoftBSWAP + Mov EBP, EAX + + Mov EAX, [BX+20] + Call SoftBSWAP + Sub EAX, EBP + StosD + Add EAX, EAX + Mov [DI+20h-4], EAX ; File size + + Mov EAX, [BX+16] ; start of loop + Call SoftBSWAP + Sub EAX, EBP + StosD + Mov EAX, [BX+20] + Call SoftBSWAP + Sub EAX, EBP + Cmp EAX, [ES:DI-4] + JB NextKRZ + StosD + + Mov EAX, [BX+28] + Call SoftBSWAP + Mov ECX, EAX + + Mov EAX, 22000 + Test ECX, ECX + JZ LoadKRZSamples7 + + Xor EDX, EDX + Mov EAX, 1000000000 + + Div ECX + Test EAX, EAX + JNZ LoadKRZSamples7 + + Mov EAX, 44100 + +LoadKRZSamples7: + StosD ; C5Speed + + Xor EAX, EAX + StosD + StosD + + Mov EAX, CS:KRZSampleOffset + Add EAX, EBP + Add EAX, EBP + StosD + + Xor EAX, EAX + StoSD + + Inc CS:NumSamples + +NextKRZ: + Pop BX + Jmp LoadKRZSamples1 + +EndP LoadKRZSamples + +; + +Proc StorePATLength + + Test DL, 1 ; 16-bit? + JZ StorePATLength1 + + ShR EAX, 1 + +StorePATLength1: + StosD + Ret + +EndP StorePATLength + +; + +Proc LoadPATSamples + + Mov AH, 3Fh + Mov CX, 129+63+47 ; 129 bytes for file header, 63 for + ; instrument header, 47 for layer + Mov DX, 65000 + Int 21h + + Mov BP, [DS:65000+129+63+6] + And BP, 0FFh ; BP = number of waves. + +LoadPATSamples1: + Mov AH, 3Fh + Mov DX, 64000 + Mov CX, 96 + Int 21h ; Read data in + + Mov AX, 96 + Mul CS:NumSamples + Mov DI, AX + + Inc CS:NumSamples + + Mov Byte Ptr [DI+88], 16 ; GUS Patch + Call TransferFileName + + Mov AL, 64 ; Global volume + StosB + + Mov AX, 4001h ; sample present + Mov DL, [DS:64000+55] ; modes + + Test DL, 1 ; 8/16 bit + JZ LoadPATSamples2 + + Or AL, 2 + +LoadPATSamples2: + Test DL, 4 ; Looping enabled? + JZ LoadPATSamples3 + + Or AL, 10h + +LoadPATSamples3: + Test DL, 8 ; Ping pong loops? + JZ LoadPATSamples4 + + Or AL, 40h + +LoadPATSamples4: + StosW ; OK.. now for name. + + Mov SI, 65000+129+2 + Mov CX, 16 + +LoadPATSamples5: + LodsB + Test AL, AL + JZ LoadPATSamples6 + StosB + Loop LoadPATSamples5 + +LoadPATSamples6: + Add CX, 9 + + Mov AL, ':' + StosB + Mov SI, 64000 + +LoadPATSamples7: + LodsB + Test AL, AL + JZ LoadPATSamples8 + StosB + Loop LoadPATSamples7 + +LoadPATSamples8: + Xor AL, AL + Rep StosB + + ; Convert, default pan + + Mov AH, 32 + Mov AL, [DS:64000+55] + And AL, 2 + ShR AL, 1 + Xor AL, 1 + StosW + + ; Length. + + Mov DL, [DS:64000+55] + + Mov EAX, [DS:64000+16] ; ->Length + Mov [DI+20h], EAX ; File size + Call StorePATLength + + Mov EAX, [DS:64000+12] ; LoopBeg + Call StorePATLength + Mov EAX, [DS:64000+16] ; LoopEnd + Call StorePATLength + + Mov AX, [DS:64000+20] + And EAX, 0FFFFh + StosD ; C5Spd + + Xor EAX, EAX + StosD + StosD + + Mov AX, 4201h + Xor CX, CX + Xor DX, DX + Int 21h ; Current position. + + StosW + Mov AX, DX + StosW + + Xor AX, AX + StosW + StosW + + Mov AX, 4201h + Mov CX, [DS:64000+10] + Mov DX, [DS:64000+8] + Int 21h + + Dec BP + JNZ LoadPATSamples1 + + Ret + +EndP LoadPATSamples + +; + diff --git a/it/IT_D_RM.INC b/it/IT_D_RM.INC new file mode 100644 index 0000000..f9b0fb0 --- /dev/null +++ b/it/IT_D_RM.INC @@ -0,0 +1,2889 @@ +; +; +; Read module functions +; + +; + +IF TUTORIAL +ELSE + +Proc D_PreLoadModule ; Returns ES = song segment + ; BX = file handle + ; DS = Diskdata area + ; AX = SaveFormat + +; Call MouseUpdateEnable + +IF DEFAULTFORMAT + Test AL, AL + JNZ D_PreLoadModuleTemp + + Mov AL, DEFAULTFORMAT + +D_PreLoadModuleTemp: +ENDIF + Mov SaveFormat, AL + + Call I_ClearTables + Call Music_ReleaseAllPatterns + Call Music_ReleaseAllSamples + Call Music_ClearAllSampleNames + Call Music_ClearAllInstruments + Call Msg_ResetMessage + Call ReleaseTimerData + + Mov DS, CS:DiskDataArea + + Mov BX, CS:CurrentFile + Add BX, BX + Mov BX, [BX] + Add BX, 8 + + Push CS + Pop ES + Mov DI, Offset FileName ; OK... + Mov SI, BX ; Data area no longer + Mov CX, 13 ; reqd + Rep MovsB + + Mov AX, 3D00h + Mov DX, BX + Int 21h + JC D_LoadFileOpenErrorMsg + + Mov BX, AX ; BX = file handle. + + Call Music_GetSongSegment + Mov ES, AX + + Ret + +EndP D_PreLoadModule + +; + +Proc D_PostLoadModule Far + + Mov AH, 3Eh ; Close file. + Int 21h + + Push CS + Pop DS + Assume DS:Disk + + Call CheckTimerData + Call GetCurrentTime + + Mov [TopTimerData], 0 + + Call GetTimerCounter + Mov [EditTimer], EAX + + Call PE_ResetOrderPattern + +; Mov AX, 1 + Ret + +EndP D_PostLoadModule + Assume DS:Nothing + +; + +Proc D_InsertOrder ; DX = inserting pattern, BP = current + ; ES = songdata + PushA + Push DS + + Push ES + Pop DS + + Mov SI, 1FFh + Mov AX, BP + +D_InsertOrder1: + Cmp AL, [SI] + JE D_InsertOrder2 + +D_InsertOrderResume: + Dec SI + Cmp SI, 100h + JAE D_InsertOrder1 + + Pop DS + PopA + Ret + +D_InsertOrder2: + Push SI + Mov CX, 1FEh + Mov DI, 1FFh + Sub CX, SI + JC D_InsertOrder3 + + Mov SI, 1FEh + + StD + Rep MovsB + ClD + + Mov AL, DL + StosB + +D_InsertOrder3: + Pop SI + Jmp D_InsertOrderResume + +EndP D_InsertOrder + +; + +Proc D_LoadXM Far + + Xor AX, AX + Call D_PreLoadModule + Assume DS:Nothing + + Mov AH, 3Fh + Mov CX, 64 ; Header length + Mov DX, 64000 + Int 21h + + Mov AH, 3Fh ; Read rest of header. + Mov CX, [DS:64000+60] + Sub CX, 4 + Mov DX, 64104 + Int 21h + + Mov DI, 4 + Mov CX, 20 + Mov SI, 64000+17 + Rep MovsB + Xor AX, AX + Mov CX, 5 + Rep StosW ; OK name transferred. + + ; Number of Instruments + Mov AX, [DS:64100+12] + StosW ; Insnum + + Mov AX, 1 + StosW + + ; Number of Patterns + Mov AX, [DS:64100+10] + StosW + Mov [ES:0C0h], AX ; Number of patterns. + + ; CWT/V, CMWT + Add DI, 4 + + ; Flags + Mov AX, [DS:64100+14] + And AX, 1 + ShL AX, 3 + Or AX, 35h ; XM Effects, Old effects, stereo, insts + StosW + + ; Reserved + Xor AX, AX + StosW + + ; GVolume. MVolume + Mov AX, 128+48*256 + StosW + + ; Initial Speed, Initial Tempo + Mov AL, [DS:64100+16] + Test AL, AL + JNZ InitialSpeedNot0 + + Mov AL, 6 + +InitialSpeedNot0: + Mov AH, [DS:64100+18] + StosW + + ; Separation + Mov AX, 128 + StosW + + ; Message length, offset, timer + Xor AX, AX + Mov CX, 5 + Rep StosW + + ; Channel Pan + + Mov CX, [DS:64100+8] ; Number of channels + Mov AL, 32 + Rep StosB + Mov AL, 128+32 + Mov CX, 64 + Sub CX, [DS:64100+8] + Rep StosB + + ; Channel Volume + + Mov AL, 64 + Mov CX, 64 + Rep StosB + + ; Orders + Add DI, 40h + Mov SI, 64100+20 ; Orders + Mov CX, [DS:64100+4] ; Song legnth + JCXZ D_LoadXMNoPatterns2 + +D_FindMaximumPattern: + LodsB + Cmp AL, 200 + JAE D_FindMaximumPattern3 + + Cmp AL, [ES:0C0h] + JB D_FindMaximumPattern2 + + Inc AX + Mov [ES:0C0h], AX + Dec AX + Jmp D_FindMaximumPattern2 + +D_FindMaximumPattern3: + Mov AL, 0FFh + +D_FindMaximumPattern2: + StosB + Loop D_FindMaximumPattern + +D_LoadXMNoPatterns2: + Mov CX, 256 + Sub CX, [DS:64100+4] + Mov AL, 0FFh + Rep StosB + + ; OK.. now to load patterns. + Cmp Word Ptr [DS:64100+10], 0 + JE D_LoadXMNoPatterns + + Xor BP, BP + +D_LoadXM1: + Push DS SI DI + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset PatternMsg + Mov AH, 5 + Mov DI, (4+16*80)*2 + Push BP + Call S_DrawString + Pop AX + + Pop DI SI DS + Assume DS:Nothing + + Mov AH, 3Fh + Mov CX, 4 + Xor DX, DX + Int 21h ; Read pattern length + + Mov AH, 3Fh + Mov CX, [DS:0] + Mov DX, 4 + Sub CX, DX + Int 21h ; Read pattern header + + Cmp Word Ptr [DS:7], 0 + JE D_LoadXM3 + + Mov AH, 3Fh + Mov CX, [DS:7] + Mov DX, 100h + Mov SI, DX + Int 21h ; DS:100h contains all the + ; pattern data. + + Cmp BP, 200 ; Too many patterns? + JAE D_LoadXM3 + + Mov AX, [DS:5] ; AX = number of rows + Mov CX, [DS:64100+8] ; CX = number of channels + Mov DX, BP + + Cmp AX, 200 + JA D_LoadXM2 + + ; TranslateXMPattern takes: + ; DS:SI points to pattern data + ; AX = rows + ; CX = channels + ; DX = pattern number + + + Call PE_TranslateXMPattern + Jmp D_LoadXM3 + +D_LoadXM2: + ShR AX, 1 + Call PE_TranslateXMPattern + + Mov DX, [ES:0C0h] ; DX = pattern number + Cmp DX, 200 + JAE D_LoadXM3 + + Inc Word Ptr [ES:0C0h] + + Call D_InsertOrder + + Mov AX, [DS:5] + Inc AX + ShR AX, 1 ; AX = number of rows. + Call PE_TranslateXMPattern + +D_LoadXM3: + Inc BP + Cmp BP, [DS:64100+10] + JB D_LoadXM1 + +D_LoadXMNoPatterns: + ; Now to load instruments + Xor BP, BP + Cmp BP, [DS:64100+12] + JE D_LoadXMInstrumentTooMany + +D_LoadXM4: + Push DS SI + + Push CS + Pop DS + Mov SI, Offset InstrumentMsg + Mov AX, BP + Inc AX + Push AX + Mov AH, 5 + Mov DI, (4+17*80)*2 + Call S_DrawString + Pop AX + + Pop SI DS + + Mov AH, 3Fh + Mov CX, 4 + Xor DX, DX + Int 21h + + Mov AH, 3Fh + Mov CX, [DS:0] + Mov DX, 4 + Sub CX, DX + Int 21h + + ; OK.. instrument loaded into DS:0.. + Mov DI, BP + Add DI, DI + Mov DI, [ES:64712+DI] ; ES:DI points to instrument + Push DI + + Mov SI, 4 + Add DI, 20h + Mov CX, 22 + Rep MovsB + Xor AX, AX + Mov CX, 4 + Rep StosW + + Pop DI + Cmp Word Ptr [DS:27], 0 + JE D_LoadXMInstrumentEnd + + Add DI, 14h ; DI points to fadeout + Mov AX, [DS:239] + Add AX, 15 + ShR AX, 5 + Cmp AX, 256 + JBE D_LoadXMInstrument1 + + Mov AX, 256 + +D_LoadXMInstrument1: + StosW + Add DI, 40h-16h ; Translation table + + Mov CX, 12 ; Kill first 12 entries. + Xor AX, AX + +D_LoadXMInstrument2: ; First 12 entries cleared + StosW + Inc AX + Loop D_LoadXMInstrument2 + + Mov CX, 96 + Mov SI, 33 ; Note translation + +D_LoadXMInstrument3: + Mov AH, [SI] + Add AH, [ES:24h] + Cmp AH, 99 + JBE D_LoadXMInstrument4 + + Mov AH, 99 + +D_LoadXMInstrument4: + StosW + Inc SI + Inc AX + Loop D_LoadXMInstrument3 + + Mov CX, 12 ; Kill first 12 entries. + Xor AH, AH + +D_LoadXMInstrument5: ; First 12 entries cleared + StosW + Inc AX + Loop D_LoadXMInstrument5 + + ; Now for volume envelope + Mov AL, [DS:233] ; Flags + Test AL, 1 + JNZ D_LoadXMVolumeEnvelope + + Mov AX, 205h + StosW + Xor AX, AX + StosW + StosW + + Mov AL, 64 + StosB + Xor AX, AX + StosW + + StosB + Mov AX, 1 + StosW + + Mov CX, 70 + Xor AX, AX + Rep StosB + + Jmp D_LoadXMInstrumentVolumeFinished + +D_LoadXMVolumeEnvelope: +; Mov CL, AL +; Mov AH, AL +; And AX, 402h +; ShR AH, 1 +; ShL AL, 1 +; Or AL, AH +; And CL, 1 +; Or AL, CL + + And AL, 2 + ShL AL, 1 + Or AL, 2+1 ; Volume envelope on, Loop on (always) + + Mov AH, [DS:225] ; No of vol env nodes + Cmp AH, 12 + JB D_NumXMVolNodes1 + + Mov AH, 12 + +D_NumXMVolNodes1: + StosW + Mov AX, [DS:228] ; Vol loop start+end + Test Byte Ptr [DS:233], 4 ; Volume loop? + JNZ VolumeLoopOK + + Mov AL, [DS:225] + Dec AX + Mov AH, AL + +VolumeLoopOK: + StosW + Mov AL, [DS:227] ; Vol Sustain point + Mov AH, AL + StosW + + Cmp Byte Ptr [DS:233], 7 + JNE D_XMVolumeNoSustain + + Cmp AL, [DS:229] ; Compare sustain to endpoint + JB D_XMVolumeLoopOK + + And Byte Ptr [ES:DI-6], Not 4 + Jmp D_XMVolumeLoopOK + +D_XMVolumeNoSustain: + Test Byte Ptr [DS:233], 2 ; Loop? + JNZ D_XMVolumeLoopOK + + Mov AL, [DS:225] ; Number of nodes + Dec AX + Mov AH, AL + Mov [ES:DI-2], AX + Or Byte Ptr [ES:DI-6], 4 + +D_XMVolumeLoopOK: + ; OK. now process volume env points + Mov CX, 12 + Mov SI, 129 + +D_LoadXMInstrument6: + Mov AL, [SI+2] + Cmp AL, 64 + JB D_LoadXMInstrument7 + + Mov AL, 64 + +D_LoadXMInstrument7: + StosB + MovsW + LodsW + Loop D_LoadXMInstrument6 + + Mov CX, 13*3+1 + Xor AX, AX + Rep StosB + + ; Now for panning envelope +D_LoadXMInstrumentVolumeFinished: + + Mov AL, [DS:234] ; Flags + Mov CL, AL + Mov AH, AL + And AX, 402h + ShR AH, 1 + ShL AL, 1 + Or AL, AH + And CL, 1 + Or AL, CL + + Mov AH, [DS:226] ; No of pan env nodes + Cmp AH, 12 + JB D_NumXMPanNodes1 + + Mov AH, 12 + +D_NumXMPanNodes1: + StosW + Mov AX, [DS:231] ; Pan loop start+end + StosW + Mov AL, [DS:230] ; Pan Sustain point + Mov AH, AL + StosW + + Test Byte Ptr [DS:234], 2 ; Panning envelope flags + JZ D_XMPanningLoopOK + + Cmp AL, [DS:232] ; Compare sustain to endpoint + JB D_XMPanningLoopOK + + And Byte Ptr [ES:DI-6], Not 4 + +D_XMPanningLoopOK: + ; OK. now process panning env points + Mov CX, 12 + Mov SI, 177 + Xor AH, AH + +D_LoadXMInstrument8: + Mov AL, [SI+2] + Cmp AL, 64 + JB D_LoadXMInstrument9 + + Mov AL, 64 + +D_LoadXMInstrument9: + Sub AL, 32 + StosB + MovsW + LodsW ; Add SI, 2 + Loop D_LoadXMInstrument8 + + Mov AX, [DS:27] + Mul Word Ptr [DS:29] + Mov CX, AX + Mov AH, 3Fh + Mov DX, 1000h + Mov SI, DX + Int 21h + + Mov CX, [DS:27] ; Update number of samples. + Mov AX, [ES:24h] + Add [ES:24h], CX + +D_LoadXMSamples1: + Cmp AX, 99 + JA D_LoadXMInstrumentTooMany + Cmp AX, [ES:24h] + JAE D_LoadXMInstrumentEnd + + Push AX + Push SI + + Mov DI, AX + Add DI, DI + Mov DI, [ES:64912+DI-2] + Add DI, 12h ; Skip filename, ID, GVL + + Mov AH, [SI+12] ; Default volume + Mov AL, 0 + Cmp DWord Ptr [SI], 0 ; Length = 0? + JE D_LoadXMSamples3 + + ; Grab the panning value + +Comment ~ + Mov AL, [SI+15] + ShR AL, 1 + Inc AX + ShR AL, 1 + + Push DI + Mov DI, BP + Add DI, DI + Mov DI, [ES:64712+DI] + Cmp Byte Ptr [ES:DI+19h], 32+128 + JE XMNoPan2 + + Mov AL, 32 + +XMNoPan2: + Mov [ES:DI+19h], AL + +XMNoPan: + Pop DI +~ + ; Sample present flag + Mov AL, 1 + + Mov CL, [SI+14] + Test CL, 10h ; 16 bit sample? + JZ D_LoadXMSamples2 + + Or AL, 2 + +D_LoadXMSamples2: + And CL, 3 + JZ D_LoadXMSamples3 ; No loop + ; CL = 1 or 2 + Cmp DWord Ptr [SI+8], 1 + JBE D_LoadXMSamples3 + + Or AL, 10h ; Loop + Dec CX + ShL CL, 6 + Or AL, CL + +D_LoadXMSamples3: + StosW + + Push SI + ; Copy sample name + Add SI, 18 + Mov CX, 22/2 + Rep MovsW + Xor AX, AX + StosW + StosW + + Pop SI + ; Conversion flags. + Mov AH, [SI+15] + ShR AH, 2 + AdC AH, 80h + Mov AL, 5 + StosW + + Mov EAX, [SI] + Call LoadXISample5 + Mov EAX, [SI+4] + Call LoadXISample5 + Mov EAX, [SI+4] + Add EAX, [SI+8] + Call LoadXISample5 + + ; C5speed.. + Push ES + Push DI + + Call Music_GetPitchTable ; Returns ES:DI + Mov AL, [SI+16] ; Relative note number + Add AL, 60 ; AL = note multiplier + And AX, 0FFh + ShL AX, 2 + Add DI, AX + Mov ECX, [ES:DI] + + Mov AL, [SI+13] ; Finetune, -128->+127 + SAR AL, 4 ; Finetune = -8->+7 + And AX, 0Fh + Add AX, AX + Mov DI, AX + MovZX EAX, [CS:FineTuneTable+DI] + + Pop DI + Pop ES + + Push EDX + + Mul ECX + ShRD EAX, EDX, 16 + Pop EDX + StosD ; C5freq + + Xor AX, AX + StosW + StosW + StosW + StosW + + ; Now for file position + Mov AX, 4201h + Xor CX, CX + Xor DX, DX + Int 21h ; Returns DX:AX + + StosW + Mov AX, DX + StosW + + ; Vibrato information + Mov AX, [DS:237] + XChg AH, AL + StosW + + Mov DX, [DS:236] + And DX, 0FFh + Mov AX, 100h + Sub AX, DX +; Cmp AL, 64 +; JBE VibratoLimit +; +; Mov AL, 64 +; +; VibratoLimit: + Mov AH, [DS:235] + StosW + + ; Move file pointer forwards + Mov AX, 4201h + Mov CX, [SI+2] + Mov DX, [SI] + Int 21h + + Pop SI + Pop AX + Add SI, [DS:29] ; Next sample header + Inc AX + Jmp D_LoadXMSamples1 + +D_LoadXMInstrumentEnd: + Inc BP + Cmp BP, 99 + JA D_LoadXMInstrumentTooMany + Cmp BP, [DS:64100+12] + JB D_LoadXM4 + +D_LoadXMInstrumentTooMany: + Mov CX, 1 ; CX = sample number (base 1) + ; DS = doesn't matter + ; ES = songdata segment + +D_LoadXMFinalSamples1: ; OK, now load the samples. + Push CX + Push ES + + Mov SI, CX + Dec SI + Add SI, SI + Mov SI, [ES:64912+SI] + Test Byte Ptr [ES:SI+12h], 1 + JZ D_LoadXMFinalSamples2 + + Push CS + Pop DS + + Push SI + Mov SI, Offset SampleMsg + Mov DI, (4+18*80)*2 + Mov AH, 5 + Push CX + Call S_DrawString + Pop DI + Pop SI ; ES:SI points to sample header. + ; DI = sample number+1 + Push ES + Pop DS + + Mov AX, 4200h + Xor CX, CX + Xor DX, DX + XChg CX, [DS:SI+4Ah] + XChg DX, [DS:SI+48h] + Int 21h ; Move file pointer. + + Mov AX, DI + Dec AX + + Call D_LoadSampleData + Jmp D_LoadXMFinalSamplesPresent + +D_LoadXMFinalSamples2: + Mov DWord Ptr [SI+48h], 0 + +D_LoadXMFinalSamplesPresent: + Pop ES + Pop CX + Inc CX + Cmp CX, 100 + JBE D_LoadXMFinalSamples1 + + Jmp D_PostLoadModule + +EndP D_LoadXM + +; + +Proc D_LoadMTM Far + + Xor AX, AX + Call D_PreLoadModule + + Assume DS:Nothing + + Mov AH, 3Fh + Mov CX, 66 ; Song header length. + Mov DX, 60000 + Int 21h + + Mov DI, 4 + Mov CX, 20 + Mov SI, 60004 + Rep MovsB + Xor AX, AX + Mov CX, 8 + Rep StosB ; Song name. + Mov AL, [DS:60027] + StosW ; Order num + Xor AL, AL + StosW ; Inst num + Mov AL, [DS:60030] + StosW ; Sample number. + Mov AL, [DS:60026] + StosW ; Pattern number + + Add DI, 4 +; Mov AX, 101h ; Cwt/v 1.0 +; StosW +; Mov AX, 100h ; Cmwt 1.0 +; StosW + + Mov AX, 31h ; Stereo. No Vol0Opt + StosW ; Use samples, old eff + Xor AX, AX + StosW + Mov AX, 3080h ; GlobalVol+MixVol + StosW + Mov AX, 7D06h + StosW + Mov AL, 128 + StosB + Xor AL, AL + Mov CX, 11 + Rep StosB + + Mov CX, 32 + Mov DX, 0 + Xor AH, AH + ; Panning positions +D_LoadMTM1: + Mov SI, 60034 + Add SI, DX + Mov AL, [DS:SI] + Mov SI, AX + Mov AL, [CS:PanningPositions+SI] + StosB + + Inc DX + Loop D_LoadMTM1 + + Mov CX, 32 + Mov AL, 160 + Rep StosB + Mov AL, 64 + Mov CX, 64 + Rep StosB + + Push DS + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset SampleHeaderMsg + Mov AH, 5 + Mov DI, (4+16*80)*2 + Call S_DrawString + + Pop DS + Assume DS:Nothing + + Mov AL, 37 + Mul Byte Ptr [ES:24h] ; AX = length of + ; sample headers + Mov CX, AX ; length.. + Mov AH, 3Fh ; read file.. + Xor DX, DX + Int 21h + + + Mov DH, [ES:24h] + Mov DI, 55912 ; Start of samples. + Xor SI, SI ; DS:SI points to MTM header. + +D_LoadMTM2: + Mov EAX, 'SPMI' + StosD + Xor AX, AX + Mov CX, 6 + Rep StosW ; Clear file name. + StosB + Mov AL, 40h + StosB + + + Mov AL, [DS:SI+36] + And AL, 1 + Add AL, AL + + Cmp DWord Ptr [DS:SI+22], 0 + JE D_LoadMTM3 ; Sample length = 0. + + Or AL, 1 ; Else there's a sample. + +D_LoadMTM3: + Mov ECX, [SI+30] ; Sample loop end + Sub ECX, [SI+26] ; Sample loop start + Cmp ECX, 2 + JBE D_LoadMTM4 + + Or AL, 16 + +D_LoadMTM4: + StosB + Mov DL, AL + Mov AL, [DS:SI+35] + StosB + + Push SI + + Mov CX, 22 + +D_LoadMTMSampleName: + LodsB + StosB + And AL, AL + LoopNZ D_LoadMTMSampleName + Pop SI + + Xor AL, AL + Add CX, 5 + Rep StosB ; Filler. + Mov AL, 32 + StosB + + Mov EAX, [DS:SI+22] + StosD + + Test DL, 1 + JNZ D_LoadMTM5 + + Xor AX, AX + Mov CX, 4 + Rep StosW ; Clear rest of sample field. + Mov AX, 8363 ; (no sample) + StosW + Xor AX, AX + Mov CX, 9 + Rep StosW + + Jmp D_LoadMTM8 + +D_LoadMTM5: + Test DL, 16 + JZ D_LoadMTM6 + + Mov EAX, [DS:SI+26] + StosD + Mov EAX, [DS:SI+30] + StosD + Jmp D_LoadMTM7 + +D_LoadMTM6: + Xor AX, AX + Mov CX, 4 + Rep StosW + +D_LoadMTM7: ; C5 speed here... + Push SI + Mov AL, [DS:SI+34] + And AX, 0Fh + Mov SI, AX + Add SI, SI + Mov AX, [CS:FineTuneTable+SI] + Pop SI + StosW + Xor AX, AX + Mov CX, 9 + Rep StosW + +D_LoadMTM8: + Add SI, 37 + Dec DH + JNZ D_LoadMTM2 ; Finished with samples. + + Mov AH, 3Fh + Mov CX, 128 + Xor DX, DX + Int 21h ; Order data. + + Mov CL, [DS:60027] + Inc CX + Xor CH, CH + Mov DX, 256 + Sub DX, CX + Xor SI, SI + Mov DI, 256 + Rep MovsB + Mov CX, DX + Mov AL, 0FFh + Rep StosB ; Order list done. + ; Now it's time to do the + ; friggen pattern stuff. + Mov AL, 37 + Mul Byte Ptr [DS:60030] + Add AX, 66+128 + Push AX + + Mov AX, 192 + Mul Word Ptr [DS:60024] + ; DX:AX = length of track data. + Mov BP, DX + Mov CX, AX + Xor DX, DX + Pop AX + Add CX, AX + AdC BP, 0 + ; BP:CX = offset to sequencer +D_LoadMTM9: ; DX = pattern no. + ; AX = offset to track data. + Push AX + Push CX + Push DX + + Push AX + + Push DS + Push SI + Push DI + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset PatternMsg + Mov AH, 5 + Mov DI, (4+17*80)*2 + Push DX + Call S_DrawString + Pop AX + + Pop DI + Pop SI + Pop DS + Assume DS:Nothing + + + Mov AX, 4200h + Mov DX, CX + Mov CX, BP + Int 21h ; Move to offset. + + Mov AH, 3Fh + Mov CX, 64 + Xor DX, DX + Int 21h ; Read seq data. + + Pop AX + + Mov CX, 32 + Xor SI, SI + Mov DX, AX ; DX = posn of track data. + Mov DI, 10000 + +D_LoadMTM10: + Push CX + Push DX + + LodsW + And AX, AX + JZ D_LoadMTM11 + + Push DS + Push SI + Push DI + Mov SI, 33 + Sub SI, CX + Push AX + Push SI + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset TrackMsg + Mov DI, (5+18*80)*2 + Mov AH, 5 + Call S_DrawString + + Pop SI + Pop AX + Pop DI + Pop SI + Pop DS + Assume DS:Nothing + + Push DX + + Dec AX + Mov CX, 192 + Mul CX + + Pop CX + Add AX, CX + AdC DX, 0 + Mov CX, DX + Mov DX, AX + Mov AX, 4200h + Int 21h ; Move ptr. + + Mov AH, 3Fh + Mov CX, 192 + Mov DX, DI + Int 21h + + Add DI, 192 + Jmp D_LoadMTM12 + +D_LoadMTM11: + Push ES + + Push DS + Pop ES + + Mov CX, 192 + Xor AL, AL + Rep StosB + + Pop ES + +D_LoadMTM12: + Pop DX + Pop CX + Loop D_LoadMTM10 + + Mov SI, 10000 + ; DS:SI points to pattern data. + + Pop DX + ; DX = pattern number + ; DS:SI = pattern data. + Call PE_TranslateMTMPattern + + Pop CX + Pop AX + Add CX, 64 + AdC BP, 0 + Inc DX + Cmp DL, [DS:60026] + JBE D_LoadMTM9 + + ; BP:CX points to comment + + Comment & + + Mov AL, 37 + Mul Byte Ptr [DS:60030] + ; AX = 37*NOS + Add AX, 194 + Add AX, Word Ptr [DS:60028] ; AX = 194+NOS*37+length_comment + Mov CX, AX + Mov AX, 192 + Mul Word Ptr [DS:60024] ; DX:AX = trcks*192 + Mov BP, DX + Add CX, AX + AdC BP, 0 ; BP:CX = 194+NOS*37+trcks*192+ + ; length(comment) + Mov AL, 64 + Mov AH, Byte Ptr [DS:60026] + Inc AH + Mul AH + Add CX, AX + AdC BP, 0 ; BP:CX = 194+NOS*37+trcks*192+ + ; 64*patterns+length(comment) + + & + +; Add CX, [DS:60028] ; Skip past comment -> samples. +; AdC BP, 0 +; + Mov AX, 4200h + Mov DX, CX + Mov CX, BP + Int 21h ; File is at pointers to samps. + + Mov CX, [DS:60028] ; Length of message + Call Msg_GetMessageOffset ; Sets up DS:DX + Mov AH, 3Fh + Int 21h + ; Now to 'process' the message. + + Mov SI, DX + Mov CX, AX + + Xor DX, DX ; DX = character count. + +D_LoadMTMMessage1: + Mov AL, [SI] + And AL, AL + JNZ D_LoadMTMMessage2 + + Mov Byte Ptr [SI], 32 ; spacebar. + +D_LoadMTMMessage2: + Inc DX + Cmp DX, 40 + JB D_LoadMTMMessage3 + + Xor DX, DX + Mov Byte Ptr [SI], 13 ; Enter! + +D_LoadMTMMessage3: + Inc SI + Loop D_LoadMTMMessage1 + + Push ES + Pop DS + Mov SI, 55912 ; DS:SI points to sample headers + Xor CX, CX + +D_LoadMTM13: + Push CX + Push SI + Test Byte Ptr [DS:SI+12h], 1 + JZ D_LoadMTM14 + ; OK.. have a sample to load. + Push DS + Push SI + + Push CS + Pop DS + Mov SI, Offset SampleMsg + Mov DI, (4+20*80)*2 + Mov AX, CX + Inc AX + Push AX + Mov AH, 5 + Call S_DrawString + Pop AX + Dec AX + + Pop SI + Pop DS + + Call D_LoadSampleData + +D_LoadMTM14: + Pop SI + Pop CX + Inc CX + Add SI, 80 + Cmp CX, 100 + JB D_LoadMTM13 + + Jmp D_PostLoadModule + +EndP D_LoadMTM + Assume DS:Nothing + +; + +Proc D_LoadS3M Far + + Mov AL, 1 + Call D_PreLoadModule + + Mov AH, 3Fh + Mov CX, 60h + Mov DX, 60000 + Int 21h + + Mov DI, 4 + Mov CX, 25 + Mov SI, 60000 + Rep MovsB + Xor AL, AL + StosB + Add DI, 14 + + Mov AX, 10h ; Old Effects + + Test Byte Ptr [DS:60000+33h], 80h + JZ D_LoadS3M1 + + Inc AX + +D_LoadS3M1: + Test Byte Ptr [DS:60000+26h], 8 + JZ D_LoadS3M2 + + Or AL, 2 + +D_LoadS3M2: + StosW + Xor AX, AX + StosW + Mov AL, [DS:60000+30h] + ShL AL, 1 + StosB + Mov AL, [DS:60000+33h] + And AL, 127 + StosB + Mov AX, [DS:60000+31h] + StosW + Mov AL, 128 + StosB + Add DI, 7 + + Mov EAX, [DS:60000+38h] + Cmp Word Ptr [DS:60000+28h], 3208h + JB D_ConvertS3MTimer + + Xor EAX, 'ITRK' + RoR EAX, 7 + Neg EAX + RoL EAX, 4 + Xor EAX, 'JTHL' + +D_ConvertS3MTimer: + StosD + ; OK, panning now... + Mov SI, 60000+40h + Mov CX, 32 + +D_LoadS3M3: + LodsB + + Mov DL, 32+128 + Cmp AL, 128 + JAE D_LoadS3M4 + + Mov AH, AL + +; Test Byte Ptr [DS:60000+33h], 128 +; JZ D_LoadS3M5 + + And AL, 127 + + Mov DL, 0 + Cmp AL, 7 + JBE D_LoadS3M4 + + Mov DL, 64 + Cmp AL, 15 + JBE D_LoadS3M4 + + Mov DL, 32 + +D_LoadS3M4: + Mov AL, DL + And AH, 80h + + StosB + Loop D_LoadS3M3 + + Mov CX, 32 + Mov AL, 32+128 + Rep StosB + + Mov CX, 64 + Mov AL, 64 + Rep StosB + + Mov DI, 100h + Mov CX, 256 + Mov AL, 255 + Rep StosB + + Push DS + + Mov CX, [DS:60000+20h] + Push ES + Pop DS + Mov DX, 100h + Mov AH, 3Fh + Int 21h + + Pop DS ; Order list loaded. + + Mov AH, 3Fh + Mov CX, [DS:60000+22h] + Add CX, [DS:60000+24h] + Add CX, CX + Xor DX, DX + Int 21h + + Cmp Byte Ptr [DS:60000+35h], 252 + JNE D_LoadS3M15 + + Mov AH, 3Fh + Mov CX, 32 + Mov DX, 1024 + Int 21h + + Mov CX, 32 + Mov SI, 1024 + Mov DI, 64 + +D_LoadS3M14: + LodsB + Test AL, 32 + JZ D_LoadS3M16 + + Mov AH, [ES:DI] + And AX, 800Fh + ShL AL, 1 + ShL AL, 1 + Add AL, 2 + Or AL, AH + Mov [ES:DI], AL + +D_LoadS3M16: + Inc DI + + Loop D_LoadS3M14 + +D_LoadS3M15: + Mov CX, 1 ; Load instruments + Mov DI, 55912 + +D_LoadS3M7: + Push CX + Push DI + + Push DI + Push DS + + Mov SI, CX + Dec SI + Add SI, SI + Mov DX, [SI] + + Push CS + Pop DS + Push CX ; For Drawstring. + + Mov AX, 4200h + Xor CX, CX + ShLD CX, DX, 4 + ShL DX, 4 + Int 21h + + Mov SI, Offset SHLoadMsg + Mov DI, (4+16*80)*2 + Mov AH, 5 + Call S_DrawString + Pop AX + + Pop DS + Pop DI + + Mov DX, 1024 ; Load inst. header. + Mov CX, 80 + Mov AH, 3Fh + Int 21h + + Mov EAX, 'SPMI' + StosD + + Mov SI, 1025 + Mov CX, 12 + Rep MovsB + Xor AL, AL + StosB + Mov AL, 64 + StosB + + Xor AL, AL + + Cmp Byte Ptr [DS:1024], 1 + JNE D_LoadS3M8 + + Mov AL, [DS:1024+1Fh] + ShR AL, 1 + And AL, 2 + + Cmp Word Ptr [DS:1024+10h], 0 + JE D_LoadS3M8 + + Inc AX + +D_LoadS3M8: + Mov CL, [DS:1024+1Fh] + Mov CH, CL ; CL = 1 -> loop + And CL, 1 + ShL CL, 4 + Or AL, CL ; Loop... + + And CH, 4 + ShR CH, 1 + Or AL, CH ; 16 bit. + +D_LoadS3M9: + StosB + Mov AL, [DS:1024+1Ch] + StosB + Mov SI, 1024+30h + Mov CX, 25 + Rep MovsB + Xor AX, AX + StosW + Mov AL, 32 + StosB + + Mov EAX, [DS:1024+10h] + StosD ; Length + + Mov EAX, [DS:1024+14h] + StosD ; LoopBeg + + Mov EAX, [DS:1024+18h] + StosD ; LoopEnd + + Mov EAX, [DS:1024+20h] + StosD ; C5Spd + + Xor AX, AX + StosW + StosW ; Susloopbegin + + StosW + StosW ; SusLoopEnd + + Cmp Byte Ptr [DS:1024], 1 + JE D_LoadS3M22 + + Xor AX, AX + StosW + StosW + Jmp D_LoadS3M23 + +D_LoadS3M22: + Mov CL, 4 + Mov AX, [DS:1024+0Eh] + Mov DL, [DS:1024+0Fh] + Mov DH, [DS:1024+0Dh] + ShL AX, CL + ShR DX, CL + StosW ; Sample pointer in file. + Mov AX, DX + StosW + + Xor AX, AX + +D_LoadS3M23: + StosW ; Vibrato info... + StosW + + Pop DI + Pop CX + Add DI, 80 + Inc CX + + Cmp CX, 100 + JAE D_LoadS3M10 + + Cmp CX, [DS:60000+22h] + JBE D_LoadS3M7 + +D_LoadS3M10: + Push DS + + Mov CX, 1 ; CX = sample number (base 1) + ; DS = doesn't matter + ; ES = songdata segment + +D_LoadS3M17: ; OK, now load the samples. + Push CX + Push ES + + Mov SI, CX + Dec SI + Add SI, SI + Mov SI, [ES:64912+SI] + Test Byte Ptr [ES:SI+12h], 1 + JZ D_LoadS3M18 + + Push CS + Pop DS + + Push SI + Mov SI, Offset SampleMsg + Mov DI, (4+17*80)*2 + Mov AH, 5 + Push CX + Call S_DrawString + Pop DI + Pop SI ; ES:SI points to sample header. + ; DI = sample number+1 + Push ES + Pop DS + + Mov AX, 4200h + Xor CX, CX + Xor DX, DX + XChg CX, [DS:SI+4Ah] + XChg DX, [DS:SI+48h] + Int 21h ; Move file pointer. + + Mov AX, DI + Dec AX + + Call D_LoadSampleData + Jmp D_LoadS3MSamplePresent + +D_LoadS3M18: + Mov DWord Ptr [SI+48h], 0 + +D_LoadS3MSamplePresent: + Pop ES + Pop CX + Inc CX + Cmp CX, 100 + JBE D_LoadS3M17 + + Pop DS + + Mov CX, 0 ; CX = pattern number + ; DS = disktransfer + +D_LoadS3M11: + Push CX ; Load patterns.... + + Push DS + + Push CS + Pop DS + + Mov DI, (4+18*80)*2 + Mov SI, Offset PatternMsg + Mov AH, 5 + Push CX + Call S_DrawString + Pop SI ; SI = Pattern Number + + Pop DS + + Add SI, [DS:60000+22h] + Add SI, SI + Mov DX, [SI] ; DX = offset of pattern / 16 + And DX, DX + JZ D_LoadS3M13 + + Push CX + + Xor CX, CX + ShLD CX, DX, 4 + ShL DX, 4 + Mov AX, 4200h + Int 21h + + Mov AH, 3Fh ; Load data. + Mov CX, 2 + Mov DX, 1024 + Int 21h + Mov AH, 3Fh + Mov CX, [DS:1024] + Mov DX, 1024 + Int 21h ; Pattern data at DS:1024 + + Pop DX ; DX = Pattern number + Mov SI, 1024 + Call PE_TranslateS3MPattern + +D_LoadS3M13: + Pop CX + Inc CX + Cmp CX, 100 + JA D_LoadS3M12 + + Cmp CX, [DS:60000+24h] + JB D_LoadS3M11 + +D_LoadS3M12: + Jmp D_PostLoadModule + + Ret + +EndP D_LoadS3M + Assume DS:Nothing + +; + +Proc D_Load669 Far + + Xor AX, AX + Call D_PreLoadModule + + Mov AH, 3Fh + Mov CX, 1F1h + Mov DX, 60000 + Int 21h + + Mov SI, 60000+2 + Mov DI, 4 + Mov CX, 25 + Rep MovsB + + Xor AX, AX + Mov CX, 7 + Rep StosB + Mov SI, 60000+6Eh + LodsB + StosW + LodsB + StosW + + Add DI, 4 + Mov AX, 19h ; Stereo control, sample controlled, + StosW ; Linear, Old EFX + Xor AX, AX + StosW ; Song message attached. + + Mov AX, 3080h ; GV/MV + StosW + + Mov AX, 78*100h+6h ; 78 BPM, speed 6 + StosW + + Mov AX, 64 ; Separation of 64 + StosW + Xor AX, AX + Mov CX, 5 + Rep StosW + + Mov AX, 4000h + StosW + StosW + StosW + StosW + Mov AL, 32+128 + Mov CX, 56 + Rep StosB ; Channel pan + Mov AL, 64 + Mov CL, AL + Rep StosB ; Channel volume + + Mov SI, 60000+71h + Mov DI, 100h ; Orders + Mov CL, 80h + Rep MovsB + Mov CL, 80h + Mov AL, 0FFh + Rep StosB ; Orders done. + + Xor BP, BP ; Sample time + + Mov DI, 512+55400 + Mov AL, 25 + Mul Byte Ptr [DS:60000+6Eh] + Mov CX, AX ; CX = bytes to read + Mov AH, 3Fh + Xor DX, DX + Int 21h + Xor SI, SI + +D_Load669_1: + Cmp BP, [ES:24h] + JAE D_Load669_2 + + Mov EAX, 'SPMI' + StosD + Mov CX, 6 + Rep MovsW + Mov AX, 4000h + StosW + + ; Flag, volume + Mov AH, 60 + Inc SI + Mov ECX, [SI] + Test ECX, ECX + JZ D_Load669_3 + + Xor EAX, EAX + Mov [ES:DI+22h], EAX + Mov [ES:DI+26h], EAX + + Mov AX, 3C01h ; Sample present + + Mov ECX, [SI+8] ; End loop + + Cmp ECX, [SI] + JA D_Load669_3 + + Sub ECX, [SI+4] ; Start loop + JC D_Load669_3 + Cmp ECX, 2 + JB D_Load669_3 + + Mov ECX, [SI+4] + Mov [ES:DI+22h], ECX + Mov ECX, [SI+8] + Mov [ES:DI+26h], ECX + + Mov AX, 3C11h ; Sample present, forwards loop + +D_Load669_3: + StosW + Mov CX, 13 + Sub SI, CX + Rep MovsB + Xor AL, AL + Mov CX, 13 + Rep StosB + Mov AH, 32 + StosW ; Convert, DfP + MovsW + MovsW + Add SI, 8 + Add DI, 8 + + Mov AX, 8363 + StosW + + Xor AX, AX + Mov CX, 9 + Rep StosW + + Inc BP + Jmp D_Load669_1 + +D_Load669_2: ; OK.. patterns.. + Xor BP, BP ; BP = pattern number + +D_Load669_4: + Cmp BP, [ES:26h] + JAE D_Load669_5 + + Mov AH, 3Fh + Mov CX, 600h + Xor DX, DX + Int 21h ; Patterns at DS:0 + + Mov AH, [DS:60000+0F1h+BP] + Mov CL, [DS:60000+171h+BP] + Call PE_Translate669Pattern + + Inc BP + Jmp D_Load669_4 + +D_Load669_5: ; Samples + + Xor BP, BP + Push ES + Pop DS + +D_Load669Samples: + Inc BP + Cmp BP, [DS:24h] + JA D_Load669End + + Mov SI, BP + Add SI, SI + Mov SI, [DS:64910+SI] + Test Byte Ptr [DS:SI+12h], 1 ; Sample present? + JZ D_Load669Samples + + Push DS + Push SI + + Push CS + Pop DS + + Push BP + Mov SI, Offset SampleMsg + Mov DI, (4+16*80)*2 + Mov AH, 5 + Call S_DrawString + + Pop AX + Pop SI + Pop DS + + Dec AX + Call D_LoadSampleData + + Jmp D_Load669Samples + +D_Load669End: + Jmp D_PostLoadModule + +EndP D_Load669 + +; + +Proc D_LoadMOD Far + + Xor AX, AX + Call D_PreLoadModule + + Mov AH, 3Fh + Mov CX, 2048 + Mov DX, 60000 + Int 21h + + Mov SI, 60000 + Mov DI, 4 + Mov CX, 20 + Rep MovsB ; Song name + Xor AX, AX + Mov CX, 8 + Rep StosW + Add DI, 4 + Mov AX, 31h ; Old effects, stereo, sample control + StosW + Xor AX, AX + StosW + Mov AX, 3080h ; GV/MV + StosW + + Mov AX, 07D06h ; 125 BPM, speed 6 + StosW + + Mov AX, 64 ; Separation of 64 + StosW + + Xor AX, AX + Mov CX, 5 + Rep StosW + + Mov DL, CS:MODNumberOfChannels + Mov CX, 64 + Cmp DL, 8 + JBE D_LoadMOD13 + + Mov CL, DL + Mov AL, 32 + Rep StosB + Mov CL, 64 + Sub CL, DL + Jmp D_LoadMOD14 + +D_LoadMOD13: + Mov AX, 4000h ; Panning. + StosW + Mov AX, 40h + StosW + Sub CX, 4 + + Cmp DL, 4 + JBE D_LoadMOD14 + + Mov AX, 4000h + StosW + Sub CX, 2 + Cmp DL, 6 + JBE D_LoadMOD14 + + Mov AX, 40h + StosW + Sub CX, 2 + +D_LoadMOD14: + Mov AL, 32+128 + Rep StosB ; Clear Panning + + Mov AL, 64 + Mov CX, 64 + Rep StosB ; Channel Volume + + Mov DI, 256 + Mov CX, 256 + Mov AL, 0FFh + Rep StosB ; Orders. + + Mov DI, 256 + Xor CH, CH + Mov CL, CS:MODNumberOfOrders + Mov SI, CS:MODOrderOffset + Mov DX, SI + Rep MovsB ; copy orders... + + ; Get number of patterns to load + Xor CX, CX + Mov SI, DX + Mov AX, 07F00h + +D_LoadMOD1: + LodsB + Cmp CL, AL + JAE D_LoadMOD2 + + Mov CL, AL + +D_LoadMOD2: + Dec AH + JNZ D_LoadMOD1 + + Inc CX ; CX = number of patterns to + ; load + Push CX + + Push BX + ; setup inst. headers + Xor CH, CH + Mov CL, CS:MODNumberOfInstruments + Mov SI, 60000+20 + Mov DI, 512+55400 + +D_LoadMOD3: + Push CX + + Mov EAX, 'SPMI' + StosD + + Mov CX, 6 + Xor AX, AX + Rep StosW + StosB + Mov AL, 64 + StosB + Xor AL, AL + Mov CX, [DS:SI+28] + XChg CH, CL + Cmp CX, 1 + JBE D_LoadMOD4 + + Or AL, 16 + +D_LoadMOD4: + Mov CX, [DS:SI+22] + XChg CH, CL + Cmp CX, 1 + JBE D_LoadMOD5 + + Or AL, 1 + +D_LoadMOD5: + StosB + Mov AL, [DS:SI+25] + StosB + Mov CX, 22 + Rep MovsB + Xor EAX, EAX + StosD + + Mov AX, 1+32*256 ; Convert signed->Unsigned + StosW ; Default pan of 32 + + LodsW + XChg AH, AL ; Sample length... + Add EAX, EAX + StosD + Mov EDX, EAX ; EDX = length + + MovZX EAX, Word Ptr [DS:SI+2] ; Loop begin + XChg AH, AL + + Cmp CS:MODOrderOffset, 60472 + JE D_LoadMOD15 + + Add EAX, EAX + +D_LoadMOD15: + Cmp EAX, EDX + JBE D_LoadMODLengthCheck1 + + Xor EAX, EAX + +D_LoadMODLengthCheck1: + StosD + Mov ECX, EAX + + MovZX EAX, Word Ptr [DS:SI+4] ; Loop end + XChg AH, AL + + Cmp CS:MODOrderOffset, 60472 + JE D_LoadMOD16 + + Add EAX, EAX + +D_LoadMOD16: + Add EAX, ECX + Cmp EAX, EDX + JBE D_LoadMODLengthCheck2 + + Mov EAX, EDX + +D_LoadMODLengthCheck2: + StosD + + LodsB ; C5Speed. + And AX, 15 + Mov BX, AX + Add BX, BX + Mov AX, [CS:FineTuneTable+BX] + StosW + Xor AX, AX + Mov CX, 9 + Rep StosW + + Add SI, 5 + + Pop CX + Loop D_LoadMOD3 + + Pop BX ; Now to load mod patterns. + + Mov AX, 4200h + Xor CX, CX + Mov DX, CS:MODPatternOffset + Int 21h ; set offset in file... + + Pop CX + Xor AX, AX ; Start with pattern 0 + +D_LoadMOD6: + Cmp AX, CX + JAE D_LoadMOD7 + + Push AX + Push CX + + Push DS + + Push CS + Pop DS + + Push AX ; AX = pattern num. + Mov SI, Offset PatternMsg + Mov DI, (4+16*80)*2 + Mov AH, 5 + Call S_DrawString + + Pop DX ; DX = pattern num + Pop DS + + Push DX + + Mov AH, 3Fh + Mov CH, CS:MODNumberOfChannels + Xor CL, CL + Xor DX, DX + Int 21h ; DS:0 contains pat data + + Pop DX + Xor SI, SI + Mov AL, CS:MODNumberOfChannels + Xor AH, AH + + Call PE_TranslateMODPattern + + Pop CX + Pop AX + Inc AX + Jmp D_LoadMOD6 + + +D_LoadMOD7: ; Finished loading patterns + Mov CX, 1 ; Time to load samples. + +D_LoadMOD8: + Push CX + Push ES + + Mov SI, CX + Dec SI + Add SI, SI + Mov SI, [ES:64912+SI] + + Test Byte Ptr [ES:SI+12h], 1 + JZ D_LoadMOD9 + + Push SI + + Push CS + Pop DS + + Push CX + Mov SI, Offset SampleMsg + Mov DI, (4+17*80)*2 + Mov AH, 5 + Call S_DrawString + +; Mov AX, 4201h +; Xor CX, CX +; Mov DX, 4 +; Int 21h ; Progress pointer + + Pop AX + + Pop SI + + Push ES + Pop DS + + Dec AX ; AX = sample to load. + Call D_LoadSampleData + +D_LoadMOD9: + Pop ES + Pop CX + Inc CX + Cmp CL, CS:MODNumberOfInstruments + JBE D_LoadMOD8 + +D_LoadMOD12: + Jmp D_PostLoadModule + + Ret + +EndP D_LoadMOD + Assume DS:Nothing + +; + +ENDIF + +Proc ConvertOldInstrument ; DS:SI points to inst. + + PushAD + Push DS + Push ES + + Push DS + Pop ES + + Mov DI, SI + + Mov AL, [SI+11h] ; Old format Flg + Mov [SI+130h], AL + + Mov EAX, [SI+12h] ; VLS, VLE, SLS, SLE + Mov [SI+132h], EAX + + Mov AX, [SI+18h] ; Fadeout + Add AX, AX + Mov [SI+14h], AX + + Mov AL, [SI+1Ah] + Mov [SI+11h], AL + + Xor AX, AX + Mov AL, [SI+1Bh] + Mov [SI+12h], AX ; DCT + + Mov AX, 60*256 ; PPS, PPC + Mov [SI+16h], AX + + Mov AX, 128+(32+128)*256 ; GbV+DfP + Mov [SI+18h], AX + + Xor AX, AX + Mov [SI+1Ah], AX + ; Now for envelope + Push SI + Xor CX, CX + + Add SI, 1F8h + Add DI, 136h + +D_LoadITInstrument2: + LodsW + Cmp AX, 0FFFFh + JE D_LoadITInstrument3 + + Mov [DI], AH ; Magintude + Xor AH, AH + Mov [DI+1], AX ; Tick + + Add DI, 3 + Inc CX + Cmp CL, 25 + JAE D_LoadITInstrument3 + + Jmp D_LoadITInstrument2 + +D_LoadITInstrument3: + Pop SI + Mov [SI+131h], CL + + Mov CX, SI + Add CX, 554 + Sub CX, DI + Xor AL, AL + Rep StosB + + Mov Byte Ptr [SI+183h], 2 ; Num nodes for panning + pitch + Mov Byte Ptr [SI+1D5h], 2 + + Mov Byte Ptr [SI+18Ch], 99 ; Magn 0 at Tick 99 + Mov Byte Ptr [SI+1DEh], 99 ; Magn 0 at Tick 99 + + Pop ES + Pop DS + PopAD + + Ret + +EndP ConvertOldInstrument + +IF TUTORIAL +ELSE + +; + +Proc D_LoadIT Far + + Xor AX, AX + Call D_PreLoadModule + + Push DS + + Push CS + Pop DS + Mov SI, Offset HeaderMsg + Mov DI, (4+16*80)*2 + Mov AH, 5 + Call S_DrawString + + Pop DS + + Mov AH, 3Fh + Mov CX, 2048 + Xor DX, DX + Int 21h + + Cmp Word Ptr [DS:28h], 208h + JB D_ConvertITTimer + + Mov EAX, [DS:3Ch] + Xor EAX, 'ITRK' + RoR EAX, 7 + Neg EAX + RoL EAX, 4 + Xor EAX, 'JTHL' + Mov [DS:3Ch], EAX + +D_ConvertITTimer: + Test Byte Ptr [DS:2Eh], 2 ; Time data? + JZ D_LoadTimeDataNone + + ; Seek to 0C0+Orders+ + ; (ins+samp+pat)*4 + Mov DX, [DS:22h] + Add DX, [DS:24h] + Add DX, [DS:26h] + ShL DX, 2 + Add DX, [DS:20h] + Add DX, 0C0h + Xor CX, CX + Mov AX, 4200h + Int 21h + + Push DS + + Push CS + Pop DS + + Mov AH, 3Fh + Mov CX, 2 + Mov DX, Offset NumTimerData + Int 21h + + Push BX ; Allocate data for timedata + Mov BX, NumTimerData + Cmp BX, 0FFFFh + JNE D_NoTimerDataOverFlow + + Dec BX + Mov NumTimerData, BX + +D_NoTimerDataOverFlow: + Mov CX, BX + ShR BX, 1 + Inc BX + Mov AH, 48h + Int 21h + Pop BX + JC D_LoadTimeDataEnd + + Mov TimerData, AX + Mov DS, AX + ShL CX, 3 + Xor DX, DX + Mov AH, 3Fh + Int 21h + +D_LoadTimeDataEnd: + Pop DS + +D_LoadTimeDataNone: + Test Byte Ptr [DS:2Eh], 8 + JZ D_LoadMIDIConfigDataNone + + PushA + Push DS + + Call Music_GetMIDIDataArea + Xor DX, DX + Mov CX, 4896 + Mov AH, 3Fh + Int 21h + + Pop DS + PopA + +D_LoadMIDIConfigDataNone: + Test Byte Ptr [DS:2Eh], 1 + JZ D_LoadITMsg1 + ; Load the message + ; Move to offset first. + Mov AX, 4200h + Mov CX, [DS:3Ah] + Mov DX, [DS:38h] + Int 21h ; Seek to position + + Push DS + + Mov CX, [DS:36h] + Call Msg_GetMessageOffset + Mov AH, 3Fh + Int 21h + + Pop DS + +D_LoadITMsg1: + ; Actually, load row hilights first... + Test Byte Ptr [DS:2Eh], 4 + JZ D_LoadITNoHilight + + Mov AX, [DS:1Eh] + Push DS + + Push Pattern + Pop DS + Assume DS:Pattern + Mov Word Ptr [RowHilight1], AX + + Pop DS + Assume DS:Nothing + +D_LoadITNoHilight: + Xor SI, SI + Xor DI, DI + Mov CX, 192 + Rep MovsB ; Header + + Mov DI, 256 + Mov CX, [DS:20h] + + Mov DX, DI + Dec CX + Sub DX, CX + Rep MovsB ; Orders + Mov AL, 0FFh + Mov CX, DX + Rep StosB + + Inc SI ; SI points to first + ; pointer + + Xor BP, BP ; Instrument time. + +D_LoadIT1: + Cmp BP, [DS:22h] + JAE D_LoadIT2 + + Push DS + Push SI + + Push CS + Pop DS + Mov SI, Offset InstrumentMsg + Mov AX, BP + Inc AX + Push AX + Mov AH, 5 + Mov DI, (4+17*80)*2 + Call S_DrawString + Pop AX + + Pop SI + Pop DS + ; Move to offset.. + LodsW + Mov DX, AX + LodsW + Mov CX, AX + Mov AX, 4200h + Int 21h + + Mov DI, [DS:2Ah] ; Format version + + Push DS + Push SI + + Push ES + Pop DS + Mov SI, BP + Add SI, SI + Mov DX, [DS:64712+SI] + Mov CX, 554 + Mov AH, 3Fh + Int 21h + + Cmp DI, 200h + JAE D_LoadITInstrument1 + + Mov SI, DX + Call ConvertOldInstrument + +D_LoadITInstrument1: + Pop SI + Pop DS + Inc BP + Jmp D_LoadIT1 + +D_LoadIT2: + Xor BP, BP ; Sample header time. + +D_LoadIT3: + Cmp BP, [DS:24h] + JAE D_LoadIT4 + + Push DS + Push SI + + Push CS + Pop DS + Mov SI, Offset SHLoadMsg + Mov AX, BP + Inc AX + Push AX + Mov AH, 5 + Mov DI, (4+18*80)*2 + Call S_DrawString + Pop AX + + Pop SI + Pop DS + ; Move to offset.. + LodsW + Mov DX, AX + LodsW + Mov CX, AX + Mov AX, 4200h + Int 21h + + Push DS + Push SI + + Push ES + Pop DS + + Mov SI, BP + Add SI, SI + Mov DX, [DS:64912+SI] + Mov CX, 80 + Mov AH, 3Fh + Int 21h + + Pop SI + Pop DS + Inc BP + Jmp D_LoadIT3 + +D_LoadIT4: + Xor BP, BP + + Push DS + Push SI + + + Push ES + Pop DS ; DS now points to song data. + +D_LoadIT7: + Mov SI, BP + Add SI, SI + Mov SI, [64912+SI] + + Test Byte Ptr [DS:SI+12h], 1 + JZ D_LoadIT8 + + Push DS + Push SI + + Push CS + Pop DS + Mov SI, Offset SampleMsg + Mov AX, BP + Inc AX + Push AX + Mov AH, 5 + Mov DI, (4+19*80)*2 + Call S_DrawString + Pop AX + + Pop SI + Pop DS + + Mov AX, 4200h + Xor CX, CX + Xor DX, DX + XChg DX, [DS:SI+48h] + XChg CX, [DS:SI+4Ah] + Int 21h ; Move file pointer. + + Mov AX, BP + Call D_LoadSampleData + Jmp D_LoadITSamplePresent + +D_LoadIT8: + Mov DWord Ptr [SI+48h], 0 + +D_LoadITSamplePresent: + Inc BP + Cmp BP, 99 + JB D_LoadIT7 + + Pop SI + Pop DS + + Xor BP, BP + +D_LoadIT5: + Cmp BP, [DS:26h] ; Pattern time. + JAE D_LoadIT6 + + Push ES + + Push DS + Push SI + + Push CS + Pop DS + Mov SI, Offset PatternMsg + Push BP + Mov AH, 5 + Mov DI, (4+20*80)*2 + Call S_DrawString + Pop AX + + Pop SI + Pop DS + ; Move to offset.. + LodsW + Mov DX, AX + LodsW + Mov CX, AX + And DX, DX + JNZ D_LoadIT12 + And CX, CX + JZ D_LoadIT13 + +D_LoadIT12: + Mov AX, 4200h + Int 21h + + Push DS + Push SI + + Mov AH, 3Fh + Mov DX, 60000 + Mov CX, 8 + Int 21h ; DS:DX = pattern header. + + Mov DX, [DS:60000] ; DX = length + Push DX + Add DX, 8 + Mov SI, BP + + Push BX + Call Music_AllocatePattern + ; ES:DI = location. + Pop BX + + Mov AX, ES + And AX, AX + JZ D_LoadIT10 + + Mov SI, 60000 + Mov CX, 8 + Rep MovsB + + Push ES + Pop DS + Mov DX, DI + Mov AH, 3Fh + Pop CX ; CX = length. + Int 21h + + Jmp D_LoadIT11 + +D_LoadIT10: + Pop CX + Push BX + + + Call PEFunction_OutOfMemoryMessage + + Pop BX + +D_LoadIT11: + Pop SI + Pop DS + +D_LoadIT13: + Pop ES + + Inc BP + Jmp D_LoadIT5 + +D_LoadIT6: + Jmp D_PostLoadModule + + Ret + +EndP D_LoadIT + +; + +Proc D_LoadFileImpulseModule Far + + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_LoadITList + + Mov AX, 5 + Ret + +EndP D_LoadFileImpulseModule + +; + +Proc D_LoadFileS3MModule Far + + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_LoadS3MList + + Mov AX, 5 + Ret + +EndP D_LoadFileS3MModule + +; + +Proc D_LoadFile669Module Far + + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_Load669List + + Mov AX, 5 + Ret + +EndP D_LoadFile669Module + +; + +Proc D_LoadFileXMModule Far + + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_LoadXMList + + Mov AX, 5 + Ret + +EndP D_LoadFileXMModule + +; + +Proc D_LoadFileMTMModule Far + + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_LoadMTMList + + Mov AX, 5 + Ret + +EndP D_LoadFileMTMModule + +; + +Proc D_LoadFileMODModule Far + + Mov AL, 31 + Mov CL, [DS:60000+950] + Mov DX, 60952 + Mov SI, 1084 + + Cmp Word Ptr [BX+23], 16 + JNE D_LoadFileMODModule1 + + Mov AL, 15 + Mov CL, [DS:60000+470] + Mov DX, 60472 + Mov SI, 600 + +D_LoadFileMODModule1: + Mov CS:MODNumberOfInstruments, AL + Mov CS:MODNumberOfOrders, CL + Mov CS:MODOrderOffset, DX + Mov CS:MODPatternOffset, SI + + Mov SI, [BX+23] + Cmp SI, 17 + JNE D_LoadFileMODModule2 + + Mov AL, [BX+22] + Jmp D_LoadFileMODModule3 + +D_LoadFileMODModule2: + Sub SI, 9 + Mov AL, [CS:MODChannelTable+SI] + +D_LoadFileMODModule3: + Mov CS:MODNumberOfChannels, AL + + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_LoadMODList + + Mov AX, 5 + Ret + +EndP D_LoadFileMODModule + +ENDIF + +; + diff --git a/it/IT_D_WM.INC b/it/IT_D_WM.INC new file mode 100644 index 0000000..22e492c --- /dev/null +++ b/it/IT_D_WM.INC @@ -0,0 +1,1785 @@ +; +; +; Write module functions +; +; + + +Proc WriteITSampleBlock + + PushAD ; BX = file handle. + Push DS + + Mov DS, CS:DiskDataArea + + Mov DX, [DS:1996] + Mov CX, [DS:1998] + Mov AX, 4200h + Int 21h + + Mov AX, 80 + Mul Word Ptr [DS:24h] + Mov CX, AX + + Mov DX, 2000 + Call D_SaveBlock + +WriteITSampleBlock1: + Pop DS + PopAD + Ret + +EndP WriteITSampleBlock + +; + +NUMS3MCHANNELS EQU 16 + +BitLUT Label Byte + DB 1, 2, 3, 3, 4, 4, 4, 4 + DB 5, 5, 5, 5, 5, 5, 5, 5 + DB 4, 4, 4, 4, 3, 3, 2 + +BitLUT16 Label Byte + DB 1, 10 SHL 3 + 3, 11 SHL 3 + 5, 11 SHL 3 + 3 + DB 3 DUP (12 SHL 3 + 5), 12 SHL 3 + 3 + DB 7 DUP (13 SHL 3 + 5), 13 SHL 3 + 3 + + DB 13 SHL 3 + 4, 7 DUP (13 SHL 3 + 5) + DB 12 SHL 3 + 4, 3 DUP (12 SHL 3 + 5) + DB 11 SHL 3 + 4, 11 SHL 3 + 5, 10 SHL 3 + 4, 2 + + +Proc D_SaveIT Far + + + Call PE_SaveCurrentPattern + + Call D_UpdateFileName + + Push CS + Pop DS + Assume DS:Disk + + Mov NoSaveError, 0 + + Mov AH, 3Ch + Xor CX, CX ; File type is normal (archive) + Mov DX, Offset SaveFileName ; DS:DX points to filename + Int 21h + JNC D_SaveIT3 + + Call PE_RestoreCurrentPattern + Jmp D_NoSaveMessage + +D_SaveIT3: + Mov BX, AX ; BX = handle + + Mov ES, DiskDataArea + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing ; DS = MusicData + + Xor SI, SI + Xor DI, DI + Mov CX, 192 + Rep MovsB ; Get header. + + ; Now to figure out the + ; orders. + Mov SI, 511 + StD + Mov CX, 256 + +D_SaveIT4: + LodsB + Cmp AL, 0FFh + LoopE D_SaveIT4 + + ClD + + Add CX, 2 + Mov [ES:20h], CX + Dec CX + + Mov SI, 256 + Rep MovsB ; Transfer orders. + Mov AL, 0FFh + StosB + +; Mov AX, 0 +; Test Byte Ptr [DS:2Ch], 4 +; JZ D_SaveIT6 +; + Call Music_GetNumberOfInstruments +; +; D_SaveIT6: + Mov [ES:22h], AX ; Number of instruments + + Call Music_GetNumberOfSamples + Mov [ES:24h], AX ; Number of samples + + Call PE_GetMaxPattern + Inc AX + Mov [ES:26h], AX ; Number of patterns. + + Xor CX, CX ; CX:DX = 'long' offsets. + Mov DX, 0C0h + Add DX, [ES:20h] + Mov AX, [ES:22h] + ShL AX, 2 + Add DX, AX + Mov AX, [ES:24h] + ShL AX, 2 + Add DX, AX + Mov AX, [ES:26h] + ShL AX, 2 + Add DX, AX + + Mov DWord Ptr [ES:36h], 0 + Mov Word Ptr [ES:2Eh], 4 ; Row hilight information + + Push DS + + Push Pattern + Pop DS + Assume DS:Pattern + + Mov AX, Word Ptr [RowHilight1] + + Pop DS + Assume DS:Nothing + + Mov [ES:1Eh], AX + + + Call GetTimerCounter + Sub EAX, EditTimer + + Cmp TimerData, 0 + JE NoTimerData + + Or Byte Ptr [ES:2Eh], 2 ; Contains timer information + + Push ES ; Put time into table. + Push DI + + Mov ES, TimerData + Mov DI, NumTimerData + ShL DI, 3 + Add DI, 4 + StosD + Add DI, 2 + + Add DX, DI ; Long offset progress. + AdC CX, 0 + + Pop DI + Pop ES + +NoTimerData: +; OK.. check for MIDI config save. + Test Byte Ptr [DS:2Ch], 128 + JZ D_SaveITNoMIDIConfig1 + + Add DX, 4896 ; MIDI Config size + AdC CX, 0 + Or Byte Ptr [ES:2Eh], 8 ; MIDI Config. + +D_SaveITNOMIDIConfig1: + + Add EAX, [ES:3Ch] + Xor EAX, 'JTHL' + RoR EAX, 4 + Neg EAX + RoL EAX, 7 + Xor EAX, 'ITRK' + + Mov [ES:3Ch], EAX + + Call Msg_GetMessageLength + Cmp AX, 1 + JE D_SaveITMsg1 + + Or Byte Ptr [ES:2Eh], 1 + Mov Word Ptr [ES:3Ah], 0 + Mov [ES:38h], DX + Mov [ES:36h], AX + Add DX, AX + +D_SaveITMsg1: + Mov BP, [ES:22h] ; Number of instruments + + Mov AX, 214h + + Cmp CS:SaveFormat, 0 + JE D_SaveNewFormat + + Inc AX + Cmp CS:SaveFormat, 3 + JE D_SaveNewFormat + + Mov AX, 200h + +D_SaveOldIT2_1: + Test BP, BP + JNZ D_SaveNewFormat + + Mov AX, 100h + +D_SaveNewFormat: + Inc BP + Mov Word Ptr [ES:28h], TRACKERVERSION + Mov [ES:2Ah], AX + And EBP, 0FFFFh + +D_SaveIT7: + Dec BP + JZ D_SaveIT8 + + Mov SI, [DS:EBP+EBP+64710] + Test Byte Ptr [SI+1D4h], 80h + JZ D_SaveIT216 + + Mov Word Ptr [ES:2Ah], 216h + +D_SaveIT216: + Mov AX, DX + StosW + Mov AX, CX + StosW + Add DX, 554 + AdC CX, 0 + + Jmp D_SaveIT7 + +D_SaveIT8: + Mov BP, [ES:24h] ; Number of samples + Inc BP + Mov [ES:1996], DX ; Store sample position. + Mov [ES:1998], CX + +D_SaveIT9: + Dec BP + JZ D_SaveIT10 + + Mov AX, DX + StosW + Mov AX, CX + StosW + + Add DX, 80 + AdC CX, 0 + + Jmp D_SaveIT9 + +D_SaveIT10: + + Xor BP, BP + +D_SaveIT11: + Cmp BP, [ES:26h] ; Number of patterns + JAE D_SaveIT12 + + Push DS + + Mov AX, BP + Call Music_GetPattern ; DS:SI has pattern + + Mov AX, DS + Cmp AX, Music + JE D_SaveIT1 + + Mov AX, DX + StosW + Mov AX, CX + StosW + + Add DX, [DS:SI] + AdC CX, 0 + Add DX, 8 ; pattern header length = 8. + AdC CX, 0 + + Jmp D_SaveIT22 + +D_SaveIT1: + Xor EAX, EAX + StosD + +D_SaveIT22: + Pop DS + + Inc BP + Jmp D_SaveIT11 + +D_SaveIT12: + ; CX:DX now point to first sample data. + Push CX + Push DX + + Push DS + + Push DI + + Push CS + Pop DS + Mov DI, (4+17*80)*2 + Mov SI, Offset HeaderMsg + Mov AH, 5 + Call S_DrawString + + Pop CX ; CX = length of header. + + Push ES + Pop DS + + Xor DX, DX + Call D_SaveBlock ; Header. + + Test Byte Ptr [DS:2Eh], 2 ; Time information? + JZ D_SaveITTimeData + + Push DS + + Push CS + Pop DS + + Mov CX, 2 + Mov DX, Offset NumTimerData + Inc [DS:NumTimerData] + Call D_SaveBlock + Mov CX, [DS:NumTimerData] + Dec [DS:NumTimerData] + ShL CX, 3 + Mov DS, [DS:TimerData] + Xor DX, DX + Call D_SaveBlock + + Pop DS + +D_SaveITTimeData: + Test Byte Ptr [DS:2Ch], 128 + JZ D_SaveITMIDIConfig + + Push DS + + Mov CX, 4896 + Xor DX, DX + Call Music_GetMIDIDataArea ; Gets DS + Call D_SaveBlock + + Pop DS + +D_SaveITMIDIConfig: + ; Message? + Test Byte Ptr [DS:2Eh], 1 + JZ D_SaveITMsg2 + + Mov CX, [DS:36h] + Push DS + Call Msg_GetMessageOffset + Call D_SaveBlock + Pop DS + +D_SaveITMsg2: + Push CS + Pop DS + Mov DI, (4+18*80)*2 + Mov SI, Offset InstrumentHeaderMsg + Mov AH, 5 + Call S_DrawString + + Pop DS + Cmp Word Ptr [ES:22h], 0 + JE D_SaveIT13 + + Mov AX, 554 + Mul Word Ptr [ES:22h] + Mov DX, 512 + Mov CX, AX + + Call D_SaveBlock ; Instrument headers... + +D_SaveIT13: + Push DS + + Push CS + Pop DS + Mov DI, (4+19*80)*2 + Mov SI, Offset SampleHeaderMsg + Mov AH, 5 + Call S_DrawString + + Pop DS ; DS = song data segment + Mov SI, 55912 ; Start of samples in mem. + Mov AX, 80 + Mul Word Ptr [ES:24h] + Mov DI, 2000 + Mov CX, AX + Rep MovsB + + Pop DX + Pop CX ; CX:DX = sample point. + + Mov BP, [ES:24h] ; Number of samples. + Mov SI, 2000 + Inc BP + +D_SaveIT14: + Dec BP + JZ D_SaveIT16 + Mov AL, [ES:SI+12h] + Mov AH, 1 + + Cmp CS:SaveFormat, 3 + JNE D_SaveNoDD + + Or AH, 4 + +D_SaveNoDD: + Test AL, 1 + JZ D_SaveIT15 + + Or AL, 8 + Cmp CS:SaveFormat, 2 + JNE D_SaveIT214_1 + + And AL, Not 8 + +D_SaveIT214_1: + Mov [ES:SI+48h], DX + Mov [ES:SI+4Ah], CX + + Test AL, 2 + Mov [ES:SI+12h], AL + Mov [ES:SI+2Eh], AH + Mov EAX, [ES:SI+30h] + JZ D_SaveIT16Bit + + Add EAX, EAX + +D_SaveIT16Bit: + Add DX, AX + PushF + ShR EAX, 16 + PopF + AdC CX, AX ; Advance sample pointer. + +D_SaveIT15: + Add SI, 80 + Jmp D_SaveIT14 + +D_SaveIT16: + Call WriteITSampleBlock + + Xor BP, BP + +D_SaveIT17: + Push DS + + Push CS + Pop DS + Mov DI, (4+20*80)*2 + Mov SI, Offset PatternMsg + Mov AH, 5 + Push BP + Call S_DrawString + Pop AX + + Call Music_GetPattern + Mov DX, DS + Cmp DX, Music + JE D_SaveIT2 + + Mov DX, SI + Mov CX, [DS:SI] + Add CX, 8 + Call D_SaveBlock + +D_SaveIT2: + Pop DS + Inc BP + Cmp BP, [ES:26h] + JB D_SaveIT17 + +; Setup compression block + Push DS + + Push CS + Pop DS + Mov SI, Offset BitLUT + + Mov DI, 10240 + Mov CX, 16/2 + Rep MovsW + +; Setup table. + + Mov CX, 16 + Mov AL, 6 + Rep StosB + + Mov CX, 28 + Inc AX + Rep StosB + + Mov CX, 64 + Inc AX + Rep StosB + + Mov CX, 8 + Inc AX + Rep StosB + + Mov CX, 64 + Dec AX + Rep StosB + + Mov CX, 29 + Dec AX + Rep StosB + + Mov CX, 16 + Dec AX + Rep StosB + + Mov CX, 15 + Sub SI, 8 + Rep MovsB + +; 16 bit Main LUT + + Mov SI, Offset BitLUT16 + Mov CX, 16 + Rep MovsB + + Mov CX, 15 + Mov AL, 14 SHL 3 + 5 + Rep StosB + Mov AL, 14 SHL 3 + 3 + StosB + + Mov CX, 31 + Mov AL, 15 SHL 3 + 5 + Rep StosB + Mov AL, 15 SHL 3 + 3 + StosB + + Mov CX, 63 + Mov AL, 16 SHL 3 + 5 + Rep StosB + Mov AL, 16 SHL 3 + 3 + StosB + + Inc AX +; Mov AL, 16 SHL 3 + 4 + StosB + Mov CX, 63 + Inc AX +; Mov AL, 16 SHL 3 + 5 + Rep StosB + + Mov AL, 15 SHL 3 + 4 + StosB + Mov CX, 31 + Mov AL, 15 SHL 3 + 5 + Rep StosB + + Mov AL, 14 SHL 3 + 4 + StosB + Mov CX, 15 + Mov AL, 14 SHL 3 + 5 + Rep StosB + + Mov CX, 16 + Rep MovsB + +; 16 bit LUT 1, for 16-bit samples with high byte = 0 + + Mov SI, Offset BitLUT + Mov CX, 16 + Rep MovsB + + Mov CX, 16 + Mov AL, 6 + Rep StosB ; AL = 6 from before + + Mov CX, 24 + Inc AX + Rep StosB + + Mov CX, 64 + Inc AX + Rep StosB + + Mov CX, 128 + Inc AX + Rep StosB + +; 16-Bit LUT 2, for 16-bit samples with high byte = 0xFF + + Mov CX, 16 + Inc AX + Rep StosB + + Mov CX, 128 + Dec AX + Rep StosB + + Mov CX, 64 + Dec AX + Rep StosB + + Mov CX, 25 + Dec AX + Rep StosB + + Mov CX, 16 + Dec AX + Rep StosB + + Mov CX, 15 + Sub SI, 8 + Rep MovsB + + Mov CX, 256-8 + Xor AX, AX + Rep StosB + + Mov CX, 16 + Inc AX + Rep StosB + + Mov CX, 256-8+256 + Dec AX + Rep StosB + + Pop DS + + Xor BP, BP ; BP = sample number. + Mov DI, 2000+48h + +D_SaveIT18: + Push DS + Push DI + + Xor CX, CX + Xor DX, DX + Mov AX, 4201h + Int 21h + + Mov [ES:DI], AX + Mov [ES:DI+2], DX + + Mov SI, BP + Add SI, SI + Mov SI, [64912+SI] ; DS:SI points to sample head. + + Test Byte Ptr [SI+12h], 1 ; Check if sample is present. + JZ D_SaveIT19 + Cmp DWord Ptr [SI+30h], 0 ; For bodgy sample crap. + JZ D_SaveIT19 + +D_SaveIT21: + Push DS ; DS:DX points to sample... + Push SI + + Push CS + Pop DS + Mov DI, (4+21*80)*2 + Mov SI, Offset SampleMsg + Mov AX, BP + Inc AX + Push AX + Mov AH, 5 + Call S_DrawString + Pop AX + + Pop SI + Pop DS ; Sample encoding to go here.. + ; But sample position needs to + ; be recoded then... + Cmp CS:SaveFormat, 2 + JNE D_SaveSampleDataCompressedCall + + Call D_SaveSampleData + Jmp D_SaveIT19 + +D_SaveSampleDataCompressedCall: + Call D_SaveSampleDataCompressed + +D_SaveIT19: + Pop DI + Pop DS + + Add DI, 80 + + Inc BP + Cmp BP, [ES:24h] + JB D_SaveIT18 + + Call WriteITSampleBlock + + Mov AH, 3Eh ; Close file + Int 21h + + Push CS + Pop DS + Mov DI, (4+23*80)*2 + Mov SI, Offset CompleteMsg + Mov AH, 5 + Call S_DrawString + +EndSaveModule: + Mov DX, Offset SaveFileName + Call D_DeleteIfError + + Call PE_RestoreCurrentPattern + + Cmp NoSaveError, 0 + JNE SaveModuleError + + Call PEResetModified + +SaveModuleError: + Mov AX, 1 + Ret + +EndP D_SaveIT + Assume DS:Nothing + +; + +Proc D_SaveS3M Far + + Call PE_SaveCurrentPattern + Call D_UpdateFileName + + Mov BP, 60h ; BP = length of header. +; Call PE_StoreCurrentPattern + + Push CS + Pop DS + Assume DS:Disk + + Mov SaveFormatError, 0 + + Mov NoSaveError, 0 + + Mov AH, 3Ch + Xor CX, CX ; File type is normal (archive) + Mov DX, Offset SaveFileName ; DS:DX points to filename + Int 21h + JNC D_SaveS3M1 + + Call PE_RestoreCurrentPattern + Jmp D_NoSaveMessage + +D_SaveS3M1: + Mov BX, AX + + Mov ES, DiskDataArea + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing ; DS = MusicData + + Mov SI, 4 + Xor DI, DI + Mov CX, 26/2 + Rep MovsW + Xor AX, AX + StosW + Mov AX, 1Ah+16*256 ; St3 module identification. + StosW + Xor AX, AX + StosW + ; Now to figure out the + ; orders. + Mov SI, 511 + StD + Mov CX, 256 + +D_SaveS3M2: + LodsB + Cmp AL, 0FFh + LoopE D_SaveS3M2 + + ClD + + Inc CX + Mov AX, CX + Inc AX ; Number of orders. + Add BP, AX + StosW + + Call Music_GetNumberOfSamples + Add BP, AX + Add BP, AX + StosW ; Number of samples. + + Call PE_GetMaxPattern + Inc AX + Add BP, AX + Add BP, AX + Cmp AX, 100 + JBE D_SaveS3M4 + + Mov AX, 100 + + Push Offset D_SaveS3M4 + Push SI + Push DI + Mov SI, Offset TooManyPatternsMsg + Mov DI, (4+23*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M4: + StosW ; Number of patterns + + ; Flags... 8 = vol0opt on. + Mov AX, [DS:2Ch] + And AX, 2 + ShL AX, 2 + StosW ; Flags stored. + + Mov AX, 3000h+TRACKERVERSION + StosW ; Impulse Tracker + + Mov AX, 2 + StosW ; Standard unsigned samples. + + Mov EAX, 'MRCS' + StosD ; ID done. + + Mov AH, [DS:2Ch] + Test AH, 4 + JZ D_SaveS3MNoInsError + + Push Offset D_SaveS3MNoInsError + Push SI + Push DI + Mov SI, Offset ST3InstrumentErrorMsg + Mov DI, (4+29*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3MNoInsError: + Mov AL, [DS:30h] + ShR AL, 1 + StosB + Mov AX, [DS:32h] ; Tempo and speed + StosW + Mov AL, [DS:31h] ; Mixing volume + Mov AH, [DS:2Ch] ; Grab stereo setting. + Cmp AL, 80h + JB D_SaveNoMixOverflow + + Mov AL, 7Fh + +D_SaveNoMixOverflow: + ShL AL, 1 + ShR AX, 1 + StosB + + Mov AX, 252*256 + StosW + Xor AX, AX + StosW + + Call GetTimerCounter + Sub EAX, EditTimer + Add EAX, [DS:3Ch] + + Xor EAX, 'JTHL' + RoR EAX, 4 + Neg EAX + RoL EAX, 7 + Xor EAX, 'ITRK' + + StosD + + Xor AX, AX + StosW + + Mov SI, 256 ; Orders. + Mov DI, 60h + JCXZ D_SaveS3M3 + +D_SaveS3M5: + LodsB + Cmp AL, 0FEh + JAE D_SaveS3M6 + Cmp AL, 100 + JB D_SaveS3M6 + + Mov AL, 0FFh ; So that pattern numbers >= 100 aren't listed + +D_SaveS3M6: + StosB + Loop D_SaveS3M5 + +D_SaveS3M3: + Mov AL, 0FFh + StosB + + ; Do channel settings. + Push BX + + Mov BX, BP + + Mov SI, 40h + Mov DI, SI + Sub BX, DI + + Mov CX, 32 + Xor AH, AH + +D_SaveS3M7: + LodsB + Test AL, 80h + JNZ D_SaveS3M9 + + Cmp AL, 64 + JBE D_SaveS3M8 + + Mov AL, 32 ; For surround. + +D_SaveS3M8: + ; Convert 0->64 to 0->15 + Mov DL, AL + ShR DL, 1 + Sub DL, 1 + AdC DL, 0 + ShR DL, 1 + Or DL, 32 ; Reqd... + + Mov AL, AH + + And AL, 1 + ShL AL, 3 + Mov DH, AH + ShR DH, 1 + Or AL, DH + + Inc AH + Jmp D_SaveS3M10 + +D_SaveS3M9: ; Muted/nonexistant + Mov AL, 0FFh + Mov DL, 0 + +D_SaveS3M10: + Mov [ES:BX+DI], DL + StosB + Loop D_SaveS3M7 + + Pop BX + + Add BP, 20h + + ; Check that channel volumes are all 64... + + Mov CX, 32 + Mov SI, 80h + +D_SaveS3M11: + LodsB + Cmp AL, 64 + JNE D_SaveS3M12 + Loop D_SaveS3M11 + Jmp D_SaveS3M13 + +D_SaveS3M12: + Push Offset D_SaveS3M13 + Push SI + Push DI + Mov SI, Offset ChannelVolumeErrorMsg + Mov DI, (4+24*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M13: + Test Byte Ptr [DS:2Ch], 8 + JZ D_SaveS3M15 + + Push Offset D_SaveS3M15 + Push SI + Push DI + Mov SI, Offset LinearSlideMsg + Mov DI, (4+25*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M15: + Push DS + + Push CS + Pop DS + Mov DI, (4+17*80)*2 + Mov SI, Offset SampleHeaderMsg + Mov AH, 5 + Call S_DrawString + + Pop DS + Assume DS:Nothing + + Push BP ; BP = length of header. + + Xor AX, AX ; AX = sample number. + Xor DX, DX ; DX:BP = file position. + ; BX = file handle + +;-------------------------------------- + +D_SaveS3M14: + Push AX + + Add BP, 15 ; Align on next 16-byte boundary. + AdC DX, 0 ; Unnecessary.. but who cares. + ; Now to store pointer. + And BP, Not 15 + + Push DX + + Mov DI, AX + Add DI, DI + + Push DI + + Add DI, 60h + Add DI, [ES:20h] + + ; Move file pointer. + Mov AX, 4200h + Mov CX, DX + Mov DX, BP + Int 21h + + SHRD AX, DX, 4 + Mov [ES:DI], AX + + ; Set up sample block at ES:1024. + Pop DI + Push BX + + Mov BX, [DS:64912+DI] ; DS:BX points to sample header. + + Mov DI, 1024 + Mov AL, [BX+12h] + Mov DL, AL + And AL, 1 + + StosB + + Mov SI, BX + Add SI, 4 + Mov CX, 12 + Rep MovsB ; filename + + Xor AX, AX + StosB + StosW + + Mov SI, BX + Add SI, 30h + Mov CX, 6 + Rep MovsW ; Length/Loopbeg/Loopend. + + Mov AL, [DS:BX+13h] + StosW ; Default sample volume. + + Mov AH, DL + Mov CL, DL + ShR AH, 4 + And AX, 100h + ShL CL, 1 + And CL, 4 + Or AH, CL + + StosW ; Loop, 16 Bit & no 'pack' + + MovsW + MovsW + + Mov CX, 6 + Xor AX, AX + Rep StosW + ; Now for sample name. + + Mov SI, BX + Add SI, 14h + Mov CX, 25 + +D_SaveS3M56: + LodsB + And AL, AL + JNZ D_SaveS3M57 + + Mov AL, 32 + +D_SaveS3M57: + StosB + Loop D_SaveS3M56 + + Xor AX, AX + StosB + StosW + + Mov EAX, 'SRCS' + StosD ; OK header is done... + + Test DL, 16+32 + JZ D_SaveS3M16 ; No loop on. + + Test DL, 32 + JNZ D_SaveS3M51 + + Test DL, 64 + JZ D_SaveS3M16 + +D_SaveS3M51: + Push Offset D_SaveS3M16 + Push SI + Push DI + Mov SI, Offset LoopMsg + Mov DI, (4+27*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M16: + Cmp Byte Ptr [DS:BX+11h], 64 + JE D_SaveS3M17 + + Push Offset D_SaveS3M17 + Push SI + Push DI + Mov SI, Offset SampleVolumeMsg + Mov DI, (4+26*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M17: + Cmp Byte Ptr [DS:BX+4Dh], 0 + JE D_SaveS3M18 + + Push Offset D_SaveS3M18 + Push SI + Push DI + Mov SI, Offset SampleVibratoMsg + Mov DI, (4+28*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M18: ; Write block. + Pop BX + Push DS + + Push ES + Pop DS + Mov DX, 1024 + Mov CX, 50h + Call D_SaveBlock + + Pop DS + Pop DX + + Add BP, 50h ; Advance file pointer. + AdC DX, 0 + + Pop AX + Inc AX + Cmp AX, [ES:22h] + JB D_SaveS3M14 ; Sample headers done. + +;----------------------------------- + ; Pattern data. + Xor AX, AX ; Start with pattern 0 + +D_SaveS3M19: + Push AX + ; Shove message on screen.... + Add BP, 15 ; Align on next 16-byte boundary. + AdC DX, 0 ; Unnecessary.. but who cares. + ; Now to store pointer. + And BP, Not 15 + + Push DX + + Push AX ; AX for pattern msg... + + Mov DI, AX + Add DI, DI + + Add DI, 60h + Add DI, [ES:20h] + Mov CX, [ES:22h] + Add CX, CX + Add DI, CX + + ; Move file pointer. + Mov AX, 4200h + Mov CX, DX + Mov DX, BP + Int 21h + + SHRD AX, DX, 4 ; DX:AX = new file pointer location + Mov [ES:DI], AX + + Push CS + Pop DS + + Mov DI, (4+18*80)*2 + Mov SI, Offset PatternMsg + Mov AH, 5 + Call S_DrawString + + Pop AX ; AX = pattern. + Call Music_GetPattern ; DS:SI points to pattern. + + Mov CX, [SI+2] ; CX = length. + Cmp CX, 64 + JE D_SaveS3M20 + + Push Offset D_SaveS3M20 + Push SI + Push DI + Mov SI, Offset PatternLengthMsg + Mov DI, (4+30*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M20: + Push BX + + Push CX + + Mov DI, 20000 + Mov CX, 64 + +D_SaveS3M25: + Mov AX, 0FD00h ; Mask & note. + StosW + Mov AH, 0FFh ; instrument & volume. + StosW + Xor AH, AH + StosW + StosW + Loop D_SaveS3M25 + + Mov DI, 30002 + Add SI, 8 + + Pop CX + Push CX + +D_SaveS3M22: ; Pattern translation time. + Push CX + +D_SaveS3M33: + LodsB + And AL, AL + JZ D_SaveS3M23 + + Mov DL, AL + And AX, 7Fh + Dec AX + Mov CL, 3 + ShL AX, CL + Mov BX, AX + Add BX, 20000 ; ES:BX points to old information. + ; Decode row into area. + + Mov DH, [ES:BX] + + Test DL, 80h + JZ D_SaveS3M24 + + LodsB ; Mask + Mov [ES:BX], AL + Mov DH, AL + +D_SaveS3M24: + Test DH, 1 + JZ D_SaveS3M26 + + LodsB + Mov [ES:BX+1], AL + +D_SaveS3M26: + Test DH, 2 + JZ D_SaveS3M27 + + LodsB + Mov [ES:BX+2], AL + +D_SaveS3M27: + Test DH, 4 + JZ D_SaveS3M28 + + LodsB + Cmp AL, 64 + JA D_SaveS3MPanError + +D_SaveS3M28_2: + Mov [ES:BX+3], AL ; Volume + +D_SaveS3M28: + Test DH, 8 + JZ D_SaveS3M29 + + LodsW ; Effect+value. + Mov [ES:BX+4], AX + +D_SaveS3M29: + And DL, 7Fh + Cmp DL, NUMS3MCHANNELS + JA D_SaveS3M30 + + Dec DX + Test DH, 33h + JZ D_SaveS3M31 + + Or DL, 32 + +D_SaveS3M31: + Test DH, 44h + JZ D_SaveS3M32 + + Or DL, 64 ; Volume + +D_SaveS3M32: + Test DH, 88h + JZ D_SaveS3M34 + + Or DL, 128 ; Effect. + +D_SaveS3M34: + ; Check if note in range. + Mov AX, [ES:BX+1] + Mov [ES:BX+6], AX ; BX+6=note, BX+7=ins. + + Cmp AL, 120 + JAE D_SaveS3M55 + + Test DH, 11h + JZ D_SaveS3M55 + Test DH, 22h + JZ D_SaveS3M55 + + Push DS + + Call Music_GetSongSegment + Mov DS, AX + Test Byte Ptr [DS:2Ch], 4 + JZ D_SaveS3M54 + + Push BX + Push DI + + Mov DI, BX + + Mov BL, [ES:BX+7] + And BX, 0FFh ; BX = ins. + JZ D_SaveS3M52 + + Add BX, BX + Mov BX, [BX+64712-2] ; BX points to instrument. + Mov AL, [ES:DI+1] + And AX, 0FFh + Add AX, AX + Add BX, AX + Mov AX, [BX+40h] + + Mov [ES:DI+6], AX + +D_SaveS3M52: + Pop DI + Pop BX + +D_SaveS3M54: + Pop DS + +D_SaveS3M55: + Mov AL, DL + + Test DL, 32 ; Do note? + JZ D_SaveS3M35 + + Mov AH, [ES:BX+6] ; AH = note. + Cmp AH, 0FDh + JAE D_SaveS3M35 + Cmp AH, 12 + JB D_SaveS3M36 ; Note out of range. + Cmp AH, 108 + JAE D_SaveS3M36 + +D_SaveS3M35: + StosB ; Store mask. + Test DL, 32 + JZ D_SaveS3M39 + + Mov AL, 0FFh + Test DH, 11h + JZ D_SaveS3M37 + + Cmp AH, 0FDh + JE D_SaveS3M37 + + Mov AL, 0FEh + Cmp AH, 0FEh + JAE D_SaveS3M37 + + Mov AL, AH + Xor AH, AH + Sub AL, 12 + Mov CX, 12*256+4 + Div CH ; AL = octave, AH = note. + ShL AL, CL + Or AL, AH + +D_SaveS3M37: + Mov AH, 0 + Test DH, 22h + JZ D_SaveS3M50 + + Mov AH, [ES:BX+7] + +D_SaveS3M50: + StosW + +D_SaveS3M39: + Test DL, 64 + JZ D_SaveS3M40 + + Mov AL, [ES:BX+3] + StosB + +D_SaveS3M40: + Test DL, 128 + JZ D_SaveS3M41 + + Mov AX, [ES:BX+4] + +; Cmp AL, 'H'-'@' +; JE D_SaveVibDepth1 +; Cmp AL, 'U'-'@' +; JE D_SaveVibDepth2 +; + Cmp AX, 'S'-'@'+9100h + JE D_SaveS3MSurround + + Cmp AL, 'V'-'@' + JE D_SaveS3M46 + Cmp AL, 'X'-'@' + JE D_SaveS3M46 + + Cmp AL, 'C'-'@' + JNE D_SaveS3M47 + + Mov AL, AH + Xor AH, AH + Mov CX, 10*256+4 + Div CH + ShL AL, CL + Or AH, AL + Mov AL, 'C'-'@' + Jmp D_SaveS3M47 + +D_SaveS3MSurround: + Mov AX, 'X'-'@'+0A400h + Jmp D_SaveS3M47 + +D_SaveS3M46: + ShR AH, 1 + +D_SaveS3M47: + StosW + +D_SaveS3M41: + Jmp D_SaveS3M33 + +; D_SaveVibDepth1: ; Command H +; Mov CL, AH +; And AH, 0Fh +; And CL, 0F0h +; Inc AH +; ShR AH, 1 +; Or AH, CL +; +; StosW +; Jmp D_SaveS3M33 +; +;D_SaveVibDepth2: +; Mov CL, AH +; And AH, 0Fh ; AH = depth +; Inc AH +; ShR AH, 1 +; And CL, 0F0h +; Or AH, CL +; +; StosW +; Jmp D_SaveS3M33 + +D_SaveS3MPanError: + Mov AL, 0FFh + Mov Byte Ptr [ES:BX+3], AL ; Volume + + Push Offset D_SaveS3M28_2 + Push SI + Push DI + Mov SI, Offset PanningErrorMsg + Mov DI, (4+33*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M30: + Push Offset D_SaveS3M33 + Push SI + Push DI + Mov SI, Offset ChannelErrorMsg + Mov DI, (4+31*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M36: + Push Offset D_SaveS3M33 + Push SI + Push DI + Mov SI, Offset NoteRangeMsg + Mov DI, (4+32*80)*2 + Jmp D_SaveS3MFormatError + +D_SaveS3M23: + StosB + Pop CX + Loop D_SaveS3M22 + + Pop CX + Pop BX + Sub CX, 64 + JNC D_SaveS3M21 + + Neg CX + Xor AL, AL + Rep StosB + +D_SaveS3M21: + Mov CX, DI + Sub CX, 30000 + Mov [ES:30000], CX ; Pattern length. + + Push ES + Pop DS + Mov DX, 30000 + Call D_SaveBlock + + Pop DX + + Add BP, CX + AdC DX, 0 + + Pop AX + Inc AX + Cmp AX, [ES:24h] + JB D_SaveS3M19 + +;----------------------------------- + ; Now to save samples. + Mov DI, 10000 + Mov CX, 200 ; ES:10000 contains sample pointers. + Xor AX, AX + Rep StosW + +D_SaveS3M42: + Inc AX + Push AX + + Xor CX, CX + Call Music_GetSampleLocation ; Gets DS:SI, ECX + JC D_SaveS3M43 + + JZ D_SaveS3M8Bit + + Add ECX, ECX + +D_SaveS3M8Bit: + Push DS + Push AX + + Push CS + Pop DS + Mov DI, (4+19*80)*2 + Mov SI, Offset SampleMsg + Mov AH, 5 + Call S_DrawString + + Pop AX + Pop DS + + ; Shove message on screen.... + Add BP, 15 ; Align on next 16-byte boundary. + AdC DX, 0 + And BP, Not 15 + + Push ECX + Push DX + Push AX ; AX = sample num + + Mov DI, AX + Dec DI + Add DI, DI + Add DI, DI + Add DI, 10000 + Mov AX, BP + StosW + Mov AX, DX + StosW + + + Mov AX, 4200h + Mov CX, DX + Mov DX, BP + Int 21h ; Set file offset. + + Pop AX + + Call D_SaveSampleDataConvert + + Pop DX + Pop ECX + Add BP, CX + PushF + ShR ECX, 16 + PopF + AdC DX, CX + +D_SaveS3M43: + Pop AX + Cmp AX, [ES:22h] + JB D_SaveS3M42 + +;----------------------------------- + + Push CS + Pop DS + Assume DS:Disk + + Mov DI, (4+20*80)*2 + Mov SI, Offset HeaderMsg + Mov AH, 5 + Call S_DrawString + + Mov AX, 4200h + Xor CX, CX + Xor DX, DX + Int 21h ; Go back to start of file. + + Push ES + Pop DS + Xor DX, DX + Pop CX ; CX = length of header. (previously BP) + Call D_SaveBlock + + ; To do sample pointers now. + Mov SI, 10000 + Xor BP, BP + +D_SaveS3M44: + Mov DI, BP + Add DI, DI + Add DI, 60h ; Length of header + Add DI, [DS:20h] ; Past Orders, DS:SI points to parasample + + Xor CX, CX + Mov DX, [DI] + SHLD CX, DX, 4 + ShL DX, 4 + + Add DX, 0Dh + + Mov AX, 4200h + Int 21h ; file re-position. + + LodsW + Mov DX, AX + LodsW ; AX:DX contains sample pointer. + + ShRD DX, AX, 4 + ShR AX, 4 ; AX:DX contains para pointer. + + Mov [DS:0], AL + Mov [DS:1], DX + Mov CX, 3 + Xor DX, DX + Call D_SaveBlock + + Inc BP + Cmp BP, [DS:22h] + JB D_SaveS3M44 + + Mov AH, 3Eh ; Close file. + Int 21h + + Push CS + Pop DS + Assume DS:Disk + + Mov DI, (4+21*80)*2 + Mov SI, Offset CompleteMsg + Mov AH, 5 + Call S_DrawString + + Cmp SaveFormatError, 0 + JE D_SaveS3M_NoKeyWait + + Call K_ClearKeyboardQueue + +D_SaveS3MKeyWait: + Call K_GetKey + Test CH, 1 + JZ D_SaveS3MKeyWait + +D_SaveS3M_NoKeyWait: + Jmp EndSaveModule + +D_SaveS3MFormatError: + Push AX + Push DS + + Push CS + Pop DS + Assume DS:Disk + + Mov SaveFormatError, 1 + Mov AH, 4 + Call S_DrawString + + Pop DS + Pop AX + Pop DI + Pop SI + RetN + +EndP D_SaveS3M + Assume DS:Nothing + +; + +Proc D_SaveFileITModule Far + + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_SaveITList + + Mov AX, 5 + Ret + +EndP D_SaveFileITModule + +; + +Proc D_SaveFileS3MModule Far + + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_SaveS3MList + + Mov AX, 5 + Ret + +EndP D_SaveFileS3MModule + + +; + diff --git a/it/IT_EMS.ASM b/it/IT_EMS.ASM new file mode 100644 index 0000000..647fbe6 --- /dev/null +++ b/it/IT_EMS.ASM @@ -0,0 +1,973 @@ +;Ŀ +; EMS Module +; + +include switch.inc + +; Memory structure for patterns: +; Memory Block Header +; Memory data +; +; Block Header +; Offset 0: DWord - Number of bytes in block (not including header) +; Offset 4: Word - Segment of last block, 0 if first +; Offset 6: Word - Segment of next block, 0 if last +; Offset 8: Byte - 0 = Unused, 1 = Used +; Offset 9-0Fh: Not used +; Offset 10h Data + + Jumps + .386 + +;Ŀ +; Externals +; + +Segment Object1 BYTE Public 'Data' + Extrn EMSErrorValue:Word + Extrn EMSErrorValue2:Word + Extrn EMSErrorValue3:Word + Extrn EMSErrorValue4:Word + Extrn EMSErrorValue5:Word + Extrn EMSErrorValue6:Word + Extrn EMSErrorValue7:Word + Extrn EMSErrorValue8:Word +EndS + + Extrn M_Object1List:Far + + Extrn O1_EMSWarningMessage + +;Ŀ +; Globals +; + + Global E_AllocateEMS:Far + Global E_InitEMS:Far + Global E_UnInitEMS:Far + Global E_GetFreeEMS:Far + Global E_ReleaseEMS:Far + Global E_MapEMSMemory:Far, E_MapAvailableEMSMemory:Far + Global E_GetEMSPageFrame:Far + Global E_EMSAvailable:Far + Global E_SaveEMSPageFrame:Far + Global E_RestoreEMSPageFrame:Far + Global E_AllocateBlockEMS:Far, E_ReleaseBlockEMS:Far + Global E_MapAlignedBlockEMS:Far + Global E_GetEMSVersion:Far + Global E_GetInternalEMSHandle:Far + +IF EMSDEBUG + + Global E_DumpEMSMemory:Far + +ENDIF + +; + +Segment EMS WORD Public 'Code' USE16 + Assume CS:EMS, DS:Nothing + +;Ŀ +; Variables +; + +CREATENEWLOGFILE EQU 0 +include debug.inc + +EMSDetectString DB "EMMXXXX0" ; Identification string +EMSHandlesRemaining DW 0 +EMSAvailable DW 0 ; Assume that it's not avail. +EMSPageFrame DW 0 +EMSHandle DW 0 +EMSVersion DB 0 + DB 0 + +IF EMSDEBUG + +EMSDumpName DB "EMSDump", 0 + +ENDIF + +EMSCorrespondenceList Label Word + Page0 DB 0, 0 + DW 0 + Page1 DB 0, 0 + DW 1 + Page2 DB 0, 0 + DW 2 + Page3 DB 0, 0 + DW 3 + +;Ŀ +; Functions +; + +Proc E_InitEMS Far + + Push DS + Push ES + + Trace " - Determining EMS presence" + + Xor AX, AX + Mov DS, AX + + Mov AX, [DS:019Eh] ; Get interrupt vector for Int 67h + And AX, AX ; Is Segment = 0? + JZ E_InitEMS1 + + Mov ES, AX + Mov DI, 0Ah ; Offset into driver of identification string + + Push CS + Pop DS + Assume DS:EMS + + Mov SI, Offset EMSDetectString + + Mov CX, 8/2 + + RepE CmpsW + JNE E_InitEMS1 + ; EMM driver is present + + Mov AH, 40h ; Get manager status + Int 67h ; Returns AH=0 -> no error + And AH, AH + JNZ E_InitEMS1 + + Trace " - Determining EMS Page Frame" + + Mov AH, 41h ; Get page frame segment + Int 67h ; AH if successful, with BX=segment + And AH, AH + JNZ E_InitEMS1 + + Mov EMSPageFrame, BX + + Trace " - Determining EMS Version" + + Mov AH, 46h ; Get EMS version + Int 67h + Test AH, AH + JNZ E_InitEMS1 + + Mov EMSVersion, AL + + Trace " - Allocating EMS block" + + Mov AH, 43h + Mov BX, 8 + Int 67h + + Test AH, AH + JNZ E_InitEMS1 + + Mov EMSHandle, DX + + Mov AX, 4400h + Xor BX, BX + Int 67h ; Map first page + + Mov ES, EMSPageFrame + Xor DI, DI + Mov EAX, 8*16*1024-16 + StosD ; Amount of memory free + Xor EAX, EAX ; No previous block, no next block + StosD + Xor AX, AX ; Unused block + StosW + + Mov EMSAvailable, 1 + + ; OK.. now to get number of EMS + ; handles available.. + + Trace " - Determining number of free EMS handles" + + Cmp EMSVersion, 40h + JB E_InitEMSBelow4 + + Mov AX, 5402h + Int 67h ; BX = total number of pages. + Test AH, AH + JNZ E_InitEMSBelow4 + + Mov DX, BX + + Mov AH, 4Bh + Int 67h + + Test AH, AH + JNZ E_InitEMSBelow4 + + Sub DX, BX + Mov EMSHandlesRemaining, DX + + Jmp E_InitEMS1 + +E_InitEMSBelow4: + + Mov CX, 256 ; Allocate 256 MAX + +E_InitEMS2: + Mov AH, 43h + Mov BX, 1 + Int 67h + + Test AH, AH + JNZ E_InitEMS3 + + Inc EMSHandlesRemaining + Push DX + Loop E_InitEMS2 + +E_InitEMS3: + Mov CX, EMSHandlesRemaining ; Now to dealloc them + + Test CX, CX +E_InitEMS4: + JZ E_InitEMS1 + + Mov AH, 45h + Pop DX + Int 67h + + Dec CX + Jmp E_InitEMS4 + +E_InitEMS1: + Pop ES + Pop DS + Ret + +EndP E_InitEMS + Assume DS:Nothing + +; + +Proc E_GetFreeEMS Far ; Returns kb free.. + + Push BX + Push DX + + Cmp EMSAvailable, 0 + JE E_GetFreeEMS2 ; No EMM driver? + + Mov AH, 42h ; Get page counts + Int 67h + + And AH, AH ; AH=0 -> no error + JNZ E_GetFreeEMS2 ; BX = free pages + + Mov AX, BX + ShL AX, 4 + + Jmp E_GetFreeEMS1 + +E_GetFreeEMS2: + Xor AX, AX + +E_GetFreeEMS1: + Pop DX + Pop BX + Ret + +EndP E_GetFreeEMS + +; + +Proc E_ReleaseEMS Far ; AX = handle. + + Push AX + Push DX + + Mov DX, AX + Mov AH, 45h ; Deallocate memory. + Int 67h + + And AH, AH ; AH = 0 -> no error + JZ E_ReleaseEMS1 + + Call EMSWarning + +E_ReleaseEMS1: + Inc CS:EMSHandlesRemaining + + Pop DX + Pop AX + + Ret + +EndP E_ReleaseEMS + +; + +Proc EMSWarning + + PushAD + Push DS + Push ES + + Mov BX, Object1 + Mov DS, BX + Assume DS:Object1 + + Mov Byte Ptr EMSErrorValue, AH + Mov EMSErrorValue2, CX + Mov EMSErrorValue3, DX + + Mov AX, Word Ptr CS:EMSVersion + Mov EMSErrorValue8, AX + + Mov AL, CS:Page0 + Mov Byte Ptr EMSErrorValue4, AL + + Mov AL, CS:Page1 + Mov Byte Ptr EMSErrorValue5, AL + + Mov AL, CS:Page2 + Mov Byte Ptr EMSErrorValue6, AL + + Mov AL, CS:Page3 + Mov Byte Ptr EMSErrorValue7, AL + + Mov DI, Offset O1_EMSWarningMessage + Mov CX, 2 + Call M_Object1List + + Pop ES + Pop DS + PopAD + + Ret + +EndP EMSWarning + Assume DS:Nothing + +; + +Proc E_MapAvailableEMSMemory Far + ; AX = handle. + + Push AX BX DX + + Mov DX, AX + + Xor AL, AL + Xor BX, BX + +E_MapAvailableEMSMemory1: + Mov AH, 44h + Int 67h + Test AH, AH + JNZ E_MapAvailableEMSMemory2 + + Inc AX + Inc BX + + Cmp AL, 3 + JBE E_MapAvailableEMSMemory1 + +E_MapAvailableEMSMemory2: + Pop DX BX AX + + Ret + +EndP E_MapAvailableEMSMemory + +; + +Proc E_MapEMSMemory Far ; CL = total pages in handle + ; CH = starting (base) page. + ; DX = handle + + Push AX + Push BX + Push CX + + Sub CL, CH + JBE E_MapEMSMemory002 + + Cmp CL, 4 + JB E_MapEMSMemory003 + + Mov CL, 4 + +E_MapEMSMemory003: + +IF EMSUSE41 + Cmp CS:EMSVersion, 40h + JAE E_MapEMSMemoryV4_1 +ENDIF + + Xor BX, BX + +E_MapEMSMemory001: + Mov AL, CL + Dec AX + Mov BL, AL + Add BL, CH + Mov AH, 44h + Int 67h + + And AH, AH + JNZ E_MapEMSMemory004 + + Dec CL + JNZ E_MapEMSMemory001 + Jmp E_MapEMSMemory002 + +IF EMSUSE41 + +E_MapEMSMemoryV4_1: + Push DS + Push SI + PushF + + CLI + + Push CS + Pop DS + Assume DS:EMS + + Mov Page0, CH + Inc CH + Mov Page1, CH + Inc CH + Mov Page2, CH + Inc CH + Mov Page3, CH + + Mov AX, 5000h + Xor CH, CH + Mov SI, Offset EMSCorrespondenceList + Int 67h + + PopF + Pop SI + Pop DS + Assume DS:Nothing + + Test AH, AH + JZ E_MapEMSMemory002 + +ENDIF + +E_MapEMSMemory004: +; Call EMSWarning + +E_MapEMSMemory002: + Pop CX + Pop BX + Pop AX + +E_MapEMSMemoryExit: + Ret + +EndP E_MapEMSMemory + +; + +Proc E_UnInitEMS Far + + Cmp EMSAvailable, 0 + JE E_UnInitEMS1 + + Mov AX, EMSHandle + Call E_ReleaseEMS + +E_UnInitEMS1: + Ret + +EndP E_UnInitEMS + +; + +Proc E_GetEMSPageFrame Far + + Mov AX, CS:EMSPageFrame + Ret + +EndP E_GetEMSPageFrame + +; + +Proc E_MapAlignedBlockEMS Far ; Given AX, Return DS:SI + + Push CX DX + + Mov SI, AX + Mov CX, AX + ShL SI, 4 + Mov CL, 8 + ShR CH, 2 + And SI, 03FFFh + + Mov DX, CS:EMSHandle + Call E_MapEMSMemory + + Mov DS, CS:EMSPageFrame + + Pop DX CX + + Ret + +EndP E_MapAlignedBlockEMS + +; + +Proc E_AllocateBlockEMS Far ; EAX = number of bytes + ; Destroys EMS page frame + ; Returns AX = segment address + ; Carry set if fail, clear if + ; successful + + ClI + Push EBX ECX EDX ESI EDI DS ES + + Cmp CS:EMSAvailable, 0 + JE AllocateBlockQuitError + + Mov ESI, EAX + Add ESI, 0Fh + And ESI, Not 0Fh + + Mov DS, CS:EMSPageFrame + Xor EDI, EDI ; EDI = current offset + + Mov CX, 0008h ; Starting page = 0, Max page = 8 + +AllocateBlockEMS2: + Mov DX, CS:EMSHandle + Call E_MapEMSMemory + +AllocateBlockEMS1: + Cmp Byte Ptr [DI+8], 0 ; Used? + JNE AllocateBlockEMSNext + + Cmp ESI, [DI] + JA AllocateBlockEMSNext + + Mov AX, DI + And AX, 3FFFh + Add AX, SI + JC AllocateBlockQuitError ; Can't fit it in! + +; OK. this block will do + Mov Byte Ptr [DI+8], 1 ; This block used + + Mov EBX, [DI] ; Size of block + Mov [DI], ESI ; New size of this block + + Mov EAX, [DI+4] ; To get next in HEAX + Mov ECX, EDI ; ECX = Current offset + ShR ECX, 4 ; ECX = Segment reference + Mov AX, CX ; AX = segment, HEAX = next seg + + Sub EBX, ESI ; Bytes in next block + JZ AllocateBlockPerfectEnd + Sub EBX, 16 + + LEA ESI, [ESI+EDI+16] ; ESI = position of split block + Push ESI + ShR ESI, 4 ; SI = segment of split block + Mov [DI+6], SI ; Store pointer to next block + Pop EDI ; EDI = position of split block + + Mov ECX, EDI ; ECX = position of split block + ShR ECX, 6 + And CH, Not 3 + Mov CL, 8 + Call E_MapEMSMemory + + Mov [DI], EBX ; bytes in block + Mov [DI+4], EAX ; Last block & Next block + Mov Byte Ptr [DI+8], 0 ; Unused block + + Push AX + Mov AX, [DI+6] + + Test AX, AX + JZ NoNextBlockSplit + + Call E_MapAlignedBlockEMS ; DS:SI Pointing to next + ShR EDI, 4 + Mov [SI+4], DI + +NoNextBlockSplit: + Pop AX + + ClC + Jmp AllocateBlockQuit + +AllocateBlockPerfectEnd: +; Mov Word Ptr [DI+6], 0 ; Last block. + ClC + Jmp AllocateBlockQuit + +AllocateBlockEMSNext: + Mov CX, [DI+6] ; Next segment + And ECX, 0FFFFh + JZ AllocateBlockQuitError + +; Check EDI and ECX for the same frame.. if the same, then skip updating (E)DI +; and only update DI + + ShLD EAX, EDI, 16 ; AL = 64k frame + Mov EDI, ECX + ShR CH, 4 + ShL EDI, 4 + + Cmp AL, CH + JE AllocateBlockEMS1 + + ShL CH, 2 + Mov CL, 8 + Jmp AllocateBlockEMS2 + +AllocateBlockQuitError: + StC + +AllocateBlockQuit: + Pop ES DS EDI ESI EDX ECX EBX + StI + Ret + +EndP E_AllocateBlockEMS + +; + +Proc E_ReleaseBlockEMS Far ; Given AX = 'segment'. + + ClI + Push EAX EBX DS SI + + Mov BX, AX ; BX = current segment + Call E_MapAlignedBlockEMS + ; DS:SI points to structure. + + Mov Byte Ptr [DS:SI+8], 0 ; This block unused. + +; Release later block first, if possible + + Mov AX, [DS:SI+6] + Test AX, AX + JZ E_ReleaseBlockEMSNoneAfter ; Nope, this is the + ; last block. + Call E_MapAlignedBlockEMS ; OK, DS:0 points to next block + Mov EAX, [DS:SI+4] ; HEAX = next block, AX = last block + Mov EBX, [DS:SI] ; Free memory + Cmp Byte Ptr [DS:SI+8], 0 ; Used? + JNE E_ReleaseBlockAfterEnd + + Call E_MapAlignedBlockEMS + Add EBX, 16 + Add [DS:SI], EBX + + Push AX + Mov AX, [DS:SI+4] + Mov [DS:SI+4], EAX + Pop AX + + Jmp E_ReleaseBlockEMSBefore + +E_ReleaseBlockAfterEnd: + Call E_MapAlignedBlockEMS + Jmp E_ReleaseBlockEMSBefore + +E_ReleaseBlockEMSNoneAfter: + Mov AX, BX + +E_ReleaseBlockEMSBefore: + Test AX, AX + JZ E_ReleaseBlockFinished + + Mov EAX, [DS:SI+4] + Mov EBX, [DS:SI] + Call E_MapAlignedBlockEMS + + Cmp Byte Ptr [DS:SI+8], 0 + JNE E_ReleaseBlockPreviousFailed + + Push AX + + Mov AX, [DS:SI+4] ; Last field + Mov [DS:SI+4], EAX ; Next field written + Add EBX, 16 + Add [DS:SI], EBX + + Pop AX + Jmp E_ReleaseBlockFinished + +E_ReleaseBlockPreviousFailed: + Mov AX, [DS:SI+6] + +E_ReleaseBlockFinished: + Mov BX, AX + Call E_MapAlignedBlockEMS ; DS:SI points to 'base' block + Mov AX, [SI+6] ; Next + + Test AX, AX + JZ E_ReleaseBlockCleanup + + Call E_MapAlignedblockEMS + Mov [SI+4], BX + +E_ReleaseBlockCleanup: + + Pop SI DS EBX EAX + StI + Ret + +EndP E_ReleaseBlockEMS + +; + +Proc E_AllocateEMS Far ; EAX = number of bytes + ; Returns AX with handle + ; 0 if no handle allocated + ; given carry = essential + ; no carry = spare EMS + + Push EBX + Push ECX + Push EDX + + Mov DX, CS:EMSHandlesRemaining + JC E_AllocateEMS3 + + Cmp DX, 10 + JB E_AllocateEMS2 + +E_AllocateEMS3: + Test DX, DX + JZ E_AllocateEMS1 + + Cmp CS:EMSAvailable, 0 + JE E_AllocateEMS2 + + Mov EBX, EAX + Add EBX, 16*1024-1 + SHR EBX, 14 + + Mov AH, 43h + Int 67h + Test AH, AH + JNZ E_AllocateEMS2 + + Dec CS:EMSHandlesRemaining + Jmp E_AllocateEMS1 + +E_AllocateEMS2: + Xor DX, DX + +E_AllocateEMS1: + Mov AX, DX + + Pop EDX + Pop ECX + Pop EBX + Ret + +EndP E_AllocateEMS + +; + +Proc E_EMSAvailable Far ; Returns Zero flag set if no EMS + + Cmp CS:EMSAvailable, 0 + Ret + +EndP E_EMSAvailable + +; + +Comment ~ + +Proc E_SavePageFrame Far ; Given DX = Handle +Public E_SavePageFrame + + Push AX + Push DX + + Mov AH, 47h + Int 67h + Test AH, AH + JZ E_SavePageFrame1 + + Call EMSWarning + +E_SavePageFrame1: + Pop DX + Pop AX + + Ret + +EndP E_SavePageFrame + +; + +Proc E_RestorePageFrame Far ; Given DX = Handle +Public E_RestorePageFrame + + Push AX + Push DX + + Mov AH, 48h + Int 67h + Test AH, AH + JZ E_RestorePageFrame1 + + Call EMSWarning + +E_RestorePageFrame1: + Pop DX + Pop AX + + Ret + +EndP E_RestorePageFrame + +~ + +; + +Proc E_SaveEMSPageFrame Far + + Cmp CS:EMSAvailable, 0 + JE E_SaveEMSPageFrame1 + + Push AX + Push DX + + Mov DX, CS:EMSHandle + Mov AH, 47h + Int 67h + +; Cmp AH, 1 + +; Test AH, AH +; JZ E_SaveEMSPageFrame2 + +; Call EMSWarning + + And AH, AH + JZ E_SaveEMSPageFrame2 + + StC + +E_SaveEMSPageFrame2: + Pop DX + Pop AX + +E_SaveEMSPageFrame1: + Ret + +EndP E_SaveEMSPageFrame + +; + +Proc E_RestoreEMSPageFrame Far + + Cmp CS:EMSAvailable, 0 + JE E_RestoreEMSPageFrame1 + + Push AX + Push DX + + Mov DX, EMSHandle + Mov AH, 48h + Int 67h + + Pop DX + Pop AX + +E_RestoreEMSPageFrame1: + Ret + +EndP E_RestoreEMSPageFrame + +; + +Proc E_GetEMSVersion Far + + Mov AL, CS:EMSVersion + Ret + +EndP E_GetEMSVersion + +; + +Proc E_GetInternalEMSHandle Far + + Mov AX, CS:EMSHandle + Ret + +EndP E_GetInternalEMSHandle + +; + +IF EMSDEBUG + +Proc E_DumpEMSMemory Far + + Push CS + Pop DS + Assume DS:EMS + + Mov AH, 3Ch + Xor CX, CX + Mov DX, Offset EMSDumpName + Int 21h + + Mov BX, AX + + Mov CX, 8 + Mov DX, EMSHandle + Call E_MapEMSMemory + + Mov AH, 40h + Mov CX, 32768 + Mov DS, EMSPageFrame + Xor DX, DX + Int 21h + + Mov AH, 40h + Mov DX, 32768 + Mov CX, DX + Int 21h + + Mov CX, 408h + Mov DX, CS:EMSHandle + Call E_MapEMSMemory + + Mov AH, 40h + Mov CX, 32768 + Xor DX, DX + Int 21h + + Mov AH, 40h + Mov DX, 32768 + Mov CX, DX + Int 21h + + Mov AH, 3Eh + Int 21h + + Xor AX, AX + Ret + +EndP E_DumpEMSMemory + Assume DS:Nothing + +ENDIF + +; + +EndS + +; + +End diff --git a/it/IT_ERR.ASM b/it/IT_ERR.ASM new file mode 100644 index 0000000..cfa1c54 --- /dev/null +++ b/it/IT_ERR.ASM @@ -0,0 +1,168 @@ +;Ŀ +; Critical Error handler. +; + + Jumps + .386 + +include switch.inc + +;Ŀ +; Externals +; + +;Ŀ +; Globals +; + + Global Error_InitHandler:Far + Global Error_UnInitHandler:Far + +; + +Segment Error BYTE Public 'Code' USE16 + Assume CS:Error + +CREATENEWLOGFILE EQU 0 +include debug.inc + +;Ŀ +; Variables +; + +OldHandlerOffset DW ? +OldHandlerSegment DW ? + +ErrorMsgs Label Word + DW Offset Error0 + DW Offset Error1 + DW Offset Error2 + DW Offset Error3 + DW Offset Error4 + DW Offset Error5 + DW Offset Error6 + DW Offset Error7 + DW Offset Error8 + DW Offset Error9 + DW Offset ErrorA + DW Offset ErrorB + DW Offset UnknownError + DW Offset UnknownError + DW Offset UnknownError + DW Offset ErrorF + +Error0 DB "Write protect error", 0 +Error1 DB "Unknown unit error", 0 +Error2 DB "Drive not ready error", 0 +Error3 DB "Unknown command error", 0 +Error4 DB "Data integrity error", 0 +Error5 DB "Bad request structure length error", 0 +Error6 DB "Seek error", 0 +Error7 DB "Unknown media type error", 0 +Error8 DB "Sector not found error", 0 +Error9 DB "Printer error", 0 +ErrorA DB "Read fault error", 0 +ErrorB DB "General failure error", 0 +ErrorF DB "Invalid disk change error", 0 +UnknownError DB "Unknown critical error", 0 + +;Ŀ +; Functions +; + +Proc ErrorHandler Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Error + + Mov BX, DI + And BX, 0FFh + Cmp BX, 0Fh + JBE ErrorHandler1 + + Mov SI, Offset UnknownError + Jmp ErrorHandler2 + +ErrorHandler1: + Add BX, BX + Mov SI, [ErrorMsgs+BX] + +ErrorHandler2: + Mov AH, 20h + Mov DI, 0B800h + Mov ES, DI + Mov DI, (2+49*80)*2 + +ErrorHandler3: + LodsB + And AL, AL + JZ ErrorHandler4 + StosW + + Jmp ErrorHandler3 + +ErrorHandler4: + Pop ES + Pop DS + PopA + + Xor AX, AX + + IRet + +EndP ErrorHandler + Assume DS:Nothing + +; + +Proc Error_InitHandler Far + + Push ES + + Trace " - Installing error handler" + + Xor AX, AX + Mov ES, AX + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ErrorHandler + + XChg [ES:90h], EAX + Mov DWord Ptr CS:OldHandlerOffset, EAX + + Pop ES + Ret + +EndP Error_InitHandler + +; + +Proc Error_UnInitHandler Far + + Push ES + Xor AX, AX + Mov ES, AX + + Mov EAX, DWord Ptr CS:OldHandlerOffset + Mov [ES:90h], EAX + + Pop ES + Ret + +EndP Error_UnInitHandler + +; + +; + +EndS + +; + +End diff --git a/it/IT_F.ASM b/it/IT_F.ASM new file mode 100644 index 0000000..2ae1157 --- /dev/null +++ b/it/IT_F.ASM @@ -0,0 +1,5950 @@ +;Ŀ +; Functions +; + + Jumps + .386 + +include switch.inc +include network.inc + +;Ŀ +; Externals +; + +IF MEMORYDEBUG + +Segment StartUp BYTE Public 'Code' +EndS + +Segment InfoPage BYTE Public 'Code' +EndS + +Segment Glbl BYTE Public 'Code' +EndS + +Segment Help BYTE Public 'Code' +EndS + +Segment Error BYTE Public 'Code' +EndS + +Segment EMS BYTE Public 'Code' +EndS + +Segment KeyBoard BYTE Public 'Code' +EndS + +Segment InfoLine BYTE Public 'Code' +EndS + +Segment Main BYTE Public 'Code' +EndS + +ENDIF + +Segment Pattern BYTE Public 'Code' + Extrn PatternDataArea:Word +EndS + +Segment Inst BYTE Public 'Code' + Extrn MaxNode:Word +EndS + +Segment Music BYTE Public 'Code' + Extrn SongDataArea:Word + Extrn MIDIDataArea:Word +EndS + +Segment Disk BYTE Public 'Code' + Extrn DiskDataArea:Word +EndS + +Segment Screen BYTE Public 'Code' +EndS + +Segment Object1 BYTE Public 'Data' +EndS + +;------------------------------------------------------------------------------- + + Extrn LastInstrument:Byte + + Extrn D_GetLoadSampleVars:Far + Extrn D_ClearFileName:Far + Extrn D_SaveSong:Far + Extrn D_ResetTimer:Far + + Extrn E_UnInitEMS:Far + Extrn E_GetFreeEMS:Far + + Extrn Glbl_F2_2:Far + Extrn Glbl_F3:Far + Extrn Glbl_Ctrl_F3:Far + Extrn Glbl_Ctrl_F4:Far + Extrn Glbl_F4:Far + Extrn Glbl_F5:Far + Extrn Glbl_Ctrl_F5:Far + Extrn Glbl_F6:Far + Extrn PE_F7:Far + Extrn Glbl_Shift_F6:Far + Extrn Glbl_Shift_F9:Far + Extrn Glbl_F9:Far + Extrn Glbl_F10:Far + Extrn Glbl_F11_2:Far + Extrn Glbl_F12:Far + + Extrn Glbl_GetHeaderMode:Far + + Extrn H_Help:Far + + Extrn I_GetInstrumentOffset:Far + Extrn I_GetSampleOffset:Far + + Extrn I_DrawWaveForm:Far + Extrn I_MapEnvelope:Far + Extrn D_DrawWaveForm:Far + + Extrn S_InitScreen:Far + Extrn S_Set80x25Mode:Far + Extrn S_SetPalette2:Far + Extrn S_RedefineCharacters:Far + Extrn S_UnInitScreen:Far + Extrn S_DrawBox:Far + Extrn S_UpdateScreen:Far + Extrn S_OverrideVGADetection:Far + Extrn S_SetDirectMode:Far + Extrn S_DrawString:Far + Extrn S_HiLight:Far + Extrn S_GetDestination:Far + Extrn S_SaveScreen:Far + Extrn S_RestoreScreen:Far + + + Extrn Music_GetSongSegment:Far + Extrn Music_InitMixTable:Far + Extrn Music_InitMuteTable:Far + Extrn Music_ClearAllInstruments:Far + Extrn Music_SetGlobalVolume:Far + Extrn Music_InitStereo:Far + Extrn Music_Stop:Far + + Extrn Music_RegetLoopInformation:Far + + Extrn Music_ReleaseAllSamples:Far ; For New Song Function + Extrn Music_ReleaseAllPatterns:Far + Extrn Music_ClearAllInstruments:Far + Extrn Music_ClearAllSampleNames:Far + Extrn Music_GetFreeSoundCardMemory:Far + Extrn Music_SoundCardLoadAllSamples:Far + Extrn Music_ReinitSoundCard:Far + Extrn Music_TimeSong:Far + + Extrn Glbl_DriverScreen:Far + Extrn Music_GetDriverVariable:Far + Extrn Music_SetDriverVariable:Far + + Extrn M_Object1List:Far + + Extrn Msg_ResetMessage:Far + + Extrn O1_EmptyList:Far + Extrn O1_ThumbStringList:Far + Extrn O1_InitialiseInstrumentList:Far + Extrn O1_NewSongList:Far + + Extrn O1_MainMenu:Far + Extrn O1_FileMenu:Far + Extrn O1_PlaybackMenu:Far + Extrn O1_SampleMenu:Far + Extrn O1_InstrumentMenu:Far + + Extrn PE_ConvAX2Num:Far + Extrn PE_ResetOrderPattern:Far + + Extrn DOSShell:Far + Extrn Quit:Far + + Extrn MouseAddEvent:Far, AddMouseQueue:Far, MouseClearEvents:Far + Extrn SetKeyboardLock:Far, NewCharacterSet:Far + Extrn MouseRemoveEvents:Far, MouseRestoreEvents:Far + Extrn MultiChannelInfo:Byte + +;Ŀ +; Globals +; + + Global F_MainMenu:Far + Global F_FileMenu:Far + Global F_PlaybackMenu:Far + Global F_SampleMenu:Far + Global F_InstrumentMenu:Far + + Global F_DrawHeader:Far + + Global F_InstrumentButtonHandler:Far + + Global F_NewSong:Far + Global F_DrawStringInput:Far + Global F_PreStringInput:Far + Global F_PostStringInput:Far + Global F_RedrawScreen:Far + Global F_Nothing:Far + Global F_DrawBoxObject:Far + Global F_DrawTextObject:Far + Global F_PostExitObject:Far + Global F_SetDirectMode:Far + Global F_CharacterDefinitions:Far + Global F_CallFarFunction:Far + Global F_CallFarPreFunction:Far + Global F_CallFarPostFunction:Far + + Global F_DrawToggle:Far + Global F_PreToggle:Far + Global F_PostToggle:Far + + Global F_Draw5Num:Far + Global F_Pre5Num:Far + Global F_Post5Num:Far + + Global F_Draw3Num:Far + Global F_Pre3Num:Far + Global F_Post3Num:Far + + Global F_DrawButtonObject:Far + Global F_PreButtonObject:Far + Global F_PostButtonObject:Far + + Global F_Return0:Far + Global F_Return1:Far + Global F_Return64:Far + Global F_Return192:Far + + Global F_DrawThumbBar:Far + Global F_DrawScalableThumbBar:Far + Global F_PreThumbBar:Far + Global F_PreScalableThumbBar:Far + Global F_PostThumbBar:Far + Global F_PostScalableThumbBar:Far + + Global F_DrawInfoLine:Far + + Global F_ShowChannels:Far + Global F_GotoEmptyList:Far + Global F_DrawSMCChannels:Far + + Global F_SetControlInstrument:Far + Global F_SetControlSample:Far + Global F_ConfigButtonSetup:Far + + Global F_SetStereo:Far + Global F_SetMono:Far + Global F_SetAmiga:Far + Global F_SetLinear:Far + + Global F_Reset5NumInputPos:Far + + Global AddressInput:Byte + Global ThumbStringEnter:Byte + + Global F_MessageEditor:Far + Global F_Help:Far ; Main menu + Global F_ViewPattern:Far + Global F_ViewVariables:Far + Global F_ViewOrderPan:Far + + Global F_FileLoad:Far + Global F_FileNew:Far + Global F_FileSaveCurrent:Far + Global F_FileSaveAs:Far + Global F_FileDOSShell:Far + Global F_FileQuit:Far + + Global F_InfoPage:Far ; Playback menu + Global F_PlaySong:Far + Global F_PlayPattern:Far + Global F_PlayOrder:Far + Global F_Stop:Far + Global F_PlayMark:Far + Global F_DriverScreen:Far + Global F_ReinitSoundCard:Far + Global F_CalculateLength:Far + + Global F_SampleList:Far + Global F_SampleLibrary:Far + Global F_ReloadGravis:Far + + Global F_InstrumentList:Far + Global F_InstrumentLibrary:Far + +IF MEMORYDEBUG + + Global F_DrawDebug:Far + Global F_DebugUp:Far + Global F_DebugDown:Far + Global F_DebugPgUp:Far + Global F_DebugPgDn:Far + Global F_DebugStringInput:Far + Public F_PostDebug + +ENDIF + + Public F_ShowMIDIZxxInput + Public F_MIDI_Up + Public F_MIDI_Down + Public F_MIDI_PgUp, F_MIDI_PgDn + +; + +Segment Functions BYTE Public 'Code' USE16 + Assume CS:Functions, DS:Nothing + +;Ŀ +; Variables +; + +ButtonVariables Label Word + DW 220h ; Standard SB Configs + DW 7 + DW 1 + DW 1 ; Clear patterns + DW 1 ; Clear samples + DW 1 ; Clear instruments + DW 1 ; Clear order list + +ButtonTypes Label Word + DW Offset ButtonType0 ; Press/Release buttons + DW Offset ButtonType1 ; Toggle Press/Release + DW Offset ButtonType2 ; One of Selection + +ButtonEffects Label Word + DW Offset ButtonEffect0 ; Return value + DW Offset ButtonEffect1 ; New object list + DW Offset ButtonEffect2 ; Call function + DW Offset ButtonEffect3 ; Set var at offset + DW Offset ButtonEffect4 ; Jump to function + DW Offset ButtonEffect5 ; Set var + DW Offset ButtonEffect6 ; Jump to function + +ButtonWidth Label Word + DW 0, 0, 0, 0, 0, 0, 0, 0 + DW 7, 7, 7, 7, 7, 7, 7, 7 + DW 0, 0, 0, 0, 0, 0, 0, 0 + DW 7, 7, 7, 7, 0, 0, 0, 0 + +MouseEventData DW 7 Dup (0), Functions + +; + +GetThumbValues Label Word + DW Offset GetPanning + DW Offset GetPEVariables + DW Offset GetSampleVariables + DW Offset GetMusicVariables + DW Offset GetPanning ; ChannelVol + DW Offset GetLoadSampleVariables + DW Offset GetInstVariables + DW Offset GetScreenVariables + DW Offset GetInstrumentVariables + DW Offset GetDriverVariables + +DrawThumbValues Label Word + DW Offset DrawPanning + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset DrawMIDIChannel + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset F_NothingNear + +PreThumbFuncs Label Word + DW Offset HiLightPanning + DW Offset GetPEVariables + DW Offset GetSampleVariables + DW Offset GetMusicVariables + DW Offset GetPanning ; Channelvol + DW Offset GetLoadSampleVariables + DW Offset GetInstVariables + DW Offset GetScreenVariables + DW Offset GetInstrumentVariables + DW Offset GetDriverVariables + +PostThumbFuncs Label Word + DW Offset SetPanning + DW Offset SetPEVariables + DW Offset SetSampleVariables + DW Offset SetMusicVariables + DW Offset SetPanning + DW Offset SetLoadSampleVariables + DW Offset SetInstVariables ; Inst + DW Offset SetScreenVariables + DW Offset SetInstrumentVariables ; Inst segment + DW Offset SetDriverVariables + +PostThumbCheck Label Word + DW Offset PanningKeys + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset FilterKeys + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset F_NothingNear + +ThumbStringEnter DB 0 + DB 4 Dup (0) + +; + +; LastStringData DD 0 + +StringInputOffset Label Word + DW Offset GetSIODiskSegment + DW Offset GetSampleString + DW Offset GetSIOInstSegment + DW Offset GetLoadSampleString + DW Offset GetMusicSegmentString ; Songsegment + DW Offset GetPatternSegmentString + DW Offset GetInstrumentString + DW Offset GetMIDIString + +PostStringInput Label Word + DW Offset F_NothingNear + DW Offset SetSampleString + DW Offset F_NothingNear + DW Offset F_NothingNear + DW Offset SetMusicSegmentString ; Songsegment + DW Offset F_NothingNear + DW Offset SetInstrumentString + DW Offset F_NothingNear + +; + +GetToggleStatus Label Word + DW Offset GetSampleToggle + DW Offset GetPatternSegmentToggle + DW Offset GetMusicSegmentToggle + DW Offset GetLoadSampleToggle + DW Offset GetInstrumentToggle + +ToggleBit Label Word + DW Offset SampleToggle + DW Offset PatternSegmentToggle + DW Offset MusicSegmentToggle + DW Offset LoadSampleToggle + DW Offset InstrumentToggle + +; + +TripleNumberPos DW 0 + +Get3NumValues Label Word + DW Offset GetInstrument3Num + +Set3NumValues Label Word + DW Offset SetInstrument3Num + +; + +NumberPos DW 0 + +Get5NumValues Label Word + DW Offset GetSample5Num + DW Offset GetLoadSample5Num + Dw Offset GetInst5Num + +Set5NumValues Label Word + DW Offset SetSample5Num + DW Offset SetLoadSample5Num + DW Offset SetInst5Num + +; + +HeaderMsg1 Label Byte +IF SHOWVERSION + DB 0FFh, 9, ' ', "Impulse Tracker v2.14 Copyright (C) 1995-2000 Jeffrey Lim", 13 +ELSE + DB 0FFh, 12, ' ', "Impulse Tracker Copyright (C) 1995-2000 Jeffrey Lim", 13 +ENDIF + DB 0FFh, 9, ' ', 0FEh, 21h, 139, 0FFh, 25, 134, 138, 0FFh, 11, ' ', 139, 0FFh, 28, 134, 138, 13 + DB 0FEh, 20h, "Song Name", 0FEh, 21h, 132, 0FEh, 5, 0FFh, 25, ' ', 0FEh, 23h, 131, 0FEh, 20h, 0 + +HeaderMsg2 DB " Instrument" + DB 0FEh, 21h, 132, 0FEh, 7, " :", 0FFh, 25, ' ', 0FEh, 23h, 131, 0 + +HeaderMsg3 DB 0FFh, 5, " Sample" + DB 0FEh, 21h, 132, 0FEh, 7, " :", 0FFh, 25, ' ', 0FEh, 23h, 131, 0 + +HeaderMsg4 DB "File Name", 0FEh, 21h, 132, 0FEh, 5, 0FFh, 18, ' ', 0FEh, 23h, 128, 0FFh, 6, 129, 136, 0FEh, 20h, "Speed/Tempo", 0FEh, 21h, 132, 0FEh, 5, " ", 0FEh, 1, "/", 0FEh, 5, " ", 0FEh, 23h, 128, 0FFh, 20, 129, 136, 13 + DB 0FEh, 20h, 0FFh, 4, " Order", 0FEh, 21h, 132, 0FEh, 5, " ", 0FEh, 1, "/", 0FEh, 5, " ", 0FEh, 23h, 128, 0FFh, 10, 129, 136, 0FEh, 20h, 0FFh, 12, " Octave", 0FEh, 21h, 132, 0FEh, 5, " ", 0FEh, 23h, 128, 0FFh, 5, 129, 136, 13 + DB 0FEh, 20h, " Pattern", 0FEh, 21h, 132, 0FEh, 5, " ", 0FEh, 1, "/", 0FEh, 5, " ", 0FEh, 23h, 131, 0FEh, 20h, " F1...Help F9.....Load ", 0FEh, 23h, 137, 129, 136, 0FEh, 20h, 0FFh, 11, " FreeMem ", 0FDh, "Dk ", 13 + DB 0FEh, 20h, 0FFh, 6, " Row", 0FEh, 21h, 132, 0FEh, 5, " ", 0FEh, 1, "/", 0FEh, 5, " ", 0FEh, 23h, 131, 0FEh, 20h, " ESC..Main Menu F5/F8..Play / Stop", 0FFh, 8, " FreeEMS ", 0FDh, "Dk", 13 + DB 0FEh, 23h, 0FFh, 9, ' ', 137, 0FFh, 7, 129, 136 + DB 0 + +ChannelMsg DB "Channel " +ChannelNumbers DB "xx", 0 + +HexNumbers DB "0123456789ABCDEF" +SurroundMessage DB "Surround", 0 +MutedMessage DB " Muted", 0 +ForwardMsg DB "Forwards", 0 +PingPongMsg DB "Ping Pong", 0 +ZxxString DB "Z", 0FDh, "X", 0 +NumberStorage DW 0, 0, 0, 0, 0, 0, 0, 0, 0 +PitchMessage DB "Pitch", 0 +FilterMessage DB "Filter", 0 + +;Ŀ +; Functions +; + +Proc F_Nothing Far + + Xor AX, AX + Ret + +EndP F_Nothing + +; + +Proc F_InstrumentButtonHandler Far + + Test AX, AX + JZ F_InstrumentButtonHandler1 + + NetworkSendInstrument + +F_InstrumentButtonHandler1: + Push DS + Call I_GetInstrumentOffset ; Returns DS:BX + Push DS + Pop ES + Mov DI, BX + Pop DS + + Add DI, [SI+24] + Ret + +EndP F_InstrumentButtonHandler + +; + +Proc F_NothingNear + + Xor AX, AX + Ret + +EndP F_NothingNear + +; + +Proc F_CallFarPreFunction Far + + Call DWord Ptr [SI+6] + + Ret + +EndP F_CallFarPreFunction + +; + +Proc F_CallFarPostFunction Far + + Mov SI, [BX] + + Call DWord Ptr [SI+10] + + Ret + +EndP F_CallFarPostFunction + +; + +Proc F_CallFarFunction Far + + Call DWord Ptr [SI+2] + + Ret + +EndP F_CallFarFunction + +; + +Proc F_DrawBoxObject Far + + LodsW + Xor AH, AH + LodsB + Push AX + LodsB + Push AX + LodsB + Push AX + LodsB + Push AX + LodsB + Push AX + Call S_DrawBox + Add SP, 10 + + Ret + +EndP F_DrawBoxObject + +; + +Proc F_DrawTextObject Far + + LodsW + + Mov BX, 3 + Xor CX, CX ; CX = string length count + Xor DX, DX + +F_DrawTextObject1: + Mov AL, [SI+BX] + Inc BX + Cmp AL, 0 + JE F_DrawTextObject2 + + Cmp AL, 0FDh + JNE F_DrawTextObject1 + Inc CX + Cmp Byte Ptr [SI+BX], 'L' + JNE F_DrawTextObject1 + Inc CX + Jmp F_DrawTextObject1 + +F_DrawTextObject2: + JCXZ F_DrawTextObject3 + Push Word Ptr [SI+BX] + Add BX, 2 + Inc DX + Dec CX + Jmp F_DrawTextObject2 + +F_DrawTextObject3: + Mov AL, 80 + Mul Byte Ptr [SI+1] + Add AL, [SI] + AdC AH, 0 + Add AX, AX + Mov DI, AX + Mov AH, [SI+2] + Add SI, 3 + Call S_DrawString + + Add DX, DX + Add SP, DX + + Ret + +EndP F_DrawTextObject + +; + +Proc F_PostExitObject Far + + Xor AX, AX + Test CH, 1 + JNZ F_PostExitObject1 + + Mov SI, [BX] + Mov DX, [SI+2] + Mov AX, 4 ; Exit from MainProc + +F_PostExitObject1: + Ret + +EndP F_PostExitObject + +; + +Proc F_SetDirectMode Far + + LodsW + LodsB + Call S_SetDirectMode + + Ret + +EndP F_SetDirectMode + +; + +Proc F_CharacterDefinitions Far + + LodsW + LodsW + Mov BX, [SI] + Add SI, 2 + Call S_RedefineCharacters + + Ret + +EndP F_CharacterDefinitions + +; + +Proc MouseButtonPress Far ; Given CX, DX = coords + ; Given AX = Object number + ; DS:SI points to mouse obj + Mov CX, 11Ch + Xor DX, DX + Call AddMouseQueue + + Mov Word Ptr [SI+8], 1108h + Mov Word Ptr [SI+12], Offset MouseButtonRelease + + Mov AL, 2 + Call SetKeyboardLock + + Xor AX, AX + Ret + +EndP MouseButtonPress + +; + +Proc MouseButtonRelease Far + + Mov CX, 01Ch + Xor DX, DX + Call AddMouseQueue + + Mov Word Ptr [SI+8], 102h + Mov Word Ptr [SI+12], Offset MouseButtonPress + + Xor AX, AX + Call SetKeyboardLock + + Ret + +EndP MouseButtonRelease + +; + +Proc F_DrawButtonObject Far ; AX = object number + ; SI = object + + Mov [CS:MouseEventData+10], AX ; Store object number + + Cmp Word Ptr [SI+16], 5 + JB F_DrawButtonObject1 + + Xor AX, AX + Call DWord Ptr [SI+18] + Mov AX, [SI+22] + ScasB +; Cmp [ES:DI], AL + + SetE [SI+33] + +F_DrawButtonObject1: + Mov BX, [SI+32] + And BX, 0FFh + Add SI, 28 + Add BX, BX + Mov DX, [CS:ButtonWidth+BX] + + Xor AH, AH + LodsB + LEA CX, [EAX*8+EDX] + Mov [CS:MouseEventData+0], CX + Push AX + + LodsB + LEA CX, [EAX*8+EDX] + Mov [CS:MouseEventData+2], CX + Push AX + + Sub DX, 7 + + LodsB + Mov CX, AX + ShL CX, 3 + Sub CX, DX + Mov [CS:MouseEventData+4], CX + Push AX + + LodsB + Mov CX, AX + ShL CX, 3 + Sub CX, DX + Mov [CS:MouseEventData+6], CX + Push AX + + LodsB ; Base Style + Mov BL, [SI] ; Up/Down + And BL, 1 + Mov [SI], BL + Add AL, BL + Push AX + Call S_DrawBox + Add SP, 10 + + Inc SI + + Mov AL, 80 + Mul Byte Ptr [SI-5] + Add AL, [SI-6] + AdC AH, 0 + Add AX, AX + Add AX, 162 + Mov DI, AX + Mov AH, 20h + + Call S_DrawString + + Push CS + Pop DS + Mov SI, Offset MouseEventData + Mov [MouseEventData+8], 102h ; Left mouse button pressed + Mov [MouseEventData+12], Offset MouseButtonPress + Call MouseAddEvent + + Ret + +EndP F_DrawButtonObject + +; + +Proc F_PreButtonObject Far + + Add SI, 28 + Xor AH, AH + LodsB + Push AX + LodsB + Push AX + LodsB + Push AX + LodsB + Push AX + LodsB ; Base Style + Mov BL, [SI] ; Up/Down + And BL, 1 + Add AL, BL + Push AX + Call S_DrawBox + Add SP, 10 + + Inc SI + + Mov AL, 80 + Mul Byte Ptr [SI-5] + Add AL, [SI-6] + AdC AH, 0 + Add AX, AX + Add AX, 162 + Mov DI, AX + Mov AH, 23h + + Call S_DrawString + + Ret + +EndP F_PreButtonObject + +; + +Proc F_PostButtonObject Far + + Mov SI, [BX] + Push SI + Push DI + Push BX + Push CX + Push DX + + Add SI, 28 + Mov AL, 80 + Mul Byte Ptr [SI+1] + Add AL, [SI] + AdC AH, 0 + Add AX, AX + Add AX, 162 + Mov DI, AX + Mov AL, 20h + Mov CL, [SI+2] + Sub CL, [SI] + Dec CL + Xor CH, CH + Call S_HiLight + + Pop DX + Pop CX + Pop BX + Pop DI + Pop SI + + Test CH, 80h + JNZ F_PostButtonNoMIDI + + Mov AL, [SI+33] + Cmp CL, 1Ch + JE F_PostButtonObject6 ; Enter + + Test AL, 2 + JNZ F_PostButtonObject7 + + Cmp CX, 1C8h ; Up pressed + JE F_PostButtonObject1 + + Cmp CX, 1D0h + JE F_PostButtonObject2 ; Down + + Cmp CX, 1CBh + JE F_PostButtonObject3 ; Left + + Cmp CX, 1CDh + JE F_PostButtonObject4 ; Right + + Cmp CX, 10Fh ; Tab + JE F_PostButtonObject4 + +; Test CL, CL +; JZ F_PostButtonNOMIDI + + Cmp DX, 0F00h ; Shift tab + JE F_PostButtonObject3 + +F_PostButtonNOMIDI: + Xor AX, AX + Ret + +F_PostButtonObject7: + Test AL, 4 + JZ F_PostButtonObject8 + Test CH, 1 + JZ F_PostButtonObject8 + + And AX, 1 + Xor AL, 1 + Mov [SI+33], AL + +F_PostButtonObject8: + Mov AX, 2 + Ret + +F_PostButtonObject4: + LodsW + +F_PostButtonObject3: + LodsW + +F_PostButtonObject2: + LodsW + +F_PostButtonObject1: + LodsW + + LodsW + Cmp AX, 0FFFFh + JNE F_PostButtonObject5 + + Xor AX, AX + Ret + +F_PostButtonObject5: + Mov [DI], AX + Mov AX, 2 + Ret + +F_PostButtonObject6: ; Enter pressed + Push BX + + Mov BX, [SI+10] + Add BX, BX + Jmp [CS:ButtonTypes+BX] + +EndP F_PostButtonObject + +; + +Proc ButtonType0 Far + + Pop BX + + Test CH, 1 + JZ ButtonType0_1 + + Or Byte Ptr [SI+33], 7 + +ButtonType0_2: + Mov AX, 2 + Ret + +ButtonType0_1: + Test AL, 1 + JNZ ButtonType0_4 + + Test AL, 2 + JZ ButtonType0_2 + +ButtonType0_4: + Mov Byte Ptr [SI+33], 0 + + Jmp ButtonEffect + +EndP ButtonType0 + +; + +Proc ButtonType1 Far + + Pop BX + + And CH, CH + JZ ButtonType1_2 + + Test AL, 2 + JNZ ButtonType1_1 + + Xor Byte Ptr [SI+33], 7 + +ButtonType1_1: + Mov AX, 2 + Ret + +ButtonType1_2: + And Byte Ptr [SI+33], 1 + + Jmp ButtonEffect + +EndP ButtonType1 + +; + +Proc ButtonEffect Far + + Mov BX, [SI+16] + Add BX, BX + Jmp [CS:ButtonEffects+BX] + +EndP ButtonEffect + +; + +Proc ButtonType2 Far + + Pop BX + + And CH, CH + JZ ButtonEffect + + Test AL, 2 + JZ ButtonType2_1 + + Mov AX, 2 + Ret + +ButtonType2_1: + Add SI, 12 + LodsW + Mov CX, AX + LodsW + Mov DX, AX + Add DX, DX + Add DI, 6 + Add DX, DI + Add CX, CX + Add DI, CX + + Xor AX, AX + +ButtonType2_2: + Mov SI, [DI] + Mov [SI+33], AL + + ScasW +; Add DI, 2 + Cmp DI, DX + JBE ButtonType2_2 + + Mov SI, [BX] + Mov Byte Ptr [SI+33], 1 + + Mov AX, 1 + Ret + +EndP ButtonType2 + +; + +Proc ButtonEffect0 Far + + Mov DX, [SI+18] + Mov AX, 4 + Ret + +EndP ButtonEffect0 + +; + +Proc ButtonEffect1 Far + + Mov CX, [SI+20] + Mov DX, [SI+18] + Mov AX, 5 + Mov SI, 1 + Ret + +EndP ButtonEffect1 + +; + +Proc ButtonEffect2 Far + + Push DS + Push SI + + Mov AL, [SI+33] + Call DWord Ptr [SI+18] + + Pop SI + Pop DS + + Mov AX, 1 + + Ret + +EndP ButtonEffect2 + +; + +Proc ButtonEffect3 Far + + Mov BX, [SI+18] ; Var number + Mov AX, [SI+20] + Add BX, BX + Mov [CS:ButtonVariables+BX], AX + + Mov AX, 1 + Ret + +EndP ButtonEffect3 + +; + +Proc ButtonEffect4 Far + + Jmp DWord Ptr [SI+18] + +EndP ButtonEffect4 + +; + +Proc ButtonEffect5 Far + + Mov AX, 1 + Call DWord Ptr [SI+18] + Mov AX, [SI+22] + + StosB +; Mov [ES:DI], AL + + Mov AX, 1 + Ret + +EndP ButtonEffect5 + +; + +Proc ButtonEffect6 Far + + Jmp DWord Ptr [SI+24] + +EndP ButtonEffect6 + +; + +Proc GetPanning ; DI = channel no. + + Push DS + + Call Music_GetSongSegment + Mov DS, AX + + Mov DL, [DI+64] + Xor DH, DH + + Pop DS + + Ret + +EndP GetPanning + +; + +Proc GetPEVariables + + Push DS + + Mov DX, Pattern + Mov DS, DX +; Call PE_GetPatternSegment + Mov DL, [DI] + Xor DH, DH + + Pop DS + Ret + +EndP GetPEVariables + +; + +Proc GetScreenVariables + + Push DS + + Mov DX, Screen + Mov DS, DX + Mov DL, [DI] + Xor DH, DH + + Pop DS + Ret + +EndP GetScreenVariables + +; + +Proc SetScreenVariables + + Push DS + Push AX + + Mov AX, Screen + Mov DS, AX + Pop AX + + Mov [DI], AL + Call S_SetPalette2 + + Pop DS + Ret + +EndP SetScreenVariables + +; + +Proc SetPanning + + Push DS + + Push AX + Call Music_GetSongSegment + Mov DS, AX + Pop AX + Add DI, 64 + + Mov [DI], AL + +IF NETWORKENABLED + Mov CX, 1 + Mov DX, DI + Call Network_SendSongDataInformation +ENDIF + + Pop DS + Ret + +EndP SetPanning + +; + +Proc SetPEVariables + + Push DS + + Push AX + Mov AX, Pattern + Mov DS, AX +; Call PE_GetPatternSegment + Pop AX + + Mov [DI], AL + + Pop DS + Ret + +EndP SetPEVariables + +; + +Proc GetInstVariables + + Push DS + Push AX + Push BX + + Call I_GetInstrumentOffset + + Mov DX, [BX+DI] + Cmp DI, 19h + JNE GetInstVariables1 + + And DX, 7Fh + +GetInstVariables1: + +; If DI = 3Ah or 3Bh, the XOR top bit. + Cmp DI, 3Ah + JB GetInstVariables4 + Cmp DI, 3Bh + JA GetInstVariables4 + + Xor DL, 80h + Jmp GetInstVariables3 + +GetInstVariables4: + + Cmp DI, 14h + JE GetInstVariables2 + Xor DH, DH + Cmp DI, 3Dh + JAE GetInstVariables3 + Cmp DI, 16h + JNE GetInstVariables2 + +GetInstVariables3: + MovSX DX, DL + +GetInstVariables2: + Pop BX + Pop AX + Pop DS + + Ret + +EndP GetInstVariables + Assume DS:Nothing + +; + +Proc GetSampleVariables + + Push DS + Push AX + Push BX + + Call I_GetSampleOffset + + Mov DL, [BX+DI] + Xor DH, DH + Cmp DI, 2Fh + JNE GetSampleVariables1 + + And DL, 7Fh + +GetSampleVariables1: + Pop BX + Pop AX + Pop DS + + Ret + +EndP GetSampleVariables + Assume DS:Nothing + +; + +Proc GetMusicVariables + + Push DS + + Call Music_GetSongSegment + Mov DS, AX + Xor DX, DX + Mov DL, [DI] + + Pop DS + + Ret + +EndP GetMusicVariables + +; + +Proc GetInstrumentVariables + + Push DS + + Mov AX, Inst + Mov DS, AX + Mov DX, [DI] + + Pop DS + + Ret + +EndP GetInstrumentVariables + +; + +Proc GetDriverVariables + + Call Music_GetDriverVariable + Mov DX, AX + Ret + +EndP GetDriverVariables + +; + +Proc SetDriverVariables + + Call Music_SetDriverVariable + Ret + +EndP SetDriverVariables + +; + +Proc GetLoadSampleVariables + + Push DS + Push SI + Push BX + + Call D_GetLoadSampleVars + Mov BX, SI + + Mov DL, [BX+DI] + Xor DH, DH + + Pop BX + Pop SI + Pop DS + + Ret + +EndP GetLoadSampleVariables + +; + +Proc SetInstVariables + + Push DS + Push BX + Push AX + + Call I_GetInstrumentOffset + + Pop AX + +IF FILTERENVELOPES + Cmp DI, 3Ah + JB SetInstVariables3 + Cmp DI, 3Bh + JA SetInstVariables3 + + Xor AL, 80h +ELSE + And Word Ptr [BX+3Ah], 7F7Fh +ENDIF + +SetInstVariables3: + Mov [BX+DI], AL + Cmp DI, 14h + JNE SetInstVariables1 + +SetInstVariables2: + Mov [BX+DI], AX + +SetInstVariables1: + NetworkSendInstrument + + Pop BX + Pop DS + + Ret + +EndP SetInstVariables + Assume DS:Nothing + +; + +Proc SetSampleVariables + + Push DS + Push BX + Push AX + + Call I_GetSampleOffset + + Pop AX + Cmp DI, 2Fh + JNE SetSampleVariables1 + + Or AL, 80h ; Turn on. + +SetSampleVariables1: + Mov [BX+DI], AL + + Pop BX + Pop DS + + NetworkSendSample + + Ret + +EndP SetSampleVariables + Assume DS:Nothing + +; + +Proc SetMusicVariables + + Push DS + Push AX + + Call Music_GetSongSegment + Mov DS, AX + + Pop AX + Mov [DI], AL + +IF NETWORKENABLED + Mov CX, 1 + Mov DX, DI + Call Network_SendSongDataInformation +ENDIF + + Cmp DI, 31h + JNE SetMusicVariables1 + + Call Music_InitMixTable + Jmp SetMusicVariablesEnd + +SetMusicVariables1: + Cmp DI, 30h + JNE SetMusicVariables3 + + Call Music_SetGlobalVolume + +SetMusicVariables3: + +SetMusicVariablesEnd: + Pop DS + + Ret + +EndP SetMusicVariables + +; + +Proc SetInstrumentVariables + + Push DS + Push AX + + Mov AX, Inst + Mov DS, AX + + Pop AX + Mov [DI], AX + + Pop DS + + Ret + +EndP SetInstrumentVariables + +; + +Proc SetLoadSampleVariables + + Push DS + Push SI + Push BX + + Call D_GetLoadSampleVars + Mov BX, SI + + Mov [BX+DI], AL + + Pop BX + Pop SI + Pop DS + + Ret + +EndP SetLoadSampleVariables + +; + +Proc MousePressThumbBar Far + + Mov DX, CX + Mov CX, 8010h + Call AddMouseQueue + + Mov Word Ptr [SI+8], 1109h ; move or release + Mov Word Ptr [SI+12], Offset MouseHeldThumbBar + + Mov AL, 1 + Call SetKeyboardLock + + Xor AX, AX + + Ret + +EndP MousePressThumbBar + +; + +Proc MouseHeldThumbBar Far + + Test BH, 8 + JNZ MouseHeldThumbBar2 + +MouseHeldThumbBar1: + Mov DX, CX + Mov CX, 8010h + Call AddMouseQueue + Ret + +MouseHeldThumbBar2: + Mov CX, 8001h ; Redraw screen + Call AddMouseQueue + +; Mov Word Ptr [SI+8], 102h +; Mov Word Ptr [SI+12], Offset MousePressThumbBar + + Xor AX, AX + Call SetKeyboardLock + + Ret + +EndP MouseHeldThumbBar + +; + +Proc F_DrawThumbBar Far + + Mov [CS:MouseEventData+10], AX ; Store object number + + Call S_GetDestination + + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Call [CS:GetThumbValues+BX] ; DX returns thumbbar value + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX ; ES:DI points to area... + + Cmp DX, [SI+6] + JG F_DrawThumbBar2 + Cmp DX, [SI+4] + JL F_DrawThumbBar2 + + Mov CX, [SI+6] + Sub CX, [SI+4] + Add CX, 15 + ShR CX, 3 + Mov BX, CX + Mov AX, 300h +; Xor AX, AX + + Push DI + Push DI + + Rep StosW + + Pop DI + Push BX + Push DI + Mov BX, DX ; DX = value to show. + Sub BX, [SI+4] + Inc BX + Mov AX, BX + ShR BX, 3 + Add BX, BX + Add DI, BX + And AX, 7 + Add AX, 155 + Mov AH, 2 + StosW + + Cmp AL, 157 + JBE F_DrawThumbBar1 + Add AL, 5 + StosW + +F_DrawThumbBar1: + Pop DI + Pop BX + LEA DI, [EDI+EBX*2+2] + Mov CH, 21h + Mov AX, DX + Call PE_ConvAX2Num + + Pop DI + +F_DrawThumbBar2: + Mov BX, [SI+8] + Add BX, BX + Call [CS:DrawThumbValues+BX] ; DX returns pan value + + Mov CX, [SI+6] + Sub CX, [SI+4] + Add CX, 15 + ShR CX, 3 + + Xor AH, AH + Mov AL, [SI+2] + ShL AX, 3 + Mov [CS:MouseEventData+0], AX + ShL CX, 3 + Add AX, CX + Dec AX + Mov [CS:MouseEventData+4], AX + + Xor AH, AH + Mov AL, [SI+3] + ShL AX, 3 + Mov [CS:MouseEventData+2], AX + Add AX, 7 + Mov [CS:MouseEventData+6], AX + + Push CS + Pop DS + Assume DS:Functions + Mov SI, Offset MouseEventData + Mov Word Ptr [SI+8], 102h + Mov Word Ptr [SI+12], Offset MousePressThumbBar + Call MouseAddEvent + + Ret + +EndP F_DrawThumbBar + Assume DS:Nothing + +; + +Proc F_DrawScalableThumbBar Far + + Mov [CS:MouseEventData+10], AX ; Store object number + + Call S_GetDestination + + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Call [CS:GetThumbValues+BX] ; DX returns thumbbar value + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX ; ES:DI points to area... + + Cmp DX, [SI+6] + JG F_DrawScalableThumbBar2 + Cmp DX, [SI+4] + JL F_DrawScalableThumbBar2 + + Push DI + Push DI + + Mov AX, 300h + Mov CX, [SI+24] ; Display length + Inc CX + Rep StosW + + ; Volume bar position = Value*Width / (MaxVal-MinVal) + + Pop DI + Push DI + + Push DX + + Mov AX, [SI+24] + ShL AX, 3 + Sub DX, [SI+4] + Mul DX + Mov CX, [SI+6] + Sub CX, [SI+4] + Div CX + + Inc AX + Mov BX, AX + ShR BX, 3 + Add BX, BX + Add DI, BX + And AX, 7 + Add AX, 155 + Mov AH, 2 + StosW + + Cmp AL, 157 + JBE F_DrawScalableThumbBar1 + Add AL, 5 + StosW + +F_DrawScalableThumbBar1: + Pop DX + + Pop DI + + Mov AX, [SI+24] + LEA DI, [EDI+EAX*2+4] + Mov CH, 21h + Mov AX, DX + Call PE_ConvAX2Num + + Pop DI + +F_DrawScalableThumbBar2: + Mov BX, [SI+8] + Add BX, BX + Call [CS:DrawThumbValues+BX] ; DX returns pan value + + Xor AH, AH + Mov AL, [SI+2] + Mov CX, AX + ShL AX, 3 + Mov [CS:MouseEventData+0], AX + Mov CX, [SI+24] + Inc CX + ShL CX, 3 + Add AX, CX + Dec AX + Mov [CS:MouseEventData+4], AX + + Xor AH, AH + Mov AL, [SI+3] + ShL AX, 3 + Mov [CS:MouseEventData+2], AX + Add AX, 7 + Mov [CS:MouseEventData+6], AX + + Push CS + Pop DS + Assume DS:Functions + Mov SI, Offset MouseEventData + Mov Word Ptr [SI+8], 102h + Mov Word Ptr [SI+12], Offset MousePressThumbBar + Call MouseAddEvent + + Ret + +EndP F_DrawScalableThumbBar + Assume DS:Nothing + +; + +Proc HiLightPanning + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Sub AX, 11 + Add AX, AX + Mov DI, AX + + Mov AL, 23h + Mov CX, 10 + Call S_HiLight + + Ret + +EndP HiLightPanning + +; + +Proc F_PreThumbBar Far + + Call S_GetDestination + + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Call [CS:GetThumbValues+BX] ; DX returns thumbbar value + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX ; ES:DI points to area... + + Cmp DX, [SI+6] + JG F_PreThumbBar2 + Cmp DX, [SI+4] + JL F_PreThumbBar2 + + Mov CX, [SI+6] + Sub CX, [SI+4] + Add CX, 15 + ShR CX, 3 + Mov BX, CX + Mov AX, 300h +; Xor AX, AX + + Push DI + Push DI + + Rep StosW + + Pop DI + Push BX + Push DI + Mov BX, DX ; DX = value to show. + Sub BX, [SI+4] + Inc BX + Mov AX, BX + ShR BX, 3 + Add BX, BX + Add DI, BX + And AX, 7 + Add AX, 155 + Mov AH, 3 + StosW + + Cmp AL, 157 + JBE F_PreThumbBar1 + Add AL, 5 + StosW + +F_PreThumbBar1: + Pop DI + Pop BX + LEA DI, [EDI+EBX*2+2] + Mov CH, 21h + Mov AX, DX + Call PE_ConvAX2Num + + Pop DI + +F_PreThumbBar2: + Mov BX, [SI+8] + Add BX, BX + Call [CS:DrawThumbValues+BX] ; DX returns pan value + +; Ret + + Call S_GetDestination + + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Call [CS:PreThumbFuncs+BX] ; DX returns pan value + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX ; ES:DI points to area... + +F_PreThumbBar3: + Mov CX, [SI+6] + Sub CX, [SI+4] + Add CX, 15 + ShR CX, 3 + Mov AL, 3 + Call S_HiLight + Ret + +EndP F_PreThumbBar + +; + +Proc F_PreScalableThumbBar Far + + Call S_GetDestination + + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Call [CS:GetThumbValues+BX] ; DX returns thumbbar value + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX ; ES:DI points to area... + + Cmp DX, [SI+6] + JG F_PreScalableThumbBar2 + Cmp DX, [SI+4] + JL F_PreScalableThumbBar2 + + Push DI + Push DI + + Mov AX, 300h + Mov CX, [SI+24] ; Display length + Inc CX + Rep StosW + + ; Volume bar position = Value*Width / (MaxVal-MinVal) + + Pop DI + Push DI + + Push DX + + Mov AX, [SI+24] + ShL AX, 3 + Sub DX, [SI+4] + Mul DX + Mov CX, [SI+6] + Sub CX, [SI+4] + Div CX + + Inc AX + Mov BX, AX + ShR BX, 3 + Add BX, BX + Add DI, BX + And AX, 7 + Add AX, 155 + Mov AH, 2 + StosW + + Cmp AL, 157 + JBE F_PreScalableThumbBar1 + Add AL, 5 + StosW + +F_PreScalableThumbBar1: + Pop DX + + Pop DI + + Mov AX, [SI+24] + LEA DI, [EDI+EAX*2+4] + Mov CH, 21h + Mov AX, DX + Call PE_ConvAX2Num + + Pop DI + +F_PreScalableThumbBar2: + Mov BX, [SI+8] + Add BX, BX + Call [CS:DrawThumbValues+BX] ; DX returns pan value + +; Ret + + Call S_GetDestination + + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Call [CS:PreThumbFuncs+BX] ; DX returns pan value + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX ; ES:DI points to area... + +F_PreScalableThumbBar3: + Mov CX, [SI+24] + Inc CX + Mov AL, 3 + Call S_HiLight + Ret + +EndP F_PreScalableThumbBar + +; + +Proc F_PostScalableThumbBar Far + + Cmp CX, 8010h + JE F_PostScalableThumbBarMouse1 + + Jmp F_PostThumbBar + +F_PostScalableThumbBarMouse1: ; DX = pixel... + Mov SI, [BX] + + Xor AX, AX + Mov AL, [SI+2] ; Left point + ShL AX, 3 ; Left pixel + Add AX, 4 + + Sub DX, AX + JNC F_PostScalableThumbBarMouse2 + + Xor DX, DX + +F_PostScalableThumbBarMouse2: ; Value = (Pixel / NumPixels)*(Max-Min)+Min + Mov CX, [SI+24] ; Length + ShL CX, 3 ; AX = MaxPixel + Cmp DX, CX + JB F_PostScalableThumbBarMouse3 + + Mov DX, CX + +F_PostScalableThumbBarMouse3: + Mov AX, [SI+6] + Sub AX, [SI+4] + Mul DX + Div CX + + ShR CX, 1 + Cmp CX, DX + AdC AX, 0 + + Add AX, [SI+4] + + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Call [CS:PostThumbFuncs+BX] + + Mov AX, 2 + Ret + +EndP F_PostScalableThumbBar + +; + +Proc F_PostThumbBar Far + + Mov SI, [BX] + + Push ES + Push DI + + Call S_GetDestination + + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Push BX + Push DX + Call [CS:GetThumbValues+BX] ; AX contains value. + Mov AX, DX + Pop DX + Pop BX + + Pop DI + Pop ES + + Push AX + Push BX + + Call [CS:PostThumbCheck+BX] + Test AX, AX + JNZ F_PostThumbBar23 + + Pop BX + Pop AX + + Cmp CX, 8010h + JE F_PostThumbBarMouse1 + + Cmp CX, 8001h + JE F_PostThumbBarMouseRedrawScreen + + Cmp CX, 1CBh + JE F_PostThumbBar2 + + Cmp CX, 1CDh + JE F_PostThumbBar4 + + Cmp CX, 1C7h + JE F_PostThumbBar10 + + Cmp CX, 1CFh + JE F_PostThumbBar11 + + Cmp CX, 1C8h + JE F_PostThumbBar5 + + Cmp CX, 1D0h + JE F_PostThumbBar6 + + Cmp CX, 10Fh + JE F_PostThumbBar7 + + Cmp CX, 1C9h + JE F_PostThumbBar21 + + Cmp CX, 1D1h + JE F_PostThumbBar22 + + Test CL, CL + JZ F_PostThumbBar20 + + Cmp DX, 0F00h + JE F_PostThumbBar8 + + Cmp DX, '0' + JB F_PostThumbBar50 + Cmp DX, '9' + JA F_PostThumbBar50 + + Jmp F_PostThumbBar30 + +F_PostThumbBar50: + Test CX, 600h + JNZ F_PostThumbBar17 + + Test CX, 1800h + JNZ F_PostThumbBar16 + +F_PostThumbBar20: + Xor AX, AX + Ret + +F_PostThumbBar23: + Pop BX + Pop AX + +F_PostThumbBarMouseRedrawScreen: + Mov AX, 1 + Ret + +F_PostThumbBar16: + Mov DI, CX + And DI, 1FFh + Cmp DI, 1CBh + JE F_PostThumbBar14 + + Cmp DI, 1CDh + JE F_PostThumbBar12 + + Jmp F_PostThumbBar20 + +F_PostThumbBar17: + Mov DI, CX + And DI, 1FFh + Cmp DI, 1CBh + JE F_PostThumbBar18 + + Cmp DI, 1CDh + JE F_PostThumbBar19 + + Jmp F_PostThumbBar20 + +F_PostThumbBar2: + Dec AX + Cmp AX, [SI+6] + JG F_PostThumbBar9 + Cmp Ax, [SI+4] + JL F_PostThumbBar9 + +F_PostThumbBar15: + Cmp AX, [SI+6] + JG F_PostThumbBarMin + Cmp AX, [SI+4] + JGE F_PostThumbBar3 + +F_PostThumbBarMin: + Mov AX, [SI+4] + +F_PostThumbBar3: + Mov DI, [SI+10] + Call [CS:PostThumbFuncs+BX] + +F_PostThumbBar9: + Mov AX, 1 + Ret + +F_PostThumbBar10: + Mov AX, [SI+4] + Jmp F_PostThumbBar3 + +F_PostThumbBar11: + Mov AX, [SI+6] + Jmp F_PostThumbBar3 + +F_PostThumbBar4: + Inc AX + Cmp AX, [SI+4] + JL F_PostThumbBar9 + + Cmp AX, [SI+6] + JG F_PostThumbBar9 + +F_PostThumbBar13: + Cmp AX, [SI+4] + JL F_PostThumbBarMax + Cmp AX, [SI+6] + JLE F_PostThumbBar3 + +F_PostThumbBarMax: + Mov AX, [SI+6] + Jmp F_PostThumbBar3 + +F_PostThumbBar12: + Add AX, 2 + Jmp F_PostThumbBar13 + +F_PostThumbBar14: + Sub AX, 2 + Jmp F_PostThumbBar15 + +F_PostThumbBar18: + Sub AX, 4 + Jmp F_PostThumbBar15 + +F_PostThumbBar19: + Add AX, 4 + Jmp F_PostThumbBar13 + +F_PostThumbBar22: + LodsW + +F_PostThumbBar21: + LodsW + +F_PostThumbBar8: + LodsW + +F_PostThumbBar7: + LodsW + +F_PostThumbBar6: + LodsW + +F_PostThumbBar5: + Add SI, 12 + LodsW + Cmp AX, 0FFFFh + JE F_PostThumbBar20 + + Mov [DI], AX + Jmp F_PostThumbBar9 + +F_PostThumbBarMouse1: ; DX = pixel... + Xor AX, AX + Mov AL, [SI+2] ; Left point + ShL AX, 3 ; Left pixel + Sub DX, AX + Sub DX, 4 + Mov AX, [SI+4] + Add AX, DX + + Cmp AX, [SI+4] + JG F_PostThumbBarMouse2 + + Mov AX, [SI+4] + Jmp F_PostThumbBarMouse3 + +F_PostThumbBarMouse2: + Cmp AX, [SI+6] + JL F_PostThumbBarMouse3 + + Mov AX, [SI+6] + +F_PostThumbBarMouse3: + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Call [CS:PostThumbFuncs+BX] + + Mov AX, 2 + Ret + +F_PostThumbBar30: + Push DS + Push SI + + Call S_SaveScreen + + Mov DI, Offset ThumbStringEnter + Push CS + Pop ES + Mov AL, DL + StosB + + Xor AL, AL + Mov CX, 4 + Rep StosB + + Mov DI, Offset O1_ThumbStringList + Mov CX, 3 + Call M_Object1List + + Call S_RestoreScreen + + Pop SI + Pop DS + + And DX, DX + JZ F_PostThumbBar31 + + ; Now get value... + Xor CX, CX + Mov DI, Offset ThumbStringEnter + +F_PostThumbBar32: + Mov AL, [CS:DI] + And AL, AL + JZ F_PostThumbBar33 + + Inc DI + + Push AX + Mov AX, 10 + Mul CX + Mov CX, AX + Pop AX + + Cmp AL, '0' + JB F_PostThumbBar31 + Cmp AL, '9' + JA F_PostThumbBar31 + + Sub AL, '0' + Xor AH, AH + Add CX, AX + Jmp F_PostThumbBar32 + +F_PostThumbBar33: ; now save value. + Cmp DI, Offset ThumbStringEnter + JE F_PostThumbBar31 + + Mov AX, CX + + Cmp AX, [SI+4] + JL F_PostThumbBar31 + Cmp AX, [SI+6] + JG F_PostThumbBar31 + + Mov BX, [SI+8] + Mov DI, [SI+10] + Add BX, BX + Call [CS:PostThumbFuncs+BX] + +F_PostThumbBar31: + Mov AX, 1 + Ret + +EndP F_PostThumbBar + +; + +Proc F_DrawInfoLine Far + + Push ES + LodsW + Push SI + Xor DX, DX + +F_DrawInfoLine1: + LodsB + Inc DX + And AL, AL + JNZ F_DrawInfoLine1 + + Dec DX + Pop SI ; DX contains length of string + Call S_GetDestination + + Mov DI, (1+11*80)*2 + Mov BX, 78 + Mov CX, BX + Cmp Byte Ptr [SI], 0 + JE F_DrawInfoLine3 + + Sub CX, DX + ShR CX, 1 + Sub BX, CX + Sub BX, DX + Sub BX, 2 + + Mov AX, 219Ah + Rep StosW + + Mov AX, 2020h + StosW + +F_DrawInfoLine2: + LodsB + StosW + Dec DX + JNZ F_DrawInfoLine2 + + Mov AX, 2020h + StosW + + Mov CX, BX + +F_DrawInfoLine3: + Mov AX, 219Ah + Rep StosW + + Pop ES + Ret + +EndP F_DrawInfoLine + +; + +Proc F_ShowChannels Far + + Push DS + + Push CS + Pop DS + Assume DS:Functions + + Mov DI, (20+15*80)*2 + Mov CX, 32 + Mov AX, 3130h + Mov Word Ptr ChannelNumbers, AX + Mov AH, 20h + Call F_ShowChannel1 + + Mov DI, (54+15*80)*2 + Mov CX, 32 + Call F_ShowChannel1 + + Pop DS + Assume DS:Nothing + Ret + +EndP F_ShowChannels + +; + +Proc F_ShowChannel1 + + Assume DS:Functions + +F_ShowChannel1_1: + Mov SI, Offset ChannelMsg + Call S_DrawString + + Inc Byte Ptr [ChannelNumbers+1] + Cmp Byte Ptr [ChannelNumbers+1], '9' + JBE F_ShowChannel1_2 + + Inc Byte Ptr [ChannelNumbers] + Mov Byte Ptr [ChannelNumbers+1], '0' + +F_ShowChannel1_2: + Add DI, 140 + Loop F_ShowChannel1_1 + + Assume DS:Nothing + + Ret + +EndP F_ShowChannel1 + +; + +Proc F_RedrawScreen Far + + Mov AX, 1 + Ret + +EndP F_RedrawScreen + +; + +Proc F_Return0 Far ; ESC pressed on opening scrn + + Xor DX, DX + Mov AX, 4 + Ret + +EndP F_Return0 + +; + +Proc F_Return64 Far + + Mov DX, 64 + Mov AX, 4 + Ret + +EndP F_Return64 + +; + +Proc F_Return192 Far + + Mov DX, 192 + Mov AX, 4 + Ret + +EndP F_Return192 + +; + +Proc PanningKeys + + Push AX + Mov AX, DX + Cmp AX, 'a' + JB PanningKeys1 + + Cmp AX, 'z' + JA PanningKeys3 + + Sub AX, 32 + +PanningKeys1: + Cmp AL, 'L' + JE PanningKeysLeft + Cmp AL, 'R' + JE PanningKeysRight + Cmp AL, 'M' + JE PanningKeysMiddle + Cmp AL, 'S' + JE PanningKeysSurround + Cmp AL, ' ' + JE PanningKeysSpace + +PanningKeys3: + Pop AX + Xor AX, AX + Ret + +PanningKeysLeft: + Xor AX, AX + Jmp PanningKeys2 + +PanningKeysRight: + Mov AX, 64 + Jmp PanningKeys2 + +PanningKeysMiddle: + Mov AX, 32 + Jmp PanningKeys2 + +PanningKeysSurround: + Mov AX, 100 + +PanningKeys2: + Mov DI, [SI+10] + Call SetPanning + Pop AX + + Mov AX, 1 + Ret + +PanningKeysSpace: + Pop AX + Xor AL, 128 + Push AX + + Mov BX, [ES:DI] + Cmp BX, 74 + JAE PanningKeys2 + + Inc Word Ptr [ES:DI] + + Jmp PanningKeys2 + +EndP PanningKeys + +; + +Proc FilterKeys + + Push DI + Mov DI, [SI+10] + + Cmp DI, 3Ah + JB FilterKeys1 + Cmp DI, 3Bh + JA FilterKeys1 + + Cmp DX, ' ' + JNE FilterKeys1 + + Xor AL, 80h + Call SetInstVariables + + Mov AX, 1 + Jmp FilterKeysEnd + +FilterKeys1: + Xor AX, AX +FilterKeysEnd: + Pop DI + Ret + +EndP FilterKeys + +; + +Proc DrawPanning + + Push DS + Push SI + + Push CS + Pop DS + + Test DL, 128 + JZ DrawPanning2 + + Mov SI, Offset MutedMessage + Mov AH, 5 + Call S_DrawString + + Jmp DrawPanning1 + +DrawPanning2: + Cmp DX, 100 + JNE DrawPanning1 + + Mov SI, Offset SurroundMessage + Mov AH, 5 + Call S_DrawString + +DrawPanning1: + Pop SI + Pop DS + Ret + +EndP DrawPanning + +; + +Proc DrawMIDIChannel + + Mov AX, [SI+0Ah] + Cmp AX, 3Fh + JA DrawMIDIChannel2 + Cmp AX, 3Ah + JB DrawMIDIChannel2 + + Cmp AX, 3Ch + JNE DrawMIDIChannel4 + +DrawMIDIChannel1: + Cmp DL, 17 + JNE DrawMIDIChannel5 + + Add DI, 22 + Mov AX, 200h+'M' + StosW + Mov AL, 'a' + StosW + Mov AL, 'p' + StosW + StosW + Mov AL, 'e' + StosW + Mov AL, 'd' + StosW + +DrawMIDIChannel5: + Test DL, DL + JZ DrawMIDIChannel3 + Jmp DrawMIDIChannel2 + +DrawMIDIChannel4: + Test DX, DX + JNS DrawMIDIChannel2 + +DrawMIDIChannel3: + Mov AX, 200h+'O' + StosW + Mov AL, 'f' + StosW + StosW + Jmp DrawMIDIChannel2 + +DrawMIDIChannel2: + Ret + +EndP DrawMIDIChannel + +; + +Proc F_Return1 Far + + Mov DX, 1 + Mov AX, 4 + Ret + +EndP F_Return1 + +; + +Proc GetSIOInstSegment + + Mov SI, Inst + Mov DS, SI + Mov SI, CX + + Ret + +EndP GetSIOInstSegment + +; + +Proc GetSIODiskSegment + + Mov SI, Disk + Mov DS, SI + Mov SI, CX + + Ret + +EndP GetSIODiskSegment + +; + +Proc GetLoadSampleString ; Returns DS:SI + + Call D_GetLoadSampleVars ; Gets SI = currentsample offset + ; DS = DiskDataArea + Add SI, CX + + Ret + +EndP GetLoadSampleString + +; + +Proc GetMusicSegmentString + + Call Music_GetSongSegment + Mov DS, AX + + Mov SI, CX + + Ret + +EndP GetMusicSegmentString + +; + +Proc SetMusicSegmentString + +IF NETWORKENABLED + Mov CX, 26 + Mov DX, 4 + Call Network_SendSongDataInformation +ENDIF + Ret + +EndP SetMusicSegmentString + +; + +Proc GetPatternSegmentString + + Push CS + Pop DS + + Mov SI, CX + + Ret + +EndP GetPatternSegmentString + +; + +Proc GetSampleString + + Call I_GetSampleOffset + Mov SI, BX + Add SI, CX + + Ret + +EndP GetSampleString + +; + +Proc SetSampleString + + NetworkSendSample + + Ret + +EndP SetSampleString + +; + +Proc GetInstrumentString + + Call I_GetInstrumentOffset + Mov SI, BX + Add SI, CX + + Ret + +EndP GetInstrumentString + +; + +Proc SetInstrumentString + + NetworkSendInstrument + Ret + +EndP SetInstrumentString + +; + +TopMIDIMacro DW 80h + +Proc GetMIDIString ; CX = select2 + + Push Music + Pop DS + Assume DS:Music + + Mov DS, MIDIDataArea + Assume DS:Nothing + + Mov SI, CX + Test CX, CX + JNS GetMIDIString1 + + Mov CX, CS:TopMIDIMacro + Sub SI, 8000h+80h*20h + ShL CX, 5 + Add SI, CX + +GetMIDIString1: + Ret + +EndP GetMIDIString + +; + +Proc MouseSelectString Far + + Mov CX, 8010h + Xor DX, DX + Call AddMouseQueue + + Xor AX, AX + + Ret + +EndP MouseSelectString + +; + +PostStringFunction DW 0 + +Proc F_GetStringInputOffset + + Mov BX, [SI+4] + Mov CX, [SI+6] + + Mov [CS:PostStringFunction], Offset F_NothingNear + + Cmp BX, 10h + JA F_GetStringInputOffset1 + + Add BX, BX + Push AX + + Mov AX, [CS:PostStringInput+BX] + Mov PostStringFunction, AX + + Pop AX + Call [CS:StringInputOffset+BX] ; DS:SI points to string + Ret + +F_GetStringInputOffset1: + Mov DS, BX + Mov SI, CX + Ret + +EndP F_GetStringInputOffset + +; + +Proc F_DrawStringInput Far + + Mov [CS:MouseEventData+10], AX ; Store object number + + Push DS + Push SI + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX + Call S_GetDestination + + Call F_GetStringInputOffset + + Mov AH, 2h + +F_DrawStringInput1: + LodsB + Test AL, AL + JZ F_DrawStringInput2 + Cmp AL, 226 + JB F_DrawStringInput3 + + Mov AL, ' ' + +F_DrawStringInput3: + + StosW + Jmp F_DrawStringInput1 + +F_DrawStringInput2: + Pop SI + Pop DS + + Xor AH, AH + Mov AL, [SI+2] ; XValue + Mov CX, AX + ShL CX, 3 + Mov [CS:MouseEventData+0], CX + + Add AL, [SI+8] + Mov CX, AX + ShL CX, 3 + Dec CX + Mov [CS:MouseEventData+4], CX + + Mov AL, [SI+3] + ShL AX, 3 + Mov [CS:MouseEventData+2], AX + Add AX, 7 + Mov [CS:MouseEventData+6], AX + + Push CS + Pop DS + Assume DS:Functions + + Mov SI, Offset MouseEventData + Mov [MouseEventData+8], 102h + Mov [MouseEventData+12], Offset MouseSelectString + + Call MouseAddEvent + + Ret + +EndP F_DrawStringInput + Assume DS:Nothing + +; + +Proc F_PreStringInput Far + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX + Call S_GetDestination + + Call F_GetStringInputOffset + +F_PreStringInput1: + LodsB + And AL, AL + JZ F_PreStringInput2 + ScasW +; Add DI, 2 + Jmp F_PreStringInput1 + +F_PreStringInput2: + Inc DI + Mov AL, 30h + StosB + Ret + +EndP F_PreStringInput + +; + +Proc F_PostStringInput Far + + Test CL, CL + JZ F_PostStringInput9 + + Mov SI, [BX] + + Cmp CX, 8010h + JE F_PostStringInput5 + + Cmp CX, 1C8h + JNE F_PostStringInput1 + + Mov AX, [SI+14] + Jmp F_PostStringInput4 + +F_PostStringInput1: + Cmp CX, 1D0h + JNE F_PostStringInput2 + + Mov AX, [SI+16] + Jmp F_PostStringInput4 + +F_PostStringInput2: + Cmp CX, 10Fh ; Tab + JNE F_PostStringInput3 + + Mov AX, [SI+18] + Jmp F_PostStringInput4 + +F_PostStringInput3: + Cmp DX, 0F00h + JNE F_PostStringInput6 + + Mov AX, [SI+20] + +F_PostStringInput4: + Cmp AX, 0FFFFh + JE F_PostStringInput12 + +; Mov Word Ptr CS:LastStringData, 0 +; Mov Word Ptr CS:LastStringData+2, 0 + + Mov [DI], AX + +F_PostStringInput5: + Mov AX, 1 + Ret + +F_PostStringInput6: + Cmp CX, 11Ch ; Enter + JNE F_PostStringInput7 + + Cmp Word Ptr [SI+10], 0 + JNE F_PostStringInput13 + + Cmp Word Ptr [SI+12], 0 + JE F_PostStringInput12 + +F_PostStringInput13: + Jmp DWord Ptr [SI+10] + +F_PostStringInput7: + Cmp CX, 10Eh ; Backspace + JNE F_PostStringInput8 + + Call F_GetStringInputOffset + + Cmp Byte Ptr [DS:SI], 0 + JE F_PostStringBackSpace2 + +F_PostStringBackSpace1: + LodsB + And AL, AL + JNZ F_PostStringBackSpace1 + + Mov [SI-2], AL + +F_PostStringBackSpace2: + Jmp F_PostStringInput11 + +F_PostStringInput8: + Cmp DX, 127 ; Ctrl-Backspace + JNE F_PostStringInput12 + + Mov DX, [SI+8] + Call F_GetStringInputOffset + + Mov CX, DX + Mov AX, DS + Mov ES, AX + Mov DI, SI + Xor AL, AL + Rep StosB + + Jmp F_PostStringInput11 + +F_PostStringInput12: + Test CL, CL + JZ F_PostStringInput9 + Cmp DL, 32 + JB F_PostStringInput9 + + Mov DI, [SI+8] + Call F_GetStringInputOffset + + Xor BX, BX + +F_PostStringInput10: + LodsB + Inc BX + And AL, AL + JNZ F_PostStringInput10 + + Dec SI + Cmp BX, DI + JAE F_PostStringInput11 + + Mov AL, DL + Xor AH, AH + Mov [DS:SI], AX + +F_PostStringInput11: + Call [CS:PostStringFunction] + + Mov AX, 1 + Ret + +F_PostStringInput9: + Xor AX, AX + Ret + +EndP F_PostStringInput + +; + +Proc F_GotoEmptyList Far + + Mov AX, 5 + Mov SI, 1 + Mov DI, AX + Mov CX, Object1 + Mov DX, Offset O1_EmptyList + + Ret + +EndP F_GotoEmptyList + +; + +Proc GetSampleToggle + + Push DS + + Call I_GetSampleOffset + Xor CL, CL + + Mov DH, [BX+DI] + Test DH, DL + JZ GetSampleToggle1 + + Inc CX + + Cmp DI, 2Fh + JE GetSampleToggle1 + + ShL DL, 1 + ShL DL, 1 + + Pop DS + Push DS + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + LEA DI, [EAX+6] ; DI points to screen part. + Push DS + Push SI + + Mov SI, Offset ForwardMsg + Test DH, DL + JZ GetSampleToggle2 + + Mov SI, Offset PingPongMsg + +GetSampleToggle2: + Push CS + Pop DS + Mov AH, 2 + Call S_DrawString + + Pop SI + Pop DS + +GetSampleToggle1: + Pop DS + Ret + +EndP GetSampleToggle + +; + +Proc GetInstrumentToggle + + Push DS + + Call I_GetInstrumentOffset + Xor CL, CL + + Mov DH, [BX+DI] + Test DH, DL + JZ GetInstrumentToggle1 + + Inc CX + + Cmp DI, 1D4h + JNE GetInstrumentToggle1 + Cmp DL, 1 + JNE GetInstrumentToggle1 + + Push DS + Push SI + + Push CS + Pop DS + + Mov DI, (28*80+57)*2 + Mov AH, 2 + Mov SI, Offset PitchMessage + Test DH, DH + JNS GetInstrumentToggle3 + + Mov SI, Offset FilterMessage + +GetInstrumentToggle3: + Call S_DrawString + + Pop SI + Pop DS + +GetInstrumentToggle1: + Cmp DI, 19h + JNE GetInstrumentToggle2 + + Xor CL, 1 + +GetInstrumentToggle2: + Pop DS + Ret + +EndP GetInstrumentToggle + +; + +Proc GetLoadSampleToggle + + Push DS + Push SI + Call D_GetLoadSampleVars ; Gets SI = currentsample offset + ; DS = DiskDataArea + + Mov BX, SI + Pop SI + + Xor CL, CL + + Mov DH, [BX+DI] + Test DH, DL + JZ GetLoadSampleToggle1 + + Inc CX + + ShL DL, 1 + ShL DL, 1 + + Pop DS + Push DS + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + LEA DI, [EAX+6] ; DI points to screen part + Push DS + Push SI + + Mov SI, Offset ForwardMsg + Test DH, DL + JZ GetLoadSampleToggle2 + + Mov SI, Offset PingPongMsg + +GetLoadSampleToggle2: + Push CS + Pop DS + Mov AH, 2 + Call S_DrawString + + Pop SI + Pop DS + +GetLoadSampleToggle1: + Pop DS + Ret + +EndP GetLoadSampleToggle + +; + +Proc GetPatternSegmentToggle + + Push DS + + Mov AX, Pattern + Mov DS, AX + + Xor CL, CL + Test [DS:DI], DL + JZ GetPatternSegmentToggle1 + + Inc CX + +GetPatternSegmentToggle1: + Pop DS + Ret + +EndP GetPatternSegmentToggle + +; + +Proc GetMusicSegmentToggle + + Push DS + + Call Music_GetSongSegment + Mov DS, AX + + Xor CL, CL + Test [DS:DI], DL + JZ GetMusicSegmentToggle1 + + Inc CX + +GetMusicSegmentToggle1: + Pop DS + Ret + +EndP GetMusicSegmentToggle + +; + +Proc SampleToggle + + Push DS + + Call I_GetSampleOffset + + Cmp DI, 2Fh + JNE SampleToggle6 + + Xor [BX+DI], DL + + Jmp SampleToggleEnd + +SampleToggle6: + Mov DH, DL + ShL DH, 1 + ShL DH, 1 + Test [BX+DI], DL + JZ SampleToggle3 + + Test [BX+DI], DH + JNZ SampleToggle3 + + Xor [BX+DI], DH + + Call Music_RegetLoopInformation + Jmp SampleToggleEnd + +SampleToggle3: + Xor [BX+DI], DL + Test [BX+DI], DL + JZ SampleToggle1 + ; Something was just toggled On. + Not DH + And [BX+DI], DH + + Cmp DL, 10h + JE SampleToggle2 + Cmp DL, 20h + JNE SampleToggle1 ; Safety Check. + ; Sustain Loop. + Mov EAX, [BX+40h] ; SusLBeg + Cmp EAX, [BX+30h] + JB SampleToggle4 + + Xor EAX, EAX + Mov [BX+40h], EAX + +SampleToggle4: + Cmp EAX, [BX+44h] + JB SampleToggle1 + + Mov EAX, [BX+30h] + Mov [BX+44h], EAX + Jmp SampleToggle1 + +SampleToggle2: ; Normal Loop + Mov EAX, [BX+34h] + Cmp EAX, [BX+30h] + JB SampleToggle5 + + Xor EAX, EAX + Mov [BX+34h], EAX + +SampleToggle5: + Cmp EAX, [BX+38h] + JB SampleToggle1 + + Mov EAX, [BX+30h] + Mov [BX+38h], EAX + +SampleToggle1: + Call Music_RegetLoopInformation + Call I_DrawWaveForm + +SampleToggleEnd: + NetworkSendSample + + Pop DS + Ret + +EndP SampleToggle + +; + +Proc InstrumentToggle + + Push DS + + Call I_GetInstrumentOffset + +IF FILTERENVELOPES + Cmp DI, 1D4h + JNE InstrumentToggle2 + Cmp DL, 1 + JNE InstrumentToggle2 + + Xor Byte Ptr [BX+DI], 80h + JNS InstrumentToggle3 + + Test [BX+DI], DL + JZ InstrumentToggle2 + + And Byte Ptr [BX+DI], 7Fh + +InstrumentToggle2: +ELSE + And Byte Ptr [BX+1D4h], 7Fh +ENDIF + Xor [BX+DI], DL + +InstrumentToggle3: + Call I_MapEnvelope + + NetworkSendInstrument + + Pop DS + Ret + +EndP InstrumentToggle + +; + +Proc LoadSampleToggle + + Push DS + Push SI + Call D_GetLoadSampleVars ; Gets SI = currentsample offset + ; DS = DiskDataArea + + Mov BX, SI + Pop SI + + Mov DH, DL + ShL DH, 1 + ShL DH, 1 + Test [BX+DI], DL + JZ LoadSampleToggle3 + + Test [BX+DI], DH + JNZ LoadSampleToggle3 + + Xor [BX+DI], DH + Pop DS + Ret + +LoadSampleToggle3: + Xor [BX+DI], DL + Test [BX+DI], DL + JZ LoadSampleToggle1 + ; Something was just toggled On. + Not DH + And [BX+DI], DH + + Cmp DL, 10h + JE LoadSampleToggle2 + Cmp DL, 20h + JNE LoadSampleToggle1 ; Safety Check. + ; Sustain Loop. + Mov EAX, [BX+40h] ; SusLBeg + Cmp EAX, [BX+30h] + JB LoadSampleToggle4 + + Xor EAX, EAX + Mov [BX+40h], EAX + +LoadSampleToggle4: + Cmp EAX, [BX+44h] + JB LoadSampleToggle1 + + Mov EAX, [BX+30h] + Mov [BX+44h], EAX + Jmp LoadSampleToggle1 + +LoadSampleToggle2: ; Normal Loop + Mov EAX, [BX+34h] + Cmp EAX, [BX+30h] + JB LoadSampleToggle5 + + Xor EAX, EAX + Mov [BX+34h], EAX + +LoadSampleToggle5: + Cmp EAX, [BX+38h] + JB LoadSampleToggle1 + + Mov EAX, [BX+30h] + Mov [BX+38h], EAX + +LoadSampleToggle1: + Call D_DrawWaveForm + + Pop DS + Ret + +EndP LoadSampleToggle + +; + +Proc PatternSegmentToggle + + Push DS + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Xor [DS:DI], DL + + Cmp DI, Offset MultiChannelInfo + JB PatternSegmentToggle1 + Cmp DI, Offset MultiChannelInfo+64 + JAE PatternSegmentToggle1 + + Test CX, 8000h + JNZ PatternSegmentToggle1 + + Inc Word Ptr [ES:BP] + +PatternSegmentToggle1: + Pop DS + Ret + +EndP PatternSegmentToggle + Assume DS:Nothing + +; + +Proc MusicSegmentToggle + + Push DS + Call Music_GetSongSegment + Mov DS, AX + + Xor [DS:DI], DL + +IF NETWORKENABLED + Mov CX, 1 + Mov DX, DI + Call Network_SendSongDataInformation +ENDIF + + Pop DS + Ret + +EndP MusicSegmentToggle + +; + +Proc MouseToggle Far + + Mov CX, 8010h + Mov DX, ' ' + Call AddMouseQueue + + Xor AX, AX + + Ret + +EndP MouseToggle + +; + +Proc F_DrawToggle Far + + Mov [CS:MouseEventData+10], AX ; Store object number + + Call S_GetDestination + Mov BX, [SI+4] ; Segment no. + Mov DI, [SI+6] + Mov DL, [SI+8] + Add BX, BX + Call [CS:GetToggleStatus+BX] ; Returns CL with 0=off, 1=on + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX ; DI points to screen part. + + Mov AX, 200h+'O' + StosW + And CL, CL + JZ F_DrawToggle1 + + Mov AL, 'n' + StosW + Jmp F_DrawToggle2 + +F_DrawToggle1: + Mov AL, 'f' + StosW + StosW + +F_DrawToggle2: + Xor AH, AH + Mov AL, [SI+2] ; XValue + ShL AX, 3 + Mov [CS:MouseEventData+0], AX + Add AX, 23 + Mov [CS:MouseEventData+4], AX + + Xor AH, AH + Mov AL, [SI+3] + ShL AX, 3 + Mov [CS:MouseEventData+2], AX + Add AX, 7 + Mov [CS:MouseEventData+6], AX + + Push CS + Pop DS + Assume DS:Functions + + Mov SI, Offset MouseEventData + Mov [MouseEventData+8], 102h + Mov [MouseEventData+12], Offset MouseToggle + + Call MouseAddEvent + + Ret + +EndP F_DrawToggle + +; + +Proc F_PreToggle Far + + Call S_GetDestination + Mov BX, [SI+4] ; Segment no. + Mov DI, [SI+6] + Mov DL, [SI+8] + Add BX, BX + Call [CS:GetToggleStatus+BX] ; Returns CL with 0=off, 1=on + + Xor CH, CH + Neg CL + Add CL, 3 ; CL = number to hilight + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX + + Mov AL, 30h + Call S_HiLight + + Ret + +EndP F_PreToggle + +; + +Proc F_PostToggle Far + + Mov SI, [BX] + + Test CL, CL + JZ F_PostToggle7 + + Cmp DX, ' ' + JNE F_PostToggle1 + + Mov BP, DI + + Mov BX, [SI+4] ; Segment no. + Mov DI, [SI+6] + Mov DL, [SI+8] + Add BX, BX + Call [CS:ToggleBit+BX] + + Mov AX, 1 + Ret + +F_PostToggle1: + Cmp CX, 1C8h + JE F_PostToggle5 + Cmp CX, 1D0h + JE F_PostToggle4 + Cmp CX, 10Fh ; Tab + JE F_PostToggle3 + Cmp CX, 1CDh + JE F_PostToggle3 + Cmp DX, 0F00h + JE F_PostToggle2 + Cmp CX, 1CBh + JE F_PostToggle2 + +F_PostToggle7: + Xor AX, AX + Ret + +F_PostToggle2: + LodsW +F_PostToggle3: + LodsW +F_PostToggle4: + LodsW +F_PostToggle5: + Add SI, 9 + LodsW + Cmp AX, 0FFFFh + JE F_PostToggle7 + + Mov [DI], AX + +F_PostToggle6: + Mov AX, 1 + Ret + +EndP F_PostToggle + +; + +Proc GetInstrument3Num + + Push DS + + Call I_GetInstrumentOffset + + Mov AL, [BX+DI] + Xor AH, AH + + Pop DS + Ret + +EndP GetInstrument3Num + +; + +Proc SetInstrument3Num ; AX = value. + + Push DS + Push SI + Push AX + + Mov AX, Inst + Mov DS, AX + Assume DS:Inst + + Mov CX, MaxNode + Dec CL + Assume DS:Nothing + + + Call I_GetInstrumentOffset + + Pop AX + Cmp AL, CL + JB SetInstrument3Num1 + + Mov AL, CL + +SetInstrument3Num1: + Mov [BX+DI], AL + + Mov SI, 132h + Call Near Ptr SetInstrument3Num2 + + Mov SI, 134h + Call Near Ptr SetInstrument3Num2 + + Mov SI, 184h + Call Near Ptr SetInstrument3Num2 + + Mov SI, 186h + Call Near Ptr SetInstrument3Num2 + + Mov SI, 1D6h + Call Near Ptr SetInstrument3Num2 + + Mov SI, 1D8h + Call Near Ptr SetInstrument3Num2 + + Call I_MapEnvelope + + Pop SI + Pop DS + + Ret + +SetInstrument3Num2: + Mov AL, [BX+SI] + Cmp AL, [BX+SI+1] + JBE SetInstrument3Num3 + + Mov [BX+SI+1], AL + +SetInstrument3Num3: + RetN + +EndP SetInstrument3Num + +; + +Proc GetSample5Num + + Push DS + + Call I_GetSampleOffset + + Mov EAX, [BX+DI] + + Pop DS + Ret + +EndP GetSample5Num + +; + +Proc GetLoadSample5Num + + Push DS + Push SI + Call D_GetLoadSampleVars ; Gets SI = currentsample offset + ; DS = DiskDataArea + + Mov BX, SI + Mov EAX, [BX+DI] + + Pop SI + Pop DS + + Ret + +EndP GetLoadSample5Num + +; + +Proc GetInst5Num + + Push DS + Mov AX, Inst + + Mov DS, AX + Mov EAX, [DI] + + Pop DS + Ret + +EndP GetInst5Num + +; + +Proc SetSample5Num ; AX = value. + + Push DS + Push AX + + Call I_GetSampleOffset + + Pop AX + Mov [BX+DI], EAX + + Pop DS + + NetworkSendSample + + Ret + +EndP SetSample5Num + +; + +Proc SetLoadSample5Num ; AX = value. + + Push DS + Push SI + + Call D_GetLoadSampleVars ; Gets SI = currentsample offset + Mov BX, SI + + Mov [BX+DI], EAX + + Pop SI + Pop DS + Ret + +EndP SetLoadSample5Num + +; + +Proc SetInst5Num + + Push DS + + Mov BX, Inst + Mov DS, BX + Mov [DI], EAX + + Pop DS + + Ret + +EndP SetInst5Num + +; + +Proc MouseNumberDecrement Far + + Mov CX, 8010h + Mov DX, '-' + Call AddMouseQueue + + Xor AX, AX + + Ret + +EndP MouseNumberDecrement + +; + +Proc MouseNumberIncrement Far + + Mov CX, 8010h + Mov DX, '+' + Call AddMouseQueue + + Xor AX, AX + + Ret + +EndP MouseNumberIncrement + +; + +Proc F_Draw3Num Far + + Mov [CS:MouseEventData+10], AX ; Store object number + + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Call [CS:Get3NumValues+BX] ; AX = value. + + Push AX + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX + Call S_GetDestination + + Pop AX + Xor DX, DX + Mov CH, 2 + Call PE_ConvAX2Num + + Xor AX, AX + Mov AL, [SI+2] ; X value + ShL AX, 3 + Mov [CS:MouseEventData+0], AX + Add AX, 3*8-1 + Mov [CS:MouseEventData+4], AX + Xor AX, AX + Mov AL, [SI+3] + ShL AX, 3 + Mov [CS:MouseEventData+2], AX + Add AX, 7 + Mov [CS:MouseEventData+6], AX + + Push CS + Pop DS + + Mov SI, Offset MouseEventData + Mov Word Ptr [SI+8], 102h + Mov Word Ptr [SI+12], Offset MouseNumberDecrement + Call MouseAddEvent + Mov Word Ptr [SI+8], 110h + Mov Word Ptr [SI+12], Offset MouseNumberIncrement + Call MouseAddEvent + + Ret + +EndP F_Draw3Num + +; + +Proc F_Pre3Num Far + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Mov DI, AX + Add DI, CS:TripleNumberPos + Add DI, DI + + Mov CX, 1 + Mov AL, 30h + Call S_HiLight + + Ret + +EndP F_Pre3Num + +; + +Proc F_Post3Num Far + + Mov SI, [BX] + Test CL, CL + JZ F_Post3Num7 + + Cmp DX, 8 + JE F_Post3Num16 + Cmp CX, 1CBh ; Left + JNE F_Post3Num1 + +F_Post3Num16: + Mov AX, CS:TripleNumberPos + Dec AX + JS F_Post3Num2 + +F_Post3Num5: + Mov CS:TripleNumberPos, AX + +F_Post3Num2: + Mov AX, 1 + Ret + +F_Post3Num1: + Cmp CX, 1CDh ; Right + JNE F_Post3Num3 + +F_Post3Num4: + Mov AX, CS:TripleNumberPos + Inc AX + Cmp AX, 2 + JA F_Post3Num2 + Jmp F_Post3Num5 + +F_Post3Num3: + Cmp CX, 1C8h ; Up + JE F_Post3Num14 + Cmp CX, 1D0h ; Down + JE F_Post3Num13 + Cmp CX, 10Fh + JE F_Post3Num12 + Cmp DX, 0F00h + JNE F_Post3Num6 + + LodsW +F_Post3Num12: + LodsW +F_Post3Num13: + LodsW +F_Post3Num14: + Add SI, 12 + LodsW + Cmp AX, 0FFFFh + JE F_Post3Num7 + + Mov [DI], AX + +F_Post3Num15: + Mov AX, 1 + Ret + +F_Post3Num18: + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Push BX + Call [CS:Get3NumValues+BX] ; AX = value. + Pop BX + Add AX, 1 + JC F_Post3Num15 + Call [CS:Set3NumValues+BX] ; AX = value. + Call Near Ptr F_Post3Num20 + Jmp F_Post3Num15 + +F_Post3Num19: + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Push BX + Call [CS:Get3NumValues+BX] ; AX = value. + Pop BX + Sub AX, 1 + JC F_Post3Num15 + Call [CS:Set3NumValues+BX] ; AX = value. + Call Near Ptr F_Post3Num20 + Jmp F_Post3Num15 + +F_Post3Num6: + Cmp DX, '+' + JE F_Post3Num18 + Cmp DX, '-' + JE F_Post3Num19 + + Cmp DX, '0' + JL F_Post3Num7 + Cmp DX, '9' + JLE F_Post3Num8 + +F_Post3Num7: + Xor AX, AX + Ret + +F_Post3Num8: ; OK... a number was inputted. + Push DX + + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Call [CS:Get3NumValues+BX] ; AX = value. + + Mov CX, 3 + Mov BX, 10 + Mov DI, Offset NumberStorage+6 + +F_Post3Num9: + Xor DX, DX + Div BX + Sub DI, 2 + Mov [CS:DI], DX + Loop F_Post3Num9 + + Mov BX, CS:TripleNumberPos + Add BX, BX + + Pop DX + Sub DX, '0' + Mov [CS:DI+BX], DX + + Xor AX, AX + Mov BX, 10 + Mov CX, 3 + Xor DX, DX + +F_Post3Num10: + Mul BX + Add AX, [CS:DI] + AdC DX, 0 + ScasW +; Add DI, 2 + Loop F_Post3Num10 + + And DX, DX + JZ F_Post3Num11 + + Mov AX, 0FFFFh + +F_Post3Num11: + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Call [CS:Set3NumValues+BX] ; AX = value. + Call Near Ptr F_Post3Num20 + Jmp F_Post3Num4 + +F_Post3Num20: + Cmp Word Ptr [SI+8], 0 + JNZ F_Post3Num17 + + Cmp Word Ptr [SI+10], 0 + JZ F_Post3Num21 + +F_Post3Num17: + Call DWord Ptr [SI+8] + +F_Post3Num21: + RetN + + +EndP F_Post3Num + +; + +Proc F_ConvEAX2Num Far + + Push EAX ; CH = colour + Push EBX ; DX:AX = number + Push CX + Push EDX + + Mov EBX, 10 + Mov CL, 7 + +F_ConvEAX2Num1: + Xor EDX, EDX + Div EBX + Push DX + Dec CL + JNZ F_ConvEAX2Num1 + + Mov CL, 7 + +F_ConvEAX2Num2: + Pop AX + Add AL, '0' + Mov AH, CH + StosW + + Dec CL + JNZ F_ConvEAX2Num2 + + Pop EDX + Pop CX + Pop EBX + Pop EAX + + Ret + +EndP F_ConvEAX2Num + +; + +Proc F_Draw5Num Far + + Mov [CS:MouseEventData+10], AX + + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Call [CS:Get5NumValues+BX] ; AX = value. + + Push AX + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX + Call S_GetDestination + + Pop AX + Xor DX, DX + Mov CH, 2 + Call F_ConvEAX2Num + + Xor AX, AX + Mov AL, [SI+2] ; X value + ShL AX, 3 + Mov [CS:MouseEventData+0], AX + Add AX, 7*8-1 + Mov [CS:MouseEventData+4], AX + Xor AX, AX + Mov AL, [SI+3] + ShL AX, 3 + Mov [CS:MouseEventData+2], AX + Add AX, 7 + Mov [CS:MouseEventData+6], AX + + Push CS + Pop DS + + Mov SI, Offset MouseEventData + Mov Word Ptr [SI+8], 102h + Mov Word Ptr [SI+12], Offset MouseNumberDecrement + Call MouseAddEvent + Mov Word Ptr [SI+8], 110h + Mov Word Ptr [SI+12], Offset MouseNumberIncrement + Call MouseAddEvent + + Ret + +EndP F_Draw5Num + +; + +Proc F_Pre5Num Far + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Mov DI, AX + Add DI, CS:NumberPos + Add DI, DI + + Mov CX, 1 + Mov AL, 30h + Call S_HiLight + + Ret + +EndP F_Pre5Num + +; + +Proc F_Post5Num Far + + Mov SI, [BX] + Test CL, CL + JZ F_Post5Num7 + + Cmp DX, 8 + JE F_Post5Num16 + Cmp CX, 1CBh ; Left + JNE F_Post5Num1 + +F_Post5Num16: + Mov AX, CS:NumberPos + Dec AX + JS F_Post5Num2 + +F_Post5Num5: + Mov CS:NumberPos, AX + +F_Post5Num2: + Mov AX, 1 + Ret + +F_Post5Num1: + Cmp CX, 1CDh ; Right + JNE F_Post5Num3 + +F_Post5Num4: + Mov AX, CS:NumberPos + Inc AX + Cmp AX, 6 + JA F_Post5Num2 + Jmp F_Post5Num5 + +F_Post5Num3: + Cmp CX, 1C8h ; Up + JE F_Post5Num14 + Cmp CX, 1D0h ; Down + JE F_Post5Num13 + Cmp CX, 10Fh + JE F_Post5Num12 + Cmp DX, 0F00h + JNE F_Post5Num6 + + LodsW +F_Post5Num12: + LodsW +F_Post5Num13: + LodsW +F_Post5Num14: + Add SI, 12 + LodsW + Cmp AX, 0FFFFh + JE F_Post5Num7 + + Mov [DI], AX + +F_Post5Num15: + Mov AX, 1 + Ret + +F_Post5Num18: + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Push BX + Call [CS:Get5NumValues+BX] ; AX = value. + Pop BX + Inc EAX + Call [CS:Set5NumValues+BX] ; AX = value. + Call Near Ptr F_Post5Num20 + Jmp F_Post5Num15 + +F_Post5Num19: + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Push BX + Call [CS:Get5NumValues+BX] ; AX = value. + Pop BX + Sub EAX, 1 + JC F_Post5Num15 + Call [CS:Set5NumValues+BX] ; AX = value. + Call Near Ptr F_Post5Num20 + Jmp F_Post5Num15 + +F_Post5Num6: + Cmp DX, '+' + JE F_Post5Num18 + Cmp DX, '-' + JE F_Post5Num19 + + Cmp DX, '0' + JL F_Post5Num7 + Cmp DX, '9' + JLE F_Post5Num8 + +F_Post5Num7: + Xor AX, AX + Ret + +F_Post5Num8: ; OK... a number was inputted. + Push DX + + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Call [CS:Get5NumValues+BX] ; EAX = value. + + Mov CX, 7 + Mov EBX, 10 + Mov DI, Offset NumberStorage+14 + +F_Post5Num9: + Xor EDX, EDX + Div EBX + Sub DI, 2 + Mov [CS:DI], DX + Loop F_Post5Num9 + + Mov BX, CS:NumberPos + Add BX, BX + + Pop DX + Sub DX, '0' + Mov [CS:DI+BX], DX + + Xor EAX, EAX + Mov BX, 10 + Mov CX, 7 + +F_Post5Num10: + IMul EAX, 10 + MovZX EBX, Word Ptr [CS:DI] + Add EAX, EBX + +; Add DI, 2 + ScasW + Loop F_Post5Num10 + +F_Post5Num11: + Mov BX, [SI+4] + Add BX, BX + Mov DI, [SI+6] + + Call [CS:Set5NumValues+BX] ; AX = value. + Call Near Ptr F_Post5Num20 + Jmp F_Post5Num4 + +F_Post5Num20: + Cmp Word Ptr [SI+8], 0 + JNZ F_Post5Num17 + + Cmp Word Ptr [SI+10], 0 + JZ F_Post5Num21 + +F_Post5Num17: + Call DWord Ptr [SI+8] + +F_Post5Num21: + RetN + +EndP F_Post5Num + +; + +Proc F_DrawHeader Far + +; Call MouseClearEvents + + Call Music_GetSongSegment + Mov DS, AX + Mov DL, [DS:2Ch] + + Push CS + Pop DS + + Call E_GetFreeEMS + Push AX + + Mov AH, 48h + Mov BX, 0FFFFh + Int 21h + ShR BX, 6 + Push BX + + Mov AH, 20h + Mov SI, Offset HeaderMsg1 + Mov DI, ((1*80)+2)*2 + Call S_DrawString + + Mov SI, Offset HeaderMsg2 + Call Glbl_GetHeaderMode + And AH, AH + JNZ F_DrawHeader1 + + Mov SI, Offset HeaderMsg3 + +F_DrawHeader1: + Mov AH, 20h + Call S_DrawString + + Mov SI, Offset HeaderMsg4 + Mov DI, ((4*80)+2)*2 + Call S_DrawString + + Add SP, 4 + + Call Music_GetFreeSoundCardMemory + ; Returns DS:SI, Carry set if nothing to show + JC F_DrawHeader2 ; and AX = value to print. + + Push BX + Push AX + + Mov AH, 20h + Mov DI, (63+8*80)*2 + Call S_DrawString + + Pop AX + Pop BX + +F_DrawHeader2: + Ret + +EndP F_DrawHeader + +; + +Proc F_DrawSMCChannels Far + +; Call MouseClearEvents + + Push CS + Pop DS + + Xor CX, CX + +F_DrawSMCChannels1: + Mov AL, CL + Inc AX + Xor AH, AH + Mov BH, 10 + Div BH + Add AX, 3030h + Mov Word Ptr ChannelNumbers, AX + + Mov BX, CX + And BX, 0Fh + Mov AX, 160 ; Calculate DI (offset on screen) + Mul BX + Mov DI, AX + Add DI, (22*80+9)*2 + Mov BX, CX + And BX, 00F0h + ShL BX, 1 + Add DI, BX + + Mov SI, Offset ChannelMsg + Mov AH, 20h + Call S_DrawString + + Inc CX + Cmp CX, 64 + JB F_DrawSMCChannels1 + + Ret + +EndP F_DrawSMCChannels + +; + +Proc F_ConfigButtonSetup Far + + Call Music_GetSongSegment + Mov DS, AX ; OK... now check for + ; control mode first. + Mov CL, [DS:2Ch] ; CL = Flags. + Add DI, 50 ; ES:DI points to inst button + + Mov BX, [ES:DI] ; ES:BX points to inst button data +; Add DI, 2 + ScasW + Xor CH, CH + Test CL, 4 + JZ F_ConfigButtonSetup1 + + Inc CH + +F_ConfigButtonSetup1: + Mov [ES:BX+33], CH ; Instrument button + + Xor CH, 1 + Mov BX, [ES:DI] +; Add DI, 2 + ScasW + Mov [ES:BX+33], CH ; Sample button + + Mov BX, [ES:DI] +; Add DI, 2 + ScasW + Xor CH, CH + Test CL, 1 + JZ F_ConfigButtonSetup2 + + Inc CH + +F_ConfigButtonSetup2: + Mov [ES:BX+33], CH ; Stereo button + + Xor CH, 1 + Mov BX, [ES:DI] +; Add DI, 2 + ScasW + Mov [ES:BX+33], CH ; Mono button + + Mov BX, [ES:DI] +; Add DI, 2 + ScasW + Xor CH, CH + Test CL, 8 ; Slides... + JZ F_ConfigButtonSetup3 + + Inc CH + +F_ConfigButtonSetup3: + Mov [ES:BX+33], CH + + Xor CH, 1 + Mov BX, [ES:DI] +; Add DI, 2 ; Compression reasons + ScasW + Mov [ES:BX+33], CH + + Ret + +EndP F_ConfigButtonSetup + +; + +IF NETWORKENABLED +Proc F_SendSongFlags + + Push CX + Push DX + + Mov CX, 1 + Mov DX, 2Ch + Call Network_SendSongDataInformation + + Pop DX + Pop CX + + Ret + +EndP F_SendSongFlags + +SendSongFlags EQU Call F_SendSongFlags + +ELSE + +SendSongFlags EQU ; + +ENDIF + +; + +Proc F_SetControlSample Far + + Call Music_GetSongSegment + Mov DS, AX + + And Byte Ptr [DS:2Ch], NOT 4 + + SendSongFlags + + Ret + +EndP F_SetControlSample + +; + +Proc F_SetControlInstrument Far + + Call Music_GetSongSegment + Mov DS, AX + + Or Byte Ptr [DS:2Ch], 4 + + Push DS + + Mov DI, Offset O1_InitialiseInstrumentList + Mov CX, 3 + Call M_Object1List + ; DX = 0 -> don't initialise + ; DX = 1 -> initialise + Pop DS ; DS = SongDataSegment + + SendSongFlags + + Test DX, DX + JZ F_SetControlInstrument3 + + Call Music_ClearAllInstruments + + ; OK.. for samples 1..99 + ; check if sample exists. + ; if so, copy name&set all + ; notes of instrument. + Push DS + Pop ES ; ES = SongDataSegment + + Xor DX, DX + +F_SetControlInstrument1: + Mov BX, DX + Add BX, BX + Mov SI, [DS:BX+64912] ; SI points to sample + Mov DI, [DS:BX+64712] ; DI points to instrument + + Test Byte Ptr [DS:SI+12h], 1 + JZ F_SetControlInstrument2 + ; No sample there! + + ; Copy name + Mov CX, 26 + Add SI, 14h + Add DI, 20h + Rep MovsB + Add DI, 7 + + Mov AL, DL ; DL = sample number + Inc AX + Mov CX, 120 + +F_SetControlInstrument4: + StosB + Inc DI + Loop F_SetControlInstrument4 + +F_SetControlInstrument2: +IF NETWORKENABLED + Call Network_GetSendQueue + JZ F_SetControlInstrument5 + + Mov AX, 400h + StosW + Mov AX, DX + StosB + +F_SetControlInstrument5: + Call Network_FinishedSendQueue +ENDIF + Inc DX + Cmp DX, 99 + JBE F_SetControlInstrument1 + +F_SetControlInstrument3: + + Ret + +EndP F_SetControlInstrument + +; + +Proc F_SetStereo Far + + Call Music_GetSongSegment + Mov DS, AX + + Or Byte Ptr [DS:2Ch], 1 + + Call Music_InitStereo + + SendSongFlags + + Ret + +EndP F_SetStereo + +; + +Proc F_SetMono Far + + Call Music_GetSongSegment + Mov DS, AX + + And Byte Ptr [DS:2Ch], NOT 1 + + Call Music_InitStereo + + SendSongFlags + + Ret + +EndP F_SetMono + +; + +Proc F_SetLinear Far + + Call Music_GetSongSegment + Mov DS, AX + + Or Byte Ptr [DS:2Ch], 8 + + SendSongFlags + + Ret + +EndP F_SetLinear + +; + +Proc F_SetAmiga Far + + Call Music_GetSongSegment + Mov DS, AX + + And Byte Ptr [DS:2Ch], NOT 8 + + SendSongFlags + + Ret + +EndP F_SetAmiga + +; + +Proc F_Reset5NumInputPos Far + + Mov CS:NumberPos, 0 + Ret + +EndP F_Reset5NumInputPos + +; + +Proc F_NewSong Far + + EnsureNoNetwork + + Mov DI, Offset O1_NewSongList + Mov CX, 11 ; OK Button.. + Call M_Object1List + And DX, DX + JZ F_NewSongEnd + + Call Music_Stop + + Cmp Word Ptr [CS:ButtonVariables+8], 0 + JE F_NewSong2 + + Call Music_ReleaseAllSamples + Call Music_ClearAllSampleNames + +F_NewSong2: + Cmp Word Ptr [CS:ButtonVariables+10], 0 + JE F_NewSong3 + + Call Music_ClearAllInstruments + +F_NewSong3: + Cmp Word Ptr [CS:ButtonVariables+12], 0 + JE F_NewSong1 + + Call D_ClearFileName + Call D_ResetTimer + + Call Music_GetSongSegment + Mov ES, AX + + Mov DI, 4 ; Clear song name + Mov CX, 13 + Xor AX, AX + Rep StosW + + Mov DI, 3Ch ; Clear Time + Xor AX, AX + StosW + StosW + + Mov CX, 64 + Mov AL, 32 + Rep StosB + + Mov CX, 64 ; Channel volume + Mov AL, 64 + Rep StosB + + Mov DI, 100h ; Orders. + Mov AL, 0FFh + Mov CX, 256 + Rep StosB + + Call Music_InitMuteTable + Call Msg_ResetMessage + +F_NewSong1: + Cmp Word Ptr [CS:ButtonVariables+6], 0 + JE F_NewSongEnd + ; Clear patterns. + Call D_ClearFileName + Call D_ResetTimer + Call Music_ReleaseAllPatterns + Call PE_ResetOrderPattern + +F_NewSongEnd: + Mov AX, 1 + Ret + +EndP F_NewSong + +; + +Proc F_MainMenu Far + + Call S_SaveScreen + + Mov CX, 0FFFFh + Mov DI, Offset O1_MainMenu + Call M_Object1List + + Call S_RestoreScreen + + Mov AX, 1 + Ret + +EndP F_MainMenu + +; + +Proc F_ViewPattern Far + + Call MouseRestoreEvents + Add SP, 20 + Jmp Glbl_F2_2 + +EndP F_ViewPattern + +; + +Proc F_ViewVariables Far + + Call MouseRestoreEvents + Add SP, 20 + Jmp Glbl_F12 + +EndP F_ViewVariables + +; + +Proc F_ViewOrderPan Far + + Call MouseRestoreEvents + Add SP, 20 + Jmp Glbl_F11_2 + +EndP F_ViewOrderPan + +; + +Proc F_MessageEditor Far + + Call MouseRestoreEvents + Add SP, 20 + Jmp Glbl_Shift_F9 + +EndP F_MessageEditor + +; + +Proc F_Help Far + + Call S_RestoreScreen + Call MouseRestoreEvents + Add SP, 20 + Jmp H_Help + +EndP F_Help + +; + +Proc F_PlaybackMenu Far + + Mov CX, 0FFFFh + Mov DI, Offset O1_PlaybackMenu + Call M_Object1List + + Call S_RestoreScreen + Mov AX, 1 + Ret + +EndP F_PlaybackMenu + +; + +Proc F_InfoPage Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + + Add SP, 48 + Jmp Glbl_F5 + +EndP F_InfoPage + +; + +Proc F_PlaySong Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_Ctrl_F5 + +EndP F_PlaySong + +; + +Proc F_PlayPattern Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_F6 + +EndP F_PlayPattern + +; + +Proc F_PlayOrder Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_Shift_F6 + +EndP F_PlayOrder + +; + +Proc F_PlayMark Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp PE_F7 + +EndP F_PlayMark + +; + +Proc F_Stop Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Music_Stop + +EndP F_Stop + +; + +Proc F_ReinitSoundCard Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Music_ReinitSoundCard + +EndP F_ReinitSoundCard + +; + +Proc F_CalculateLength Far + + Call S_RestoreScreen + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Music_TimeSong + +EndP F_CalculateLEngth + +; + +Proc F_DriverScreen Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_DriverScreen + +EndP F_DriverScreen + +; + +Proc F_SampleMenu Far + + Mov CX, 0FFFFh + Mov DI, Offset O1_SampleMenu + Call M_Object1List + + Call S_RestoreScreen + Mov AX, 1 + Ret + +EndP F_SampleMenu + +; + +Proc F_InstrumentMenu Far + + Mov CX, 0FFFFh + Mov DI, Offset O1_InstrumentMenu + Call M_Object1List + + Call S_RestoreScreen + Mov AX, 1 + Ret + +EndP F_InstrumentMenu + +; + +Proc F_SampleList Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_F3 + +EndP F_SampleList + +; + +Proc F_InstrumentList Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_F4 + +EndP F_InstrumentList + +; + +Proc F_InstrumentLibrary Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_Ctrl_F4 + +EndP F_InstrumentLibrary + +; + +Proc F_ReloadGravis Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Music_SoundCardLoadAllSamples + +EndP F_ReloadGravis + +; + +Proc F_SampleLibrary Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_Ctrl_F3 + +EndP F_SampleLibrary + +; + +Proc F_FileMenu Far + + Mov CX, 0FFFFh + Mov DI, Offset O1_FileMenu + Call M_Object1List + + Call S_RestoreScreen + Mov AX, 1 + Ret + +EndP F_FileMenu + +; + +Proc F_FileLoad Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_F9 + +EndP F_FileLoad + + +; + +Proc F_FileNew Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Call S_RestoreScreen + Add SP, 48 + Jmp F_NewSong + +EndP F_FileNew + +; + +Proc F_FileSaveCurrent Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Call S_RestoreScreen + Add SP, 48 + Jmp D_SaveSong + +EndP F_FileSaveCurrent + +; + +Proc F_FileSaveAs Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Add SP, 48 + Jmp Glbl_F10 + +EndP F_FileSaveAs + +; + +Proc F_FileDOSShell Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Call S_RestoreScreen + Add SP, 48 + Jmp DOSShell + +EndP F_FileDOSShell + +; + +Proc F_FileQuit Far + + Call MouseRestoreEvents + Call MouseRestoreEvents + Call S_RestoreScreen + Add SP, 48 + Jmp Quit + +EndP F_FileQuit + +; + +IF MEMORYDEBUG + +DebugOffset DW 0 +DebugSegment DW 0 + +AddressInput DB 0 + DB 19 Dup (0) +SegmentMsg DB "Segment: ", 0FDh, 'Xh', 0 + +DebugSegmentNames DB 10, "STARTUP", 0 + DW Startup + + DB 11, "KEYBOARD", 0 + DW Keyboard + + DB 10, "PATTERN", 0 + DW Pattern + + DB 7, "DISK", 0 + DW Disk + + DB 6, "EMS", 0 + DW EMS + + DB 8, "ERROR", 0 + DW Error + + DB 7, "INST", 0 + DW Inst + + DB 12, "FUNCTIONS", 0 + DW Functions + + DB 9, "GLOBAL", 0 + DW Glbl + + DB 7, "HELP", 0 + DW Help + + DB 11, "INFOLINE", 0 + DW InfoLine + + DB 7, "MAIN", 0 + DW Main + + DB 8, "MUSIC", 0 + DW Music + + DB 9, "SCREEN", 0 + DW Screen + + DB 10, "OBJECT1", 0 + DW Object1 + + DB 11, "INFOPAGE", 0 + DW InfoPage + + DB 11, "SONGDATA", 0 +DebugSongDataSegment DW 0 + + DB 11, "DISKDATA", 0 +DebugDiskDataSegment DW 0 + + DB 14, "PATTERNDATA", 0 +DebugPatternDataSegment DW 0 + + DB 0FFh ; End of list. + +DebugMsg DB "CX: ", 0FDh, "X, DX: ", 0FDh, "X ", 0 +DebugCX DW 0 +DebugDX DW 0 + +; + +Proc F_DrawDebug Far + + Push CS + Pop DS + Assume DS:Functions + + Call S_GetDestination + Mov SI, Offset SegmentMsg + Mov DI, (4+13*80)*2 + + Push DebugSegment +; Mov AX, DebugSegment +; Push AX + Mov AH, 21h + Call S_DrawString ; OK segment done + Pop AX ; Clear stack. + + ; Put offsets on screen. + ; Work out digits. + Mov CX, 1E04h + Mov DI, (3+15*80)*2 + Mov DX, DebugOffset + Xor BH, BH + Mov AH, 2 + +F_DrawDebug1: + Push DI + + Mov BL, DH + ShR BL, CL + Mov AL, [HexNumbers+BX] ; Blah.. how inefficient + StosW + Mov BL, DH + And BL, 0Fh + Mov AL, [HexNumbers+BX] + StosW + Mov BL, DL + ShR BL, CL + Mov AL, [HexNumbers+BX] + StosW + Mov BL, DL + And BL, 0Fh + Mov AL, [HexNumbers+BX] + StosW ; Offset is on screen. + + Mov AL, ':' + StosW + + Pop DI + Add DI, 160 + Add DX, 16 + Dec CH + JNZ F_DrawDebug1 + + ; Now to shove debug stuff. + Mov SI, DebugOffset + Mov DS, DebugSegment + Assume DS:Nothing + Mov DI, (10+15*80)*2 + + Mov DX, 30 + +F_DrawDebug2: + Push DI + Push SI + + Mov CX, 1004h + +F_DrawDebug3: + Cmp CH, 8 + JNE F_DrawDebug4 + + Mov AL, '-' + StosW + Xor AL, AL + StosW + +F_DrawDebug4: + LodsB ; Number. + Mov BL, AL + ShR BL, CL + Mov BL, [CS:HexNumbers+BX] + XChg AL, BL + And BL, 0Fh + StosW + Mov AL, [CS:HexNumbers+BX] + StosW + + Xor AL, AL + StosW + + Dec CH ; Hex number loop + JNZ F_DrawDebug3 + + StosW + + Pop SI + Mov CX, 16 + +F_DrawDebug5: + LodsB + StosW + Loop F_DrawDebug5 + + Pop DI + Add DI, 160 ; Next line. + + Dec DX ; line loop. + JNZ F_DrawDebug2 + + Push CS + Pop DS + + Push DebugDX + Push DebugCX + + Mov SI, Offset DebugMsg + Mov AH, 20h + Mov DI, (40+47*80)*2 + Call S_DrawString + Pop AX + Pop AX + + Mov AX, 1 + Ret + +EndP F_DrawDebug + Assume DS:Nothing + +; + +Proc F_PostDebug Far + + Mov CS:DebugCX, CX + Mov CS:DebugDX, DX + + Xor AX, AX + Ret + +EndP F_PostDebug + +; + +Proc F_DebugUp Far + + Sub CS:DebugOffset, 16 + + Mov AX, 1 + Ret + +EndP F_DebugUp + +; + +Proc F_DebugDown Far + + Add CS:DebugOffset, 16 + + Mov AX, 1 + Ret + +EndP F_DebugDown + +; + +Proc F_DebugPgUp Far + + Sub CS:DebugOffset, 16*30 + + Mov AX, 1 + Ret + +EndP F_DebugPgUp + +; + +Proc F_DebugPgDn Far + + Add CS:DebugOffset, 16*30 + + Mov AX, 1 + Ret + +EndP F_DebugPgDn + +; + +Proc F_DebugStringInput Far + + Mov AX, Disk + Mov DS, AX + Assume DS:Disk + Mov DX, DiskDataArea + + Xor BP, BP ; BP = ':' count. + + Mov AX, Music + Mov DS, AX + Assume DS:Music + Mov BX, SongDataArea + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + Mov SI, PatternDataArea + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:Functions ; ES = functions also. + + Mov DebugSongDataSegment, BX + Mov DebugDiskDataSegment, DX + Mov DebugPatternDataSegment, SI + + Mov SI, Offset DebugSegmentNames + Xor BX, BX + +F_DebugStringInput1: + Mov DI, Offset AddressInput + LodsB + Cmp AL, 0FFh + JE F_DebugStringInput2 + + Mov BL, AL + Push SI + ; OK.. compare in here.. +F_DebugStringInput4: + LodsB + Mov AH, [DI] + + And AL, AL + JZ F_DebugStringInput3 + + And AH, AH + JZ F_DebugStringInput6 + + Cmp AH, 'a' + JB F_DebugStringInput6 + Cmp AH, 'z' + JA F_DebugStringInput6 + + Add AH, 'A'-'a' + +F_DebugStringInput6: + Inc DI + Cmp AH, AL + JE F_DebugStringInput4 + + +F_DebugStringInput5: + Pop SI + Add SI, BX + Jmp F_DebugStringInput1 + + +F_DebugStringInput3: + And AH, AH + JNZ F_DebugStringInput6 + + LodsW + Pop SI + Mov DebugSegment, AX + Mov DebugOffset, 0 + + Mov AX, 1 + Ret + +F_DebugStringInput2: ; We have a hex address(?) + Mov SI, Offset AddressInput + Cmp Byte Ptr [SI], 0 + JE F_DebugStringInput15 + +F_DebugStringInput7: + LodsB + And AL, AL + JZ F_DebugStringInput10 + + Cmp AL, '0' + JB F_DebugStringInput8 + Cmp AL, '9' + JBE F_DebugStringInput7 + +F_DebugStringInput8: + Cmp AL, 'A' + JB F_DebugStringInput9 + Cmp AL, 'F' + JBE F_DebugStringInput7 + + +F_DebugStringInput9: + Cmp AL, 'a' + JB F_DebugStringInput16 + Cmp AL, 'f' + JBE F_DebugStringInput7 + +F_DebugStringInput16: + Cmp AL, ':' + JE F_DebugStringInput7 + +F_DebugStringInput15: + Xor AX, AX + Ret + +F_DebugStringInput10: ; Hex address + Mov BX, DebugSegment + Mov CL, 4 + Xor DX, DX ; BX:DX contains address + + Xor AX, AX + Mov SI, Offset AddressInput + +F_DebugStringInput11: + LodsB + And AL, AL + JZ F_DebugStringInput12 + + Cmp AL, ':' + JE F_DebugStringInput13 + + Sub AL, '0' + Cmp AL, 9 + JBE F_DebugStringInput14 + + Sub AL, '@'-'9' + Cmp AL, 15 + JBE F_DebugStringInput14 + + Sub AL, 32 + +F_DebugStringInput14: + ShL DX, CL + Add DX, AX + + Jmp F_DebugStringInput11 + +F_DebugStringInput13: + Inc BP + Cmp BP, 2 + JAE F_DebugStringInput17 + + Mov BX, DX + Xor DX, DX + Jmp F_DebugStringInput11 + +F_DebugStringInput17: + Mov DebugSegment, BX + Mov DebugOffset, DX + Xor DX, DX + Jmp F_DebugStringInput11 + +F_DebugStringInput12: + Cmp BP, 2 + JB F_DebugStringInput18 + + LDS SI, DWord Ptr [DebugOffset] + Mov [SI], DL + Jmp F_DebugStringInput19 + +F_DebugStringInput18: + Mov DebugSegment, BX + Mov DebugOffset, DX + +F_DebugStringInput19: + Mov AX, 1 + Ret + +EndP F_DebugStringInput + +ENDIF + +; + +Proc F_ShowMIDIZxxInput Far + + Push CS + Pop DS + Assume DS:Functions + + Mov SI, Offset ZxxString + Mov AX, TopMIDIMacro + Add AX, 6 + Mov CX, 7 + +F_ShowMIDIZxxInput1: + Push AX + Dec AX + Loop F_ShowMIDIZxxInput1 + + Mov CX, 7 + Mov DI, (13+42*80)*2 + +F_ShowMIDIZxxInput2: + Mov AH, 20h + Call S_DrawString + Pop AX + Add DI, (80-3)*2 + Loop F_ShowMIDIZxxInput2 + + Ret + +EndP F_ShowMIDIZxxInput + Assume DS:Nothing + +; + +Proc F_MIDI_Up Far + + Cmp CS:TopMIDIMacro, 80h + JBE F_MIDI_Up1 + + Dec CS:TOPMIDIMacro + Jmp F_MIDI_Up2 + +F_MIDI_Up1: + Mov Word Ptr [ES:DI], 33 + +F_MIDI_Up2: + Mov AX, 1 + Ret + +EndP F_MIDI_Up + +; + +Proc F_MIDI_Down Far + + Cmp CS:TopMIDIMacro, 0F9h + JAE F_MIDI_Down1 + + Inc CS:TOPMIDIMacro + +F_MIDI_Down1: + Mov AX, 1 + Ret + +EndP F_MIDI_Down + +; + +Proc F_MIDI_PgUp Far + + Cmp Word Ptr [ES:DI], 33 + JBE F_MIDI_PgUp1 + + Sub Byte Ptr [CS:TopMIDIMacro], 7 + JS F_MIDI_PgUp1 + + Mov Byte Ptr [CS:TopMIDIMacro], 80h + +F_MIDI_PgUp1: + Mov AX, 1 + Ret + +EndP F_MIDI_PgUp + +; + +Proc F_MIDI_PgDn Far + + Cmp Word Ptr [ES:DI], 33 + JBE F_MIDI_PgDn1 + + Add [CS:TopMIDIMacro], 7 + Cmp [CS:TopMIDIMacro], 0F9h + JB F_MIDI_PgDn1 + + Mov [CS:TopMIDIMacro], 0F9h + +F_MIDI_PgDn1: + Mov AX, 1 + Ret + +EndP F_MIDI_PgDn + +; + +EndS + +; + +End diff --git a/it/IT_FOUR.ASM b/it/IT_FOUR.ASM new file mode 100644 index 0000000..8f9058a --- /dev/null +++ b/it/IT_FOUR.ASM @@ -0,0 +1,612 @@ +;Ŀ +; Fast Fourier Transform Module +; + + Jumps + .386P + .387 + +include switch.inc + +IF SPECTRUMANALYSER + +;Ŀ +; Externals +; + +Segment Object1 BYTE Public 'Data' +EndS +Segment DiskData PARA Public 'Data' +EndS + + Extrn O1_FourierDisplay:Far + + Extrn M_Object1List:Far + + Extrn Music_GetWaveForm:Far + + Extrn S_InitScreen:Far + Extrn S_SetDirectMode:Far + + Global MouseUpdateEnable:Far, MouseUpdateDisable:Far + Extrn VESA_Detect:Far + Extrn VESA_SetMode:Far + Extrn VESA_SetBlock:Far + Extrn InitMouse:Far, UnInitMouse:Far + Extrn S_DefineSmallNumbers:Far + +; + + +Segment Infopage BYTE Public 'Code' USE16 + Assume CS:Infopage, DS:Nothing, ES:Nothing + +;Ŀ +; Variables +; + +;Ŀ +; Functions +; + +; + +Proc Fourier_CreateTable Far ; Fills in ES:16384 +Public Fourier_CreateTable + + Mov DI, 20480 + Xor CX, CX + +Fourier_CreateTable1: + Mov DX, 11 + + Xor AX, AX + Mov BX, CX + +Fourier_CreateTable2: + ShR BX, 1 + AdC AX, AX + + Dec DX + JNZ Fourier_CreateTable2 + + ShL AX, 3 + StosW + + Inc CX + Cmp CX, 2048 + JB Fourier_CreateTable1 + + Ret + +EndP Fourier_CreateTable + +; + +Const1_2048 DD 3C000000h +ConstHalf DD 3F000000h +Steps DW 0 +CurrentOffset DW 0 + +Proc Fourier_Transform Far +Public Fourier_Transform + ; Given DS:16384->DS:20480 = 2048 16-bit signed int samples + ; Given DS:20480->24576 = relocation table + ; Given DS:0->DS:16384 = working area + + ; Returns: DS:24576 -> 16-bit table of frequencies. (first 1024) + + Push DiskData + Pop DS + + Push DS + Pop ES + + Mov CX, 2048 ; Prepare 2048 samples + Mov SI, 16384 + Xor EDX, EDX + +Fourier_TransformRelocate1: + FILd Word Ptr [SI] + Mov DI, [SI+4096] + LodsW ; Add SI, 2 + Mov [DI+4], EDX + FStP DWord Ptr [DI] + Dec CX + JNZ Fourier_TransformRelocate1 + +; Samples relocated - now for transform + Mov CX, 1 + +Fourier_Transform1: + Mov [DS:24576], CX ; Store count + + FLdZ + FLd1 ; CurrentPhase.r, CurrentPhase.i + + FLdPi + FChs + FIDiv Word Ptr [DS:24576] ; -Pi/Step + FSinCos ; deltaphase.r, deltaphase.i, currentphase.r, currentphase.i + + Xor DX, DX + +Fourier_Transform2: + Mov SI, DX ; SI = k + Mov DI, CX ; DI = k+i + Mov BX, CX ; BX = i*2 + Add DI, DX + ShL SI, 3 ; SI = k*8 + ShL DI, 3 ; DI = (k+i)*8 + ShL BX, 4 ; BX = i*8*2 + +Fourier_Transform3: + FLd DWord Ptr [DI] + FMul ST, ST(3) ; cr*sr + FLd DWord Ptr [DI+4] + FMul ST, ST(4) ; cr*si, cr*sr, dr, di, cr, ci + FLd DWord Ptr [DI] + FMul ST, ST(6) + FLd DWord Ptr [DI+4] + FMul ST, ST(7) ; ci*si, ci*sr, cr*si, cr*sr, dr, di, cr, ci + FXCh + FAddP ST(2), ST + FSubP ST(2), ST ; tempi, tempr, dr, di, cr, ci + FLd DWord Ptr [SI+4] ; ri, tempi, tempr, dr, di, cr, ci + FAdd ST, ST(1) + FLd DWord Ptr [SI] + FAdd ST, ST(3) ; rr, ri, tempi, tempr, dr, di, cr, ci + FXCh ST(3) ; tempr, ri, tempi, rr, dr, di, cr, ci + FSubR DWord Ptr [SI] ; kr, ri, tempi, rr, dr, di, cr, ci + FXCh ST(2) + FSubR DWord Ptr [SI+4] ; ki, ri, kr, rr, dr, di, cr, ci + FXCh ST(3) ; rr, ri, kr, ki, dr, di, cr, ci + FStP DWord Ptr [SI] + FStP DWord Ptr [SI+4] + FStP DWord Ptr [DI] + FStP DWord Ptr [DI+4] + + Add SI, BX + Add DI, BX + + Cmp SI, 16384 + JB Fourier_Transform3 + +; Left with deltaphase.r, deltaphase.i, currentphase.r, currentphase.i + FLd ST ; d.r, d.r, d.i, c.r, c.i + FMul ST, ST(3) ; d.r*c.r, d.r, d.i, c.r, c.i + FXCh ST(3) ; c.r, d.r, d.i, d.r*c.r, c.i + FMul ST, ST(2) ; c.r*d.i, d.r, d.i, d.r*c.r, c.i + FLd ST(2) ; d.i, c.r*d.i, d.r, d.i, d.r*c.r, c.i + FMul ST, ST(5) ; d.i*c.i, c.r*d.i, d.r, d.i, d.r*c.r, c.i + FSubP ST(4), ST ; c.r*d.i, d.r, d.i, newr, c.i + FXCh ST(4) ; c.i, d.r, d.i, newr, c.r*d.i + FMul ST, ST(1) ; c.i*d.r, d.r, d.i, newr, c.r*d.i + FAddP ST(4), ST ; d.r, d.i, newr, newi + + Inc DX + Cmp DX, CX + JB Fourier_Transform2 + + FComPP + FComPP + + ShL CX, 1 + Cmp CX, 2048 + JB Fourier_Transform1 + +; Cleanup code. + Mov CX, 1024 + Xor SI, SI + Mov DI, 24576 + + FLd CS:Const1_2048 +; FMul ST, ST ; Include if no sqrt +; FMul ST, ST + +Fourier_CalculateMagnitudes1: ; Could be interleaved, but speed isn't + ; *really* a problem. + FLd DWord Ptr [SI] + FMul ST, ST + FLd DWord Ptr [SI+4] + FMul ST, ST + FAdd + FSqrt + FMul ST, ST(1) + + FStP DWord Ptr [DI] + + Add SI, 8 + Add DI, 4 + + Dec CX + JNZ Fourier_CalculateMagnitudes1 + + FStP ST + + Ret + +EndP Fourier_Transform + +; + +FourierPalette DB 0 + +Proc Fourier_ChangePalette Far +Public Fourier_ChangePalette + + Xor [CS:FourierPalette], 1 + Call Fourier_SetPalette + + Mov AX, 1 + Ret + +EndP Fourier_ChangePalette + +; + +Proc Fourier_SetPalette + + Mov DX, 3C8h + Xor AL, AL + Out DX, AL + Inc DX + + Cmp [CS:FourierPalette], 0 + JE Fourier_PaletteB + + Mov CX, 64 + +Fourier_PaletteA1: + Xor AL, AL + Out DX, AL + Out DX, AL + Mov AL, 64 + Sub AL, CL + ShR AL, 1 + Out DX, AL + Loop Fourier_PaletteA1 + + Mov CX, 64 + +Fourier_PaletteA2: + Xor AL, AL + Out DX, AL + Mov BL, 64 + Sub BL, CL + ShR BL, 1 + Mov AL, BL + Out DX, AL + Mov AL, BL + Add AL, 32 + Out DX, AL + Loop Fourier_PaletteA2 + + Mov CX, 128 + +Fourier_PaletteA3: + Mov AL, 128 + Sub AL, CL + ShR AL, 1 + Out DX, AL + ShR AL, 1 + Add AL, 32 + Out DX, AL + Mov AL, 63 + Out DX, AL + Loop Fourier_PaletteA3 + + Ret + +Fourier_PaletteB: + Mov CX, 32 + Xor BX, BX + +Fourier_PaletteB1: + Xor AL, AL + Out DX, AL + Out DX, AL + Mov AL, BL + Out DX, AL + Add BX, 2 + Loop Fourier_PaletteB1 + + Mov CX, 32 + Xor BL, BL + +Fourier_PaletteB2: + Mov AL, BL + Out DX, AL + Xor AL, AL + Out DX, AL + Mov AL, 63 + Out DX, AL + Add BX, 2 + + Loop Fourier_PaletteB2 + + Mov CX, 32 + +Fourier_PaletteB3: + Mov AL, 63 + Out DX, AL + Xor AL, AL + Out DX, AL + Mov AL, CL + Add AL, AL + Dec AL + Out DX, AL + Loop Fourier_PaletteB3 + + Mov CX, 32 + Xor BX, BX + +Fourier_PaletteB4: + Mov AL, 63 + Out DX, AL + Mov AL, BL + Out DX, AL + Xor AL, AL + Out DX, AL + Add BX, 2 + Loop Fourier_PaletteB4 + + Mov CX, 128 + Xor BX, BX + +Fourier_PaletteB5: + Mov AL, 63 + Out DX, AL + Out DX, AL + Mov AL, BL + ShR AL, 1 + Out DX, AL + Inc BX + Loop Fourier_PaletteB5 + + Ret + +EndP Fourier_SetPalette + +; + +ScreenWidth DW 0 +ScreenHeight DW 0 + +Proc Fourier_Start Far +Public Fourier_Start + + Push DiskData + Pop ES + Xor DI, DI + Mov CX, 32768 + Xor AX, AX + Rep StosW ; Clear data area first. + + Call Fourier_CreateTable + + Mov AL, 1 ; Prevent S_Update calls. + Call S_SetDirectMode + + Call VESA_Detect + JC Fourier_End + + Mov AX, 107h + +Fourier_NextMode: + Call VESA_SetMode ; Returns CX = width, DX = height + JNC Fourier_ModeOK + + Sub AL, 2 + JC Fourier_End + Jmp Fourier_NextMode + +Fourier_ModeOK: + Mov ScreenWidth, CX + Mov ScreenHeight, DX + + Call Fourier_SetPalette + + Mov CurrentOffset, 0 + + Call UnInitMouse + Mov DI, Offset O1_FourierDisplay + Xor CX, CX + Call M_Object1List + +Fourier_End: + Call S_InitScreen + Call InitMouse + Call S_DefineSmallNumbers + + Ret + +EndP Fourier_Start + +; + +Proc Fourier_PreDrawScreen Far +Public Fourier_PreDrawScreen + + Ret + +EndP Fourier_PreDrawScreen + +; + +ControlWord DW 003Fh + +Proc Fourier_DrawScreen Far +Public Fourier_DrawScreen + + FLdCW [CS:ControlWord] + + Push DiskData + Pop ES + Mov DI, 16384 + Call Music_GetWaveForm + JC Fourier_DrawScreen1 + + Push ES + Pop DS + Call Fourier_Transform ; Have table at DS:0 + + Mov CX, 1024 + Mov SI, 24576 + +Fourier_ConvertToInteger: + FLd DWord Ptr [SI] + FIStP DWord Ptr [SI] + Mov EDX, [SI] + ShR EDX, 6 + Cmp EDX, 255 + JB Fourier_DrawScreen3 + + Mov DL, 255 + +Fourier_DrawScreen3: + Mov [SI], DL + Add SI, 4 + Loop Fourier_ConvertToInteger + + Xor AX, AX + Call VESA_SetBlock + + Push 0A000h + Pop ES + Mov DI, CurrentOffset + Mov CX, ScreenHeight + Sub CX, 64 + Mov BX, ScreenWidth + LEA SI, [24576+ECX*4] + +Fourier_DrawScreen2: + Mov DL, [SI] + Mov [ES:DI], DL + + Sub SI, 4 + Add DI, BX + JNC Fourier_DrawScreen4 + + Inc AX + Call VESA_SetBlock + +Fourier_DrawScreen4: + Dec CX + JNZ Fourier_DrawScreen2 + + Mov AX, CurrentOffset + Inc AX + Xor DX, DX + Div BX + Mov CurrentOffset, DX + +; Now to draw volume bars. + + Mov CX, 64 + And EBX, 0FFFFh + + Mov BP, BX + Xor EDI, EDI + Cmp BP, 1024 + JB Fourier_DrawBars2 + + Mov DI, BX + Mov BP, 1024 + Sub DI, BP + ShR DI, 1 + +Fourier_DrawBars2: + +Fourier_DrawBars1: + Push BX + Push CX + Push EDI + + Xor EAX, EAX + + Mov AX, ScreenHeight + Sub AX, CX + Mul EBX ; EAX = offset. + Add EAX, EDI + + Mov DI, AX + ShR EAX, 16 + Call VESA_SetBlock + + Mov DX, BP + Mov BL, CL + Dec BL + ShL BL, 2 ; BL = 0->256 + + Push AX + Mov SI, 24580 + +Fourier_DrawBars3: + Cmp BL, Byte Ptr [SI] + SBB AL, AL + + Mov [ES:DI], AL + + Add DI, 1 + JNC Fourier_DrawBars4 + + Pop AX + Inc AX + Call VESA_SetBlock + Push AX + +Fourier_DrawBars4: + Add SI, 4 + Dec DX + JNZ Fourier_DrawBars3 + + Pop AX + + Pop EDI + Pop CX + Pop BX + Loop Fourier_DrawBars1 + +Fourier_DrawScreen1: + Ret + +EndP Fourier_DrawScreen + +; + +Proc Fourier_IdleList Far +Public Fourier_IdleList + + Mov AX, 1 + Ret + +EndP Fourier_IdleList + +; + +Proc Fourier_PostFunction Far +Public Fourier_PostFunction + + Cmp CX, 101h + JE Fourier_PostFunction2 + +Fourier_PostFunction1: + Xor AX, AX + Ret + +Fourier_PostFunction2: + Mov AX, 4 + Ret + +EndP Fourier_PostFunction + +; + + +EndS + +ENDIF + +End + diff --git a/it/IT_G.ASM b/it/IT_G.ASM new file mode 100644 index 0000000..081b030 --- /dev/null +++ b/it/IT_G.ASM @@ -0,0 +1,1026 @@ +;Ŀ +; Global Key Handler +; + + Jumps + +include switch.inc +include network.inc + +;Ŀ +; Externals +; + +Segment Pattern BYTE Public 'Code' + Extrn LastInstrument:Byte + Extrn Order:Word + Extrn MaxRow:Word + Extrn NumberOfRows:Word + Extrn PatternNumber:Word +EndS + +Segment Inst BYTE Public 'Code' + Extrn SampleNumber:Byte + Extrn InstrumentScreen:Word +EndS + +Segment Object1 BYTE Public 'Data' +EndS + + Extrn D_InitLoadModule:Far + Extrn D_InitLoadSamples:Far + Extrn D_InitLoadInstruments:Far + Extrn Display_SelectDisplayList:Far + + Extrn M_Object1List:Far + + Extrn I_ClearTables:Far + + Extrn Music_GetInstrumentMode:Far + Extrn Music_GetPlayMode:Far + Extrn Music_PlayPattern:Far + Extrn Music_PlaySong:Far + Extrn Music_Stop:Far + Extrn Music_ToggleChannel:Far + Extrn Music_GetSlaveChannelInformationTable:Far + Extrn Music_IncreaseSpeed:Far + Extrn Music_DecreaseSpeed:Far + Extrn Music_IncreaseVolume:Far + Extrn Music_DecreaseVolume:Far + Extrn Music_GetSongSegment:Far + Extrn Music_GetDriverScreen:Far + + Extrn SetInfoLine:Far + + Extrn PE_GetCurrentPattern:Far + Extrn PE_SetPatternModified:far + + Extrn O1_InstrumentListGeneral:Far + Extrn O1_InstrumentListVolume:Far + Extrn O1_InstrumentListPanning:Far + Extrn O1_InstrumentListPitch:Far + + Extrn O1_KeyboardList:Far + Extrn O1_LoadSampleList:Far + Extrn O1_OrderPanningList:Far + Extrn O1_PatternEditList:Far + Extrn O1_PEConfigList:Far + Extrn O1_SampleList:Far + Extrn O1_LoadModuleList:Far + Extrn O1_ViewInstrumentLibrary:Far + Extrn O1_SaveModuleList:Far + Extrn O1_LoadInstrumentList:Far + Extrn O1_MessageList:Far + Extrn O1_OrderVolumeList:Far + Extrn O1_DisplayList:Far + Extrn I_DrawWaveForm:Far + Extrn S_DefineSmallNumbers:Far + Extrn S_SaveScreen:Far, S_RestoreScreen:Far + Extrn RestoreMouse:Far, RestoreMouseGraphics:Far + Extrn D_ClearFileSpecifier:Far + Extrn O1_ConfigureITList:Far + Extrn O1_ViewSampleLibrary:Far + Extrn O1_ConfigurePaletteList:Far + Extrn O1_MIDIScreen:Far + Extrn O1_TimerList:Far + Extrn I_MapEnvelope:Far + Extrn NewCharacterSet:Far + Extrn S_GetDestination:Far + Extrn S_DefineHiASCII:Far + +IF MEMORYDEBUG + Extrn O1_DebugList:Far +ENDIF + +;Ŀ +; Globals +; + + Global Glbl_Ctrl_F1:Far + Global Glbl_Ctrl_F3:Far + Global Glbl_Ctrl_F4:Far + Global Glbl_Ctrl_F5:Far + Global Glbl_Ctrl_F12:Far + Global Glbl_F2:Far + Global Glbl_F3:Far + Global Glbl_F4:Far + Global Glbl_F4_2:Far + Global Glbl_F5:Far + Global Glbl_F6:Far + Global Glbl_Shift_F1:Far + Global Glbl_Shift_F6:Far + Global Glbl_Shift_F9:Far + Global Glbl_F8:Far + Global Glbl_F9:Far + Global Glbl_F10:Far + Global Glbl_F11:Far + Global Glbl_F12:Far + Global Glbl_Alt_F1:Far + Global Glbl_Alt_F2:Far + Global Glbl_Alt_F3:Far + Global Glbl_Alt_F4:Far + Global Glbl_Alt_F5:Far + Global Glbl_Alt_F6:Far + Global Glbl_Alt_F7:Far + Global Glbl_Alt_F8:Far + Global Glbl_LeftBrace:Far + Global Glbl_RightBrace:Far + Global Glbl_LeftSquareBracket:Far + Global Glbl_RightSquareBracket:Far + Global Glbl_LoadSample:Far + Global Glbl_LoadInstrument:Far + Global Glbl_GetHeaderMode:Far + Global Glbl_SetCurrentMode:Far + Global Glbl_GetCurrentMode:Far + Global Glbl_SaveMode:Far + Global Glbl_RestoreMode:Far + +IF TIMERSCREEN + Global Glbl_TimerScreen:Far +ENDIF + + Global CurrentMode:Byte + + Public Glbl_F2_2 + Public Glbl_F11_2 + +IF MEMORYDEBUG + Global Glbl_Debug:Far +ENDIF + Global Glbl_DriverScreen:Far + + +; + +Segment Glbl BYTE Public 'Code' + Assume CS:Glbl, DS:Nothing + +;Ŀ +; Variables +; + +SLAVECHANNELSIZE EQU 128 + +CurrentMode DB 0 ; 2 = Pattern edit + ; 3 = Sample list + ; 4 = Instrument list + ; 5 = Info list + ; 6 = configure pattern edit + ; 9 = load list + ; 10 = save list + ; 11 = order/panning list + ; 12 = configure IT list + ; 13 = load sample list. + ; 14 = palette config list. + ; 15 = load instrument list + ; 16 = message list + ; 21 = order/volume list + ; 22 = debug + ; 23 = timer + ; 24 = Network screen + ; 31 = MIDI list + ; 1 = Keyboard list + ; 0 = Nothing in particular :) + ; 100 = Driver Screen + ; 200 = Full screen display + ; 201 = VGA display + +CurrentMode2 DB 0 +CurrentList DW 0 +CurrentListSegment DW 0 + +TempoSetMsg DB "Tempo set to ", 0FDh, "D beats per minute", 0 +SpeedSetMsg DB "Speed set to ", 0FDh, "D frames per row", 0 +VolumeSetMsg DB "Global Volume set to ", 0FDh, "D", 0 + +InstrumentScreenTable Label + DW Offset O1_InstrumentListGeneral + DW Offset O1_InstrumentListVolume + DW Offset O1_InstrumentListPanning + DW Offset O1_InstrumentListPitch + +;Ŀ +; Functions +; + +Proc Glbl_F2 Far + + Call Glbl_SampleToInstrument + Cmp CS:CurrentMode, 2 + + JE Glbl_F2_1 + +Glbl_F2_2: + Call S_DefineSmallNumbers + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 2 + + Mov DX, Offset O1_PatternEditList + + Ret + +Glbl_F2_1: + Mov CS:CurrentMode, 6 + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AX, MaxRow + Inc AX + Mov NumberOfRows, AX + + Mov DI, Offset O1_PEConfigList + Mov CX, 0FFFFh + Call M_Object1List + Call PE_SetPatternModified + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov BX, NumberOfRows + Dec BX + Mov MaxRow, BX + +IF NETWORKENABLED + Call Network_GetSendQueue + JZ Glbl_F2_Network + + Mov AX, NETWORK_SETPATTERNLENGTH*100h ; Destination ALL + StosW + Mov AH, BL + Mov AL, [Byte Ptr PatternNumber] + StosW + +Glbl_F2_Network: + Call Network_FinishedSendQueue +ENDIF + Mov CS:CurrentMode, 2 + + Mov AX, 1 + Ret + +EndP Glbl_F2 + Assume DS:Nothing + +; + +Proc Glbl_F3 Far + + Call I_DrawWaveForm + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 3 + + Mov DX, Offset O1_SampleList + Ret + +EndP Glbl_F3 + +; + +Proc Glbl_F4 Far + + ; Init SampleNumber + Call Glbl_SampleToInstrument + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov BL, LastInstrument + And BL, BL + JNZ Glbl_F4_1 + + Mov LastInstrument, 1 + +Glbl_F4_1: + Mov AX, Inst + Mov DS, AX + Assume DS:Inst + Mov SampleNumber, BL + +Proc Glbl_F4_2 Far + + Call I_MapEnvelope + + Mov DI, InstrumentScreen + Add DI, DI + Mov DX, [DI+InstrumentScreenTable] + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 4 + + Ret + +EndP Glbl_F4_2 + +EndP Glbl_F4 + Assume DS:Nothing + +; + +Proc Glbl_F5 Far + + Cmp CS:CurrentMode, 5 + JE Glbl_F5_1 + + Call S_DefineSmallNumbers + + Call Music_GetPlayMode + Test AX, AX + JNZ Glbl_F5_4 + + Call Music_GetSlaveChannelInformationTable + +Glbl_F5_3: + Test Byte Ptr [SI], 1 + JNZ Glbl_F5_4 + + Add SI, SLAVECHANNELSIZE + Loop Glbl_F5_3 + + Call I_ClearTables + + Xor AX, AX + Call Music_PlaySong + +Glbl_F5_4: + Jmp Display_SelectDisplayList + +Glbl_F5_1: + Call Music_GetPlayMode + And AX, AX + JNZ Glbl_F5_2 + + Call I_ClearTables + + Xor AX, AX + Call Music_PlaySong + +Glbl_F5_2: + Mov AX, 1 + Ret + +EndP Glbl_F5 + +; + +Proc Glbl_F6 Far + + Call I_ClearTables + + Call PE_GetCurrentPattern + Xor CX, CX + Call Music_PlayPattern + + Mov AX, 1 + Ret + +EndP Glbl_F6 + +; + +Proc Glbl_LoadSample Far + + Call D_InitLoadSamples + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 13 + + Mov DX, Offset O1_LoadSampleList + Ret + +EndP Glbl_LoadSample + +; + +Proc Glbl_LoadInstrument Far + + Call D_InitLoadInstruments + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 15 + + Mov DX, Offset O1_LoadInstrumentList + Ret + +EndP Glbl_LoadInstrument + +; + +Proc Glbl_Shift_F1 Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 31 + + Mov DX, Offset O1_MIDIScreen + Ret + +EndP Glbl_Shift_F1 + +; + +Proc Glbl_Shift_F9 Far + + Call S_DefineHIASCII + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 16 + + Mov DX, Offset O1_MessageList + Ret + +EndP Glbl_Shift_F9 + +; + +Proc Glbl_Shift_F6 Far + + Call I_ClearTables + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + Mov AX, Order + + Call Music_PlaySong + + Mov AX, 1 + Ret + +EndP Glbl_Shift_F6 + Assume DS:Nothing + +; + +Proc Glbl_F8 Far + + Call Music_Stop + + Mov AX, 1 + Ret + +EndP Glbl_F8 + +; + +Proc Glbl_F9 Far + + Call D_InitLoadModule + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 9 + + Mov DX, Offset O1_LoadModuleList + + Mov DS, CX + Mov BX, DX + Mov Word Ptr [BX], 12 + + Ret + +EndP Glbl_F9 + +; + +Proc Glbl_F10 Far + + Call D_InitLoadModule + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 10 + + Mov DX, Offset O1_SaveModuleList + + Mov DS, CX + Mov BX, DX + Mov Word Ptr [BX], 15 + + Call D_ClearFileSpecifier + + Ret + +EndP Glbl_F10 + +; + +Proc Glbl_F11 Far + + Cmp CS:CurrentMode, 11 + JE Glbl_F11_1 + +Glbl_F11_2: + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_OrderPanningList + + Mov CS:CurrentMode, 11 + Ret + +Glbl_F11_1: + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov DX, Offset O1_OrderPanningList + + Mov CS:CurrentMode, 21 + Mov DX, Offset O1_OrderVolumeList + Ret + +EndP Glbl_F11 + +; + +Proc Glbl_F12 Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 12 + + Mov DX, Offset O1_ConfigureITList + Ret + +EndP Glbl_F12 + +; + +Proc Glbl_Ctrl_F1 Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 1 + + Mov DX, Offset O1_KeyboardList + Ret + +EndP Glbl_Ctrl_F1 + +; + +Proc Glbl_Ctrl_F3 Far + + Call D_InitLoadSamples + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 13 + + Mov DX, Offset O1_ViewSampleLibrary + Ret + +EndP Glbl_Ctrl_F3 + +; + +Proc Glbl_Ctrl_F4 Far + + Call D_InitLoadInstruments + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 15 + + Mov DX, Offset O1_ViewInstrumentLibrary + Ret + +EndP Glbl_Ctrl_F4 + +; + +Proc Glbl_Ctrl_F5 Far + + Call I_ClearTables + + Xor AX, AX + Call Music_PlaySong + + Mov AX, 1 + Ret + +EndP Glbl_Ctrl_F5 + +; + +Proc Glbl_Ctrl_F12 Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 14 + + Mov DX, Offset O1_ConfigurePaletteList + + Ret + +EndP Glbl_Ctrl_F12 + +; + +Proc Glbl_GetHeaderMode Far + + Push DS + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + Mov AL, LastInstrument + Pop DS + + Xor AH, AH + + Cmp CS:CurrentMode, 3 ; Sample list + JE Glbl_GetHeaderMode1 + + Cmp CS:CurrentMode, 13 ; Sample load list + JE Glbl_GetHeaderMode1 + + Cmp CS:CurrentMode, 4 + JE Glbl_GetHeaderMode2 + + Call Music_GetInstrumentMode + +Glbl_GetHeaderMode1: + Ret + +Glbl_GetHeaderMode2: + Push DS + Push AX + + Mov AX, Inst + Mov DS, AX + Assume DS:Inst + + Pop AX + Mov AL, SampleNumber + + Pop DS + Ret + +EndP Glbl_GetHeaderMode + Assume DS:Nothing + +; + +Proc Glbl_SetCurrentMode Far + + Mov CS:CurrentMode, AL + + Ret + +EndP Glbl_SetCurrentMode + +; + +Proc Glbl_GetCurrentMode Far ; Returns AL + + Mov AL, CS:CurrentMode + + Ret + +EndP Glbl_GetCurrentMode + +; + +Proc Glbl_Alt_F1 Far + + Mov AX, 0 + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP Glbl_Alt_F1 + +; + +Proc Glbl_Alt_F2 Far + + Mov AX, 1 + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP Glbl_Alt_F2 + +; + +Proc Glbl_Alt_F3 Far + + Mov AX, 2 + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP Glbl_Alt_F3 + +; + +Proc Glbl_Alt_F4 Far + + Mov AX, 3 + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP Glbl_Alt_F4 + +; + +Proc Glbl_Alt_F5 Far + + Mov AX, 4 + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP Glbl_Alt_F5 + +; + +Proc Glbl_Alt_F6 Far + + Mov AX, 5 + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP Glbl_Alt_F6 + +; + +Proc Glbl_Alt_F7 Far + + Mov AX, 6 + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP Glbl_Alt_F7 + +; + +Proc Glbl_Alt_F8 Far + + Mov AX, 7 + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP Glbl_Alt_F8 + +; + +Proc Glbl_LeftBrace Far + + Push CS + Pop DS + + Call Music_IncreaseSpeed + Mov SI, Offset SpeedSetMsg + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP Glbl_LeftBrace + +; + +Proc Glbl_RightBrace Far + + Push CS + Pop DS + + Call Music_DecreaseSpeed + Mov SI, Offset SpeedSetMsg + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP Glbl_RightBrace + +; + +Proc Glbl_LeftSquareBracket Far + + Push CS + Pop DS + + Call Music_DecreaseVolume + + Mov SI, Offset VolumeSetMsg + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP Glbl_LeftSquareBracket + +; + +Proc Glbl_RightSquareBracket Far + + Push CS + Pop DS + + Call Music_IncreaseVolume + + Mov SI, Offset VolumeSetMsg + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP Glbl_RightSquareBracket + +; + +Proc Glbl_SaveMode Far + +; Call S_GetDestination +; Mov AX, 0B800h +; Mov ES, AX +; Call RestoreMouse + + Call S_SaveScreen + + Mov AL, CurrentMode + Mov CurrentMode2, AL + + Mov BP, SP + Mov AX, [BP+16] + Mov CurrentList, AX + Mov AX, [BP+18] + Mov CurrentListSegment, AX + Mov CurrentMode, 0 + + Ret + +EndP Glbl_SaveMode + +; + +Proc Glbl_RestoreMode Far + +; Call NewCharacterSet + + Call S_RestoreScreen + + Mov AL, CurrentMode2 + Mov CurrentMode, AL + + Mov AX, 5 + Mov SI, 1 + Mov CX, CurrentListSegment + Mov DX, CurrentList + + Ret + +EndP Glbl_RestoreMode + +; + +IF MEMORYDEBUG + +Proc Glbl_Debug Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 22 + + Mov DX, Offset O1_DebugList + Ret + +EndP Glbl_Debug + +ENDIF + +; + +Proc Glbl_SampleToInstrument + + Cmp CS:CurrentMode, 3 + JNE Glbl_SampleToInstrument1 + + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + + Test Byte Ptr [DS:2Ch], 4 + JZ Glbl_SampleToInstrument1 + + Mov AX, Pattern + Mov ES, AX + Assume ES:Pattern + + Mov AH, ES:LastInstrument + Mov BX, [DS:64712] ; Offset of first instrument + + ; Search for sample in tables. + Mov DX, 99 + +Glbl_SampleToInstrument2: + Push BX + + Add BX, 41h ; To note/sample tables + Mov CX, 120 + +Glbl_SampleToInstrument4: + Cmp [BX], AH + JE Glbl_SampleToInstrument3 + Add BX, 2 + Loop Glbl_SampleToInstrument4 + + Pop BX + Add BX, 554 ; Length of instrument + Dec DX + JNZ Glbl_SampleToInstrument2 + + Ret + +Glbl_SampleToInstrument3: + Pop BX + + Mov AL, 100 + Sub AL, DL + Mov ES:LastInstrument, AL + +Glbl_SampleToInstrument1: + Ret + +EndP Glbl_SampleToInstrument + Assume ES:Nothing + +; + +IF TIMERSCREEN + +Proc Glbl_TimerScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + Mov CS:CurrentMode, 23 + + Mov DX, Offset O1_TimerList + Ret + +EndP Glbl_TimerScreen + +ENDIF + +; + +Proc Glbl_DriverScreen Far + + Call Music_GetDriverScreen + JC Glbl_DriverScreen1 + + Mov CurrentMode, 100 + +Glbl_DriverScreen1: + Ret + +EndP Glbl_DriverScreen + +; + +EndS + +; + +End diff --git a/it/IT_H.ASM b/it/IT_H.ASM new file mode 100644 index 0000000..4d99b62 --- /dev/null +++ b/it/IT_H.ASM @@ -0,0 +1,1552 @@ +;Ŀ +; Help Module +; + + .386 + Jumps + +include switch.inc + +Segment Object1 BYTE Public 'Data' +EndS + +;Ŀ +; Externals +; + + Extrn M_Object1List:Far + Extrn Glbl_SaveMode:Far + Extrn Glbl_RestoreMode:Far + + Extrn S_DrawString:Far + + Extrn O1_HelpList:Far + +;Ŀ +; Globals +; + + Global H_SetHelpContext:Far + Global H_DrawHelp:Far + Global H_Help:Far + Global H_HelpUp:Far + Global H_HelpDown:Far + Global H_HelpPgUp:Far + Global H_HelpPgDn:Far + Global H_HelpESC:Far + +; + +Segment Object1 BYTE Public 'Data' +EndS + +Segment Help BYTE Public USE16 'Code' + Assume CS:Help, DS:Nothing + +;Ŀ +; Variables +; + + ; Help contexts.... + ; 0 = Order list & Panning + ; 1 = Pattern edit list + ; 2 = Sample list + ; 3 = Load module + ; 4 = Order list & Volume + ; 5 = Configuration screen + ; 6 = Load sample list + ; 7 = Instrument list + ; 8 = Keyboard list + ; 9 = Info page + ; 10 = Palette configuration + ; 11 = Instrument list + ; 12 = message editor + ; 13 = MIDI Input + ; 14 = MIDI Output + +HelpContext DW 0 +TopLine DW 0 + +Positions DW 15 Dup (0) + +HelpContextPtrs Label Word + DW Offset HelpContext0Ptrs + DW Offset HelpContext1Ptrs + DW Offset HelpContext2Ptrs + DW Offset NoHelpContext + DW Offset HelpContext4Ptrs + DW Offset NoHelpContext + DW Offset NoHelpContext + DW Offset HelpContext7Ptrs + DW Offset NoHelpContext + DW Offset HelpContext9Ptrs + DW Offset NoHelpContext + DW Offset NoHelpContext + DW Offset HelpContext12Ptrs + DW Offset NoHelpContext + DW Offset NoHelpContext + +NoHelpContext DW Offset NewLine + DW Offset HelpGlobal_0 + DW Offset HelpGlobal_1 + DW Offset HelpGlobal_37 + DW Offset HelpGlobal_3 + DW Offset HelpGlobal_4 + DW Offset HelpGlobal_20 + DW Offset HelpGlobal_9 + DW Offset HelpGlobal_10 + DW Offset HelpGlobal_19 + DW Offset HelpGlobal_11 + DW Offset HelpGlobal_12 + DW Offset HelpGlobal_33 + DW Offset HelpGlobal_13 + DW Offset HelpGlobal_5 + DW Offset HelpGlobal_6 + DW Offset HelpGlobal_2 + DW Offset HelpGlobal_7 + DW Offset HelpGlobal_8 + DW Offset HelpGlobal_32 + DW Offset NewLine + DW Offset HelpGlobal_17 + DW Offset HelpGlobal_31 + DW Offset HelpGlobal_18 + DW Offset NewLine + DW Offset HelpGlobal_16 + DW Offset HelpGlobal_34 + DW Offset HelpGlobal_35 + DW Offset HelpGlobal_36 + DW Offset HelpGlobal_21 + DW Offset HelpGlobal_14 + DW Offset HelpGlobal_15 + DW 0 + +HelpContext0Ptrs DW Offset HelpContext0_26 + DW Offset HelpContext0_0 + DW Offset HelpContext0_27 + DW Offset NewLine + DW Offset HelpContext0_6 + DW Offset HelpContext0_28 + DW Offset HelpContext0_8 + DW Offset HelpContext0_9 + DW Offset HelpContext0_13 + DW Offset HelpContext0_14 + DW Offset HelpContext0_12 + DW Offset HelpContext0_15 + DW Offset NewLine + DW Offset HelpContext0_30 + DW Offset HelpContext0_29 + DW Offset NewLine + DW Offset Divider + DW Offset NewLine + DW Offset HelpGlobal_0 + DW Offset HelpGlobal_1 + DW Offset HelpGlobal_37 + DW Offset HelpGlobal_3 + DW Offset HelpGlobal_4 + DW Offset HelpGlobal_9 + DW Offset HelpGlobal_10 + DW Offset HelpGlobal_19 + DW Offset HelpGlobal_11 + DW Offset HelpGlobal_12 + DW Offset HelpGlobal_33 + DW Offset HelpGlobal_13 + DW Offset HelpGlobal_5 + DW Offset HelpGlobal_6 + DW Offset HelpGlobal_2 + DW Offset HelpGlobal_7 + DW Offset HelpGlobal_8 + DW Offset HelpGlobal_32 + DW Offset NewLine + DW Offset HelpGlobal_17 + DW Offset HelpGlobal_31 + DW Offset HelpGlobal_18 + DW Offset NewLine + DW Offset HelpGlobal_16 + DW Offset HelpGlobal_34 + DW Offset HelpGlobal_35 + DW Offset HelpGlobal_36 + DW Offset HelpGlobal_21 + DW Offset HelpGlobal_14 + DW Offset HelpGlobal_15 + DW Offset NewLine + DW Offset Divider + DW 0 + +HelpContext4Ptrs DW Offset HelpContext4_0 + DW Offset HelpContext4_1 + DW Offset HelpContext4_2 + DW Offset NewLine + DW Offset HelpContext0_6 + DW Offset HelpContext0_28 + DW Offset HelpContext0_8 + DW Offset HelpContext0_9 + DW Offset HelpContext0_13 + DW Offset HelpContext0_14 + DW Offset HelpContext0_12 + DW Offset HelpContext0_15 + DW Offset NewLine + DW Offset Divider + DW Offset NewLine + DW Offset HelpGlobal_0 + DW Offset HelpGlobal_1 + DW Offset HelpGlobal_37 + DW Offset HelpGlobal_3 + DW Offset HelpGlobal_4 + DW Offset HelpGlobal_20 + DW Offset HelpGlobal_9 + DW Offset HelpGlobal_22 + DW Offset HelpGlobal_10 + DW Offset HelpGlobal_19 + DW Offset HelpGlobal_11 + DW Offset HelpGlobal_12 + DW Offset HelpGlobal_33 + DW Offset HelpGlobal_13 + DW Offset HelpGlobal_5 + DW Offset HelpGlobal_23 + DW Offset HelpGlobal_6 + DW Offset HelpGlobal_2 + DW Offset HelpGlobal_7 + DW Offset HelpGlobal_8 + DW Offset HelpGlobal_32 + DW Offset NewLine + DW Offset HelpGlobal_17 + DW Offset HelpGlobal_31 + DW Offset HelpGlobal_18 + DW Offset NewLine + DW Offset HelpGlobal_16 + DW Offset HelpGlobal_34 + DW Offset HelpGlobal_35 + DW Offset HelpGlobal_36 + DW Offset HelpGlobal_21 + DW Offset HelpGlobal_14 + DW Offset HelpGlobal_15 + DW Offset NewLine + DW Offset Divider + DW 0 + +NewLine DB 0, 0 +Divider DB 2, 0FFh, 76, 154, 0 + +HelpContext0_26 DB 27, 0FFh, 1, 139, 0FFh, 26, 134, 0FFh, 1, 138, 0 +HelpContext0_0 DB 27, 0FFh, 1, 132, ' ', 0B9h, 0AAh, 0A1h, 0B8h, ' ', 0FFh, 1, 145, 0 +HelpContext0_27 DB 27, 0FFh, 1, 137, 0FFh, 26, 143, 0FFh, 1, 150, 0 + +HelpContext4_0 DB 22, 0FFh, 1, 139, 0FFh, 33, 134, 0FFh, 1, 138, 0 +HelpContext4_1 DB 22, 0FFh, 1, 132, ' ', 0B9h, 0AAh, 0A1h, 8Dh, 89h, ' ', 0FFh, 1, 145, 0 +HelpContext4_2 DB 22, 0FFh, 1, 137, 0FFh, 33, 143, 0FFh, 1, 150, 0 + +HelpContext0_6 DB 3, 0B9h, 0ADh, '.', 0 +HelpContext0_28 DB 5, 'N', 0FFh, 17, ' ', 83h, 0B4h, 85h, 0 +HelpContext0_8 DB 5, '-', 0FFh, 17, ' End ', 0BEh, 'song mark', 0 +HelpContext0_9 DB 5, '+', 0FFh, 17, ' Skip ', 0B1h, 0B4h, 0B9h, 'mark', 0 +HelpContext0_13 DB 5, 0C1h, 0FFh, 15, ' ', 83h, 0BFh, 85h, 0 +HelpContext0_14 DB 5, 0C2h, 0FFh, 15, ' ', 84h, 0BFh, 85h, 0 +HelpContext0_12 DB 5, 'Tab/', 82h, 'Tab', 0FFh, 5, ' ', 9Ch, 0B1h, 0B4h, 0B6h, 0 +HelpContext0_15 DB 5, 81h, 'F7', 0FFh, 11, ' ', 9Fh, 'this ', 0B9h, 0B4h, 0 + +HelpContext0_30 DB 3, 0B8h, 0ADh, '.', 0 +HelpContext0_29 DB 5, 'L/M/R/S', 0FFh, 11, ' ', 0A6h, 0B5h, 0B1h, 'Left/Middle/Right/Surround', 0 + +HelpGlobal_0 DB 3, 'G', 0B2h, 0ADh, '.', 0 +HelpGlobal_1 DB 5, 'F1', 0FFh, 16, ' Help (Context sensitive!)', 0 +HelpGlobal_37 DB 5, 82h, 'F1', 0FFh, 10, ' MIDI Screen', 0 +HelpGlobal_3 DB 5, 'F2', 0FFh, 16, ' ', 86h, 'Editor / ', 86h, 'Editor Options', 0 +HelpGlobal_4 DB 5, 'F3', 0FFh, 16, ' ', 94h, 0AAh, 0 +HelpGlobal_20 DB 5, 81h, 'F3', 0FFh, 11, ' ', 94h, 0ABh, 0 +HelpGlobal_9 DB 5, 'F4', 0FFh, 16, ' ', 8Eh, 0AAh, 0 +HelpGlobal_22 DB 5, 81h, 'F4', 0FFh, 11, ' ', 8Eh, 0ABh, 0 +HelpGlobal_10 DB 5, 'F5', 0FFh, 16, ' ', 9Fh, 'Information / ', 9Fh, 'song', 0 +HelpGlobal_19 DB 5, 81h, 'F5', 0FFh, 11, ' ', 9Fh, 'Song', 0 +HelpGlobal_11 DB 5, 'F6', 0FFh, 16, ' ', 9Fh, 0A2h, 85h, 0 +HelpGlobal_12 DB 5, 82h, 'F6', 0FFh, 10, ' ', 9Fh, 'song ', 0A9h, 0A2h, 0B9h, 0 +HelpGlobal_33 DB 5, 'F7', 0FFh, 16, ' ', 9Fh, 0A9h, 'mark / ', 0A2h, 'row', 0 +HelpGlobal_13 DB 5, 'F8', 0FFh, 16, ' Stop Playback', 0 +HelpGlobal_5 DB 5, 'F9', 0FFh, 16, ' Load Module', 0 +HelpGlobal_23 DB 5, 82h, 'F9', 0FFh, 10, ' Message Editor', 0 +HelpGlobal_6 DB 5, 'F10', 0FFh, 15, ' Save Module', 0 +HelpGlobal_2 DB 5, 'F11', 0FFh, 15, ' ', 0B9h, 0AAh, 0A1h, 0B8h, 0 +HelpGlobal_7 DB 3, '2*F11', 0FFh, 15, ' ', 0B9h, 0AAh, 0A1h, 8Dh, 89h, 0 +HelpGlobal_8 DB 5, 'F12', 0FFh, 15, ' Song Variables & Directory Configuration', 0 +HelpGlobal_32 DB 5, 81h, 'F12', 0FFh, 10, ' Palette Configuration', 0 + +HelpGlobal_17 DB 5, '{ }', 0FFh, 15, ' ', 93h, '/', 92h, ' playback ', 0C4h, 0 +HelpGlobal_31 DB 5, '[ ]', 0FFh, 15, ' ', 93h, '/', 92h, ' g', 0B2h, 8Ah, 0 +HelpGlobal_18 DB 5, 80h, 'F1 -> ', 80h, 'F8 ', 9Dh, 0A3h, 's 1->8', 0 + +HelpGlobal_16 DB 5, 81h, 'D', 0FFh, 12, ' DOS Shell', 0 +HelpGlobal_34 DB 5, 81h, 'E', 0FFh, 12, ' Refresh screen ', 0A1h, 'reset cache identification', 0 +HelpGlobal_35 DB 5, 81h, 'I', 0FFh, 12, ' Reinitialise sound driver', 0 +HelpGlobal_36 DB 5, 81h, 'M', 0FFh, 12, ' ', 9Dh, 'mouse cursor', 0 +HelpGlobal_21 DB 5, 81h, 'N', 0FFh, 12, ' New Song', 0 +HelpGlobal_14 DB 5, 81h, 'Q', 0FFh, 12, ' Quit ', 0B1h, 'DOS', 0 +HelpGlobal_15 DB 5, 81h, 'S', 0FFh, 12, ' Save ', 0A2h, 'song', 0 + + +HelpContext1Ptrs Label Word + DW Offset HelpContext1_0 + DW Offset HelpContext1_1 + DW Offset HelpContext1_2 + DW Offset NewLine + DW Offset HelpContext1_3 + DW Offset NewLine + DW Offset HelpContext1_200 + DW Offset HelpContext1_201 + DW Offset HelpContext1_202 + DW Offset HelpContext1_203 + DW Offset HelpContext1_204 + DW Offset HelpContext1_205 + DW Offset HelpContext1_206 + DW Offset HelpContext1_207 + DW Offset HelpContext1_208 + DW Offset NewLine + DW Offset HelpContext1_299 + DW Offset HelpContext1_4 + DW Offset HelpContext1_5 + DW Offset HelpContext1_6 + DW Offset HelpContext1_7 + DW Offset HelpContext1_8 + DW Offset HelpContext1_9 + DW Offset HelpContext1_10 + DW Offset HelpContext1_11 + DW Offset HelpContext1_12 + DW Offset HelpContext1_13 + DW Offset HelpContext1_14 + DW Offset HelpContext1_15 + DW Offset HelpContext1_16 + DW Offset HelpContext1_17 + DW Offset HelpContext1_18 + DW Offset HelpContext1_19 + DW Offset HelpContext1_20 + DW Offset HelpContext1_21 + DW Offset HelpContext1_22 + DW Offset HelpContext1_23 + DW Offset HelpContext1_24 + DW Offset HelpContext1_141 + DW Offset HelpContext1_142 + DW Offset HelpContext1_143 + DW Offset HelpContext1_25 + DW Offset HelpContext1_26 + DW Offset HelpContext1_135 + DW Offset HelpContext1_136 + DW Offset HelpContext1_137 + DW Offset HelpContext1_27 + DW Offset HelpContext1_28 + DW Offset HelpContext1_29 + DW Offset HelpContext1_30 + DW Offset HelpContext1_31 + DW Offset HelpContext1_32 + DW Offset HelpContext1_33 + DW Offset HelpContext1_34 + DW Offset HelpContext1_35 + DW Offset HelpContext1_36 + DW Offset HelpContext1_45 + DW Offset HelpContext1_46 + DW Offset HelpContext1_47 + DW Offset HelpContext1_48 + DW Offset HelpContext1_49 + DW Offset HelpContext1_50 + DW Offset HelpContext1_51 + DW Offset HelpContext1_62 + DW Offset HelpContext1_63 + DW Offset HelpContext1_64 + DW Offset HelpContext1_65 + DW Offset HelpContext1_66 + DW Offset HelpContext1_52 + DW Offset HelpContext1_53 + DW Offset HelpContext1_144 + DW Offset HelpContext1_145 + DW Offset HelpContext1_153 + DW Offset HelpContext1_154 + DW Offset HelpContext1_155 + DW Offset HelpContext1_156 + DW Offset HelpContext1_157 + DW Offset HelpContext1_162 + DW Offset HelpContext1_168 + DW Offset HelpContext1_169 + DW Offset HelpContext1_170 + DW Offset HelpContext1_171 + DW Offset HelpContext1_54 + DW Offset HelpContext1_55 + DW Offset HelpContext1_56 + DW Offset HelpContext1_57 + DW Offset HelpContext1_146 + DW Offset HelpContext1_58 + DW Offset HelpContext1_59 + DW Offset HelpContext1_60 + DW Offset HelpContext1_61 + DW Offset HelpContext1_179 + DW Offset HelpContext1_180 + DW Offset HelpContext1_67 + DW Offset HelpContext1_68 + DW Offset HelpContext1_69 + DW Offset HelpContext1_70 + DW Offset HelpContext1_138 + DW Offset HelpContext1_139 + DW Offset HelpContext1_140 + DW Offset HelpContext1_71 + DW Offset HelpContext1_72 + DW Offset HelpContext1_73 + DW Offset NewLine + DW Offset Divider + DW Offset NewLine + DW Offset HelpContext1_74 + DW Offset HelpContext1_114 + DW Offset HelpContext1_115 + DW Offset HelpContext1_134 + DW Offset HelpContext1_75 + DW Offset HelpContext1_76 + DW Offset HelpContext1_77 + DW Offset HelpContext1_78 + DW Offset HelpContext1_79 + DW Offset HelpContext1_80 + DW Offset HelpContext1_81 + DW Offset HelpContext1_181 + DW Offset NewLine + DW Offset HelpContext1_82 + DW Offset HelpContext1_83 + DW Offset HelpContext1_163 + DW Offset HelpContext1_84 + DW Offset HelpContext1_85 + DW Offset NewLine + DW Offset HelpContext1_86 + DW Offset HelpContext1_127 + DW Offset NewLine + DW Offset HelpContext1_87 + DW Offset HelpContext1_164 + DW Offset HelpContext1_129 + DW Offset HelpContext1_88 + DW Offset HelpContext1_131 + DW Offset HelpContext1_90 + DW Offset HelpContext1_89 + DW Offset HelpContext1_160 + DW Offset HelpContext1_91 + DW Offset HelpContext1_92 + DW Offset HelpContext1_93 + DW Offset NewLine + DW Offset HelpContext1_116 + DW Offset HelpContext1_124 + DW Offset NewLine + DW Offset HelpContext1_130 + DW Offset HelpContext1_117 + DW Offset HelpContext1_161 + DW Offset NewLine + DW Offset HelpContext1_166 + DW Offset HelpContext1_174 + DW Offset HelpContext1_300 + DW Offset NewLine + DW Offset HelpContext1_176 + DW Offset NewLine + DW Offset HelpContext1_118 + DW Offset HelpContext1_119 + DW Offset HelpContext1_120 + DW Offset HelpContext1_121 + DW Offset HelpContext1_122 + DW Offset HelpContext1_123 + DW Offset HelpContext1_128 + DW Offset NewLine + DW Offset HelpContext1_167 + DW Offset NewLine + DW Offset HelpContext1_159 + DW Offset NewLine + DW Offset HelpContext1_94 + DW Offset HelpContext1_95 + DW Offset HelpContext1_96 + DW Offset HelpContext1_97 + DW Offset HelpContext1_98 + DW Offset HelpContext1_165 + DW Offset NewLine + DW Offset HelpContext1_99 + DW Offset NewLine + DW Offset HelpContext1_113 + DW Offset HelpContext1_100 + DW Offset HelpContext1_101 + DW Offset HelpContext1_102 + DW Offset HelpContext1_103 + DW Offset HelpContext1_104 + DW Offset HelpContext1_133 + DW Offset HelpContext1_105 + DW Offset HelpContext1_106 + DW Offset HelpContext1_132 + DW Offset HelpContext1_107 + DW Offset NewLine + DW Offset HelpContext1_108 + DW Offset HelpContext1_109 + DW Offset HelpContext1_110 + DW Offset HelpContext1_111 + DW Offset HelpContext1_173 + DW Offset NewLine + DW Offset HelpContext1_125 + DW Offset HelpContext1_126 + DW Offset NewLine + DW Offset HelpContext1_112 + DW Offset HelpContext1_175 + DW Offset NewLine + DW Offset HelpContext1_147 + DW Offset HelpContext1_148 + DW Offset HelpContext1_149 + DW Offset NewLine + DW Offset HelpContext1_152 + DW Offset HelpContext1_158 + DW Offset NewLine + DW Offset HelpContext1_150 + DW Offset HelpContext1_151 + DW Offset NewLine + DW Offset HelpContext1_172 + DW Offset HelpContext1_177 + DW Offset HelpContext1_178 + DW Offset NewLine + DW Offset Divider + DW Offset NewLine + DW Offset HelpGlobal_0 + DW Offset HelpGlobal_1 + DW Offset HelpGlobal_37 + DW Offset HelpGlobal_3 + DW Offset HelpGlobal_4 + DW Offset HelpGlobal_20 + DW Offset HelpGlobal_9 + DW Offset HelpGlobal_22 + DW Offset HelpGlobal_10 + DW Offset HelpGlobal_19 + DW Offset HelpGlobal_11 + DW Offset HelpGlobal_12 + DW Offset HelpGlobal_33 + DW Offset HelpGlobal_13 + DW Offset HelpGlobal_5 + DW Offset HelpGlobal_23 + DW Offset HelpGlobal_6 + DW Offset HelpGlobal_2 + DW Offset HelpGlobal_7 + DW Offset HelpGlobal_8 + DW Offset HelpGlobal_32 + DW Offset NewLine + DW Offset HelpGlobal_17 + DW Offset HelpGlobal_31 + DW Offset HelpGlobal_18 + DW Offset NewLine + DW Offset HelpGlobal_16 + DW Offset HelpGlobal_34 + DW Offset HelpGlobal_35 + DW Offset HelpGlobal_36 + DW Offset HelpGlobal_21 + DW Offset HelpGlobal_14 + DW Offset HelpGlobal_15 + DW Offset NewLine + DW Offset Divider + + Comment & + + DW Offset NewLine + DW Offset HelpHexTable0 + DW Offset HelpHexTable1 + DW Offset HelpHexTable2 + DW Offset NewLine + DW Offset HelpHexTable3 + DW Offset Divider + DW Offset HelpHexTable4 + DW Offset HelpHexTable5 + DW Offset HelpHexTable6 + DW Offset HelpHexTable7 + DW Offset HelpHexTable8 + DW Offset HelpHexTable9 + DW Offset HelpHexTable10 + DW Offset HelpHexTable11 + DW Offset HelpHexTable12 + DW Offset HelpHexTable13 + DW Offset HelpHexTable14 + DW Offset HelpHexTable15 + DW Offset HelpHexTable16 + DW Offset HelpHexTable17 + DW Offset HelpHexTable18 + DW Offset HelpHexTable19 + DW Offset HelpHexTable20 + DW Offset HelpHexTable21 + DW Offset HelpHexTable22 + DW Offset HelpHexTable23 + DW Offset HelpHexTable24 + DW Offset HelpHexTable25 + DW Offset HelpHexTable26 + DW Offset HelpHexTable27 + DW Offset HelpHexTable28 + DW Offset HelpHexTable29 + DW Offset HelpHexTable30 + DW Offset HelpHexTable31 + DW Offset HelpHexTable32 + DW Offset HelpHexTable33 + DW Offset HelpHexTable34 + DW Offset HelpHexTable35 + DW Offset Divider + + & + DW 0 + +HelpContext1_0 DB 32, 0FFh, 1, 139, 0FFh, 16, 134, 0FFh, 1, 138, 0 +HelpContext1_1 DB 32, 0FFh, 1, 132, ' ', 86h, 'Edit ', 0FFh, 1, 145, 0 +HelpContext1_2 DB 32, 0FFh, 1, 137, 0FFh, 16, 143, 0FFh, 1, 150, 0 +HelpContext1_3 DB 3, 'Summary ', 0BEh, 'Effects.', 0 + +HelpContext1_200 DB 4, 89h, 'Column ', 0BDh, 's.', 0 +HelpContext1_201 DB 5, 'Ax', 8Bh, 8Ah, 87h, 0 +HelpContext1_202 DB 5, 'Bx', 8Bh, 8Ah, 88h, 0 +HelpContext1_203 DB 5, 'Cx ', 89h, 87h, 0 +HelpContext1_204 DB 5, 'Dx ', 89h, 88h, 0 +HelpContext1_205 DB 5, 'Ex ', 0BAh, 88h, 0 +HelpContext1_206 DB 5, 'Fx ', 0BAh, 87h, 0 +HelpContext1_207 DB 5, 'Gx ', 0BCh, 0B1h, 0A5h, 0A0h, 0C4h, 'x', 0 +HelpContext1_208 DB 5, 'Hx V', 0B3h, 0A0h, 0C6h, 'x', 0 + +HelpContext1_299 DB 4, 'General ', 0BDh, 's.', 0 + +HelpContext1_4 DB 5, 'Axx ', 0A6h, 'song ', 0C4h, '(hex)', 0 +HelpContext1_5 DB 5, 'Bxx Jump ', 0B1h, 0B9h, '(hex)', 0 +HelpContext1_6 DB 5, 'Cxx Break ', 0B1h, 'row xx (hex) ', 0BEh, 0B4h, 85h, 0 +HelpContext1_7 DB 5, 'D0x ', 89h, 88h, 0 +HelpContext1_8 DB 5, 'Dx0 ', 89h, 87h, 0 +HelpContext1_9 DB 5, 'DFx', 8Bh, 8Ah, 88h, 0 +HelpContext1_10 DB 5, 'DxF', 8Bh, 8Ah, 87h, 0 +HelpContext1_11 DB 5, 'Exx ', 0BAh, 88h, 'x', 0 +HelpContext1_12 DB 5, 'EFx', 8Bh, 0BBh, 88h, 0 +HelpContext1_13 DB 5, 'EEx Extra fine ', 0BBh, 88h, 0 +HelpContext1_14 DB 5, 'Fxx ', 0BAh, 87h, 'x', 0 +HelpContext1_15 DB 5, 'FFx', 8Bh, 0BBh, 87h, 0 +HelpContext1_16 DB 5, 'FEx Extra fine ', 0BBh, 87h, 0 +HelpContext1_17 DB 5, 'Gxx ', 0BCh, 0B1h, 0A5h, 0A0h, 0C4h, 'xx', 0 +HelpContext1_18 DB 5, 'Hxy V', 0B3h, 0A0h, 0C5h, 0 +HelpContext1_19 DB 5, 'Ixy Tremor ', 0A0h, 'ontime x ', 0A1h, 'offtime y', 0 +HelpContext1_20 DB 5, 'Jxy Arpeggio ', 0A0h, 'halftones x ', 0A1h, 'y', 0 +HelpContext1_21 DB 5, 'Kxx', 9Bh, 'H00 & Dxx', 0 +HelpContext1_22 DB 5, 'Lxx', 9Bh, 'G00 & Dxx', 0 +HelpContext1_23 DB 5, 'Mxx ', 0A6h, 0A4h, 8Ah, 0B1h, 'xx (0->40h)', 0 +HelpContext1_24 DB 5, 'N0x ', 8Dh, 8Ah, 88h, 0 +HelpContext1_141 DB 5, 'Nx0 ', 8Dh, 8Ah, 87h, 0 +HelpContext1_142 DB 5, 'NFx', 8Bh, 0A4h, 8Ah, 88h, 0 +HelpContext1_143 DB 5, 'NxF', 8Bh, 0A4h, 8Ah, 87h, 0 +HelpContext1_25 DB 5, 'Oxx ', 0A6h, 95h, ' offset ', 0B1h, 'yxx00h, y set ', 0A0h, 'SAy', 0 +HelpContext1_26 DB 5, 'P0x ', 0B8h, 0A7h, 0B1h, 'right ', 0B0h, 'x', 0 +HelpContext1_135 DB 5, 'Px0 ', 0B8h, 0A7h, 0B1h, 'left ', 0B0h, 'x', 0 +HelpContext1_136 DB 5, 'PFx', 8Bh, 0B5h, 0A7h, 0B1h, 'right ', 0B0h, 'x', 0 +HelpContext1_137 DB 5, 'PxF', 8Bh, 0B5h, 0A7h, 0B1h, 'left ', 0B0h, 'x', 0 +HelpContext1_27 DB 5, 'Qxy Retrigger ', 0A5h, 'every y ticks ', 0A0h, 8Ah, 'modifier x', 0 +HelpContext1_28 DB 7, 'Values for x:', 0 +HelpContext1_29 DB 9, '0: No ', 8Ah, 0C9h, 0FFh, 8, ' 8: Not used', 0 +HelpContext1_30 DB 9, '1: -1', 0FFh, 23, ' 9: +1', 0 +HelpContext1_31 DB 9, '2: -2', 0FFh, 23, ' A: +2', 0 +HelpContext1_32 DB 9, '3: -4', 0FFh, 23, ' B: +4', 0 +HelpContext1_33 DB 9, '4: -8', 0FFh, 23, ' C: +8', 0 +HelpContext1_34 DB 9, '5: -16', 0FFh, 22, ' D: +16', 0 +HelpContext1_35 DB 9, '6: *2/3', 0FFh, 21, ' E: *3/2', 0 +HelpContext1_36 DB 9, '7: *1/2', 0FFh, 21, ' F: *2', 0 +; HelpContext1_37 DB 9, '8: Not used', 0 +; HelpContext1_38 DB 9, '9: +1', 0 +; HelpContext1_39 DB 9, 'A: +2', 0 +; HelpContext1_40 DB 9, 'B: +4', 0 +; HelpContext1_41 DB 9, 'C: +8', 0 +; HelpContext1_42 DB 9, 'D: +16', 0 +; HelpContext1_43 DB 9, 'E: *3/2', 0 +; HelpContext1_44 DB 9, 'F: *2', 0 +HelpContext1_45 DB 5, 'Rxy Tremelo ', 0A0h, 0C5h, 0 +HelpContext1_46 DB 5, 0FEh, 7, 'S0x ', 0A6h, 'filter', 0 +HelpContext1_47 DB 5, 0FEh, 7, 'S1x ', 0A6h, 'glissando control', 0 +HelpContext1_48 DB 5, 0FEh, 7, 'S2x ', 0A6h, 'finetune', 0 +HelpContext1_49 DB 5, 'S3x ', 0A6h, 'v', 0B3h, 9Ah, 0 +HelpContext1_50 DB 5, 'S4x ', 0A6h, 'tremelo ', 9Ah, 0 +HelpContext1_51 DB 5, 'S5x ', 0A6h, 'panbrello ', 9Ah, 0 +HelpContext1_62 DB 7, 'Waveforms for commands S3x, S4x ', 0A1h, 'S5x:', 0 +HelpContext1_63 DB 9, '0: Sine wave', 0 +HelpContext1_64 DB 9, '1: Ramp down', 0 +HelpContext1_65 DB 9, '2: Square wave', 0 +HelpContext1_66 DB 9, '3: Random wave', 0 +HelpContext1_52 DB 5, 'S6x ', 86h, 'delay for x ticks', 0 +HelpContext1_53 DB 5, 'S70', 0C0h, 0A5h, 'cut', 0 +HelpContext1_144 DB 5, 'S71', 0C0h, 0A5h, 'off', 0 +HelpContext1_145 DB 5, 'S72', 0C0h, 0A5h, 'fade', 0 +HelpContext1_153 DB 5, 'S73', 96h, 0A5h, 'cut', 0 +HelpContext1_154 DB 5, 'S74', 96h, 'continue', 0 +HelpContext1_155 DB 5, 'S75', 96h, 0A5h, 'off', 0 +HelpContext1_156 DB 5, 'S76', 96h, 0A5h, 'fade', 0 +HelpContext1_157 DB 5, 'S77 ', 0ACh, 'off ', 8Ah, 8Ch, 0 +HelpContext1_162 DB 5, 'S78 ', 0ACh, 'on ', 8Ah, 8Ch, 0 +HelpContext1_168 DB 5, 'S79 ', 0ACh, 'off ', 0B5h, 8Ch, 0 +HelpContext1_169 DB 5, 'S7A ', 0ACh, 'on ', 0B5h, 8Ch, 0 +HelpContext1_170 DB 5, 'S7B ', 0ACh, 'off ', 0BBh, 8Ch, 0 +HelpContext1_171 DB 5, 'S7C ', 0ACh, 'on ', 0BBh, 8Ch, 0 +HelpContext1_54 DB 5, 'S8x ', 0A6h, 0B5h, 'position', 0 +HelpContext1_55 DB 5, 'S91 ', 0A6h, 'surround sound', 0 +HelpContext1_56 DB 5, 'SAy ', 0A6h, 'high value ', 0BEh, 95h, ' offset yxx00h', 0 +HelpContext1_57 DB 5, 'SB0 ', 0A6h, 'loopback point', 0 +HelpContext1_146 DB 5, 'SBx Loop x times ', 0B1h, 'loopback point', 0 +HelpContext1_58 DB 5, 'SCx ', 0C3h, 'cut after x ticks', 0 +HelpContext1_59 DB 5, 'SDx ', 0C3h, 'delay for x ticks', 0 +HelpContext1_60 DB 5, 'SEx ', 86h, 'delay for x rows', 0 +HelpContext1_61 DB 5, 'SFx ', 0A6h, 'parameterised MIDI Macro', 0 +HelpContext1_179 DB 5, 'T0x ', 97h, 88h, 0 +HelpContext1_180 DB 5, 'T1x ', 97h, 87h, 0 +HelpContext1_67 DB 5, 'Txx ', 0A6h, 97h, 0B1h, 'xx (20h->0FFh)', 0 +HelpContext1_68 DB 5, 'Uxy', 8Bh, 'v', 0B3h, 0A0h, 0C5h, 0 +HelpContext1_69 DB 5, 'Vxx ', 0A6h, 'g', 0B2h, 8Ah, 0B1h, 'xx (0->80h)', 0 +HelpContext1_70 DB 5, 'W0x G', 0B2h, 8Ah, 88h, 0 +HelpContext1_138 DB 5, 'Wx0 G', 0B2h, 8Ah, 87h, 0 +HelpContext1_139 DB 5, 'WFx', 8Bh, 'g', 0B2h, 8Ah, 88h, 0 +HelpContext1_140 DB 5, 'WxF', 8Bh, 'g', 0B2h, 8Ah, 87h, 0 +HelpContext1_71 DB 5, 'Xxx ', 0A6h, 0B5h, 'position (0->0FFh)', 0 +HelpContext1_72 DB 5, 'Yxy Panbrello ', 0A0h, 0C5h, 0 +HelpContext1_73 DB 5, 'Zxx MIDI Macros', 0 + +HelpContext1_74 DB 3, 86h, 'Edit ', 0ADh, '.', 0 +HelpContext1_114 DB 5, 'Grey +,-', 0FFh, 9, ' ', 0C7h, 85h, 0CDh, 0 +HelpContext1_115 DB 5, 'Shift +,-', 0FFh, 8, ' ', 0C7h, '4 ', 85h, 0CDh, 0 +HelpContext1_134 DB 5, "Ctrl +,-", 0FFh, 9, " ", 0C7h, "order's ", 85h, 0CDh, 0 +HelpContext1_75 DB 5, '0-9', 0FFh, 14, ' ', 0C8h, 'octave/volume/', 8Fh, 0 +HelpContext1_76 DB 5, '0-9, A-F', 0FFh, 9, ' ', 0C8h, 0BDh, 'value', 0 +HelpContext1_77 DB 5, 'A-Z', 0FFh, 14, ' ', 0C8h, 0BDh, 0 +HelpContext1_78 DB 5, '. (Period)', 0FFh, 7, ' Clear field(s)', 0 +HelpContext1_79 DB 5, '1', 0FFh, 16, ' ', 0C3h, 'cut (^^^)', 0 +HelpContext1_80 DB 5, '`', 0FFh, 16, ' ', 0C3h, 'off (', 0FFh, 3, ') / ', 0B8h, 9Dh, 0 + +HelpContext1_81 DB 5, 'Spacebar', 0FFh, 9, ' Use last note/', 8Fh, '/volume/', 0BDh, '/', 0BDh, 'value', 0 +HelpContext1_181 DB 5, 'Caps Lock+Key', 0FFh, 4, ' Preview ', 0A5h, 0 +HelpContext1_82 DB 5, 99h, 0FFh, 11, ' Get default note/', 8Fh, '/volume/', 0BDh, 0 +HelpContext1_83 DB 5, '< or ', 81h, 'Up', 0FFh, 5, ' ', 93h, ' ', 8Fh, 0 +HelpContext1_163 DB 5, '> or ', 81h, 'Down ', 92h, ' ', 8Fh, 0 +HelpContext1_84 DB 5, 'Grey /,*', 0FFh, 9, ' ', 93h, '/', 92h, ' octave', 0 +HelpContext1_85 DB 5, ', (Comma)', 0FFh, 8, ' ', 9Dh, 'edit mask for ', 0A2h, 'field', 0 +HelpContext1_86 DB 5, 0C1h, '/', 0C2h, 0FFh, 10, ' ', 9Eh, 0BFh, 'row to/', 0A9h, 0A2h, 0A3h, 0 +HelpContext1_127 DB 5, 80h, 0C1h, '/', 0C2h, 0FFh, 6, ' ', 9Eh, 'an entire row to/', 0A9h, 85h, 0CDh, 0 +HelpContext1_87 DB 5, 'Up/Down', 0FFh, 10, ' ', 9Ch, 0B7h, 0B0h, 'the skipvalue (set ', 0A0h, 'Alt 0-9)', 0 +HelpContext1_164 DB 5, 81h, 'Home/End', 0FFh, 4, ' ', 9Ch, 0B7h, 0B0h, '1 row', 0 +HelpContext1_129 DB 5, 80h, 'Up/Down', 0FFh, 6, ' ', 0BCh, 85h, 0B7h, 0B0h, '1 row', 0 +HelpContext1_88 DB 5, 'Left/Right', 0FFh, 7, ' ', 9Ch, 'cursor left/right', 0 +HelpContext1_131 DB 5, 80h, 'Left/Right ', 9Ch, 'forwards/backwards one ', 0A3h, 0 +HelpContext1_90 DB 5, 'Tab/', 82h, 'Tab', 0FFh, 4, ' ', 9Ch, 'forwards/backwards ', 0B1h, 0A5h, 'column', 0 +HelpContext1_89 DB 5, 'PgUp/PgDn', 0FFh, 8, ' ', 9Ch, 0B7h, 'n lines (n=Row Hilight Major)', 0 +HelpContext1_160 DB 5, 81h, 'PgUp/PgDn ', 9Ch, 0B1h, 'top/bottom ', 0BEh, 85h, 0 +HelpContext1_91 DB 5, 'Home', 0FFh, 13, ' ', 9Ch, 0B1h, 'start ', 0BEh, 'column/start of line/start of ', 85h, 0 +HelpContext1_92 DB 5, 'End', 0FFh, 14, ' ', 9Ch, 0B1h, 'end ', 0BEh, 'column/end ', 0BEh, 'line/end of', 85h, 0 +HelpContext1_93 DB 5, 'Backspace', 0FFh, 8, ' ', 9Ch, 0B1h, 'previous position (accounts for Multi', 0A3h, ')', 0 +HelpContext1_116 DB 5, 80h, 'N', 0FFh, 12, ' ', 9Dh, 'Multichannel mode for ', 0A2h, 0A3h, 0 +HelpContext1_124 DB 3, '2*', 80h, 'N', 0FFh, 12, ' Multichannel Selection menu', 0 +HelpContext1_130 DB 5, 80h, 99h, 0FFh, 7, ' Store ', 85h, 90h, 0 +HelpContext1_117 DB 5, 80h, 'Backspace', 0FFh, 4, ' Revert ', 85h, 90h, ' ', 0CDh, 0 +HelpContext1_161 DB 5, 81h, 'Backspace Undo - any function ', 0A0h, 0CDh, ' can be undone', 0 + +HelpContext1_166 DB 5, 81h, 'C', 0FFh, 11, ' ', 9Dh, 'centralise cursor', 0 +HelpContext1_174 DB 5, 81h, 'H', 0FFh, 11, ' ', 9Dh, 0A2h, 'row hilight', 0 +HelpContext1_300 DB 5, 81h, 'V', 0FFh, 11, ' ', 9Dh, 'default ', 8Ah, 'display', 0 + +HelpContext1_176 DB 5, 81h, 'F2', 0FFh, 10, ' ', 0A6h, 85h, 'length', 0 + +HelpContext1_118 DB 4, 'Track View Functions.', 0 +HelpContext1_119 DB 5, 80h, "T", 0FFh, 12, " Cycle ", 0A2h, "track's view", 0 +HelpContext1_120 DB 5, 80h, 'R', 0FFh, 12, ' Clear all ', 0CBh, 'views', 0 +HelpContext1_121 DB 5, 80h, 'H', 0FFh, 12, ' ', 9Dh, 0CBh, 'view divisions', 0 +HelpContext1_122 DB 5, 81h, '0', 0FFh, 11, ' Deselect ', 0A2h, 0CBh, 0 +HelpContext1_123 DB 5, 81h, '1 - ', 81h, '5 View ', 0A2h, 0CBh, 'in scheme 1-5', 0 +HelpContext1_128 DB 5, 81h, 'Left/Right ', 9Ch, 'left/right ', 0A8h, 0CBh, 'view columns', 0 + +HelpContext1_167 DB 5, 'L-Ctrl&Shift 1-4 Quick view scheme setup', 0 + +HelpContext1_159 DB 5, 81h, 'T', 0FFh, 11, ' ', 9Dh, 'View-', 8Dh, 'cursor-tracking', 0 + +HelpContext1_94 DB 4, 'Block Functions.', 0 +HelpContext1_95 DB 5, 80h, 'B', 0FFh, 12, ' ', 0CAh, 'beginning ', 0BEh, 0CCh, 0 +HelpContext1_96 DB 5, 80h, 'E', 0FFh, 12, ' ', 0CAh, 'end ', 0BEh, 0CCh, 0 +HelpContext1_97 DB 5, 80h, 'D', 0FFh, 12, ' Quick mark n/2n/4n/... lines (n=Row Hilight Major)', 0 +HelpContext1_98 DB 5, 80h, 'L', 0FFh, 12, ' ', 0CAh, 'entire column/', 85h, 0 +HelpContext1_165 DB 5, 82h, 'Arrows', 0FFh, 5, ' ', 0CAh, 0CCh, 0 + +HelpContext1_99 DB 5, 80h, 'U', 0FFh, 12, ' Unmark block/Release ', 98h, 'memory', 0 + +HelpContext1_113 DB 5, 80h, 'Q', 0FFh, 12, ' Raise notes ', 0B0h, 0BFh, 0AFh, 0CDh, 0 +HelpContext1_100 DB 5, 80h, 'A', 0FFh, 12, ' Lower notes ', 0B0h, 0BFh, 0AFh, 0CDh, 0 +HelpContext1_101 DB 5, 80h, 'S', 0FFh, 12, ' ', 0A6h, 8Eh, 0CDh, 0 +HelpContext1_102 DB 5, 80h, 'V', 0FFh, 12, ' ', 0A6h, 'volume/', 0B5h, 0CDh, 0 +HelpContext1_103 DB 5, 80h, 'W', 0FFh, 12, ' ', 0CEh, 'vol/pan not associated ', 0A0h, 0BFh, 'note/', 8Fh, ' ', 0CDh, 0 +HelpContext1_104 DB 5, 80h, 'K', 0FFh, 12, ' ', 0BCh, 'volume/', 0B5h, 'column ', 0CDh, 0 +HelpContext1_133 DB 3, '2*', 80h, 'K', 0FFh, 12, ' ', 0CEh, 'all volume/', 0B5h, 'controls ', 0CDh, 0 +HelpContext1_105 DB 5, 80h, 'J', 0FFh, 12, ' ', 89h, 'amplifier ', 0CDh, ' / Fast ', 8Ah, 'attenuate ', 0CDh, 0 +HelpContext1_106 DB 5, 80h, 'Z', 0FFh, 12, ' Cut ', 0CCh, 0CDh, 0 +HelpContext1_132 DB 5, 80h, 'X', 0FFh, 12, ' ', 0BCh, 0BDh, ' value ', 0CDh, 0 +HelpContext1_107 DB 3, '2*', 80h, 'X', 0FFh, 12, ' ', 0CEh, 'all ', 0BDh, ' ', 90h, ' ', 0CDh, 0 + +HelpContext1_108 DB 5, 80h, 'C', 0FFh, 12, ' Copy ', 0CCh, 'into ', 98h, 0 +HelpContext1_109 DB 5, 80h, 'P', 0FFh, 12, ' Paste ', 90h, ' ', 0A9h, 98h, 0CDh, 0 +HelpContext1_110 DB 5, 80h, 'O', 0FFh, 12, ' Overwrite ', 0A0h, 90h, ' ', 0A9h, 98h, ' ', 0CDh, 0 +HelpContext1_111 DB 5, 80h, 'M', 0FFh, 12, ' Mix each row ', 0A9h, 98h, 0A0h, 85h, 90h, ' ', 0CDh, 0 +HelpContext1_173 DB 3, '2*', 80h, 'M', 0FFh, 12, ' Mix each field ', 0A9h, 98h, 0A0h, 85h, 90h, 0 + +HelpContext1_125 DB 5, 80h, 'F', 0FFh, 12, ' Double ', 0CCh, 'length ', 0CDh, 0 +HelpContext1_126 DB 5, 80h, 'G', 0FFh, 12, ' Halve ', 0CCh, 'length ', 0CDh, 0 + +HelpContext1_112 DB 5, 80h, 'I', 0FFh, 12, ' Select Template mode / Fast ', 8Ah, 'amplify ', 0CDh, 0 + +HelpContext1_175 DB 5, 81h, 'J', 0FFh, 11, ' ', 9Dh, 'fast ', 8Ah, 'mode', 0 + +HelpContext1_147 DB 3, 'Playback Functions.', 0 +HelpContext1_148 DB 5, '4', 0FFh, 16, ' ', 9Fh, 0A5h, 'under cursor', 0 +HelpContext1_149 DB 5, '8', 0FFh, 16, ' ', 9Fh, 'row', 0 + +HelpContext1_152 DB 5, 81h, 'F6', 0FFh, 10, ' ', 9Fh, 0A9h, 0A2h, 'row', 0 +HelpContext1_158 DB 5, 81h, 'F7', 0FFh, 10, ' Set/Clear playback mark (for use ', 0A0h, 'F7)', 0 + +HelpContext1_150 DB 5, 80h, 'F9', 0FFh, 11, ' ', 9Dh, 0A2h, 0A3h, 0 +HelpContext1_151 DB 5, 80h, 'F10', 0FFh, 10, ' Solo ', 0A2h, 0A3h, 0 + +HelpContext1_172 DB 5, 'Scroll Lock', 0FFh, 6, ' ', 9Dh, 'playback tracing', 0 +HelpContext1_177 DB 5, 81h, 'Z', 0FFh, 11, ' ', 0C8h, 'MIDI playback trigger', 0 +HelpContext1_178 DB 5, 80h, 'Scroll Lock ', 9Dh, 'MIDI input', 0 + +HelpContext2Ptrs Label Word + DW Offset HelpContext2_0 + DW Offset HelpContext2_1 + DW Offset HelpContext2_2 + DW Offset NewLine + DW Offset HelpContext2_3 + DW Offset HelpContext2_10 + DW Offset HelpContext2_4 + DW Offset HelpContext2_5 + DW Offset NewLine + DW Offset HelpContext2_11 + DW Offset HelpContext2_23 + DW Offset HelpContext2_8 + DW Offset HelpContext2_6 + DW Offset HelpContext2_17 + DW Offset HelpContext2_18 + DW Offset HelpContext2_27 + DW Offset HelpContext2_30 + DW Offset HelpContext2_33 + DW Offset HelpContext2_7 + DW Offset HelpContext2_29 + DW Offset HelpContext2_28 + DW Offset HelpContext2_14 + DW Offset HelpContext2_19 + DW Offset HelpContext2_12 + DW Offset HelpContext2_13 + DW Offset HelpContext2_16 + DW Offset HelpContext2_15 + DW Offset HelpContext2_9 + DW Offset NewLine + DW Offset HelpContext2_31 + DW Offset HelpContext2_32 + DW Offset NewLine + DW Offset HelpContext2_26 + DW Offset NewLine + DW Offset HelpContext2_21 + DW Offset HelpContext2_22 + DW Offset HelpContext2_24 + DW Offset HelpContext2_25 + DW Offset NewLine + DW Offset Divider + DW Offset NewLine + DW Offset HelpGlobal_0 + DW Offset HelpGlobal_1 + DW Offset HelpGlobal_37 + DW Offset HelpGlobal_3 + DW Offset HelpGlobal_4 + DW Offset HelpGlobal_20 + DW Offset HelpGlobal_9 + DW Offset HelpGlobal_22 + DW Offset HelpGlobal_10 + DW Offset HelpGlobal_19 + DW Offset HelpGlobal_11 + DW Offset HelpGlobal_12 + DW Offset HelpGlobal_33 + DW Offset HelpGlobal_13 + DW Offset HelpGlobal_5 + DW Offset HelpGlobal_23 + DW Offset HelpGlobal_6 + DW Offset HelpGlobal_2 + DW Offset HelpGlobal_7 + DW Offset HelpGlobal_8 + DW Offset HelpGlobal_32 + DW Offset NewLine + DW Offset HelpGlobal_17 + DW Offset HelpGlobal_31 + DW Offset HelpGlobal_18 + DW Offset NewLine + DW Offset HelpGlobal_16 + DW Offset HelpGlobal_34 + DW Offset HelpGlobal_35 + DW Offset HelpGlobal_36 + DW Offset HelpGlobal_21 + DW Offset HelpGlobal_14 + DW Offset HelpGlobal_15 + DW Offset NewLine + DW Offset Divider + DW 0 ; End of list. + +HelpContext2_0 DB 31, 0FFh, 1, 139, 0FFh, 17, 134, 0FFh, 1, 138, 0 +HelpContext2_1 DB 31, 0FFh, 1, 132, ' ', 94h, 0AAh, ' ', 0FFh, 1, 145, 0 +HelpContext2_2 DB 31, 0FFh, 1, 137, 0FFh, 17, 143, 0FFh, 1, 150, 0 + +HelpContext2_3 DB 3, 94h, 0AAh, 0ADh, '.', 0 +HelpContext2_10 DB 5, 99h, 0FFh, 7, ' Load new ', 95h, 0 +HelpContext2_4 DB 5, 'Tab', 0FFh, 10, ' ', 9Ch, 0A8h, 'options', 0 +HelpContext2_5 DB 5, 'PgUp/PgDn', 0FFh, 4, ' ', 9Ch, 0B7h, '(when not on list)', 0 + +HelpContext2_11 DB 5, 80h, 'A', 0FFh, 8, ' Convert Signed to/', 0A9h, 'Unsigned ', 95h, 's', 0 +HelpContext2_23 DB 5, 80h, 'B', 0FFh, 8, ' Pre-Loop cut ', 95h, 0 +HelpContext2_8 DB 5, 80h, 'C', 0FFh, 8, ' Clear ', 94h, 'Name & Filename (Used in ', 94h, 'Name ', 0B6h, ')', 0 +HelpContext2_6 DB 5, 80h, 'D', 0FFh, 8, ' ', 084h, 94h, 0 +HelpContext2_17 DB 5, 80h, 'E', 0FFh, 8, ' Resize ', 94h, '(', 0A0h, 'interpolation)', 0 +HelpContext2_18 DB 5, 80h, 'F', 0FFh, 8, ' Resize ', 94h, '(without interpolation)', 0 +HelpContext2_27 DB 5, 80h, 'G', 0FFh, 8, ' Reverse ', 94h, 0 +HelpContext2_30 DB 5, 80h, 'H', 0FFh, 8, ' Centralise ', 94h, 0 +HelpContext2_33 DB 5, 80h, 'I', 0FFh, 8, ' Invert ', 94h, 0 +HelpContext2_7 DB 5, 80h, 'L', 0FFh, 8, ' Post-Loop cut ', 95h, 0 +HelpContext2_29 DB 5, 80h, 'M', 0FFh, 8, ' ', 94h, 'amplifier', 0 +HelpContext2_28 DB 5, 80h, 'N', 0FFh, 8, ' ', 9Dh, 'Multi', 0A4h, 'playback', 0 +HelpContext2_14 DB 5, 80h, 'O', 0FFh, 8, ' Save ', 0A2h, 95h, ' ', 0B1h, 'disk (IT Format)', 0 +HelpContext2_19 DB 5, 80h, 'Q', 0FFh, 8, ' ', 9Dh, 95h, ' quality', 0 +HelpContext2_12 DB 5, 80h, 'R', 0FFh, 8, ' Replace ', 0A2h, 95h, ' in song', 0 +HelpContext2_13 DB 5, 80h, 'S', 0FFh, 8, ' Swap ', 95h, ' (in song also)', 0 +HelpContext2_16 DB 5, 80h, 'T', 0FFh, 8, ' Save ', 0A2h, 95h, ' ', 0B1h, 'disk (ST3 Format)', 0 + +IF SAVESAMPLEWAV +HelpContext2_15 DB 5, 80h, 'W', 0FFh, 8, ' Save ', 0A2h, 95h, ' ', 0B1h, 'disk (WAV Format)', 0 +ELSE +HelpContext2_15 DB 5, 80h, 'W', 0FFh, 8, ' Save ', 0A2h, 95h, ' ', 0B1h, 'disk (RAW Format)', 0 +ENDIF + +HelpContext2_9 DB 5, 80h, 'X', 0FFh, 8, ' Ex', 0C9h, 95h, ' (only in ', 94h, 'List)', 0 + +HelpContext2_31 DB 5, 80h, 0C1h, 0FFh, 6, ' ', 83h, 95h, ' ', 91h, 0 +HelpContext2_32 DB 5, 80h, 0C2h, 0FFh, 6, ' Remove ', 95h, ' ', 91h, 0 + +HelpContext2_26 DB 5, '< >', 0FFh, 10, ' ', 93h, '/', 92h, ' playback ', 0A3h, 0 + +HelpContext2_21 DB 5, 80h, 'Grey + ', 92h, 0AEh, 'octave', 0 +HelpContext2_22 DB 5, 80h, 'Grey - ', 93h, 0AEh, 'octave', 0 +HelpContext2_24 DB 5, 81h, 'Grey + ', 92h, 0AEh, 0AFh, 0 +HelpContext2_25 DB 5, 81h, 'Grey - ', 93h, 0AEh, 0AFh, 0 + +HelpContext7Ptrs Label Word + DW Offset HelpContext7_0 + DW Offset HelpContext7_1 + DW Offset HelpContext7_2 + DW Offset NewLine + DW Offset HelpContext7_8 + DW Offset HelpContext7_26 + DW Offset HelpContext7_9 + DW Offset HelpContext7_10 + DW Offset HelpContext7_36 + DW Offset HelpContext7_22 + DW Offset NewLine + DW Offset HelpContext7_25 + DW Offset HelpContext7_24 + DW Offset HelpContext7_23 + DW Offset HelpContext7_28 + DW Offset HelpContext7_11 + DW Offset HelpContext7_12 + DW Offset HelpContext7_13 + DW Offset HelpContext7_14 + DW Offset NewLine + DW Offset HelpContext7_34 + DW Offset HelpContext7_35 + DW Offset NewLine + DW Offset HelpContext7_33 + DW Offset NewLine + DW Offset HelpContext7_3 + DW Offset HelpContext7_4 + DW Offset HelpContext7_5 + DW Offset NewLine + DW Offset HelpContext7_6 + DW Offset HelpContext7_7 + DW Offset HelpContext7_27 + DW Offset HelpContext7_29 + DW Offset HelpContext7_30 + DW Offset NewLine + DW Offset HelpContext7_15 + DW Offset HelpContext7_16 + DW Offset HelpContext7_17 + DW Offset HelpContext7_18 + DW Offset HelpContext7_19 + DW Offset NewLine + DW Offset HelpContext7_20 + DW Offset HelpContext7_21 + DW Offset NewLine + DW Offset Divider + DW Offset NewLine + DW Offset HelpGlobal_0 + DW Offset HelpGlobal_1 + DW Offset HelpGlobal_37 + DW Offset HelpGlobal_3 + DW Offset HelpGlobal_4 + DW Offset HelpGlobal_20 + DW Offset HelpGlobal_9 + DW Offset HelpGlobal_22 + DW Offset HelpGlobal_10 + DW Offset HelpGlobal_19 + DW Offset HelpGlobal_11 + DW Offset HelpGlobal_12 + DW Offset HelpGlobal_33 + DW Offset HelpGlobal_13 + DW Offset HelpGlobal_5 + DW Offset HelpGlobal_23 + DW Offset HelpGlobal_6 + DW Offset HelpGlobal_2 + DW Offset HelpGlobal_7 + DW Offset HelpGlobal_8 + DW Offset HelpGlobal_32 + DW Offset NewLine + DW Offset HelpGlobal_17 + DW Offset HelpGlobal_31 + DW Offset HelpGlobal_18 + DW Offset NewLine + DW Offset HelpGlobal_16 + DW Offset HelpGlobal_34 + DW Offset HelpGlobal_35 + DW Offset HelpGlobal_36 + DW Offset HelpGlobal_21 + DW Offset HelpGlobal_14 + DW Offset HelpGlobal_15 + DW Offset NewLine + DW Offset Divider + + DW 0 ; End of list + +HelpContext7_0 DB 29, 0FFh, 1, 139, 0FFh, 21, 134, 0FFh, 1, 138, 0 +HelpContext7_1 DB 29, 0FFh, 1, 132, ' ', 8Eh, 0AAh, ' ', 0FFh, 1, 145, 0 +HelpContext7_2 DB 29, 0FFh, 1, 137, 0FFh, 21, 143, 0FFh, 1, 150, 0 + +HelpContext7_8 DB 3, 8Eh, 0AAh, 0ADh, ".", 0 +HelpContext7_26 DB 5, 99h, 0FFh, 10, " Load new ", 8Fh, 0 +HelpContext7_9 DB 5, 81h, "PgUp/PgDn ", 9Ch, 8Fh, " ", 0B7h, "(when not on list)", 0 +HelpContext7_10 DB 5, 80h, "C", 0FFh, 11, " Clear ", 8Fh, " name & filename", 0 +HelpContext7_36 DB 5, 80h, "W", 0FFh, 11, ' ', 0CEh, 8Fh, " ", 90h, 0 +HelpContext7_22 DB 5, "Spacebar", 0FFh, 8, " Edit ", 8Fh, " name (ESC ", 0B1h, "exit)", 0 + +HelpContext7_25 DB 5, 80h, 'D', 0FFh, 11, ' ', 084h, 8Fh, ' & all related ', 95h, 's', 0 +HelpContext7_24 DB 5, 80h, 'N', 0FFh, 11, ' ', 9Dh, 'Multi', 0A4h, 'playback', 0 +HelpContext7_23 DB 5, 80h, 'O', 0FFh, 11, ' Save ', 0A2h, 8Fh, ' ', 0B1h, 'disk', 0 +HelpContext7_28 DB 5, 80h, 'P', 0FFh, 11, ' Copy ', 8Fh, 0 +HelpContext7_11 DB 5, 80h, 'R', 0FFh, 11, ' Replace ', 0A2h, 8Fh, ' in song', 0 +HelpContext7_12 DB 5, 80h, 'S', 0FFh, 11, ' Swap ', 08Fh, 's (in song also)', 0 +HelpContext7_13 DB 5, 80h, 'U', 0FFh, 11, ' Update ', 85h, 90h, 0 +HelpContext7_14 DB 5, 80h, 'X', 0FFh, 11, ' Ex', 0C9h, 08Fh, 's (only in ', 08Eh, 'List)', 0 + +HelpContext7_34 DB 5, 80h, 0C1h, 0FFh, 9, ' ', 83h, 8Fh, ' ', 91h, 0 +HelpContext7_35 DB 5, 80h, 0C2h, 0FFh, 9, ' Remove ', 8Fh, ' ', 91h, 0 + +HelpContext7_33 DB 5, '< >', 0FFh, 13, ' ', 93h, '/', 92h, ' playback ', 0A3h, 0 + +HelpContext7_3 DB 3, 0C3h, "Translation.", 0 +HelpContext7_4 DB 5, 99h, 0FFh, 10, " Pickup ", 95h, " number & default play ", 0A5h, 0 +HelpContext7_5 DB 5, "< >", 0FFh, 13, " ", 93h, "/", 92h, " ", 95h, " number", 0 +HelpContext7_6 DB 5, 80h, "A", 0FFh, 11, " ", 0C8h, "all ", 95h, "s", 0 +HelpContext7_7 DB 5, 80h, "N", 0FFh, 11, " ", 99h, 0B4h, 0A5h, 0 +HelpContext7_27 DB 5, 80h, "P", 0FFh, 11, " ", 99h, "previous ", 0A5h, 0 +HelpContext7_29 DB 5, 80h, "Up/Down", 0FFh, 5, " Transpose all notes ", 0BFh, 0AFh, 0B7h, 0 +HelpContext7_30 DB 5, 80h, 0C1h, "/", 0C2h, 0FFh, 5, " ", 9Eh, 0BFh, "row ", 0A9h, "the table", 0 + +HelpContext7_15 DB 3, 'Envelope ', 0ADh, '.', 0 +HelpContext7_16 DB 5, 99h, 0FFh, 10, ' Pick up/Drop ', 0A2h, 'node', 0 +HelpContext7_17 DB 5, 83h, 0FFh, 9, ' Add node', 0 +HelpContext7_18 DB 5, 84h, 0FFh, 9, ' ', 084h, 'node', 0 +HelpContext7_19 DB 5, 80h, 'Arrow ', 0ADh, ' ', 9Ch, 'node (fast)', 0 + +HelpContext7_20 DB 5, 'Press Spacebar ', 9Fh, 'default ', 0A5h, 0 +HelpContext7_21 DB 5, 'Release Space ', 0C3h, 'off command', 0 + +HelpContext9Ptrs Label Word + DW Offset HelpContext9_0 + DW Offset HelpContext9_1 + DW Offset HelpContext9_2 + DW Offset NewLine + DW Offset HelpContext9_3 + DW Offset HelpContext9_4 + DW Offset HelpContext9_11 + DW Offset HelpContext9_5 + DW Offset HelpContext9_6 + DW Offset HelpContext9_7 + DW Offset NewLine + DW Offset HelpContext9_15 + DW Offset HelpContext9_16 + DW Offset NewLine + DW Offset HelpContext9_8 + DW Offset HelpContext9_9 + DW Offset NewLine + DW Offset HelpContext9_10 + DW Offset NewLine + DW Offset HelpContext9_12 + DW Offset HelpContext9_14 + DW Offset NewLine + DW Offset HelpContext9_13 + DW Offset NewLine + DW Offset Divider + DW Offset NewLine + DW Offset HelpGlobal_0 + DW Offset HelpGlobal_1 + DW Offset HelpGlobal_37 + DW Offset HelpGlobal_3 + DW Offset HelpGlobal_4 + DW Offset HelpGlobal_20 + DW Offset HelpGlobal_9 + DW Offset HelpGlobal_22 + DW Offset HelpGlobal_10 + DW Offset HelpGlobal_19 + DW Offset HelpGlobal_11 + DW Offset HelpGlobal_12 + DW Offset HelpGlobal_33 + DW Offset HelpGlobal_13 + DW Offset HelpGlobal_5 + DW Offset HelpGlobal_23 + DW Offset HelpGlobal_6 + DW Offset HelpGlobal_2 + DW Offset HelpGlobal_7 + DW Offset HelpGlobal_8 + DW Offset HelpGlobal_32 + DW Offset NewLine + DW Offset HelpGlobal_17 + DW Offset HelpGlobal_31 + DW Offset HelpGlobal_18 + DW Offset NewLine + DW Offset HelpGlobal_16 + DW Offset HelpGlobal_34 + DW Offset HelpGlobal_35 + DW Offset HelpGlobal_36 + DW Offset HelpGlobal_21 + DW Offset HelpGlobal_14 + DW Offset HelpGlobal_15 + DW Offset NewLine + DW Offset Divider + DW 0 + +HelpContext9_0 DB 33, 0FFh, 1, 139, 0FFh, 13, 134, 0FFh, 1, 138, 0 +HelpContext9_1 DB 33, 0FFh, 1, 132, ' Info Page ', 0FFh, 1, 145, 0 +HelpContext9_2 DB 33, 0FFh, 1, 137, 0FFh, 13, 143, 0FFh, 1, 150, 0 + +HelpContext9_3 DB 3, 83h, 0FFh, 11, ' Add ', 0BFh, 'new ', 0B6h, 0 +HelpContext9_4 DB 3, 84h, 0FFh, 11, ' ', 084h, 0A2h, 0B6h, 0 +HelpContext9_11 DB 3, 'Tab/', 82h, 'Tab', 0FFh, 5, ' ', 9Ch, 0A8h, 0B6h, 's', 0 +HelpContext9_5 DB 3, 'Up/Dn/Left/Right ', 9Ch, 'highlighted ', 0A3h, 0 +HelpContext9_6 DB 3, 'PgUp/PgDn', 0FFh, 9, ' ', 0C8h, 0B6h, ' type', 0 +HelpContext9_7 DB 3, 80h, 'Up/Down', 0FFh, 7, ' ', 9Ch, 0B6h, ' base ', 0B7h, 0 + +HelpContext9_15 DB 3, 'V', 0FFh, 17, ' ', 9Dh, 0A8h, 'volume/velocity bars', 0 +HelpContext9_16 DB 3, 'I', 0FFh, 17, ' ', 9Dh, 0A8h, 95h, '/', 8Fh, ' names', 0 + +HelpContext9_8 DB 3, 'Q', 0FFh, 17, ' Mute/Unmute ', 0A2h, 0A3h, 0 +HelpContext9_9 DB 3, 'S', 0FFh, 17, ' Solo ', 0A2h, 0A3h, 0 + +HelpContext9_10 DB 3, 'Grey +, Grey -', 0FFh, 4, ' ', 9Ch, 'forwards/backwards one ', 85h, 'in song', 0 + +HelpContext9_12 DB 3, 80h, 'S', 0FFh, 13, ' ', 9Dh, 'Stereo playback', 0 +HelpContext9_14 DB 3, 80h, 'R', 0FFh, 13, ' Reverse output ', 0A3h, 's', 0 + +Helpcontext9_13 DB 3, 'G', 0FFh, 17, ' Goto ', 85h, 'currently playing', 0 + +HelpContext12Ptrs Label Word + DW Offset HelpContext12_0 + DW Offset HelpContext12_1 + DW Offset HelpContext12_2 + DW Offset NewLine + DW Offset HelpContext12_3 + DW Offset NewLine + DW Offset HelpContext12_4 + DW Offset HelpContext12_5 + DW Offset HelpContext12_6 + DW Offset NewLine + DW Offset Divider + DW Offset NewLine + DW Offset HelpGlobal_0 + DW Offset HelpGlobal_1 + DW Offset HelpGlobal_37 + DW Offset HelpGlobal_3 + DW Offset HelpGlobal_4 + DW Offset HelpGlobal_20 + DW Offset HelpGlobal_9 + DW Offset HelpGlobal_22 + DW Offset HelpGlobal_10 + DW Offset HelpGlobal_19 + DW Offset HelpGlobal_11 + DW Offset HelpGlobal_12 + DW Offset HelpGlobal_33 + DW Offset HelpGlobal_13 + DW Offset HelpGlobal_5 + DW Offset HelpGlobal_23 + DW Offset HelpGlobal_6 + DW Offset HelpGlobal_2 + DW Offset HelpGlobal_7 + DW Offset HelpGlobal_8 + DW Offset HelpGlobal_32 + DW Offset NewLine + DW Offset HelpGlobal_17 + DW Offset HelpGlobal_31 + DW Offset HelpGlobal_18 + DW Offset NewLine + DW Offset HelpGlobal_16 + DW Offset HelpGlobal_34 + DW Offset HelpGlobal_35 + DW Offset HelpGlobal_36 + DW Offset HelpGlobal_21 + DW Offset HelpGlobal_14 + DW Offset HelpGlobal_15 + DW Offset NewLine + DW Offset Divider + DW 0 + +HelpContext12_0 DB 31, 0FFh, 1, 139, 0FFh, 18, 134, 0FFh, 1, 138, 0 +HelpContext12_1 DB 31, 0FFh, 1, 132, ' Message Editor ', 0FFh, 1, 145, 0 +HelpContext12_2 DB 31, 0FFh, 1, 137, 0FFh, 18, 143, 0FFh, 1, 150, 0 + +HelpContext12_3 DB 3, 99h, '/ ESC', 0FFh, 5, ' Edit message / finished editing', 0 + +HelpContext12_4 DB 3, 'Editing ', 0ADh, '.', 0 +HelpContext12_5 DB 5, 81h, 'Y', 0FFh, 8, ' ', 084h, 'line', 0 +HelpContext12_6 DB 5, 80h, 'C', 0FFh, 9, ' Clear message', 0 + +; + +DecodeWord80h DB "Alt-", 0 +DecodeWord81h DB "Ctrl-", 0 +DecodeWord82h DB "Shift-", 0 +DecodeWord83h DB 0C1h, "ert ", 0 +DecodeWord84h DB 0C2h, "ete ", 0 +DecodeWord85h DB "pattern ", 0 +DecodeWord86h DB "Pattern ", 0 +DecodeWord87h DB 0A7h, "up ", 0B0h, "x", 0 +DecodeWord88h DB 0A7h, "down ", 0B0h, "x", 0 +DecodeWord89h DB "Volume ", 0 +DecodeWord8Ah DB "volume ", 0 +DecodeWord8Bh DB " Fine ", 0 +DecodeWord8Ch DB "envelope", 0 +DecodeWord8Dh DB "Channel ", 0 +DecodeWord8Eh DB 0C1h, "trument ", 0 +DecodeWord8Fh DB "instrument", 0 +DecodeWord90h DB "data", 0 +DecodeWord91h DB "slot (updates ", 85h, 90h, ")", 0 +DecodeWord92h DB "Increase", 0 +DecodeWord93h DB "Decrease", 0 +DecodeWord94h DB "Sample ", 0 +DecodeWord95h DB "sample", 0 +DecodeWord96h DB " ", 0A6h, "NNA ", 0B1h, 0 +DecodeWord97h DB "Tempo ", 0 +DecodeWord98h DB "clipboard ", 0 +DecodeWord99h DB "Enter ", 0 +DecodeWord9Ah DB "waveform ", 0B1h, "type x", 0 +DecodeWord9Bh DB " Dual Command: ", 0 +DecodeWord9Ch DB "Move ", 0 +DecodeWord9Dh DB "Toggle ", 0 +DecodeWord9Eh DB 0C1h, "ert/", 0C2h, "ete ", 0 +DecodeWord9Fh DB "Play ", 0 +DecodeWordA0h DB "with ", 0 +DecodeWordA1h DB "and ", 0 +DecodeWordA2h DB "current ", 0 +DecodeWordA3h DB "channel", 0 +DecodeWordA4h DB 0A3h, ' ', 0 +DecodeWordA5h DB "note ", 0 +DecodeWordA6h DB "Set ", 0 +DecodeWordA7h DB "slide ", 0 +DecodeWordA8h DB "between ", 0 +DecodeWordA9h DB "from ", 0 +DecodeWordAAh DB "List ", 0 +DecodeWordABh DB "Library ", 0 +DecodeWordACh DB "Turn ", 0 +DecodeWordADh DB "Keys", 0 +DecodeWordAEh DB ' C-5 Frequency by 1 ', 0 +DecodeWordAFh DB 'semitone ', 0 +DecodeWordB0h DB "by ", 0 +DecodeWordB1h DB "to ", 0 +DecodeWordB2h DB "lobal ", 0 +DecodeWordB3h DB "ibra", 0B1h, 0 +DecodeWordB4h DB "next ", 0 +DecodeWordB5h DB "panning ", 0 +DecodeWordB6h DB "window", 0 +DecodeWordB7h DB "up/down ", 0 +DecodeWordB8h DB "Panning ", 0 +DecodeWordB9h DB "Order ", 0 +DecodeWordBAh DB "Pitch ", 0 +DecodeWordBBh DB "pitch ", 0 +DecodeWordBCh DB "Slide ", 0 +DecodeWordBDh DB "effect", 0 +DecodeWordBEh DB "of ", 0 +DecodeWordBFh DB "a ", 0 +DecodeWordC0h DB " Past ", 0 +DecodeWordC1h DB "Ins", 0 +DecodeWordC2h DB "Del", 0 +DecodeWordC3h DB "Note ", 0 +DecodeWordC4h DB "speed ", 0 +DecodeWordC5h DB 0C4h, "x, ", 0C6h, "y", 0 +DecodeWordC6h DB "depth ", 0 +DecodeWordC7h DB "Next/Previous ", 0 +DecodeWordC8h DB "Change ", 0 +DecodeWordC9h DB "change ", 0 +DecodeWordCAh DB "Mark ", 0 +DecodeWordCBh DB "track ", 0 +DecodeWordCCh DB "block ", 0 +DecodeWordCDh DB " (*)", 0 +DecodeWordCEh DB "Wipe ", 0 + +; channel, pitch, column, effect, note, current, list, library +; speed/width, turn, on, off, down, instrument +; semitone, octave, block, edit, save, (g)lobal, (v)ibrato, (p)anbrello +; cursor, window + +DecodeBuffer DB 80 Dup (0) +DecodeWords DW Offset DecodeWord80h, Offset DecodeWord81h + DW Offset DecodeWord82h, Offset DecodeWord83h + DW Offset DecodeWord84h, Offset DecodeWord85h + DW Offset DecodeWord86h, Offset DecodeWord87h + DW Offset DecodeWord88h, Offset DecodeWord89h + DW Offset DecodeWord8Ah, Offset DecodeWord8Bh + DW Offset DecodeWord8Ch, Offset DecodeWord8Dh + DW Offset DecodeWord8Eh, Offset DecodeWord8Fh + DW Offset DecodeWord90h, Offset DecodeWord91h + DW Offset DecodeWord92h, Offset DecodeWord93h + DW Offset DecodeWord94h, Offset DecodeWord95h + DW Offset DecodeWord96h, Offset DecodeWord97h + DW Offset DecodeWord98h, Offset DecodeWord99h + DW Offset DecodeWord9Ah, Offset DecodeWord9Bh + DW Offset DecodeWord9Ch, Offset DecodeWord9Dh + DW Offset DecodeWord9Eh, Offset DecodeWord9Fh + DW Offset DecodeWordA0h, Offset DecodeWordA1h + DW Offset DecodeWordA2h, Offset DecodeWordA3h + DW Offset DecodeWordA4h, Offset DecodeWordA5h + DW Offset DecodeWordA6h, Offset DecodeWordA7h + DW Offset DecodeWordA8h, Offset DecodeWordA9h + DW Offset DecodeWordAAh, Offset DecodeWordABh + DW Offset DecodeWordACh, Offset DecodeWordADh + DW Offset DecodeWordAEh, Offset DecodeWordAFh + DW Offset DecodeWordB0h, Offset DecodeWordB1h + DW Offset DecodeWordB2h, Offset DecodeWordB3h + DW Offset DecodeWordB4h, Offset DecodeWordB5h + DW Offset DecodeWordB6h, Offset DecodeWordB7h + DW Offset DecodeWordB8h, Offset DecodeWordB9h + DW Offset DecodeWordBAh, Offset DecodeWordBBh + DW Offset DecodeWordBCh, Offset DecodeWordBDh + DW Offset DecodeWordBEh, Offset DecodeWordBFh + DW Offset DecodeWordC0h, Offset DecodeWordC1h + DW Offset DecodeWordC2h, Offset DecodeWordC3h + DW Offset DecodeWordC4h, Offset DecodeWordC5h + DW Offset DecodeWordC6h, Offset DecodeWordC7h + DW Offset DecodeWordC8h, Offset DecodeWordC9h + DW Offset DecodeWordCAh, Offset DecodeWordCBh + DW Offset DecodeWordCCh, Offset DecodeWordCDh + DW Offset DecodeWordCEh + +;Ŀ +; Functions +; + +Proc H_DrawHelp Far + + Push CS + Pop DS + + Push CS + Pop ES + + Assume DS:Help + + Mov CX, 32 + Mov SI, HelpContext + Add SI, SI + Mov SI, [HelpContextPtrs+SI] + Mov DI, 13*160 + + Mov AX, TopLine + Add AX, AX + Add SI, AX + +H_DrawHelp1: + Push SI + Push DI + + Mov SI, [SI] + LodsB + Xor AH, AH + Add AX, AX + Add DI, AX + +; DS:SI points to string. Deposit into buffer + + Push DI + Mov DI, Offset DecodeBuffer + + Mov DX, 1 + +H_DecodeBuffer1: + LodsB + Test AL, AL + JZ H_DecodeBuffer4 + JS H_DecodeBuffer2 + + StosB + Jmp H_DecodeBuffer1 + +H_DecodeBuffer2: + Cmp AL, -2 + JGE H_DecodeBuffer3 + + ; Insert word + Push SI + LEA SI, [EAX*2 + Offset DecodeWords - 100h] + Inc DX + Mov SI, [SI] + Jmp H_DecodeBuffer1 + +H_DecodeBuffer3: + StosB + JE H_DecodeBuffer1 + MovsB + MovsB + Jmp H_DecodeBuffer1 + +H_DecodeBuffer4: + Dec DX + JZ H_DecodeBufferEnd + + Pop SI + Jmp H_DecodeBuffer1 + +H_DecodeBufferEnd: + Xor AL, AL + StosB + Pop DI + + Mov SI, Offset DecodeBuffer + Mov AH, 6 + Call S_DrawString + + Pop DI + Pop SI + LodsW ; Add SI, 2 + Add DI, 160 + Cmp Word Ptr [SI], 0 + LoopNZ H_DrawHelp1 + + Ret + +EndP H_DrawHelp + Assume DS:Nothing + +; + +Proc H_Help Far + + Call Glbl_SaveMode + + Mov BX, CS:HelpContext + Add BX, BX + Mov AX, [CS:Positions+BX] + + Mov CS:TopLine, AX + + Mov AX, 5 + Mov CX, Object1 + Mov DX, Offset O1_HelpList + Mov SI, 1 + + Ret + +EndP H_Help + +; + +Proc H_HelpUp Far + + Sub CS:TopLine, 1 + AdC CS:Topline, 0 + + Mov AX, 1 + Ret + +EndP H_HelpUp + +; + +Proc H_HelpDown Far + + Push CX + + Push CS + Pop DS + Assume DS:Help + + Mov SI, HelpContext + Add SI, SI + Mov SI, [HelpContextPtrs+SI] + Mov BX, TopLine + Add BX, BX + Add SI, BX + Mov CX, 32 + +H_HelpDown2: + Add SI, 2 + Cmp Word Ptr [SI], 0 + LoopNZ H_HelpDown2 + JZ H_HelpDown1 + + Inc TopLine + +H_HelpDown1: + Pop CX + + Mov AX, 1 + Ret + +EndP H_HelpDown + Assume DS:Nothing + +; + +Proc H_HelpPgUp Far + + Mov AX, CS:TopLine + Sub AX, 32 + JNS H_HelpPgUp1 + + Xor AX, AX +H_HelpPgUp1: + Mov CS:TopLine, AX + + Mov AX, 1 + Ret + +EndP H_HelpPgUp + +; + +Proc H_HelpPgDn Far + + Mov CX, 32 + +H_HelpPgDn1: + Call H_HelpDown + Loop H_HelpPgDn1 + + Ret ; AX = 1, set by H_HelpDown + +EndP H_HelpPgDn + +; + +Proc H_HelpESC Far + + Mov AX, CS:TopLine + Mov BX, CS:HelpContext + Add BX, BX + + Mov [CS:Positions+BX], AX + + Jmp Glbl_RestoreMode + +EndP H_HelpESC + +; + +Proc H_SetHelpContext Far + + Mov AX, [SI+2] + Mov CS:HelpContext, AX + + Ret + +EndP H_SetHelpContext + +; + +EndS + +; + +End diff --git a/it/IT_I.ASM b/it/IT_I.ASM new file mode 100644 index 0000000..a9e4f49 --- /dev/null +++ b/it/IT_I.ASM @@ -0,0 +1,9023 @@ +;Ŀ +; Instrument List module +; + + Jumps + .386 + +include switch.inc +include network.inc + +;Ŀ +; Externals +; + +Segment Object1 BYTE Public 'Data' + Extrn SampleFrequency:Word +EndS + +Segment DiskData PARA Public 'Data' +EndS + +Segment Pattern BYTE Public 'Code' + Extrn BaseOctave:Byte + Extrn LastInstrument:Byte +EndS + + Extrn F_Reset5NumInputPos:Far + Extrn Glbl_F4_2:Far + + Extrn Glbl_GetCurrentMode:Far + Extrn S_GetDestination:Far + Extrn S_SaveScreen:Far + Extrn S_RestoreScreen:Far + Extrn S_DrawString:Far + Extrn M_FunctionDivider:Far + Extrn M_Object1List:Far + Extrn M_Object1ListDefault:Far + Extrn Music_GetSongSegment:Far + Extrn Music_ReleaseSample:Far + Extrn Music_ClearSampleName:Far + Extrn Music_PlaySample:Far + Extrn Music_GetInstrumentMode:Far +; Extrn Music_UpdateSampleLocation:Far + + Extrn S_GetGenerationTableOffset:Far + Extrn S_GenerateCharacters:Far + Extrn S_SetDirectMode:Far + Extrn S_DrawBox:Far + Extrn S_DrawSmallBox:Far + + Extrn O1_ConfirmDeleteSample:Far + Extrn O1_ConfirmConvertList:Far + Extrn O1_ConfirmConvert2List:Far + Extrn O1_ConfirmCutSample:Far + Extrn O1_ExchangeSampleList:Far + Extrn O1_ExchangeInstrumentList:Far + Extrn O1_SwapSampleList:Far + Extrn O1_SwapInstrumentList:Far + Extrn O1_ReplaceSampleList:Far + Extrn O1_ReplaceInstrumentList:Far + Extrn O1_ResizeSampleList:Far + Extrn O1_ShowSampleFrequencyList:Far + Extrn O1_FrequencyIndeterminedList:Far + Extrn O1_ConfirmDeleteInstrument:Far + Extrn O1_SampleAmplificationList:Far + Extrn O1_CopyInstrumentList:Far + Extrn O1_SampleCenterList:Far + + Extrn O1_InstrumentListGeneral:Far + Extrn O1_InstrumentListVolume:Far + Extrn O1_InstrumentListPanning:Far + Extrn O1_InstrumentListPitch:Far + Extrn O1_C5FrequencyList:Far + Extrn O1_GetInstrumentAmpList:Far + + Extrn PE_GetLastInstrument:Far + Extrn PE_SwapInstruments:Far + Extrn PE_UpdateInstruments:Far + Extrn PEFunction_OutOfMemoryMessage:Far + Extrn PE_TranslateMIDI:Far, PE_RestoreMIDINote:Far + Extrn PE_InsertInstrument:Far + Extrn PE_DeleteInstrument:Far + + Extrn Music_PlayPattern:Far + Extrn Music_Stop:Far + Extrn Music_PlaySong:Far + Extrn Music_PlayNote:Far + Extrn Music_ToggleChannel:Far + Extrn Music_SoloChannel:Far + Extrn Music_GetSampleLocation:Far + Extrn Music_ClearInstrument:Far + Extrn Music_GetInstrumentMode:Far + Extrn Music_AllocateSample:Far + Extrn Music_GetSlaveChannelInformationTable:Far + Extrn Music_SoundCardLoadAllSamples:Far + Extrn Music_GetNumChannels:Far + + Extrn Music_RegetLoopInformation:Far + + Extrn SetInfoLine:Far + + Extrn MouseAddEvent:Far, AddMouseQueue:Far, MouseClearEvents:Far + Extrn SetKeyboardLock:Far, MouseSetXY:Far + Extrn MouseRemoveEvents:Far, MouseGetStatus:Far + Extrn SetMouseCursorType:Far + + Extrn Fourier_Transform:Far, Fourier_CreateTable:Far + + +;Ŀ +; Globals +; + + Global I_DrawPitchPanCenter:Far + Global I_PrePitchPanCenter:Far + Global I_PostPitchPanCenter:Far + + Global I_ClearTables:Far + Global I_TagInstrument:Far + Global I_TagSample:Far + + Global I_DrawEnvelope:Far + Global I_PreEnvelope:Far + Global I_PostEnvelope:Far + + Global I_ConvertSample:Far + Global I_DeleteSample:Far + Global I_CutSample:Far + Global I_ClearSampleName:Far + Global I_ExchangeSamples:Far + Global I_ReplaceInstrument:Far + Global I_ToggleSampleQuality:Far + Global I_CenterSample:Far + + Global I_InstrumentListSpace:Far + Global I_InstrumentListNoteOff:Far + Global I_IncreasePlayChannel:Far + Global I_DecreasePlayChannel:Far + Global I_ToggleMultiChannel:Far + + Global I_ScaleInstrumentVolumes:Far + Global I_ScaleSampleVolumes:Far + Global I_CopyInstrument:Far + Global I_DeleteInstrument:Far + Global I_DrawSampleList:Far + Global I_PreSampleList:Far + Global I_PostSampleList:Far + Global I_ShowSampleInfo:Far + Global I_SampleUp:Far + Global I_SampleDown:Far + Global I_CheckLoopValues:Far + Global I_CheckSusLoopValues:Far + Global I_MapEnvelope:Far + Global I_DrawWaveForm:Far + Global I_SampleButtonHandler:Far + + Global I_DrawInstrumentWindow:Far + Global I_PreInstrumentWindow:Far + Global I_PostInstrumentWindow:Far + + Global I_DrawNoteWindow:Far + Global I_PreNoteWindow:Far + Global I_PostNoteWindow:Far + + Global I_AmplifySample:Far + Global I_ExchangeInstruments:Far + Global I_ReverseSample:Far + Global I_SwapSamples:Far + Global I_SwapInstruments:Far + Global I_ReplaceSample:Far + Global I_UpdateInstrument:Far + Global I_ResizeSample:Far + Global I_ResizeSampleNoInt:Far + Global I_InvertSample:Far + + Global I_GetInstrumentOffset:Far + Global I_GetSampleOffset:Far + Global I_CutSampleBeforeLoop:Far + + Global I_CalculateC5Speed:Far + Global I_PrintC5Frequency:Far + + Global I_DoubleSampleSpeed:Far + Global I_HalveSampleSpeed:Far + Global I_SampleSpeedSemiUp:Far + Global I_SampleSpeedSemiDown:Far + + Global I_ShowSamplePlay:Far + Global I_ShowInstrumentPlay:Far + + Global I_PlaySample:Far + Global I_SelectScreen:Far + + Global I_GetInstrumentScreen:Far + Global I_IdleUpdateEnvelope:Far + + Global I_PlayNote:Far + + Global SampleNumberInput:Byte + Global SampleNumber:Byte + + Global MaxNode:Word + Global NewSampleSize:DWord + Global SampleAmplification:Word + + Global InstrumentEdit:Byte + Global NodeHeld:Byte + Global InstrumentScreen:Word + + Global I_GetPresetEnvelopeOffset:Far + + Public UpdateWAVEForm + Public MIDI_PlayNote, MIDI_NoteOff, MIDI_ClearTable + Public MIDI_PlaySample, MIDI_FindChannel, MIDI_AllocateChannel + Public MIDI_GetChannel + + Global InstrumentAmplification + +; + +Segment Inst WORD Public 'Code' USE16 + Assume CS:Inst, DS:Nothing + +;Ŀ +; Variables +; + +SLAVECHANNELSIZE EQU 128 +HOSTCHANNELSIZE EQU 80 +ENVELOPEGRANULARITY EQU 50 +MAXENVELOPETICK EQU 9999 + +InstrumentAmplification DW 50 +InstrumentScreen DW 0 + +LastPlaySample DB 5*12 +SampleNumber DB 1 ; For instrument-sample + ; editing + +NoteReleased DB 1 +TopInstrument DW 1 +InstrumentPos DW 0 + +SamplePlayTable DB 128 Dup (0) +InstrumentPlayTable DB 128 Dup (0) + +TopNote DW 0 +CurrentNote DW 0 +NotePos DW 0 ; 0->4 + +SampleNumberInput DB 0 + DB 3 Dup(0) + +NewSampleSize DD 0 + +CurrentNode DW 0 ; Volume envelope +MaxNode DW 0 + +AmplitudeCompensate DB 0 + DB 0 ; Filler +CurrentAmplitude DW 0 +CurrentTick DW 0 +LastAmplitude DW 0 +LastTick DW 0 +UpperLimit DW 0 + +NodeHeld DB 0 + DB 0 +WaveLength DW 0 +SearchDirection DW 0 +EndPoint DW 0 + +InstrumentEdit DB 0 +LastKey DW 0 + +Interpolate DB 0 ; For resizing routines +Quality DB 0 +MultiChannel DB 0 + +PlayChannel DW 0 +SampleAmplification DW 0 ; Percentage + +MIDITable DB 128 Dup (0) ; Contains channel of each note + +NoteData DB 0, 0, 0FFh, 0, 0 ; For noteplay in notelist + +PlayNote DB 5*12 + +NotePosTable DB 4, 6, 8, 9 +SamplePos DW 25 + +Resolution DB 0 +UpdateInstrumentScreen DB 1 + +CompleteMsg DB 0FDh, "D% Complete", 0 +TopSample DW 1 +NoSampleMsg DB "No sample", 0 +Quality8Msg DB "8 bits", 0 +Quality16Msg DB "16 bits", 0 +LengthMsg DB 0FDh, 'L', 0 + +EnvelopeSetMsg DB "Envelope copied into slot ", 0FDh, "D", 0 + +EnvelopeMsg DB "Node ", 0FDh, "D/", 0FDh, "D", 13, 13 + DB "Tick ", 0FDh, "D", 13, 13 + DB "Value ", 0FDh, "S", 0 + +PlayChannelMsg DB "Using channel ", 0FDh, "D for playback", 0 + +MultiChannelEnabledMsg DB "Multichannel playback enabled", 0 +MultiChannelDisabledMsg DB "Multichannel playback disabled", 0 + +C5FrequencyText DB "Calculated C5Speed: ", 0FDh, "L", 0 + +LastWaveformValues DW 0 + +EnvelopeHeaderTable Label + DW Offset VolEnv, Offset VolEnvEdit + DW Offset PanEnv, Offset PanEnvEdit + DW Offset PitchEnv, Offset PitchEnvEdit + +VolEnv DB "Volume Envelope", 0 +VolEnvEdit DB "Volume Envelope (Edit)", 0 +PanEnv DB "Panning Envelope", 0 +PanEnvEdit DB "Panning Envelope (Edit)", 0 +PitchEnv DB "Frequency Envelope", 0 +PitchEnvEdit DB "Frequency Envelope (Edit)", 0 + +EnvelopeOffsets Label Word + DW 130h, 182h, 1D4h + +NoteTable DB "C-C#D-D#E-F-F#G-G#A-A#B-" +KeyBoardTable DW 12Ch, 0, 11Fh, 1, 12Dh, 2, 120h, 3, 12Eh, 4 + DW 12Fh, 5, 122h, 6, 130h, 7, 123h, 8, 131h, 9 + DW 124h, 10, 132h, 11, 110h, 12, 103h, 13, 111h, 14 + DW 104h, 15, 112h, 16, 113h, 17, 106h, 18, 114h, 19 + DW 107h, 20, 115h, 21, 108h, 22, 116h, 23, 117h, 24 + DW 10Ah, 25, 118h, 26, 10Bh, 27, 119h, 28, 0FFFFh + +SampleMouseEvent DW 5*8, 13*8, 35*8-1, 48*8-1 +SampleMouseCondition DW 102h, 28, Offset MouseSelectInst, Inst +SampleMouseOffEvent DW 0, 0, 0, 0, 1108h, 28, MouseSelectOff, Inst +NoteMouseEvent DW 32*8, 16*8, 42*8-1, 48*8-1 +NoteMouseCondition DW 102h, 10, Offset MouseSelectNote, Inst +NoteMouseOffEvent DW 0, 0, 0, 0, 1108h, 10, MouseSelectNoteOff, Inst + +ENVELOPELEFT EQU 32 +ENVELOPETOP EQU 18 + +MouseNodeHeld DB 0 + +MouseX DW 0 +MouseY DW 0 +LowerTickLimit DW 0 +UpperTickLimit DW 0 + +EnvelopeEvent1 DW ENVELOPELEFT*8, ENVELOPETOP*8 + DW (ENVELOPELEFT+32)*8-1, (ENVELOPETOP+8)*8-1 + DW 102h, 10, Offset MouseEnvelopeEvent1, Inst +EnvelopeEvent4 DW ENVELOPELEFT*8, ENVELOPETOP*8 + DW (ENVELOPELEFT+32)*8-1, (ENVELOPETOP+8)*8-1 + DW 110h, 10, Offset MouseEnvelopeEvent4, Inst +EnvelopeEvent2 DW 0, 0, 0, 0, 1005h, 10, Offset MouseEnvelopeEvent2, Inst +EnvelopeEvent3 DW 0, 0, 0, 0, 1108h, 10, Offset MouseEnvelopeEvent3, Inst + ; Release + +PresetEnvelopes Label Byte + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + DB 0, 2, 0, 0, 0, 0, 32, 0, 0, 32, 100, 0, 69 Dup (0) + +; + +InstrumentScreenTable Label + DW Offset O1_InstrumentListGeneral + DW Offset O1_InstrumentListVolume + DW Offset O1_InstrumentListPanning + DW Offset O1_InstrumentListPitch + +; + +SampleListKeys Label + DB 0 ; Mouse left button + DW 8010h + DW Offset I_SelectInstrument + + DB 0 ; 0 = CX, 1 = DX, 2 = Alt CX, 3 = Ctrl + DW 1C8h + DW Offset I_SampleUp + + DB 0 + DW 1D0h + DW Offset I_SampleDown + + DB 0 + DW 1C9h + DW Offset I_SamplePgUp + + DB 0 + DW 1D1h + DW Offset I_SamplePgDn + + DB 3 + DW 1C9h + DW Offset I_SampleCtrlPgUp + + DB 3 + DW 1D1h + DW Offset I_SampleCtrlPgDn + + DB 2 + DW 1D2h ; Alt Ins + DW Offset I_InsertSample + + DB 2 + DW 1D3h ; Alt Del + DW Offset I_RemoveSample + + DB 0 + DW 1CBh + DW Offset I_SampleLeft + + DB 0 + DW 1CDh + DW Offset I_SampleRight + + DB 0 + DW 1C7h + DW Offset I_SampleHome + + DB 0 + DW 1CFh + DW Offset I_SampleEnd + + DB 0 + DW 10Fh + DW Offset I_SampleTab + + DB 1 ; Alt... + DW 2E00h ; 'C' + DW Offset I_ClearSampleName + + DB 0FFh + +InstrumentListKeys Label + DB 0 ; Mouse left button + DW 8010h + DW Offset I_SelectInstrument2 + + DB 0 ; 0 = CX, 1 = DX, 2 = Alt CX, 3 = Ctrl + DW 1C8h + DW Offset I_SampleUp + + DB 0 + DW 1D0h + DW Offset I_SampleDown + + DB 0 + DW 1C9h + DW Offset I_SamplePgUp + + DB 0 + DW 1D1h + DW Offset I_SamplePgDn + + DB 2 + DW 1D2h ; Alt Ins + DW Offset I_InsertInstrument + + DB 2 + DW 1D3h ; Alt Del + DW Offset I_RemoveInstrument + + DB 3 + DW 1C9h + DW Offset I_SampleCtrlPgUp + + DB 3 + DW 1D1h + DW Offset I_SampleCtrlPgDn + + DB 0 + DW 1CBh + DW Offset I_InstrumentLeft + + DB 0 + DW 1CDh + DW Offset I_InstrumentRight + + DB 0 + DW 1C7h + DW Offset I_InstrumentHome + + DB 0 + DW 1CFh + DW Offset I_InstrumentEnd + + DB 0 + DW 10Fh + DW Offset I_InstrumentTab + + DB 4 + DW 10Fh + DW Offset I_InstrumentShiftTab + + DB 1 ; Alt + DW 2E00h ; 'C' + DW Offset I_InstrumentNameClear + + DB 1 ; Alt... + DW 1100h ; 'W' + DW Offset I_InstrumentClear + + DB 0FFh + +NoteListKeys Label + DB 0 + DW 8010h + DW Offset I_SelectNoteMouse + + DB 0 ; 0 = CX, 1 = DX, 2 = Alt CX, 3 = Ctrl + DW 1C8h + DW Offset I_NoteUp + + DB 0 + DW 1D0h + DW Offset I_NoteDown + + DB 0 + DW 1C9h + DW Offset I_NotePgUp + + DB 0 + DW 1D1h + DW Offset I_NotePgDn + + DB 0 + DW 1C7h + DW Offset I_NoteHome + + DB 0 + DW 1CFh + DW Offset I_NoteEnd + + DB 0 + DW 1CBh + DW Offset I_NoteLeft + + DB 0 + DW 1CDh + DW Offset I_NoteRight + + DB 0 + DW 10Fh + DW Offset I_NoteTab + + DB 4 + DW 10Fh ; Shift-Tab + DW Offset I_NoteShiftTab + + DB 1 + DW '>' + DW Offset I_NoteSampleIncrease + + DB 1 + DW "'" + DW Offset I_NoteSampleIncrease + + DB 1 + DW '<' + DW Offset I_NoteSampleDecrease + + DB 1 + DW ';' + DW Offset I_NoteSampleDecrease + + DB 1 ; Alt... + DW 1E00h ; 'A' + DW Offset I_NoteAll + + DB 1 ; Alt... + DW 3100h ; 'N' + DW Offset I_NoteNext + + DB 1 ; Alt... + DW 1900h ; 'P' + DW Offset I_NotePrevious + + DB 2 ; Alt up + DW 1C8h + DW Offset I_NoteTransposeUp + + DB 2 ; Alt down + DW 1D0h + DW Offset I_NoteTransposeDown + + DB 2 + DW 1D2h ; Alt Ins + DW Offset I_NoteInsert + + DB 2 + DW 1D3h ; Alt Del + DW Offset I_NoteDelete + + DB 1 + DW ' ' + DW Offset I_NoteSpace + + DB 0 + DW 11Ch ; Enter + DW Offset I_NoteSamplePickup + + DB 0FFh + +VolumeEnvelopeKeys Label + DB 0 + DW 8010h + DW Offset I_MouseEnvelopePress + + DB 0 + DW 8001h + DW Offset I_MouseEnvelopeDrag + + DB 0 + DW 8002h + DW Offset I_MouseEnvelopeReleased + + DB 0 + DW 8003h + DW Offset I_MouseEnvelopeDelete + + DB 0 + DW 10Fh ; Tab + DW Offset I_NoteShiftTab + + DB 4 ; Shifttab + DW 10Fh + DW Offset I_NoteShiftTab + + DB 0 + DW 1CBh + DW Offset I_VolumeEnvelopeLeft + + DB 0 + DW 1CDh + DW Offset I_VolumeEnvelopeRight + + DB 0 ; Enter + DW 11Ch + DW Offset I_VolumeEnvelopeEnter + + DB 0 ; Up arrow + DW 1C8h + DW Offset I_VolumeEnvelopeUp + + DB 0 ; Up arrow + DW 1D0h + DW Offset I_VolumeEnvelopeDown + + DB 0 + DW 1D2h + DW Offset I_VolumeEnvelopeInsert + + DB 0 + DW 1D3h + DW Offset I_VolumeEnvelopeDelete + + DB 0FFh + +VolumeEnvelopeNodeKeys Label + DB 0 + DW 8010h + DW Offset I_MouseEnvelopePress + + DB 0 + DW 8001h + DW Offset I_MouseEnvelopeDrag + + DB 0 + DW 8002h + DW Offset I_MouseEnvelopeReleased + + DB 0 + DW 8003h + DW Offset I_MouseEnvelopeDelete + + DB 0 ; Enter + DW 11Ch + DW Offset I_VolumeEnvelopeEnter + + DB 0 + DW 1C8h ; Up arrow + DW Offset I_VolumeEnvelopeHeldUp + + DB 0 + DW 1D0h ; Down arrow + DW Offset I_VolumeEnvelopeHeldDown + + DB 2 + DW 1C8h + DW Offset I_VolumeEnvelopeHeldPgUp + + DB 2 + DW 1D0h + DW Offset I_VolumeEnvelopeHeldPgDn + + DB 0 + DW 1CBh + DW Offset I_VolumeEnvelopeHeldLeft + + DB 0 + DW 1CDh + DW Offset I_VolumeEnvelopeHeldRight + + DB 0 + DW 10Fh + DW Offset I_VolumeEnvelopeHeldRightFast + + DB 4 + DW 10Fh + DW Offset I_VolumeEnvelopeHeldLeftFast + + DB 2 + DW 1CBh + DW Offset I_VolumeEnvelopeHeldLeftFast + + DB 2 + DW 1CDh + DW Offset I_VolumeEnvelopeHeldRightFast + + DB 0 + DW 1C9h + DW Offset I_VolumeEnvelopeHeldPgUp + + DB 0 + DW 1D1h + DW Offset I_VolumeEnvelopeHeldPgDn + + DB 0 + DW 1C7h + DW Offset I_VolumeEnvelopeHeldHome + + DB 0 + DW 1CFh + DW Offset I_VolumeEnvelopeHeldEnd + + DB 0 + DW 1D2h + DW Offset I_VolumeEnvelopeInsert + + DB 0 + DW 1D3h + DW Offset I_VolumeEnvelopeDelete + + DB 3 + DW 1CBh + DW Offset I_VolumeEnvelopeLeft + + DB 3 + DW 1CDh + DW Offset I_VolumeEnvelopeRight + + DB 0FFh + +PitchPanCenterKeys Label + DB 0 + DW 10Fh ; Tab + DW Offset I_NoteShiftTab + + DB 4 ; Shifttab + DW 10Fh + DW Offset I_NoteShiftTab + + DB 0 + DW 1C8h ; Up arrow + DW Offset I_PitchPanCenterUp + + DB 0 + DW 1D0h ; Down arrow + DW Offset I_PitchPanCenterDown + + DB 1 + DW '+' + DW Offset I_PitchPanCenterSemiUp + + DB 1 + DW '-' + DW Offset I_PitchPanCenterSemiDown + + DB 0 + DW 1CBh + DW Offset I_PitchPanCenterSemiDown + + DB 0 + DW 1CDh + DW Offset I_PitchPanCenterSemiUp + + DB 0FFh + +;Ŀ +; Functions +; + +; + +Proc I_GetInstrumentScreen Far + + Push CS + Pop ES + Mov DI, Offset InstrumentScreen + + Ret + +EndP I_GetInstrumentScreen + +; + +Proc I_GetInstrumentOffset Far + + Call PE_GetLastInstrument + Add BX, BX + Call Music_GetSongSegment + Mov DS, AX + Mov BX, [DS:64712+BX] + + Ret + +EndP I_GetInstrumentOffset + +; + +Proc I_GetSampleOffset Far + + Call PE_GetLastInstrument + Add BX, BX + Call Music_GetSongSegment + Mov DS, AX + Mov BX, [DS:64912+BX] + + Ret + +EndP I_GetSampleOffset + +; + +Proc I_GetEnvelopeOffset ; Returns DS:SI + + Push AX + Call I_GetInstrumentOffset ; Returns DS:BX + Mov SI, CS:InstrumentScreen + Add SI, SI + Mov SI, [SI+EnvelopeOffsets-2] + Add SI, BX + Pop AX + + Ret + +EndP I_GetEnvelopeOffset + +; + +Proc I_SelectScreen Far + + Mov BX, [SI+22] + + Push CS + Pop DS + Assume DS:Inst + + Mov InstrumentScreen, BX + + Mov AX, [ES:DI] + + Add BX, BX + Mov BX, [CS:InstrumentScreenTable+BX] + Mov [ES:BX], AX + + Jmp Glbl_F4_2 + +EndP I_SelectScreen + +; + +Proc MouseSelectOff Far + + Mov Word Ptr [SI-16+8], 102h + Mov CS:SampleMouseCondition, 102h + Mov AX, 1 + + Ret + +EndP MouseSelectOff + +; + +Proc MouseSelectNoteOff Far + + Mov Word Ptr [SI-16+8], 102h + Mov CS:NoteMouseCondition, 102h + Mov AX, 1 + Ret + +EndP MouseSelectNoteOff + +; + +Proc MouseSelectNote Far + + Mov CS:NoteMouseCondition, 1107h + + Push CX + Mov CX, 8010h + Call AddMouseQueue + Pop CX + + Cmp DX, 16*8 + JA MouseSelectNote1 + + Mov DX, 16*8 + +MouseSelectNote1: + Cmp DX, 48*8-1 + JB MouseSelectNote2 + + Mov DX, 48*8-1 + +MouseSelectNote2: + Call MouseSetXY + + Xor AX, AX + Ret + +EndP MouseSelectNote + +; + +Proc MouseSelectInst Far + + Mov CS:MouseX, CX + + Mov CS:SampleMouseCondition, 1107h + + Push CX + + Mov CX, 8010h + ShR DX, 3 + Sub DX, 13 + Call AddMouseQueue + + Pop CX + And DX, DX + JNS MouseSelectInst1 + + Mov DX, 13*8 + Jmp MouseSelectInst2 + +MouseSelectInst1: + Cmp DX, 35 + JB MouseSelectInst3 + + Mov DX, 48*8-1 + +MouseSelectInst2: + Call MouseSetXY + +MouseSelectInst3: + Xor AX, AX + Ret + +EndP MouseSelectInst + +; + +Proc AddSelectEvent + + Call MouseGetStatus + Test AL, 6 + JNZ AddSelectEvent1 + + Mov Word Ptr [SI+8], 102h + +AddSelectEvent1: + Call MouseAddEvent + + Ret + +EndP AddSelectEvent + +; + +Proc I_DrawSampleList Far + + Call S_GetDestination + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + + Test AL, AL + JNZ I_DrawSampleList1 + + Inc AX + Mov LastInstrument, AL + +I_DrawSampleList1: + Push CS + Pop DS + Assume DS:Inst + + Mov BX, TopSample + Cmp BL, AL + JBE I_DrawSampleList2 + + Mov BL, AL + +I_DrawSampleList2: ; BL = top, AL = current + Mov CL, BL + Add CL, 34 + Cmp CL, AL + JAE I_DrawSampleList3 + + Mov BL, AL + Sub BL, 34 + +I_DrawSampleList3: + Mov TopSample, BX + ; BX = topinstrument + + Mov DI, (2+13*80)*2 + + Mov DX, 0A23h + +I_DrawSampleList4: + Mov AX, BX + Div DH + ; AH = units, AL = tens + Add AL, '0' + StosB + Mov AL, 20h + StosB + XChg AH, AL + Add AL, '0' + StosW + + Inc BX + Add DI, 156 + Dec DL + JNE I_DrawSampleList4 + + Mov BX, TopSample + + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + + Mov CX, 35 + Mov DI, (5+13*80)*2 + Dec BX + Add BX, BX + Mov SI, [BX+64912] + +I_DrawSampleList5: + Push CX + Push SI + Push DI + + Add SI, 14h + Mov CX, 25 + Mov AH, 6 + +I_DrawSampleList6: + LodsB + Cmp AL, 226 + JB I_DrawSampleNoMouse + + Mov AL, ' ' + +I_DrawSampleNoMouse: + StosW + Loop I_DrawSampleList6 + + Mov AX, 2A8h + StosW + + Mov AX, 700h+'P' + + Test Byte Ptr [SI-14h-25+12h], 1 + JZ I_DrawSampleList8 + + Mov AH, 6 + +I_DrawSampleList8: + StosW + Mov AL, 'l' + StosW + Mov AL, 'a' + StosW + Mov AL, 'y' + StosW + + Pop DI + Pop SI + Pop CX + Add SI, 80 + Add DI, 160 + + Loop I_DrawSampleList5 + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + Xor AH, AH + Sub AX, TopSample + Add AX, 13 + Mov BX, 160 + Mul BX + Add AX, 10 + Mov DI, AX + + Mov CX, 30 + +I_DrawSampleList7: + Mov AX, [ES:DI] + And AH, 0Fh + Or AH, 0E0h + StosW + + Loop I_DrawSampleList7 + + ; Add on pointer... + Push CS + Pop DS + Assume DS:Inst + + Mov SI, Offset SampleMouseEvent + Mov Word Ptr [SI+4], 35*8-1 + Mov Word Ptr [SI+10], 28 + Call AddSelectEvent + Mov SI, Offset SampleMouseOffEvent + Mov Word Ptr [SI+4], 35*8-1 + Call MouseAddEvent + + Ret + +EndP I_DrawSampleList + Assume DS:Nothing + +; + +Proc I_PreSampleList Far + + Call S_GetDestination + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + Xor AH, AH + Mov SI, AX + Sub AX, TopSample + Add AX, 13 + Mov BX, 160 + Mul BX + Add AX, 10 + Mov DI, AX + + Mov AX, SamplePos + Cmp AX, 25 + JB I_PreSampleList1 + + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + + Dec SI + Add SI, SI + Mov SI, [SI+64912] + + Mov CX, 4 + Add DI, 52 + Mov AL, 30h + Test Byte Ptr [SI+12h], 1 + JNZ I_PreSampleList2 + + Mov AL, 60h + +I_PreSampleList2: + Inc DI + StosB + + Loop I_PreSampleList2 + + Ret + +I_PreSampleList1: + Add DI, AX + Add DI, AX + + Mov AL, 30h + Inc DI + StosB + Ret + +EndP I_PreSampleList + +; + +Proc I_PostSampleList Far + + Push CS + Pop DS + Assume DS:Inst + + Mov SI, Offset SampleListKeys + Call M_FunctionDivider + JC I_PostSampleList7 + + Jmp [SI] + +I_PostSampleList7: + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + Xor AH, AH + Mov SI, AX + Dec SI + + Mov AX, SamplePos + Cmp AX, 25 + JAE I_PostSampleList2 + + Mov BX, AX ; BX = Pos. SI = LastInst + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + + Add SI, SI + Mov SI, [64912+SI] ; SI = sample offset. + + Test CL, CL + JZ I_PostSampleList1 + Cmp DL, 32 ; Space bar or less?? + JB I_PostSampleList1 + + Add BX, 14h ; To sample name. + Add BX, SI + Add SI, 2Ch + +I_PostSampleList3: + Cmp SI, BX + JBE I_PSL3 + + Mov AL, [SI-1] + Mov [SI], AL + Dec SI + Jmp I_PostSampleList3 + +I_PSL3: + Mov [SI], DL + + Inc SamplePos + + Jmp I_PostSampleListEnd + +I_PostSampleList1: + Cmp CX, 10Eh + JNE I_PostSampleList4 + + And BX, BX + JZ I_PostSampleList4 + + Dec SamplePos + Add BX, 14h + Add BX, SI + Add SI, 2Dh + +I_PostSampleList5: + Mov AL, [BX] + Mov [BX-1], AL + Inc BX + Cmp BX, SI + JB I_PostSampleList5 + + Mov Byte Ptr [BX-1], 0 + +I_PostSampleListEnd: + NetworkSendSample + + Mov AX, 1 + Ret + +I_PostSampleList4: + Cmp CX, 1D3h ; Delete... + JNE I_PostSampleList6 + + Add BX, 15h + Add BX, SI + Add SI, 2Dh + Jmp I_PostSampleList5 + +I_PostSampleList6: + Xor AX, AX + Ret + +I_PostSampleList2: ; Play note.... + Push CS + Pop DS + + Test CH, Not 1 + JNZ I_PostSampleList9 + + Cmp CX, LastKey + JE I_PostSampleList9 + + Mov LastKey, CX + + + Mov SI, Offset KeyBoardTable + +I_PostSampleList8: + LodsW + Cmp AX, 0FFFFh + JE I_PostSampleList9 + + Mov BX, AX + LodsW + + Cmp BL, CL + JNE I_PostSampleList8 + ; Note to play... + ; AX = notemod. + And CH, CH + JZ I_PostSampleList10 + + Mov CX, AX + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, 12 + Mul BaseOctave + Add AL, CL + Mov AH, LastInstrument + + Push CS + Pop DS + Assume DS:Inst + + Call UpdateMultiChannel + + Mov LastPlaySample, AL + + Mov CX, PlayChannel + Call Music_PlaySample + Jmp I_PostSampleList9 + +I_PostSampleList10: + Mov SI, Offset NoteData + Mov Word Ptr [SI], 0FFh + Mov AX, PlayChannel + Mov DH, 32+128 + Call Music_PlayNote ; Note off. + +I_PostSampleList9: + Xor AX, AX + Ret + +EndP I_PostSampleList + +; + +Proc I_SampleLeft Far + + Mov AX, SamplePos + Dec AX + JS I_SampleLeft1 + + Mov SamplePos, AX + +I_SampleLeft1: + Mov AX, 1 + Ret + +EndP I_SampleLeft + +; + +Proc I_SampleRight Far + + Mov AX, SamplePos + Inc AX + Cmp AX, 25 + JA I_SampleRight1 + + Mov SamplePos, AX + +I_SampleRight1: + Mov AX, 1 + Ret + +EndP I_SampleRight + +; + +Proc I_RedrawWave + + Call Glbl_GetCurrentMode + + Cmp AL, 3 + JE I_RedrawWave1 + Cmp AL, 4 + JNE I_RedrawWave2 + + Call I_MapEnvelope + Ret + +I_RedrawWave1: + Call I_DrawWaveForm + +I_RedrawWave2: + Ret + +EndP I_RedrawWave + +; + +Proc I_SelectInstrument2 + Assume DS:Inst + + ; Set Instrument pos... + Mov AX, MouseX + ShR AX, 3 + Sub AX, 5 + JNC I_SelectInstrument8 + + Xor AX, AX + +I_SelectInstrument8: + Cmp AX, 24 + JB I_SelectInstrument7 + + Mov AX, 24 + +I_SelectInstrument7: + Mov InstrumentPos, AX + + Add DX, TopInstrument + Jmp I_SelectInstrument4 + +Proc I_SelectInstrument Far + + Mov AX, MouseX + Sub AX, 40 + ShR AX, 3 + Cmp AX, 25 + JB I_SelectInstrument6 + + Mov AX, 25 + +I_SelectInstrument6: + Mov SamplePos, AX + + Add DX, TopSample + +I_SelectInstrument4: + Cmp DX, 1 + JGE I_SelectInstrument1 + + Mov DX, 1 + +I_SelectInstrument1: + Cmp DX, 99 + JL I_SelectInstrument3 + + Mov DX, 99 + +I_SelectInstrument3: + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Cmp DL, LastInstrument + Mov LastInstrument, DL + JE I_SelectInstrument5 + + Call I_RedrawWave + +I_SelectInstrument5: + Mov AX, 1 + Ret + +EndP I_SelectInstrument + +EndP I_SelectInstrument2 + Assume DS:Nothing + +; + +Proc I_SampleDown Far + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + + Inc AX + Cmp AL, 100 + JAE I_SampleDown1 + + Mov LastInstrument, AL + Call I_RedrawWave + +I_SampleDown1: + + Mov AX, 1 + Ret + +EndP I_SampleDown + Assume DS:Nothing + +; + +Proc I_SampleUp Far + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + + Dec AL + JZ I_SampleUp1 + + Mov LastInstrument, AL + Call I_RedrawWave + +I_SampleUp1: + Mov AX, 1 + Ret + +EndP I_SampleUp + Assume DS:Nothing + +; + +Proc I_SamplePgUp Far + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + + Cmp AL, 1 + JE I_SamplePgUp3 + + Sub AL, 16 + JZ I_SamplePgUp1 + JNC I_SamplePgUp2 + +I_SamplePgUp1: + Mov AL, 1 + +I_SamplePgUp2: + Mov LastInstrument, AL + Call I_RedrawWave + +I_SamplePgUp3: + Mov AX, 1 + Ret + +EndP I_SamplePgUp + Assume DS:Nothing + +; + +Proc I_SamplePgDn Far + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + Cmp AL, 99 + JE I_SamplePgDn2 + + Add AL, 16 + Cmp AL, 99 + JBE I_SamplePgDn1 + + Mov AL, 99 + +I_SamplePgDn1: + Mov LastInstrument, AL + Call I_RedrawWave + +I_SamplePgDn2: + Mov AX, 1 + Ret + +EndP I_SamplePgDn + Assume DS:Nothing + +; + +Proc I_SampleCtrlPgUp Far + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov LastInstrument, 1 + Call I_RedrawWave + + Mov AX, 1 + Ret + +EndP I_SampleCtrlPgUp + +; + +Proc I_SampleCtrlPgDn Far + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov LastInstrument, 99 + Call I_RedrawWave + + Mov AX, 1 + Ret + +EndP I_SampleCtrlPgDn + +; + +Proc I_SampleEnd Far + + Mov SamplePos, 25 + + Mov AX, 1 + Ret + +EndP I_SampleEnd + +; + +Proc I_SampleHome Far + + Mov SamplePos, 0 + + Mov AX, 1 + Ret + +EndP I_SampleHome + +; + +Proc I_SampleTab Far + + Mov Word Ptr [ES:DI], 7 + + Mov AX, 1 + Ret + +EndP I_SampleTab + +; + +Proc I_ShowSampleInfo Far + + Call I_GetSampleOffset + + Push DWord Ptr [BX+30h] + + Mov AL, [BX+12h] + + Push CS + Pop DS + Assume DS:Inst + + Mov SI, Offset NoSampleMsg + + Mov AH, 2 + Test AL, 1 + JZ I_ShowSampleInfo1 + + Mov SI, Offset Quality8Msg + Test AL, 2 + JZ I_ShowSampleInfo1 + + Mov SI, Offset Quality16Msg + +I_ShowSampleInfo1: + Mov DI, (64+22*80)*2 + Call S_DrawString + +I_ShowSampleInfo2: + Mov DI, (64+23*80)*2 + Mov SI, Offset LengthMsg + Call S_DrawString + + Pop EAX + + Ret + +EndP I_ShowSampleInfo + +; + +Proc I_VibratoButtonSelect Far + + Call I_GetSampleOffset + Mov AL, [BX+04Fh] ; AL = type. + Xor AH, AH + + Add DI, 82 + Xor CX, CX + +I_VibratoButtonSelect1: + Mov SI, [ES:DI] + + Mov CH, AH ; Assume up + Cmp AL, CL + JNE I_VibratoButtonSelect2 + + Inc CH + +I_VibratoButtonSelect2: + Mov [ES:SI+33], CH + +; Add DI, 2 + ScasW + Inc CX + Cmp CL, 3 + JLE I_VibratoButtonSelect1 + + Ret + +EndP I_VibratoButtonSelect + +; + +Proc I_SetVibratoWaveform Far ; AH = waveform. + + Mov AX, [SI+24] + Push AX + Call I_GetSampleOffset + Pop AX + + Mov [BX+4Fh], AL + + Ret + +EndP I_SetVibratoWaveform + +; + +Proc I_CheckLoopValues Far + + Call I_GetSampleOffset + + Mov EAX, [BX+30h] + Sub EAX, 1 + AdC EAX, 0 + Cmp EAX, [BX+34h] + JA I_CheckLoopValues3 + + Mov [BX+34h], EAX + +I_CheckLoopValues3: + Inc EAX + Cmp EAX, [BX+38h] + JAE I_CheckLoopValues2 + + Mov [BX+38h], EAX + +I_CheckLoopValues2: + Mov EAX, [BX+38h] + Cmp EAX, [BX+34h] + JA I_CheckLoopValues1 + + And Byte Ptr [BX+12h], NOT 00010000b + +I_CheckLoopValues1: + Call Music_RegetLoopInformation + Call I_DrawWaveForm + Ret + +EndP I_CheckLoopValues + +; + +Proc I_CheckSusLoopValues Far + + Call I_GetSampleOffset + + Mov EAX, [BX+30h] + Sub EAX, 1 + AdC EAX, 0 + Cmp EAX, [BX+40h] + JA I_CheckSusLoopValues3 + + Mov [BX+40h], EAX + +I_CheckSusLoopValues3: + Inc EAX + Cmp EAX, [BX+44h] + JAE I_CheckSusLoopValues2 + + Mov [BX+44h], EAX + +I_CheckSusLoopValues2: + Mov EAX, [BX+44h] + Cmp EAX, [BX+40h] + JA I_CheckLoopValues1 + + And Byte Ptr [BX+12h], NOT 00100000b + +I_CheckSusLoopValues1: + Call Music_RegetLoopInformation + Call I_DrawWaveForm + Ret + +EndP I_CheckSusLoopValues + +; + +Proc I_DrawWaveForm Far + + Mov [CS:LastWaveformValues], 7f80h + + Call S_GetGenerationTableOffset + Push DI + Mov CX, 176*32 + Xor AL, AL + Rep StosB + Pop DI + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + And AL, AL + JNZ I_DrawWaveForm1 + + Mov AL, 1 + +I_DrawWaveForm1: + Mov LastInstrument, AL + Xor AH, AH + Xor CX, CX + Call Music_GetSampleLocation + Assume DS:Nothing + + JC I_DrawWaveFormEnd + + SetNZ CS:Resolution + JZ I_DrawWaveForm8Bit + + Add ECX, ECX + Inc SI + +I_DrawWaveForm8Bit: + Test ECX, ECX + JZ I_DrawWaveFormEnd + + Push AX ; AX = instrument num + ; DS:ESI = waveform, ECX = length + ; ES:DI = charactergenerationtable + + Mov EAX, ECX + Mov ECX, 176 + Xor EDX, EDX + Div ECX ; EAX = major shift. EDX = minor shift. + + Mov EBX, EAX + Xor EAX, EAX + Div ECX + + Mov EDX, EAX + Xor EAX, EAX + + Mov EBP, ESI + +I_DrawWaveForm6: + Add EAX, EDX + AdC EBP, EBX + Push EAX + Push EBX + Push ECX + Push EDX + + Mov CL, [SI] + Mov CH, CL + MovZX BX, CS:Resolution + Inc BX + +I_DrawWaveForm10: + Cmp ESI, EBP + JAE I_DrawWaveForm7 + + Mov AL, [SI] + Add SI, BX ; Get max/min vals. + JC I_DrawWaveformNewBlock + +I_DrawWaveformResume: + Cmp AL, CL + JL I_DrawWaveForm8 + + Cmp AL, CH + JLE I_DrawWaveForm10 + + Mov CH, AL + Jmp I_DrawWaveForm10 + +I_DrawWaveformNewBlock: + Add ESI, 10000h + Int 3 + Jmp I_DrawWaveFormResume + +I_DrawWaveForm8: + Mov CL, AL + Jmp I_DrawWaveForm10 + +I_DrawWaveForm7: ; CL = min, CH = max. + Mov AX, CX + + XChg CX, [CS:LastWaveformValues] + + Cmp AL, CH + JL I_DrawWaveform7a + + Mov AL, CH + +I_DrawWaveform7a: + Cmp AH, CL + JG I_DrawWaveform7b + + Mov AH, CL + +I_DrawWaveform7b: + SAR AH, 1 + SAR AL, 1 + Add AX, 202h + SAR AH, 2 + SAR AL, 2 + + Xor CH, CH + Mov CL, AH + Sub CL, AL ; CX = iterations. + Inc CX + + Mov AL, 16 + Sub AL, AH + Cmp AL, 32 + JNE I_DrawWaveForm13 + + Mov AL, 31 + +I_DrawWaveForm13: + Mov AH, 176 + Mul AH + Mov BX, AX + +I_DrawWaveForm11: + Mov Byte Ptr [ES:DI+BX], 1 + Add BX, 176 + Loop I_DrawWaveForm11 + +I_DrawWaveForm12: + Pop EDX + Pop ECX + Pop EBX + Pop EAX + Inc DI + Loop I_DrawWaveForm6 + + ; Get Sample header offset. + Call Music_GetSongSegment + Mov DS, AX + Pop SI + Dec SI + Add SI, SI + Mov SI, [64912+SI] + + Mov EBX, [DS:SI+30h] + Test Byte Ptr [DS:SI+12h], 10h + JZ I_DrawWaveForm14 + + Mov ECX, EBX + ShR ECX, 1 + + Mov EAX, 175 + Mul DWord Ptr [DS:SI+34h] + Add EAX, ECX + AdC EDX, 0 + Div EBX + + Push EAX ; AX = loop start. + + Mov EAX, 175 + Mul DWord Ptr [DS:SI+38h] + Add EAX, ECX + AdC EDX, 0 + Div EBX + Mov EDX, EAX + Pop EAX ; EDX = loop end (0-175) + ; EAX = loop start (0-175) + + Call S_GetGenerationTableOffset + ; ES:DI + Add DI, AX + Sub DX, AX + Dec DX + Mov CX, 32 + Mov AH, 1 + +I_DrawSampleWaveFormLoop1: + Push DI + +; Xor AL, AL +; Test AH, 2 +; JZ I_DrawSampleWaveFormLoop2 +; +; Inc AL +; +;I_DrawSampleWaveFormLoop2: + Mov AL, AH + ShR AL, 1 + And AL, 1 + + StosB + Add DI, DX + StosB + + Pop DI + Add DI, 176 + Inc AH + Loop I_DrawSampleWaveFormLoop1 + +I_DrawWaveForm14: + Test Byte Ptr [DS:SI+12h], 20h + JZ I_DrawWaveFormEnd + + Mov ECX, EBX + ShR ECX, 1 + + Mov EAX, 175 + Mul DWord Ptr [DS:SI+40h] + Add EAX, ECX + AdC EDX, 0 + Div EBX + + Push EAX ; AX = loop start. + + Mov EAX, 175 + Mul DWord Ptr [DS:SI+44h] + Add EAX, ECX + AdC EDX, 0 + Div EBX + Mov EDX, EAX + Pop EAX ; DX = loop end (0-175) + ; AX = loop start (0-175) + + Call S_GetGenerationTableOffset + ; ES:DI + Add DI, AX + Sub DX, AX + Dec DX + Mov CX, 32 + Mov AL, 1 + +I_DrawSampleWaveFormSusLoop1: + Push DI + + StosB + Add DI, DX + StosB + + Pop DI + Add DI, 176 + Xor AL, 1 + Loop I_DrawSampleWaveFormSusLoop1 + +I_DrawWaveFormEnd: + Mov AX, 1 + Mov BX, 22 + Mov CX, 4 + Call S_GenerateCharacters + + Ret + +EndP I_DrawWaveForm + +; + +Proc I_DeleteSample Far + + Mov DI, Offset O1_ConfirmDeleteSample + Mov CX, 4 + Call M_Object1List + + And DX, DX + JZ I_DeleteSample1 + + Call Music_Stop + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + Dec AX + Xor AH, AH + + Call Music_ReleaseSample + Call Music_ClearSampleName + + Call I_DrawWaveForm + +I_DeleteSample1: + Mov AX, 1 + Ret + +EndP I_DeleteSample + Assume DS:Nothing + +; + +C5Speed DD 0 + +Proc I_CalculateC5Speed Far + + Mov AX, 1 + Ret + +Comment ! + Push DiskData + Pop ES + Call Fourier_CreateTable + + Call PE_GetLastInstrument ; Into BX + Mov AX, BX + Inc AX + + Xor CX, CX + Call Music_GetSampleLocation ; Returns DS:ESI, ECX + JC I_CalculateC5SpeedEnd + + PushF + Mov DX, 2048 + Mov DI, 16384 + + Cmp CX, DX + JB I_CalculateC5Speed1 + + Mov CX, DX + +I_CalculateC5Speed1: + Sub DX, CX + PopF + JNZ I_CalculateC5Speed16Bit + +I_CalculateC5Speed8Bit: + LodsB + StosW + Loop I_CalculateC5Speed8Bit + Jmp I_CalculateC5Speed2 + +I_CalculateC5Speed16Bit: + Rep MovsW + +I_CalculateC5Speed2: + Mov CX, DX + Xor AX, AX + Rep StosW + + Push ES + Pop DS + Call Fourier_Transform + +Comment ~ + + Mov DX, 1 + JZ I_CalculateC5BitSkip + + Inc DX + +I_CalculateC5BitSkip: + Mov EBP, ECX ; EBP = number of samples + +I_CalculateC5Speed1: + Sub EBP, 512 + JC I_CalculateC5SpeedDisplay + + Mov DI, 16384 + Mov BX, 512 + +I_CalculateC5Loop1: + Cmp DX, 2 + JE I_CalculateC5Speed16Bit + +I_CalculateC5Speed8Bit: + Mov AL, [SI] + Mov AH, AL + Jmp I_CalculateC5SpeedTransfer + +I_CalculateC5Speed16Bit: + Mov AX, [SI] + +I_CalculateC5SpeedTransfer: +; StosW + Mov CX, 4 + Rep StosW + + Add SI, DX + JC I_CalculateC5UpdateSampleLocation + +I_CalculateC5Continue: + Dec BX + JNZ I_CalculateC5Loop1 + +; OK.. do fourier + Push DS + PushAD + + Call Fourier_Transform + +; Now accumulate + Mov CX, 1024-64 + Mov SI, 24576+64*4 + Mov DI, 32768+64*4 + +I_CalculateC5Speed2: + FLd DWord Ptr [SI] + FAdd DWord Ptr [DI] + FStP DWord Ptr [DI] + Add SI, 4 + Add DI, 4 + Loop I_CalculateC5Speed2 + + PopAD + Pop DS + Jmp I_CalculateC5Speed1 + +I_CalculateC5UpdateSampleLocation: + Add ESI, 10000h + Int 3 + Jmp I_CalculateC5Continue + +I_CalculateC5SpeedDisplay: + Push ES + Pop DS +~ + Mov SI, 24768 + Xor CX, CX + Xor EAX, EAX + Xor EBX, EBX + +I_CalculateC5Speed3: + Cmp EAX, [SI] + JAE I_CalculateC5Speed4 + + Mov BX, CX + Mov EAX, [SI] + +I_CalculateC5Speed4: + Add SI, 4 + Inc CX + + Cmp CX, 1024 + JB I_CalculateC5Speed3 + +; Have BX = wavelength. + Mov EAX, 17145893 ; = C5Freq * 65536 + Mul EBX ; EDX:EAX = frequency in 48:16 format + ShRD EAX, EDX, 16 + + Mov CS:C5Speed, EAX +; EAX = C5Freq + Mov DI, Offset O1_C5FrequencyList + Call M_Object1ListDefault + +I_CalculateC5SpeedEnd: + Mov AX, 1 + Ret +! + +EndP I_CalculateC5Speed + +; + +Proc I_PrintC5Frequency Far + + Push CS + Pop DS + Assume DS:Inst + + Push C5Speed + + Mov SI, Offset C5FrequencyText + Mov AH, 20h + Mov DI, (27+27*80)*2 + Call S_DrawString + + Pop AX ; Clean up stack. + Pop BX + + Ret + +EndP I_PrintC5Frequency + Assume DS:Nothing + +; + +Proc I_DeleteInstrument Far + + Mov DI, Offset O1_ConfirmDeleteInstrument + Mov CX, 4 + Call M_Object1List + + And DX, DX + JZ I_DeleteInstrument1 + + Call Music_Stop + + Call I_GetInstrumentOffset ; Gets DS:BX + + Mov CX, 120 + Add BX, 41h + +I_DeleteInstrument2: + Mov AL, [BX] + And AX, 0FFh + JZ I_DeleteInstrument3 + + Push DS + Push BX + Push CX + + Dec AX + + Call Music_ReleaseSample + Call Music_ClearSampleName + + Pop CX + Pop BX + Pop DS + +I_DeleteInstrument3: + Add BX, 2 + Loop I_DeleteInstrument2 + + Call I_InstrumentClear ; This sends network data already + +I_DeleteInstrument1: + Mov AX, 1 + Ret + +EndP I_DeleteInstrument + +; + +Proc I_ConvertSample Far ; Signed/Unsigned + + EnsureNoNetwork + + Call PE_GetLastInstrument + Mov CX, BX + Inc CX + Add BX, BX + + Call Music_GetSongSegment + Mov DS, AX + Mov SI, [64912+BX] + Test Byte Ptr [DS:SI+12h], 1 + JZ I_ConvertSample1 + + Push CX + + Mov DI, Offset O1_ConfirmConvertList + Mov CX, 3 + Call M_Object1List + + Pop AX ; AX = sample number + + And DX, DX + JZ I_ConvertSample1 + + Call Music_Stop + + Xor CX, CX + Call Music_GetSampleLocation ; DS:SI = location + JC I_ConvertSample1 ; CX = length. + + SetNZ BL + Xor BH, BH + Add SI, BX + + Inc BX + + +I_ConvertSample2: + Xor Byte Ptr [SI], 80h + Add SI, BX + JC I_ConvertSample3 + +I_ConvertSample4: + LoopD I_ConvertSample2 + + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_ConvertSample1: + Mov AX, 1 + Ret + +I_ConvertSample3: + Add ESI, 10000h + Int 3 + Jmp I_ConvertSample4 + +EndP I_ConvertSample + +; + +Proc I_InvertSample Far ; Signed/Unsigned + + EnsureNoNetwork + + Call PE_GetLastInstrument + Mov CX, BX + Inc CX + Add BX, BX + + Call Music_GetSongSegment + Mov DS, AX + Mov SI, [64912+BX] + Test Byte Ptr [DS:SI+12h], 1 + JZ I_InvertSample1 + + XChg AX, CX ; AX = sample number. + + Xor CX, CX + Call Music_GetSampleLocation ; DS:SI = location + JC I_InvertSample1 ; CX = length. + JNZ I_InvertSample_16Bit + +I_InvertSample2: + Neg Byte Ptr [SI] + Add SI, 1 + JC I_InvertSample3 + +I_InvertSample4: + LoopD I_InvertSample2 + +I_InvertSampleExit: + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_InvertSample1: + Mov AX, 1 + Ret + +I_InvertSample3: + Add ESI, 10000h + Int 3 + Jmp I_InvertSample4 + +I_InvertSample_16Bit: + Neg Word Ptr [SI] + Add SI, 2 + JC I_InvertSample_16Bit2 + +I_InvertSample_16Bit1: + LoopD I_InvertSample_16Bit + + Jmp I_InvertSampleExit + +I_InvertSample_16Bit2: + Add ESI, 10000h + Int 3 + Jmp I_InvertSample_16Bit1 + +EndP I_InvertSample + +; + +Proc I_CutSampleBeforeLoopUpdateLoop Near + + Sub [DS:BX+DI], EDX + JNC I_CutSampleBeforeLoopUpdateLoop1 + + Mov DWord Ptr [DS:BX+DI], 0 + +I_CutSampleBeforeLoopUpdateLoop1: + Add DI, 4 + Ret + +EndP I_CutSampleBeforeLoopUpdateLoop + +; + +Proc I_CutSampleBeforeLoop Far + + EnsureNoNetwork + + Call I_GetSampleOffset + + Cmp DWord Ptr [DS:BX+34h], 0 +; Test Byte Ptr [DS:BX+12h], 10h + JZ I_CutSampleBeforeLoop1 + + Push DS + Push BX + + Mov DI, Offset O1_ConfirmCutSample + Mov CX, 4 + Call M_Object1List + + Pop BX + Pop DS + + And DX, DX + JZ I_CutSampleBeforeLoop1 + + Call Music_Stop + + Mov EDX, [DS:BX+34h] + Test Byte Ptr [DS:BX+12h], 32 + JZ I_CutSampleBeforeLoop2 + + Mov EAX, [DS:BX+40h] + + Cmp EDX, EAX + JB I_CutSampleBeforeLoop2 + Mov EDX, EAX + +I_CutSampleBeforeLoop2: + Mov DI, 34h + Call I_CutSampleBeforeLoopUpdateLoop ; BX+34h - Begin + Call I_CutSampleBeforeLoopUpdateLoop ; BX+38h - End + + Add DI, 4 + Call I_CutSampleBeforeLoopUpdateLoop ; BX+40h - SusLBeg + Call I_CutSampleBeforeLoopUpdateLoop ; BX+44h - SusLEnd + +I_CutSampleBeforeLoop4: + Sub [BX+30h], EDX + Mov ECX, [BX+30h] + + Test Byte Ptr [BX+12h], 2 + JZ I_CutSampleBeforeLoop6 + + Add EDX, EDX + Add ECX, ECX + +I_CutSampleBeforeLoop6: + Mov ESI, EDX + Call I_RepositionSample + + ; To diskdata segment first. + Mov AX, DiskData + Mov ES, AX + Assume ES:Nothing + + Xor EDI, EDI + +I_CutSampleBeforeLoop7: + Mov AL, [SI] + Mov [ES:DI], AL + + Add SI, 1 + JC I_CutSampleBeforeLoop8 + +I_CutSampleBeforeLoop9: + Add DI, 1 + JC I_CutSampleBeforeLoop10 + +I_CutSampleBeforeLoop11: + LoopD I_CutSampleBeforeLoop7 + + Mov ESI, EDI + Int 3 + Mov CX, DI + + Push DS + Push ES + Pop DS + Pop ES ; Swap DS and ES + + Xor SI, SI + Xor DI, DI + Rep MovsB + + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_CutSampleBeforeLoop1: + Mov AX, 1 + Ret + +I_CutSampleBeforeLoop8: + Add ESI, 10000h + Int 3 + Jmp I_CutSampleBeforeLoop9 + +I_CutSampleBeforeLoop10: + PushAD + Push DS + Push ES + + Mov ESI, EDI + Int 3 + + Push DS + Push ES + Pop DS + Pop ES ; Swap DS and ES + + Mov CX, 16384 + Xor SI, SI + Xor DI, DI + Rep MovsD + + Pop ES + Pop DS + PopAD + + Add EDI, 10000h + + Int 3 + Jmp I_CutSampleBeforeLoop11 + +EndP I_CutSampleBeforeLoop + +; + +Proc I_CutSample Far + + EnsureNoNetwork + + Call I_GetSampleOffset + + Cmp DWord Ptr [DS:BX+38h], 0 +; Test Byte Ptr [DS:BX+12h], 10h ; Loop? + JZ I_CutSample1 + + Push DS + Push BX + + Mov DI, Offset O1_ConfirmCutSample + Mov CX, 4 + Call M_Object1List + + Pop BX + Pop DS + + And DX, DX + JZ I_CutSample1 + + Call Music_Stop + + Mov EAX, [DS:BX+38h] + Mov EDX, [DS:BX+44h] + Cmp EAX, EDX + JAE I_CutSample2 + Mov EAX, EDX + +I_CutSample2: + Mov [DS:BX+30h], EAX + + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_CutSample1: + Mov AX, 1 + Ret + +Proc I_CutSampleCheckValue Near + + Cmp DWord Ptr [DS:BX+DI], EAX + JBE I_CutSampleCheckValue1 + + Mov [DS:BX+DI], EAX + +I_CutSampleCheckValue1: + Ret + +EndP I_CutSampleCheckValue + +EndP I_CutSample + +; + +Proc I_ClearSampleName Far + Assume DS:Inst + + Mov SamplePos, 0 + +I_ClearSampleName2: + Call I_GetSampleOffset + + Push DS + Pop ES + + Mov DI, BX + +I_ClearSampleName3: + Add DI, 4 + + Mov CX, 6 + Xor AX, AX + Rep StosW + + Add DI, 4 + Mov CX, 13 + Rep StosW + + NetworkSendSample + + Inc AX + Ret + +EndP I_ClearSampleName + Assume DS:Nothing + +; + +Proc I_InsertSample Far + + EnsureNoNetwork + + Call Music_GetSongSegment + Mov DS, AX + Mov SI, [DS:64912+(99-1)*2] + Test Byte Ptr [SI+12h], 1 + JNZ I_InsertSampleEnd + + Call PE_GetLastInstrument + Cmp BL, 98 + JE I_InsertSampleEnd + + Call Music_Stop + + Call PE_GetLastInstrument + Mov DL, BL + Push BX + + Call Music_GetSongSegment + + Mov ES, AX + Mov DS, AX + + Mov AX, 98 + Sub AX, BX + Mov CX, 80 + Add BX, BX + Mul CX + Mov SI, [DS:64912+BX] + Add SI, AX + Dec SI + LEA DI, [SI+80] + Mov CX, AX + + StD + Rep MovsB + ClD + + Mov DWord Ptr [SI+1+48h], 0 + Mov Byte Ptr [SI+1+12h], 0 + + Call Music_SoundCardLoadAllSamples + + Pop AX + Push AX + Call Music_ClearSampleName + + Pop DX + Inc DX ; DL = instrument + + Call Music_GetInstrumentMode + JZ I_InsertSampleSampleMode + ; Instrument mode.. + ; step through inst. + + Xor EAX, EAX + +I_InsertSample4: + Mov SI, [DS:64712+EAX*2] + Add SI, 41h + + Mov CX, 120 + +I_InsertSample5: + Cmp [SI], DL + JB I_InsertSample6 + + Cmp Byte Ptr [SI], 99 + JAE I_InsertSample6 + + Inc Byte Ptr [SI] + +I_InsertSample6: + Add SI, 2 + Loop I_InsertSample5 + + Inc AX + Cmp AX, 99 + JB I_InsertSample4 + + Jmp I_InsertSampleFinished + +I_InsertSampleSampleMode: + Call PE_InsertInstrument + +I_InsertSampleFinished: + Call I_DrawWaveform + +I_InsertSampleEnd: + Mov AX, 1 + Ret + +EndP I_InsertSample + +; + +Proc I_RemoveSample Far + + EnsureNoNetwork + + Call I_GetSampleOffset + Test Byte Ptr [BX+12h], 1 + JNZ I_RemoveSampleEnd + + Call Music_Stop + + Call PE_GetLastInstrument + Mov DL, BL + Push BX + + Call Music_GetSongSegment + + Mov ES, AX + Mov DS, AX + + Mov AX, 98 + Sub AX, BX + Mov CX, 80 + Add BX, BX + Mul CX + Mov DI, [DS:64912+BX] + LEA SI, [DI+80] + Mov CX, AX + + Rep MovsB + + Pop DX + Inc DX ; DL = instrument + + Push DS + Push DI + + Mov DWord Ptr [DI+48h], 0 + Mov Byte Ptr [DI+12h], 0 + + Call Music_SoundCardLoadAllSamples + + Call Music_GetInstrumentMode + JZ I_RemoveSampleSampleMode + ; Instrument mode.. + ; step through inst. + + Xor EAX, EAX + +I_RemoveSample4: + Mov SI, [DS:64712+EAX*2] + Add SI, 41h + + Mov CX, 120 + +I_RemoveSample5: + Cmp [SI], DL + JB I_RemoveSample6 + + Dec Byte Ptr [SI] + +I_RemoveSample6: + Add SI, 2 + Loop I_RemoveSample5 + + Inc AX + Cmp AX, 99 + JB I_RemoveSample4 + + Jmp I_RemoveSampleFinished + +I_RemoveSampleSampleMode: + Call PE_DeleteInstrument + +I_RemoveSampleFinished: + Call I_DrawWaveform + + Pop DI + Pop ES + Jmp I_ClearSampleName3 + +I_RemoveSampleEnd: + Mov AX, 1 + Ret + +EndP I_RemoveSample + +; + +Proc I_InsertInstrument Far + + EnsureNoNetwork + + Call PE_GetLastInstrument + Cmp BL, 98 + JE I_InsertInstrumentEnd + + Call Music_Stop + + Call PE_GetLastInstrument + Mov DL, BL + Push BX + + Call Music_GetSongSegment + + Mov ES, AX + Mov DS, AX + + Mov AX, 98 + Sub AX, BX + Mov CX, 554 + Add BX, BX + Mul CX + Mov SI, [DS:64712+BX] + Add SI, AX + Dec SI + LEA DI, [SI+554] + Mov CX, AX + + StD + Rep MovsB + ClD + + Pop DX + Inc DX ; DL = instrument + + Call Music_GetInstrumentMode + JZ I_InsertInstrumentFinished + + Call PE_InsertInstrument + +I_InsertInstrumentFinished: + Jmp I_InstrumentClear ; Sends network data + +I_InsertInstrumentEnd: + Mov AX, 1 + Ret + +EndP I_InsertInstrument + +; + +Proc I_RemoveInstrument Far + + EnsureNoNetwork + + Call Music_Stop + + Call PE_GetLastInstrument + Mov DL, BL + Push BX + + Call Music_GetSongSegment + + Mov ES, AX + Mov DS, AX + + Mov AX, 98 + Sub AX, BX + Mov CX, 554 + Add BX, BX + Mul CX + MOv DI, [DS:64712+BX] + LEA SI, [DI+554] + Mov CX, AX + + Rep MovsB + + Pop DX + Inc DX ; DL = instrument + + Call Music_GetInstrumentMode + JZ I_RemoveInstrumentFinished + + Call PE_DeleteInstrument + +I_RemoveInstrumentFinished: + Mov AX, 98 + Call Music_ClearInstrument + + Call I_MapEnvelope + +I_RemoveInstrumentEnd: + Mov AX, 1 + Ret + +EndP I_RemoveInstrument + +; + +Proc GetSampleNumber ; Carry if not a num. + ; DX otherwise, + Push CS + Pop DS + + Mov SI, Offset SampleNumberInput + Xor DX, DX + +GetSampleNumber1: + LodsB + And AL, AL + JZ GetSampleNumber2 + + Cmp AL, '0' + JB GetSampleNumber3 + Cmp AL, '9' + JA GetSampleNumber3 + + Sub AL, '0' + XChg DL, AL + Mov AH, 10 + Mul AH + Add DL, AL + + Jmp GetSampleNumber1 + +GetSampleNumber3: + StC + Ret + +GetSampleNumber2: + Test DX, DX + JZ GetSampleNumber3 + +; ClC + Ret + +EndP GetSampleNumber + +; + +Proc GetNumberInput ; DI = Offset of list. + ; Returns DX with sample number. + + Push DI + + Mov DI, Offset SampleNumberInput + Push CS + Pop ES + Xor AL, AL + Mov CX, 4 + Rep StosB + + Pop DI + + Call S_SaveScreen + + Mov CX, 3 + Call M_Object1List + + Call S_RestoreScreen + + And DX, DX + JZ GetNumberInput1 + + Call Music_Stop + + Call GetSampleNumber + JC GetNumberInput1 + + Ret + +GetNumberInput1: + Pop AX ; Add SP, 2 + Mov AX, 1 + RetF + +EndP GetNumberInput + +; + +Proc I_ExchangeSamples Far + + ; Clear input... + + EnsureNoNetwork + + Mov DI, Offset O1_ExchangeSampleList + Call GetNumberInput + + Mov SI, DX + Dec SI + Add SI, SI + + Call PE_GetLastInstrument + Add BX, BX + + Cmp BX, SI + JE I_ExchangeSamples1 + + Call Music_GetSongSegment + Mov ES, AX + Mov DS, AX + Mov DI, [DS:64912+BX] + Mov SI, [DS:64912+SI] ; DS:SI, ES:DI point to + ; sample headers + + Mov CX, 80 + +I_ExchangeSamples2: + Mov AL, [ES:DI] + MovsB + Mov [DS:SI-1], AL + + Loop I_ExchangeSamples2 + + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_ExchangeSamples1: + Mov AX, 1 + Ret + +EndP I_ExchangeSamples + +; + +Proc I_SwapSamples Far + + ; Clear input... + + EnsureNoNetwork + + Mov DI, Offset O1_SwapSampleList + Call GetNumberInput + + Mov SI, DX + Dec SI + Add SI, SI + + Call PE_GetLastInstrument + Mov DH, BL + Inc DH ; DH/DL = samples to swap + Add BX, BX + + Cmp DL, DH + JE I_SwapSamples1 + + Call Music_GetSongSegment + Mov ES, AX + Mov DS, AX + Mov DI, [DS:64912+BX] + Mov SI, [DS:64912+SI] ; DS:SI, ES:DI point to + ; sample headers + + Mov CX, 80 + +I_SwapSamples2: + Mov AL, [ES:DI] ; Swapping headers. + MovsB + Mov [DS:SI-1], AL + + Loop I_SwapSamples2 + + ; Now to swap pattern + ; stuff... + Call Music_GetInstrumentMode + JZ I_SwapSamples3 + ; Instrument mode.. + ; step through inst. + Xor AX, AX + +I_SwapSamples4: + Push AX + + Mov BX, AX + Add BX, BX + Mov SI, [DS:64712+BX] + Add SI, 41h + + Mov CX, 120 + +I_SwapSamples5: + Mov AL, [SI] + Cmp AL, DL + JNE I_SwapSamples6 + + Mov [SI], DH + Jmp I_SwapSamples7 + +I_SwapSamples6: + Cmp AL, DH + JNE I_SwapSamples7 + + Mov [SI], DL + +I_SwapSamples7: + Add SI, 2 + Loop I_SwapSamples5 + + Pop AX + + Inc AX + Cmp AX, 99 + JB I_SwapSamples4 + + Jmp I_SwapSamples8 + +I_SwapSamples3: ; Sample mode.. + Call PE_SwapInstruments + +I_SwapSamples8: + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_SwapSamples1: + Mov AX, 1 + Ret + +EndP I_SwapSamples + +; + +Proc I_ReplaceSample Far + + EnsureNoNetwork + + Mov DI, Offset O1_ReplaceSampleList + Call GetNumberInput + + Call PE_GetLastInstrument + Mov DH, BL + Inc DH ; DH/DL = samples to swap + + Cmp DL, DH + JE I_ReplaceSample1 + + Call Music_GetSongSegment + Mov ES, AX + Mov DS, AX + ; Now to swap pattern + ; stuff... + Call Music_GetInstrumentMode + JZ I_ReplaceSample3 + ; Instrument mode.. + ; step through inst. + Xor AX, AX + +I_ReplaceSample4: + Push AX + + Mov BX, AX + Add BX, BX + Mov SI, [DS:64712+BX] + Add SI, 41h + + Mov CX, 120 + +I_ReplaceSample5: + Mov AL, [SI] + + Cmp AL, DH + JNE I_ReplaceSample7 + + Mov [SI], DL + +I_ReplaceSample7: + Add SI, 2 + Loop I_ReplaceSample5 + + Pop AX + + Inc AX + Cmp AX, 99 + JBE I_ReplaceSample4 + + Mov AX, 1 + Ret + +I_ReplaceSample3: ; Sample mode.. + XChg DH, DL + Or DH, 80h + Call PE_SwapInstruments + +I_ReplaceSample1: + Mov AX, 1 + Ret + +EndP I_ReplaceSample + +; + +Proc I_ReMix + Assume DS:Nothing + + EnsureNoNetwork + + Call Music_Stop + ; OK... + Call I_GetSampleOffset + Mov EDX, CS:NewSampleSize + Mov AX, 99 + + Test Byte Ptr [BX+12h], 2 + JZ I_ReMix1 + + Add EDX, EDX + +I_ReMix1: + ; Limit size of EDX... + Cmp EDX, 4177920 + JBE I_ReMixLimitMaxSize + + Mov EDX, 4177920 + Mov CS:NewSampleSize, EDX + + Test Byte Ptr [BX+12h], 2 + JZ I_ReMixLimitMaxSize + + ShR CS:NewSampleSize, 1 + +I_ReMixLimitMaxSize: + Call Music_AllocateSample ; Returns ES:DI + Mov AX, ES + And AX, AX + JNZ I_ReMixEnoughMem + + Call PEFunction_OutOfMemoryMessage + +I_ReMixNoMix: + Ret + +I_ReMixEnoughMem: + Mov AX, DiskData + Mov ES, AX + Assume ES:Nothing + + Call PE_GetLastInstrument ; Into BX + Mov AX, BX + Inc AX + + Xor CX, CX + Call Music_GetSampleLocation ; Returns DS:ESI, ECX + JNZ I_ReMix16Bit + +I_ReMix8Bit: + Mov EAX, ECX + Xor EDX, EDX + Div CS:NewSampleSize + + Mov BP, AX + ShR EAX, 16 + JNZ I_ReMixNoMix + + Xor EAX, EAX ; BP:AX = skip value... + Div CS:NewSampleSize + + ShR EAX, 16 + Mov BX, AX + + ; BP:BX = skip value. + Xor ESI, ESI ; DS:ESI = source + Xor EDI, EDI ; Go from the start! + Xor CX, CX ; CX = error. + ; ES:EDI = destination + +I_ReMix8Bit2: + Cmp CS:Interpolate, 0 + JNE I_ReMix8BitInterpolate + + Mov AL, [SI] + Jmp I_ReMix8BitStore + +I_ReMix8BitInterpolate: + MovSX AX, Byte Ptr [SI] + Mov DX, 100h + Sub DL, CH + SbB DH, 0 + IMul DX ; AX = [SI]*(1-Remainder)*256 + + Push AX + + Add SI, 1 + JNC I_ReMix8BitInterpolate2 + + Add ESI, 10000h + Int 3 + +I_ReMix8BitInterpolate2: + MovSX AX, Byte Ptr [SI] + Mov DL, CH + Xor DH, DH + Mul DX + + Pop DX ; DX = Old AX = [SI]*(1-Remainder)*256 + Add AX, DX + Add AX, 80h ; Rounding. + Mov AL, AH + + Sub ESI, 1 + +I_ReMix8BitStore: + Mov [ES:DI], AL + + Add CX, BX + AdC SI, BP + JC I_ReMix8Bit3 + +I_ReMix8Bit4: + Add DI, 1 + JC I_ReMix8Bit5 + +I_ReMix8Bit6: + Cmp EDI, CS:NewSampleSize + JB I_ReMix8Bit2 + + Jmp I_ReMixCleanUp + +I_ReMix8Bit3: + Add ESI, 10000h + Int 3 + Jmp I_Remix8Bit4 + +I_ReMix8Bit5: + PushAD + Push DS + Push ES + + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + Mov ESI, EDI + Int 3 + + Push DS + Push ES + Pop DS + Pop ES + + Mov CX, 16384 + Xor SI, SI + Xor DI, DI + Rep MovsD + + Pop ES + Pop DS + PopAD + + Add EDI, 10000h + + Call I_RepositionSample + Jmp I_ReMix8Bit6 + +I_ReMix16Bit: + Mov EAX, ECX + Xor EDX, EDX + Div CS:NewSampleSize + + Mov BP, AX + Add BP, BP + ShR EAX, 15 + JNZ I_ReMixNoMix + + Xor EAX, EAX ; BP:AX = skip value... + Div CS:NewSampleSize + + ShR EAX, 16 + Mov BX, AX + + ; BP:BX = skip value. + Xor ESI, ESI ; DS:ESI = source + Xor EDI, EDI ; Go from the start! + Xor CX, CX ; CX = error. + ; ES:EDI = destination + +I_ReMix16Bit2: + Cmp CS:Interpolate, 0 + JNE I_ReMix16BitInterpolate + + Mov AX, [SI] + Jmp I_ReMix16BitStore + +I_ReMix16BitInterpolate: + Mov AX, [SI] ; AX = [SI]*(1-Remainder)*256 + Mov DX, 100h + Sub DL, CH + SbB DH, 0 + IMul DX ; DX:AX = [SI]*(1-Remainder)*256 + + Push DX + Push AX + + Add SI, 2 + JNC I_ReMix16BitInterpolate2 + + Add ESI, 10000h + Int 3 + +I_ReMix16BitInterpolate2: + Mov AX, [SI] + + MovZX DX, CH + IMul DX ; DX:AX = Remainder*256 + ShL EDX, 16 + Mov DX, AX + + Pop EAX + + Add EAX, EDX + Add EAX, 80h ; Rounding. + ShR EAX, 8 + + Sub ESI, 2 + +I_ReMix16BitStore: + Mov [ES:DI], AX + + Xor AX, AX + Add CX, BX + SetC AL + Add AX, AX + Add AX, BP + Add SI, AX + JC I_ReMix16Bit3 + +I_ReMix16Bit4: + Add DI, 2 + JC I_ReMix16Bit5 + +I_ReMix16Bit6: + Mov EAX, EDI + ShR EAX, 1 + Cmp EAX, CS:NewSampleSize + JB I_ReMix16Bit2 + + Jmp I_ReMixCleanUp + +I_ReMix16Bit3: + Add ESI, 10000h + Int 3 + Jmp I_Remix16Bit4 + +I_ReMix16Bit5: + PushAD + Push DS + Push ES + + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + Mov ESI, EDI + Int 3 + + Push DS + Push ES + Pop DS + Pop ES + + Mov CX, 16384 + Xor SI, SI + Xor DI, DI + Rep MovsD + + Pop ES + Pop DS + PopAD + + Add EDI, 10000h + + Call I_RepositionSample + Jmp I_ReMix16Bit6 + +I_ReMixCleanUp: + ; Copy leftover stuff... + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + Mov ESI, EDI + Int 3 + + Push DS + Push ES + Pop DS + Pop ES + + Mov CX, DI + Xor SI, SI + Xor DI, DI + Rep MovsB + + Call I_GetSampleOffset ; Gets DS:BX + Mov SI, BX + Mov ECX, [SI+30h] + Mov EBX, CS:NewSampleSize + ; ECX = length of old samp + ; EBX = length of new samp + Mov [SI+30h], EBX + Add SI, 34h + + Call Near Ptr I_ReMix5 + Call Near Ptr I_ReMix5 + Call Near Ptr I_ReMix5 + Call Near Ptr I_ReMix5 + Call Near Ptr I_ReMix5 + ; Now grab the data from Inst99 + Call I_SwapMemoryAllocation + + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + + Ret + +I_ReMix5: + Mov EAX, [SI] + Mul EBX + + Cmp EDX, ECX + JAE I_ReMix6 + + Div ECX + Cmp EAX, 9999999 + JB I_ReMix7 + +I_ReMix6: + Mov EAX, 9999999 + +I_ReMix7: + Mov [SI], EAX + Add SI, 4 + +I_ReMixEnd: + Ret + +EndP I_ReMix + Assume DS:Nothing + +; + +Proc I_ResizeSample Far + + Mov CS:Interpolate, 1 + Jmp I_ResizeJumpPoint + +EndP I_ResizeSample + +; + +Proc I_ResizeSampleNoInt Far + + Mov CS:Interpolate, 0 + +I_ResizeJumpPoint: + EnsureNoNetwork + + Call I_GetSampleOffset + Mov AL, [BX+12h] + Test AL, 1 + JZ I_ResizeSampleNoInt1 + + And AL, 2 + Mov CS:Quality, AL + + Cmp DWord Ptr [DS:BX+30h], 0 + JE I_ResizeSampleNoInt1 + + Mov EAX, [DS:BX+30h] ; Old length + Mov CS:NewSampleSize, EAX + + Call F_Reset5NumInputPos + Call S_SaveScreen + + Mov DI, Offset O1_ResizeSampleList + Mov CX, 3 + Call M_Object1List + + Call S_RestoreScreen + + And DX, DX + JZ I_ResizeSampleNoInt1 + + Push CS + Pop DS + Assume DS:Inst + + Mov EDX, NewSampleSize + And EDX, EDX + JZ I_ResizeSampleNoInt1 + + Call I_Remix + +I_ResizeSampleNoInt1: + Mov AX, 1 + Ret + +EndP I_ResizeSampleNoInt + Assume DS:Nothing + +; + +Proc I_CenterSample Far + + EnsureNoNetwork + + Call PE_GetLastInstrument + Mov AX, BX + Inc AX + + Xor CX, CX + Call Music_GetSampleLocation ; Gets DS:SI, and ECX. + ; Zero flag if 8 bit. + JNC I_CenterSample1 + + Xor AX, AX + Ret + +I_CenterSample1: + Push AX ; Remember sample num. + ; Scan through wave first, + ; and find max deviation from + ; mean. + JNZ I_CenterSamplePre16Bit1 + Mov BL, [SI] + Mov DL, [SI] + +I_CenterSamplePre8Bit1: + Mov AL, [SI] + Cmp AL, BL + JL I_CenterSamplePre8Bit3 + Cmp AL, DL + JG I_CenterSamplePre8Bit4 + +I_CenterSamplePre8Bit2: + Add SI, 1 + JC I_CenterSamplePre8BitNextBlock + +I_CenterSamplePre8Bit5: + LoopD I_CenterSamplePre8Bit1 + + MovSX BX, BL + MovSX DX, DL + + Add BX, DX + Neg BX + SAR BX, 1 + + Jmp I_CenterSample2 + +I_CenterSamplePre8Bit3: + Mov BL, AL + Jmp I_CenterSamplePre8Bit2 + +I_CenterSamplePre8Bit4: + Mov DL, AL + Jmp I_CenterSamplePre8Bit2 + +I_CenterSamplePre8BitNextBlock: + Add ESI, 10000h + Int 3 + + Jmp I_CenterSamplePre8Bit5 + +I_CenterSamplePre16Bit: + Mov BX, [SI] + Mov DX, [SI] + +I_CenterSamplePre16Bit1: + Mov AX, [SI] + Cmp AX, BX + JL I_CenterSamplePre16Bit3 + Cmp AX, DX + JG I_CenterSamplePre16Bit4 + +I_CenterSamplePre16Bit2: + Add SI, 2 + JC I_CenterSamplePre16BitNextBlock + +I_CenterSamplePre16Bit5: + LoopD I_CenterSamplePre16Bit1 + + MovSX EBX, BX + MovSX EDX, DX + Add EBX, EDX + Neg EBX + SAR EBX, 1 + + Jmp I_CenterSample2 + +I_CenterSamplePre16Bit3: + Mov BX, AX + Jmp I_CenterSamplePre16Bit2 + +I_CenterSamplePre16Bit4: + Mov DX, AX + Jmp I_CenterSamplePre16Bit2 + +I_CenterSamplePre16BitNextBlock: + Add ESI, 10000h + Int 3 + Jmp I_CenterSamplePre16Bit5 + +I_CenterSample2: + Push BX + + Mov DI, Offset O1_SampleCenterList + Mov CX, 3 + Call M_Object1List + + Pop BX + Pop AX ; AX = sample num + Test DL, 1 + JZ I_CenterSampleEnd + + Call Music_Stop + + Xor CX, CX + Call Music_GetSampleLocation ; Loads DS:ESI and ECX again. + JNZ I_CenterSample16Bit1 + +I_CenterSample8Bit1: + Add [SI], BL + Add SI, 1 + JC I_CenterSample8BitNextBlock + +I_CenterSample8Bit2: + LoopD I_CenterSample8Bit1 + Jmp I_CenterSample3 + +I_CenterSample8BitNextBlock: + Add ESI, 10000h + Int 3 + Jmp I_CenterSample8Bit2 + +I_CenterSample16Bit1: + Add [SI], BX + Add SI, 2 + JC I_CenterSample16BitNextBlock + +I_CenterSample16Bit2: + LoopD I_CenterSample16Bit1 + Jmp I_CenterSample3 + +I_CenterSample16BitNextBlock: + Add ESI, 10000h + Int 3 + Jmp I_CenterSample16Bit2 + +I_CenterSample3: + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_CenterSampleEnd: + Mov AX, 1 + Ret + +EndP I_CenterSample + +; + +Proc I_AmplifySample Far + + EnsureNoNetwork + + Call PE_GetLastInstrument + Mov AX, BX + Inc AX + + Xor CX, CX + Call Music_GetSampleLocation ; Gets DS:SI, and ECX. + JNC I_AmplifySample1 + + Xor AX, AX + Ret + +I_AmplifySample1: + Push AX ; Remember sample num. + ; Scan through wave first, + ; and find max deviation from + ; mean. + Mov BX, 0 ; BX = deviation from mean + JNZ I_AmplifySample11 ; 16 bit stuff. + +I_AmplifySample2: + Mov AL, [SI] +; Sub AL, 80h + CBW + Xor AL, AH + Sub AL, AH + + Cmp AL, BH + JB I_AmplifySample3 + + Mov BH, AL + +I_AmplifySample3: + Add SI, 1 + JC I_AmplifySample8 + +I_AmplifySample9: + LoopD I_AmplifySample2 + Jmp I_AmplifySample10 + +I_AmplifySample8: + Add ESI, 10000h + Int 3 + Jmp I_AmplifySample9 + +I_AmplifySample11: + Mov AX, [SI] +; Sub AX, 8000h + CWD + Xor AX, DX + Sub AX, DX + Cmp AX, BX + JB I_AmplifySample12 + + Mov BX, AX + +I_AmplifySample12: + Add SI, 2 + JC I_AmplifySample13 + +I_AmplifySample14: + LoopD I_AmplifySample11 + Jmp I_AmplifySample10 + +I_AmplifySample13: + Add ESI, 10000h + Int 3 + Jmp I_AmplifySample14 + + +I_AmplifySample10: + ; OK. so BL contains max dev. + ; Amplificat = (8000h/MaxDev)*100 + Xor AX, AX + Mov DX, 32h + + Cmp DX, BX + JAE I_AmplifySample4 + + Div BX + + Cmp AX, 400 + JB I_AmplifySample5 + +I_AmplifySample4: + Mov AX, 400 + +I_AmplifySample5: + Mov CS:SampleAmplification, AX + + Mov DI, Offset O1_SampleAmplificationList + Mov CX, 3 + Call M_Object1List + + Pop AX ; AX = sample num + And DX, DX + JZ I_AmplifySampleEnd + + Call Music_Stop + + Xor CX, CX + Call Music_GetSampleLocation ; Loads DS:ESI and ECX again. + + PushF + + ; NewSample = OldSample*SampleAmplification/100, clipped. + + Mov AX, CS:SampleAmplification + Xor DX, DX + Mov BX, 100 + Div BX + ShL EAX, 16 + Div BX + Mov EBX, EAX ; EBX = multiplier, 16.16 bit. + + PopF + JNZ I_AmplifySample20 + +I_AmplifySample6: + MovSX EAX, Byte Ptr [SI] + + IMul EBX + + Add EAX, 8000h ; Rounding factor + ShR EAX, 16 + + Cmp AX, 7Fh + JGE I_AmplifySampleClip1 + + Cmp AX, -80h + JGE I_AmplifySample7 + + Mov AL, 80h + Jmp I_AmplifySample7 + +I_AmplifySampleClip1: + Mov AL, 7Fh + +I_AmplifySample7: + Mov [SI], AL + Add SI, 1 + JC I_AmplifySample16 + +I_AmplifySample17: + LoopD I_AmplifySample6 + Jmp I_AmplifySample15 + +I_AmplifySample16: + Add ESI, 10000h + Int 3 + Jmp I_AmplifySample17 + +I_AmplifySample20: ; 16 bit amplification!, EBX = 16.16 bit multiplier. + ; Newsample = OldSample*SampleAmplification/100 + + Mov AX, [SI] + MovSX EAX, AX + + IMul EBX + Add EAX, 8000h ; Rounding factor + AdC EDX, 0 ; Rounding stuff, etc. + + ShRD EAX, EDX, 16 + + Cmp EAX, 7FFFh + JGE I_AmplifySampleClip2 + + Cmp EAX, -8000h + JGE I_AmplifySample18 + + Mov AX, 8000h + Jmp I_AmplifySample18 + +I_AmplifySampleClip2: + Mov AX, 7FFFh + +I_AmplifySample18: + Mov [SI], AX + + Add SI, 2 + JC I_AmplifySample21 + +I_AmplifySample19: + LoopD I_AmplifySample20 + Jmp I_AmplifySample15 + +I_AmplifySample21: + Add ESI, 10000h + Int 3 + Jmp I_AmplifySample19 + +I_AmplifySample15: + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_AmplifySampleEnd: + Mov AX, 1 + Ret + +EndP I_AmplifySample + +; + +Proc I_ReverseSample Far + + EnsureNoNetwork + + Call PE_GetLastInstrument + Mov AX, BX + Inc AX + + Xor CX, CX + Call Music_GetSampleLocation ; Gets DS:SI, and CX. + JC I_ReverseSample1 + + JNZ I_ReverseSample10 + + Call Music_Stop + + Push ECX + + Mov EDX, ECX + Mov AX, 99 + Call Music_AllocateSample ; Returns ES:DI + Mov AX, ES + And AX, AX + + Pop ECX + + JZ I_ReverseSampleError + + Mov ESI, ECX + Dec ESI + Call I_RepositionSample + + Mov AX, DiskData + Mov ES, AX + Assume ES:Nothing + + Xor EDI, EDI + +I_ReverseSample2: + Mov AL, [SI] + Mov [ES:DI], AL + + Sub SI, 1 + JC I_ReverseSample4 + +I_ReverseSample5: + Add DI, 1 + JC I_ReverseSample6 + +I_ReverseSample7: + LoopD I_ReverseSample2 + Jmp I_ReverseSample3 + +I_ReverseSample4: + Sub ESI, 10000h + JC I_ReverseSample5 + Int 3 + + Jmp I_ReverseSample5 + +I_ReverseSample6: + PushAD + Push DS + Push ES + + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + Mov ESI, EDI + Int 3 + + Push DS + Push ES + + Pop DS + Pop ES + + Xor SI, SI + Xor DI, DI + Mov CX, 16384 + Rep MovsD + + Pop ES + Pop DS + PopAD + Add EDI, 10000h + Call I_RepositionSample + Jmp I_ReverseSample7 + +I_ReverseSample10: + Call Music_Stop + + Push ECX + + Mov EDX, ECX + Add EDX, EDX + Mov AX, 99 + Call Music_AllocateSample ; Returns ES:DI + Mov AX, ES + And AX, AX + + Pop ECX + + JZ I_ReverseSampleError + + Mov ESI, ECX + Dec ESI + Add ESI, ESI + Call I_RepositionSample + + Mov AX, DiskData + Mov ES, AX + Assume ES:Nothing + + Xor EDI, EDI + +I_ReverseSample12: + Mov AX, [SI] + Mov [ES:DI], AX + + Sub SI, 2 + JC I_ReverseSample14 + +I_ReverseSample15: + Add DI, 2 + JC I_ReverseSample16 + +I_ReverseSample17: + LoopD I_ReverseSample12 + Jmp I_ReverseSample3 + +I_ReverseSample14: + Sub ESI, 10000h + JC I_ReverseSample15 + Int 3 + + Jmp I_ReverseSample15 + +I_ReverseSample16: + PushAD + Push DS + Push ES + + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + Mov ESI, EDI + Int 3 + + Push DS + Push ES + + Pop DS + Pop ES + + Xor SI, SI + Xor DI, DI + Mov CX, 16384 + Rep MovsD + + Pop ES + Pop DS + PopAD + Add EDI, 10000h + Call I_RepositionSample + Jmp I_ReverseSample17 + + +I_ReverseSampleError: + Call PEFunction_OutOfMemoryMessage + + Mov AX, 1 + Ret + +I_ReverseSample3: + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + + Mov ESI, EDI + Int 3 + + Mov CX, DI + + Push DS + Push ES + Pop DS + Pop ES + + Xor SI, SI + Xor DI, DI + Rep MovsB + + ; Now to release old memory, and swap + ; in new lot... + Call I_SwapMemoryAllocation + + Call I_GetSampleOffset ; Returns DS:BX + + Mov EDX, [BX+30h] ; DX = length + Mov EAX, EDX + Mov ECX, EDX + + Sub EAX, [BX+34h] + Sub ECX, [BX+38h] + Mov [BX+34h], ECX + Mov [BX+38h], EAX + + Mov EAX, EDX + Mov ECX, EDX + + Sub EAX, [BX+40h] + Sub ECX, [BX+44h] + Mov [BX+40h], ECX + Mov [BX+44h], EAX + + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_ReverseSample1: + Mov AX, 1 + Ret + +EndP I_ReverseSample + +; + +Proc I_SwapMemoryAllocation + + Call I_GetSampleOffset ; Gets DS:BX + Mov SI, [DS:64912+99*2] + Mov EAX, [SI+48h] + XChg [BX+48h], EAX + Mov [SI+48h], EAX + + Mov AX, 99 + Call Music_ReleaseSample + + Ret + +EndP I_SwapMemoryAllocation + +; + +Proc I_RepositionSample + + + Push AX + Push BX + Push ECX + Push ESI + + Call PE_GetLastInstrument + Mov AX, BX ; AX = sample no. + Inc AX + Xor CX, CX + Call Music_GetSampleLocation ; Return DS:ESI, ECX + + Pop ESI + Int 3 + + Pop ECX + Pop BX + Pop AX + Ret + +EndP I_RepositionSample + +; + +Proc I_ToggleSampleQuality Far + + EnsureNoNetwork + + Call I_GetSampleOffset + Mov AL, [BX+12h] + Test AL, 1 + JZ I_ToggleSampleQuality1 + + Test AL, 2 + JZ I_To16Bit + +I_To8Bit: + Push DS + Push BX + + Mov DI, Offset O1_ConfirmConvert2List + Mov CX, 3 + Call M_Object1List + + Pop BX + Pop DS + + And DX, DX + JZ I_ToggleSampleQuality1 + + Call Music_Stop + + Cmp DX, 1 + JE I_ConvertTo8Bit + + And Byte Ptr [BX+12h], Not 2 + + ShL DWord Ptr [BX+30h], 1 + ShL DWord Ptr [BX+34h], 1 + ShL DWord Ptr [BX+38h], 1 + ShL DWord Ptr [BX+40h], 1 + ShL DWord Ptr [BX+44h], 1 + + Jmp I_ToggleSampleQualityEnd + +I_ConvertTo8Bit: + Mov EDX, [BX+30h] + Mov AX, 99 ; Shove it into inst 99 first. + Call Music_AllocateSample + + Mov AX, ES + And AX, AX + JZ I_OutOfMemory + + And Byte Ptr [BX+12h], Not 2 + + Call PE_GetLastInstrument + Mov AX, BX ; AX = sample no. + Inc AX + + Xor CX, CX + Call Music_GetSampleLocation ; Return DS:ESI + + Mov AX, DiskData + Mov ES, AX + Assume ES:Nothing + + Xor EDI, EDI + +I_ConvertTo8Bit1: + Mov AX, [SI] +; Add AX, 80h +; SBB AH, 0 + Mov [ES:DI], AH + + Add SI, 2 + JC I_ConvertTo8Bit2 + +I_ConvertTo8Bit3: + Add DI, 1 + JC I_ConvertTo8Bit5 + +I_ConvertTo8Bit4: + LoopD I_ConvertTo8Bit1 + + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + + Mov ESI, EDI + Int 3 + + Mov CX, DI + + Push DS + Push ES + Pop DS + Pop ES + + Xor SI, SI + Xor DI, DI + Rep MovsB + + ; Now to release old memory, and swap + ; in new lot... + Call I_SwapMemoryAllocation + + Jmp I_ToggleSampleQualityEnd + +I_ConvertTo8Bit2: + Add ESI, 10000h + Int 3 + Jmp I_ConvertTo8Bit3 + +I_ConvertTo8Bit5: + PushAD + Push DS + Push ES + + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + + Mov ESI, EDI + Int 3 + + Push DS + Push ES + + Pop DS + Pop ES + + Xor SI, SI + Xor DI, DI + Mov CX, 16384 + Rep MovsD + + Pop ES + Pop DS + PopAD + + Call I_RepositionSample + + Add EDI, 10000h + Jmp I_ConvertTo8Bit4 + +I_OutOfMemory: + Call PEFunction_OutOfMemoryMessage + Jmp I_ToggleSampleQuality1 + +I_To16Bit: + Push DS + Push BX + + Mov DI, Offset O1_ConfirmConvert2List + Mov CX, 3 + Call M_Object1List + + Pop BX + Pop DS + + And DX, DX + JZ I_ToggleSampleQuality1 + + Call Music_Stop + + Cmp DX, 1 + JE I_ConvertTo16Bit + + Or Byte Ptr [BX+12h], 2 + + ShR DWord Ptr [BX+30h], 1 + ShR DWord Ptr [BX+34h], 1 + ShR DWord Ptr [BX+38h], 1 + ShR DWord Ptr [BX+40h], 1 + ShR DWord Ptr [BX+44h], 1 + + Jmp I_ToggleSampleQualityEnd + +I_ConvertTo16Bit: + Mov EDX, [BX+30h] + Add EDX, EDX + Mov AX, 99 ; Shove it into inst 99 first. + Call Music_AllocateSample + + Mov AX, ES + And AX, AX + JZ I_OutOfMemory + + Or Byte Ptr [BX+12h], 2 + + Mov ECX, [BX+30h] + Xor ESI, ESI + Call I_RepositionSample + + Mov AX, DiskData + Mov ES, AX + Assume ES:Nothing + + Xor EDI, EDI + +I_ConvertTo16Bit1: + Mov AH, [SI] + Xor AL, AL + Mov [ES:DI], AX + + Add SI, 1 + JC I_ConvertTo16Bit2 + +I_ConvertTo16Bit3: + Add DI, 2 + JC I_ConvertTo16Bit5 + +I_ConvertTo16Bit4: + LoopD I_ConvertTo16Bit1 + + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + + Mov ESI, EDI + Int 3 + + Mov CX, DI + + Push DS + Push ES + Pop DS + Pop ES + + Xor SI, SI + Xor DI, DI + Rep MovsB + + Call I_SwapMemoryAllocation + + Jmp I_ToggleSampleQualityEnd + +I_ConvertTo16Bit2: + Add ESI, 10000h + Int 3 + Jmp I_ConvertTo16Bit3 + +I_ConvertTo16Bit5: + PushAD + Push DS + Push ES + + Mov AX, 100 + Xor CX, CX + Call Music_GetSampleLocation + + Mov ESI, EDI + Int 3 + + Push DS + Push ES + + Pop DS + Pop ES + + Xor SI, SI + Xor DI, DI + Mov CX, 16384 + Rep MovsD + + Pop ES + Pop DS + PopAD + + Call I_RepositionSample + + Add EDI, 10000h + Jmp I_ConvertTo16Bit4 + +I_ToggleSampleQualityEnd: + Call I_DrawWaveForm + Call Music_SoundCardLoadAllSamples + +I_ToggleSampleQuality1: + Mov AX, 1 + Ret + +EndP I_ToggleSampleQuality + +; + +Proc I_DrawInstrumentWindow Far + + Call S_GetDestination + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + Test AL, AL + JNZ I_DrawInstrumentWindow1 + + Inc AX + Mov LastInstrument, AL + +I_DrawInstrumentWindow1: ; AL = last instrument + Xor AH, AH ; Now for bounds check. + + Push CS + Pop DS + Assume DS:Inst + + Mov BX, TopInstrument + Cmp AX, BX + JAE I_DrawInstrumentWindow2 + + Mov BX, AX + +I_DrawInstrumentWindow2: + Mov CX, BX + Add CX, 34 + Cmp CX, AX + JAE I_DrawInstrumentWindow3 + + Mov BX, AX + Sub BX, 34 + +I_DrawInstrumentWindow3: + Mov TopInstrument, BX ; OK.. now to draw nums + Push AX + + Mov DI, (2+13*80)*2 + + Mov DX, 0A23h + +I_DrawInstrumentWindow4: + Mov AX, BX + Div DH + ; AH = units, AL = tens + Add AL, '0' + StosB + Mov AL, 20h + StosB + XChg AH, AL + Add AL, '0' + StosW + + Inc BX + Add DI, 156 + Dec DL + JNE I_DrawInstrumentWindow4 + + Mov BX, TopInstrument + + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + + Mov DX, 35 + Mov DI, (5+13*80)*2 + Dec BX + Mov SI, BX + Add SI, SI + Mov SI, [SI+64712] + Add SI, 20h + + Pop CX ; CX = last instrument + Dec CX + +I_DrawInstrumentWindow5: + Push CX + + Mov AH, 6 + Cmp BX, CX + JNE I_DrawInstrumentWindow7 + + Mov AH, 0E6h + +I_DrawInstrumentWindow7: + Mov CX, 25 + +I_DrawInstrumentWindow6: + LodsB + + Cmp AL, 226 + JB I_DrawInstrumentNoMouse + + Mov AL, ' ' + +I_DrawInstrumentNoMouse: + StosW + Loop I_DrawInstrumentWindow6 + + Add DI, 160-(25*2) + Add SI, 554-25 + Pop CX + + Inc BX + Dec DX + JNZ I_DrawInstrumentWindow5 + + Push CS + Pop DS + + Mov SI,Offset SampleMouseEvent + Mov Word Ptr [SI+4], 30*8-1 + Mov Word Ptr [SI+10], 4 + Call AddSelectEvent + Mov SI, Offset SampleMouseOffEvent + Mov Word Ptr [SI+4], 30*8-1 + Call MouseAddEvent + + Ret + +EndP I_DrawInstrumentWindow + Assume DS:Nothing + +; + +Proc I_PreInstrumentWindow Far + + Call S_GetDestination + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, LastInstrument + Xor AH, AH + Mov SI, AX + Sub AX, TopInstrument + Add AX, 13 + Mov BX, 160 + Mul BX + Add AX, 11 + Mov DI, AX + Cmp InstrumentEdit, 1 + JE I_PreInstrumentWindow2 + + Mov CX, 25 + +I_PreInstrumentWindow1: + Mov Byte Ptr [ES:DI], 30h +; Add DI, 2 + ScasW + + Loop I_PreInstrumentWindow1 + Ret + +I_PreInstrumentWindow2: + Mov AX, CS:InstrumentPos + Add AX, AX + Add DI, AX + Mov Byte Ptr [ES:DI], 30h + + Ret + +EndP I_PreInstrumentWindow + Assume DS:Nothing + +; + +Proc MIDI_AllocateChannel Far ; Given AX = Base channel, DL = note + ; Finds physical channel, returns AX + ; if no channel available, then + ; overtakes channel at base channel + ; Given DI = max channel + Push BX CX DX SI DS + + Push DX + + Push CS + Pop DS + Assume DS:Inst + + Mov DX, AX + Mov BX, AX + +MIDI_AllocateChannel1: + Inc DX + Cmp DX, DI + JA MIDI_AllocateChannelOvertake + + Mov SI, Offset MIDITable + Mov CX, 128 + +MIDI_AllocateChannel2: + LodsB + Cmp AL, DL + JE MIDI_AllocateChannel1 + Loop MIDI_AllocateChannel2 + + Mov AX, DX + Jmp MIDI_AllocateChannelEnd + +MIDI_AllocateChannelOvertake: ; Search for basechannel + Mov SI, Offset MIDITable + +MIDI_AllocateChannel3: + LodsB + Cmp AL, DL + JNE MIDI_AllocateChannel3 + + ; Clear out last entry... + Mov Byte Ptr [SI-1], 0 + Mov AX, BX + Inc AX + +MIDI_AllocateChannelEnd: + Pop BX ; BL = note + And BX, 07Fh + Mov [MIDITable+BX], AL + + Dec AX + + Pop DS SI DX CX BX + Ret + +EndP MIDI_AllocateChannel + + +; + +Proc MIDI_GetChannel Far + + Xor AX, AX + Mov AL, [CS:MIDITable+BX] + Ret + +EndP MIDI_GetChannel + +; + +Proc MIDI_FindChannel Far ; Given BX = Note, returns AX = channel + ; number, cleans up table, AL = 0FFh = + ; note not present + + Xor AX, AX + XChg [CS:MIDITable+BX], AL + Dec AL + + Ret + +EndP MIDI_FindChannel + +; + +Proc MIDI_ClearTable Far + + Push AX CX ES DI + + Push CS + Pop ES + + Mov DI, Offset MIDITable + Xor AX, AX + Mov CX, 64 + Rep StosW + + Pop DI ES CX AX + + Ret + +EndP MIDI_ClearTable + +; + +Proc MIDI_NoteOff Far + + Push CS + Pop DS + Assume DS:Inst + + ; DL = note +MIDI_NoteOff2: + Call Music_GetInstrumentMode + Mov CX, 0FFh + JNZ MIDI_NoteOff3 + + Dec CX + +MIDI_NoteOff3: + MovZX BX, DL + Call MIDI_FindChannel + Cmp AL, 0FFh + JE MIDI_NoteOff1 + + Mov SI, Offset NoteData + Mov Word Ptr [SI], CX ; Note off/cut + Mov Word Ptr [SI+3], 0 ; No effect + Mov DH, 32 + Call Music_PlayNote + +MIDI_NoteOff1: + Mov AX, 1 +; Xor AX, AX + Ret + +EndP MIDI_NoteOff + Assume DS:Nothing + +; + +Proc MIDI_PlayNote Far + + Push CS + Pop DS + Assume DS:Inst + + Call PE_TranslateMIDI + JC MIDI_PlayNote1 + JZ MIDI_NoteOff2 + + Call PE_GetLastInstrument + Mov AH, BL + Inc AH + Mov AL, DL ; Note + + Mov SI, Offset NoteData + Mov [SI], AX + Mov [SI+2], DH + Mov Word Ptr [SI+3], 0 + + Call Music_GetNumChannels ; Into AX + Mov DI, AX + Mov AX, PlayChannel + Call PE_RestoreMIDINote + Call MIDI_AllocateChannel + + Mov DH, 32 + Call Music_PlayNote + + Mov Byte Ptr [SI+2], 0FFh + Mov AX, 1 + Ret + +MIDI_PlayNote1: + Xor AX, AX + Ret + + +EndP MIDI_PlayNote + Assume DS:Nothing + +; + +Proc I_PlayNote Far + + Push CS + Pop DS + Assume DS:Inst + + Test CH, Not 1 + JNZ I_PlayNote5 + + Cmp CX, LastKey + JE I_PlayNote5 + + Mov LastKey, CX + + Mov SI, Offset KeyBoardTable + +I_PlayNote1: + LodsW + Cmp AX, 0FFFFh + JE I_PlayNote5 + + Mov BX, AX + LodsW + + Cmp BL, CL + JNE I_PlayNote1 + ; Note to play... + ; AX = notemod. + Mov CL, AL + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, 12 + Mul BaseOctave + Add AL, CL + Cmp AL, 119 + JBE I_PlayNoteMax + + Mov AL, 119 + +I_PlayNoteMax: + Mov DL, AL + + Test CH, CH + JZ MIDI_NoteOff + + Call PE_GetLastInstrument + Mov AH, BL + Inc AH + + Push CS + Pop DS + + MovZX BX, AL + Cmp [MIDITable+BX], 0 + JNE I_PlayNote6 + + Call UpdateMultiChannel + + Mov PlayNote, AL + +I_PlayNote3: + Mov SI, Offset NoteData + Mov [SI], AX + + Push DS + + Call I_GetInstrumentOffset + + Test Byte Ptr [BX+19h], 80h + Mov DH, 32 + JZ I_PlayNote4 + + Add DH, 128 + +I_PlayNote4: + Pop DS + Call Music_GetNumChannels ; Into AX + Mov DI, AX + Mov AX, PlayChannel + Call MIDI_AllocateChannel + Call Music_PlayNote + +I_PlayNote6: + Mov AX, 1 + Ret + +I_PlayNote5: + Xor AX, AX + Ret + +EndP I_PlayNote + Assume DS:Nothing + +; + +Proc I_PostInstrumentWindow Far + Assume DS:Inst + + Push CS + Pop DS + Mov SI, Offset InstrumentListKeys + Call M_FunctionDivider + JC I_PostInstrumentWindow1 + + Jmp [SI] + +I_PostInstrumentWindow1: + Cmp InstrumentEdit, 0 + JE I_PostInstrumentWindow7 + + Cmp CX, 101h + JE I_PostInstrumentWindow15 + Cmp CX, 11Ch + JNE I_PostInstrumentWindow13 + +I_PostInstrumentWindow15: + Mov InstrumentEdit, 0 + Jmp I_PostInstrumentWindow12 + +I_PostInstrumentWindow13: + Call PE_GetLastInstrument + Mov SI, BX + Mov BX, InstrumentPos + ; BX = Pos, SI = LastInst + Call Music_GetSongSegment + Mov DS, AX + Assume DS:Nothing + + Add SI, SI + Mov SI, [64712+SI] ; SI = instrument offset. + + Test CL, CL + JZ I_PostInstrumentWindow3 + Cmp DL, 32 + JB I_PostInstrumentWindow3 + + Add BX, 20h + Add BX, SI + Add SI, 38h + +I_PostInstrumentWindow2: + Cmp SI, BX + JBE I_PIW2 + + Mov AL, [SI-1] + Mov [SI], AL + Dec SI + Jmp I_PostInstrumentWindow2 + +I_PIW2: + + Mov [SI], DL + NetworkSendInstrument + + Push CS + Pop DS + Jmp I_InstrumentRight + +I_PostInstrumentWindow3: + Cmp CX, 10Eh ; Backspace + JNE I_PostInstrumentWindow5 + + And BX, BX + JZ I_PostInstrumentWindow6 + + Dec InstrumentPos + Add BX, 20h + Add BX, SI + Add SI, 39h + +I_PostInstrumentWindow4: + Mov AL, [BX] + Mov [BX-1], AL + Inc BX + Cmp BX, SI + JB I_PostInstrumentWindow4 + + Mov Byte Ptr [BX-1], 0 + NetworkSendInstrument + +I_PostInstrumentWindow12: + + Mov AX, 1 + Ret + +I_PostInstrumentWindow5: + Assume DS:Inst + + Cmp CX, 1D3h ; Delete... + JNE I_PostInstrumentWindow6 + + Add BX, 21h + Add BX, SI + Add SI, 39h + Jmp I_PostInstrumentWindow4 + +I_PostInstrumentWindow6: + Xor AX, AX + Ret + +I_PostInstrumentWindow7: + Assume DS:Inst + Cmp DX, ' ' ; Spacebar + JNE I_PostInstrumentWindow14 + + Mov InstrumentEdit, 1 + Mov InstrumentPos, 0 + + Mov AX, 1 + Ret + +I_PostInstrumentWindow14: + Xor AX, AX + Ret + +EndP I_PostInstrumentWindow + Assume DS:Nothing + +; + +Proc I_InstrumentLeft Far + + Assume DS:Inst + + Cmp InstrumentEdit, 0 + JE I_InstrumentLeft2 + + Cmp InstrumentPos, 0 + JE I_InstrumentLeft1 + + Dec InstrumentPos +; Jmp I_InstrumentLeft1 + +I_InstrumentLeft2: +; Mov Word Ptr [ES:DI], 8 + +I_InstrumentLeft1: + Mov AX, 1 + Ret + +EndP I_InstrumentLeft + Assume DS:Nothing + +; + +Proc I_InstrumentRight Far + + Assume DS:Inst + + Cmp InstrumentEdit, 0 + JE I_InstrumentRight2 + + Cmp InstrumentPos, 24 + JAE I_InstrumentRight1 + + Inc InstrumentPos + Jmp I_InstrumentRight1 + +I_InstrumentRight2: + Mov Word Ptr [ES:DI], 5 + +I_InstrumentRight1: + Mov AX, 1 + Ret + + +EndP I_InstrumentRight + Assume DS:Nothing + +; + +Proc I_InstrumentHome Far + + Assume DS:Inst + + Mov InstrumentPos, 0 + + Mov AX, 1 + Ret + +EndP I_InstrumentHome + Assume DS:Nothing + +; + +Proc I_InstrumentEnd Far + + Assume DS:Inst + + Mov InstrumentPos, 24 + + Mov AX, 1 + Ret + +EndP I_InstrumentEnd + Assume DS:Nothing + +; + +Proc I_InstrumentTab Far + + Mov Word Ptr [ES:DI], 5 + + Mov AX, 1 + Ret + +EndP I_InstrumentTab + +; + +Proc I_InstrumentShiftTab Far + + Mov Word Ptr [ES:DI], 8 + + Mov AX, 1 + Ret + +EndP I_InstrumentShiftTab + +; + +Proc I_InstrumentNameClear Far + + Call I_GetInstrumentOffset + Push DS + Pop ES + Mov DI, BX + + Xor AX, AX + Mov CX, 6 + Add DI, 4 + Rep StosW + + Add DI, 10h + Mov CX, 13 + Rep StosW + + NetworkSendInstrument + + Inc AX + Ret + +EndP I_InstrumentNameClear + +; + +Proc I_InstrumentClear Far + + Call PE_GetLastInstrument + Mov AX, BX + Call Music_ClearInstrument + + Call I_MapEnvelope + + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_InstrumentClear + +; + +Proc I_DrawNoteWindow Far + + Push CS + Pop DS + Assume DS:Inst + + Mov SI, Offset NoteMouseEvent + Call AddSelectEvent + Mov SI, Offset NoteMouseOffEvent + Call MouseAddEvent + + Mov AX, CurrentNote + ; Now for bounds check. + + Mov BX, TopNote + Cmp AX, BX + JAE I_DrawNoteWindow2 + + Mov BX, AX + +I_DrawNoteWindow2: + Mov CX, BX + Add CX, 31 + Cmp CX, AX + JAE I_DrawNoteWindow3 + + Mov BX, AX + Sub BX, 31 + +I_DrawNoteWindow3: + Mov TopNote, BX ; OK.. now to draw nums + Mov CX, BX + + Call S_GetDestination + + Call I_GetInstrumentOffset + Add BX, 40h + Add BX, CX + Add BX, CX + Mov DI, (32+16*80)*2 + + Mov DX, 0C20h + XChg SI, BX + ; DS:SI = pointer to translation + ; ES:DI = screen + ; CX = Current note. +I_DrawNoteWindow4: + ; Draw left hand note first. + Mov AX, CX + Div DH ; AH = note, AL = octave. + Push AX + + Mov AL, AH + Mov BX, AX + And BX, 0FFh ; BX = note. + Add BX, BX ; BX = note*2 + Mov AH, 2 + Mov AL, [CS:BX+NoteTable] + StosW + Mov AL, [CS:BX+NoteTable+1] + StosW + + Pop AX ; AL = octave + Add AL, '0' + Mov AH, 2 + StosW + + ; View division... + Mov AL, 0A8h + StosW + ; Note translation... + + LodsB ; AL = note.. + Xor AH, AH + Div DH + Push AX + + Mov AL, AH + Mov BX, AX + And BX, 0FFh ; BX = note. + Add BX, BX ; BX = note*2 + Mov AH, 2 + Mov AL, [CS:BX+NoteTable] + StosW + Mov AL, [CS:BX+NoteTable+1] + StosW + + Pop AX ; AL = octave + Add AL, '0' + Mov AH, 2 + StosW + + Mov AL, ' ' + StosW + ; Now sample number. + LodsB ; AL = sample number (base 0) +; Inc AL ; Convert to base 1 + + And AL, AL + JNZ I_DrawNoteWindow5 + + Mov AL, 173 + StosW + StosW + Jmp I_DrawNoteWindow6 + +I_DrawNoteWindow5: + Xor AH, AH + Mov BL, 10 + Div BL ; AH = units, AL = tens. + Add AX, 3030h + Mov BL, AH + Mov AH, 2 + StosW + Mov AL, BL + StosW + +I_DrawNoteWindow6: + Add DI, 160-10*2 + + Inc CX + Dec DL + JNZ I_DrawNoteWindow4 + + Ret + +EndP I_DrawNoteWindow + +; + +Proc I_PreNoteWindow Far + + Push CS + Pop DS + Assume DS:Inst + + Call S_GetDestination + Mov AX, CurrentNote + Sub AX, TopNote + Add AX, 16 + Mov BX, 160 + Mul BX + Add AX, 32*2 + Mov DI, AX ; First hilight the row.. + + Mov CX, 10 + Push DI + +I_PreNoteWindow1: + Inc DI + Or Byte Ptr [ES:DI], 0E0h + Inc DI + Loop I_PreNoteWindow1 + + Pop DI + + Mov BX, NotePos + Mov BL, [NotePosTable+BX] + Xor BH, BH + Add DI, BX + Add DI, BX + + Inc DI + Mov Byte Ptr [ES:DI], 30h + + Ret + +EndP I_PreNoteWindow + Assume DS:Nothing + +; + +Proc I_PostNoteWindow Far + + Push CS + Pop DS + Assume DS:Inst + + Mov SI, Offset NoteListKeys + Call M_FunctionDivider + JC I_PostNoteWindow1 + + Jmp [SI] + +I_PostNoteWindow1: + Cmp NotePos, 0 + JNE I_PostNoteWindow5 + + Mov SI, Offset KeyBoardTable + +I_PostNoteWindow2: + LodsW + Cmp AX, 0FFFFh + JE I_PostNoteWindow3 + + Mov BX, AX + LodsW + + Cmp BX, CX + JNE I_PostNoteWindow2 + ; Note to play... + ; AX = notemod. + Mov CX, AX + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AL, 12 + Mul BaseOctave + + Push CS + Pop DS + Assume DS:Inst + Mov SI, CurrentNote + Add SI, SI + + Add CX, AX + Cmp CX, 119 + JA I_PostNoteWindow4 ; If note > B-9... not valid! + + Mov CH, SampleNumber + + Call I_GetInstrumentOffset + Mov [DS:BX+SI+40h], CX + + Push CS + Pop DS + + Mov SI, Offset NoteData + Call PE_GetLastInstrument + Mov AH, BL + Inc AH + Mov AL, Byte Ptr CurrentNote + Mov [SI], AX + + Mov AX, PlayChannel + Mov DH, 32+128 + Call Music_PlayNote + + NetworkSendInstrument + Jmp I_NoteDown + +I_PostNoteWindow4: + Mov AX, 1 + Ret + +I_PostNoteWindow3: + Xor AX, AX + Ret + +I_PostNoteWindow5: + Cmp DL, '0' + JB I_PostNoteWindow6 + Cmp DL, '9' + JA I_PostNoteWindow6 + + Sub DL, '0' + + Mov SI, CurrentNote + Add SI, SI + + Call I_GetInstrumentOffset + Assume DS:Nothing + ; DS:BX points to inst. + Add BX, 40h + + Mov AX, NotePos + Cmp AL, 1 + JE I_PostNoteWindow7 + + Inc BX + + Cmp AL, 2 + JE I_PostNoteWindow8 + + Cmp AL, 3 + JE I_PostNoteWindow9 + +I_PostNoteWindow6: + Cmp DX, '.' + JNE I_PostNoteWindow10 + Cmp NotePos, 2 + JB I_PostNoteWindow10 + + Mov SI, CurrentNote + Add SI, SI + + Call I_GetInstrumentOffset + Assume DS:Nothing + Add BX, SI + Add BX, 41h + Mov Byte Ptr [BX], 0 + + NetworkSendInstrument + Jmp I_NoteDown + +I_PostNoteWindow10: + Xor AX, AX + Ret + +I_PostNoteWindow7: ; Octave of note. + Mov AL, [DS:BX+SI] ; AL = Note + Xor AH, AH + Mov CL, 0Ch + Div CL ; AL = octave, AH = Note + + Mov AL, DL + Mov CH, AH + Mul CL + Add AL, CH ; AL = new note + + Mov [DS:BX+SI], AL + + NetworkSendInstrument + Jmp I_NoteDown + +I_PostNoteWindow8: + Mov AL, [DS:BX+SI] ; AL = sample. + Xor AH, AH + Mov CL, 10 + Div CL ; AL = tens, AH = units + + Mov AL, DL + Mov CH, AH + Mul CL + Add AL, CH + + Mov SampleNumber, AL + Mov [DS:BX+SI], AL + + NetworkSendInstrument + Jmp I_NoteRight + +I_PostNoteWindow9: + Mov AL, [DS:BX+SI] + Xor AH, AH + Mov CL, 10 + Div CL + + Mov CH, AH + Mul CL + + Add AL, DL + + Mov SampleNumber, AL + Mov [DS:BX+SI], AL + + Mov NotePos, 2 + +I_PostNoteWindowEnd: + NetworkSendInstrument + Jmp I_NoteDown + +EndP I_PostNoteWindow + Assume DS:Nothing + +; + +Proc I_SelectNoteMouse Far + Assume DS:Inst + + ShR DX, 3 + Add DX, TopNote + Sub DX, 16 + JNC I_SelectNoteMouse1 + + Xor DX, DX + +I_SelectNoteMouse1: + Cmp DX, 119 + JB I_SelectNoteMouse2 + + Mov DX, 119 + +I_SelectNoteMouse2: + Mov CurrentNote, DX + + Mov AX, 1 + Ret + +EndP I_SelectNoteMouse + Assume DS:Nothing + +; + +Proc I_NoteUp Far + + Assume DS:Inst + + Mov AX, CurrentNote + Dec AX + JS I_NoteUp2 + + Mov CurrentNote, AX + Jmp I_NoteUp1 + +I_NoteUp2: + Mov Word Ptr [ES:DI], 5 + +I_NoteUp1: + Mov AX, 1 + Ret + +EndP I_NoteUp + Assume DS:Nothing + +; + +Proc I_NoteDown Far + + Push CS + Pop DS + Assume DS:Inst + + Mov AX, CurrentNote + Inc AX + Cmp AX, 119 + JA I_NoteDown1 + + Mov CurrentNote, AX + +I_NoteDown1: + Mov AX, 1 + Ret + +EndP I_NoteDown + Assume DS:Nothing + +; + +Proc I_NotePgUp Far + + Assume DS:Inst + + Mov AX, CurrentNote + Sub AX, 12 + JNS I_NotePgUp1 + + Xor AX, AX + +I_NotePgUp1: + Mov CurrentNote, AX + + Mov AX, 1 + Ret + +EndP I_NotePgUp + Assume DS:Nothing + +; + +Proc I_NotePgDn Far + + Assume DS:Inst + + Mov AX, CurrentNote + Add AX, 12 + Cmp AX, 119 + JBE I_NotePgDn1 + + Mov AX, 119 + +I_NotePgDn1: + Mov CurrentNote, AX + + Mov AX, 1 + Ret + +EndP I_NotePgDn + Assume DS:Nothing + +; + +Proc I_NoteRight Far + + Push CS + Pop DS + Assume DS:Inst + + Mov AX, NotePos + Inc AX + Cmp AX, 4 + JB I_NoteRight1 + + Mov AX, 3 + +I_NoteRight1: + Mov NotePos, AX + + Mov AX, 1 + Ret + +EndP I_NoteRight + Assume DS:Nothing + +; + +Proc I_NoteLeft Far + + Assume DS:Inst + Mov AX, NotePos + Dec AX + JS I_NoteLeft1 + + Mov NotePos, AX + +I_NoteLeft1: + Mov AX, 1 + Ret + +EndP I_NoteLeft + Assume DS:Nothing + +; + +Proc I_NoteHome Far + Assume DS:Inst + + Mov CurrentNote, 0 + + Mov AX, 1 + Ret + +EndP I_NoteHome + Assume DS:Nothing + +; + +Proc I_NoteEnd Far + Assume DS:Inst + + Mov CurrentNote, 119 + + Mov AX, 1 + Ret + +EndP I_NoteEnd + Assume DS:Nothing + +; + +Proc I_NoteTab Far + + Mov Word Ptr [ES:DI], 16 + + Mov AX, 1 + Ret + +EndP I_NoteTab + Assume DS:Nothing + +; + +Proc I_NoteShiftTab Far + + Mov Word Ptr [ES:DI], 4 + + Mov AX, 1 + Ret + +EndP I_NoteShiftTab + Assume DS:Nothing + +; + +Proc I_NoteSampleIncrease Far + + Assume DS:Inst + + Mov AL, SampleNumber + Inc AX + Cmp AL, 99 + JA I_NoteSampleIncrease1 + + Mov SampleNumber, AL + +I_NoteSampleIncrease1: + Mov AX, 1 + Ret + +EndP I_NoteSampleIncrease + Assume DS:Nothing + +; + +Proc I_NoteSampleDecrease Far + + Assume DS:Inst + + Mov AL, SampleNumber + Dec AL + JS I_NoteSampleDecrease1 + + Mov SampleNumber, AL + +I_NoteSampleDecrease1: + Mov AX, 1 + Ret + +EndP I_NoteSampleDecrease + Assume DS:Nothing + +; + +Proc I_NoteSamplePickUp Far + + Assume DS:Nothing + + Call I_GetInstrumentOffset + + Mov SI, CurrentNote + Mov AX, SI + Mov PlayNote, AL + Add SI, SI + + Mov AX, [DS:BX+SI+40h] + + Mov SampleNumber, AH + + Mov AX, 1 + Ret + +EndP I_NoteSamplePickUp + +; + +Proc I_NoteNext Far + Assume DS:Inst + + Mov SI, CurrentNote + Add SI, SI + JZ I_NoteNext1 + + Call I_GetInstrumentOffset + Assume DS:Nothing + + Add BX, SI + Add BX, 40h + + Mov AX, [DS:BX-2] ; 'Last note.' + Cmp AL, 119 ; Is previous note >= B-9 + JAE I_NoteNext1 + + Inc AX + Mov [DS:BX], AX + + NetworkSendInstrument + Jmp I_NoteDown + +I_NoteNext1: + Mov AX, 1 + Ret + +EndP I_NoteNext + Assume DS:Nothing + +; + +Proc I_NotePrevious Far + Assume DS:Inst + + Mov SI, CurrentNote + Cmp SI, 119 + JAE I_NotePrevious1 + + Add SI, SI + + Call I_GetInstrumentOffset + Assume DS:Nothing + + Add BX, SI + Add BX, 40h + + Mov AX, [DS:BX+2] ; 'Last note.' + Test AL, AL + JZ I_NotePrevious1 + + Dec AX + Mov [DS:BX], AX + + Push CS + Pop DS + Assume DS:Inst + + Mov AX, CurrentNote + Dec AX + JS I_NotePrevious1 + + Mov CurrentNote, AX + NetworkSendInstrument + +I_NotePrevious1: + + Mov AX, 1 + Ret + +EndP I_NotePrevious + Assume DS:Nothing + +; + +Proc I_NoteAll Far + + Assume DS:Nothing + + Call I_GetInstrumentOffset + Push DS + Pop ES + + LEA DI, [BX+40h] + + Mov CX, 120 + Mov AH, SampleNumber + Xor AL, AL + + +I_NoteAll1: + StosW + Inc AX + Loop I_NoteAll1 + + Sub DI, 110h + + MovZX BX, SampleNumber + Add BX, BX + JZ I_NoteAll2 + + Mov SI, [BX+64910] + Add SI, 14h + + Mov CX, 26 + Rep MovsB + +I_NoteAll2: + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_NoteAll + Assume DS:Nothing + +; + +Proc I_NoteInsert Far + + Assume DS:Nothing + + Call I_GetInstrumentOffset + Push DS + Pop ES + LEA DI, [BX+40h+120*2-2] + LEA SI, [DI-2] + Mov CX, 119 + + StD + Rep MovsW + Xor AX, AX + StosW + ClD + + NetworkSendInstrument + Mov AX, 1 + Ret + +EndP I_NoteInsert + +; + +Proc I_NoteDelete Far + + Assume DS:Nothing + + Call I_GetInstrumentOffset + Push DS + Pop ES + LEA DI, [BX+40h] + LEA SI, [DI+2] + Mov CX, 119 + + Rep MovsW + Xor AX, AX + StosW + + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_NoteDelete + +; + +Proc I_NoteTransposeUp Far + + Assume DS:Nothing + + Call I_GetInstrumentOffset + Push DS + Pop ES + + LEA DI, [BX+40h] + + Mov CX, 120 + +I_NoteTransposeUp1: + Mov AL, [DI] + Inc AX + Cmp AL, 119 + JBE I_NoteTransposeUp2 + + Mov AL, 119 + +I_NoteTransposeUp2: + StosB + Inc DI + Loop I_NoteTransposeUp1 + + NetworkSendInstrument + Mov AX, 1 + Ret + +EndP I_NoteTransposeUp + Assume DS:Nothing + +; + +Proc I_NoteTransposeDown Far + + Assume DS:Nothing + + Call I_GetInstrumentOffset + Push DS + Pop ES + + LEA DI, [BX+40h] + + Mov CX, 120 + +I_NoteTransposeDown1: + Mov AL, [DI] + Sub AL, 1 + AdC AL, 0 + StosB + Inc DI + Loop I_NoteTransposeDown1 + + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_NoteTransposeDown + Assume DS:Nothing + +; + +Proc I_NoteSpace Far + + Assume DS:Inst + Cmp NotePos, 2 + JB I_NoteSpace1 + + Mov SI, CurrentNote + Add SI, SI + + Call I_GetInstrumentOffset + Assume DS:Nothing + Mov AL, SampleNumber + Mov [BX+SI+41h], AL + + Jmp I_NoteDown + +I_NoteSpace1: + NetworkSendInstrument + Xor AX, AX + Ret + +EndP I_NoteSpace + Assume DS:Nothing + +; + +Proc I_ExchangeInstruments Far + + EnsureNoNetwork + + Mov DI, Offset O1_ExchangeInstrumentList + Call GetNumberInput + + Mov SI, DX + Dec SI + Add SI, SI + + Call PE_GetLastInstrument + Add BX, BX + + Cmp SI, BX + JE I_ExchangeInstruments1 + + Call Music_GetSongSegment + Mov ES, AX + Mov DS, AX + Mov DI, [DS:64712+BX] + Mov SI, [DS:64712+SI] ; DS:SI, ES:DI point to + ; sample headers + + Mov CX, 554 + +I_ExchangeInstruments2: + Mov AL, [ES:DI] + MovsB + Mov [DS:SI-1], AL + + Loop I_ExchangeInstruments2 + + Call I_MapEnvelope + +I_ExchangeInstruments1: + Mov AX, 1 + Ret + +EndP I_ExchangeInstruments + +; + +Proc I_DoubleSampleSpeed Far + + Call I_GetSampleOffset + Mov EAX, [BX+3Ch] + ShL EAX, 1 + Cmp EAX, 9999999 + JA I_DoubleSampleSpeed1 + + Mov [BX+3Ch], EAX + +I_DoubleSampleSpeed1: + NetworkSendSample + + Mov AX, 1 + Ret + +EndP I_DoubleSampleSpeed + +; + +Proc I_HalveSampleSpeed Far + + Call I_GetSampleOffset + ShR DWord Ptr [BX+3Ch], 1 + + NetworkSendSample + + Mov AX, 1 + Ret + +EndP I_HalveSampleSpeed + +; + +Proc I_SampleSpeedSemiUp Far + + Call I_GetSampleOffset + + Mov EAX, 255392045 + Mul DWord Ptr [BX+3Ch] + + Add EDX, [BX+3Ch] + JC I_SampleSpeedSemiUp1 + + Mov [BX+3Ch], EDX + +I_SampleSpeedSemiUp1: + NetworkSendSample + + Mov AX, 1 + Ret + +EndP I_SampleSpeedSemiUp + +; + +Proc I_SampleSpeedSemiDown Far + + Call I_GetSampleOffset + + Mov EAX, 4053909306 + Mul DWord Ptr [BX+3Ch] + Mov [BX+3Ch], EDX + + NetworkSendSample + + Mov AX, 1 + Ret + +EndP I_SampleSpeedSemiDown + +; + +Proc I_ReplaceInstrument Far + + EnsureNoNetwork + + Mov DI, Offset O1_ReplaceInstrumentList + Call GetNumberInput + + Call PE_GetLastInstrument + Mov DH, BL + Inc DH ; DH/DL = samples to swap + + Cmp DL, DH + JE I_ReplaceInstrument1 + + Call Music_GetInstrumentMode + JZ I_ReplaceInstrument1 + + XChg DH, DL + Or DH, 80h + Call PE_SwapInstruments + +I_ReplaceInstrument1: + Mov AX, 1 + Ret + +EndP I_ReplaceInstrument + +; + +Proc I_ScaleSampleVolumes Far + + EnsureNoNetwork + + Mov DI, Offset O1_GetInstrumentAmpList + Mov CX, 3 + Call M_Object1List + + Cmp DX, 1 + JNE I_ScaleSampleVolumesEnd + + Mov BP, CS:InstrumentAmplification + Mov BX, 100 + + Call Music_GetSongSegment + Mov DS, AX + Mov SI, 64912 + Mov CX, 99 + +I_ScaleSampleVolumes1: + Xor AX, AX + Mov DI, [SI] + Mov AL, [DI+11h] + Mul BP + Div BX + Cmp AX, 64 + JB I_ScaleSampleVolumes2 + + Mov AX, 64 + +I_ScaleSampleVolumes2: + Mov [DI+11h], AL + + Add SI, 2 + Dec CX + JNZ I_ScaleSampleVolumes1 + +I_ScaleSampleVolumesEnd: + Mov AX, 1 + Ret + +EndP I_ScaleSampleVolumes + +; + +Proc I_ScaleInstrumentVolumes Far + + EnsureNoNetwork + + Mov DI, Offset O1_GetInstrumentAmpList + Mov CX, 3 + Call M_Object1List + + Cmp DX, 1 + JNE I_ScaleInstrumentVolumesEnd + + Mov BP, CS:InstrumentAmplification + Mov BX, 100 + + Call Music_GetSongSegment + Mov DS, AX + Mov SI, 64712 + Mov CX, 99 + +I_ScaleInstrumentVolumes1: + Xor AX, AX + Mov DI, [SI] + Mov AL, [DI+18h] + Mul BP + Div BX + Cmp AX, 128 + JB I_ScaleInstrumentVolumes2 + + Mov AX, 128 + +I_ScaleInstrumentVolumes2: + Mov [DI+18h], AL + + Add SI, 2 + Dec CX + JNZ I_ScaleInstrumentVolumes1 + +I_ScaleInstrumentVolumesEnd: + Mov AX, 1 + Ret + +EndP I_ScaleInstrumentVolumes + +; + +Proc I_CopyInstrument Far + + Mov DI, Offset O1_CopyInstrumentList + Call GetNumberInput + + Call I_GetInstrumentOffset ; Gets DS:BX with cur inst. + + Mov DI, BX + Mov SI, DX + Add SI, SI + Mov SI, [64710+SI] + + Push DS + Pop ES + + Mov CX, 554/2 + Rep MovsW + + Call I_MapEnvelope + + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_CopyInstrument + +; + +Proc I_SwapInstruments Far + + EnsureNoNetwork + + Mov DI, Offset O1_SwapInstrumentList + Call GetNumberInput + + Mov SI, DX +; Dec SI + Add SI, SI + + Call PE_GetLastInstrument + Mov DH, BL + Inc DH ; DH/DL = samples to swap + Add BX, BX + + Cmp DL, DH + JE I_SwapInstruments1 + + Call Music_GetSongSegment + Mov ES, AX + Mov DS, AX + Mov DI, [DS:64712+BX] + Mov SI, [DS:64710+SI] ; DS:SI, ES:DI point to + ; sample headers + + Mov CX, 554 + +I_SwapInstruments2: + Mov AL, [ES:DI] ; Swapping headers. + MovsB + Mov [DS:SI-1], AL + + Loop I_SwapInstruments2 + + ; Now to swap pattern + ; stuff... + Call Music_GetInstrumentMode + JZ I_SwapInstruments3 + + Call PE_SwapInstruments + +I_SwapInstruments3: + Call I_MapEnvelope + +I_SwapInstruments1: + Mov AX, 1 + Ret + +EndP I_SwapInstruments + +; + +Proc I_UpdateInstrument Far + + EnsureNoNetwork + + Call PE_GetLastInstrument + Mov DX, BX + Inc DX + Add BX, BX + + Call Music_GetSongSegment + Mov ES, AX + Mov DI, [ES:64712+BX] + Add DI, 40h + + Call PE_UpdateInstruments + + Mov AX, 1 + Ret + +EndP I_UpdateInstrument + +; + +Proc MouseEnvelopeEvent1 Far + + Mov CS:MouseX, CX + Mov CS:MouseY, DX + + Mov CX, 8010h ; Envelope mouse control request.. + Call AddMouseQueue + + Xor AX, AX + Ret + +EndP MouseEnvelopeEvent1 + +; + +Proc MouseEnvelopeEvent4 Far ; Delete node + + Test BH, 6 + JNZ MouseEnvelopeEvent4_1 + + Mov CS:MouseX, CX + Mov CS:MouseY, DX + + Mov CX, 8003h ; Envelope mouse control request.. + Call AddMouseQueue + +MouseEnvelopeEvent4_1: + Xor AX, AX + Ret + +EndP MouseEnvelopeEvent4 + +; + +Proc MouseEnvelopeEvent2 Far ; Envelope drag + + Mov CS:MouseX, CX + Mov CS:MouseY, DX + + Mov CX, 8001h + Call AddMouseQueue + + Xor AX, AX + Ret + +EndP MouseEnvelopeEvent2 + +; + +Proc MouseEnvelopeEvent3 Far ; Release envelope + + Mov CX, 8002h + Call AddMouseQueue + + Xor AX, AX + Ret + +EndP MouseEnvelopeEvent3 + +; + +Proc DrawEnvelopeHeader ; AH = colour, DS = inst + Assume DS:Inst + + Mov SI, InstrumentScreen ; 1-3 + Add SI, SI ; 2-6 + Add SI, Word Ptr NodeHeld ; 2-7 + Add SI, SI ; 4-14 + Mov SI, [EnvelopeHeaderTable+SI-4] + Mov DI, (33+16*80)*2 + + Call S_DrawString + + Ret + +EndP DrawEnvelopeHeader + Assume DS:Nothing + +; + +Proc I_DrawEnvelope Far + + Push CS + Pop DS + Assume DS:Inst + + Mov AH, 20h + Call DrawEnvelopeHeader + + Call S_GetDestination + Mov DI, (32+18*80)*2 + Mov AX, 0C00h + + Mov DX, 8 + +I_DrawEnvelope1: + Mov CX, 32 + +I_DrawEnvelope2: + StosW + Inc AX + Loop I_DrawEnvelope2 + + Add DI, (80-32)*2 + Dec DX + JNZ I_DrawEnvelope1 + + Call I_GetEnvelopeOffset ; Returns DS:SI + Mov BX, CS:CurrentNode ; to envelope table + Mov CX, BX + + Add BX, BX + Add BX, CX ; BX = CurrentNode*3 + + Mov AL, [SI+BX+6] + CBW ; Value + + Test Byte Ptr [SI], 80h + JZ I_DrawEnvelope5 + + Add AX, 32 + +I_DrawEnvelope5: + Push AX + Push Word Ptr [SI+BX+7] ; Tick + Push CS:MaxNode + Push CX ; Node + + Mov DI, (66+19*80)*2 + Mov AH, 2 + Push CS + Pop DS + Mov SI, Offset EnvelopeMsg + Call S_DrawString + + Add SP, 8 + + Cmp MouseNodeHeld, 0 + JZ I_DrawEnvelope4 + + Call MouseGetStatus + Test AL, 6 + JNZ I_DrawEnvelope3 + + Call I_MouseEnvelopeReleased + Jmp I_DrawEnvelope4 + +I_DrawEnvelope3: + Mov SI, Offset EnvelopeEvent3 + Call MouseAddEvent + Mov SI, Offset EnvelopeEvent2 + Call MouseAddEvent + + Ret + +I_DrawEnvelope4: + Mov SI, Offset EnvelopeEvent1 + Call MouseAddEvent + Mov SI, Offset EnvelopeEvent4 + Call MouseAddEvent + + Ret + +EndP I_DrawEnvelope + Assume DS:Nothing + +; + +Proc I_PreEnvelope Far + + Push CS + Pop DS + + Mov AH, 23h + Call DrawEnvelopeHeader + + Ret + +EndP I_PreEnvelope + Assume DS:Nothing + +; + +Proc I_PostEnvelope Far + + Push CS + Pop DS + Assume DS:Inst + + Mov SI, Offset VolumeEnvelopeNodeKeys + + Cmp NodeHeld, 1 + JE I_PostEnvelope2 + + Mov SI, Offset VolumeEnvelopeKeys + +I_PostEnvelope2: + Call M_FunctionDivider + JC I_PostEnvelope1 + + Jmp [SI] + +I_PostEnvelope1: +IF ENABLEPRESETENVELOPES + + Cmp DX, '0' + JB I_PostEnvelopeNoPreset + Cmp DX, '9' + JA I_PostEnvelopeNoPreset + + Call I_GetEnvelopeOffset + Push DS + Pop ES + Mov DI, SI ; ES:DI set + + Push CS + Pop DS + Mov AL, 81 + Sub DL, '0' + Mul DL ; AX = offset + Mov SI, AX + Add SI, Offset PresetEnvelopes + + Mov CX, 6/2 + Rep MovsW + Mov CX, 25 + +I_PostEnvelopePreset1: + LodsB + Sub AL, AmplitudeCompensate + StosB + MovsW + Loop I_PostEnvelopePreset1 + + Call I_MapEnvelope + NetworkSendInstrument + + Mov AX, 1 + Ret + +I_PostEnvelopeNoPreset: + Test CH, 60h ; Alt? + JZ I_PostEnvelopeNoSet + Test CH, 1 ; On keypress + JZ I_PostEnvelopeNoSet + + Cmp CL, 2 + JB I_PostEnvelopeNoSet + Cmp CL, 0Bh + JA I_PostEnvelopeNoSet + JNE I_PostEnvelopeSet2 + + Mov CL, 1 + +I_PostEnvelopeSet2: + Mov AX, CX + Dec AX + And AX, 0FFh + Mov SI, Offset EnvelopeSetMsg + Call SetInfoLine + Mov CL, 81 + Mul CL + + Call I_GetEnvelopeOffset ; Gets DS:SI + Push CS + Pop ES + Mov DI, AX + Add DI, Offset PresetEnvelopes ; ES:DI points to dest + + LodsW + And AL, 7Fh + StosW + + Mov CX, 4/2 + Rep MovsW + Mov CX, 25 + +I_PostEnvelopeSet1: + LodsB + Add AL, CS:AmplitudeCompensate + StosB + MovsW + Loop I_PostEnvelopeSet1 + + Call I_MapEnvelope + + Mov AX, 1 + Ret + +I_PostEnvelopeNoSet: +ENDIF ; PRESETENVELOPES + Xor AX, AX + Ret + +EndP I_PostEnvelope + +; + +Proc I_MapEnvelope Far + + Push CS + Pop DS + Assume DS:Inst + + Cmp InstrumentScreen, 0 + JNE I_MapEnvelope1 + + Ret + +I_MapEnvelope1: + Mov UpdateInstrumentScreen, 0 + + Push BP + + Call S_GetGenerationTableOffset + Push DI ; ES:DI points to table. + Mov CX, 32*8*8*8/4 + Xor EAX, EAX + Rep StosD + Pop DI + Push DI + + Add DI, 3 + Mov CX, 32 + Inc AX + +I_MapEnvelopeYAxis1: + StosB + Add DI, 511 + Loop I_MapEnvelopeYAxis1 + + Pop DI + Push DI + + Call I_GetEnvelopeOffset ; DS:SI points to envelope + Assume DS:Nothing + + Mov AL, 32 + + Add DI, 31*256 + + Test Byte Ptr [SI], 80h + JNZ I_MapEnvelopeFilterCompensate + Cmp Byte Ptr [CS:InstrumentScreen], 1 + JNE I_MapEnvelopeXAxis1 + + Xor AL, AL +I_MapEnvelopeFilterCompensate: + Add DI, 31*256 + +I_MapEnvelopeXAxis1: + Mov CS:AmplitudeCompensate, AL + + Mov AX, 100h + Mov CX, 128 + + Rep StosW ; X-axis drawn + + Pop DI + + Xor DH, DH + Mov DL, [SI+1] + + Mov CS:MaxNode, DX + Cmp CS:CurrentNode, DX + JB I_MapEnvelope2 + + Mov AX, DX + Sub AX, 1 + AdC AX, 0 + Mov CS:CurrentNode, AX + +I_MapEnvelope2: + Test DX, DX + JZ I_MapEnvelopeEnd + + Sub DX, 1 + AdC DX, 1 + + Push DX + + ; DX = last node + ; DS:SI = envelope, ES:DI = table + Mov BX, DX ; MaxNode + Add BX, BX + Add BX, DX ; BX = MaxNode*3 + + Mov AX, [DS:SI+BX+6+1-3] ; Get last nodes tick + Xor DX, DX + Mov BX, ENVELOPEGRANULARITY + Div BX + Inc AX + Mul BX + Mov CS:UpperLimit, AX + + Push DI + Xor BP, BP + Jmp I_MapEnvelope4 + +I_MapEnvelope3: + Push CX + Push DI + +I_MapEnvelope4: ; Node drawing part + Mov BX, BP + Add BX, BX + Add BX, BP + + Mov AL, 64 + Sub AL, CS:AmplitudeCompensate + Sub AL, [SI+BX+6] + Mov AH, 244 ; 244 = 61/64*256 + Mul AH + ; AX = amplitude + Mov CS:CurrentAmplitude, AX + Mov CX, AX ; CX = amplitude + + Mov AX, [SI+BX+7] + Cmp AX, CS:UpperLimit + JAE I_MapEnvelopeError + + Mov DX, 250 ; 249 if UpperLimit = LastNode tick + Mul DX +; Add AX, 125 +; AdC DX, 0 + Div CS:UpperLimit + + Mov CS:CurrentTick, AX + + ; OK.. plot points + Xor CL, CL + Add DI, AX + Add DI, CX + Add DI, 256+3 + + Mov AX, 101h + Mov [ES:DI], AX + Mov [ES:DI-256], AX + Mov [ES:DI+256], AX + Mov [ES:DI-1], AL + Mov [ES:DI-256-1], AL + Mov [ES:DI+256-1], AL + + Cmp BP, CS:CurrentNode + JNE I_MapEnvelope5 + + Dec AX + Mov [ES:DI+2], AX + Mov [ES:DI+256+2], AX + Mov [ES:DI-256+2], AX + XChg AH, AL + Mov [ES:DI-3], AX + Mov [ES:DI+256-3], AX + Mov [ES:DI-256-3], AX + +I_MapEnvelope5: + Sub DI, CX + Sub DI, 256 + Mov AX, BP + Mov CX, 64 + + Test Byte Ptr [SI], 2 + JZ I_MapEnvelope6 + + Mov AH, 1 + + Cmp AL, [SI+2] + JE I_MapEnvelopeLoop1 + Cmp AL, [SI+3] + JNE I_MapEnvelope6 + +I_MapEnvelopeLoop1: + Mov AL, AH + ShR AL, 1 + StosB + Add DI, 255 + Inc AH + Loop I_MapEnvelopeLoop1 + + Jmp I_MapEnvelope7 + +I_MapEnvelope6: + Test Byte Ptr [SI], 4 + JZ I_MapEnvelope7 + + Cmp AL, [SI+4] + JE I_MapEnvelopeSusLoop2 + Cmp AL, [SI+5] + JNE I_MapEnvelope7 + +I_MapEnvelopeSusLoop2: + Mov AL, 1 + +I_MapEnvelopeSusLoop1: + StosB + Add DI, 255 + Xor AL, 1 + Loop I_MapEnvelopeSusLoop1 + +I_MapEnvelope7: ; Now for line segment + Test BP, BP + JZ I_MapEnvelope8 ; Don't draw line for first node + + Pop DI + Push DI + + Add DI, CS:LastTick + Add DI, 103h + + Mov CX, CS:CurrentTick + Sub CX, CS:LastTick + JC I_MapEnvelope8 ; Error.. + JNZ I_MapEnvelope11 + + ; Vertical line. + Mov AX, CS:LastAmplitude + Mov CX, CS:CurrentAmplitude + Xor AL, AL + Xor CL, CL + + Add DI, AX ; LastAmplitude + + Mov DX, 256 + + Sub CX, AX + JNS I_MapEnvelope9 + + Neg DX + Neg CX + +I_MapEnvelope9: + ShR CX, 8 + JZ I_MapEnvelope12 + +I_MapEnvelope10: + Mov Byte Ptr [ES:DI], 1 + Add DI, DX + Loop I_MapEnvelope10 + +I_MapEnvelope12: + Jmp I_MapEnvelope8 + +I_MapEnvelope11: ; Diagonal line + Push SI + + Xor SI, SI + Mov AX, CS:CurrentAmplitude + Sub AX, CS:LastAmplitude + JNS I_MapEnvelope13 + + Inc SI ; SI = 1 if opp direction + Neg AX + +I_MapEnvelope13: + Xor DX, DX + Div CX + Mov DX, AX + + Test SI, SI + Mov SI, -256 + JZ I_MapEnvelope15 + + Neg SI + Neg DX + +I_MapEnvelope15: + Mov BX, CS:LastAmplitude + Inc CX + Dec DI + Push DI + Jmp I_MapEnvelope17 + +I_MapEnvelope14: + Push DI + Push BX + Xor BL, BL + Add DI, BX + +I_MapEnvelope16: + Mov Byte Ptr [ES:DI], 1 + Add DI, SI + Dec AL + JNZ I_MapEnvelope16 + + Pop BX + +I_MapEnvelope17: + Mov AL, BH + Add BX, DX + Sub AL, BH + + CBW ; + Xor AL, AH ; AL = |AL| + Sub AL, AH ; + Sub AL, 1 + AdC AL, 1 + + Pop DI + Inc DI + Loop I_MapEnvelope14 + + Pop SI + +I_MapEnvelope8: + Mov AX, CS:CurrentAmplitude + Mov BX, CS:CurrentTick + Mov CS:LastAmplitude, AX + Mov CS:LastTick, BX + +I_MapEnvelopeError: + Pop DI + Pop CX + Inc BP + Loop I_MapEnvelope3 + + ; Now shove on playing points. + + Call PE_GetLastInstrument + Inc BX + + Mov CX, CS:InstrumentScreen + Mov BP, CX + Mov DL, 1 + Add CL, 11 + ShL BP, 4 + ShL DX, CL + Add BP, 48h + + Call Music_GetSlaveChannelInformationTable + ; Returns DS:SI, CX + Assume DS:Nothing + +I_MapEnvelopePlaying1: + Cmp [SI+33h], BL + JNE I_MapEnvelopePlayingNext + + Test Byte Ptr [SI], 1 + JZ I_MapEnvelopePlayingNext + + Mov AX, [DS:SI+BP] + And AX, AX + JNZ I_MapEnvelopePlaying2 + + Test [SI], DX + JZ I_MapEnvelopePlayingNext + +I_MapEnvelopePlaying2: + Cmp AX, CS:UpperLimit + JAE I_MapEnvelopePlayingNext + + Push CX + Push DX + + Call S_GetGenerationTableOffset + Add DI, 3 + + Mov DX, 250 + Mul DX + Div CS:UpperLimit + + Add DI, AX + Mov CX, 64 + +I_DrawEnvelopePlaying1: + Mov Byte Ptr [ES:DI], 1 + Add DI, 256 + Loop I_DrawEnvelopePlaying1 + + Mov CS:UpdateInstrumentScreen, 1 + + Pop DX + Pop CX + +I_MapEnvelopePlayingNext: + Add SI, SLAVECHANNELSIZE + Loop I_MapEnvelopePlaying1 + +I_MapEnvelopeEnd: + Xor AX, AX + Mov BX, 32 + Mov CX, 8 + Call S_GenerateCharacters + + Pop BP + + Push CS + Pop DS + + Ret + +EndP I_MapEnvelope + Assume DS:Nothing + +; + +Proc I_GetMouseNode ; Returns DI, carry if none + + Call I_GetEnvelopeOffset + ; Returns DS:SI to envelope + Xor CH, CH + Mov CL, [SI+1] + + Add SI, 6 ; Start of envelope.. have to find + ; a point that fits MouseX, MouseY + ; XPixel = ENVELOPELEFT*8 + 250*Tick/UpperLimit + 3 + ; YPixel = ENVELOPETOP*8 + 61*(64-AmplitudeCompensate-Amplitude)/64 + 1 + + Xor DI, DI ; DI = node number. + JCXZ I_GetMouseNode3 + +I_GetMouseNode1: + Mov BX, DI + Add BX, BX + Add BX, DI + + Mov AX, 250 + Mul Word Ptr [SI+BX+1] + Div CS:UpperLimit + Add AX, ENVELOPELEFT*8+2 + + Mov DL, 64 + Sub DL, CS:AmplitudeCompensate + Sub DL, [SI+BX] + + Mov BX, AX ; BX = XPixel + + Mov AL, 244 ; 244 = 61/64*256 + Mul DL + Mov AL, AH + Xor AH, AH + Add AX, ENVELOPETOP*8 ; AX = YPixel of node... + + Cmp MouseX, BX + JB I_GetMouseNode2 + Cmp MouseY, AX + JB I_GetMouseNode2 + Add AX, 2 + Add BX, 2 + Cmp MouseX, BX + JA I_GetMouseNode2 + Cmp MouseY, AX + JA I_GetMouseNode2 + +I_GetMouseNode3: + ClC + Ret + +I_GetMouseNode2: + Inc DI + Cmp DI, CX + JB I_GetMouseNode1 + + StC + Ret + +EndP I_GetMouseNode + +; + +Proc I_MouseEnvelopeDelete Far + + Call I_GetMouseNode + JC I_MouseEnvelopeDelete1 + Mov CS:CurrentNode, DI + + Push CS + Pop DS + Jmp I_VolumeEnvelopeDelete + +I_MouseEnvelopeDelete1: + Mov AX, 1 + Ret + +EndP I_MouseEnvelopeDelete + +; + +Proc I_MouseEnvelopePress Far + Assume DS:Nothing + ; If on top of node, then pick up this + ; node, ; MouseNodeHeld = 1 + ; If NOT near node, and nodes < 25, + ; then CREATE new node in appropriate + ; position, MouseNodeHeld = 1. If + ; no node will fit in-between, then + ; do nothing. + ; Else nothing + Call I_GetMouseNode + JNC I_MouseEnvelopeNodeFound1 + Cmp CX, 25 + JAE I_MouseEnvelopePressError + + ; Figger out envelope tick position... + Mov AX, MouseX + Sub AX, ENVELOPELEFT*8+3 + JNC I_MouseEnvelopeCreateNode4 + + Xor AX, AX + +I_MouseEnvelopeCreateNode4: + Mov BX, 250 + Mul CS:UpperLimit + Add AX, 125 + AdC DX, 0 + Div BX + + Mov CX, AX ; CX = new position.... + Cmp AX, MAXENVELOPETICK + JB I_MouseEnvelopeCreateNode3 + + Mov CX, MAXENVELOPETICK + +I_MouseEnvelopeCreateNode3: + Call I_GetEnvelopeOffset + Mov DL, [SI+1] + Mov BX, SI + Xor DH, DH + Xor DI, DI + Add BX, 7 + +I_MouseEnvelopeCreateNode1: + Cmp CX, [BX] + JE I_MouseEnvelopePressError + JB I_MouseEnvelopeCreateNode2 + + Add BX, 3 + Inc DI + Cmp DI, DX + JB I_MouseEnvelopeCreateNode1 + +I_MouseEnvelopeCreateNode2: + ClI + + Inc Byte Ptr [SI+1] + + Push BX + Push CX + Push DI + + Mov CX, DI + Cmp CL, [SI+2] + JA I_MEPIns1 + + Inc Byte Ptr [SI+2] + +I_MEPIns1: + Cmp CL, [SI+3] + JA I_MEPIns2 + + Inc Byte Ptr [SI+3] + +I_MEPIns2: + Cmp CL, [SI+4] + JA I_MEPIns3 + + Inc Byte Ptr [SI+4] + +I_MEPIns3: + Cmp CL, [SI+5] + JA I_MEPIns4 + + Inc Byte Ptr [SI+5] + +I_MEPIns4: + + Push DS + Pop ES + + StD + + Sub DX, DI + Mov CX, DX + Add CX, CX + Add CX, DX ; CX = (Last-New)*3 + + LEA DI, [BX+1] + Add DI, CX + LEA SI, [DI-3] + + Rep MovsB + + ClD + + Pop DI + Pop CX + Pop BX + + Mov [BX], CX + + Mov CX, 61 + Mov AX, MouseY + Sub AX, ENVELOPETOP*8 + JNC I_MEPChk1 + + Xor AX, AX + +I_MEPChk1: + Cmp AX, CX + JB I_MepChk2 + + Mov AX, CX + +I_MEPChk2: + ShL AX, 6 + Xor DX, DX + Div CX + + Mov DL, 64 + Sub DL, AL + Sub DL, CS:AmplitudeCompensate + Mov [BX-1], DL + +I_MouseEnvelopeNodeFound1: ; Have to find limits... + Mov CurrentNode, DI + Call I_EnvelopeSelected + + StI + + Mov BX, DI + Mov CL, BL + Inc CX + Add BX, BX + Add BX, DI + ; AX = lower limit, DX = upper limit + Xor AX, AX + Xor DX, DX + And DI, DI + JZ I_MouseEnvelopeNodeFound3 + + Mov DX, MAXENVELOPETICK + Mov AX, [SI+BX+6+1-3] + Inc AX + +I_MouseEnvelopeNodeFound2: + Cmp CL, [SI+1] + JAE I_MouseEnvelopeNodeFound3 + + Mov DX, [SI+BX+6+1+3] + Dec DX + +I_MouseEnvelopeNodeFound3: + Mov LowerTickLimit, AX + Mov UpperTickLimit, DX + + Mov BX, 2 + Call SetMouseCursorType + + Mov AX, 1 + Mov MouseNodeHeld, AL + Call SetKeyboardLock + Jmp I_MousePressChain + +I_MouseEnvelopePressError: + Mov AX, 1 + Ret + +EndP I_MouseEnvelopePress + Assume DS:Nothing + +; + +Proc I_MouseEnvelopeDrag Far + Assume DS:Nothing + ; CurrentNode update + + Call I_GetEnvelopeOffset + ; Returns DS:SI to envelope + Mov AX, CurrentNode + Mov BX, AX + Add BX, BX + Add BX, AX + LEA SI, [SI+BX+6] ; DS:SI points to current node + + ; Tick first + Mov AX, MouseX + Sub AX, ENVELOPELEFT*8+3 + JNC I_MouseEnvelopeDrag1 + + Xor AX, AX + +I_MouseEnvelopeDrag1: + Mov BX, 250 + Mul CS:UpperLimit + Add AX, 125 + AdC DX, 0 + Div BX + ; AX = tick.. now to check bounds.. + Cmp AX, LowerTickLimit + JAE I_MouseEnvelopeDrag2 + + Mov AX, LowerTickLimit + +I_MouseEnvelopeDrag2: + Cmp AX, UpperTickLimit + JBE I_MouseEnvelopeDrag3 + + Mov AX, UpperTickLimit + +I_MouseEnvelopeDrag3: + ClI + + Mov [SI+1], AX + + Mov AX, MouseY + Mov CX, 61 + Sub AX, ENVELOPETOP*8 + JNC I_MouseEnvelopeDrag4 + + Xor AX, AX + +I_MouseEnvelopeDrag4: + Cmp AX, CX + JBE I_MouseEnvelopeDrag5 + + Mov AX, CX + +I_MouseEnvelopeDrag5: + ShL AX, 6 + Xor DX, DX + Div CX + + Mov DL, 64 + Sub DL, AL + Sub DL, CS:AmplitudeCompensate + Mov [SI], DL + + StI + + ; XPixel = ENVELOPELEFT*8 + 250*Tick/UpperLimit + 3 + ; YPixel = ENVELOPETOP*8 + 61*(64-AmplitudeCompensate-Amplitude)/64 + 1 + +I_MousePressChain: + Push CS:UpperLimit + Call I_RedrawWave + Pop AX + Cmp AX, CS:UpperLimit + JE I_GetMousePositionEnd + + ; Set position.... + Call I_GetEnvelopeOffset + Mov AX, CS:CurrentNode + Add SI, AX + Add SI, AX + Add SI, AX + Add SI, 6 + + Mov AX, 250 + Mul Word Ptr [SI+1] + Div CS:UpperLimit + Add AX, ENVELOPELEFT*8-1 ; +3 + Mov CX, AX + + Xor DX, DX + Mov AL, 64 + Sub AL, CS:AmplitudeCompensate + Sub AL, [SI] + Mov AH, 244 + Mul AH + Mov DL, AH + + Add DX, ENVELOPETOP*8-2 ; +1 + Call MouseSetXY + +I_GetMousePositionEnd: + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_MouseEnvelopeDrag + Assume DS:Nothing + +; + +Proc I_MouseEnvelopeReleased Far + Assume DS:Inst + ; MouseNodeHeld = 0 + + Xor BX, BX + Call SetMouseCursorType + + Xor AX, AX + Mov CS:MouseNodeHeld, AL + Call SetKeyboardLock + + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_MouseEnvelopeReleased + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeRight Far + + Assume DS:Inst + + Mov AX, CurrentNode + Inc AX + Cmp AX, MaxNode + JAE I_VolumeEnvelopeRight1 + + Mov CurrentNode, AX + Call I_MapEnvelope + +I_VolumeEnvelopeRight1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeRight + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeLeft Far + + Assume DS:Inst + + Cmp CurrentNode, 0 + JE I_VolumeEnvelopeLeft1 + + Dec CurrentNode + Call I_MapEnvelope + +I_VolumeEnvelopeLeft1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeLeft + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeUp Far + + Mov Word Ptr [ES:DI], 5 + + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeUp + +; + +Proc I_VolumeEnvelopeDown Far + + Mov Word Ptr [ES:DI], 17 + + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeDown + +; + +Proc I_VolumeEnvelopeHeldUp Far + + Assume DS:Inst + + Mov CX, CurrentNode + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, CX + Add SI, CX + Add SI, 6 + + Mov AL, [SI] + Add AL, CS:AmplitudeCompensate + + Cmp AL, 64 + JAE I_VolumeEnvelopeHeldUp1 + + Inc Byte Ptr [SI] + + Call I_MapEnvelope + NetworkSendInstrument + +I_VolumeEnvelopeHeldUp1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldUp + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeHeldDown Far + + Assume DS:Inst + + Mov CX, CurrentNode + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, CX + Add SI, CX + Add SI, 6 + + Mov AL, [SI] + Add AL, CS:AmplitudeCompensate + + JZ I_VolumeEnvelopeHeldDown1 + + Dec Byte Ptr [SI] + + Call I_MapEnvelope + NetworkSendInstrument + +I_VolumeEnvelopeHeldDown1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldDown + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeHeldLeft Far + + Assume DS:Inst + + Mov CX, CurrentNode + Mov DX, CX + Add DX, DX + JZ I_VolumeEnvelopeHeldLeft1 + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, DX + Add SI, 7 ; DS:SI points to node's posn + + Mov AX, [SI] + + Dec AX + Cmp AX, [SI-3] ; Last node. + JE I_VolumeEnvelopeHeldLeft1 + + Mov [SI], AX + + Call I_MapEnvelope + NetworkSendInstrument + +I_VolumeEnvelopeHeldLeft1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldLeft + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeHeldLeftFast Far + + Assume DS:Inst + + Mov CX, CurrentNode + Mov DX, CX + Add DX, DX + JZ I_VolumeEnvelopeHeldLeftFast2 + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, DX + Add SI, 7 + + Mov AX, [SI] + + Sub AX, 16 + JNC I_VolumeEnvelopeHeldLeftFast3 + + Xor AX, AX + +I_VolumeEnvelopeHeldLeftFast3: + Cmp AX, [SI-3] ; Last node. + JA I_VolumeEnvelopeHeldLeftFast1 + + Mov AX, [SI-3] + Inc AX + +I_VolumeEnvelopeHeldLeftFast1: + Mov [SI], AX + + Call I_MapEnvelope + NetworkSendInstrument + +I_VolumeEnvelopeHeldLeftFast2: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldLeftFast + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeHeldHome Far + + Assume DS:Inst + + Mov CX, CurrentNode + Mov DX, CX + Add DX, DX + JZ I_VolumeEnvelopeHeldHome1 + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, DX + Add SI, 7 + + Mov AX, [SI-3] + Inc AX + Mov [SI], AX + + Call I_MapEnvelope + NetworkSendInstrument + +I_VolumeEnvelopeHeldHome1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldHome + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeHeldRight Far + + Assume DS:Inst + + Mov CX, CurrentNode + Mov DX, CX + Add DX, DX + JZ I_VolumeEnvelopeHeldRight1 + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, DX + Add SI, 7 + + Mov AX, [SI] + Cmp AX, MAXENVELOPETICK + JAE I_VolumeEnvelopeHeldRight1 + + Inc AX + Inc CX + Cmp CX, CS:MaxNode + JE I_VolumeEnvelopeHeldRight2 + + Cmp AX, [SI+3] ; Last node. + JE I_VolumeEnvelopeHeldRight1 + +I_VolumeEnvelopeHeldRight2: + Mov [SI], AX + + Call I_MapEnvelope + NetworkSendInstrument + +I_VolumeEnvelopeHeldRight1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldRight + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeHeldEnd Far + + Assume DS:Inst + + Mov CX, CurrentNode + Mov DX, CX + Add DX, DX + JZ I_VolumeEnvelopeHeldEnd1 + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, DX + Add SI, 7 + + + Mov AX, MAXENVELOPETICK + Inc CX + Cmp CX, CS:MaxNode + JE I_VolumeEnvelopeHeldEnd2 + + Mov AX, [SI+3] + Dec AX + +I_VolumeEnvelopeHeldEnd2: + Mov [SI], AX + + Call I_MapEnvelope + NetworkSendInstrument + +I_VolumeEnvelopeHeldEnd1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldEnd + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeHeldRightFast Far + + Assume DS:Inst + + Mov CX, CurrentNode + Mov DX, CX + Add DX, DX + JZ I_VolumeEnvelopeHeldRightFast1 + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, DX + Add SI, 7 + + Mov AX, [SI] + + Add AX, 16 + Inc CX + Cmp CX, CS:MaxNode + JE I_VolumeEnvelopeHeldRightFast3 + + Cmp AX, [SI+3] + JB I_VolumeEnvelopeHeldRightFast2 + + Mov AX, [SI+3] + Dec AX + +I_VolumeEnvelopeHeldRightFast3: + Cmp AX, MAXENVELOPETICK + JBE I_VolumeEnvelopeHeldRightFast2 + + Mov AX, MAXENVELOPETICK + +I_VolumeEnvelopeHeldRightFast2: + Mov [SI], AX + + Call I_MapEnvelope + NetworkSendInstrument + +I_VolumeEnvelopeHeldRightFast1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldRightFast + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeHeldPgDn Far + + Assume DS:Inst + + Mov CX, CurrentNode + Mov AH, AmplitudeCompensate + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, CX + Add SI, CX + Add SI, 6 + + Mov AL, [SI] + Add AL, AH + Sub AL, 8 + JNS I_VolumeEnvelopeHeldPgDn1 + + Xor AL, AL + +I_VolumeEnvelopeHeldPgDn1: + Sub AL, AH + Mov [SI], AL + + Call I_MapEnvelope + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldPgDn + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeHeldPgUp Far + + Assume DS:Inst + + Mov CX, CurrentNode + Mov AH, AmplitudeCompensate + + Call I_GetEnvelopeOffset + Assume DS:Nothing + + Add SI, CX + Add SI, CX + Add SI, CX + Add SI, 6 + + Mov AL, [SI] + Add AL, AH + Add AL, 8 + Cmp AL, 64 + JBE I_VolumeEnvelopeHeldPgUp1 + + Mov AL, 64 + +I_VolumeEnvelopeHeldPgUp1: + Sub AL, AH + Mov [SI], AL + + Call I_MapEnvelope + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeHeldPgUp + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeInsert Far + Assume DS:Inst + + Mov DX, CurrentNode + + Inc DX + Mov CX, MaxNode + Cmp DX, CX + JE I_VolumeEnvelopeInsert1 + + Mov DI, CX + Sub CX, DX + + Cmp DI, 25 + JE I_VolumeEnvelopeInsert1 + + Call I_GetEnvelopeOffset ; DS:SI + Assume DS:Nothing + + LEA BX, [SI+6] + Add BX, DX + Add BX, DX + Add BX, DX + Mov AX, [BX+1] + Sub AX, [BX-2] + Cmp AX, 2 + JB I_VolumeEnvelopeInsert1 + + ClI + + Inc Byte Ptr [SI+1] + + Mov BX, DI + Add BX, BX + Add BX, DI + LEA BX, [BX+SI+6] + +I_VolumeEnvelopeInsert2: + Mov AX, [BX-3] + Mov [BX], AX + Mov AL, [BX-1] + Mov [BX+2], AL + + Sub BX, 3 + Loop I_VolumeEnvelopeInsert2 + + Mov AX, [BX+4] + Add AX, [BX-2] + ShR AX, 1 + Mov [BX+1], AX + + Mov AH, CS:AmplitudeCompensate + Mov AL, [BX+3] + Add AL, [BX-3] + Add AL, AH + Add AL, AH + ShR AL, 1 + Sub AL, AH + Mov [BX], AL + + Mov CL, Byte Ptr CS:CurrentNode + Cmp CL, [SI+2] + JAE I_VolumeEnvelopeInsert4 + + Inc Byte Ptr [SI+2] + +I_VolumeEnvelopeInsert4: + Cmp CL, [SI+3] + JAE I_VolumeEnvelopeInsert5 + + Inc Byte Ptr [SI+3] + +I_VolumeEnvelopeInsert5: + Cmp CL, [SI+4] + JAE I_VolumeEnvelopeInsert6 + + Inc Byte Ptr [SI+4] + +I_VolumeEnvelopeInsert6: + Cmp CL, [SI+5] + JAE I_VolumeEnvelopeInsert7 + + Inc Byte Ptr [SI+5] + +I_VolumeEnvelopeInsert7: + StI + + Call I_MapEnvelope + NetworkSendInstrument + +I_VolumeEnvelopeInsert1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeInsert + Assume DS:Nothing + +; + +Proc I_VolumeEnvelopeDelete Far + + Assume DS:Inst + + Mov DX, CurrentNode + Mov DI, DX + Add DI, DI + Add DI, DX ; DI = CurrentNode*3 + JZ I_VolumeEnvelopeDelete1 + + Mov CX, MaxNode + Cmp CX, 2 + JBE I_VolumeEnvelopeDelete1 + + Call I_GetEnvelopeOffset ; Returns DS:SI + Assume DS:Nothing + + ClI + + Dec Byte Ptr [SI+1] + + Mov BX, SI + LEA SI, [BX+DI+6] + + Sub CX, DX + Dec CX + JZ I_VolumeEnvelopeDelete11 + +I_VolumeEnvelopeDelete2: + Mov AL, [SI+3] + Mov [SI], AL + Mov AX, [SI+4] + Mov [SI+1], AX + + Add SI, 3 + Loop I_VolumeEnvelopeDelete2 + +I_VolumeEnvelopeDelete11: + Xor AX, AX ; Neatness.. clear ending + Mov [SI], AX + Mov [SI+2], AL + ; Ok.. check loop stuff + Mov DL, [BX+1] + Dec DX ; DL = number of nodes + Mov DH, Byte Ptr CS:CurrentNode + + Cmp DH, [BX+2] + JAE I_VolumeEnvelopeDelete7 + + Dec Byte Ptr [BX+2] + +I_VolumeEnvelopeDelete7: + Cmp DH, [BX+3] + JAE I_VolumeEnvelopeDelete8 + + Dec Byte Ptr [BX+3] + +I_VolumeEnvelopeDelete8: + Cmp DH, [BX+4] + JAE I_VolumeEnvelopeDelete9 + + Dec Byte Ptr [BX+4] + +I_VolumeEnvelopeDelete9: + Cmp DH, [BX+5] + JAE I_VolumeEnvelopeDelete10 + + Dec Byte Ptr [BX+5] + +I_VolumeEnvelopeDelete10: + Cmp DL, [BX+2] + JAE I_VolumeEnvelopeDelete3 + + Mov [BX+2], DL + +I_VolumeEnvelopeDelete3: + Cmp DL, [BX+3] + JAE I_VolumeEnvelopeDelete4 + + Mov [BX+3h], DL + +I_VolumeEnvelopeDelete4: + Cmp DL, [BX+4] + JAE I_VolumeEnvelopeDelete5 + + Mov [BX+4], DL + +I_VolumeEnvelopeDelete5: + Cmp DL, [BX+5] + JAE I_VolumeEnvelopeDelete6 + + Mov [BX+5], DL + +I_VolumeEnvelopeDelete6: + StI + Call I_MapEnvelope + +I_VolumeEnvelopeDelete1: + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeDelete + +; + +Proc I_EnvelopeSelected + + Call I_GetEnvelopeOffset ; Returns DS:SI + +IF FILTERENVELOPES + Cmp CS:InstrumentScreen, 3 + JNE I_MouseEnvelopeNoFilter + + Test Byte Ptr [SI], 1 + JNZ I_MouseEnvelopeNoFilter + + Or Byte Ptr [SI], 80h + +I_MouseEnvelopeNoFilter: +ELSE + And Byte Ptr [SI], 7Fh ; Turn of filters. + +ENDIF + + Or Byte Ptr [SI], 1 ; Turn on envelope + Ret + +EndP I_EnvelopeSelected + +; + +Proc I_VolumeEnvelopeEnter Far + + Assume DS:Inst + + Xor NodeHeld, 1 + JZ I_VolumeEnvelopeEnter1 + + Call I_EnvelopeSelected + +I_VolumeEnvelopeEnter1: + Mov AX, 1 + Ret + +EndP I_VolumeEnvelopeEnter + Assume DS:Nothing + +; + +Proc I_InstrumentListSpace Far + + Push CS + Pop DS + Assume DS:Inst + + Cmp NoteReleased, 1 + JNE I_InstrumentSpace1 + + Mov NoteReleased, 0 + Mov SI, Offset NoteData + Call PE_GetLastInstrument + Mov AH, BL + Inc AH + Mov AL, PlayNote + Mov [SI], AX + Mov AX, PlayChannel + Mov DH, 32+128 + Call Music_PlayNote + +I_InstrumentSpace1: + Mov AX, 1 + Ret + +EndP I_InstrumentListSpace + Assume DS:Nothing + +; + +Proc I_InstrumentListNoteOff Far + + Push CS + Pop DS + Assume DS:Inst + + Mov NoteReleased, 1 + Mov SI, Offset NoteData + Mov Word Ptr [SI], 255 + Mov AX, PlayChannel + Mov DH, 32+128 + Call Music_PlayNote + + Mov AX, 1 + Ret + +EndP I_InstrumentListNoteOff + Assume DS:Nothing + +; + +Proc I_ShowSamplePlay Far + ; Clear table first. + + Push CS + Pop DS + ; DS = Inst + Mov SI, Offset SamplePlayTable + Mov CX, 100 + +I_ShowSamplePlayClearTable: + And Byte Ptr [SI], Not 3 + Inc SI + Loop I_ShowSamplePlayClearTable + + Call Music_GetSlaveChannelInformationTable + ; DS:SI points to table. + ; CX = numchannels. + Xor BH, BH + +I_ShowSamplePlay1: + Mov AX, [SI] + Test AL, 1 ; Is channel on? + JZ I_ShowSamplePlay2 + + Test AH, 8 ; Is it muted? + JNZ I_ShowSamplePlay2 + + Mov BL, [SI+36h] + Cmp BL, 100 + JAE I_ShowSamplePlay2 + + Or [CS:SamplePlayTable+BX], 1 ; Show sample is on. + + Cmp DWord Ptr [SI+2Ch], 0 + JNE I_ShowSamplePlay2 + + Or [CS:SamplePlayTable+BX], 2 + +I_ShowSamplePlay2: + Add SI, SLAVECHANNELSIZE + Loop I_ShowSamplePlay1 + + ; OK.. now to dump the stuff + ; onscreen + + Mov BX, TopSample + Dec BX + Mov SI, Offset SamplePlayTable + + Jmp I_ShowInstrumentPlay5 + +EndP I_ShowSamplePlay + +; + +Proc I_ShowInstrumentPlay Far + ; Clear table first. + + Call Music_GetInstrumentMode + JZ I_ShowInstrumentPlayEnd + + Push CS + Pop DS + ; DS = Inst + Mov SI, Offset InstrumentPlayTable + Mov CX, 100 + +I_ShowInstrumentPlayClearTable: + And Byte Ptr [SI], Not 3 + Inc SI + Loop I_ShowInstrumentPlayClearTable + + Call Music_GetSlaveChannelInformationTable + ; DS:SI points to table. + ; CX = numchannels. + Xor BH, BH + +I_ShowInstrumentPlay1: + Mov AX, [SI] + Test AL, 1 ; Is channel on? + JZ I_ShowInstrumentPlay2 + + Test AH, 8 ; Is it muted? + JNZ I_ShowInstrumentPlay2 + + Mov BL, [SI+33h] + Cmp BL, 100 + JAE I_ShowInstrumentPlay2 + + Or [CS:InstrumentPlayTable+BX], 1 ; Show sample is on. + + Cmp DWord Ptr [SI+2Ch], 0 + JNE I_ShowInstrumentPlay2 + + Or [CS:InstrumentPlayTable+BX], 2 + +I_ShowInstrumentPlay2: + Add SI, SLAVECHANNELSIZE + Loop I_ShowInstrumentPlay1 + + ; OK.. now to dump the stuff + ; onscreen + + Mov BX, TopInstrument + Mov SI, Offset InstrumentPlayTable + +I_ShowInstrumentPlay5: + Call S_GetDestination + + Mov CX, 35 + Mov DI, (1+13*80)*2 + +I_ShowInstrumentPlay3: + Mov AX, 2100h + + Mov DL, [CS:SI+BX] + + Cmp DL, 0 ; No dot. + JE I_ShowInstrumentPlay4 + + Mov AL, 173 + + Cmp DL, 4 ; Dark small dot + JE I_ShowInstrumentPlay4 + + Mov AH, 23h + + Test DL, 2 ; Small bright dot + JZ I_ShowInstrumentPlay4 + + Mov AL, 183 ; Large bright dot. + +I_ShowInstrumentPlay4: + StosW + + Add DI, 158 + Inc BX + Loop I_ShowInstrumentPlay3 + +I_ShowInstrumentPlayEnd: + Ret + + +EndP I_ShowInstrumentPlay + +; + +Proc I_ClearTables Far + + Push CS + Pop ES + + Mov DI, Offset SamplePlayTable + Mov CX, 128 + + Xor AX, AX + Rep StosW + + Ret + +EndP I_ClearTables + +; + +Proc I_TagInstrument Far + + Mov Byte Ptr [CS:InstrumentPlayTable+BX], 4 + Ret + +EndP I_TagInstrument + +; + +Proc I_TagSample Far + + Mov Byte Ptr [CS:SamplePlayTable+BX], 4 + Ret + +EndP I_TagSample + +; + +Proc MIDI_PlaySample Far + + Push CS + Pop DS + Assume DS:Inst + + Test DH, DH + JNZ MIDI_PlaySample1 + + Jmp MIDI_NoteOff2 + +MIDI_PlaySample1: + Call Music_GetNumChannels ; Into AX + Mov DI, AX + Mov AX, PlayChannel + Call MIDI_AllocateChannel + + Call PE_GetLastInstrument + Mov CX, AX + Mov AL, DL + Mov AH, BL + Inc AH + Call Music_PlaySample + +MIDI_PlaySample2: + Mov AX, 1 + Ret + +EndP MIDI_PlaySample + +; + +Proc I_PlaySample Far + + Mov AX, Pattern + Mov DS, AX + Assume DS:Pattern + + Mov AH, LastInstrument + Mov AL, CS:LastPlaySample + + Mov CX, CS:PlayChannel + Call Music_PlaySample + + Xor AX, AX + Ret + +EndP I_PlaySample + Assume DS:Nothing + +; + +Proc I_IncreasePlayChannel Far + + Push CS + Pop DS + Assume DS:Inst + + Mov AX, PlayChannel + Cmp AX, 63 + JAE I_IncreasePlayChannel1 + + Inc AX + +I_IncreasePlayChannel1: + Mov PlayChannel, AX + + Inc AX + Mov SI, Offset PlayChannelMsg + + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP I_IncreasePlayChannel + Assume DS:Nothing + +; + +Proc I_DecreasePlayChannel Far + + Push CS + Pop DS + Assume DS:Inst + + Mov AX, PlayChannel + And AX, AX + JZ I_DecreasePlayChannel1 + + Dec AX + +I_DecreasePlayChannel1: + Mov PlayChannel, AX + + Inc AX + Mov SI, Offset PlayChannelMsg + + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP I_DecreasePlayChannel + Assume DS:Nothing + +; + +Proc UpdateMultiChannel + + Cmp CS:MultiChannel, 0 + JE UpdateMultiChannel1 + + Push AX + Push BX + Push DS + Push SI + Assume DS:Inst + + Push CS + Pop DS + + Call Music_GetNumChannels ; Into AX + Mov BX, PlayChannel + Inc BX + Cmp BX, AX + JB UpdateMultiChannel2 + + Xor BX, BX + +UpdateMultiChannel2: + Mov PlayChannel, BX + Mov AX, BX + Inc AX + + Mov SI, Offset PlayChannelMsg + Call SetInfoLine + + Pop SI + Pop DS + Pop BX + Pop AX + +UpdateMultiChannel1: + Ret + +EndP UpdateMultiChannel + Assume DS:Nothing + +; + +Proc I_ToggleMultiChannel Far + + Push CS + Pop DS + Assume DS:Inst + + Mov SI, Offset MultiChannelEnabledMsg + Xor MultiChannel, 1 + JNZ I_ToggleMultiChannel1 + + Mov SI, Offset MultiChannelDisabledMsg + +I_ToggleMultiChannel1: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP I_ToggleMultiChannel + Assume DS:Nothing + +; + +Proc I_DrawPitchPanCenter Far + + Call S_GetDestination + Call I_GetInstrumentOffset ; Returns DS:BX + Mov DI, (54+45*80)*2 + + Mov AL, [BX+17h] + Mov CL, 12 + Xor AH, AH + Xor BH, BH + + Div CL + ; AL = octave, AH = note + Mov BL, AH + Mov DL, AL + Add BX, BX + Add DL, '0' + + Mov AH, 2 + Mov AL, [CS:NoteTable+BX] + StosW + Mov AL, [CS:NoteTable+BX+1] + StosW + Mov AL, DL + StosW + + Ret + +EndP I_DrawPitchPanCenter + +; + +Proc I_PrePitchPanCenter Far + + Call S_GetDestination + Mov AL, 3h + Mov DI, (54+45*80)*2+1 + StosB + Inc DI + StosB + Inc DI + StosB + + Ret + +EndP I_PrePitchPanCenter + +; + +Proc I_PostPitchPanCenter Far + + Push CS + Pop DS + Assume DS:Inst + + Mov SI, Offset PitchPanCenterKeys + Call M_FunctionDivider + JC I_PostPitchPanCenter1 + + Jmp [SI] + +I_PostPitchPanCenter1: + Xor AX, AX + Ret + +EndP I_PostPitchPanCenter + +; + +Proc I_PitchPanCenterUp Far + + Mov Word Ptr [ES:DI], 27 + Mov AX, 1 + Ret + +EndP I_PitchPanCenterUp + +; + +Proc I_PitchPanCenterDown Far + + Mov Word Ptr [ES:DI], 29 + Mov AX, 1 + Ret + +EndP I_PitchPanCenterDown + +; + +Proc I_PitchPanCenterSemiUp Far + + Call I_GetInstrumentOffset + Mov AL, [BX+17h] + + Cmp AL, 119 + JAE I_PitchPanCenterSemiUp1 + + Inc AX + Mov [BX+17h], AL + +I_PitchPanCenterSemiUp1: + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_PitchPanCenterSemiUp + +; + +Proc I_PitchPanCenterSemiDown Far + + Call I_GetInstrumentOffset + Mov AL, [BX+17h] + + Dec AL + JS I_PitchPanCenterSemiDown1 + + Mov [BX+17h], AL + +I_PitchPanCenterSemiDown1: + NetworkSendInstrument + + Mov AX, 1 + Ret + +EndP I_PitchPanCenterSemiDown + +; + +Proc I_IdleUpdateEnvelope Far + + Push CS + Pop DS + Assume DS:Inst + + Cmp UpdateInstrumentScreen, 0 + JNE I_IdleUpdateEnvelope2 + + Mov CL, Byte Ptr InstrumentScreen + Add CL, 11 + Mov DL, 1 + ShL DX, CL + + Call PE_GetLastInstrument ; Gets BX + Inc BX + Call Music_GetSlaveChannelInformationTable + Assume DS:Nothing + +I_IdleUpdateEnvelope1: + Cmp Byte Ptr [SI+33h], BL + JNE I_IdleUpdateEnvelope4 + + Test Byte Ptr [SI], 1 + JZ I_IdleUpdateEnvelope4 + + Test [SI], DX + JZ I_IdleUpdateEnvelope4 + +I_IdleUpdateEnvelope2: + Call I_MapEnvelope + Jmp I_IdleUpdateEnvelope3 + +I_IdleUpdateEnvelope4: + Add SI, SLAVECHANNELSIZE + Loop I_IdleUpdateEnvelope1 + +I_IdleUpdateEnvelope3: + Xor AX, AX + Ret + +EndP I_IdleUpdateEnvelope + +; + +Proc UpdateWAVEForm Far + + Call I_RedrawWave + Ret + +EndP UpdateWAVEForm + +; + +Proc I_SampleButtonHandler Far + + Test AX, AX + JZ I_SampleButtonHandler1 + + NetworkSendSample + +I_SampleButtonHandler1: + Push DS + + Call I_GetSampleOffset + Push DS + Pop ES + Mov DI, BX + Pop DS + + Add DI, [SI+24] + + Ret + +EndP I_SampleButtonHandler + +; + +Proc I_GetPresetEnvelopeOffset Far + + Push CS + Pop DS + Mov DX, Offset PresetEnvelopes + + Ret + +EndP I_GetPresetEnvelopeOffset + +; + +EndS + +; + +End diff --git a/it/IT_K.ASM b/it/IT_K.ASM new file mode 100644 index 0000000..bfe0816 --- /dev/null +++ b/it/IT_K.ASM @@ -0,0 +1,1812 @@ +;Ŀ +; Keyboard Module +; + + Jumps + .386 + +include switch.inc + +;Ŀ +; Externals +; + + Extrn D_GotoStartingDirectory:Far + + Extrn E_UnInitEMS:Far + Extrn S_GetDestination:Far + Extrn Music_Stop:Far + Extrn Music_KBPlaySong:Far + Extrn Music_IncreaseVolume:Far + Extrn Music_DecreaseVolume:Far + Extrn S_DrawString:Far + Extrn CrashRecovery:Far + + Extrn IsStartupKeyList:Far + Extrn GetStartupKeyList:Far + +;Ŀ +; Globals +; + + Global K_DrawTables:Far + Global K_InitKeyBoard:Far + Global K_UnInitKeyBoard:Far + Global K_IsKeyWaiting:Far + Global K_GetKey:Far + Global K_IsAnyKeyDown:Far + Global K_IsKeyDown:Far + Global K_ClearKeyBoardQueue:Far + Global K_ResetKeyboardTables:Far + Global K_SelectKBButton:Far + Global K_SetKeyboardType:Far + Global K_InstallDOSHandler:Far + Global K_UnInstallDOSHandler:Far + Global K_SwapKeyBoard:Far + Global K_InstallKeyboardType:Far + Global K_RemoveKeyboardType:Far + Global K_SetScrollLock:Far + + Global CountryTable:Byte + + Public MIDIBufferEmpty, MIDISend, K_ShowMIDIInput + +; + +Segment KeyBoard BYTE Public 'Code' USE16 + Assume CS:KeyBoard, DS:KeyBoard + +CREATENEWLOGFILE EQU 0 +include debug.inc + +;Ŀ +; Variables +; + +KeyBoardTable DB 256 Dup (?) ; Table of current keypresses +KeyBoardBuffer DB 256 Dup (?) ; Queue of keys. +LastKey DW 0 ; For Caps/Numlock processing + ; only on FIRST press +KBStart DW 0 ; Buffer start ptr +KBEnd DW 0 ; Buffer end ptr + +OldKBHandler Label DWord +OldKBHandlerOffset DW ? ; Old Interrupt handler offset +OldKBHandlerSegment DW ? ; Old interrupt handler segment + +HighSet DB 0 + +Caps DB 0 ; Internal flag +NumLock DB 0 ; Internal flag +ScrollLock DB 0 + +KeyboardFile DB "KEYBOARD.CFG", 0 +KeyboardFileLength DW 0 + +KeypadValueFlag DB 0 +KeypadValue DB 0 + +MIDIStatusByte DB 0 +MIDIDataByte1 DB 0 +MIDIDataByte2 DB 0 +MIDIDataInput DB 0 + +MIDIMessage DB "MIDI Input: ", 0FDh, "X ", 0FDh, "X ", 0FDh, "X ", 0 + +TranslationTable Label DWord +TranslationTableOffset DW Offset USKeyboardTable +TranslationTableSegment DW Keyboard + +USKeyboardTable Label Byte + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; @ + DW '@' + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; # + DW '#' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; ^ + DW '^' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; & + DW '&' + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; * + DW '*' + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ( + DW '(' + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; ) + DW ')' + DB 0FFh + + DB 12 ; - + DB 0 + DW '-' + DB 3 ; _ + DW '_' + DB 0FFh + + DB 13 ; = + DB 0 + DW '=' + DB 3 ; + + DW '+' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; [ + DB 0 + DW '[' + DB 3 ; { + DW '{' + DB 0FFh + + DB 27 ; ] + DB 0 + DW ']' + DB 3 ; } + DW '}' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; ; + DB 0 + DW ';' + DB 3 ; : + DW ':' + DB 0FFh + + DB 40 ; ' + DB 0 + DW "'" + DB 3 ; " + DW '"' + DB 0FFh + + DB 41 ; ` + DB 0 + DW '`' + DB 3 ; ~ + DW '~' + DB 0FFh + + DB 43 ; \ + DB 0 + DW '\' + DB 3 ; | + DW '|' + DB 0FFh + + DB 44 ; z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1Ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW '<' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW '>' + DB 0FFh + + DB 53 ; / + DB 0 + DW '/' + DB 3 + DW '?' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 3 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 83 + DB 8 + DW '.' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +;Ŀ +; Functions +; + +Alt DB 0 +Ctrl DB 0 + +Proc K_KBHandler + + Push AX + Push BX + Push DS + + Push CS + Pop DS + + In AL, 60h ; Get input from port + + Cmp AL, 0FAh + JE K_KBHandler3 ; Is it a LED response?, 2 prev. + + Mov BX, KBEnd ; No... add a key to the queue + Inc BX + And BX, 0FFh + Cmp BX, KBStart + JE K_KBHandler1 + + Mov [KeyBoardBuffer+BX], AL + Mov KBEnd, BX + +K_KBHandler1: + Cmp AL, 1Dh ; Left Ctrl, Right Ctrl + JE K_KBHandlerCtrlPressed + Cmp AL, 9Dh + JE K_KBHandlerCtrlReleased + + Cmp AL, 38h ; Left Alt, Right Alt + JE K_KBHandlerAltPressed + Cmp AL, 0B8h + JE K_KBHandlerAltReleased + + Cmp AL, 42h ; F8 + JNE K_KBHandlerDel + + Cmp Word Ptr [Alt], 0 + JNE K_KBHandler3 + + Call Music_Stop + Jmp K_KBHandler3 + +K_KBHandlerCtrlPressed: + Mov Ctrl, 1 + Jmp K_KBHandler3 + +K_KBHandlerCtrlReleased: + Mov Ctrl, 0 + Jmp K_KBHandler3 + +K_KBHandlerAltPressed: + Mov Alt, 1 + Jmp K_KBHandler3 + +K_KBHandlerAltReleased: + Mov Alt, 0 + Jmp K_KBHandler3 + +K_KBHandlerDel: +CRASHRECOVERYKEY EQU $+1 + Cmp AL, 53h ; Delete, 52h = insert + JNE K_KBHandler3 + + Cmp Word Ptr [Alt], 101h + JNE K_KBHandler3 + + ; Crash recovery + Push BP + Mov BP, SP + DB 66h, 0C7h, 46h, 08h ; Mov DWord Ptr [BP+8], CrashRecovery + DD DWord Ptr CrashRecovery ; + Pop BP + +K_KBHandler3: + In AL, 61h ; KB Acknowledgement. + Mov AH, AL ; (Only for old 8042 chips.) + Or AL, 80h + Out 61h, AL + Mov AL, AH + Out 61h, AL + +K_KBHandler2: + Mov AL, 20h ; IRQ Acknowledgement. + Out 20h, AL + + Pop DS + Pop BX + Pop AX + IRet + +EndP K_KBHandler + +; + +Proc K_DOSKBHandler Far + + Push AX + + In AL, 60h + + Cmp AL, 4Eh ; Grey plus + JE K_DOSKBHandler5 + + Cmp AL, 4Ah ; Grey Minus + JE K_DOSKBHandler6 + + Cmp AL, 0E0h + JNE K_DOSKBHandler3 + + Mov CS:HighSet, 1 + Jmp K_DOSKBHandler4 + +K_DOSKBHandler3: + Cmp CS:HighSet, 0 + JE K_DOSKBHandler4 + + Mov CS:HighSet, 0 + + Cmp AL, 1Dh ; Right Ctrl. + JNE K_DOSKBHandler1 + + PushF + Call DWord Ptr [CS:OldKBHandler] + Call Music_KBPlaySong + Pop AX + IRet + +K_DOSKBHandler1: + Cmp AL, 38h ; Right Alt. + JNE K_DOSKBHandler4 + + PushF + Call DWord Ptr [CS:OldKBHandler] + Call Music_Stop + Pop AX + IRet + +K_DOSKBHandler4: + Pop AX + Jmp DWord Ptr [CS:OldKBHandler] + +K_DOSKBHandler5: ; Grey Plus + Mov AL, 20h + Out 20h, AL + + Call Music_IncreaseVolume + + Pop AX + IRet + +K_DOSKBHandler6: + Mov AL, 20h + Out 20h, AL + + Call Music_DecreaseVolume ; Grey minus + + Pop AX + IRet + +EndP K_DOSKBHandler + +; + +Proc K_SetKeyBoardLights ; Reqs: DS:KeyBoard + ; Sets keyboard lights (duh!) + Push AX + Mov AL, 0EDh + Out 60h, AL + + Xor AL, AL + + Cmp Caps, 0 + JE K_SetKeyBoardLights1 + + Mov AL, 4 + +K_SetKeyBoardLights1: + Cmp NumLock, 0 + JE K_SetKeyBoardLights2 + + Or AL, 2 + +K_SetKeyBoardLights2: + Cmp ScrollLock, 0 + JE K_SetKeyboardLights3 + + Or AL, 1 + +K_SetKeyBoardLights3: + Out 60h, AL + Pop AX + + Ret + +EndP K_SetKeyBoardLights + +; + +Proc K_InitKeyBoard Far ; Raises key repeat rate + ; to 30 char/s, + ; delay before second char=0.25s + ; Gets old IRQ handler + ; and CAPS/NumLock states + ; Checks for Keyboard chip + ; Installs new IRQ handler + + Push AX + Push DS + Push ES + + Push CS + Pop DS + + Trace " - Detecting Windows presence" + + Mov AX, 1600h ; Windows detection. + Int 2Fh + Test AL, 7Fh + JZ NoWindows + + Mov Byte Ptr [CRASHRECOVERYKEY], 52h + +NoWindows: + Trace " - Setting keyboard repeat rate" + + Mov AX, 305h ; Set repeat rate + Xor BX, BX + Int 16h + + Trace " - Installing keyboard handler" + + ClI + + In AL, 21h + Or AL, 00000010b ; Disable keyboard IRQ + Out 21h, AL + + Xor AX, AX + Mov ES, AX + + Mov EAX, [ES:36] + Mov OldKBHandler, EAX + +K_InitKeyBoard3: ; Chained to from K_UnInstallDOSHandler + Mov AL, [ES:417h] ; Keyboard status byte. + Mov AH, AL + And AL, 40h + Mov Caps, AL + And AH, 20h + Mov NumLock, AH + + ; New keyboard IRQ handler + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset K_KBHandler + + Mov Word Ptr [ES:5], 0 ; Screw Int1 + Mov [ES:36], EAX + + In AL, 21h + And AL, 11111101b + Out 21h, AL + + StI + + Trace " - Initialising keyboard tables" + + Call K_ResetKeyboardTables ; Initialise keyboard tables. + + Trace " - Initialising keyboard lights" + + Call K_SetKeyboardLights + + Pop ES + Pop DS + Pop AX + + Ret + +EndP K_InitKeyBoard + +; + +Proc K_UnInitKeyBoard Far + + Push AX + Push DS + Push ES + + Push CS + Pop DS + + ClI + + In AL, 21h + Or AL, 00000010b + Out 21h, AL + + Xor AX, AX + Mov ES, AX + + Mov EAX, OldKBHandler + Mov [ES:36], EAX + +K_UnInitKeyBoard3: ; Chain to from InstallDOSHandler + In AL, 21h + And AL, 11111101b + Out 21h, AL + + StI + + Mov AL, [ES:417h] + And AL, 10010000b + Cmp CS:Caps, 0 + JE K_UnInitKeyBoard2 + + Or AL, 40h ; Set caps lock flag + +K_UnInitKeyBoard2: + Cmp CS:NumLock, 0 + JZ K_UnInitKeyBoard1 + + Or AL, 20h + +K_UnInitKeyBoard1: + Mov [ES:417h], AL + + Pop ES + Pop DS + Pop AX + + Ret + +EndP K_UnInitKeyBoard + +; + +Proc K_InstallDOSHandler Far + + Push AX + Push DS + Push ES + + Push CS + Pop DS + + ClI + + In AL, 21h + Or AL, 00000010b + Out 21h, AL + + Xor AX, AX + Mov ES, AX + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset K_DOSKBHandler + + Mov [ES:36], EAX + + Jmp K_UnInitKeyBoard3 + +EndP K_InstallDOSHandler + +; + +Proc K_UnInstallDOSHandler Far + + Push AX + Push DS + Push ES + + Push CS + Pop DS + + Mov AX, 305h ; Set repeat rate + Xor BX, BX + Int 16h + + ClI + + In AL, 21h + Or AL, 00000010b ; Disable keyboard IRQ + Out 21h, AL + + Xor AX, AX + Mov ES, AX + + Jmp K_InitKeyBoard3 + +EndP K_UnInstallDOSHandler + +; + +Proc K_GetNextKeyByte + + Inc BX + And BX, 0FFh + Mov AL, [KeyBoardBuffer+BX] + + Ret + +EndP K_GetNextKeyByte + +; + +Proc K_IsKeyWaiting Far ; Returns 1 in AX if key is ready + ; 0 in AX if no key is ready + + Push DS + Push BX + Push CX + + Call IsStartupKeyList + And AX, 0FFh + + JNZ K_IsKeyWaiting1 + + Push CS + Pop DS + + Mov AX, KBEnd + Sub AX, KBStart + And AX, 0FFh + JZ K_IsKeyWaiting1 + + Mov CX, AX + + Mov BX, KBStart + Call K_GetNextKeyByte + Cmp AL, 0E0h + JNE K_IsKeyWaiting2 + + Mov AX, CX + Dec AX + Jmp K_IsKeyWaiting1 + +K_IsKeyWaiting2: + Mov AX, 1 + +K_IsKeyWaiting1: + Pop CX + Pop BX + Pop DS + Ret + +EndP K_IsKeyWaiting + +; + +Proc K_GetKey Far ; CX/DX = input/translated + + Push AX + Push BX + Push DS + Push SI + + Push CS + Pop DS + + Call IsStartupKeyList + Test AL, AL + JZ K_GetKeyNoStartupKeyList + + Call GetStartupKeyList + Jmp K_GetKey20 + +K_GetKeyNoStartupKeyList: + ; Check MIDI first + Cmp [MIDIDataInput], 2 + JB K_GetKey1 + + ; OK.. have MIDI message + + Mov CH, [MIDIStatusByte] + Xor CL, CL + Mov DX, Word Ptr [MIDIDataByte1] + Mov [MIDIDataInput], 0 + Jmp K_GetKey20 + +K_GetKey1: + Call K_IsKeyWaiting + And AX, AX + JZ K_GetKey1 + + Xor SI, SI + + Mov BX, KBStart + Call K_GetNextKeyByte + Cmp AL, 0E0h + JB K_GetKey2 + Cmp AL, 0E1h + JA K_GetKey2 + + Mov CX, AX + And CX, 1 + Inc CX + +K_GetKey18: + Mov KBStart, BX + Call K_IsKeyWaiting + And AX, AX + JZ K_GetKey18 + + Add SI, 128 + Call K_GetNextKeyByte + + Loop K_GetKey18 + + Cmp SI, 128 + JBE K_GetKey2 + + Mov SI, 64 + +K_GetKey2: + Mov KBStart, BX + And AL, AL + JS K_GetKey3 + + Inc BH + +K_GetKey3: + And AX, 07Fh + Add SI, AX + Mov CX, SI + Mov CH, BH + + ; OK test for + ; stupid input. + Cmp CL, 0AAh + JE K_GetKey17 + Cmp CL, 0B6h + JE K_GetKey17 + + Mov [KeyBoardTable+SI], BH + + Cmp CX, 13Ah + JNE K_GetKey14 + + Cmp LastKey, CX + JE K_GetKey10 + + Xor Caps, 40h ; Toggle Caps Lock + Call K_SetKeyBoardLights + Jmp K_GetKey10 + +K_GetKey14: + Cmp CX, 145h ; Num Lock + JNE K_GetKey10 + + Cmp LastKey, CX + JE K_GetKey10 + + Xor NumLock, 20h + Call K_SetKeyBoardLights + +K_GetKey10: + Mov LastKey, CX + Cmp Byte Ptr [KeyBoardTable+02Ah], 0 ; Left Shift Key + JE K_GetKey4 + + Or CH, 2 ; Left Shift Key + +K_GetKey4: + Cmp Byte Ptr [KeyBoardTable+36h], 0 ; Right Shift Key + JE K_GetKey5 + + Or CH, 4 ; Right Shift Key + +K_GetKey5: + Cmp Byte Ptr [KeyBoardTable+1Dh], 0 ; Left Ctrl Key + JE K_GetKey6 + + Or CH, 8 + +K_GetKey6: + Cmp Byte Ptr [KeyBoardTable+9Dh], 0 ; Right Ctrl Key + JE K_GetKey7 + + Or CH, 16 ; Right Ctrl Key + +K_GetKey7: + Cmp Byte Ptr [KeyBoardTable+38h], 0 ; Left Alt Key + JE K_GetKey8 + + Or CH, 32 ; Left Alt Key + +K_GetKey8: + Cmp Byte Ptr [KeyBoardTable+0B8h], 0 ; Right Alt Key + JE K_GetKey9 + + Or CH, 64 ; Right Alt Key + +K_GetKey9: + Test CH, 1 ; Keypress? - actually need to check for + ; Alt-keypad stuff. + JNZ K_TranslateKeyPress + + Cmp CL, 38h + JE K_TranslateAltRelease + Cmp CL, 0B8h + JNE K_TranslateKeyNoKey + +K_TranslateAltRelease: + Xor DX, DX + + Cmp KeypadValueFlag, 0 + JE K_TranslateKeyNoKey + + XChg Word Ptr KeypadValueFlag, DX ; Reset flag + value + ShR DX, 8 + Cmp DL, 32 + JB K_TranslateKeyNoKey + Jmp K_TranslateKeyEnd + +K_TranslateKeyPress: + LDS SI, TranslationTable + Assume DS:Nothing + +K_TranslateKey1: + LodsB + Cmp AL, CL + JE K_TranslateKey3 + Cmp AL, 0FFh + JE K_TranslateKeyNoKey + +K_TranslateKey2: + LodsB + Cmp AL, 0FFh + JE K_TranslateKey1 + LodsW + Jmp K_TranslateKey2 + +K_TranslateKey3: + LodsB + Mov BL, AL + LodsW + Mov DX, AX + Cmp BL, 1 + JB K_TranslateCondition0 + JE K_TranslateCondition1 + + Cmp BL, 3 + JB K_TranslateCondition2 + JE K_TranslateCondition3 + + Cmp BL, 5 + JB K_TranslateCondition4 + JE K_TranslateCondition5 + + Cmp BL, 7 + JB K_TranslateCondition6 + JE K_TranslateCondition7 + + Cmp BL, 9 + JB K_TranslateCondition8 + JE K_TranslateCondition9 + + Cmp BL, 11 + JB K_TranslateCondition10 + + Jmp K_TranslateKeyNoKey + +K_TranslateCondition0: ; Keypress + Test CH, Not 1 + JNZ K_TranslateKey3 + Jmp K_TranslateKeyEnd + +K_TranslateCondition1: + Cmp Caps, 0 + JE K_TranslateCondition3 ; Caps off -> check shift + +K_TranslateConditionNoShift: + Test CH, Not 7 + JNZ K_TranslateKey3 + Test CH, 6 + JNZ K_TranslateKey3 + Jmp K_TranslateKeyEnd + +K_TranslateCondition2: + Cmp Caps, 0 + JE K_TranslateConditionNoShift + ; Fall through to shift check + +K_TranslateCondition3: ; Shift + Test CH, Not 7 + JNZ K_TranslateKey3 + Test CH, 6 + JZ K_TranslateKey3 + Jmp K_TranslateKeyEnd + +K_TranslateCondition4: ; Ctrl + Test CH, Not 19h + JNZ K_TranslateKey3 + Test CH, 18h + JZ K_TranslateKey3 + Jmp K_TranslateKeyEnd + +K_TranslateCondition5: ; Alt + Test CH, Not 61h + JNZ K_TranslateKey3 + Test CH, 60h + JZ K_TranslateKey3 + Jmp K_TranslateKeyEnd + +K_TranslateCondition6: ; Left alt + Test CH, Not 21h + JNZ K_TranslateKey3 + Test CH, 20h + JZ K_TranslateKey3 + Jmp K_TranslateKeyEnd + +K_TranslateCondition7: ; Right alt + Test CH, Not 41h + JNZ K_TranslateKey3 + Test CH, 40h + JZ K_TranslateKey3 + Jmp K_TranslateKeyEnd + +K_TranslateCondition8: + Test CH, Not 1 + JNZ K_TranslateKey3 + Cmp NumLock, 0 + JE K_TranslateKey3 + Jmp K_TranslateKeyEnd + +K_TranslateCondition9: + Test CH, Not 1 + JNZ K_TranslateKey3 + Cmp NumLock, 0 + JNE K_TranslateKey3 + Jmp K_TranslateKeyEnd + +K_TranslateCondition10: + Test CH, Not 61h + JNZ K_TranslateKey3 + Test CH, 60h + JZ K_TranslateKey3 + + Mov CS:KeyPadValueFlag, 1 + Mov AL, 10 + Mul CS:KeyPadValue + Add AL, DL + Mov CS:KeyPadValue, AL + +K_TranslateKeyNoKey: + Xor DX, DX + +K_TranslateKeyEnd: + Cmp NumLock, 0 + JNE K_GetKey15 + + Cmp CL, 47h + JB K_GetKey15 + Cmp CL, 53h + JA K_GetKey15 + Cmp CL, 4Ah + JE K_GetKey15 + Cmp CL, 4Eh + JE K_GetKey15 + + Add CL, 80h + Jmp K_GetKey20 + +K_GetKey15: + Cmp CL, 9Ch ; Grey enter... + JNE K_GetKey20 + + Mov CL, 1Ch ; Normal enter! + Jmp K_GetKey20 + +K_GetKey17: + Xor CX, CX + Xor DX, DX + +K_GetKey20: + Pop SI + Pop DS + Pop BX + Pop AX + Ret + + +EndP K_GetKey + +; + +Proc K_ClearKeyBoardQueue Far + + Push AX + +K_ClearKeyBoardQueue1: + Call K_IsKeyWaiting + Test AX, AX + JZ K_ClearKeyBoardQueue2 + Call K_GetKey + Jmp K_ClearKeyBoardQueue1 + +K_ClearKeyBoardQueue2: + Pop AX + Ret + +EndP K_ClearKeyBoardQueue + +; + +Proc K_IsAnyKeyDown Far ; Returns AL = 1 if key is down. + + Push CX + Push DS + Push SI + + Push CS + Pop DS + Assume DS:Keyboard + + Mov SI, Offset KeyBoardTable + Mov CX, 256 + +K_IsAnyKeyDown1: + LodsB + And AL, AL + LoopZ K_IsAnyKeyDown1 + + JCXZ K_IsAnyKeyDown2 + + Mov AL, 1 + +K_IsAnyKeyDown2: + Pop SI + Pop DS + Pop CX + + Ret + +EndP K_IsAnyKeyDown + +; + +Proc K_IsKeyDown Far ; BX = key to test + + Cmp [CS:KeyboardTable+BX], 0 + Ret + +EndP K_IsKeyDown + +; + +Proc K_ResetKeyboardTables Far + + Push CS + Pop ES + Mov DI, Offset KeyboardTable + Mov CX, 518 + Xor AL, AL + Rep StosB + + Mov AX, 1 + Ret + +EndP K_ResetKeyboardTables + +; + +Proc K_DrawTables Far + + Call S_GetDestination + Mov DI, (2+15*80)*2 + + Push CS + Pop DS + Assume DS:KeyBoard + Mov SI, Offset KeyboardBuffer + + Mov CX, 2004h ; CH = row count, CL = ShR + Mov AH, 2h + +K_DrawTables1: + Mov DL, 08h ; BL = count + Push DI + +K_DrawTables3: + LodsB + Mov DH, AL + ShR AL, CL + Cmp AL, 10 + SBB AL, 69h + DAS + StosW + + Mov AL, DH + And AL, 0Fh + Cmp AL, 10 + SBB AL, 69h + DAS + StosW + + Dec DL + JZ K_DrawTables2 + + Mov AL, ' ' + StosW + Jmp K_DrawTables3 + +K_DrawTables2: + Pop DI + Add DI, 160 + + Dec CH + JNZ K_DrawTables1 + + ; Now for keypress tables. + Mov SI, Offset KeyboardTable + Mov DI, (29+15*80)*2 + + Mov CX, 2004h ; CH = row count, CL = ShR + Xor DL, DL + +K_DrawTable4: + Mov DH, 8 + Push DI + +K_DrawTable5: + Mov AH, 2 + LodsB + + Cmp AL, 1 + SBB AH, -1 + + Mov AL, DL + ShR AL, CL + Cmp AL, 10 + SBB AL, 69h + DAS + StosW + + Mov AL, DL + And AL, 0Fh + Cmp AL, 10 + SBB AL, 69h + DAS + StosW + + Inc DL + Dec DH + JZ K_DrawTable7 + + Mov AL, ' ' + StosW + Jmp K_DrawTable5 + +K_DrawTable7: + Pop DI + Add DI, 160 + + Dec CH + JNZ K_DrawTable4 + + Xor AX, AX + Ret + +EndP K_DrawTables + Assume DS:Nothing + +; + +Proc K_ShowMIDIInput Far + + Push CS + Pop DS + Assume DS:Keyboard + + ; Now to shove the MIDI input info. + Xor AX, AX + Mov AL, [MIDIDataByte2] + Push AX + Mov AL, [MIDIDataByte1] + Push AX + Mov AL, [MIDIStatusByte] + Push AX + + Mov DI, (2+13*80)*2 + Mov SI, Offset MIDIMessage + Mov AH, 20h + Call S_DrawString + + Add SP, 6 + + Xor AX, AX + Ret + +EndP K_ShowMIDIInput + Assume DS:Nothing + +; + +Proc K_InstallKeyboardType Far + + Call D_GotoStartingDirectory + + Push CS + Pop DS + Assume DS:Keyboard + + Mov AX, 3D00h + Mov DX, Offset KeyboardFile + Int 21h + JC K_InstallKeyboardType2 + + Trace " - Custom keyboard file found" + + Mov BX, AX + + Mov AH, 3Fh + Mov CX, 2 ; Read 2 bytes + Mov DX, Offset KeyboardFileLength + Int 21h + JC K_InstallKeyboardType1 + + Trace " - Allocating memory" + + Push BX + Mov AH, 48h ; Allocate memory + Mov BX, KeyboardFileLength + Mov CX, BX ; CX = length for next call. + Add BX, 15 + ShR BX, 4 + Int 21h + Pop BX + JC K_InstallKeyboardType1 + ; AX = load destination + + Trace " - Loading custom keyboard data" + + Mov DS, AX + Xor DX, DX + Mov AH, 3Fh ; Load data + Int 21h + JC K_InstallKeyboardType3 + + Trace " - Installing new keyboard translation table" + + Mov AX, DS + ShL EAX, 16 + Mov CS:TranslationTable, EAX + Jmp K_InstallKeyboardType1 + +K_InstallKeyboardType3: + Push DS + Pop ES + Mov AH, 49h + Int 21h + +K_InstallKeyboardType1: + Mov AH, 3Eh ; Close file + Int 21h + +K_InstallKeyboardType2: + Ret + +EndP K_InstallKeyboardType + +; + +Proc K_RemoveKeyboardType Far + + Push CS + Pop DS + Assume DS:Keyboard + + Mov AX, TranslationTableSegment + Mov BX, CS + Cmp AX, BX + JE K_RemoveKeyboardType1 + + Mov ES, AX + Mov AH, 49h + Int 21h + +K_RemoveKeyboardType1: + Ret + +EndP K_RemoveKeyboardType + +; + +Proc K_SetScrollLock Far + + Push CS + Pop DS + Mov ScrollLock, AL + Call K_SetKeyboardLights + Ret + +EndP K_SetScrollLock + +; + +Proc MIDIBufferEmpty Far ; Returns carry set if input OK. + ; Returns carry CLEAR if input full. + + Cmp [CS:MIDIDataInput], 2 + Ret + +EndP MIDIBufferEmpty + +; + +Proc MIDISend Far ; Given AL = data byte. + + Push DS + + Push CS + Pop DS + Assume DS:Keyboard + + Test AL, AL ; Status byte? + JNS MIDISend1 + + Mov [MIDIStatusByte], AL + Mov [MIDIDataInput], 0 + Jmp MIDISendEnd + +MIDISend1: + Xor BX, BX + Mov SI, Offset MIDIDataByte1 + Add BL, [MIDIDataInput] + Mov [SI+BX], AL + Mov AL, [MIDIStatusByte] + Inc BX + Cmp AL, 0C0h + JB MIDISend2 + Cmp AL, 0E0h + JAE MIDISend2 + + Inc BX + Mov [MIDIDataByte2], 0 + +MIDISend2: + Mov [MIDIDataInput], BL + +MIDISendEnd: + Pop DS + Ret + +EndP MIDISend + Assume DS:Nothing + +; + +EndS + +; + +End diff --git a/it/IT_L.ASM b/it/IT_L.ASM new file mode 100644 index 0000000..7085bce --- /dev/null +++ b/it/IT_L.ASM @@ -0,0 +1,559 @@ +;Ŀ +; Info Line Module - Playing info updates / other messages +; + + Jumps + .386 + +include switch.inc + +;Ŀ +; Externals +; + +Segment Glbl BYTE Public 'Code' + Extrn CurrentMode:Byte +EndS + + Extrn I_ShowSamplePlay:Far + Extrn I_ShowInstrumentPlay:Far + + Extrn S_UpdateScreen:Far + Extrn S_DrawString:Far + Extrn S_SetDirectMode:Far + Extrn S_GetDestination:Far + + Extrn Music_GetPlayMode:Far + Extrn Music_Poll:Far + Extrn Music_GetSlaveChannelInformationTable:Far + +IF NETWORKENABLED + Extrn Network_Poll:Far +ENDIF + + Extrn PE_ShowOrder:Far + Extrn PE_FillSpeedTempo:Far + Extrn PE_GetMaxOrder:Far + Extrn Glbl_TutorialHandler:Far + +;Ŀ +; Globals +; + + Global UpdateInfoLine:Far + Global IdleUpdateInfoLine:Far + Global ClearInfoLine:Far + Global SetInfoLine:Far, SetInfoLine2:Far + Global StartClock:Far + Global GlobalStartTime:Far + Public ShowUsageTime + Public InitTimerHandler + Public UnInitTimerHandler + Public GetTimerCounter + +; + +Segment InfoLine DWORD Public 'Code' USE16 + Assume CS:InfoLine, DS:InfoLine + +CREATENEWLOGFILE EQU 0 +include debug.inc + +;Ŀ +; Variables +; + +SLAVECHANNELSIZE = 128 + +OldTimerHandler DD 0 +TimerCounter DD 0 +PlaybackTimer DD 0 + +InfoLineText DD 0 +InfoLineDelay DW 0 +InfoLineVariable DW 0 + +; Colouring for ZaStaR +; PatternPlayMsg DB "Playing, Pattern: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, ", Row: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, "/", 0FDh, "D", 0FFh, 13, " ", 0 +; SongPlayMsg DB "Playing, Order: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, "/", 0FDh, "D, Pattern: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, ", Row: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, "/", 0FDh, "D", 0FFh, 6, " ", 0 + +NoSoundDriverMsg DB "Error: No sound driver loaded.", 0 +PatternPlayMsg DB "Playing, Pattern: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, ", Row: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, "/", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, ", ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, " Channels", 0FFh, 10, " ", 0 +SongPlayMsg DB "Playing, Order: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, "/", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, ", Pattern: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, ", Row: ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, "/", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, ", ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, " Channels", 0FFh, 10, " ", 0 +ChannelMsg DB "Playing, ", 0FEh, 23h, 0FDh, "D", 0FEh, 20h, " Channels", 0 +EmptyMsg DB 0 +TimeMsg DB " Time ", 0FDh, "D:" +Minutes DB "00:" +Seconds DB "00", 0 +DisplayChannelMsg DB 0 +ShowUsageTime DB 1 + + +;Ŀ +; Functions +; + +Proc TimerInterruptHandler + + Sub CS:InfoLineDelay, 1 + AdC CS:InfoLineDelay, 0 + + Inc CS:TimerCounter + Jmp [CS:OldTimerHandler] + +EndP TimerInterruptHandler + +; + +Proc InitTimerHandler Far + + Push DS + + Trace " - Installing new timer interrupt" + + Xor AX, AX + Mov DS, AX + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset TimerInterruptHandler + + ClI + XChg EAX, [DS:20h] + Mov [CS:OldTimerHandler], EAX + StI + + Pop DS + Ret + +EndP InitTimerHandler + +; + +Proc UninitTimerHandler Far + + Push DS + + Xor AX, AX + Mov DS, AX + + Mov EAX, [CS:OldTimerHandler] + ClI + Mov [DS:20h], EAX + StI + + Pop DS + Ret + +EndP UninitTimerHandler + +; + +Proc FillToEOL + + Push ES + Mov AX, ' ' + 2000h + Call S_GetDestination + +UpdateInfoLineEOL: + Cmp DI, (61+9*80)*2 + JAE UpdateInfoLineEOL2 + + StosW + Jmp UpdateInfoLineEOL + +UpdateInfoLineEOL2: + Pop ES + Ret + +EndP FillToEOL + +; + +Proc UpdateInfoLine Far + + Push DS + Push SI + + Push Glbl + Pop DS + Assume DS:Glbl + + Cmp CurrentMode, 200 + JAE UpdateInfoLineEnd2 + + Push CS + Pop DS + + Mov DI, (2+9*80)*2 + + Cmp InfoLineDelay, 0 + JE UpdateInfoLine1 +; Mov CX, InfoLineDelay +; JCXZ UpdateInfoLine1 +; +; Dec InfoLineDelay + +UpdateInfoLine2: + LDS SI, InfoLineText + Mov CX, DS + JCXZ UpdateInfoLineEnd + + Mov AX, CS:InfoLineVariable + Push AX + + Mov AH, 20h + Call S_DrawString + Call FillToEOL + + Pop AX + + Call Music_GetPlayMode +; Call ShowTime + Jmp UpdateInfoLine6 + +UpdateInfoLine1: +; ****** + Call Music_GetSlaveChannelInformationTable + ; DS:SI points to tables + ; CX = numchannels. + Xor DI, DI ; DI = counter of + ; currently act. + ; channels. +CountChannels1: + Mov AX, [SI] + Test AH, 8 + JNZ CountChannels2 + + And AX, 1 + Add DI, AX + +CountChannels2: + Add SI, SLAVECHANNELSIZE + Loop CountChannels1 + + Push CS + Pop DS +; ****** + Call Music_GetPlayMode + ; AX = playmode + ; BX = row + ; CX = pattern + ; DX = order + ; SI = max row. + + Push AX + Push DI + Cmp AX, 1 + JB UpdateInfoLineChanMsg + Push SI + Push BX ; BX = row + Push CX ; CX = pattern + JE UpdateInfoLine3 + JA UpdateInfoLine4 + +UpdateInfoLineChanMsg: + Mov SI, Offset ChannelMsg + Cmp DI, 1 + JA UpdateInfoLineChanMsg2 + + Mov SI, Offset EmptyMsg + +UpdateInfoLineChanMsg2: + Mov DI, (2+9*80)*2 + Mov AH, 20h + Call S_DrawString + Call FillToEOL + Pop AX + + Pop AX + Mov DisplayChannelMsg, 1 + Jmp UpdateInfoLine7 + +UpdateInfoLineEnd: + Call ShowTime + +UpdateInfoLineEnd2: + Pop SI + Pop DS + + Mov AX, 1 + Ret + +UpdateInfoLine3: + Mov DI, (2+9*80)*2 + Mov SI, Offset PatternPlayMsg + Mov AH, 20h + Call S_DrawString + Call FillToEOL + + Add SP, 8 + Jmp UpdateInfoLine5 + +UpdateInfoLine4: + Call PE_GetMaxOrder + + Push AX + Push DX + + Mov DI, (2+9*80)*2 + Mov SI, Offset SongPlayMsg + Mov AH, 20h + Call S_DrawString + Call FillToEOL + + Add SP, 12 + +UpdateInfoLine5: + Pop AX + +UpdateInfoLine6: +; Cmp AX, 2 +; JNE UpdateInfoLine7 + + +UpdateInfoLine7: + Call ShowTime + Call UpdatePointers + + Pop SI + Pop DS + + Mov AX, 1 + Ret + +EndP UpdateInfoLine + Assume DS:Nothing + +; + +Proc IdleUpdateInfoLine Far + + Call Music_Poll + +IF TUTORIAL +ELSE + Mov AL, 1 + Call S_SetDirectMode +ENDIF + + Call UpdateInfoLine + +IF TUTORIAL + Call Glbl_TutorialHandler +ENDIF + +IF TUTORIAL + Call S_UpdateScreen +ELSE + Mov AL, 0 + Call S_SetDirectMode +ENDIF + +IF NETWORKENABLED + Jmp Network_Poll +ELSE + Xor AX, AX + Ret +ENDIF + +EndP IdleUpdateInfoLine + +; + +Proc ClearInfoLine Far + + Mov DWord Ptr [CS:InfoLineText], 0 + + Ret + +EndP ClearInfoLine + +; + +Proc SetInfoLine Far ; DS:SI points to msg. + + Mov CS:InfoLineDelay, 20 + +SetInfoLineChain: + Mov Word Ptr [CS:InfoLineText], SI + Mov Word Ptr [CS:InfoLineText+2], DS + Mov Word Ptr [CS:InfoLineVariable], AX + + Ret + +EndP SetInfoLine + +; + +Proc SetInfoLine2 Far ; DS:SI points to msg. + + Mov CS:InfoLineDelay, BX + Jmp SetInfoLineChain + +EndP SetInfoLine2 + +; + +Proc UpdatePointers ; BX = row, CX = pattern + + Mov SI, Glbl + Mov DS, SI + Assume DS:Glbl + + Mov AH, CurrentMode + +; And AH, AH +; JZ UpdatePointers6 + + Push AX + Push BX + Push CX + +; Call S_GetDestination ; Get ES. + Call PE_FillSpeedTempo + + Pop CX + Pop BX + Pop AX + +UpdatePointers6: +; Cmp AH, 2 +; JNE UpdatePointers1 +; +; Cmp AL, 1 +; JB UpdatePointersEnd +; +; Call PE_ShowPatternRow +; Ret +; +; UpdatePointers1: + Cmp AL, 2 ; Playmode. + JNE UpdatePointers3 + + Cmp AH, 11 + JE UpdatePointers2 + Cmp AH, 21 + JNE UpdatePointers3 + +UpdatePointers2: + Call PE_ShowOrder + + Ret + +UpdatePointers3: + Cmp AH, 3 + JNE UpdatePointers4 + + Call I_ShowSamplePlay + Ret + +UpdatePointers4: + Cmp AH, 4 + JNE UpdatePointers5 + + Call I_ShowInstrumentPlay + Ret + +UpdatePointers5: +UpdatePointersEnd: + Ret + +EndP UpdatePointers + Assume DS:Nothing + +; + +Proc ShowTime + + PushA + Push DS + + Push CS + Pop DS + Assume DS:InfoLine + + Cmp AX, 2 + Mov EAX, [TimerCounter] + JE ShowTime3 + + Cmp ShowUsageTime, 0 + JE ShowTime2 + + Jmp ShowTime4 + +ShowTime3: + Sub EAX, [PlaybackTimer] + +ShowTime4: + Mov EDX, 3600 + Mul EDX + ShRD EAX, EDX, 16 + ShR EDX, 16 + JNZ ShowTime2 + ; EAX = number of seconds + Mov EBX, 60 + Div EBX ; EAX = minutes, EDX = seconds + + Push EDX + Xor EDX, EDX + Div EBX ; EAX = hours, EDX = minutes + + Pop ECX + Push AX ; Hours on stack, CX = seconds, DX = min + Mov BL, 10 + + Mov AX, DX + Div BL + Add AX, 3030h + Mov [Word Ptr Minutes], AX + + Mov AX, CX + Div BL + Add AX, 3030h + Mov [Word Ptr Seconds], AX + + Mov SI, Offset TimeMsg + Mov DI, (62+9*80)*2 + Mov AH, 20h + Call S_DrawString + Pop AX ; To clear stack + +ShowTime2: + Pop DS + PopA + + Ret + +EndP ShowTime + Assume DS:Nothing + +; + +Proc StartClock Far + + Push EAX + Mov EAX, CS:TimerCounter + Mov [CS:PlaybackTimer], EAX + Pop EAX + + Ret + +EndP StartClock + +; + +Proc GetTimerCounter Far + + Mov EAX, [CS:TimerCounter] + Ret + +EndP GetTimerCounter + +; + +EndS + +; + +End diff --git a/it/IT_M.ASM b/it/IT_M.ASM new file mode 100644 index 0000000..7ba3bf9 --- /dev/null +++ b/it/IT_M.ASM @@ -0,0 +1,664 @@ +;Ŀ +; Main Module +; + + Jumps + .386 + +include switch.inc + +;Ŀ +; Externals +; + +Segment Object1 BYTE Public 'Data' USE16 +EndS + + + Extrn F_DrawStringInput:Far + Extrn F_PreStringInput:Far + Extrn F_PostStringInput:Far + Extrn F_Nothing:Far + Extrn F_DrawBoxObject:Far + Extrn F_DrawTextObject:Far + Extrn F_PostExitObject:Far + Extrn F_SetDirectMode:Far + Extrn F_CharacterDefinitions:Far + Extrn F_DrawButtonObject:Far + Extrn F_PreButtonObject:Far + Extrn F_PostButtonObject:Far + Extrn F_CallFarFunction:Far + Extrn F_DrawThumbBar:Far + Extrn F_DrawScalableThumbBar:Far + Extrn F_PreThumbBar:Far + Extrn F_PreScalableThumbBar:Far + Extrn F_PostThumbBar:Far + Extrn F_PostScalableThumbBar:Far + Extrn F_DrawInfoLine:Far + Extrn F_CallFarPreFunction:Far + Extrn F_CallFarPostFunction:Far + Extrn F_DrawToggle:Far + Extrn F_PreToggle:Far + Extrn F_PostToggle:Far + + Extrn F_Draw5Num:Far + Extrn F_Pre5Num:Far + Extrn F_Post5Num:Far + + Extrn F_Draw3Num:Far + Extrn F_Pre3Num:Far + Extrn F_Post3Num:Far + + Extrn Glbl_TutorialHandler:Far + + Extrn H_SetHelpContext:Far + + Extrn K_GetKey:Far + Extrn K_InitKeyBoard:Far + Extrn K_UnInitKeyBoard:Far + Extrn K_IsKeyWaiting:Far + Extrn K_IsAnyKeyDown:Far + + Extrn PE_DrawOrderList:Far + Extrn PE_PreOrderList:Far + Extrn PE_PostOrderList:Far + + Extrn S_Set80x25Mode:Far + Extrn S_SetPalette:Far + Extrn S_RedefineCharacters:Far + Extrn S_DrawBox:Far + Extrn S_ClearScreen:Far + Extrn S_UpdateScreen:Far + +; Extrn MouseDirectEnable:Far, MouseDirectDisable:Far + Extrn MouseSaveEvents:Far, MouseRestoreEvents:Far + Extrn MouseInput:Far, MouseClearEvents:Far + Extrn GetKeyboardLock:Far, MIDIBufferEmpty:Far + +;Ŀ +; Globals +; + + Global M_FunctionDivider:Far + Global M_FunctionHandler:Far + Global M_Object1List:Far + Global M_Object1ListDefault:Far + Public ReleaseTimeSlice + +; + +Segment Main DWORD Public 'Code' USE16 + Assume CS:Main, DS:Nothing + +;Ŀ +; Variables +; + +DrawObjectList Label DWord + DD DWord Ptr F_DrawBoxObject ; 0 + DD DWord Ptr F_DrawTextObject ; 1 + DD DWord Ptr F_DrawButtonObject ; 2 + DD DWord Ptr F_Nothing ; Empty obj number, 3 + DD DWord Ptr F_Nothing ; 4 + DD DWord Ptr F_SetDirectMode ; 5 + DD DWord Ptr F_CharacterDefinitions ; 6 + DD DWord Ptr F_Nothing ; Empty obj number 7 + DD DWord Ptr F_CallFarFunction ; 8 + DD DWord Ptr F_DrawThumbBar ; 9 + DD DWord Ptr F_DrawInfoLine ; 10 + DD DWord Ptr H_SetHelpContext ; 11 + DD DWord Ptr PE_DrawOrderList ; 12 + DD DWord Ptr F_Draw3Num ; 13 + DD DWord Ptr F_DrawScalableThumbBar ; 14 + DD DWord Ptr F_CallFarFunction ; 15 + DD DWord Ptr F_DrawStringInput ; 16 + DD DWord Ptr F_DrawToggle ; 17 + DD DWord Ptr F_Draw5Num ; 18 + + +PreFunctionList Label DWord + DD DWord Ptr F_Nothing ; 0 + DD DWord Ptr F_Nothing ; 1 + DD DWord Ptr F_PreButtonObject ; 2 + DD DWord Ptr F_Nothing ; 3 + DD DWord Ptr F_Nothing ; 4 + DD DWord Ptr F_Nothing ; 5 + DD DWord Ptr F_Nothing ; 6 + DD DWord Ptr F_Nothing ; 7 + DD DWord Ptr F_Nothing ; 8 + DD DWord Ptr F_PreThumbBar ; 9 + DD DWord Ptr F_Nothing ; 10 + DD DWord Ptr F_Nothing ; 11 + DD DWord Ptr PE_PreOrderList ; 12 + DD DWord Ptr F_Pre3Num ; 13 + DD DWord Ptr F_PreScalableThumbBar ; 14 + DD DWord Ptr F_CallFarPreFunction ; 15 + DD DWord Ptr F_PreStringInput ; 16 + DD DWord Ptr F_PreToggle ; 17 + DD DWord Ptr F_Pre5Num ; 18 + +PostFunctionList Label DWord + DD DWord Ptr F_Nothing ; 0 + DD DWord Ptr F_Nothing ; 1 + DD DWord Ptr F_PostButtonObject ; 2 + DD DWord Ptr F_Nothing ; 3 + DD DWord Ptr F_PostExitObject ; 4 + DD DWord Ptr F_Nothing ; 5 + DD DWord Ptr F_Nothing ; 6 + DD DWord Ptr F_Nothing ; 7 + DD DWord Ptr F_Nothing ; 8 + DD DWord Ptr F_PostThumbBar ; 9 + DD DWord Ptr F_Nothing ; 10 + DD DWord Ptr F_Nothing ; 11 + DD DWord Ptr PE_PostOrderList ; 12 + DD DWord Ptr F_Post3Num ; 13 + DD DWord Ptr F_PostScalableThumbBar ; 14 + DD DWord Ptr F_CallFarPostFunction ; 15 + DD DWord Ptr F_PostStringInput ; 16 + DD DWord Ptr F_PostToggle ; 17 + DD DWord Ptr F_Post5Num ; 18 + +GlobalKeyList DD ? +ReleaseTimeSlice DB 0 + +;Ŀ +; Functions +; + +Proc M_FunctionDivider Far ; Given DS:SI points to list + ; Carry set if none found + Push BX + +M_FunctionDivider1: ; 0 = Direct comparison + ; 1 = Key comparison + ; 2 = Alt, 3 = Ctrl, 4 = Shift + ; 5 = capital key comparison + ; 6 = MIDI message + LodsB + Test AL, AL + JS M_FunctionDivider4 ; End of list + + Mov BX, CX + JZ M_FunctionDivider2 ; If AL = 0 + + Cmp AL, 2 + JE M_FunctionDivider8 + JB M_FunctionDivider5 + + Cmp AL, 4 + JB M_FunctionDivider18 + JE M_FunctionDivider10 ; If AL = 4 + + Cmp AL, 6 + JB M_FunctionDividerCAPS + +M_FunctionDividerMIDI: + Test CL, CL + JNZ M_FunctionDivider9 + Mov BX, CX + And BX, 0F000h + Jmp M_FunctionDividerCheck + +M_FunctionDividerCAPS: + Mov BX, DX + Cmp BX, 'a' + JB M_FunctionDivider6 + Cmp BX, 'z' + JA M_FunctionDivider9 + + Sub BL, 32 + +M_FunctionDivider6: + Cmp BX, 'A' + JB M_FunctionDivider9 + Cmp BX, 'Z' + JA M_FunctionDivider9 + Jmp M_FunctionDivider2 + +M_FunctionDivider5: + Mov BX, DX ; If al = 1... + Jmp M_FunctionDivider2 + +M_FunctionDivider8: + Test CH, 60h + JZ M_FunctionDivider9 + + And BX, 1FFh + Jmp M_FunctionDivider2 + +M_FunctionDivider18: + Test CH, 18h ; Ctrl + JZ M_FunctionDivider9 + And BX, 1FFh + + Jmp M_FunctionDivider2 + +M_FunctionDivider10: + Test CH, 6 + JZ M_FunctionDivider9 + And BX, 1FFh + +M_FunctionDivider2: + Test CL, CL + JZ M_FunctionDivider9 + +M_FunctionDividerCheck: + LodsW + Cmp AX, BX + JE M_FunctionDivider3 + + LodsW + Jmp M_FunctionDivider1 + +M_FunctionDivider9: + LodsW + LodsW + Jmp M_FunctionDivider1 + +M_FunctionDivider3: + DB 85h ; ClC +M_FunctionDivider4: ; + StC ; + + Pop BX + + Ret + +EndP M_FunctionDivider + +; + +Proc M_FunctionHandler Far + ARG ObjectList:DWord + + Push BP + Mov BP, SP + + Call MouseSaveEvents + +M_FunctionHandler1: ; Draw all objects in list + Call GetKeyboardLock + Cmp AL, 2 + JE MouseInput1 + + Call MouseClearEvents + + LDS SI, ObjectList ; DS:SI points to object list + Add SI, 6 ; Skip pass list header + Xor AX, AX + +M_FunctionHandler2: + Cmp Word Ptr [SI], 0 ; DS:SI points to an offset of + JE M_FunctionHandler4 ; an object + +M_FunctionHandler3: + Push AX ; AX = object number + Push DS + Push SI + Push BP + + LES DI, ObjectList ; ES:DI points to object list + Mov SI, [SI] ; DS:SI points to object + Mov BX, [SI] ; BX = object type + Mov CL, 2 + ShL BX, CL + + Call DWord Ptr [DrawObjectList+BX] + + Pop BP + Pop SI ; DS:SI Points to an offset of + Pop DS ; an object + Pop AX + Inc AX + Add SI, 2 ; Advance Pointer + Jmp M_FunctionHandler2 ; Next Object + +M_FunctionHandler4: ; Call Prefunction for object + LDS SI, ObjectList ; DS:SI points to object list + Mov AX, [SI] ; AX = Active object number + LEA SI, [ESI+EAX*2+6] ; Skip pas list header (+6) + ; AX = object number + + Cmp Word Ptr [SI], 0 ; if list doesn't point to + JE M_FunctionHandler21 ; anything, don't call prefunc + +M_FunctionHandler20: + Mov SI, [SI] ; DS:SI points to object + Mov BX, [SI] ; BX = object type + ShL BX, 2 + + Push BP + Call DWord Ptr [PreFunctionList+BX] + Pop BP + +M_FunctionHandler21: + +IF TUTORIAL + Call Glbl_TutorialHandler +ENDIF + + Call S_UpdateScreen + +M_FunctionHandler5: ; Input... +; Call K_IsAnyKeyDown +; And AL, AL +; JNZ M_KeyBoardInput1 + +MouseInput1: + Call MouseInput ; returns 0 if nothing + ; 1 if input (BX, CX, DX set) + ; 2 if no input, but keyboard + ; locked + Cmp AX, 1 + JB M_KeyBoardInput1 + JA M_FunctionHandler6 ; IdleList + ; Handle postobject, of + ; object BX + + Mov AX, DI + Cmp BX, 0FFFFh + JE M_FunctionHandler23 + + LES DI, ObjectList ; ES:DI points to object list + Push ES + Pop DS + + Mov [DI], BX ; Object number in BX. + LEA BX, [EBX*2+EDI+6] ; ES:BX points to offset of + ; active object. + + Mov SI, [BX] ; DS:SI points to object + + Mov SI, [SI] ; SI = object type of active obj + ShL SI, 2 + + Push BP + Call DWord Ptr [PostFunctionList+SI] + Pop BP + Jmp M_FunctionHandler23 + +M_KeyBoardInput1: + Call MIDIBufferEmpty + JAE M_FunctionHandler8 + + Call K_IsKeyWaiting + + Test AX, AX + JNZ M_FunctionHandler8 + ; Check for mouse info... + +M_FunctionHandler6: ; IdleList + Cmp CS:ReleaseTimeSlice, 0 + JE NoReleaseTimeSlice + + Mov AX, 1680h + Int 2Fh + +NoReleaseTimeSlice: +; StI + + LDS SI, ObjectList ; DS:SI points to object list + Add SI, 2 ; DS:SI points to idle list + + Cmp Word Ptr [SI], 0 + JE M_FunctionHandler5 ; If Offset of IdleList = 0, + ; check for another key + +M_FunctionHandler7: + Mov SI, [SI] + Xor BX, BX ; Clear flag. + +M_FunctionHandler19: + Cmp Word Ptr [SI], 0 + JNE M_FunctionHandler18 + + Cmp Word Ptr [SI+2], 0 + JE M_FunctionHandler29 + +M_FunctionHandler18: + Push SI + Push BX + Push DS + Push BP + + Call DWord Ptr [SI] + + Pop BP + Pop DS + Pop BX + + Cmp AX, 5 + JE M_FunctionHandlerIdleCommand + + Pop SI + + Add SI, 4 + + Or BX, AX + Jmp M_FunctionHandler19 + +M_FunctionHandlerIdleCommand: + Pop AX ; Pull off SI from the stack + Mov AX, DI + Jmp M_FunctionHandler10 +; Mov SI, 1 +; Jmp M_FunctionHandler16 + +M_FunctionHandler29: + Test BX, BX + JZ M_FunctionHandler5 + + Jmp M_FunctionHandler1 + +M_FunctionHandler8: + Call K_GetKey ; CX = Keyboard Input Data + ; DX = Translated Input Data + ; else MIDI input if CL = 0 + +M_FunctionHandler9: + LES DI, ObjectList ; ES:DI points to object list + Push ES + Pop DS + + Mov BX, [DI] ; BX = active object number + LEA BX, [EDI+EBX*2+6] ; ES:BX points to offset of + ; active object. + Xor AX, AX + + Cmp Word Ptr [BX], 0 + JE M_FunctionHandler23 + +M_FunctionHandler22: + Mov SI, [BX] ; DS:SI points to object + + Mov SI, [SI] ; SI = object type of active obj + ShL SI, 2 + + Push BP + Call DWord Ptr [PostFunctionList+SI] + Pop BP + +M_FunctionHandler23: + Push DS + Push SI + + LDS SI, ObjectList + Add SI, 4 + Mov SI, [SI] + Mov Word Ptr CS:GlobalKeyList+2, DS + Mov Word Ptr CS:GlobalKeyList, SI + + Pop SI + Pop DS + +; Xor BX, BX ; Extra key list starts at 0 + +M_FunctionHandler10: + Cmp AX, 1 + JB M_FunctionHandler11 ; If AX = 0 + JE M_FunctionHandler1 ; Redraw screen if AX = 1 + + Cmp AX, 3 + JB M_FunctionHandler4 ; Goto preobject if AX = 2 + JE M_FunctionHandler5 ; Get next input + + Cmp AX, 5 ; New list + JE M_FunctionHandler16 + JA M_FunctionHandler11 ; If > 5 + + Call MouseRestoreEvents + + Pop BP + Ret 4 + +M_FunctionHandler16: + Mov Word Ptr Offset ObjectList, DX + Mov Word Ptr Offset ObjectList+2, CX + Mov AX, SI + + Jmp M_FunctionHandler10 + +M_FunctionHandler11: + LDS SI, CS:GlobalKeyList + + Cmp Word Ptr [SI], 0 + JE M_FunctionHandler4 + +M_FunctionHandler12: + LodsB + Mov BX, DX + Cmp AL, 1 + JE M_FunctionHandler13 ; Keycode compare (1) + Mov BX, CX + JB M_FunctionHandler13 ; Scancode compare (0) + + And BX, 1FFh + + Cmp AL, 3 + JB M_FunctionHandlerAlt ; Alt-keycode compare (2) + JE M_FunctionHandlerCtrl ; Ctrl-keycode compare (3) + + Cmp AL, 5 + JB M_FunctionHandlerForced ; Always call function (4) + JE M_FunctionHandlerNewListNear ; Chain to new list (5) + + Cmp AL, 7 + JB M_FunctionHandlerShift ; Shift-keycode compare (6) + JE M_FunctionHandlerNewListFar ; Chain to far list (7) + + Cmp AL, 9 + JB M_FunctionHandlerCapCheck ; Capitalised keycode (8) + JE M_FunctionHandlerMIDI ; MIDI message (9) + +; Jmp M_FunctionHandler1 + Jmp M_FunctionHandler4 ; Undefined compare.. +; ; -> end of list + +M_FunctionHandlerAlt: + Test CH, 60h + JZ M_FunctionHandler14 + Jmp M_FunctionHandler13 + +M_FunctionHandlerCtrl: + Test CH, 18h + JZ M_FunctionHandler14 + Jmp M_FunctionHandler13 + +M_FunctionHandlerShift: + Test CH, 6h + JZ M_FunctionHandler14 + Jmp M_FunctionHandler13 + +M_FunctionHandlerNewListNear: + LodsW + Mov Word Ptr CS:GlobalKeyList, AX + Jmp M_FunctionHandler11 + +M_FunctionHandlerNewListFar: + LodsD + Mov CS:GlobalKeyList, EAX + Jmp M_FunctionHandler11 + +M_FunctionHandlerForced: + LodsW + Jmp M_FunctionHandler26 + +M_FunctionHandlerCapCheck: ; Capital OK? (8) + Mov BX, DX + Cmp BX, 'A' + JB M_FunctionHandler14 + Cmp BX, 'z' + JA M_FunctionHandler14 + Cmp BX, 'a' + JB M_FunctionHandlerCapCheck1 + + Sub BL, 32 + +M_FunctionHandlerCapCheck1: + Jmp M_FunctionHandler13 + +M_FunctionHandlerMIDI: + Test CL, CL + JNZ M_FunctionHandler14 + Mov BX, CX + And BX, 0F000h + Jmp M_FunctionHandlerCheck + +M_FunctionHandler13: + Test CL, CL + JZ M_FunctionHandler14 + +M_FunctionHandlerCheck: + LodsW + Cmp BX, AX + JNE M_FunctionHandler14 + +M_FunctionHandler26: + LES DI, ObjectList ; ES:DI points to object list + Push BP + Call DWord Ptr [SI] + Pop BP + Jmp M_FunctionHandler15 + +M_FunctionHandler14: + Xor AX, AX + +M_FunctionHandler15: + Add Word Ptr CS:GlobalKeyList, 7 + Jmp M_FunctionHandler10 + +EndP M_FunctionHandler + +; + +Proc M_Object1ListDefault Far ; Reqs: DI = offset of list + + Mov CX, 0FFFFh + +Proc M_Object1List Far ; Reqs.. CX = inital object. + ; Reqs.. DI = offset of list + + Mov AX, Object1 + Push AX + Mov ES, AX + Push DI + Cmp CX, 0FFFFh + JE M_Object1List1 + + Mov Word Ptr [ES:DI], CX + +M_Object1List1: + Call M_FunctionHandler + + Ret + +EndP M_Object1List +EndP M_Object1ListDefault + +; + +EndS + +; + +End diff --git a/it/IT_MDATA.ASM b/it/IT_MDATA.ASM new file mode 100644 index 0000000..e4e01cc --- /dev/null +++ b/it/IT_MDATA.ASM @@ -0,0 +1,3652 @@ + +; + +Segment SongData PARA Public 'Data' + +Org 0 + + DB "IMPM", 36 Dup (0) + DW 0, 0, 9, 0 + DB 128, 30h, 6, 125, 128, 0 + DW 0, 0, 0, 0, 0 + DB 64 Dup (32), 64 Dup (64), 64 Dup (0) + + DB 256 Dup (0FFh) ; 512 bytes + +; Instrument headers, unrolled simply because TASM runs out of memory otherwise + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 4 Dup (0) + +; Sample headers + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + + + DW 400 Dup (0) + +OffsetCounter = 512 + +Rept 100 + DW OffsetCounter + OffsetCounter = OffsetCounter + 554 +EndM + +Rept 100 + DW OffsetCounter + OffsetCounter = OffsetCounter + 80 +EndM + + DW 65114 + +MIDISampleHeader Label Byte + DB "MIDI", 13 Dup (0), 64, 11h, 64, "MIDI Instrument", 13 Dup (0) + DD 8, 0, 8, 44100, 0, 0 + DW 1 + + DW SongData+4075 + DD 0 + + DB 22 Dup (0) + DW (128+16+9)*32/2 Dup (0) +EndS + +; + +End + diff --git a/it/IT_MMTSR.ASM b/it/IT_MMTSR.ASM new file mode 100644 index 0000000..7aebdcd --- /dev/null +++ b/it/IT_MMTSR.ASM @@ -0,0 +1,1028 @@ +;Ŀ +; MMTSR Module +; + + .386 + +include switch.inc + +;Ŀ +; Externals +; + + Extrn E_AllocateEMS:Far + Extrn E_GetEMSPageFrame:Far + Extrn E_ReleaseEMS:Far + Extrn E_MapEMSMemory:Far + Extrn Music_Stop:Far + +;Ŀ +; Globals +; + + Global MMTSR_InstallMMTSR:Far + Global MMTSR_UninstallMMTSR:Far + +; + +Segment MMTSR PARA Public USE16 'Code' + Assume CS:MMTSR, DS:MMTSR + +CREATENEWLOGFILE EQU 0 +include debug.inc + +;Ŀ +; Variables +; + +MAX8 equ 0f8H ; decompression constants +MAX16 equ 0fff0h + +BBsize equ 0 ; stucture of MMCMP BigBlocks header +BBcmpsize equ 4 ; (relative offset) +BBxorchk equ 8 +BBnblk equ 12 +BBflag equ 14 +BBntab equ 16 +BBsnbit equ 18 +BBheadersize equ 20 + +InstalledFromIT DB 0 + +;Ŀ +; Functions +; + +; + +Proc MMTSR_InstallMMTSR Far + + Push CS + Push CS + Pop DS + Pop ES + + Trace " - Determining if MMTSR is already installed" + + mov ax,4370h + int 21h ; check if already installed + + cmp eax,4352697ah + je @error ; if installed, don't install it again + +@notinstalled: + Trace " - Allocating 64kb of EMS memory for MMTSR decoding" + + StC + Mov EAX, 65536 ; 64k + Call E_AllocateEMS + + Test AX, AX + JZ @error ; AX = handle, 0 if error. + +@emsdriver: + Mov _memhandle, AX + Call E_GetEMSPageFrame + Mov BaseSeg, AX + +@fixups: + Trace " - Installing new INT21h handler" + + mov si,offset _inbuf+2 + mov [si],ax + mov dx,Bufsize + shr dx,4 + add ax,dx + mov [si+4],ax + add ax,20h + mov [si+8],ax + add ax,110h + mov [si+12],ax + add ax,dx + mov [si+16],ax + + mov ax,3521h + int 21h + mov word ptr [_old21],bx ; get old INT 21h handler + mov word ptr [_old21+2],es + mov dx,offset @new21 + mov ax,2521h + int 21h ; set new INT 21h handler + + mov byte ptr [_actived],1 ; MMTSR is ACTIVE! + + Mov InstalledFromIT, 1 + +@error: +@error0: ; print message at offset DS:DX onto screen + Ret + +EndP MMTSR_InstallMMTSR + +; + +Proc MMTSR_UninstallMMTSR Far + + Push CS + Pop DS + + Cmp InstalledFromIT, 0 + JE MMTSR_UninstallMMTSR1 + + Mov DX, Word Ptr [_old21] ; Reset handler. + Mov DS, Word Ptr [_old21+2] + Mov AX, 2521h + Int 21h + + Mov AX, CS:_memhandle + Call E_ReleaseEMS + +MMTSR_UninstallMMTSR1: + Ret + +EndP MMTSR_UninstallMMTSR + +; + + +;**************************************************************************** +; NEW INTERRUPT 21 HANDLER +;**************************************************************************** + +@activate: + and al,1 + mov byte ptr cs:[_actived],al + IRet + +@installcheck: + mov eax,4352697ah + iret +@new21: ; <<<<---------- INT 21 starts here + cmp ax,4370h + je short @installcheck + cmp ax,4371h + je short @activate + cmp ax,4372h + je short @activate + cmp byte ptr cs:[_actived],1 + jne short @noopen ; originaly intercepts 'open' only... + cmp ah,3dh ; now stands for 'do old interrupt' + je short @intercept + cmp ah,3eh ; MMTSR intercepts 'open file' calls, and + jne short @noopen ; close file if the handle is the + cmp bx,cs:_modulehandle ; temporary decompressed module handle + je short @intercept + +@noopen: + jmp dword ptr cs:[_old21] ; Chain to old interrupt + +@intercept: + mov byte ptr cs:[_actived],0 ; desactivate MMTSR while running + mov byte ptr cs:[_function],ah + mov word ptr cs:[_oldstack],sp ; une hook's stack + mov word ptr cs:[_oldstack+2],ss + + pushf + + Call DWord Ptr [CS:_old21] + + push es bx ax + les bx,cs:[_oldstack] ; + pushf ; + pushf ; preserve "returned from interrupt" flags + pop ax ; and set IF!! ;) + or ah,2 ; + mov word ptr es:[bx+4],ax ; + popf ; "or" modifies flags... + pop ax bx es ; + jc @eoi ; I/O error + cmp cs:[_function],3dh + je short @open + + ; close temporary file and delete it +@close: + cmp byte ptr cs:_openedfile,1 + jne @eoi + pusha + push ds + mov ax,cs + mov ds,ax + mov dx,offset _tempfile + mov ah,41h + int 21h + pop ds + popa + mov word ptr cs:[_modulehandle],0 + mov byte ptr cs:[_openedfile],0 + jmp @eoi + + ; open file, create the temporary one, decompress, etc.... +@open: + mov word ptr cs:[_cmphandle],ax + pushad + push ds + push es + push fs + push gs + +;---------------------------------------------------------------------------- +; all registers are preserved +;---------------------------------------------------------------------------- + mov ax,cs + mov ds,ax + mov bp,sp + + mov bx,[_cmphandle] + mov ax,4400h + int 21h + test dx,0080h + jne @nochg ; handle is a DEVICE handle, not a file! + mov bx,[_cmphandle] + mov cx,8 + mov dx,OFFSET _signaturecheck + mov ah,03fh ; read first 8 bytes of the opened file + int 21h + push ax + mov bx,[_cmphandle] + xor edx,edx ; reset file pointer to its beginning + call @lseek + pop ax + cmp ax,8 + jne @nochg + cmp dword ptr _signaturecheck,4352697ah ; + jne @nochg ; check for ziRCONia + cmp dword ptr [_signaturecheck+4],61694e4fh ; + jne @nochg ; + + Call Music_Stop + +@emsswap: + mov dx,_memhandle + Mov AH, 47h + Int 67h + + Mov CX, 4 + Call E_MapEMSMemory + +;------------------ we now have free mem to work --------------------------- +@afterswap: + mov ah,3ch ; + mov cx,20h ; create temporary file + mov dx,offset _tempfile ; + int 21h + jc @swapback + mov word ptr [_modulehandle],ax + mov byte ptr [_openedfile],1 + mov bx,[_cmphandle] + mov edx,8 + call @lseek + push 16 + push ds + push offset _filehead ; read file header, 16 bytes minimum + call @read ; (as for now, 16 bytes max too....) + add sp,6 + mov bx,[_cmphandle] + mov edx,_blockptr + call @lseek + mov ax,_blktoprocess + shl ax,2 ; load the BigBlock offset table into + push ax ; memory + push dword ptr _blkoffset + call @read + add sp,6 + mov word ptr _curblock,0 + +@blockloop: + les di,_blkoffset + add di,_curblock + add word ptr _curblock,4 + mov edx,es:[di] ; + mov bx,_cmphandle ; lseek to next BigBlock + call @lseek + les di,_BB ; es:0 -> current BB + mov di,BBheadersize + push di + push dword ptr [_BB] ; read the BB + call @read ; + add sp,6 + mov ax,es:[BBnblk] ; number of small block within BB + shl ax,3 + push ax + push es + push di + call @read ; read all 'small blocks' info + add sp,6 ; (dw offset, dw size) = 8 bytes each + mov dword ptr _curblkpos,0 ; offset 0 in the first small blk + mov al,es:[BBsnbit] + mov _snbit,al ; snbit: compression info... + test word ptr es:[BBflag],1 + je @notcompressed ; if not compressed, why bother? + +@compressed: + push word ptr es:[BBntab] + push dword ptr _ttabl ; read translation table (cmp stuff...) + call @read + add sp,6 + movzx eax,ax + mov esi,es:[BBcmpsize] ; esi = toread (copmressed size) + sub esi,eax ; - trans table size + xor eax,eax + mov _lasteax,eax ; _lastXXXX: since blocks may be larger + ; than the buffer, small blocks may have + ; to be decompressed in more than one shot. + ; _lastXXX preserve current state of reg. + + mov dword ptr _left,eax ; changes also _lastsmp + mov byte ptr _lastch,al + jmp @compressloopend +@compressloop: + movzx eax,word ptr Bufsize + sub ax,_left + cmp esi,eax ; read the most we can... + jnb short @readbuf + mov eax,esi +@readbuf: + push ax + mov eax,_inbuf + add ax,_left + push eax + call @read ; fill inbuf + add sp,6 + movzx eax,ax + sub esi,eax + add ax,_left + mov _rd,ax ; _rd = number of bytes of data in inbuf + test word ptr es:[BBflag],4 + jne short @16bits + call @Uncompbuf8 ; (inbuf, outbuf, &used) in DS + mov _towrite,ax + call @Translatebuf8 ; (outbuf, towrite) in DS + test word ptr es:[BBflag],2 + je short @nodelta8 + call @Undeltabuf8; (outbuf, towrite, lastbyte) in DS +@nodelta8: + mov cl,8 + jmp short @deltadone +@16bits: + call @UncompBuf16 ; for now, write function is ok even is we have a + mov _towrite,ax ; 16 bits buffer with and odd length. + call @UndeltaBuf16 ; (outbuf, towrite, lastbyte) in DS + xor cl,cl + +@deltadone: + lfs bx,_outbuf + add bx,_towrite + mov ax,fs:[bx-2] + shr ax,cl + mov word ptr _lastsmp,ax ; keep the last sample for future 'undelta' + mov cx,_rd + sub cx,_used + jnb short @leftok + xor cx,cx +@leftok: + mov _left,cx ; inbuf might not have been used up, some is left + je short @writeblock + add cx,3 + shr cx,2 + push ds es si di + les di,_inbuf + mov si,_used ; copy unused part of inbuf to its bottom + add si,di + mov ds,word ptr [_inbuf+2] + rep movsd + pop di si es ds +@writeblock: + call @writeblk ; function to write blocks of data (see it...) +@compressloopend: + movzx eax,word ptr _left + or eax,esi ; is there something left to uncompress? + jne @compressloop + jmp short @blockloopend + + ; this part simply copy the uncompressed buffer from the compressed + ; module to the temp uncompressed module +@notcompressed: + mov esi,es:[BBcmpsize] ; esi = toread +@continuenc: + movzx eax,word ptr Bufsize + cmp esi,eax + jnb short @readubuf + mov ax,si +@readubuf: + push ax + push dword ptr _outbuf + call @read + add sp,6 + mov _towrite,ax + movzx eax,ax + sub esi,eax + call @writeblk + or esi,esi + jne short @continuenc + +@blockloopend: + dec word ptr _blktoprocess ; BigBlocks loop end + jne @blockloop + +; ----------------------------- done decompressing! ------------------------- + mov bx,_modulehandle + mov ah,3eh + int 21h ; close temp file to set file size correctly + mov dx,offset _tempfile + mov ax,3d00h + int 21h ; reeopen it in read only for the Player/tracker + mov _modulehandle,bx + mov [bp+36],bx ; put handle in preserved register + mov ah,3eh + mov bx,_cmphandle + int 21h + +;------------------ swap back memory --------------------------- + +@swapback: +@emsswapback: + mov ah,48h + mov dx,_memhandle + int 67h + +@swapbackdone: +; pop gs ; this part must be used to return +; pop fs ; after somthing has been done when +; pop es ; debugging. +; pop ds +; popad +; lss sp,cs:[_oldstack] +; mov cs:byte ptr [_actived],1 +; iret +;---------------------------------------------------------------------------- +; restore all registers +;---------------------------------------------------------------------------- +@nochg: + pop gs + pop fs + pop es + pop ds + popad +@eoi: +; lss sp,cs:[_oldstack] + mov cs:byte ptr [_actived],1 + iret + +;**************************************************************************** +; I/O ROUTINES +;**************************************************************************** + + ; writes decompressed blocks of data at their respective offsets + ; withing the temp module + ; _towrite = lenght to write + ; _curblkpos = current position relative to beginning of the current + ; small block +@writeblk proc near + push ebp + push si + xor si,si + mov ebp,_curblkpos +@writeloop: + mov edx,es:[di] + add edx,ebp + mov bx,_modulehandle + call @lseek + mov ecx,es:[di+4] + sub ecx,ebp + xor ebx,ebx + mov bx,_towrite + cmp ebx,ecx + jnb short @100 + mov cx,bx +@100:push cx + mov bx,_modulehandle + mov ah,40h + push ds + lds dx,_outbuf + add dx,si + int 21h + pop ds + pop ax + add si,ax + sub _towrite,ax + movzx eax,ax + add ebp,eax + cmp ebp,es:[di+4] + jne short @notblockend + add di,8 + dec word ptr es:[BBnblk] + xor ebp,ebp +@notblockend: + or word ptr _towrite,0 + jz short @writeend + or word ptr es:[BBnblk],0 + jnz short @writeloop +@writeend: + mov _curblkpos,ebp + pop si + pop ebp + ret +@writeblk endp + + ; this reads only from the compressed module! +@read proc near + push bp + +; Mov DX, _memhandle +; Mov CX, 4 +; Call E_MapEMSMemory + + mov bp,sp + mov bx,_cmphandle + push ds + lds dx,[bp+4] + mov cx,[bp+8] + mov ah,3fh + int 21h + pop ds bp + ret +@read endp + +@lseek proc near + shld ecx,edx,16 + mov ax,4200h + int 21h + ret +@lseek endp + +;**************************************************************************** +; ROUTINES TO UNCOMPRESS +;**************************************************************************** + + ; unsigned int Uncompress(char far *ib, char far *ob, word far *used) +@Uncompbuf8 proc near + push bp + mov bp,sp + sub sp,2 + push si + push di + push fs + push es + lfs si,_inbuf + les di,_outbuf + + lea ax,[di-100h] + add ax,Bufsize + mov [bp-2],ax + + mov ch,_lastch ; bit count in eax + mov eax,_lasteax ; eax : data + mov cl,_snbit ; num of bit to use + inc cl + xor bh,bh + xor dx,dx + jmp short @017 + +@012:shrd dx,ax,cl + shr eax,cl + rol dx,cl + sub ch,cl + mov bl,cl +@013:cmp dl,[bx+_bchg8-1] + jb short @016 + shl bx,1 + jmp word ptr [bx+_fct1-2] +@015c:and dl,7 ; 3 bits used + jmp short @011 +@015b:and dl,3 ; 2 bits used, get highest bit + shr eax,1 + rcl dl,1 + sub ch,1 + jmp short @011 +@015a:and dl,1 ; 1 bit used, get 2 highest bits + shl dl,2 + shrd dx,ax,2 + shr eax,2 + rol dx,2 + sub ch,2 + jmp short @011 +@015:xor dl,dl ; no bit used, get 3 bits + shrd dx,ax,3 + shr eax,3 + rol dx,3 + sub ch,3 +@011:shr bx,1 + inc dl + cmp cl,dl + je short @011a + mov cl,dl + jmp short @017 +@011a: ; Special commands (254,255, end); + mov dl,al + shr eax,3 + sub ch,3 + and dl,7 + cmp dl,7 + je short @019 ; maybe end-of-buf command +@016a:add dl,MAX8 +@016:mov es:[di],dl ; Store uncompressed data + inc di + cmp di,[bp-2] + je short @019b + xor dl,dl +@017:cmp ch,10H + jnb short @012 +@018:xchg cl,ch + ror eax,cl + mov ax,fs:[si] + add si,2 + rol eax,cl + add cl,10H + xchg cl,ch + jmp @012 +@019:dec ch + shr eax,1 + jnc @016a ; no only a 255 +@019b: + mov _lastch,ch + mov _lasteax,eax + dec cl + mov _snbit,cl + sub si,word ptr _inbuf + mov _used,si + sub di,word ptr _outbuf + mov ax,di + pop es + pop fs + pop di + pop si + leave + ret +@Uncompbuf8 endp + +; void UndeltaBuf8(void far *buf, unsigned int len, char lastbyte) +@UndeltaBuf8 proc near + push ds + mov cx,_towrite + add cx,3 + and cl,0fch + mov dl,byte ptr _lastsmp + lds bx,_outbuf + add cx,bx +@091:mov eax,[bx] + add al,dl + add ah,al + mov dl,ah + ror eax,16 + add al,dl + add ah,al + mov dl,ah + ror eax,16 + mov [bx],eax + add bx,4 + cmp bx,cx + jne short @091 +@092:pop ds + ret +@UndeltaBuf8 endp + +; void TranslateBuf8(char far *buf, unsigned int len) +@TranslateBuf8 proc near + push es + push ds + push si + push di + mov cx,_towrite + add cx,3 + shr cx,2 + les di,_outbuf + lds si,_ttabl + xor bh,bh +@110: mov eax,es:[di] + mov bl,al + mov al,[bx+si] + mov bl,ah + mov ah,[bx+si] + ror eax,16 + mov bl,al + mov al,[bx+si] + mov bl,ah + mov ah,[bx+si] + ror eax,16 + stosd + dec cx + jne short @110 + pop di + pop si + pop ds + pop es + ret +@TranslateBuf8 endp + +;******************************************************************* +;******************** 16 bits decompression code ******************* + + ; unsigned int Uncompbuf16(char far *ib, char far *ob, CompProcess *CP) +@Uncompbuf16 proc near + push bp + mov bp,sp + sub sp,2 + push si + push di + push fs + push es + lfs si,_inbuf + les di,_outbuf + + lea ax,[di-100h] + add ax,Bufsize + mov [bp-2],ax + + mov ch,_lastch ; bit count in eax + mov eax,_lasteax ; eax : data + mov cl,_snbit ; num of bit to use + + inc cl + xor dx,dx + xor ebx,ebx + jmp @217 + +@212:shrd dx,ax,cl + shr eax,cl + rol dx,cl + sub ch,cl + mov bl,cl + cmp ch,10H + jnb short @213 + xchg cl,ch + ror eax,cl + mov ax,fs:[si] + add si,2 + rol eax,cl + add cl,10H + xchg cl,ch +@213: dd 1b943b67H ;\ + dw (_bchg16-2) ; } cmp dx,[ebx+ebx+_bchg16-2] + dw 0 ;/ + jb @216 + dd 1ba4ff67H ;\ jmp word ptr [ebx+ebx+_fct3-2] still this + dw (_fct3-2) ; } bug with 16 bits labels... + dw 0 ;/ +@215d:and dx,15 ; 4 bits used + jmp short @211 +@215c:and dl,7 ; 3 bits used, get highest bit + shr eax,1 + rcl dl,1 + dec ch + jmp short @211 +@215b:and dl,3 ; 2 bit used, get 2 highest bits + shl dl,2 + shrd dx,ax,2 + shr eax,2 + rol dx,2 + sub ch,2 + jmp short @211 +@215a:and dl,1 ; 1 bit used, get 3 highest bits + shl dl,3 + shrd dx,ax,3 + shr eax,3 + rol dx,3 + sub ch,3 + jmp short @211 +@215:xor dl,dl ; no bit used, get 4 bits + shrd dx,ax,4 + shr eax,4 + rol dx,4 + sub ch,4 +@211:inc dl + cmp cl,dl + je short @211a + mov cl,dl + jmp short @217 +@211a: ; Special commands; + cmp ch,10H + jnb short @216b + xchg cl,ch + ror eax,cl + mov ax,fs:[si] + add si,2 + rol eax,cl + add cl,10H + xchg cl,ch +@216b:mov dl,al + shr eax,4 + sub ch,4 + and dx,15 + cmp dl,15 + je short @219 ; maybe end-of-buf command +@216a:add dx,MAX16 +@216:mov es:[di],dx ; Store uncompressed data + add di,2 + cmp di,[bp-2] + je short @219b + xor dx,dx +@217:cmp ch,10H + jnb @212 +@218:xchg cl,ch + ror eax,cl + mov ax,fs:[si] + add si,2 + rol eax,cl + add cl,10H + xchg cl,ch + jmp @212 +@219:cmp ch,10H + jnb short @219a + xchg cl,ch + ror eax,cl + mov ax,fs:[si] + add si,2 + rol eax,cl + add cl,10H + xchg cl,ch +@219a:dec ch + shr eax,1 + jnc @216a ; no only a 65535 +@219b: + mov _lastch,ch + mov _lasteax,eax + dec cl + mov _snbit,cl + sub si,word ptr _inbuf + mov _used,si + sub di,word ptr _outbuf + mov ax,di + pop es + pop fs + pop di + pop si + leave + ret +@Uncompbuf16 endp + +; void UndeltaBuf16(char far *buf, unsigned int len, CompProcess *CP) +@UndeltaBuf16 proc near + push ds + push si + mov cx,_towrite + add cx,3 + shr cx,2 + mov bx,_lastsmp + lds si,_outbuf + test word ptr es:[BBflag],2 + je short @321 +@320:mov eax,[si] + shr ax,1 + rcr dx,1 + sar dx,15 + xor ax,dx + add ax,bx + mov bx,ax + ror eax,16 + shr ax,1 + rcr dx,1 + sar dx,15 + xor ax,dx + add ax,bx + mov bx,ax + ror eax,16 + mov [si],eax + add si,4 + dec cx + jne short @320 + jmp short @323 +@321:test word ptr es:[BBflag],200h + je short @323 +@322:mov eax,[si] + shr ax,1 + rcr dx,1 + sar dx,15 + xor ax,dx + ror eax,16 + shr ax,1 + rcr dx,1 + sar dx,15 + xor ax,dx + ror eax,16 + mov [si],eax + add si,4 + dec cx + jne short @322 +@323:pop si + pop ds + mov word ptr _lastsmp,bx + ret +@UndeltaBuf16 endp + +;******************************************************************* +;******************** 8 bits decompression data ******************** +_bchg8 label byte + db 01H + db 03H + db 07H + db 0fH + db 1eH + db 3cH + db 78H + db 0f8H +EVEN +_fct1 label word + dw @015 + dw @015 + dw @015 + dw @015 + dw @015a + dw @015b + dw @015c + dw @015c +;******************************************************************* +;********************* 16 bits compression data ******************** +_bchg16 label word + dw 00001H ;1 + dw 00003H ;2 + dw 00007H ;3 + dw 0000fH ;4 + dw 0001eH ;5 + dw 0003cH ;6 + dw 00078H ;7 + dw 000f0H ;8 + dw 001f0H ;9 + dw 003f0H ;10 + dw 007f0H ;11 + dw 00ff0H ;12 + dw 01ff0H ;13 + dw 03ff0H ;14 + dw 07ff0H ;15 + dw 0fff0H ;16 + +_fct3 label word + dw @215 + dw @215 + dw @215 + dw @215 + dw @215a + dw @215b + dw @215c + dw @215d + dw @215d + dw @215d + dw @215d + dw @215d + dw @215d + dw @215d + dw @215d + dw @215d + +@settings: +align 4 +BaseSeg dw 08000h +Bufsize dw 06E00h ; 0b000h or anything else for XMS... + +_inbuf dd 0 ; size: Bufsize ; Basemem +_ttabl dd 0 ; size: 200h ; Basemem + Bufsize +_BB dd 0 ; size: 1100h ; Basemem + Bufsize + 200h +_outbuf dd 0 ; size: Bufsize ; Basemem + Bufsize + 1300h +_blkoffset dd 0 ; size: 2000h ; Basemem + 2*Bufsize + 1300h + +_tempfile db 'C:\_~zirc~_.tmp',0,0,0,0,0,0,0,0 ; 23 b + NULL (24 b) + +_old21 dd 0 +_driver dd 0 +_oldstack dd 0 +_memhandle dw 0 +_actived db 0 +_openedfile db 0 +_function db 0 + +_signaturecheck label qword +_filehead: + _headersize dw 0 + _version dw 0 + _blktoprocess dw 0 + _unpacklen dd 0 + _blockptr dd 0 + _dummy dw 0 + +_cmphandle dw 0 +_modulehandle dw 0 + +_lasteax dd 0 +_left dw 0 +_lastsmp dw 0 +_lastch db 0 + +_curblock dw 0 +_curblkpos dd 0 +_towrite dw 0 +_rd dw 0 +_used dw 0 +_snbit db 0 + +align 2 + +EndS + +; + +; + +EndS + +; + +End diff --git a/it/IT_MOUSE.ASM b/it/IT_MOUSE.ASM new file mode 100644 index 0000000..d58a965 --- /dev/null +++ b/it/IT_MOUSE.ASM @@ -0,0 +1,1412 @@ +;Ŀ +; Mouse Module +; + + Jumps + .386P + +; MouseRecord Structure... +; Area DW Left, Top, Right, Bottom +; Condition DB ? +; Flags DB ? +; ObjectNumber DW ? +; Function DD DWord FunctionPtr +; +; Condition bits +; Bit 0: Mouse moved +; Bit 1: Left button pressed +; Bit 2: Left button held +; Bit 3: Left button released +; Bit 4: Right button pressed +; Bit 5: Right button held +; Bit 6: Right button released +; +; Flags +; Bit 0-1: Condition test +; 0 = equal +; 1 = result when ANDed +; 2, 3 = reserved +; Bit 2: NOT of condition test +; Bit 3: Off - Cursor within area +; On - Cursor outside area +; Bit 4: Always call, ignore area + +include switch.inc + +;Ŀ +; Externals +; + + Extrn S_SetSequencer:Far, S_ResetSequencer:Far + Extrn S_SetDirectMode:Far + Extrn S_GetDestination:Far + +;Ŀ +; Globals +; + + Global InitMouse:Far, UnInitMouse:Far + Global MouseCharacterGenerationOffset:Word + Global RestoreMouse:Far, DrawMouse:Far + Global MouseSecondSetEnable:Far, MouseSecondSetDisable:Far + Global RestoreMouseGraphics:Far, MouseToggle:Far + Global MouseInput:Far, AddMouseQueue:Far + Global SetKeyboardLock:Far, GetKeyboardLock:Far + Global MouseSaveEvents:Far, MouseRestoreEvents:Far + Global MouseAddEvent:Far, MouseClearEvents:Far + Global MouseRemoveEvents:Far, MouseSetXY:Far + Global MouseGetStatus:Far, NewCharacterSet:Far + Global MouseUpdateEnable:Far, MouseUpdateDisable:Far + Global SetMouseCursorType:Far, CmdLineDisableMouse:Far + Global ForceMouseRestore:Far + +; + +Segment Mouse PARA Public 'Code' USE16 + Assume CS:Mouse, DS:Nothing + +CREATENEWLOGFILE EQU 0 +include debug.inc + + ; Assumes 80x50 display (512 characters, 8x8 pixels per char.) + +;Ŀ +; Variables +; + +STARTINGCHARACTER EQU 247 ; Use last 9 characters +QUEUEELEMENTSIZE EQU 8 +MAXXPIXEL EQU 639 +MAXYPIXEL EQU 399 + +MouseCharacterGenerationOffset DW 512*32 +MouseAvailable DB 0 +MouseDisplay DB 1 +MouseEnabled DB 1 + +MouseCursorType DW 0 + +MouseCursorOffset DW 0 +MouseCursorWidth DB 0 +MouseCursorHeight DB 0 + +NewMouseX DW 40*8 +NewMouseY DW 30*8 +MouseX DW 40*8 +MouseY DW 30*8 +MouseXHotSpot DW 0 +MouseYHotSpot DW 0 + +OldCharacterData DW 9 Dup (0) +Label EndOldCharacterData +CharacterTypes DW 247, 248, 249, 250, 251, 252, 253, 254, 255 + +OldBitmapData DB 9*8 Dup (0) +NewBitmapData DB 24*4 Dup (0) + +OverWriteSecondSet DB 1 +RestoreGraphicsRequired DB 0 +LockKeyBoard DB 0 +UpdateScreen DB 0 + +MouseCursorHotSpot Label + DB 0, 0 + DB 4, 3 +; DB 8, 16 + +MouseCursorTypes Label + DW Offset MouseCursorArrow + DW Offset MouseCursorCrossHairs +; DW Offset MouseCursorDownArrow + +Label MouseCursorArrow + DW 0011111111111111b, 0000000000000000b + DW 0001111111111111b, 0100000000000000b + DW 0000111111111111b, 0110000000000000b + DW 0000011111111111b, 0111000000000000b + DW 0000001111111111b, 0111100000000000b + DW 0000000111111111b, 0111110000000000b + DW 0000000011111111b, 0111111000000000b + DW 0000000001111111b, 0111111100000000b + DW 0000000000111111b, 0111111110000000b + DW 0000000001111111b, 0111111100000000b + DW 0000000111111111b, 0111110000000000b + DW 0000000011111111b, 0100011000000000b + DW 1011000011111111b, 0000011000000000b + DW 1111100001111111b, 0000001100000000b + DW 1111100001111111b, 0000001100000000b + DW 1111110011111111b, 0000000000000000b + +Label MouseCursorCrossHairs + DW 1111111111111111b, 0000000000000000b + DW 1111011111111111b, 0000000000000000b + DW 1100000111111111b, 0000100000000000b + DW 1000000011111111b, 0011111000000000b + DW 1100000111111111b, 0000100000000000b + DW 1111011111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + DW 1111111111111111b, 0000000000000000b + + Comment ~ + +Label MouseCursorDownArrow + DW 1111111111111111b, 0000000000000000b + DW 1111000000001111b, 0000000000000000b + DW 1111000000001111b, 0000011111100000b + DW 1111000000001111b, 0000011111100000b + DW 1111000000001111b, 0000011111100000b + DW 1111000000001111b, 0000011111100000b + DW 1111000000001111b, 0000011111100000b + DW 0000000000000000b, 0000011111100000b + DW 0000000000000000b, 0111111111111110b + DW 1000000000000001b, 0011111111111100b + DW 1100000000000011b, 0001111111111000b + DW 1110000000000111b, 0000111111110000b + DW 1111000000001111b, 0000011111100000b + DW 1111100000011111b, 0000001111000000b + DW 1111110000111111b, 0000000110000000b + DW 1111111001111111b, 0000000000000000b + + ~ + +MouseEvents DB 100 * 16 Dup (0) +MouseEventStack DW 8 Dup (0) +MouseEventStackPointer DW 0 +MouseEventStart DW Offset MouseEvents +MouseEventEnd DW Offset MouseEvents + +MouseStatus DB 0 ; Same as conditions... + +MouseQueue DW 128 Dup (0) +MouseQueueStart DB 0 +MouseQueueEnd DB 0 + +;Ŀ +; Functions +; + +; + +Proc RestoreMouse Far + + Push CS + Pop DS + Assume DS:Mouse + + Cmp MouseDisplay, 0 + JE RestoreMouse1 + + Call RemoveMouseCursor + +RestoreMouse1: + Ret + +EndP RestoreMouse + Assume DS:Nothing + +; + +Proc RemoveMouseCursor ; Given ES=cursor to remove + + Assume DS:Mouse + Mov BX, Offset OldCharacterData + Mov DI, MouseCursorOffset + + + Mov DX, Word Ptr MouseCursorWidth + Test DH, DH + JZ RemoveMouseCursor3 + Test DL, DL + JZ RemoveMouseCursor3 + + Mov CL, STARTINGCHARACTER + +RemoveMouseCursor1: + Push CX + Push BX + Push DI + Mov DL, MouseCursorWidth + +RemoveMouseCursor2: + Mov AX, [BX] + Test AH, 8 + JNZ RemoveMouseCursor4 + + Cmp [ES:DI], CL + JNE RemoveMouseCursor8 + Mov [ES:DI], AX + Jmp RemoveMouseCursor8 + +RemoveMouseCursor4: + Or RestoreGraphicsRequired, 1 + +RemoveMouseCursor8: +; Add DI, 2 + ScasW + Add BX, 2 + Inc CX + Dec DL + JNZ RemoveMouseCursor2 + + Pop DI + Pop BX + Pop CX + + Add CL, 3 + Add BX, 6 + Add DI, 160 + + Dec DH + JNZ RemoveMouseCursor1 + +RemoveMouseCursor3: + Ret + +EndP RemoveMouseCursor + Assume DS:Nothing + +; + +Proc RestoreMouseGraphics Far + + Push CS + Pop DS + Assume DS:Mouse + + Mov AL, RestoreGraphicsRequired + Cmp MouseDisplay, 0 + JE RestoreMouseGraphics4 + Cmp OverWriteSecondSet, 1 + JE RestoreMouseGraphics4 + Test AL, 10 + JNZ RestoreMouseGraphics4 + Test AL, 4 + JZ RestoreMouseGraphics4 + + Or RestoreGraphicsRequired, 8 + Test AL, 1 + JZ RestoreMouseGraphics4 + + Call S_SetSequencer + + Mov AX, 0A000h + Mov ES, AX + + Xor BX, BX + Mov DH, MouseCursorHeight + Test DH, DH + JZ RestoreMouseGraphics4 + +RestoreMouseGraphics1: + Push BX + Mov DL, MouseCursorWidth + +RestoreMouseGraphics2: + Mov AX, [OldCharacterData+BX] + Test AH, 8 + JZ RestoreMouseGraphics3 + + ; AL = character in extended set. + And AX, 0FFh + Mov DI, AX + Mov SI, BX + ShL DI, 5 + ShL SI, 2 ; DS:SI points to OldBitMap table + Add SI, Offset OldBitMapData + Add DI, MouseCharacterGenerationOffset + ; ES:DI points to output table + + Mov CX, 8 + Rep MovsB + +RestoreMouseGraphics3: + Add BX, 2 + Dec DL + JNZ RestoreMouseGraphics2 + + Pop BX + Add BX, 6 + + Dec DH + JNZ RestoreMouseGraphics1 + + Call S_ResetSequencer + +RestoreMouseGraphics4: + Ret + +EndP RestoreMouseGraphics + Assume DS:Nothing + +; + +Proc SaveMouseCursor + Assume DS:Mouse + + Push CS ; *** + Pop DS ; *** + + PushF + ClI + Mov SI, NewMouseX + Mov AX, NewMouseY + PopF + + Mov MouseX, SI + Mov MouseY, AX + + +; Mov AX, MouseY + ShR AX, 3 + + Mov DX, 50 + Sub DX, AX ; CX = height + + Cmp DX, 3 + JB SaveMouseCursor1 + + Mov DL, 3 + +SaveMouseCursor1: + Mov MouseCursorHeight, DL + + Mov BL, 160 + Mul BL +; Mov SI, MouseX + ShR SI, 3 + + Mov CX, 80 + Sub CX, SI + Cmp CX, 3 + JB SaveMouseCursor2 + + Mov CL, 3 + +SaveMouseCursor2: + Add SI, SI + Mov MouseCursorWidth, CL + + Add SI, AX + Mov MouseCursorOffset, SI + Mov DI, Offset OldCharacterData + Xor EAX, EAX + + Mov DWord Ptr [DI], EAX ; Clear buffer first. + Mov DWord Ptr [DI+4], EAX + Mov DWord Ptr [DI+8], EAX + Mov DWord Ptr [DI+12], EAX + Mov Word Ptr [DI+16], AX + +SaveMouseCursor3: + Push DI + Push SI + Push CX + +SaveMouseCursor4: + Mov AX, [ES:SI] + Mov [DI], AX + + Add SI, 2 +; Add DI, 2 + ScasW + Dec CX + JNZ SaveMouseCursor4 + + Pop CX + Pop SI + Pop DI + Add SI, 160 + Add DI, 6 + + Dec DX + JNZ SaveMouseCursor3 + + ; Now get bitmap data... + + Call S_SetSequencer + + Push ES + + Mov AX, 0A000h + Mov ES, AX + + Mov BX, Offset OldCharacterData + Mov DI, Offset OldBitmapData + +SaveMouseCursor5: + Mov AX, [BX] + Mov SI, AX + And SI, 0FFh + ShL SI, 5 + Test AH, 8 + JZ SaveMouseCursor6 + + Mov AL, RestoreGraphicsRequired + Test AL, 1 + JZ SaveMouseCursor8 + Test AL, 10 + JZ SaveMouseCursor7 ; JNZ 8 +; Test AL, 4 +; JZ SaveMouseCursor7 + +SaveMouseCursor8: + Add SI, MouseCharacterGenerationOffset + +SaveMouseCursor6: + Mov EAX, [ES:SI] + Mov [DI], EAX + Mov EAX, [ES:SI+4] + Mov [DI+4], EAX + +SaveMouseCursor7: + Add DI, 8 + Add BX, 2 + Cmp BX, Offset EndOldCharacterData + JB SaveMouseCursor5 + + Pop ES + + Test RestoreGraphicsRequired, 10 + JZ SaveMouseCursor9 + + And RestoreGraphicsRequired, Not 14 + +SaveMouseCursor9: + Ret + +EndP SaveMouseCursor + Assume DS:Nothing + +; + +Proc GenerateMouseCursor + Assume DS:Mouse + +; Push CS ; *** +; Pop DS ; *** + + ; Has to work out new table and write chars + Mov SI, Offset OldBitMapData + Mov DI, Offset NewBitMapData + Mov DX, 3 + +GenerateMouseCursor1: + Mov CX, 8 + +GenerateMouseCursor2: +; Mov Byte Ptr [DI], 0 + Mov AL, [SI+16] + Mov [DI+1], AL + Mov AL, [SI+8] + Mov [DI+2], AL + Mov AL, [SI] + Mov [DI+3], AL + + Inc SI + Add DI, 4 + Loop GenerateMouseCursor2 + + Add SI, 16 + + Dec DX + JNZ GenerateMouseCursor1 + + Mov BX, MouseX + And BX, 7 ; CX = MouseX % 8 + Mov CX, 8 + Sub CX, BX + Mov EDX, 0FF000000h + ShL EDX, CL ; EDX = 0FF000000h << (8 - shift); + Mov CX, BX + + Mov SI, MouseCursorType +; Add SI, SI + Mov SI, [MouseCursorTypes+SI] + ; DS:SI points to masks. + Mov DI, MouseY + And DI, 7 + ShL DI, 2 + Add DI, Offset NewBitMapData + + Mov BX, 16 ; Cursor height = 16 + +GenerateMouseCharacter3: + Mov AX, [SI] + ShL EAX, 16 + Mov AX, 0FFFFh + RCR EAX, CL + Or EAX, EDX + And [DI], EAX + + Mov AX, [SI+2] + ShL EAX, 16 + ShR EAX, CL + Or [DI], EAX + + Add SI, 4 + Add DI, 4 + Dec BX + JNZ GenerateMouseCharacter3 + + ; Lets write the characters! + + Push ES + Mov AX, 0A000h + Mov ES, AX + + Mov BX, Offset OldCharacterData + Mov SI, Offset NewBitmapData+3 + + Mov DL, 3 + +GenerateMouseCharacter7: + Mov DH, 3 + +GenerateMouseCharacter4: + Mov AX, [BX] + ; Get DI = char to write to... + Test AH, 8 + JZ GenerateMouseCharacter5 + + Cmp OverWriteSecondSet, 0 + JNE GenerateMouseCharacter6 + + And AX, 0FFh + ShL AX, 5 + Add AX, MouseCharacterGenerationOffset + Mov DI, AX + Jmp GenerateMouseCharacter9 + +GenerateMouseCharacter5: + Mov AX, [BX+18] + ShL AX, 5 + Mov DI, AX + +GenerateMouseCharacter9: + ; ES:DI points to character map memory + + Mov CX, 8 + Push SI + +GenerateMouseCharacter8: + MovsB + Add SI, 3 + +; Mov AL, [SI] +; StosB + Loop GenerateMouseCharacter8 + + Pop SI + +GenerateMouseCharacter6: + Dec SI +; Inc SI + + Add BX, 2 + Dec DH + JNZ GenerateMouseCharacter4 + + Add SI, 35 +; Add SI, 32-3 + + Dec DL + JNZ GenerateMouseCharacter7 + + Cmp BX, Offset EndOldCharacterData + JB GenerateMouseCharacter4 + + + Pop ES + + Ret + +EndP GenerateMouseCursor + Assume DS:Nothing + +; + +Proc PlotMouseCursor + Assume DS:Mouse + + Push CS ; *** + Pop DS ; *** + + Mov DH, MouseCursorHeight + And DH, DH + JZ PlotMouseCursor4 + + Mov AL, STARTINGCHARACTER + Mov BX, MouseCursorOffset + +PlotMouseCursor1: + Push AX + Push BX + + Mov DL, MouseCursorWidth + +PlotMouseCursor2: + Test Word Ptr [ES:BX], 800h + JNZ PlotMouseCursor3 + + Mov [ES:BX], AL + +PlotMouseCursor3: + Inc AX + Add BX, 2 + Dec DL + JNZ PlotMouseCursor2 + + Pop BX + Pop AX + Add BX, 160 + Add AX, 3 + + Dec DH + JNZ PlotMouseCursor1 + +PlotMouseCursor4: + Ret + +EndP PlotMouseCursor + Assume DS:Nothing + +; + +Proc DrawMouseCursor ; Given ES to write to. + + Call SaveMouseCursor + Call GenerateMouseCursor + + Call S_ResetSequencer + + ; Write block... + Call PlotMouseCursor + + Ret + +EndP DrawMouseCursor + +; + +Proc DrawMouse Far + + Push CS + Pop DS + Assume DS:Mouse + + Cmp MouseDisplay, 0 + JE DrawMouse1 + + Call DrawMouseCursor + +DrawMouse1: + Ret + +EndP DrawMouse + Assume DS:Nothing + +; + +Proc MouseInterruptHandler Far + + PushF + + ClI + CLD + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Mouse + + Mov NewMouseX, CX + Mov NewMouseY, DX + + Xor BH, BH ; BH = new status. + Mov BL, MouseStatus + + Test AL, 1 ; Mouse moved + JZ MIH1 + + Or BH, 1 + Or RestoreGraphicsRequired, 4 + +MIH1: + Test AL, 2 ; Left pressed + JZ MIH2 + + Or BH, 2 + Jmp MIH4 + +MIH2: + Test AL, 4 + JZ MIH3 + + Or BH, 8 + Jmp MIH4 + +MIH3: + Test BL, 6 ; If last status had press or + JZ MIH4 ; held... + + Or BH, 4 ; Set held + +MIH4: + Test AL, 8 ; Left pressed + JZ MIH5 + + Or BH, 10h + Jmp MIH7 + +MIH5: + Test AL, 10h + JZ MIH6 + + Or BH, 40h + Jmp MIH7 + +MIH6: + Test BL, 30h ; If last status had press or + JZ MIH7 ; held... + + Or BH, 20h ; Set held + +MIH7: + + Mov MouseStatus, BH + + Cmp MouseDisplay, 0 + JE MouseInterruptHandler1 + + Mov SI, MouseEventStart + + Cmp UpdateScreen, 0 + JE NoUpdateCursor + + Test BH, 1 ; Moved? + JZ NoUpdateCursor + + PushAD + Mov AX, 0B800h + Mov ES, AX + Push ES + Call RemoveMouseCursor + Call RestoreMouseGraphics + Pop ES + Call DrawMouseCursor + PopAD + +NoUpdateCursor: + Add CX, MouseXHotSpot + Add DX, MouseYHotSpot + +MouseInterruptHandler2: ; BH = status + Cmp SI, MouseEventEnd + JAE MouseInterruptHandler1 + Mov AX, [SI+8] ; AH = flags, AL = conditions + ; AH: Bit 0-1 = test case + ; 0 = equal + ; 1 = result when and + ; Bit 2: NOT of test case + ; Bit 3: Inside/outside area + ; Bit 4: Ignore area + Test AH, 10h + JNZ MouseCheckCondition + + Cmp CX, [SI] + JB MouseAreaOutside1 + Cmp CX, [SI+4] + JA MouseAreaOutside1 + Cmp DX, [SI+2] + JB MouseAreaOutside1 + Cmp DX, [SI+6] + JA MouseAreaOutside1 + + Test AH, 8 + JZ MouseCheckCondition + Jmp MouseInterruptHandler3 + +MouseAreaOutside1: + Test AH, 8 + JZ MouseInterruptHandler3 + +MouseCheckCondition: + And AH, 7 + Cmp AH, 1 + JB MouseCheckCondition0 + JE MouseCheckCondition1 + + Cmp AH, 5 + JB MouseCheckCondition4 + JE MouseCheckCondition5 + Jmp MouseInterruptHandler3 + +MouseCheckCondition0: + Cmp AL, BH + JE MouseEventOK + Jmp MouseInterruptHandler3 + +MouseCheckCondition1: + Test AL, BH + JNZ MouseEventOK + Jmp MouseInterruptHandler3 + +MouseCheckCondition4: + Cmp AL, BH + JNE MouseEventOK + Jmp MouseInterruptHandler3 + +MouseCheckCondition5: + Test AL, BH + JNZ MouseInterruptHandler3 +; JZ MouseEventOK +; Jmp MouseInterruptHandler3 + +MouseEventOK: ; Call function! + Mov AX, [SI+10] + Call DWord Ptr [SI+12] + And AX, AX + JZ MouseInterruptHandler1 + +MouseInterruptHandler3: + Add SI, 16 + Jmp MouseInterruptHandler2 + +MouseInterruptHandler1: + Pop ES + Pop DS + PopAD + PopF + + Ret + +EndP MouseInterruptHandler + Assume DS:Nothing + +; + +Proc InitMouse Far + + Cmp CS:MouseEnabled, 0 + JE InitMouse2 + + Trace " - Determining mouse availability" + + Xor AX, AX + Mov ES, AX + + Mov Byte Ptr [ES:449h], 6 ; 'Setting' display mode + + Int 33h + + Cmp AX, -1 + JE InitMouse1 + + Mov MouseDisplay, 0 + +InitMouse2: + Ret + +InitMouse1: + Trace " - Setting Mouse extents" + + Mov MouseAvailable, 1 + + Xor CX, CX ; X Limits + Mov DX, MAXXPIXEL + Mov AX, 7 + Int 33h + + Xor CX, CX ; Y Limits + Mov DX, MAXYPIXEL + Mov AX, 8 + Int 33h + + Mov CX, MouseX + Mov DX, MouseY + Call MouseSetXY + + Trace " - Installing mouse handler" + + Push CS + Pop ES + Mov CX, 1Fh ; Call on mouse move + ; left button press, release. + ; right button press, release. + ; Ignores central button (if any) + Mov DX, Offset MouseInterruptHandler + Mov AX, 0Ch + Int 33h + + Ret + +EndP InitMouse + +; + +Proc UnInitMouse Far + + Xor AX, AX + Int 33h + + Ret + +EndP UnInitMouse + +; + +Proc MouseSecondSetEnable Far + + Mov CS:OverwriteSecondSet, 0 + Ret + +EndP MouseSecondSetEnable + +; + +Proc MouseSecondSetDisable Far + + Mov CS:OverwriteSecondSet, 1 + Ret + +EndP MouseSecondSetDisable + +; + +Proc MouseToggle Far + + Push CS + Pop DS + Assume DS:Mouse + + Cmp MouseAvailable, 0 + JE MouseToggle1 + + Xor MouseDisplay, 1 + JNZ MouseToggle1 + + Mov AX, 0B800h + Mov ES, AX + Call RemoveMouseCursor + Mov MouseDisplay, 1 + Or RestoreGraphicsRequired, 4 + Call RestoreMouseGraphics + Mov MouseDisplay, 0 + +MouseToggle1: + Mov AX, 1 + Ret + +EndP MouseToggle + Assume DS:Nothing + +; + +Proc MouseSetXY Far + + PushF + + Mov NewMouseX, CX + Mov NewMouseY, DX + + Cmp CS:MouseAvailable, 0 + JE MouseSetXY1 + + ClI + + Mov AX, 4 + Int 33h + + Sub CX, MouseXHotSpot + JNS MouseSetXY2 + + Xor CX, CX + +MouseSetXY2: + Sub DX, MouseYHotSpot + JNS MouseSetXY3 + + Xor DX, DX + +MouseSetXY3: + Cmp CX, MAXXPIXEL + JB MouseSetXY4 + + Mov CX, MAXXPIXEL + +MouseSetXY4: + Cmp DX, MAXYPIXEL + JB MouseSetXY5 + + Mov DX, MAXYPIXEL + +MouseSetXY5: + Mov MouseX, CX + Mov MouseY, DX + + Or CS:RestoreGraphicsRequired, 4 + +MouseSetXY1: + PopF + + Ret + +EndP MouseSetXY + +; + +Proc MouseSaveEvents Far + + PushF + Push DS + + Push CS + Pop DS + Assume DS:Mouse + + Cmp MouseAvailable, 0 + JE MouseSaveEvents1 + + ClI + + Mov AX, MouseEventStart + Mov SI, MouseEventStackPointer + Mov [MouseEventStack+SI], AX + Add MouseEventStackPointer, 2 + + Mov AX, MouseEventEnd + Mov MouseEventStart, AX + +MouseSaveEvents1: + Pop DS + PopF + + Ret + +EndP MouseSaveEvents + Assume DS:Nothing + +; + +Proc MouseRestoreEvents Far + + PushF + Push DS + + Push CS + Pop DS + Assume DS:Mouse + + Cmp MouseAvailable, 0 + JE MouseRestoreEvents1 + + ClI + + Mov AX, MouseEventStart + Mov MouseEventEnd, AX + + Sub MouseEventStackPointer, 2 + Mov SI, MouseEventStackPointer + Mov AX, [MouseEventStack+SI] + Mov MouseEventStart, AX + +MouseRestoreEvents1: + Pop DS + PopF + + Ret + +EndP MouseRestoreEvents + Assume DS:Nothing + +; + +Proc SetKeyboardLock Far ; AL = lock state + + Mov CS:LockKeyBoard, AL + Ret + +EndP SetKeyboardLock + +; + +Proc GetKeyboardLock Far + + Mov AL, CS:LockKeyBoard + Ret + +EndP GetKeyboardLock + +; + +Proc AddMouseQueue Far ; AX, CX, DX + + Push DS + + Push CS + Pop DS + Assume DS:Mouse + + Mov BH, QUEUEELEMENTSIZE + Mov BL, MouseQueueEnd + Add BH, BL + Cmp BH, MouseQueueStart + JE AddMouseQueue1 ; No space left on queue. + + Mov MouseQueueEnd, BH + And BX, 0FFh + Mov [MouseQueue+BX], AX + Mov [MouseQueue+BX+2], CX + Mov [MouseQueue+BX+4], DX + Mov [MouseQueue+BX+6], DI + +AddMouseQueue1: + Pop DS + Ret + +EndP AddMouseQueue + Assume DS:Nothing + +; + +Proc MouseInput Far + + PushF + + Push CS + Pop DS + Assume DS:Mouse + + ClI + + Cmp MouseDisplay, 0 + JE MouseInput1 + + Mov CL, MouseQueueEnd + Mov BL, MouseQueueStart + Sub CL, BL + JNZ MouseInput2 + + Cmp LockKeyBoard, 0 + JE MouseInput1 + + Mov AX, 2 + PopF + Ret + +MouseInput1: + Mov AX, 0 + PopF + Ret + +MouseInput2: + And BX, 0FFh + Mov SI, BX + + Add MouseQueueStart, QUEUEELEMENTSIZE + +MouseInput3: + Mov BX, [MouseQueue+SI] + Mov CX, [MouseQueue+SI+2] + Mov DX, [MouseQueue+SI+4] + Mov DI, [MouseQueue+SI+6] + + Mov AX, 1 + PopF + Ret + +EndP MouseInput + Assume DS:Nothing + +; + +Proc MouseAddEvent Far ; Given DS:SI to event + + PushF + + Cmp CS:MouseAvailable, 0 + JE MouseAddEvent1 + + Push SI + Push ES + Push DI + + ClI + CLD + + Push CS + Pop ES + Mov DI, CS:MouseEventEnd + + Mov CX, 8 + Rep MovsW + + Mov CS:MouseEventEnd, DI + + Pop DI + Pop ES + Pop SI + +MouseAddEvent1: + PopF + Ret + +EndP MouseAddEvent + +; + +Proc MouseClearEvents Far + + Mov AX, CS:MouseEventStart + Mov CS:MouseEventEnd, AX + Ret + +EndP MouseClearEvents + +; + +Proc MouseRemoveEvents Far ; AX = number to remove + + ShL AX, 4 + Sub CS:MouseEventEnd, AX + Ret + +EndP MouseRemoveEvents + +; + +Proc MouseGetStatus Far + + Mov AL, CS:MouseStatus + Ret + +EndP MouseGetStatus + +; + +Proc NewCharacterSet Far + + Or CS:RestoreGraphicsRequired, 2 + Ret + +EndP NewCharacterSet + +; + +Proc MouseUpdateEnable Far + + Mov CS:UpdateScreen, 1 + Ret + +EndP MouseUpdateEnable + +; + +Proc MouseUpdateDisable Far + + Mov CS:UpdateScreen, 0 + Ret + +EndP MouseUpdateDisable + +; + +Proc SetMouseCursorType Far + + PushF + Push DS + + Push CS + Pop DS + Assume DS:Mouse + ClI + + Mov MouseCursorType, BX + Mov AX, [MouseCursorHotSpot+BX] + Mov CX, MouseX + Mov DX, MouseY + + Add CX, MouseXHotSpot + Add DX, MouseYHotSpot + + Mov Byte Ptr MouseXHotSpot, AL + Mov Byte Ptr MouseYHotSpot, AH + + Sub CX, MouseXHotSpot + JNS SetMouseCursorType1 + + Xor CX, CX + +SetMouseCursorType1: + Sub DX, MouseYHotSpot + JNS SetMouseCursorType2 + + Xor DX, DX + +SetMouseCursorType2: + Cmp CX, MAXXPIXEL + JB SetMouseCursorType3 + + Mov CX, MAXXPIXEL + +SetMouseCursorType3: + Cmp DX, MAXYPIXEL + JB SetMouseCursorType4 + + Mov DX, MAXYPIXEL + +SetMouseCursorType4: +; Mov NewMouseX, CX +; Mov NewMouseY, DX + + Call MouseSetXY + + Pop DS + PopF + Ret + +EndP SetMouseCursorType + +; + +Proc CmdLineDisableMouse Far + + Mov Word Ptr CS:MouseDisplay, 0 + Ret + +EndP CmdLineDisableMouse + +; + +Proc ForceMouseRestore Far + + Call MouseUpdateDisable + ClI + Call RestoreMouse + Or RestoreGraphicsRequired, 4 + Call RestoreMouseGraphics + StI + Jmp MouseUpdateEnable + +EndP ForceMouseRestore + +; + +; + +EndS + +; + +End diff --git a/it/IT_MSG.ASM b/it/IT_MSG.ASM new file mode 100644 index 0000000..8b25efd --- /dev/null +++ b/it/IT_MSG.ASM @@ -0,0 +1,1031 @@ +;Ŀ +; Message Module +; + + .386 + Jumps + +;Ŀ +; Externals +; + + Extrn M_FunctionDivider:Far + Extrn M_Object1List:Far + Extrn S_GetDestination:Far + Extrn O1_LongMessageList:Far + Extrn O1_ConfirmClearMessage:Far + +;Ŀ +; Globals +; + + Global Msg_ResetMessage:Far + Global Msg_DrawMessage:Far + Global Msg_PreMessage:Far + Global Msg_PostMessage:Far + Global Msg_GetMessageLength:Far + Global Msg_GetMessageOffset:Far + +; + +Segment Message BYTE Public 'Code' USE16 + Assume CS:Message, DS:Nothing + +;Ŀ +; Variables +; + +MESSAGELENGTH Equ 8000 + +TopLine DW 0 +CurrentPosition DW 0 +MessageData DB MESSAGELENGTH Dup (0) + DW 0 ; Security +MessageDataTerminator DB 0 +Edit DB 0 ; if Edit=1, show '' for enter. +HorizontalPosition DW 0 +CurrentLine DW 0 +CharacterColour DB 12 + +NoEditKeys Label + DB 0 + DW 1C8h ; Up arrow + DW Msg_ViewMsgUp + + DB 0 + DW 1D0h ; Down arrow + DW Msg_ViewMsgDown + + DB 0 + DW 1C9h + DW Msg_ViewMsgPgUp + + DB 0 + DW 1D1h + DW Msg_ViewMsgPgDn + + DB 0 + DW 11Ch + DW Msg_ViewMsgEdit + + DB 1 + DW 'T'-'@' ; Ctrl 'T' + DW Msg_ToggleCharacterSet + + DB 0FFh ; End of List + +EditMsgKeys Label + DB 0 + DW 1C7h + DW Msg_EditMsgHome + + DB 0 + DW 1CFh + DW Msg_EditMsgEnd + + DB 0 + DW 1CBh + DW Msg_EditMsgLeft + + DB 0 + DW 1CDh + DW Msg_EditMsgRight + + DB 0 + DW 1C8h ; Up arrow + DW Msg_EditMsgUp + + DB 0 + DW 1D0h ; Down arrow + DW Msg_EditMsgDown + + DB 0 + DW 1C9h ; PgUp + DW Msg_EditMsgPgUp + + DB 0 + DW 1D1h ; PgDn + DW Msg_EditMsgPgDn + +; DB 2 +; DW 1C8h ; Up arrow +; DW Msg_ViewMsgUp +; +; DB 2 +; DW 1D0h ; Down arrow +; DW Msg_ViewMsgDown + + DB 0 + DW 1D2h ; Insert + DW Msg_EditMsgInsert + + DB 0 + DW 10Fh + DW Msg_Tab + + DB 0 + DW 1D3h ; Delete + DW Msg_EditMsgDelete + + DB 0 + DW 101h ; Escape + DW Msg_EditMsgView + + DB 0 + DW 10Eh ; Backspace + DW Msg_EditMsgBackSpace + + DB 1 + DW 19h + DW Msg_EditMsgDeleteLine + + DB 1 + DW 2E00h ; Alt 'C' + DW Msg_ClearMessage + + DB 1 + DW 'T'-'@' ; Ctrl 'T' + DW Msg_ToggleCharacterSet + + DB 0FFh + +;Ŀ +; Functions +; +; + +Proc Msg_ResetMessage Far + + Push CS + Pop ES + Mov DI, Offset MessageData + Xor AX, AX + Mov CX, 4000 + Rep StosW + + Mov CS:Edit, 0 + Mov CS:TopLine, 0 + + Ret + +EndP Msg_ResetMessage + +; + +Proc Msg_DrawMessage Far + + Call S_GetDestination + + Push CS + Pop DS + Assume DS:Message + + Cmp Edit, 0 + JE Msg_DrawMessage7 + + Mov SI, Offset MessageData + Mov CX, CurrentPosition + Xor DX, DX ; DX = line count. + Xor BX, BX ; BX = cursor position. + JCXZ Msg_DrawMessage4 + +Msg_DrawMessage1: + LodsB + Test AL, AL + JZ Msg_DrawMessage4 + + Inc BX + + Cmp AL, 13 ; Enter? + JNE Msg_DrawMessage2 + + Inc DX ; Increase current line. + Xor BX, BX + +Msg_DrawMessage2: + Loop Msg_DrawMessage1 + +Msg_DrawMessage4: + Mov CurrentLine, DX + Mov HorizontalPosition, BX + + Mov AX, TopLine ; Boundary checking... + Cmp AX, DX + JBE Msg_DrawMessage5 + + Mov AX, DX ; Need new top line. + +Msg_DrawMessage5: + LEA CX, [EAX+34] + Cmp CX, DX + JAE Msg_DrawMessage6 + + Mov AX, DX + Sub AX, 34 + JNC Msg_DrawMessage6 + + Xor AX, AX + +Msg_DrawMessage6: + Mov TopLine, AX + ; Now to get the stuff onto + ; the screen... +Msg_DrawMessage7: + Mov CX, TopLine + Mov SI, Offset MessageData + JCXZ Msg_DrawMessage9 + +Msg_DrawMessage8: + LodsB + And AL, AL + JZ Msg_DrawMessageEnd + + Cmp AL, 13 + JNE Msg_DrawMessage8 + Loop Msg_DrawMessage8 + +Msg_DrawMessage9: + Mov DI, (2+13*80)*2 + Mov BL, CharacterColour + Mov CX, 35 + Mov DX, 20+100h + Mov AH, BL + + Push DI + + Cmp Edit, 1 + JE Msg_DrawMessage10 + + Mov DX, 300h + +Msg_DrawMessage10: + LodsB + And AL, AL + JZ Msg_DrawMessage12 + + Cmp AL, 13 + JE Msg_DrawMessage11 + + Cmp AL, ' ' + JE Msg_DrawMessage14 + + StosW + Jmp Msg_DrawMessage10 + +Msg_DrawMessage14: + Mov AH, 3 + StosW + Mov AH, BL + Jmp Msg_DrawMessage10 + +Msg_DrawMessage11: + Mov AX, DX + StosW + + Mov AH, BL + + Pop DI + Add DI, 160 + Push DI + + Loop Msg_DrawMessage10 + Jmp Msg_DrawMessage13 + +Msg_DrawMessage12: + Mov AX, DX + Inc AH + StosW + +Msg_DrawMessage13: + Pop DI + +Msg_DrawMessageEnd: + Ret + +EndP Msg_DrawMessage + Assume DS:Nothing + +; + +Proc Msg_PreMessage Far + + Push CS + Pop DS + Assume DS:Message + + Cmp Edit, 0 + JE Msg_PreMessage1 + + Call S_GetDestination + + Mov AX, CurrentLine + Sub AX, TopLine + Mov BX, 80 + Mul BX + Add AX, HorizontalPosition + LEA DI, [EAX*2+(2+13*80)*2+1] + + And Byte Ptr [ES:DI], 8 + Or Byte Ptr [ES:DI], 30h + +Msg_PreMessage1: + Ret + +EndP Msg_PreMessage + Assume DS:Nothing + +; + +Proc Msg_PostMessage Far + + Push CS + Pop DS + + Cmp Edit, 0 + JNE Msg_PostMessage2 + + Mov SI, Offset NoEditKeys + Call M_FunctionDivider + JC Msg_PostMessage1 + + Jmp [SI] + +Msg_PostMessage1: + Xor AX, AX + Ret + +Msg_PostMessage2: + Mov SI, Offset EditMsgKeys + Call M_FunctionDivider + JC Msg_PostMessage3 + + Jmp [SI] + +Msg_PostMessage3: + Cmp CX, 11Ch ; Enter + JE Msg_PostMessage6 + Test CL, CL + JZ Msg_PostMessage1 + + Cmp DL, 32 + JB Msg_PostMessage1 + Jmp Msg_PostMessage4 + +Msg_PostMessage6: + Mov DL, 13 + +Msg_PostMessage4: + Push DX + + Mov DX, 1 + Mov SI, CurrentPosition + Call InsertData + + Pop DX + + JC Msg_PostMessage5 + + Mov [SI+MessageData], DL + Call CheckWordWrap + Jmp Msg_EditMsgRight + +Msg_PostMessage5: + Mov AX, 1 + Ret + +EndP Msg_PostMessage + Assume DS:Nothing + +; + +Proc Msg_Tab Far + + Mov CX, 8 + +Msg_Tab1: + Push CX + Mov DX, 32 + Call Far Ptr Msg_PostMessage4 + Pop CX + Loop Msg_Tab1 + + Ret + + +EndP Msg_Tab + +; + +Proc Msg_ViewMsgUp Far + Assume DS:Message + + Mov AX, TopLine + Sub AX, 1 + AdC AX, 0 + Mov TopLine, AX + + Mov AX, 1 + Ret + +EndP Msg_ViewMsgUp + Assume DS:Nothing + +; + +Proc Msg_ViewMsgDown Far + Assume DS:Message + + Mov AX, TopLine + Inc AX + Cmp AX, 7970 + JB Msg_ViewMsgDown1 + + Mov AX, 7970 + +Msg_ViewMsgDown1: + Mov TopLine, AX + + Mov AX, 1 + Ret + +EndP Msg_ViewMsgDown + Assume DS:Nothing + +; + +Proc Msg_ViewMsgPgUp Far + Assume DS:Message + + Mov AX, TopLine + Sub AX, 35 + JNC Msg_ViewMsgPgUp1 + + Xor AX, AX + +Msg_ViewMsgPgUp1: + Mov TopLine, AX + + Mov AX, 1 + Ret + +EndP Msg_ViewMsgPgUp + Assume DS:Nothing + +; + +Proc Msg_ViewMsgPgDn Far + Assume DS:Message + + Mov AX, TopLine + Add AX, 35 + Cmp AX, 7970 + JB Msg_ViewMsgPgDn1 + + Mov AX, 7970 + +Msg_ViewMsgPgDn1: + Mov TopLine, AX + + Mov AX, 1 + Ret + +EndP Msg_ViewMsgPgDn + Assume DS:Nothing + +; + +Proc Msg_ViewMsgEdit Far + Assume DS:Message + + Mov TopLine, 0 + Mov CurrentLine, 0 + Mov CurrentPosition, 0 + Mov Edit, 1 + + Mov AX, 1 + Ret + +EndP Msg_ViewMsgEdit + Assume DS:Nothing + +; + +Proc Msg_EditMsgView Far + Assume DS:Message + + Mov Edit, 0 + + Mov AX, 1 + Ret + +EndP Msg_EditMsgView + Assume DS:Nothing + +; + +Proc Msg_EditMsgLeft Far + Assume DS:Message + + Sub CurrentPosition, 1 + AdC CurrentPosition, 0 + + Mov AX, 1 + Ret + +EndP Msg_EditMsgLeft + Assume DS:Nothing + +; + +Proc Msg_EditMsgRight Far + Assume DS:Message + + Mov SI, CurrentPosition + Cmp SI, MESSAGELENGTH-2 + JAE Msg_EditMsgRight1 + + Cmp Word Ptr [SI+MessageData], 0 + JE Msg_EditMsgRight1 + + Inc CurrentPosition + +Msg_EditMsgRight1: + Mov AX, 1 + Ret + +EndP Msg_EditMsgRight + Assume DS:Nothing + +; + +Proc Msg_EditMsgUp Far + Assume DS:Message + + Mov SI, CurrentPosition ; Need to search back + ; twice... + Call FindStart + And SI, SI + JZ Msg_EditMsgUpEnd + Dec SI + Call FindStart + + Add SI, Offset MessageData + + Mov CX, HorizontalPosition + JCXZ Msg_EditMsgUp3 + +Msg_EditMsgUp2: + LodsB + Cmp AL, 13 + LoopNE Msg_EditMsgUp2 + JNE Msg_EditMsgUp3 + + Dec SI + +Msg_EditMsgUp3: + Sub SI, Offset MessageData + Mov CurrentPosition, SI + +Msg_EditMsgUpEnd: + Mov AX, 1 + Ret + +EndP Msg_EditMsgUp + Assume DS:Nothing + +; + +Proc Msg_EditMsgPgUp Far + + Mov CX, 35 + +Msg_EditMsgPgUp1: + Push CX + Call Msg_EditMsgUp + Pop CX + Loop Msg_EditMsgPgUp1 + + Mov AX, 1 + Ret + +EndP Msg_EditMsgPgUp + +; + +Proc Msg_EditMsgDown Far + Assume DS:Message + ; Search for enter + Mov SI, CurrentPosition + +Msg_EditMsgDown1: + Mov AL, [SI+MessageData] + Inc SI + And AL, AL + JZ Msg_EditMsgDownEnd + + Cmp AL, 13 + JNE Msg_EditMsgDown1 + + Mov CX, HorizontalPosition + JCXZ Msg_EditMsgDown3 + +Msg_EditMsgDown2: + Mov AL, [SI+MessageData] + And AL, AL + JZ Msg_EditMsgDown3 + + Cmp AL, 13 + JE Msg_EditMsgDown3 + + Inc SI + Loop Msg_EditMsgDown2 + +Msg_EditMsgDown3: + Cmp SI, MESSAGELENGTH-2 + JAE Msg_EditMsgDownEnd + + Mov CurrentPosition, SI + +Msg_EditMsgDownEnd: + Mov AX, 1 + Ret + +EndP Msg_EditMsgDown + Assume DS:Nothing + +; + +Proc Msg_EditMsgPgDn Far + + Mov CX, 35 + +Msg_EditMsgPgDn1: + Push CX + Call Msg_EditMsgDown + Pop CX + Loop Msg_EditMsgPgDn1 + + Mov AX, 1 + Ret + +EndP Msg_EditMsgPgDn + +; + +Proc Msg_EditMsgDelete Far + Assume DS:Message + + Mov SI, CurrentPosition + Mov DX, 1 + Call DeleteData + Call CheckWordWrap + + Mov AX, 1 + Ret + +EndP Msg_EditMsgDelete + Assume DS:Nothing + +; + +Proc Msg_EditMsgInsert Far + + Mov SI, CurrentPosition + Mov DX, 1 + Call InsertData + JC Msg_EditMsgInsert1 + + Mov Byte Ptr [SI+MessageData], 32 + Call CheckWordWrap + +Msg_EditMsgInsert1: + Mov AX, 1 + Ret + +EndP Msg_EditMsgInsert + +; + +Proc Msg_EditMsgBackspace Far + Assume DS:Message + + Mov SI, CurrentPosition + And SI, SI + JZ Msg_EditMsgBackspace1 + + Call Msg_EditMsgLeft + Call Msg_EditMsgDelete + +Msg_EditMsgBackspace1: + Mov AX, 1 + Ret + +EndP Msg_EditMsgBackspace + Assume DS:Nothing + +; + +Proc Msg_EditMsgDeleteLine Far + Assume DS:Message + + Mov SI, CurrentPosition ; Search back for + ; start of line.. + Call FindStart + + ; Find length to delete. + Xor BX, BX ; DI = length + +Msg_EditMsgDeleteLine3: + Mov AL, [SI+BX+MessageData] + Inc BX + + And AL, AL + JZ Msg_EditMsgDeleteLine4 + Cmp AL, 13 + JNE Msg_EditMsgDeleteLine3 + +Msg_EditMsgDeleteLine4: + Mov DX, BX + Call DeleteData + + Mov CurrentPosition, SI + + Mov AX, 1 + Ret + +EndP Msg_EditMsgDeleteLine + Assume DS:Nothing + +; + +Proc Msg_ClearMessage Far + + Mov DI, Offset O1_ConfirmClearMessage + Mov CX, 4 + Call M_Object1List + + And DX, DX + JZ Msg_ClearMessage1 + + Call Msg_ResetMessage + +Msg_ClearMessage1: + Mov AX, 1 + Ret + +EndP Msg_ClearMessage + +; + +Proc Msg_EditMsgHome Far + Assume DS:Message + + Mov SI, CurrentPosition + Call FindStart + Mov CurrentPosition, SI + + Mov AX, 1 + Ret + +EndP Msg_EditMsgHome + Assume DS:Nothing + +; + +Proc Msg_EditMsgEnd Far + Assume DS:Message + + Mov SI, CurrentPosition + +Msg_EditMsgEndLoop: + Mov AL, [SI+MessageData] + + Inc SI + + And AL, AL + JZ Msg_EditMsgEnd1 + + Cmp AL, 13 + JNE Msg_EditMsgEndLoop + +Msg_EditMsgEnd1: + Dec SI + Mov CurrentPosition, SI + + Mov AX, 1 + Ret + +EndP Msg_EditMsgEnd + Assume DS:Nothing + +; + +Proc FindStart + +FindStart1: + Sub SI, 1 + JC FindStart2 + + Cmp Byte Ptr [SI+MessageData], 13 + JNE FindStart1 + +FindStart2: + Inc SI + Ret + +EndP FindStart + +; + +Proc InsertData ; SI = pos, DX = length. + + Push CX + Push DX + Push SI + + Mov CX, MESSAGELENGTH-1 + Sub CX, SI + Sub CX, DX + + Mov SI, Offset MessageData+MESSAGELENGTH-2 + Mov DI, SI + Sub SI, DX + + Cmp Byte Ptr [SI], 0 + JNE InsertDataError + + Push DS + Pop ES + + StD + Rep MovsB + ClD + + ClC + Jmp InsertDataEnd + +InsertDataError: + Push DS + + Mov DI, Offset O1_LongMessageList + Mov CX, 2 + Call M_Object1List + + Pop DS + + StC + +InsertDataEnd: + Pop SI + Pop DX + Pop CX + Ret + +EndP InsertData + +; + +Proc DeleteData ; SI = pos, DX = length + ; Assume DS:Message + + Push CX + Push DX + Push SI + + Push CS + Pop ES + + Mov CX, MESSAGELENGTH + Sub CX, SI + Sub CX, DX + JS DeleteData1 + + Add SI, Offset MessageData + Mov DI, SI + Add SI, DX + + Rep MovsB + + Xor AX, AX + Mov CX, DX + Rep StosB + +DeleteData1: + Pop SI + Pop DX + Pop CX + Ret + +EndP DeleteData + +; + +Proc CheckWordWrap ; Check current line only. + + Mov SI, CurrentPosition + Call FindStart + + ; OK, so SI = pos of last line. + ; Now count length of new line. + Xor BX, BX ; BX = count. + +CheckWordWrap3: + Mov AL, [SI+BX+MessageData] + + Inc BX + + And AL, AL + JZ CheckWordWrap4 + Cmp AL, 13 + JNE CheckWordWrap3 + +CheckWordWrap4: ; OK.. now if BX > 66... + Cmp BX, 75 + JA CheckWordWrap5 + + Ret + +CheckWordWrap5: ; Search back for a space and REPLACE + ; it with an enter... + Mov BX, 75 + +CheckWordWrap6: + Dec BX + JZ CheckWordWrap7 + + Cmp Byte Ptr [SI+BX+MessageData], 32 + JNE CheckWordWrap6 + + Mov Byte Ptr [SI+BX+MessageData], 13 + + Ret + +CheckWordWrap7: ; Insert an enter + Mov DX, 1 + Add SI, 75 + Call InsertData + Mov Byte Ptr [SI+MessageData], 13 + +CheckWordWrap8: + Ret + +EndP CheckWordWrap + +; + +Proc Msg_GetMessageLength Far ; Returns AX + + Push DS + Push SI + + Push CS + Pop DS + + Mov SI, Offset MessageData + +Msg_GetMessageLength1: + LodsB + And AL, AL + JNZ Msg_GetMessageLength1 + + Sub SI, Offset MessageData + Mov AX, SI + + Pop SI + Pop DS + Ret + +EndP Msg_GetMessageLength + +; + +Proc Msg_GetMessageOffset Far + + Push CS + Pop DS + + Mov DX, Offset MessageData + Ret + +EndP Msg_GetMessageOffset + +; + +Proc Msg_ToggleCharacterSet Far + Assume DS:Message + + Xor CharacterColour, 6 xor 12 + + Mov AX, 1 + Ret + +EndP Msg_ToggleCharacterSet + Assume DS:Nothing + +; + +EndS + +; + +End diff --git a/it/IT_MUSIC.ASM b/it/IT_MUSIC.ASM new file mode 100644 index 0000000..ce4deba --- /dev/null +++ b/it/IT_MUSIC.ASM @@ -0,0 +1,7481 @@ +;Ŀ +; Music Module +; + + .386 + .387 + +include switch.inc +include network.inc + +;Ŀ +; Externals +; + + Extrn D_GotoStartingDirectory:Far + Extrn D_SetDriveDirectoryFar:Far + Extrn D_GetFileName:Far + Extrn D_Showtime:Far + + Extrn E_EMSAvailable:Far + Extrn E_SaveEMSPageFrame:Far + Extrn E_RestoreEMSPageFrame:Far + Extrn E_UnInitEMS:Far + Extrn E_AllocateEMS:Far + Extrn E_MapEMSMemory:Far + Extrn E_GetEMSPageFrame:Far + Extrn E_ReleaseEMS:Far + Extrn E_AllocateBlockEMS:Far, E_ReleaseBlockEMS:Far + Extrn E_MapAlignedBlockEMS:Far + Extrn E_GetInternalEMSHandle:Far + + Extrn I_TagInstrument:Far + Extrn I_TagSample:Far + + Extrn O1_OutOfSoundCardMemoryList:Far + + Extrn M_FunctionHandler:Far + Extrn M_Object1List:Far + + Extrn Network_UpdatePatternIfIdle:Far + + Extrn PE_GetCurrentPattern:Far + Extrn PE_FillHeader:Far + Extrn S_GetDestination:Far + Extrn S_UnInitScreen:Far + Extrn S_DirectDrawString:Far + Extrn S_DrawString:Far + Extrn S_SetDirectMode:Far + Extrn S_SaveScreen:Far + Extrn S_RestoreScreen:Far + Extrn S_DrawBox:Far + Extrn S_DrawString:Far + Extrn S_UpdateScreen:Far + Extrn S_DrawSmallBox:Far + Extrn F_DrawHeader:Far + + Extrn K_GetKey:Far + Extrn StartClock:Far + Extrn SetInfoLine:Far, SetInfoLine2:Far + Extrn M_Object1List:Far + + Extrn MaxRow + + Extrn IdleUpdateInfoLine:Far + Extrn GlobalKeyList:Far + Extrn GetEnvironment:Far + + Extrn MIDIBufferEmpty:Far, MIDISend:Far, MIDI_ClearTable:Far + Extrn O1_ShowTime + +;Ŀ +; Globals +; + + Global Music_GetDisplayVariables:Far + Global Music_AutoDetectSoundCard:Far + + Global Music_Poll:Far + + Global Music_ReinitSoundCard:Far + Global Music_InitMusic:Far + Global Music_UnInitMusic:Far + Global Music_GetSongSegment:Far + Global Music_GetInstrumentMode:Far + Global Music_ReleasePattern:Far + Global Music_GetPattern:Far + Global Music_GetPatternLocation:Far + Global Music_GetPatternLocationNoCount:Far + Global Music_AllocatePattern:Far + Global Music_AllocateSample:Far + Global Music_IncreaseSpeed:Far + Global Music_DecreaseSpeed:Far + Global Music_GetOutputWaveform:Far + Global Music_PlayPartSong:Far + Global Music_GetPatternLength:Far + Global Music_ShowAutodetectSoundcard:Far + Global Music_GetWaveForm:Far + Global Music_ToggleOrderUpdate:Far + + Global Music_NextOrder:Far + Global Music_LastOrder:Far + + Global Music_SetSoundCard:Far + Global Music_SetDMA:Far + Global Music_SetMixSpeed:Far + Global Music_SetIRQ:Far + Global Music_SetAddress:Far + Global Music_SetLimit:Far + Global Music_ReverseChannels:Far + + Global Music_GetNumChannels:Far + Global Music_InitStereo:Far + Global Music_ReleaseSample:Far + Global Music_ReleaseAllSamples:Far + Global Music_ReleaseAllPatterns:Far + Global Music_ClearSampleName:Far + Global Music_ClearAllSampleNames:Far + Global Music_GetNumberOfSamples:Far + Global Music_GetNumberOfInstruments:Far + Global Music_ClearInstrument:Far + Global Music_ClearAllInstruments:Far + Global Music_GetHostChannelInformationTable:Far + Global Music_GetSlaveChannelInformationTable:Far + Global Music_SetGlobalVolume:Far + + Global Music_InitMuteTable:Far + Global Music_UnmuteAll:Far + + Global Music_GetPlayMode:Far + Global Music_GetPlayMode2:Far + Global Music_PlayPattern:Far + Global Music_PlaySample:Far + Global Music_PlayNote:Far + Global Music_Stop:Far + Global Music_PlaySong:Far + Global Music_ToggleChannel:Far + Global Music_SoloChannel:Far + Global Music_InitMixTable:Far + Global Music_GetSampleLocation:Far + Global Music_UpdatePatternOffset:Far + Global Music_AssignSampleToInstrument:Far + Global Music_KBPlaySong:Far + Global Music_IncreaseVolume:Far + Global Music_DecreaseVolume:Far + Global Music_SetSoundCardDriver:Far + Global Music_RegetLoopInformation:Far + + Global Music_SoundCardLoadSample:Far + Global Music_SoundCardLoadAllSamples:Far + Global Music_GetFreeSoundCardMemory:Far + Global Music_GetPitchTable:Far + Global Music_GetMIDIDataArea:Far + + Global Music_ToggleReverse:Far + Global Music_PatternStorage:Far + + Global Music_GetDriverScreen:Far + Global Music_GetLastChannel:Far + + Global SongDataArea:Word + Global MixDataArea:Word + + Global Music_GetDriverVariable:Far, Music_SetDriverVariable:Far + Public Music_GetDelay + Public Music_SetNextOrder + Public Music_TimeSong + Public Music_ShowTime + Public Music_SaveMIDIConfig + Public MIDIDataArea + + Public Music_ToggleSoloInstrument, Music_ToggleSoloSample + + Extrn PE_GetLastInstrument:Far + Public CurrentPattern + +; + +; +; Functions for playing control +; Music_PlaySong........ parameters, AX = order +; Music_Stop............ parameters, None +; Music_PlayPattern..... parameters, AX = pattern, BX = number of rows, CX = row +; Music_ToggleChannel... parameters, AX = channel +; Music_SoloChannel..... parameters, AX = channel +; + +Segment SongData PARA Public 'Data' +EndS + +Segment Music DWORD Public 'Code' USE16 + Assume CS:Music + +CREATENEWLOGFILE EQU 0 +include debug.inc + +;Ŀ +; Variables +; + +HOSTCHANNELSIZE EQU 80 +SLAVECHANNELSIZE EQU 128 +MAXSLAVECHANNELS EQU 256 +NONOTE EQU 0FDh + +MIDICOMMAND_START EQU 0 +MIDICOMMAND_STOP EQU 20h +MIDICOMMAND_TICK EQU 40h +MIDICOMMAND_PLAYNOTE EQU 60h +MIDICOMMAND_STOPNOTE EQU 80h +MIDICOMMAND_CHANGEVOLUME EQU 0A0h +MIDICOMMAND_CHANGEPAN EQU 0C0h +MIDICOMMAND_BANKSELECT EQU 0E0h +MIDICOMMAND_PROGRAMSELECT EQU 100h +MIDICOMMAND_CHANGEPITCH EQU 0FFFFh + +FineSineData Label Byte + DB 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23 + DB 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44 + DB 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59 + DB 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64 + DB 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60 + DB 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46 + DB 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26 + DB 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2 + DB 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23 + DB -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44 + DB -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59 + DB -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64 + DB -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60 + DB -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46 + DB -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26 + DB -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2 + +FineRampDownData Label Byte + DB 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 59, 58, 58, 57, 57, 56 + DB 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48 + DB 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40 + DB 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32 + DB 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24 + DB 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16 + DB 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8 + DB 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0 + DB 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8 + DB -8, -9, -9,-10,-10,-11,-11,-12,-12,-13,-13,-14,-14,-15,-15,-16 + DB -16,-17,-17,-18,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24 + DB -24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32 + DB -32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40 + DB -40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48 + DB -48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-56 + DB -56,-57,-57,-58,-58,-59,-59,-60,-60,-61,-61,-62,-62,-63,-63,-64 + +FineSquareWave Label Byte + DB 128 Dup (64), 128 Dup (0) + +EmptyPattern Label + DW 64, 64, 0, 0 + DB 64 Dup (0) + +; + + ; Zero globals. + +LastSample DW 0 +PlayMode DW 0 ; Playmode 0 = Freeplay + ; Playmode 1 = Pattern + ; Playmode 2 = Song +CurrentOrder DW 0 ; } Must follow +CurrentPattern DW 0 ; } +CurrentRow DW 0 ; } +ProcessOrder DW 0 +ProcessRow DW 0 +BytesToMix DW 0 ; = Bytes per frame +PatternOffset DW 0 +PatternSegment DW 0 +BreakRow DW 0 +RowDelay DB 0 ; } Must join on. +RowDelayOn DB 0 ; } +PatternArray DB 0 + +; + +ALIGN 4 + +PitchDepthConstant DD 98304.0 +HostChannelInformationTable DB 64*HOSTCHANNELSIZE Dup(?) +SlaveChannelInformationTable DB MAXSLAVECHANNELS*SLAVECHANNELSIZE Dup(?) +MuteChannelTable DB 64 Dup (?) +ChannelCountTable DB 400 Dup (?) +;AllocateCount1 DB 0 +;AllocateCount2 DB 0 +;AllocateCount3 DB 0 + +; + +ALIGN 2 + +PatternDataSegment DW ? +CurrentEditPattern DW ? +PatternEditMaxRow DW ? + +; + +NumberOfRows DW 64 ; Non zero globals +CurrentTick DW 6 +CurrentSpeed DW 6 +ProcessTick DW 0 +Tempo DB 125 +GlobalVolume DB 128 +NumChannels DW 256 +SoloSample DB 0FFh ; * ORDER IS IMPORTANT +SoloInstrument DB 0FFh ; * ORDER IS IMPORTANT + +AllocateNumChannels DW 0 +AllocateSlaveOffset DW 0 +LastSlaveChannel DW 0 + +DecodeExpectedPattern DW 0FFFEh +DecodeExpectedRow DW 0FFFEh + +; + +CmdLineNumChannels DW 0FFFFh + +DriverRequiredVariables Label ; * ORDER IS IMPORTANT +BasePort DW 0FFFFh ; * ORDER IS IMPORTANT +IRQ DW 0FFFFh ; * ORDER IS IMPORTANT +DMA DW 0FFFFh ; * ORDER IS IMPORTANT +CmdLineMixSpeed DW 0 ; * ORDER IS IMPORTANT +SongDataArea DW SongData ; * ORDER IS IMPORTANT +MIDIDataArea DW SongData + 4076 + +CmdLineDMASize DW 1024 ; default +ReverseChannels DB 0 + +InstrumentHeader Label Byte + DB "IMPI" + DB 19 Dup (0), 60, 128, 32+128, 34 Dup (0) + DB 0, 0FFh, 0FFh, 0FFh + DB 0, 0, 1, 0, 2, 0, 3, 0, 4, 0 + DB 5, 0, 6, 0, 7, 0, 8, 0, 9, 0 + DB 10, 0, 11, 0, 12, 0, 13, 0, 14, 0 + DB 15, 0, 16, 0, 17, 0, 18, 0, 19, 0 + DB 20, 0, 21, 0, 22, 0, 23, 0, 24, 0 + DB 25, 0, 26, 0, 27, 0, 28, 0, 29, 0 + DB 30, 0, 31, 0, 32, 0, 33, 0, 34, 0 + DB 35, 0, 36, 0, 37, 0, 38, 0, 39, 0 + DB 40, 0, 41, 0, 42, 0, 43, 0, 44, 0 + DB 45, 0, 46, 0, 47, 0, 48, 0, 49, 0 + DB 50, 0, 51, 0, 52, 0, 53, 0, 54, 0 + DB 55, 0, 56, 0, 57, 0, 58, 0, 59, 0 + DB 60, 0, 61, 0, 62, 0, 63, 0, 64, 0 + DB 65, 0, 66, 0, 67, 0, 68, 0, 69, 0 + DB 70, 0, 71, 0, 72, 0, 73, 0, 74, 0 + DB 75, 0, 76, 0, 77, 0, 78, 0, 79, 0 + DB 80, 0, 81, 0, 82, 0, 83, 0, 84, 0 + DB 85, 0, 86, 0, 87, 0, 88, 0, 89, 0 + DB 90, 0, 91, 0, 92, 0, 93, 0, 94, 0 + DB 95, 0, 96, 0, 97, 0, 98, 0, 99, 0 + DB 100, 0, 101, 0, 102, 0, 103, 0, 104, 0 + DB 105, 0, 106, 0, 107, 0, 108, 0, 109, 0 + DB 110, 0, 111, 0, 112, 0, 113, 0, 114, 0 + DB 115, 0, 116, 0, 117, 0, 118, 0, 119, 0 + DB 0, 2, 4 Dup (0), 64, 0, 0, 64, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 0, 2, 4 Dup (0), 0, 0, 0, 0, 100, 0, 70 Dup (0) + DB 7 Dup (0) + +SampleHeader Label Byte + DB "IMPS", 13 Dup (0), 64, 0, 64, 40 Dup (0) + DW 8363 + DB 18 Dup (0) + +MidiPitchSendString DB 65h, 0, 64h, 0, 06 + +PatternLooping DB 0 +PatternStorage DB 1 ; 0 = conventional only + ; 1 = selective + ; 2 = EMS only. + +PrepareSamplesMsg DB "Preparing Samples", 0 +ReverseMsg DB "Left/right outputs reversed", 0 +NoSoundCardMsg DB " No sound card detected", 0 +MIDIConfigFileName DB "ITMIDI.CFG", 0 + +OrderUpdateEnabledMsg DB "Order list unlocked", 0 +OrderUpdateDisabledMsg DB "Order list locked", 0 +OrderLockFlag DB 0 + +UnsoloMsg DB "Solo disabled", 0 +SoloSampleMsg DB "Solo sample ", 0FDh, "D", 0 +SoloInstrumentMsg DB "Solo instrument ", 0FDh, "D", 0 + +IFDEF DEBUG + +LoadDriverMessage DB "Loading driver:", 0 +UnableToReadFileMessage DB "Unable to read file", 0 +DetectingMessage DB "Testing driver", 0 +ScreenOffset DW 0 + +ENDIF + +PCSpeakerDriver DB "ITPCSPKR.DRV", 0 +SBDriver DB "ITSB.DRV", 0 +SB2Driver DB "ITSB2.DRV", 0 +SBProDriver DB "ITSBPRO.DRV", 0 +SB16Driver DB "ITSB16.DRV", 0 +AWE32Driver DB "ITAWE32.DRV", 0 +GUSDriver DB "ITGUS.DRV", 0 +InterwaveDriver DB "ITIW.DRV", 0 +PASDriver DB "ITPAS.DRV", 0 +PAS16Driver DB "ITPAS16.DRV", 0 +WSSDriver DB "ITWSS.DRV", 0 +ESSDriver DB "ITES1868.DRV", 0 +MIDIDriver DB "ITMPU401.DRV", 0 +EWSCodecDriver DB "ITEWSCOD.DRV", 0 +VIVOCodecDriver DB "ITVIVO.DRV", 0 +ST97PCICodecDriver DB "ITSTCODE.DRV", 0 +WAVDriver DB "ITWAV.DRV", 0 +MIDDriver DB "ITMID.DRV", 0 +VSoundMMXDriver DB "ITVSOUND.MMX", 0 +VSoundDriver DB "ITVSOUND.DRV", 0 +DefaultDriver DB "ITSOUND.DRV", 0 + +DriverNameTable Label + DW 0FFFFh + DW Offset PAS16Driver, SB16Driver + DW Offset InterwaveDriver, Offset GUSDriver + DW Offset AWE32Driver, Offset SBProDriver + DW Offset SBDriver, Offset PCSpeakerDriver + DW Offset SB2Driver, Offset PASDriver + DW Offset WAVDriver, Offset WSSDriver + DW Offset ESSDriver, MIDIDriver + DW Offset EWSCodecDriver, VIVOCodecDriver + DW Offset ST97PCICodecDriver, Offset MIDDRIVER + DW Offset DefaultDriver, Offset VSoundMMXDriver + DW Offset VSoundDriver + +DriverName DD 0 + +DriverDetectionOrder DW 19, 20, 21, 17, 16, 15, 13, 1, 10, 2, 12, 3, 4, 5, 6, 9, 7, 8, 0FFFFh +DriverSoundCard DW 0, 8, 7, 9, 6 + DW 2, 5, 4, 3, 10 + DW 1, 12, 13, 15, 16 + DW 0, 0, 0, 0, 14 + DW 11, 18 + +ALIGN 4 + +PitchTable Label DWord + DW 2048, 0, 2170, 0, 2299, 0, 2435, 0, 2580, 0, 2734, 0 + DW 2896, 0, 3069, 0, 3251, 0, 3444, 0, 3649, 0, 3866, 0 + + DW 4096, 0, 4340, 0, 4598, 0, 4871, 0, 5161, 0, 5468, 0 + DW 5793, 0, 6137, 0, 6502, 0, 6889, 0, 7298, 0, 7732, 0 + + DW 8192, 0, 8679, 0, 9195, 0, 9742, 0, 10321, 0, 10935, 0 + DW 11585, 0, 12274, 0, 13004, 0, 13777, 0, 14596, 0, 15464, 0 + + DW 16384, 0, 17358, 0, 18390, 0, 19484, 0, 20643, 0, 21870, 0 + DW 23170, 0, 24548, 0, 26008, 0, 27554, 0, 29193, 0, 30929, 0 + + DW 32768, 0, 34716, 0, 36781, 0, 38968, 0, 41285, 0, 43740, 0 + DW 46341, 0, 49097, 0, 52016, 0, 55109, 0, 58386, 0, 61858, 0 + + DW 0, 1, 3897, 1, 8026, 1, 12400, 1, 17034, 1, 21944, 1 + DW 27146, 1, 32657, 1, 38496, 1, 44682, 1, 51236, 1, 58179, 1 + + DW 0, 2, 7794, 2, 16051, 2, 24800, 2, 34068, 2, 43888, 2 + DW 54292, 2, 65314, 2, 11456, 3, 23828, 3, 36936, 3, 50823, 3 + + DW 0, 4, 15588, 4, 32103, 4, 49600, 4, 2601, 5, 22240, 5 + DW 43048, 5, 65092, 5, 22912, 6, 47656, 6, 8336, 7, 36110, 7 + + DW 0, 8, 31176, 8, 64205, 8, 33663, 9, 5201, 10, 44481, 10 + DW 20559, 11, 64648, 11, 45823, 12, 29776, 13, 16671, 14, 6684, 15 + + DW 0, 16, 62352, 16, 62875, 17, 1790, 19, 10403, 20, 23425, 21 + DW 41118, 22, 63761, 23, 26111, 25, 59552, 26, 33342, 28, 13368, 30 + +; Pitch extention for loading some XIs + + DW 0, 32, 59167, 33, 60214, 35, 3580, 38, 20806, 40, 46850, 42 + DW 16701, 45, 61986, 47, 52221, 50, 53567, 53, 1148, 57, 26736, 60 + +IF USEFPUCODE + +FPSave DB 128 Dup (0) + +Const_14317456 DD 14317456.0 +Const1_On_768 DD 3AAAAAABh +SlideValue DW 0 +NewControlWord DW 7Fh + +ELSE + +FineLinearSlideUpTable Label + DW 0, 1, 59, 1, 118, 1, 178, 1, 237, 1 ; 0->4 + DW 296, 1, 356, 1, 415, 1, 475, 1, 535, 1 ; 5->9 + DW 594, 1, 654, 1, 714, 1, 773, 1, 833, 1 ; 10->14 + DW 893, 1 ; 15 + +LinearSlideUpTable Label ; Value = 2^(Val/192) + DW 0, 1, 237, 1, 475, 1, 714, 1, 953, 1 ; 0->4 + DW 1194, 1, 1435, 1, 1677, 1, 1920, 1, 2164, 1 ; 5->9 + DW 2409, 1, 2655, 1, 2902, 1, 3149, 1, 3397, 1 ; 10->14 + DW 3647, 1, 3897, 1, 4148, 1, 4400, 1, 4653, 1 ; 15->19 + DW 4907, 1, 5157, 1, 5417, 1, 5674, 1, 5932, 1 ; 20->24 + DW 6190, 1, 6449, 1, 6710, 1, 6971, 1, 7233, 1 ; 25->29 + DW 7496, 1, 7761, 1, 8026, 1, 8292, 1, 8559, 1 ; 30->34 + DW 8027, 1, 9096, 1, 9366, 1, 9636, 1, 9908, 1 ; 35->39 + DW 10181, 1, 10455, 1, 10730, 1, 11006, 1, 11283,1 ; 40->44 + DW 11560, 1, 11839, 1, 12119, 1, 12400, 1, 12682,1 ; 45->49 + DW 12965, 1, 13249, 1, 13533, 1, 13819, 1, 14106,1 ; 50->54 + DW 14394, 1, 14684, 1, 14974, 1, 15265, 1, 15557,1 ; 55->59 + DW 15850, 1, 16145, 1, 16440, 1, 16737, 1, 17034,1 ; 60->64 + DW 17333, 1, 17633, 1, 17933, 1, 18235, 1, 18538,1 ; 65->69 + DW 18842, 1, 19147, 1, 19454, 1, 19761, 1, 20070,1 ; 70->74 + DW 20379, 1, 20690, 1, 21002, 1, 21315, 1, 21629,1 ; 75->79 + DW 21944, 1, 22260, 1, 22578, 1, 22897, 1, 23216,1 ; 80->84 + DW 23537, 1, 23860, 1, 24183, 1, 24507, 1, 24833,1 ; 85->89 + DW 25160, 1, 25488, 1, 25817, 1, 26148, 1, 26479,1 ; 90->94 + DW 26812, 1, 27146, 1, 27481, 1, 27818, 1, 28155,1 ; 95->99 + DW 28494, 1, 28834, 1, 29175, 1, 29518, 1, 29862,1 ; 100->104 + DW 30207, 1, 30553, 1, 30900, 1, 31248, 1, 31599,1 ; 105->109 + DW 31951, 1, 32303, 1, 32657, 1, 33012, 1, 33369,1 ; 110->114 + DW 33726, 1, 34085, 1, 34446, 1, 34807, 1, 35170,1 ; 115->119 + DW 35534, 1, 35900, 1, 36267, 1, 36635, 1, 37004,1 ; 120->124 + DW 37375, 1, 37747, 1, 38121, 1, 38496, 1, 38872,1 ; 125->129 + DW 39250, 1, 39629, 1, 40009, 1, 40391, 1, 40774,1 ; 130->134 + DW 41158, 1, 41544, 1, 41932, 1, 42320, 1, 42710,1 ; 135->139 + DW 43102, 1, 43495, 1, 43889, 1, 44285, 1, 44682,1 ; 140->144 + DW 45081, 1, 45481, 1, 45882, 1, 46285, 1, 46690,1 ; 145->149 + DW 47095, 1, 47503, 1, 47917, 1, 48322, 1, 48734,1 ; 150->154 + DW 49147, 1, 49562, 1, 49978, 1, 50396, 1, 50815,1 ; 155->159 + DW 51236, 1, 51658, 1, 52082, 1, 52507, 1, 52934,1 ; 160->164 + DW 53363, 1, 53793, 1, 54224, 1, 54658, 1, 55092,1 ; 165->169 + DW 55529, 1, 55966, 1, 56406, 1, 56847, 1, 57289,1 ; 170->174 + DW 57734, 1, 58179, 1, 58627, 1, 59076, 1, 59527,1 ; 175->179 + DW 59979, 1, 60433, 1, 60889, 1, 61346, 1, 61805,1 ; 180->184 + DW 62265, 1, 62727, 1, 63191, 1, 63657, 1, 64124,1 ; 185->189 + DW 64593, 1, 65064, 1, 0, 2, 474, 2, 950, 2 ; 190->194 + DW 1427, 2, 1906, 2, 2387, 2, 2870, 2, 3355, 2 ; 195->199 + DW 3841, 2, 4327, 2, 4818, 2, 5310, 2, 5803, 2 ; 200->204 + DW 6298, 2, 6795, 2, 7294, 2, 7794, 2, 8296, 2 ; 205->209 + DW 8800, 2, 9306, 2, 9814, 2, 10323, 2, 10835,2 ; 210->214 + DW 11348, 2, 11863, 2, 12380, 2, 12899, 2, 13419,2 ; 215->219 + DW 13942, 2, 14467, 2, 14993, 2, 15521, 2, 16051,2 ; 220->224 + DW 16583, 2, 17117, 2, 17653, 2, 18191, 2, 18731,2 ; 225->229 + DW 19273, 2, 19817, 2, 20362, 2, 20910, 2, 21460,2 ; 230->234 + DW 22011, 2, 22565, 2, 23121, 2, 23678, 2, 24238,2 ; 235->239 + DW 24800, 2, 25363, 2, 25929, 2, 25497, 2, 27067,2 ; 240->244 + DW 27639, 2, 28213, 2, 28789, 2, 29367, 2, 29947,2 ; 245->249 + DW 30530, 2, 31114, 2, 31701, 2, 32289, 2, 32880, 2 ; 250->254 + DW 33473, 2, 34068, 2 ; 255->256 + +FineLinearSlideDownTable Label + DW 65535, 65477, 65418, 65359, 65300, 65241, 65182, 65359 ; 0->7 + DW 65065, 65006, 64947, 64888, 64830, 64772, 64713, 64645 ; 8->15 + +LinearSlideDownTable Label + DW 65535, 65300, 65065, 64830, 64596, 64364, 64132, 63901 ; 0->7 + DW 63670, 63441, 63212, 62984, 62757, 62531, 62306, 62081 ; 8->15 + DW 61858, 61635, 61413, 61191, 60971, 60751, 60532, 60314 ; 16->23 + DW 60097, 59880, 59664, 59449, 59235, 59022, 58809, 58597 ; 24->31 + DW 58386, 58176, 57966, 57757, 57549, 57341, 57135, 56929 ; 32->39 + DW 56724, 56519, 56316, 56113, 55911, 55709, 55508, 55308 ; 40->47 + DW 55109, 54910, 54713, 54515, 54319, 54123, 53928, 53734 ; 48->55 + DW 53540, 53347, 53155, 52963, 52773, 52582, 52393, 52204 ; 56->63 + DW 52016, 51829, 51642, 51456, 51270, 51085, 50901, 50718 ; 64->71 + DW 50535, 50353, 50172, 49991, 49811, 49631, 49452, 49274 ; 72->79 + DW 49097, 48920, 48743, 48568, 48393, 48128, 48044, 47871 ; 80->87 + DW 47699, 47527, 47356, 47185, 47015, 46846, 46677, 46509 ; 88->95 + DW 46341, 46174, 46008, 45842, 45677, 45512, 45348, 45185 ; 96->103 + DW 45022, 44859, 44698, 44537, 44376, 44216, 44057, 43898 ;104->111 + DW 43740, 43582, 43425, 43269, 43113, 42958, 42803, 42649 ;112->119 + DW 42495, 42342, 42189, 42037, 41886, 41735, 41584, 41434 ;120->127 + DW 41285, 41136, 40988, 40840, 40639, 40566, 40400, 40253 ;128->135 + DW 40110, 39965, 39821, 39678, 39535, 39392, 39250, 39109 ;136->143 + DW 38968, 38828, 38688, 38548, 38409, 38271, 38133, 37996 ;144->151 + DW 37859, 37722, 37586, 37451, 37316, 37181, 37047, 36914 ;152->159 + DW 36781, 36648, 36516, 36385, 36254, 36123, 35993, 35863 ;160->167 + DW 35734, 35605, 35477, 35349, 35221, 35095, 34968, 34842 ;168->175 + DW 34716, 34591, 34467, 34343, 34219, 34095, 33973, 33850 ;176->183 + DW 33728, 33607, 33486, 33365, 33245, 33125, 33005, 32887 ;184->191 + DW 32768, 32650, 32532, 32415, 32298, 32182, 32066, 31950 ;192->199 + DW 31835, 31720, 31606, 31492, 31379, 31266, 31153, 31041 ;200->207 + DW 30929, 30817, 30706, 30596, 30485, 30376, 30226, 30157 ;208->215 + DW 30048, 29940, 29832, 29725, 29618, 29511, 29405, 29299 ;216->223 + DW 29193, 29088, 28983, 28879, 28774, 28671, 28567, 28464 ;224->231 + DW 28362, 28260, 28158, 28056, 27955, 27855, 27754, 27654 ;232->239 + DW 27554, 27455, 27356, 27258, 27159, 27062, 26964, 26867 ;240->247 + DW 26770, 26674, 26577, 26482, 26386, 26291, 26196, 26102 ;248->255 + DW 26008 ; 256 + +ENDIF ; USEFPUCODE + +; + +InitCommandTable Label Word + DW Offset InitNoCommand, Offset InitCommandA + DW Offset InitCommandB, Offset InitCommandC + DW Offset InitCommandD, Offset InitCommandE + DW Offset InitCommandF, Offset InitCommandG + DW Offset InitCommandH, Offset InitCommandI + DW Offset InitCommandJ, Offset InitCommandK + DW Offset InitCommandL, Offset InitCommandM + DW Offset InitCommandN, Offset InitCommandO + DW Offset InitCommandP, Offset InitCommandQ + DW Offset InitCommandR, Offset InitCommandS + DW Offset InitCommandT, Offset InitCommandU + DW Offset InitCommandV, Offset InitCommandW + DW Offset InitCommandX, Offset InitCommandY + DW Offset InitCommandZ, Offset InitNoCommand + DW Offset InitNoCommand, Offset InitNoCommand + DW Offset InitNoCommand, Offset InitNoCommand + +CommandTable Label Word + DW Offset NoCommand, Offset NoCommand + DW Offset NoCommand, Offset NoCommand + DW Offset CommandD, Offset CommandE + DW Offset CommandF, Offset CommandG + DW Offset CommandH, Offset CommandI + DW Offset CommandJ, Offset CommandK + DW Offset CommandL, Offset NoCommand + DW Offset CommandN, Offset NoCommand + DW Offset CommandP, Offset CommandQ + DW Offset CommandR, Offset CommandS + DW Offset CommandT, Offset CommandH + DW Offset NoCommand, Offset CommandW + DW Offset NoCommand, Offset CommandY + DW Offset NoCommand, Offset NoCommand + DW Offset NoCommand, Offset NoCommand + +VolumeEffectTable Label Word + DW Offset NoCommand, Offset NoCommand ; Last 2 of command + ; table + VolumeComA + ; and VolumeComB + DW Offset VolumeCommandC, Offset VolumeCommandD + DW Offset VolumeCommandE, Offset VolumeCommandF + DW Offset VolumeCommandG, Offset CommandH + + +RetrigOffsets Label + DW CommandQ_0, CommandQ_1, CommandQ_2, CommandQ_3 + DW CommandQ_4, CommandQ_5, CommandQ_6, CommandQ_7 + DW CommandQ_8, CommandQ_9, CommandQ_A, CommandQ_B + DW CommandQ_C, CommandQ_D, CommandQ_E, CommandQ_F + +;Ŀ +; Sound Driver Data +; + +IF OLDDRIVER + DriverID DB "Impulse Tracker Sound Driver" +ELSE + DriverID DB "Impulse Tracker Advanced Sound Driver" +ENDIF + +ALIGN 2 +SoundDriverSegment DW 0 + +;******************* + +DriverVariableTable Label +DriverMaxChannels DW 32 +StopEndOfPlaySection DW 0 +DefaultChannels DW 32 +DriverFlags DW 0 ; Bit 1 = MIDI Out supported + ; Bit 2 = Hiqual + ; Bit 3 = Output waveform data available + +IF OLDDRIVER + DB 64 - ($ - DriverVariableTable) Dup (0) +ELSE + DB 16 - ($ - DriverVariableTable) Dup (0) +ENDIF + + +ALIGN 4 + +StartDriverFunctions Label +DriverDetectCard DD 0 +DriverInitSound DD 0 +DriverReinitSound DD 0 +DriverUninitSound DD 0 + +DriverPoll DD 0 + +DriverSetTempo DD 0 +DriverSetMixVolume DD 0 +DriverSetStereo DD 0 + +DriverLoadSample DD 0 +DriverReleaseSample DD 0 +DriverResetMemory DD 0 +DriverGetStatus DD 0 + +DriverSoundCardScreen DD 0 +DriverGetVariable DD 0 +DriverSetVariable DD 0 + +DriverMIDIOut DD 0 +DriverGetWaveform DD 0 + +EndDriverFunctions Label + +IF OLDDRIVER + DD 63-(EndDriverFunctions-StartDriverFunctions)/4 Dup (0) +ELSE + DD 31-(EndDriverFunctions-StartDriverFunctions)/4 Dup (0) +ENDIF + DW 0 + +DriverLength DW 0 + +DriverRequiredFunctions Label + DD DWord Ptr Update + DD DWord Ptr Music_GetSampleHeader + DD DWord Ptr Music_GetSampleLocation + DD DWord Ptr Music_FarUpdateSampleLocation + DD DWord Ptr E_GetEMSPageFrame + DD DWord Ptr E_SaveEMSPageFrame + DD DWord Ptr E_RestoreEMSPageFrame + DD DWord Ptr Music_GetTempo + DD DWord Ptr M_FunctionHandler + DD DWord Ptr SetInfoLine2 + DD DWord Ptr Music_SoundCardLoadAllSamples + DD DWord Ptr GlobalKeyList + DD DWord Ptr IdleUpdateInfoLine + DD DWord Ptr F_DrawHeader + DD DWord Ptr PE_FillHeader + DD DWord Ptr D_GotoStartingDirectory + DD DWord Ptr D_GetFileName + DD DWord Ptr D_SetDriveDirectoryFar + DD DWord Ptr Music_Stop + DD DWord Ptr GetEnvironment + DD DWord Ptr Music_GetSlaveChannelInformationTable + DD DWord Ptr RecalculateAllVolumes + DD DWord Ptr MIDIBufferEmpty + DD DWord Ptr MIDISend + DD DWord Ptr S_GetDestination + DD DWord Ptr S_DrawString + +;Ŀ +; Functions +; + +;Ŀ +; Command/Effect (call it what you like) information here!! +; +; For initialisation, DS:DI points to host channel data. +; Registers for use: All except DS:DI & ES (points to SongDataSegment) +; +; For update, DS:DI points to host channel data. +; Registers for use: AX, BX, DX, ES, SI +; + +Proc RecalculateAllVolumes Far + + Mov CX, NumChannels + Mov SI, Offset SlaveChannelInformationTable + +RecalculateAllVolumes1: + Or Byte Ptr [SI], 18 + + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ RecalculateAllVolumes1 + + Ret + +EndP RecalculateAllVolumes + +; + +Proc InitPlayInstrument ; BX = instrument offset + + Push ECX + + Mov [SI+30h], BX ; InsOffset + + Mov AL, [ES:BX+11h] ; NNA + Mov [SI+3Bh], AL + + Mov AX, [ES:BX+12h] ; DCT and DCA + Mov [SI+28h], AX + + Mov AX, [DI+0Ch] ; MCh and MPr + Test AL, AL + JZ InitPlayInstrumentNoMIDI + + Mov [SI+3Ch], AX + Mov AX, [ES:BX+3Eh] ; MidiBank + Mov [SI+3Eh], AX + Mov AL, [DI+3] + Mov [SI+0Bh], AL + +InitPlayInstrumentNoMIDI: + Mov DX, [DI+2Eh] ; ChannelVol=DH, Pan=DL + + Mov AL, [ES:BX+19h] ; Instrument pan + Mov [SI+23h], DH + + Test AL, 80h + JNZ AllocatePan1 + + Mov DL, AL + +AllocatePan1: + Push BX ; Check for sample pan + + Mov BL, [DI+0Fh] + And BX, 0FFh + JZ InitPlayInstrumentNoSamplePan + + Add BX, BX + Mov BX, [ES:64910+BX] ; BX = sample offset + Mov AL, [ES:BX+2Fh] + Test AL, AL + + JNS InitPlayInstrumentNoSamplePan + + And AL, 7Fh + Mov DL, AL + +InitPlayInstrumentNoSamplePan: + Pop BX + + Cmp DL, 100 + JE AllocatePanSurround + + Xor DH, DH + Mov AL, [DI+3] ; Note + Mov CX, [ES:BX+16h] ; Pitch pan separation + Sub AL, CH + IMul CL + + SAR AX, 3 + + Add AX, DX + JS AllocatePan2 + Cmp AX, 64 + JBE AllocatePan3 + + Mov AL, 64 + Jmp AllocatePan3 + +AllocatePan2: + Xor AL, AL + Jmp AllocatePan3 + +AllocatePanSurround: + Mov AL, 100 + +AllocatePan3: + Mov AH, AL + Xor ECX, ECX ; Envelope init + Mov [SI+2Ah], AX ; Write panning + + Mov [SI+58h], ECX + Mov [SI+5Ch], CX + Mov [SI+60h], ECX + Mov [SI+68h], ECX + Mov [SI+6Ch], CX + Mov [SI+70h], ECX + Mov [SI+78h], ECX + Mov [SI+7Ch], CX + Mov DWord Ptr [SI+50h], 400000h ; 64*65536 + + Mov AH, [ES:BX+1D4h] + Mov AL, [ES:BX+182h] + And AX, 101h + ShL AH, 1 + Or AH, AL + Mov AL, [ES:BX+130h] + ShL AH, 1 + And AL, 1 + Or AH, AL + ShL AH, 4 + Or AX, 133h + + Mov Word Ptr [SI], AX + + Push DI + + Mov DI, LastSlaveChannel + Test DI, DI + JZ InitInstrumentCarry + +InitInstrumentVolumeCarry: + Mov AL, [ES:BX+130h] + And AL, 9 + Cmp AL, 9 + JNE InitInstrumentPanCarry + +; Transfer volume data + Mov ECX, [DI+50h] + Mov EDX, [DI+54h] + Mov [SI+50h], ECX + Mov [SI+54h], EDX + Mov ECX, [DI+58h] + Mov DX, [DI+5Ch] + Mov [SI+58h], ECX + Mov [SI+5Ch], DX + +InitInstrumentPanCarry: + Mov AL, [ES:BX+182h] + And AL, 9 + Cmp AL, 9 + JNE InitInstrumentPitchCarry +; Transfer pan data + Mov ECX, [DI+60h] + Mov EDX, [DI+64h] + Mov [SI+60h], ECX + Mov [SI+64h], EDX + Mov ECX, [DI+68h] + Mov DX, [DI+6Ch] + Mov [SI+68h], ECX + Mov [SI+6Ch], DX + + +InitInstrumentPitchCarry: + Mov AL, [ES:BX+1D4h] + And AL, 9 + Cmp AL, 9 + JNE InitInstrumentCarry +; Transfer pitch data + Mov ECX, [DI+70h] + Mov EDX, [DI+74h] + Mov [SI+70h], ECX + Mov [SI+74h], EDX + Mov ECX, [DI+78h] + Mov DX, [DI+7Ch] + Mov [SI+78h], ECX + Mov [SI+7Ch], DX + +InitInstrumentCarry: + Pop DI + + Or Byte Ptr [DI], 80h ; Apply random volume/pan + + Cmp Byte Ptr [DI+0Ch], 0 + JNE InitPlayInstrumentNoSample + + Push BX + Mov BX, [ES:BX+3Ah] ; Initial filter cutoff +; If IFC bit 7 == 1, then set filter cutoff + + Mov Word Ptr [SI+3Eh], 0FFh + +; Test BL, 8080h +; JNZ InitPlayInstrumentFilter +; +;; No filters, reset devices. +; Mov BL, 7Fh +; Call SetFilterCutoff +; Xor BL, BL +; Call SetFilterResonance +; +; Jmp InitPlayInstrumentFilterResonance +; +;InitPlayInstrumentFilter: + Test BL, BL + JNS InitPlayInstrumentFilterCutoff + + And BL, 7Fh +; Mov [SI+3Eh], BL + Call SetFilterCutoff + +InitPlayInstrumentFilterCutoff: +; If IFR bit 7 == 1, then set filter resonance + Test BX, BX + JNS InitPlayInstrumentFilterResonance + + Mov BL, BH + And BL, 7Fh + Mov [SI+3Fh], BL + Call SetFilterResonance + +InitPlayInstrumentFilterResonance: + Pop BX + +InitPlayInstrumentNoSample: + Pop ECX + + Ret + +EndP InitPlayInstrument + +; + +Proc ApplyRandomValues + + Mov SI, [DI+24h] + Mov BX, [SI+30h] + + And Byte Ptr [DI], Not 80h + + Call Random ; AL = -128->+127 + + Mov AH, [ES:BX+1Ah] ; Random volume, 0->100 + Test AH, AH + JZ RandomVolumeEnd + + IMul AH ; AX = -12800->12700 + SAR AX, 6 ; AX = -200->+198(.4) + Inc AX ; AX = -199->+199 + + MovZX DX, Byte Ptr [SI+24h] ; Sample volume set + Mov CX, 199 + Push DX + IMul DX ; AX = -199*128->199*128 + ; AX = -25472->25472 + + IDiv CX ; AX = -128->+128 + Pop CX + Add AX, CX + + Cmp AX, 0 + JL RandomVolume3 + Cmp AX, 128 + JG RandomVolume4 + + Mov [SI+24h], AL + Jmp RandomVolumeEnd + +RandomVolume3: + Mov Byte Ptr [SI+24h], 0 + Jmp RandomVolumeEnd + +RandomVolume4: + Mov Byte Ptr [SI+24h], 128 + +RandomVolumeEnd: + Call Random ; AL = -128->+127 + + Mov AH, [ES:BX+1Bh] ; Random pan, 0->64 + Test AH, AH + JZ RandomPanEnd + + Xor DX, DX + IMul AH ; AX = -64*128->64*127, -8192->8128 + Mov DL, [SI+2Ah] + SAR AX, 7 + Cmp DL, 100 + JE RandomPanEnd + Add DX, AX + JS RandomPan1 + Cmp DX, 64 + JA RandomPan2 + + Mov DH, DL + Mov [SI+2Ah], DX + Ret + +RandomPan2: + Mov Word Ptr [SI+2Ah], 4040h + Ret + +RandomPan1: + Mov Word Ptr [SI+2Ah], 0 + +RandomPanEnd: + Ret + +EndP ApplyRandomValues + +; + +LastMIDIByte DB 0FFh + +Proc MIDISendFilter + + Test CS:DriverFlags, 1 + JZ MIDISendFilter2 + + Test AL, AL + JNS MIDISendFilter1 + Cmp AL, 0F0h + JAE MIDISendFilter1 + + Cmp AL, CS:LastMIDIByte + JE MIDISendFilter2 + + Mov CS:LastMIDIByte, AL + +MIDISendFilter1: + Call DriverMIDIOut + +MIDISendFilter2: + Ret + +EndP MIDISendFilter + Assume DS:Nothing + +; + +Proc SetFilterCutoff ; Given BL = filtervalue. + ; Assumes that channel is non-disowned + + Push DI + + Mov DI, [SI+38h] + + Mov AL, 0F0h + Call MIDISendFilter + Mov AL, 0F0h + Call MIDISendFilter + Xor AL, AL + Call MIDISendFilter + Mov AL, BL + Call MIDISendFilter + + Pop DI + Ret + +EndP SetFilterCutoff + +; + +Proc SetFilterResonance ; Given BL = filtervalue. + ; Assumes that channel is non-disowned + + Push DI + + Mov DI, [SI+38h] + + Mov AL, 0F0h + Call MIDISendFilter + Mov AL, 0F0h + Call MIDISendFilter + Mov AL, 1 + Call MIDISendFilter + Mov AL, BL + Call MIDISendFilter + + Pop DI + Ret + +EndP SetFilterResonance + +; + +MIDIPitchDepthSent DW 0 + +Proc MIDITranslate ; Assumes DS:SI points to slave + ; And DS:DI points to host. + ; BX = offset of MIDI command to interpret + + Assume DS:Music + + Test DriverFlags, 1 + JZ MIDITranslateEnd + + PushA + + Cmp BX, 0F000h + JB MIDITranslateParameterised + +; Internal MIDI commands. + + Test Byte Ptr [ES:2Ch], 64 ; Do pitch wheel? + JZ MIDITranslateInternalEnd + +; Pitch wheel +; Formula is: Depth = 16384*12 / PitchWheelDepth * log2(Freq / OldFreq) +; Do calculation, check whether pitch needs to be sent. + + Xor EAX, EAX + Mov AL, [ES:35h] ; AL = PWD + + Test AL, AL ; No depth! + JZ MIDITranslateInternalEnd + + Mov DWord Ptr [ChannelCountTable+200], EAX ; scratch area + +IFE USEFPUCODE ; If FPU code is being used, FP registers are already saved + FNSave [ChannelCountTable] ; Scratch area + FNInit +ENDIF + FLd [PitchDepthConstant] + FIDiv DWord Ptr [ChannelCountTable+200] + FILd DWord Ptr [SI+10h] ; Current pitch + FIDiv DWord Ptr [SI+1Ch] ; Original pitch + FYL2X + FIStP DWord Ptr [ChannelCountTable+200] +IFE USEFPUCODE + FRstor [ChannelCountTable] +ENDIF + +; OK.. [ChannelCountTable] contains pitch depth. +; Have to check: +; a) Within ranges? +; b) Comparison to old pitch for this channel + + Mov CL, [SI+3Ch] + Mov AX, 1 + Dec CL + JS MIDITranslateInternalEnd + + Cmp DWord Ptr [ChannelCountTable+200], 0 + JE MIDIPitchDepthSent1 + + ShL AX, CL + Test MIDIPitchDepthSent, AX + JNZ MIDIPitchDepthSent1 + + Or MIDIPitchDepthSent, AX + +; Send MIDI Pitch depth stuff + + Push SI + + Mov AL, 0B0h + Or AL, CL + Call MIDISendFilter + + Mov DX, 5 + Mov SI, Offset MIDIPitchSendString + +Music_SendPitchDepth1: + LodsB + Call MIDISendFilter + Dec DX + JNZ Music_SendPitchDepth1 + + Pop SI + + Mov AL, [ES:35h] + Call MIDISendFilter + +MIDIPitchDepthSent1: + Mov EAX, DWord Ptr [ChannelCountTable+200] + Add EAX, 2000h + JNS PitchRange1 + + Xor EAX, EAX + +PitchRange1: + Cmp EAX, 4000h + JL PitchRange2 + + Mov AX, 3FFFh + +PitchRange2: + Mov BL, [SI+3Ch] ; BL = channel + And BX, 0FFh + Add BX, BX + Cmp [MIDIPitch+BX-2], AX + JE MIDITranslateInternalEnd + + Mov [MIDIPitch+BX-2], AX + +; Output pitch change + + Mov AL, 0E0h + Or AL, CL + + Call MIDISendFilter ; Ec command + + Mov AL, Byte Ptr [MIDIPitch+BX-2] + And AL, 7Fh + Call MIDISendFilter + + Mov AX, [MIDIPitch+BX-2] + ShR AX, 7 + And AL, 7Fh + Call MIDISendFilter + +MIDITranslateInternalEnd: + PopA + Ret + +; Now for user input MIDI stuff. + +MIDITranslateParameterised: + Push FS + + Xor AX, AX + Xor CX, CX + Mov FS, MIDIDataArea + +MIDITranslate1: + Mov AH, [FS:BX] + Inc BX + Test AH, AH + JZ MIDITranslate2 + + Cmp AH, ' ' ; Interpretation time. + JNE MIDITranslateNoSpace + + Test CX, CX + JZ MIDITranslate1 + Jmp MIDITranslateSend + +MIDITranslateNoSpace: + Sub AH, '0' + JC MIDITranslate1 + Cmp AH, 9 + JA MIDITranslateValue1 + + ShL AL, 4 + Or AL, AH + Inc CX + Jmp MIDITranslateValueEnd + +MIDITranslateValue1: + Sub AH, 'A'-'0' + JC MIDITranslate1 + Cmp AH, 'F'-'A' + JA MIDITranslateValue2 + + ShL AL, 4 + Add AH, 10 + Or AL, AH + Inc CX + Jmp MIDITranslateValueEnd + +MIDITranslateValue2: + Sub AH, 'a'-'A' + JC MIDITranslate1 + Cmp AH, 'z'-'a' + JA MIDITranslate1 + + Cmp AH, 'c'-'a' + JNE MIDITranslateValue3 + + Test SI, SI + JZ MIDITranslate1 + +; Mov AH, [DI+0Ch] + Mov AH, [SI+3Ch] + ShL AL, 4 + Dec AH + Or AL, AH + Inc CX + Jmp MIDITranslateValueEnd + +MIDITranslateValue3: + Test CX, CX + JZ MIDITranslateValue4 + + Call MIDISendFilter + + Xor CX, CX + +MIDITranslateValue4: + Mov AL, [DI+7] ; Effect. + Cmp AH, 'z'-'a' ; Zxx? + JE MIDITranslateSend + + Mov AL, [DI+12h] + Cmp AH, 'o'-'a' + JE MIDITranslateSend + + Test SI, SI + JZ MIDITranslate1 + + Mov AL, [SI+32h] ; [DI+0Eh] + Cmp AH, 'n'-'a' ; Note? + JE MIDITranslateSend + + Mov AL, [SI+0Bh] + Cmp AH, 'm'-'a' + JE MIDITranslateSend + + Cmp AH, 'v'-'a' ; Velocity? + JNE MIDITranslateValue7 + + Xor AL, AL + Test Word Ptr [SI], 800h + JNZ MIDITranslateSend + + Mov AL, [SI+22h] ; 0->2^6 + Xor DX, DX + Mul GlobalVolume ; 0->2^13 + Mov DL, [SI+23h] ; Channel volume + Mul DX ; 0->2^19 + SHRD AX, DX, 4 ; 0->2^15 + Mov DL, [SI+24h] ; Sample & Instrument Volume + Mul DX ; 0->2^22 + SHRD AX, DX, 15 ; 0->2^7 + Sub AL, 1 + AdC AL, 1 ; 1->2^7 + JNS MIDITranslateSend + Dec AX +; Mov AL, 7Fh + Jmp MIDITranslateSend + +Comment ~ + Mov AL, [SI+22h] ; 0->64 + Add AL, AL ; 0->128 + Sub AL, 1 + AdC AL, 1 ; 1->128 + Cmp AL, 128 + JB MIDITranslateSend + Dec AX + Jmp MIDITranslateSend +~ + +MIDITranslateValue7: + Cmp AH, 'u'-'a' ; Volume? + JNE MIDITranslateValue8 + + Xor AL, AL + Test Word Ptr [SI], 800h + JNZ MIDITranslateSend + + Mov AL, [SI+20h] ; 0->128 + Sub AL, 1 + AdC AL, 1 ; 1->128 + Cmp AL, 128 + JB MIDITranslateSend + Dec AX + Jmp MIDITranslateSend + +MIDITranslateValue8: + Mov AL, [SI+3Ah] ; HCN + And AL, 7Fh + Cmp AH, 'h'-'a' + JE MIDITranslateSend + + Mov AL, [SI+2Ah] ; Pan set + Cmp AH, 'x'-'a' + JE MIDITranslatePanValue + + Mov AL, [SI+25h] ; Final pan + Cmp AH, 'y'-'a' + JE MIDITranslatePanValue + + Mov AL, [SI+3Dh] + Cmp AH, 'p'-'a' ; Program? + JE MIDITranslateSend + + Mov DX, [SI+3Eh] + Mov AL, DL + Add AL, 1 + AdC AX, 0 + Dec AX + Cmp AH, 'b'-'a' + JE MIDITranslateSend + + Mov AL, DH + Add AL, 1 + AdC AX, 0 + Dec AX + Cmp AH, 'a'-'a' + JE MIDITranslateSend + + Xor AX, AX + Jmp MIDITranslate1 + +MIDITranslatePanValue: + Add AL, AL + Cmp AL, 7Fh + JBE MIDITranslateSend + Dec AX + Cmp AL, 7Fh + JBE MIDITranslateSend + Mov AL, 40h + Jmp MIDITranslateSend + +MIDITranslateValueEnd: + Cmp CL, 2 + JB MIDITranslate1 + +MIDITranslateSend: + Call MIDISendFilter + + Xor AX, AX + Xor CX, CX + Jmp MIDITranslate1 + +MIDITranslate2: + Test CX, CX + JZ MIDITranslate3 + + Call MIDISendFilter + +MIDITranslate3: + Pop FS + PopA + +MIDITranslateEnd: + Ret + +EndP MIDITranslate + Assume DS:Nothing + +; + +Proc AllocateChannel ; Returns SI. Carry set if problems + Assume DS:Music + + Push CX + Mov LastSlaveChannel, 0 + + Test Byte Ptr [ES:2Ch], 4 + JNZ AllocateChannel1 + +AllocateChannel15: ; Sample handler + MovZX SI, Byte Ptr [DI+20h] + Mov AX, SI + ShL SI, 7 ; SLAVECHANNELSIZE + Add SI, Offset SlaveChannelInformationTable + + Test Byte Ptr CS:DriverFlags, 2 + JZ AllocateChannelHiQual1 + Test Byte Ptr [SI], 1 ; Channel on? + JZ AllocateChannelHiQual1 + +; copy out channel + Push CX + Push SI + Push DI + Push ES + + Push DS + Pop ES + + Or Word Ptr [SI], 200h + Or Byte Ptr [SI+3Ah], 80h + + LEA DI, [SI+64*SLAVECHANNELSIZE] + Mov CX, SLAVECHANNELSIZE/4 + Rep MovsD + + Pop ES + Pop DI + Pop SI + Pop CX + +AllocateChannelHiQual1: + Mov [DI+24h], SI + Mov [SI+38h], DI + Mov [SI+3Ah], AL + Mov Word Ptr [SI], 133h ; Recalc freq,vol&pan Channel on. + + Mov AX, [DI+2Eh] ; ChannelVol=AH, Pan=AL + Mov [SI+23h], AH + Mov AH, AL + Mov [SI+2Ah], AX + ; Get sample offset. +AllocateChannel3: ; General stuff. + Pop CX + + Mov Word Ptr [SI+26h], 0400h ; FadeOut + Mov Word Ptr [SI+52h], 64 + Mov Word Ptr [SI+3Eh], 0FFh ; Filter cutoff + + Mov AX, [DI+3] + Mov [SI+32h], AX ; Nte&Ins + + Mov BL, [DI+0Fh] + And BX, 0FFh + JZ AllocateChannel21 + Dec BX + + Call I_TagSample + + Mov [SI+36h], BL + + Add BX, BX + Mov BX, [ES:64912+BX] + Mov [SI+34h], BX ; Sample memory offset. + + Xor EAX, EAX + Mov [SI+18h], EAX ; Reset vibrato info. + Mov Word Ptr [SI+62h], AX ; No pan deviation + Mov Word Ptr [SI+72h], AX ; No pitch deviation + Mov Byte Ptr [SI+0Bh], AL ; Reset loop dirn + + Cmp [ES:BX+30h], EAX ; No sample! + JE AllocateChannel21 + + Mov AX, [ES:BX+11h] + Test AH, 1 + JZ AllocateChannel21 ; No sample! + + And AH, 2 + Add AL, AL + Mov [SI+18h], AH + Mov [SI+24h], AL ; Sample volume + + ClC + Ret + +AllocateChannel21: + Mov Word Ptr [SI], 200h + And CH, Not 4 + StC + Ret + +AllocateChannel5: + Pop CX + StC + Ret + +AllocateChannel1: ; Instrument handler! + Mov DX, NumChannels + + Mov AllocateSlaveOffset, Offset SlaveChannelInformationTable + Mov AllocateNumChannels, DX + + Mov BX, MAXSLAVECHANNELS + Cmp Byte Ptr [DI+0Fh], 101 + JNE AllocateChannelNoMIDI + Cmp DX, BX + JE AllocateChannelNoMIDI + + Sub BX, DX ; CX = number of channels remaining + ShL DX, 7 + Mov AllocateNumChannels, BX + Add DX, Offset SlaveChannelInformationTable + Mov AllocateSlaveOffset, DX + +AllocateChannelNoMIDI: + Mov BL, [DI+4] + + Cmp BL, 0FFh + JE AllocateChannel15 + + And EBX, 0FFh + JZ AllocateChannel5 + + Call I_TagInstrument + + Mov BX, [ES:64710+EBX*2] ; ES:BX points to instrument + + Test CH, 4 ; Test Byte Ptr [DI], 4 + JZ AllocateChannel8 + ; New note action handling... + Mov SI, [DI+24h] + + Cmp [SI+30h], BX + JNE AllocateLastChannelDifferentInstrument + + Mov LastSlaveChannel, SI + +AllocateLastChannelDifferentInstrument: + Mov AL, [SI+3Bh] + + Test AL, AL + JZ AllocateChannel20 ; Notecut. + + Or Byte Ptr [SI+3Ah], 80h ; Disown channel + +AllocateHandleNNA: + Cmp Byte Ptr [SI+22h], 0 ; Is volume set = 0? + JE AllocateChannel20 + Cmp Byte Ptr [SI+23h], 0 ; Is channel volume = 0? + JE AllocateChannel20 + Cmp Byte Ptr [SI+24h], 0 ; Is sample volume = 0? + JE AllocateChannel20 + + Cmp AL, 2 + JB AllocateChannel8 ; Note continue + JE AllocateChannel14 ; Note off. + + ; AL = 3 -> Fade + Or Byte Ptr [SI], 8 ; Fade flag. + Jmp AllocateChannel8 + +AllocateChannel14: + Or Byte Ptr [SI], 4 ; Note off.. + + Push BX + Call GetLoopInformation + Pop BX + + Jmp AllocateChannel8 + +AllocateChannel20MIDI: + Or Word Ptr [SI], 200h + Or Byte Ptr [SI+3Ah], 80h ; Disown channel + + Cmp Byte Ptr [DI+0Fh], 101 + JNE AllocateChannel4 ; Sample.. + +AllocateChannelMIDIDC: + Mov SI, AllocateSlaveOffset + Mov CX, AllocateNumChannels + + Mov DL, [DI+0Eh] + Mov DH, [DI+4] + Mov BP, 32h + Mov AH, [DI+0Ch] + Mov CH, [ES:BX+13h] ; CH = DCA + Jmp AllocateChannel6 + +AllocateChannel20: + Cmp Byte Ptr [SI+36h], 100 ; MIDI? + JE AllocateChannel20MIDI + +AllocateChannel20Samples: + Test Byte Ptr CS:DriverFlags, 2 + JNZ AllocateChannelHiQual + + Mov AL, [ES:BX+12h] + Mov Word Ptr [SI], 200h + Test AL, AL + JZ AllocateChannelInstrument + Jmp AllocateChannel11 + +AllocateChannelHiQual: + Or Word Ptr [SI], 200h + Or Byte Ptr [SI+3Ah], 80h ; Disown channel + Jmp AllocateChannel4 + +AllocateChannel8: + Cmp Byte Ptr [DI+0Fh], 101 + JE AllocateChannelMIDIDC + + Mov AL, [ES:BX+12h] + Test AL, AL + JZ AllocateChannel4 ; Duplicate check off. + +AllocateChannel11: ; Duplicate check... + Mov SI, AllocateSlaveOffset + Mov CX, AllocateNumChannels + + Mov DX, [DI+3] ; DX = note + Mov BP, 32h + Cmp AL, 1 + JE AllocateDCT + + Mov BP, 33h ; Duplicate instrument + Mov DL, DH + Cmp AL, 3 + JE AllocateDCT + + Mov BP, 36h ; Duplicate sample + Mov DL, [DI+0Fh] + Dec DL + JS AllocateChannel4 + +AllocateDCT: + Mov AH, [DI+20h] ; AH = HCN + Or AH, 80h + Mov CH, [ES:BX+13h] ; CH = DCA + +AllocateChannel6: + Test Byte Ptr [SI], 1 + JZ AllocateChannel7 + + Cmp Byte Ptr [DI+0Fh], 101 + JE AllocateChannelMIDIDCT + + Mov AL, [SI+3Ah] ; AL = HCN of slave. + Cmp AH, AL + JNE AllocateChannel7 + ; OK. same channel... now.. + +AllocateChannelMIDIDCT: + Cmp DH, [SI+33h] ; Same inst? + JNE AllocateChannel7 + + Cmp DL, [DS:SI+BP] ; Same note/sample/inst? + JNE AllocateChannel7 + + Cmp Byte Ptr [DI+0Fh], 101 ; New note is a MIDI? + JE AllocateChannelMIDIHandling + + Cmp CH, [SI+29h] + JNE AllocateChannel7 + + Test CH, CH ; Checks for hiqual + JZ AllocateChannel20Samples + + Mov Word Ptr [SI+28h], 0 + Mov AL, CH + Inc AX + Jmp AllocateHandleNNA + +AllocateChannelMIDIHandling: + Cmp Byte Ptr [SI+36h], 100 ; Is current channel a MIDI chan + JNE AllocateChannel7 + + Cmp AH, [SI+3Ch] + JNE AllocateChannel7 + + Or Word Ptr [SI], 200h + Test Byte Ptr [SI+3Ah], 80h + JNZ AllocateChannel7 + + Mov BP, [SI+38h] + Or Byte Ptr [SI+3Ah], 80h + And Byte Ptr [DS:BP], Not 4 + +AllocateChannel7: + Add SI, SLAVECHANNELSIZE + Dec CL + JNZ AllocateChannel6 + +AllocateChannel4: + Mov CX, AllocateNumChannels + Mov SI, AllocateSlaveOffset + + Cmp Byte Ptr [DI+0Fh], 101 + JNE AllocateChannel10 + +; MIDI 'slave channels' have to be maintained if still referenced + + Push DI + +AllocateMIDIChannel1: + Test Byte Ptr [SI], 1 + JNZ AllocateMIDIChannel2 + + ; Have a channel.. check that it's host's slave isn't SI + Mov DI, [SI+38h] + Test DI, DI + JZ AllocateMIDIChannelFound + Cmp SI, [DI+24h] + JNE AllocateMIDIChannelFound + +AllocateMIDIChannel2: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ AllocateMIDIChannel1 + + Pop DI + + Jmp AllocateChannel17 + +AllocateChannel10: + Test Byte Ptr [SI], 1 + JZ AllocateChannelInstrument + + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ AllocateChannel10 + +AllocateChannel17: ; Common sample search + Push BX + Push DI + Push ES + + Push CS + Pop ES + + Mov DI, Offset ChannelCountTable + Xor AX, AX + Mov CX, (100+200)/2 + Rep StosW ; Clear table + Dec AX + Mov CX, 100/2 ; Volumes + Rep StosW + + Pop ES + + Mov CX, AllocateNumChannels + Xor EBX, EBX + Mov DI, AllocateSlaveOffset + +AllocateChannelCommonSample1: + Mov BL, [DI+36h] ; BX = sample pointer into + ; table. + Cmp BL, 99 ; Just for safety + JA AllocateChannelCommonSample2 + + Inc Byte Ptr [ChannelCountTable+BX] + + Mov AH, [ChannelCountTable+BX+300] ; Volume + + Test Byte Ptr [DI+3Ah], 80h ; Disowned channel? + JZ AllocateChannelCommonSample2 + + Cmp AH, [DI+20h] ; Lower Volume? + JBE AllocateChannelCommonSample2 + + Mov AH, [DI+20h] ; Get volume + Mov Word Ptr [ChannelCountTable+EBX+EBX+100], DI ; Store location + Mov [ChannelCountTable+BX+300], AH ; Store volume + +AllocateChannelCommonSample2: + Add DI, SLAVECHANNELSIZE + Dec CX + JNZ AllocateChannelCommonSample1 + + ; OK.. now search table for maximum + ; occurrence of sample... + + Xor EDI, EDI + Xor SI, SI + Mov AH, 2 ; Find maximum count, has to be + ; greater than 2 channels + Mov CX, 100 + +AllocateChannelCommonSample3: + Cmp AH, [ChannelCountTable+DI] + JAE AllocateChannelCommonSample4 + + Mov AH, [ChannelCountTable+DI] + Mov SI, Word Ptr [ChannelCountTable+EDI+EDI+100] + +AllocateChannelCommonSample4: + Inc DI + Dec CX + JNZ AllocateChannelCommonSample3 + + Pop DI + Pop BX + +; Inc AllocateCount1 + + Test SI, SI + JNZ AllocateChannelInstrument + +; Dec AllocateCount1 + + ; Find out which host channel has the most + ; (disowned) slave channels + ; Then find the softest non-single sample + ; in that channel. + Push BX + + Push ES + Push DI + + Push CS + Pop ES + Mov DI, Offset ChannelCountTable + Xor AX, AX + Mov CX, 32 + Rep StosW + + Pop DI + Pop ES + + Xor BX, BX + Mov CX, AllocateNumChannels + Mov SI, AllocateSlaveOffset + +AllocateChannelCount1: + Mov BL, [SI+3Ah] ; Host channel number + And BL, 3Fh + Inc Byte Ptr [ChannelCountTable+BX] + +AllocateChannelCount2: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ AllocateChannelCount1 + +AllocateChannelCountEnd: + ; OK.. search through and find + ; the most heavily used channel + + Mov AX, 100h ; AH = channel count + Xor BX, BX ; AL = channel + Mov CX, 64 ; 64 = physical channels + +AllocateChannelCountSearch1: + Cmp AH, [BX+ChannelCountTable] + JAE AllocateChannelCountSearch2 + + Mov AH, [BX+ChannelCountTable] + Mov AL, BL + +AllocateChannelCountSearch2: + Inc BX + Dec CX + JNZ AllocateChannelCountSearch1 + + Pop BX + + ; AH = channel to use. + Cmp AH, 1 + JBE AllocateChannelSoftestSearch + + Or AL, 80h ; Search for disowned only + + Push BX + Push DI + + Mov BH, [DI+0Fh] + Dec BH + + Mov CX, AllocateNumChannels + Mov DI, AllocateSlaveOffset + Xor SI, SI ; Offset + Mov AH, 0FFh + +AllocateChannelNonSingle1: + Cmp AL, [DI+3Ah] + JNE AllocateChannelNonSingle3 + + Cmp AH, [DI+20h] ; Lower Volume? + JBE AllocateChannelNonSingle3 + + ; Now check if any other + ; channel contains this + ; sample + Cmp BH, [DI+36h] + JE AllocateChannelNonSingle6 + + Push CX + Push SI + + Mov BL, [DI+36h] ; Sample number + Mov Byte Ptr [DI+36h], 0FFh + + Mov SI, AllocateSlaveOffset + Mov CX, AllocateNumChannels + +AllocateChannelNonSingle2: + Cmp BH, [SI+36h] + JE AllocateChannelNonSingle5 + + Cmp BL, [SI+36h] ; A second sample? + JE AllocateChannelNonSingle5 + +AllocateChannelNonSingle4: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ AllocateChannelNonSingle2 + + Mov [DI+36h], BL + + Pop SI + Pop CX + Jmp AllocateChannelNonSingle3 + +AllocateChannelNonSingle5: + Mov [DI+36h], BL + + Pop SI + Pop CX + +AllocateChannelNonSingle6: ; OK found a second sample. + Mov SI, DI ; get offset. + Mov AH, [DI+20h] ; Get volume + +AllocateChannelNonSingle3: + Add DI, SLAVECHANNELSIZE + Dec CX + JNZ AllocateChannelNonSingle1 + + Pop DI + Pop BX + + Test SI, SI + JNZ AllocateChannelSampleSearch +; JNZ AllocateChannelInstrument + + Push BX + Mov SI, AX + And SI, 03Fh + Mov Byte Ptr [ChannelCountTable+SI], 0 + Jmp AllocateChannelCountEnd ; Next cycle... + +AllocateChannelSampleSearch: +; Inc AllocateCount2 + + Push DI + + Mov AL, [SI+36h] + + Mov CX, AllocateNumChannels + Mov DI, AllocateSlaveOffset + Mov AH, 0FFh + +AllocateChannelSampleSearch1: + Cmp AL, [DI+36h] ; Same sample? + JNE AllocateChannelSampleSearch2 + + Test Byte Ptr [DI+3Ah], 80h ; Disowned channel? + JZ AllocateChannelSampleSearch2 + + Cmp AH, [DI+20h] ; Lower Volume? + JBE AllocateChannelSampleSearch2 + + Mov SI, DI ; get offset. + Mov AH, [DI+20h] ; Get volume + +AllocateChannelSampleSearch2: + Add DI, SLAVECHANNELSIZE + Dec CX + JNZ AllocateChannelSampleSearch1 + + Pop DI + + Jmp AllocateChannelInstrument + +AllocateChannelSoftestSearch: + Push DI ; Now search for softest + ; disowned sample + ; (not non-single) + + Mov CX, AllocateNumChannels + Mov DI, AllocateSlaveOffset + Xor SI, SI ; Offset + Mov AH, 0FFh + +AllocateChannel18: + Test Byte Ptr [DI+3Ah], 80h ; Disowned??? + JZ AllocateChannel19 ; No.. then look for next + + Cmp AH, [DI+20h] ; Volume set... + JB AllocateChannel19 + + Mov SI, DI ; get offset. + Mov AH, [DI+20h] ; Get volume + +AllocateChannel19: + Add DI, SLAVECHANNELSIZE + Dec CX + JNZ AllocateChannel18 + + Pop DI + +; Inc AllocateCount3 + + Test SI, SI + JNZ AllocateChannelInstrument + + Pop CX + And CH, Not 4 + + StC + Ret + +AllocateMIDIChannelFound: + Pop DI + +AllocateChannelInstrument: + Mov [DI+24h], SI ; SCOffset + + Mov AL, [DI+20h] + Mov [SI+3Ah], AL ; HCN + + Mov [SI+38h], DI ; HCOffset + + Xor EAX, EAX + Mov [SI+18h], EAX ; Reset vibrato info. + Mov Byte Ptr [SI+0Bh], AL ; Reset loop dirn + + Call InitPlayInstrument + + Mov AL, [ES:BX+18h] + Mov [SI+24h], AL + + Pop CX + + Mov Word Ptr [SI+26h], 0400h ; FadeOut, VolEnv&Pos + + Mov AX, [DI+3] + Cmp Byte Ptr [DI+0Fh], 101 + JNE NoMIDINote + + Mov AL, [DI+0Eh] + +NoMIDINote: + Mov [SI+32h], AX ; Nte&Ins + + Mov BL, [DI+0Fh] + And BX, 0FFh + JZ AllocateChannel21 + Dec BX + + Call I_TagSample + + Mov [SI+36h], BL + + Add BX, BX + Mov BX, [ES:64912+BX] + Mov [SI+34h], BX ; Sample memory offset. + + Cmp DWord Ptr [ES:BX+30h], 0 + JE AllocateChannelInstrument2 ; No sample! + + Mov AX, [ES:BX+11h] + Test AH, 1 + JZ AllocateChannelInstrument2 ; No sample! + + And AH, 2 + Mov [SI+18h], AH + + Mul Byte Ptr [SI+24h] + ShR AX, 6 + Mov [SI+24h], AL ; SI = 0->128 + + ClC + Ret + +AllocateChannelInstrument2: + Mov Word Ptr [SI], 200h + And CH, Not 4 + StC + Ret + +EndP AllocateChannel + Assume DS:Nothing + +; + +Seed1 DW 1234h +Seed2 DW 5678h + +Proc Random + + Push BX + Push CX + Push DX + + Mov AX, Seed1 + Mov BX, Seed2 + Mov CX, BX + Mov DX, BX + + Add AX, BX + Rol AX, CL + Xor AX, DX + XChg CL, CH + Add BX, CX + Add DX, BX + Add CX, AX + Ror BX, 1 + SBB AX, DX + Mov Seed2, DX + Mov Seed1, AX + + Pop DX + Pop CX + Pop BX + + Ret + +EndP Random + +; + +Proc GetLoopInformation + ; Destroys AX, BX, CX, DX + Mov BX, [SI+34h] ; ES:BX points to sample header + Mov AL, [ES:BX+12h] ; AL = sample flags + + Test AL, 30h ; Loop?? + JZ GetLoopInformation4 + + Mov ECX, [ES:BX+34h] ; CX = loopbeg + Mov EDX, [ES:BX+38h] ; DX = loopend + + Mov AH, AL + + Test AL, 20h ; SusLoop? + JZ GetLoopInformation2 + + Test Byte Ptr [SI], 4 + JNZ GetLoopInformation1 + + Mov ECX, [ES:BX+40h] + Mov EDX, [ES:BX+44h] + ShR AH, 1 + Jmp GetLoopInformation2 + +GetLoopInformation1: + Test AL, 10h + JZ GetLoopInformation4 + +GetLoopInformation2: + Test AH, 40h + JNZ GetLoopInformation3 + + Mov AH, 8 + Jmp GetLoopInformation5 + +GetLoopInformation3: + Mov AH, 24 + Jmp GetLoopInformation5 + +GetLoopInformation4: + Xor ECX, ECX + Mov EDX, [ES:BX+30h] + Mov AH, 0 + +GetLoopInformation5: + Cmp [SI+0Ah], AH + JNE GetLoopInformation6 + Cmp [SI+40h], ECX + JNE GetLoopInformation6 + Cmp [SI+44h], EDX + JNE GetLoopInformation6 + + Ret + +GetLoopInformation6: + Mov [SI+0Ah], AH + Mov [SI+40h], ECX + Mov [SI+44h], EDX + Or Word Ptr [SI], 400h ; Loop changed. + + Ret + +EndP GetLoopInformation + +; + +include it_m_eff.inc + +; + +Proc PitchSlideDown ; Expects SI to slave + ; BX = slide value + Assume DS:Music + +IF USEFPUCODE + Neg BX + +EndP PitchSlideDown ; EndP for PitchSlideDown + +ELSE + Test Byte Ptr [ES:2Ch], 8 + JNZ PitchSlideDownLinear + ; Go on to amiga slide down. +EndP PitchSlideDown + +; + +Proc PitchSlideDownAmiga + + Or Byte Ptr [SI], 32 ; recalculate pitch! + + Mov EAX, [SI+10h] + MovZX EBX, BX + Mul EBX ; EDX:EAX = cmd*InitialFreq + + Xor CX, CX ; CX = counter. + + Add EAX, 1712*8363 + AdC EDX, 0 + JZ PitchSlideDownAmiga1 + +PitchSlideDownAmiga2: + ShR EDX, 1 + RCR EAX, 1 + Inc CX + + Test EDX, EDX + JNZ PitchSlideDownAmiga2 + +PitchSlideDownAmiga1: + Mov EBX, EAX ; EBX = 1712*8363+Cmd*InitialFreq + + Mov EAX, 8363*1712 + Mul DWord Ptr [SI+10h] + + JCXZ PitchSlideDownAmiga4 + +PitchSlideDownAmiga5: + ShR EDX, 1 + RCR EAX, 1 + Loop PitchSlideDownAmiga5 + +PitchSlideDownAmiga4: + Cmp EBX, EDX + JBE PitchSlideDownAmiga3 + + Div EBX + + Mov [SI+10h], EAX + +PitchSlideDownAmiga3: + Ret + +EndP PitchSlideDownAmiga + +; + +Proc PitchSlideDownLinear +; Given BX = slide down value = 0->1024 + + Or Byte Ptr [SI], 32 ; recalculate pitch! + + Push DI + Mov DI, Offset LinearSlideDownTable + + Cmp BX, 0Fh + JA PitchSlideDownLinear1 + + Mov DI, Offset FineLinearSlideDownTable + Add BX, BX + Jmp PitchSlideDownLinear2 + +PitchSlideDownLinear1: + ShR BX, 1 + And BX, Not 1 + +PitchSlideDownLinear2: + MovZX EAX, Word Ptr [DI+BX] + Mul DWord Ptr [SI+10h] + SHRD EAX, EDX, 16 + + Mov [SI+10h], EAX + + Pop DI + Ret + +EndP PitchSlideDownLinear + +; + +ENDIF ; USEFPUCODE + +Proc PitchSlideUp ; Expects SI to slave + ; BX = slide value + Test Byte Ptr [ES:2Ch], 8 + JZ PitchSlideUpAmiga + ; Go on to linear slide + +EndP PitchSlideUp + +; + +Proc PitchSlideUpLinear + +IF USEFPUCODE + Mov [CS:SlideValue], BX + FILD Word Ptr [CS:SlideValue] + FMul [CS:Const1_On_768] ; Have SlideValue/768.0 + FLd ST + FRndInt + FSub ST(1), ST + FXCh + F2XM1 + FLd1 + FAdd + FScale + FIMul DWord Ptr [SI+10h] + FIStP DWord Ptr [SI+10h] + FStP ST + +PitchSlideUpFPUFreqCheck: + Or Byte Ptr [SI], 32 ; recalculate pitch! + Cmp DWord Ptr [SI+10h], 07FFFFFFFh + JAE PitchSlideUpLinear1 + Ret + +PitchSlideUpLinear1: ; Turn off channel + Or Word Ptr [SI], 200h + And Byte Ptr [DI], Not 4 +ELSE + + Or Byte Ptr [SI], 32 ; recalculate pitch! + + Push DI + Cmp BX, 0Fh + Mov DI, Offset LinearSlideUpTable + JA PitchSlideUpLinear3 + + Mov DI, Offset FineLinearSlideUpTable + ShL BX, 2 + + Jmp PitchSlideUpLinear2 + +PitchSlideUpLinear3: + And BX, Not 3 + +PitchSlideUpLinear2: + Mov EAX, [SI+10h] + Mul DWord Ptr [DI+BX] + SHRD EAX, EDX, 16 + + Test EDX, 0FFFF0000h + JNZ PitchSlideUpLinear1 + + Mov [SI+10h], EAX + + Pop DI + Ret + +PitchSlideUpLinear1: ; Turn off channel + Pop DI + Or Word Ptr [SI], 200h + And Byte Ptr [DI], Not 4 +; And Byte Ptr [SI], Not 1 +; Or Byte Ptr [SI+1], 2 ; Cut! +; And Byte Ptr [DI], Not 4 + +ENDIF + + Ret + +EndP PitchSlideUpLinear + Assume DS:Nothing + +; + +Proc PitchSlideUpAmiga + +IF USEFPUCODE + Mov [CS:SlideValue], BX + FILD Word Ptr [CS:SlideValue] + FILD DWord Ptr [SI+10h] ; InitFreq, Cmd + FMul ST(1), ST ; InitFreq, Cmd.InitFreq + FLd [CS:Const_14317456] ; 1712*8363, InitFreq, Cmd.InitFreq + FSubR ST(2), ST ; 1712*8363, InitFreq, 1712*8363-Cmd.InitFreq + FMul ; 1712*8363*InitFreq, 1712*8363-Cmd.InitFreq + FDivRP ST(1), ST ; FinalFreq + FIStP DWord Ptr [SI+10h] + Jmp PitchSlideUpFPUFreqCheck + +ELSE + Or Byte Ptr [SI], 32 ; recalculate pitch! + + Mov EAX, [SI+10h] + MovZX EBX, BX + Mul EBX ; EDX:EAX = InitialFreq*Cmd + + Test EDX, EDX + JNZ PitchSlideUpAmiga1 + + Mov ECX, 1712*8363 + Mov EDX, ECX + Sub ECX, EAX ; ECX = 1712*8363-Cmd*InitialFreq + JBE PitchSlideUpAmiga1 + + Mov EAX, [SI+10h] + Mul EDX + Cmp ECX, EDX + JBE PitchSlideUpAmiga1 + + Div ECX + + Mov [SI+10h], EAX + + Ret + +PitchSlideUpAmiga1: ; Turn off channel + Or Word Ptr [SI], 200h + And Byte Ptr [DI], Not 4 +; And Byte Ptr [SI], Not 1 +; Or Byte Ptr [SI+1], 2 ; Cut! +; And Byte Ptr [DI], Not 4 + + Ret +ENDIF + +EndP PitchSlideUpAmiga + +; + +Proc Music_GetWaveForm Far + + Test Byte Ptr CS:DriverFlags, 4 + JZ Music_GetWaveForm1 + + Call [CS:DriverGetWaveform] + + DB 85h + +Music_GetWaveForm1: + StC + Ret + +EndP Music_GetWaveForm + +; + +Proc Music_Poll Far + + Mov AX, CS:PlayMode + Mov BX, CS:CurrentPattern + Jmp [DriverPoll] + +EndP Music_Poll + Assume DS:Nothing + +; + +Proc Music_InitTempo Far + + PushA + Call Music_GetTempo + Call [DriverSetTempo] + PopA + + Ret + +EndP Music_InitTempo + +; + +Proc GetChannels ; Returns min of NumChannels & DriverMaxChannels + ; Also uses default channels if num channels + ; = 0ffffh + Push DS + + Push CS + Pop DS + Assume DS:Music + + Mov AX, CmdLineNumChannels + Cmp AX, 0FFFFh + JNE GetChannels2 + + Mov AX, DefaultChannels + +GetChannels2: + Cmp AX, DriverMaxChannels + JBE GetChannels1 + + Mov AX, DriverMaxChannels + +GetChannels1: + Cmp AX, MAXSLAVECHANNELS + JB GetChannels3 ; MC4 + + Mov AX, MAXSLAVECHANNELS + +GetChannels3: ; MC4 + Mov NumChannels, AX + + Pop DS + Ret + +EndP GetChannels + Assume DS:Nothing + +; + +Proc Music_ReinitSoundCard Far + + Call GetChannels + Call [DriverReinitSound] + Jmp Music_SoundCardLoadAllSamples + +EndP Music_ReinitSoundCard + +; + +Proc Music_UnInitSoundCard Far + + Jmp [DriverUninitSound] + +EndP Music_UnInitSoundCard + +; + +Proc Music_InitMusic Far + + PushAD + Push DS + Push ES + + Xor AX, AX + Mov DS, AX + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset Music_UpdateSampleLocation +IF ENABLEINT3 +ELSE + Mov [DS:0Ch], EAX +ENDIF + + Trace " - Initialising SoundDriver Tables" + + Call Music_ClearDriverTables + Call D_GotoStartingDirectory + + Push CS + Pop DS + + Assume DS:Music + + Trace " - Loading MIDI configuration" + + ; Open MIDI Config file. + Mov AX, 3D00h + Mov DX, Offset MIDIConfigFileName + Int 21h + JC Music_InitMusic1 + + Mov BX, AX + + Mov DS, MIDIDataArea + Xor DX, DX + Mov AH, 3Fh + Mov CX, (128+16+9)*32 + Int 21h + + Mov AH, 3Eh ; Close + Int 21h + +Music_InitMusic1: + Trace " - Initialising playback tables" + + Call Music_Stop + + Pop ES + Pop DS + PopAD + Assume DS:Nothing + + Ret + +EndP Music_InitMusic + +; + +Proc Music_ReleasePattern Far ; AX = pattern number + + Push AX + Push DS + Push SI + Push ES + + LEA SI, [63912+EAX*4] + Push SI + + Mov DS, CS:SongDataArea + + LodsW + Cmp AL, 1 + JB Music_ReleasePattern1 + JA Music_ReleasePattern2 + + LodsW + Mov ES, AX + Mov AH, 49h + Int 21h + Jmp Music_ReleasePattern1 + +Music_ReleasePattern2: + Cmp AL, 3 + JB Music_ReleasePattern3 + JA Music_ReleasePattern1 + + LodsW + Dec AX + Call E_ReleaseBlockEMS + + Jmp Music_ReleasePattern1 + +Music_ReleasePattern3: + LodsW + Call E_ReleaseEMS + +Music_ReleasePattern1: + Pop SI + Mov DWord Ptr [SI], 0 + + Pop ES + Pop SI + Pop DS + Pop AX + + Ret + +EndP Music_ReleasePattern + +; + +Proc Music_GetPattern Far ; AX = pattern number + ; Returns DS:SI points to pattern data. + + Push AX + +; ShL AX, 2 +; Mov SI, 63912 +; Add SI, AX + LEA SI, [63912+EAX*4] + + Mov DS, CS:SongDataArea + + LodsW + Cmp AL, 1 + JE Music_GetPattern1 + JA Music_GetPattern2 + + Push CS + Pop DS + Mov SI, Offset EmptyPattern + + Pop AX + Ret + +Music_GetPattern1: + LodsW + Mov DS, AX + Xor SI, SI + + Pop AX + Ret + +Music_GetPattern2: + Cmp AL, 3 + JB Music_GetPattern3 + + LodsW + Call E_MapAlignedBlockEMS + + Pop AX + Ret + +Music_GetPattern3: + Push CX + Push DX + + MovZX CX, AH + Mov DX, [SI] + Call E_MapEMSMemory + Call E_GetEMSPageFrame + Mov DS, AX + Xor SI, SI + + Pop DX + Pop CX + + Pop AX + Ret + +EndP Music_GetPattern + +; + +Proc Music_GetPatternLocation Far ; AX = pattern number + ; Returns AX = handle + ; EBX = page/offset or + ; seg/offset + ; CX = length + + Call Music_GetPattern ; Returns DS:SI + Mov CX, [SI] + Add CX, 8 ; CX = size of data including header + +Proc Music_GetPatternLocationNoCount Far + + LEA SI, [63912+EAX*4] + + Mov DS, CS:SongDataArea + + LodsW + Cmp AL, 1 + JE Music_GetPatternLocation1 + JA Music_GetPatternLocation2 + + Mov BX, CS + Xor AX, AX + ShL EBX, 16 + Xor DX, DX + Mov BX, Offset EmptyPattern + + Ret + +Music_GetPatternLocation1: + LodsW + Mov BX, AX + ShL EBX, 16 + Xor AX, AX + Xor DX, DX + + Ret + +Music_GetPatternLocation2: + Cmp AL, 3 + JB Music_GetPatternLocation3 + + LodsW ; AX = "Segment" into EMS block + ; Want page = (AX >> 10) + ; offset = (AX << 4) & 0xFFFF + Mov BX, AX + ShL AX, 4 + ShL EBX, 6 + + Mov BX, AX + And EBX, 03F3FFFh + + Call E_GetInternalEMSHandle + Mov DL, 1 + + Ret + +Music_GetPatternLocation3: + LodsW + Xor EBX, EBX + Mov DL, 1 + + Ret + +EndP Music_GetPatternLocationNoCount + +EndP Music_GetPatternLocation + +; + +Proc Music_AllocatePattern Far ; DX = length. + ; SI = Pattern + ; ES:DI points to pattern area + Cmp CS:PatternStorage, 1 + JB Music_AllocatePatternConventionalOnly + JA Music_AllocatePatternEMS2 + +Music_AllocatePatternEMS: ; Try allocating EMS + Xor EAX, EAX + Mov AX, DX + Call E_AllocateBlockEMS + JC Music_AllocatePatternEMS2 + + Mov ES, CS:SongDataArea + LEA DI, [ESI*4+63914] + Inc AX + StosW + Mov Word Ptr [ES:DI-4], 3 + + Push DS + Push SI + + Call E_MapAlignedBlockEMS + + Push DS + Pop ES + Mov DI, SI + + Pop SI + Pop DS + Ret + +Music_AllocatePatternEMS2: + MovZX EAX, DX + ClC + Call E_AllocateEMS + Test AX, AX + JZ Music_AllocatePatternConventional + + Push CX + Push DX + + Mov ES, CS:SongDataArea + LEA DI, [ESI*4+63914] +; Mov DI, SI +; ShL DI, 2 +; Add DI, 63914 + StosW + + Add DX, 16383 + RCR DX, 1 + ShR DX, 13 + Mov CX, DX + Mov DX, AX + Call E_MapEMSMemory + + Mov CH, CL + Mov CL, 2 + + Mov [ES:DI-4], CX + Call E_GetEMSPageFrame + + Mov ES, AX + Xor DI, DI + + Pop DX + Pop CX + + Ret + +Music_AllocatePatternConventionalOnly: + Mov AH, 48h ; How much free? + Mov BX, 0FFFFh + Int 21h + + Cmp BX, -1 + JE Music_AllocatePatternEMS + + Cmp BX, 4096 + JAE Music_AllocatePatternConventional + + ShL BX, 4 ; BX = size in bytes of + ; conv remaining + Cmp DX, BX + JA Music_AllocatePatternEMS + +Music_AllocatePatternConventional: + Mov AH, 48h + Mov BX, DX + + Add BX, 15 + RCR BX, 1 + ShR BX, 3 + + Int 21h + JC Music_AllocatePattern2 + + Push DS + Mov DS, CS:SongDataArea + LEA SI, [ESI*4+63912] +; ShL SI, 2 +; Add SI, 63912 + Mov Word Ptr [SI], 1 + Mov [SI+2], AX + + Pop DS + Mov ES, AX + Xor DI, DI + + Ret + +Music_AllocatePattern2: + Xor AX, AX + Mov ES, AX + + Ret + +EndP Music_AllocatePattern + +; + +Proc Music_AllocateSample Far ; AX = Sample number, 0 based + ; EDX = length + ; Returns ES:DI, ES = 0 if not. + Push EAX + Push BX + Push CX + Push EDX + Push DS + Push SI + + Mov AH, 2 + Call Music_ReleaseSample + And AX, 0FFh + + Add EDX, 8 ; Extra 8 bytes allocated.. + + Mov BX, AX + Add BX, BX + Mov DS, CS:SongDataArea + Mov SI, [64912+BX] + + Cmp EDX, 1024 + JA Music_AllocateSample5 + + Mov EBX, EDX + Add EBX, 15 + RCR EBX, 1 + SHR EBX, 3 + + Mov AH, 48h + Int 21h + + JNC Music_AllocateSample4 + +Music_AllocateSample5: + Mov EAX, EDX + StC + Call E_AllocateEMS + Test AX, AX ; AX = handle + JZ Music_AllocateSample1 + + Mov Byte Ptr [DS:SI+48h], 2 + Mov [DS:SI+4Ah], AX + Add EDX, 16383 + RCR EDX, 1 + ShR EDX, 13 + Mov [DS:SI+49h], DL + + Xor CH, CH + Mov CL, DL + Mov DX, AX + Call E_MapEMSMemory + + Call E_GetEMSPageFrame + Mov ES, AX + Xor DI, DI + Or Byte Ptr [SI+12h], 1 + + Jmp Music_AllocateSample3 + +Music_AllocateSample1: + Cmp EDX, 1048576 + JAE Music_AllocateSample2 + + Mov EBX, EDX + Add EBX, 15 + RCR EBX, 1 + SHR EBX, 3 + + Mov AH, 48h + Int 21h + + JC Music_AllocateSample2 + +Music_AllocateSample4: + Mov Byte Ptr [SI+48h], 1 + Mov [SI+4Ah], AX + Or Byte Ptr [SI+12h], 1 + + Mov ES, AX + Xor DI, DI + Jmp Music_AllocateSample3 + +Music_AllocateSample2: + And Byte Ptr [SI+12h], 0F0h + + Xor AX, AX + Mov ES, AX + +Music_AllocateSample3: + Pop SI + Pop DS + Pop EDX + Pop CX + Pop BX + Pop EAX + Ret + +EndP Music_AllocateSample + +; + +Proc Music_ReleaseSample Far ; AX = sample number, 0 based + ; AH = 1 = called from network + ; = 2 = called from allocate + + PushAD + Push DS + Push ES + + Mov DX, AX + And AX, 0FFh + + Mov BX, AX + Add BX, BX + Mov DS, CS:SongDataArea + Mov BX, [BX+64912] + ; DS:BX points to sample + PushAD + Mov SI, BX + Call [DriverReleaseSample] + PopAD + + Mov DI, BX + + Test Byte Ptr [BX+12h], 1 + JZ Music_ReleaseSample1 ; Used to be ReleaseSample5. + ; Changed for network code + + Mov AL, [BX+48h] + Cmp AL, 1 + JB Music_ReleaseSample5 + JE Music_ReleaseSample2 + Cmp AL, 2 + JA Music_ReleaseSample1 + + Mov AX, [BX+4Ah] + Call E_ReleaseEMS + Jmp Music_ReleaseSample1 + +Music_ReleaseSample2: + Mov ES, [BX+4Ah] + Mov AH, 49h + Int 21h + +Music_ReleaseSample1: + Mov DWord Ptr [DI+30h], 0 + Mov DWord Ptr [DI+48h], 0 + + Cmp DH, 1 + JA Music_ReleaseSample5 + JE Music_ReleaseSample6 + +IF NETWORKENABLED + Mov AH, DL + Mov AL, NETWORK_DELETESAMPLEOBJECT + Call Network_AddWordToQueue +ENDIF + +Music_ReleaseSample6: + Push DS + Pop ES + Xor AX, AX + And Byte Ptr [DI+12h], 0FEh + Add DI, 14h + Mov CX, 3Ch/2 + Rep StosW + +Music_ReleaseSample5: + Pop ES + Pop DS + PopAD + Ret + +EndP Music_ReleaseSample + +; + +Proc Music_ClearSampleName Far ; AX = Sample number (0 based) + + Push CX + Push DS + Push SI + Push ES + Push DI + + Push CS + Pop DS + Mov SI, Offset SampleHeader + + Mov ES, CS:SongDataArea + Mov DI, AX + Add DI, DI + Mov DI, [ES:64912+DI] + + Mov CX, 80 + Rep MovsB + + Pop DI + Pop ES + Pop SI + Pop DS + Pop CX + Ret + +EndP Music_ClearSampleName + +; + +Proc Music_ClearAllSampleNames Far + + Push AX + Push CX + + Mov CX, 100 + +Music_ClearAllSampleNames1: + Mov AX, CX + Dec AX + Call Music_ClearSampleName + + Loop Music_ClearAllSampleNames1 + + Pop CX + Pop AX + + Ret + +EndP Music_ClearAllSampleNames + +; + +Proc Music_ReleaseAllSamples Far + + Push AX + Push CX + + Mov CX, 100 + +Music_ReleaseAllSamples1: + Mov AX, CX + Dec AX + Call Music_ReleaseSample + + Loop Music_ReleaseAllSamples1 + + Pop CX + Pop AX + Ret + +EndP Music_ReleaseAllSamples + +; + +Proc Music_ReleaseAllPatterns Far + + Push AX + Push CX + + Mov CX, 200 + +Music_ReleaseAllPatterns1: + Mov AX, CX + Dec AX + Call Music_ReleasePattern + Loop Music_ReleaseAllPatterns1 + + Pop CX + Pop AX + Ret + +EndP Music_ReleaseAllPatterns + +; + +Proc Music_ClearInstrument Far ; AX = Instrument number + ; (0 based) + + Push CX + Push DS + Push SI + Push ES + Push DI + + Push CS + Pop DS + Assume DS:Music + + Mov DI, AX + Add DI, DI + Mov ES, SongDataArea + Mov DI, [ES:DI+64712] ; ES:DI points to inst. + Mov SI, Offset InstrumentHeader + Mov CX, 554 + Rep MovsB + + Pop DI + Pop ES + Pop SI + Pop DS + Pop CX + Ret + +EndP Music_ClearInstrument + Assume DS:Nothing + +; + +Proc Music_ClearAllInstruments Far + + Mov AX, 99 + +Music_ClearAllInstruments1: + Call Music_ClearInstrument + Dec AX + JNS Music_ClearAllInstruments1 + + Ret + +EndP Music_ClearAllInstruments + +; + +Proc Music_UnInitMusic Far + + Call Music_UnInitSoundCard + Call Music_UnloadDriver + + Cmp CS:SongDataArea, 0 + JE Music_UnInitMusic1 + + Call Music_ReleaseAllPatterns + Call Music_ReleaseAllSamples + +Music_UnInitMusic1: + Mov ES, CS:SongDataArea + Mov AH, 49h + Int 21h + + Ret + +EndP Music_UnInitMusic + +; + +Proc Music_GetSongSegment Far + + Mov AX, CS:SongDataArea + Ret + +EndP Music_GetSongSegment + +; + +Proc Music_UnloadDriver + + Xor AX, AX + XChg AX, CS:SoundDriverSegment + Test AX, AX + JZ Music_UnloadDriver1 + + Mov ES, AX + Mov AH, 49h + Int 21h + +Music_UnloadDriver1: + Ret + +EndP Music_UnloadDriver + +; + +Proc NoFunction2 + + Push CS + Pop DS + Mov SI, Offset NoSoundCardMsg + +Proc NoFunction Far + + Xor AX, AX + StC + Ret + +EndP NoFunction + +EndP NoFunction2 + +; + +Proc Music_ClearDriverTables + ; Makes all of them point to + ; Xor AX, AX, StC, RetF + Mov AX, CS + Mov ES, AX + + ShL EAX, 16 + Mov AX, Offset NoFunction2 + Mov DI, Offset StartDriverFunctions + StosD + StosD + + Mov AX, Offset NoFunction +IF OLDDRIVER + Mov CX, 61 +ELSE + Mov CX, 29 +ENDIF + Rep StosD + + Xor EAX, EAX + StosD + + Mov DriverMaxChannels, 32 + + Ret + +EndP Music_ClearDriverTables + +; + +Proc Music_LoadDriver ; Given DS:DX = filename + Assume DS:Nothing + +IFDEF DEBUG + + PushA + Push ES + Push DS + + Mov DI, 0B800h + Mov ES, DI + + Push CS + Pop DS + Assume DS:Music + + Mov DI, [ScreenOffset] + Mov SI, Offset LoadDriverMessage + Mov AH, 2 + +LoadDriverMessage1: + LodsB + StosW + Test AL, AL + JNZ LoadDriverMessage1 + + Pop DS + Assume DS:Nothing + + Mov SI, DX + +LoadDriverMessage2: + LodsB + StosW + Test AL, AL + JNZ LoadDriverMessage2 + + Add [CS:ScreenOffset], 160 + + Pop ES + PopA + +ENDIF + + Mov AX, 3D00h + Int 21h + ClD + JNC Music_LoadDriver2 + +IFDEF DEBUG + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Music + + Mov DI, 0B800h + Mov ES, DI + + Mov SI, Offset UnableToReadFileMessage + Mov DI, [ScreenOffset] + Mov AH, 2 + +UnableToReadFileLoop: + LodsB + StosW + Test AL, AL + JNZ UnableToReadFileLoop + + Add [ScreenOffset], 160 + + Pop ES + Pop DS + PopA + Assume DS:Nothing + +ENDIF + + Jmp Music_LoadDriverNoClose + +Music_LoadDriverError: + Mov AH, 3Eh + Int 21h + +Music_LoadDriverNoClose: + ClD + + Call Music_ClearDriverTables + + Push CS + Pop DS + + StC + Ret + +Music_LoadDriver2: + Mov BX, AX ; BX = file handle + Mov AH, 3Fh ; Read file + +IF OLDDRIVER + Mov CX, 256 +ELSE + Mov CX, 128 +ENDIF + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:Music + + Mov DX, Offset StartDriverFunctions + Mov SI, DX + Int 21h + JC Music_LoadDriverError + Cmp AX, CX + JNE Music_LoadDriverError + +IF OLDDRIVER + Mov CX, 28 +ELSE + Mov CX, 37 ; Length of ID +ENDIF + + Mov DI, Offset DriverID + RepE CmpsB + JNE Music_LoadDriverError + + ; OK.. ID OK. Now get length, allocate memory + ; load driver, and fill in headers. + Push BX + + Mov BX, DriverLength + Add BX, 15 + Mov AH, 48h + ShR BX, 4 + Int 21h + Pop BX + JC Music_LoadDriverError ; Insufficient memory + + Mov CX, DriverLength + Mov SoundDriverSegment, AX + Mov DS, AX + Assume DS:Nothing + + Mov DI, AX ; DI = segment of driver... + + Mov AH, 3Fh ; Load driver into memory! + Xor DX, DX + Int 21h + + Push CS + Pop DS + Assume DS:Music + + Mov AH, 3Fh + Mov DX, Offset DriverVariableTable + +IF OLDDRIVER + Mov CX, 64 +ELSE + Mov CX, 16 +ENDIF + Int 21h + + Mov AH, 3Fh + +IF OLDDRIVER + Mov CX, 128 + Mov DX, Offset StartDriverFunctions+128 +ELSE + Mov CX, 64 + Mov DX, Offset StartDriverFunctions+64 +ENDIF + Mov SI, DX + Int 21h + JC Music_LoadDriverError + Cmp AX, CX + JNE Music_LoadDriverError + + Mov AH, 3Eh + Int 21h + + ; Setup reqd function table + SHRD EAX, EDI, 16 ; High word of EAX contains + ; segment... + Mov DI, Offset StartDriverFunctions + +IF OLDDRIVER + Mov CX, 64 +ELSE + Mov CX, 32 +ENDIF + +DriverFunctionLoop1: + LodsW + StosD + Loop DriverFunctionLoop1 + + ; Setup variable table + Mov ES, SoundDriverSegment + Xor DI, DI + +IF OLDDRIVER + Mov CX, 256 +ELSE + Mov CX, 16 +ENDIF + Mov SI, Offset DriverRequiredVariables + Rep MovsB + + Mov SI, Offset DriverRequiredFunctions + +IF OLDDRIVER + Mov CX, 128 +ELSE + Mov CX, 32 +ENDIF + Rep MovsD + +IFDEF DEBUG + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Music + + Mov DI, 0B800h + Mov ES, DI + + Mov SI, Offset DetectingMessage + Mov DI, [ScreenOffset] + Mov AH, 2 + +DetectingMessageLoop: + LodsB + StosW + Test AL, AL + JNZ DetectingMessageLoop + + Add [ScreenOffset], 160 + + Pop ES + Pop DS + PopA + Assume DS:Nothing + +ENDIF + ClC + + Ret + +EndP Music_LoadDriver + +; + +ADSCParams DW 7 Dup (0) + +; + +Proc Music_AutoDetectSoundCard Far + ; Returns DS:SI = string + ; AX, BX, CX, DX, DI = parameters + + Call D_GotoStartingDirectory + + Xor SI, SI + + Mov DX, Word Ptr [CS:DriverName] + And DX, DX + JZ Music_AutoDetectSoundCard1 + + Trace " - Loading specific soundcard driver" + + Cmp DX, 0FFFFh + JE Music_AutoDetectSoundCard4 + + Mov DS, Word Ptr [CS:DriverName+2] + Call Music_LoadDriver + JC Music_AutoDetectSoundCard4 + + Mov AL, 1 ; Forced + Mov BX, TRACKERVERSION + Mov ECX, [CS:DriverName] + Call [DriverDetectCard] + JC Music_AutodetectSoundCard5 + Cmp EAX, 'Jeff' + JE Music_AutoDetectSoundCard4 + +Music_AutodetectSoundCard5: + Call Music_UnloadDriver + Call Music_ClearDriverTables + Jmp Music_AutoDetectSoundCard4 + +Music_AutoDetectSoundCard1: + Trace " - Testing soundcard driver" + + Push SI + Push CS + Pop DS + Assume DS:Music + + Mov Word Ptr [DriverName+2], DS + + Mov BX, [SI+DriverDetectionOrder] + Cmp BX, 0FFFFh + JE Music_AutoDetectSoundCard2 + + Add BX, BX + Mov DX, [DriverNameTable+BX] + Mov Word Ptr [DriverName], DX + Call Music_LoadDriver + JC Music_AutoDetectSoundCard3 + + Xor AX, AX ; Not forced + Mov BX, TRACKERVERSION + Mov ECX, [CS:DriverName] + Call [DriverDetectCard] + JC Music_AutoDetectSoundCard6 + + Cmp EAX, 'Jeff' + JE Music_AutoDetectSoundCard2 + +Music_AutoDetectSoundCard6: + Call Music_UnloadDriver + Call Music_ClearDriverTables + +Music_AutoDetectSoundCard3: + + Pop SI + Add SI, 2 + Jmp Music_AutoDetectSoundCard1 + +Music_AutoDetectSoundCard2: + Pop AX + +Music_AutoDetectSoundCard4: + Call GetChannels + Call [CS:DriverInitSound] + + Mov [CS:ADSCParams+2], DS + + Push CS + Pop DS + Assume DS:Music + + Mov [ADSCParams], SI + Mov [ADSCParams+12], DI + Mov [ADSCParams+10], DX + Mov [ADSCParams+8], CX + Mov [ADSCParams+6], BX + Mov [ADSCParams+4], AX + + Call Music_InitStereo + + Call Music_InitMixTable + + Ret + +EndP Music_AutoDetectSoundCard + Assume DS:Nothing + +; + +Proc Music_ShowAutoDetectSoundCard Far + + Push CS + Pop DS + Assume DS:Music + + Push DWord Ptr [ADSCParams+10] + Push DWord Ptr [ADSCParams+6] + Push [ADSCParams+4] + + LDS SI, DWord Ptr [ADSCParams] + + Mov AH, 20h + Mov DI, (26+28*80)*2 + Call S_DrawString + + Add SP, 10 + Ret + +EndP Music_ShowAutoDetectSoundCard + Assume DS:Nothing + +; + +Proc Music_GetInstrumentMode Far + + Push DS + Mov DS, CS:SongDataArea + Mov AH, [DS:2Ch] + And AH, 4 + + Pop DS + + Ret + +EndP Music_GetInstrumentMode + +; + +Proc UpdateGOTONote ; Get offset & arrayed flag. + + Push DS + Assume DS:Nothing + + Call PE_GetCurrentPattern + ; AX = Pattern number + ; BX = MaxRow + ; DS = PatternDataSegment + Cmp AX, CS:CurrentPattern + JNE UpdateGOTONote1 + + Mov DecodeExpectedPattern, AX + Mov CS:PatternSegment, DS + + Pop DS + Assume DS:Music + Mov NumberOfRows, BX + Mov AX, ProcessRow + Cmp AX, BX + JB UpdateGOTONote2 + + Xor AX, AX + Mov ProcessRow, AX + Mov CurrentRow, AX + +UpdateGOTONote2: + Mov DecodeExpectedRow, AX + + LEA AX, [EAX*4+EAX] ; PatternRowSize = *320 + ShL AX, 6 +; Mov BX, 320 +; Mul BX + Mov PatternOffset, AX + Mov PatternArray, 1 + + Ret + +UpdateGOTONote1: + Pop DS + Assume DS:Music + + Mov AX, CurrentPattern + Mov DecodeExpectedPattern, AX +IF NETWORKENABLED + Call Network_UpdatePatternIfIdle +ENDIF + Call Music_GetPattern + Assume DS:Nothing + ; DS:SI points to pattern. + + LodsW + LodsW ; AX = number of rows + + Mov CX, ProcessRow + Cmp AX, CX + JA UpdateGotoNote3 + + Xor CX, CX + +UpdateGOTONote3: + Mov CurrentRow, CX + Mov ProcessRow, CX + Mov DecodeExpectedRow, CX + Mov NumberOfRows, AX + Add SI, 4 + Inc CX + +UpdateGOTONote10: + Dec CX + JZ UpdateGOTONote5 + +UpdateGOTONote4: ; OK.. now to find the right + ; offset & update tables. + LodsB + Test AL, AL + JZ UpdateGOTONote10 + + Mov DL, AL + + And AX, 7Fh + Dec AX + LEA BX, [EAX*4+EAX] ; BX = AX*5 + ShL BX, 4 ; BX = AX*80 + LEA DI, [HostChannelInformationTable+BX] + + +; And AL, 7Fh +; Dec AL +; Mov AH, HOSTCHANNELSIZE +; Mul AH +; Mov DI, AX +; Add DI, Offset HostChannelInformationTable + ; CS:DI points. + + Mov DH, [CS:DI+2] + Test DL, 80h + JZ UpdateGOTONote6 + + Mov DH, [SI] + Inc SI + Mov [CS:DI+2], DH + +UpdateGOTONote6: + Test DH, 1 + JZ UpdateGOTONote7 + + LodsB + Mov [CS:DI+3], AL + +UpdateGOTONote7: + Test DH, 2 + JZ UpdateGOTONote8 + + LodsB + Mov [CS:DI+4], AL + +UpdateGOTONote8: + Test DH, 4 + JZ UpdateGOTONote9 + + LodsB + Mov [CS:DI+5], AL + +UpdateGOTONote9: + Test DH, 8 + JZ UpdateGOTONote4 + + LodsW + Mov [CS:DI+8], AX + Jmp UpdateGOTONote4 + +UpdateGOTONote5: + Push CS + Pop DS + Assume DS:Music + + Mov PatternOffset, SI + Mov PatternArray, 0 + + Ret + +EndP UpdateGOTONote + Assume DS:Nothing + +; + +Proc PreInitCommand + + Push DS + Push SI + + Push CS + Pop DS + Assume DS:Music + + Test Byte Ptr [DI+2], 33h + JZ PreInitCommandEnd + + Test Byte Ptr [ES:2Ch], 4 + JNZ PreInitCommand1 + +PreInitCommand2: + Mov AX, [DS:DI+3] + Mov [DS:DI+0Eh], AX ; Sample/note + + Jmp PreInitCommandEnd + +PreInitCommand1: ; Have to xlat. + Mov SI, [DS:DI+3] ; Not a note? + And SI, 0FFh + Cmp SI, 120 + JAE PreInitCommand2 + + Mov BL, [DS:DI+4] + And EBX, 0FFh + JZ PreInitCommand2 + + Add SI, SI + Mov BX, [ES:64710+EBX+EBX] + + Mov AX, [ES:BX+3Ch] + Cmp AL, 0 + JE PreInitCommandNoMIDI + Cmp AL, 17 + JNE PreInitCommandMIDI1 + + Mov AL, [DS:DI+20h] + And AL, 0Fh + Inc AL ; AL = HCN + +PreInitCommandMIDI1: + Mov [DS:DI+0Ch], AX + Mov AH, 101 + Mov AL, [ES:BX+SI+40h] +; Mov AL, [DS:DI+3] + Jmp PreInitCommandMIDIEnd + +PreInitCommandNoMIDI: + Mov AX, [ES:BX+SI+40h] + +PreInitCommandMIDIEnd: + Mov [DS:DI+0Eh], AX + Test AH, AH ; No sample? + JZ PreInitCommand4 + +PreInitCommandEnd: + Mov BL, [DS:DI+6] + And EBX, 31 + + Call Word Ptr [InitCommandTable+EBX+EBX] ; Init note + + Or Byte Ptr [DI], 64 + + MovZX BX, Byte Ptr [DI+20h] ; Check whether chn + ; is on + Test Byte Ptr [ES:BX+40h], 80h + JZ PreInitCommand4 + + Test Byte Ptr [DI], 32 + JNZ PreInitCommand4 + + Test Byte Ptr [DI], 4 + JZ PreInitCommand4 ; Channel was off. + + Mov SI, [DI+24h] + Or Byte Ptr [SI+1], 8 + +PreInitCommand4: + Pop SI + Pop DS + Ret + +EndP PreInitCommand + +; + +Proc UpdateNoteData + Assume DS:Music + + Mov PatternLooping, 0 + + Mov AX, CurrentPattern + Cmp AX, DecodeExpectedPattern + JNE UpdateNoteData1 + + Mov AX, CurrentRow + Inc DecodeExpectedRow + Cmp AX, DecodeExpectedRow + JE UpdateNoteData2 + +UpdateNoteData1: + Call UpdateGOTONote + +UpdateNoteData2: + Mov CX, 64 ; 64 channels +; Xor AX, AX ; Just to get rid of "jumps" + Mov DI, Offset HostChannelInformationTable + + Cmp PatternArray, 1 + JE UpdateNoteArrayed + +UpdateNoteCompressed: ; First clear all old command&value. +; Mov CX, 64 ; Done above + +UpdateNoteCompressed1: + And Word Ptr [DI], Not (3+32+64+256) + Add DI, HOSTCHANNELSIZE + Dec CX + JNZ UpdateNoteCompressed1 + + Push DS + + Mov AX, CurrentPattern +IF NETWORKENABLED +; Call Network_UpdatePatternIfIdle +ENDIF + Call Music_GetPattern ; Gets DS + + Mov SI, CS:PatternOffset +; Mov DS, PatternSegment + Assume DS:Nothing + +UpdateNoteCompressed2: + LodsB + Test AL, AL + JZ UpdateNoteCompressed3 ; No more! + ; else... go through decoding. + Mov DL, AL + + And AX, 7Fh + Dec AX + LEA DI, [EAX*4+EAX] + ShL DI, 4 ; HOSTCHANNELSIZE + Add DI, Offset HostChannelInformationTable + + Mov DH, [CS:DI+2] ; mask. + Test DL, 80h + JZ UpdateNoteCompressed4 + + Mov DH, [SI] + Inc SI + Mov [CS:DI+2], DH + +UpdateNoteCompressed4: ; DH = mask + Test DH, 1 + JZ UpdateNoteCompressed6 + + LodsB + Mov [CS:DI+3], AL + +UpdateNoteCompressed6: + Test DH, 2 + JZ UpdateNoteCompressed8 + + LodsB + Mov [CS:DI+4], AL + +UpdateNoteCompressed8: + Test DH, 4 + JZ UpdateNoteCompressed10 + + LodsB + Mov [CS:DI+5], AL + +UpdateNoteCompressed10: + Test DH, 8 + JZ UpdateNoteCompressed11 + + LodsW + Mov [CS:DI+8], AX + Jmp UpdateNoteCompressed13 + +UpdateNoteCompressed11: + Test DH, 80h + JZ UpdateNoteCompressed12 + + Mov AX, [CS:DI+8] + Jmp UpdateNoteCompressed13 + +UpdateNoteCompressed12: + Xor AX, AX + +UpdateNoteCompressed13: + Mov [CS:DI+6], AX + Call PreInitCommand + + Jmp UpdateNoteCompressed2 + +UpdateNoteCompressed3: + Pop DS + Assume DS:Music + + Mov PatternOffset, SI + + Ret + +UpdateNoteArrayed: + Assume DS:Music + + Push DS + + Mov SI, PatternOffset + Mov DS, PatternSegment + Assume DS:Nothing + +; Mov CX, 64 ; 64 channels +; Mov DI, Offset HostChannelInformationTable + +UpdateNoteArrayed1: + Xor DL, DL ; DL = mask. + And Word Ptr [CS:DI], Not (3+32+64+256) + ; Turn off all calling... + + LodsB ; AL = note data. + Cmp AL, NONOTE + JE UpdateNoteArrayed2 + + Mov [CS:DI+3], AL + Or DL, 1 + +UpdateNoteArrayed2: + LodsB + Test AL, AL + JZ UpdateNoteArrayed3 + + Mov [CS:DI+4], AL + Or DL, 2 + +UpdateNoteArrayed3: + LodsB + Cmp AL, 0FFh + JE UpdateNoteArrayed4 + + Mov [CS:DI+5], AL + Or DL, 4 + +UpdateNoteArrayed4: + LodsW + Mov [CS:DI+6], AX + Mov [CS:DI+8], AX + + Test AX, AX + JZ UpdateNoteArrayed5 + + Or DL, 8 + +UpdateNoteArrayed5: + Test DL, DL + JZ UpdateNoteArrayed6 + + Mov [CS:DI+2], DL + Push CX + + Call PreInitCommand + + Pop CX + Assume DS:Nothing + + +UpdateNoteArrayed6: + Add DI, HOSTCHANNELSIZE + Dec CX + JNZ UpdateNoteArrayed1 + + Pop DS + Assume DS:Music + + Mov PatternOffset, SI + + Ret + +EndP UpdateNoteData + Assume DS:Nothing + +; + +Proc UpdateVibrato ; DS:SI points to slavechannelstruct. + + Mov BX, [SI+34h] ; ES:BX points to sample + Mov DL, [ES:BX+4Dh] ; Vibrato depth + Test DL, DL + JZ UpdateVibrato1 + + Mov CX, [SI+1Ah] + Add CL, [ES:BX+4Eh] ; Vibrato rate + AdC CH, 0 + + Cmp CH, DL + JBE UpdateVibrato5 + + Mov CH, DL + +UpdateVibrato5: + Mov [SI+1Ah], CX + + Mov AH, [ES:BX+4Ch] ; AH = speed + Mov BH, [ES:BX+4Fh] ; BH = waveform + Test AH, AH + JZ UpdateVibrato1 + + Cmp BH, 3 + JE UpdateVibrato2 + + Mov BL, [SI+19h] + + Add BL, AH + Mov [SI+19h], BL ; Update pointer. + + Mov AL, [FineSineData+BX] + Jmp UpdateVibrato3 + +UpdateVibrato2: + Call Random + And AL, 127 + Sub AL, 64 + +UpdateVibrato3: + IMul CH + + SAL AX, 2 + MovSX BX, AH + +IFE USEFPUCODE + JS UpdateVibrato4 +ENDIF + JZ UpdateVibrato1 + + Push DI + Mov DI, [SI+38h] + Call PitchSlideUpLinear + Pop DI + +IFE USEFPUCODE + Jmp UpdateVibrato1 + +UpdateVibrato4: + Neg BX + Call PitchSlideDownLinear +ENDIF + +UpdateVibrato1: + Ret + +EndP UpdateVibrato + +; + +Proc Update Far + + Push CS + Pop DS + Assume DS:Music + +IF USEFPUCODE + FNSave FPSave + FNInit + FLdCW [NewControlWord] +ENDIF + + Mov CX, MAXSLAVECHANNELS + Mov SI, Offset SlaveChannelInformationTable + Mov DI, [SI+38h] + + Mov BX, MIDICOMMAND_TICK + Call MIDITranslate + + Mov ES, SongDataArea + +Update2: + Test Byte Ptr [SI], 1 + JZ Update3 + ; reset volume + Mov BL, [SI+22h] + Cmp BL, [SI+21h] + JE Update4 + + Mov [SI+21h], BL + Or Byte Ptr [SI], 10h + +Update4: + Mov EAX, [SI+14h] ; Freq + Cmp EAX, [SI+10h] + JE Update3 + + Mov [SI+10h], EAX + Or Byte Ptr [SI], 20h ; Recalc freq. + +Update3: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ Update2 + + Call UpdateData + + Test Byte Ptr [ES:2Ch], 4 + JZ Update5 + + Call UpdateInstruments + Jmp UpdateEnd + +Update5: + Call UpdateSamples + +UpdateEnd: + Mov CX, NumChannels + Mov SI, Offset SlaveChannelInformationTable + Mov AX, PlayMode + +IF USEFPUCODE + FRstor FPSave +ENDIF + Ret + + +EndP Update + +; + +Proc UpdateSamples + + Assume DS:Music + + Mov CX, NumChannels + Mov SI, Offset SlaveChannelInformationTable + +UpdateSamples1: + Test Byte Ptr [SI], 1 + JZ UpdateSamples2 + + Mov BX, [SI] ; OK.. if recalc volume is on. + ; then recalc volume! :) + Push CX + + Test BL, 16 + JZ UpdateSamples3 + + And BL, Not 16 + Mov CL, SoloSample + + Or BL, 64 ; Recalc final vol + Cmp CL, 0FFh + JE UpdateSamples6 + + Cmp [SI+36h], CL + JE UpdateSamples6 + + Or BH, 8 + +UpdateSamples6: + Xor DX, DX + Mov AL, [SI+21h] ; AL = vol + Mul Byte Ptr [SI+23h] ; Channel volume, AX = 0->64^2 + Mov DL, Byte Ptr [SI+24h] ; Sample volume + Mul DX ; AX = 0->64*64*128 + + SHRD AX, DX, 4 ; AX = 0->32768 + + Mov DL, GlobalVolume + Mul DX ; AX = 0->32768*128 + + SHRD AX, DX, 7 + + Mov [SI+20h], AH ; Final vol stored. + Mov [SI+4Ah], AX + +UpdateSamples3: + Test BL, 2 + JZ UpdateSamples4 + + And BL, Not 2 + Or BH, 128 + + Mov AL, [SI+2Ah] + Mov [SI+25h], AL + Cmp AL, 100 + JE UpdateSamples5 + + Sub AL, 32 + ; Pan = (Pan-32)* Separation/128 + 32 + Mov AH, [ES:34h] + ShR AH, 1 ; AH = 0->64 (Separation) + IMul AH ; AX = -2048->+2048 + ; ie. AH = -8->+8 + SAR AX, 6 ; AL = -32->+32 + + Cmp ReverseChannels, 0 + JE UpdateSamplePan3 + + Neg AL + +UpdateSamplePan3: + Add AL, 32 + +UpdateSamples5: + Mov [SI+37h], AL + +UpdateSamples4: + Mov [SI], BX + + Call UpdateVibrato + + Pop CX + +UpdateSamples2: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ UpdateSamples1 + + Ret + +EndP UpdateSamples + Assume DS:Nothing + +; + +Proc UpdateEnvelope ; Returns Carry if envelope needs + ; to be turned off + ; Reqs ES:DI points to envelope + ; DS:SI points to slave channel envelope structure + ; Called only if envelope is ON + ; BP != 0 if sustain points released, 0 otherwise + + Mov DX, [SI+8] ; DX = current pos + + Cmp DX, [SI+0Ch] ; Expected end pos + JAE UpdateEnvelope1 + + Inc DX + Mov EAX, [SI+4] ; Update value + + Mov [SI+8], DX ; Increase position + Add [SI], EAX + + ClC + Ret + +UpdateEnvelope1: ; Procedure: + ; 1) Get current pos' value + ; 2) Figure out next pos (inc/loop) + ; 3) Figure out delta to next pos + ; 4) Terminate if no loop (with carry) + ; or place new check in [SI+0Ch] + + Xor BX, BX + Mov BL, [SI+0Ah] ; BX = cur env node + LEA AX, [BX+1] + LEA BX, [EBX*2+EBX] ; BX = BX*3 + + Xor DH, DH + Mov DL, [ES:DI+BX+6] + ShL EDX, 16 + Mov [SI], EDX ; Current pos value done. + + ; AX = next cur env node + Mov DX, [ES:DI] + + Test DL, 6 ; Any loop at all? + JZ UpdateEnvelope2 + + Mov BX, [ES:DI+2] ; Normal Loop + + Test DL, 4 ; No SusLoop? + JZ UpdateEnvelope3 + + Test BP, BP + JNZ UpdateEnvelope4 + + Mov BX, [ES:DI+4] + Jmp UpdateEnvelope3 + +UpdateEnvelope4: + Test DL, 2 + JZ UpdateEnvelope2 + +UpdateEnvelope3: ; Loop + Cmp AL, BH + JBE UpdateEnvelope2 + + Xor BH, BH + Mov [SI+0Ah], BL ; BL=New node + LEA BX, [EBX*2+EBX] + + Mov AX, [ES:DI+BX+7] + Mov [SI+8], AX + Mov [SI+0Ch], AX + + ClC + Ret + +UpdateEnvelope2: ; AX = new node + Cmp AL, DH ; DH = number of nodes + JB UpdateEnvelope7 + + StC + Ret + +UpdateEnvelope7: + Mov [SI+0Ah], AL ; New node + LEA BX, [EAX*2+EAX] + + Mov DX, [ES:DI+BX+7] ; New node's tick + Mov [SI+0Ch], DX + Mov AX, [ES:DI+BX+7-3] ; Last node's tick + Sub DX, AX + Inc AX + Mov [SI+8], AX ; For security. + + Mov AL, [ES:DI+BX+6] ; New node's amplitude + Sub AL, [ES:DI+BX+6-3] ; Last node's amplitude + + Mov BX, DX ; BX = delta(ticks) + Xor DX, DX + CBW + Test AX, AX + PushF + JNS UpdateEnvelope5 + + Neg AX + +UpdateEnvelope5: + Sub BX, 1 + AdC BX, 1 ; Just to prevent div 0 errors + + Div BX + ShL EAX, 16 ; This clears AX also + Div BX + ; EAX = value + PopF + JNS UpdateEnvelope6 + + Neg EAX + +UpdateEnvelope6: + Mov [SI+4], EAX ; Delta done + + ClC + Ret + +EndP UpdateEnvelope + +; + +DoMIDICycle DB 0 + +MIDIPrograms DB 16 Dup (0FFh) ; Do NOT change order! +MIDIBanks DW 16 Dup (0FFFFh) +MIDIPan DB 16 Dup (0FFh) +MIDIPitch DW 16 Dup (2000h) + +; + +Proc UpdateMIDI + Assume DS:Music + +; Stop cycle + + Mov CX, MAXSLAVECHANNELS + Mov SI, Offset SlaveChannelInformationTable + +UpdateMIDI1: + Test Word Ptr [SI], 200h + JZ UpdateMIDI2 + Cmp Byte Ptr [SI+36h], 100 + JNE UpdateMIDI2 + Test Byte Ptr [SI], 1 + JZ UpdateMIDI2 + + Mov Word Ptr [SI], 0 + Mov DI, [SI+38h] ; Host channel in DI + + Mov BX, MIDICOMMAND_STOPNOTE + Call MIDITranslate + + Test Byte Ptr [SI+3Ah], 80h + JNZ UpdateMIDI2 + + Or Byte Ptr [SI+3Ah], 80h + And Byte Ptr [DI], Not 4 ; Signify channel off + +UpdateMIDI2: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ UpdateMIDI1 + +; Play cycle + + Mov CX, MAXSLAVECHANNELS + Mov SI, Offset SlaveChannelInformationTable + +UpdateMIDI3: + Cmp Byte Ptr [SI+36h], 100 ; MIDI Instrument? + JNE UpdateMIDI4 + + Mov DX, [SI] + Test DL, 1 + JZ UpdateMIDI4 + + Mov AL, [SI+4Ch] + Mov Byte Ptr [SI+4Ch], 1 + Mov [SI+2Ch], AL + + Test DX, 800h ; Muted? + JNZ UpdateMIDI4 + + Mov DI, [SI+38h] ; Host channel in DI + And Word Ptr [SI], 0111100010001101b + + Test DH, 1 + JZ UpdateMIDINoPlayNote + +UpdateMIDIPlayNote: ; Check if there's a bank select. + Mov AX, [SI+3Eh] ; MIDI Bank + Cmp AX, 0FFFFh + JE UpdatemIDIBankSelectDone + + Mov BL, [SI+3Ch] ; BL = channel + And BX, 0FFh + Add BX, BX + Cmp [MIDIBanks+BX-2], AX + JE UpdateMIDIBankSelectDone + + Mov [MIDIBanks+BX-2], AX + ShR BX, 1 + Mov [MIDIPrograms+BX-1], 0FFh ; Reset program + + Mov BX, MIDICOMMAND_BANKSELECT + Call MIDITranslate + +UpdateMIDIBankSelectDone: ; Check for a program specification + Cmp Byte Ptr [SI+3Dh], 0 + JL UpdateMIDIProgramDone + + Mov BL, [SI+3Ch] ; BL = channel + And BX, 0FFh + Mov AL, [SI+3Dh] ; MIDI program + Cmp [MIDIPrograms+BX-1], AL + JE UpdateMIDIProgramDone + + Mov [MIDIPrograms+BX-1], AL + + Mov BX, MIDICOMMAND_PROGRAMSELECT + Call MIDITranslate + +UpdateMIDIProgramDone: +; Check for MIDI pitch wheel.. + Test Byte Ptr [ES:2Ch], 64 + JZ UpdateMIDINoPitchWheel + + Mov BL, [SI+3Ch] ; BL = channel + And BX, 0FFh + Add BX, BX + Cmp [MIDIPitch+BX-2], 2000h + JE UpdateMIDINoPitchWheel + + Mov [MIDIPitch+BX-2], 2000h + Mov AL, [SI+3Ch] + Dec AL + Or AL, 0E0h + Call MIDISendFilter + Xor AL, AL + Call MIDISendFilter ; Reset pitch wheel + Mov AL, 40h + Call MIDISendFilter + +UpdateMIDINoPitchWheel: + Mov EAX, [SI+14h] + Mov BX, MIDICOMMAND_PLAYNOTE + Mov [SI+1Ch], EAX + Call MIDITranslate + Jmp UpdateMIDINoChangeVolume + +UpdateMIDINoPlayNote: ; Change in volume? + Test DL, 64 + JZ UpdateMIDINoChangeVolume + + Mov BX, MIDICOMMAND_CHANGEVOLUME + Call MIDITranslate + +UpdateMIDINoChangeVolume: + Test DH, 80h ; Pan changed? + JZ UpdateMIDINoChangePan + + Mov BL, [SI+3Ch] ; BL = channel + And BX, 0FFh + Mov AL, [SI+37h] ; FPP + + Cmp [MIDIPan+BX-1], AL + JE UpdateMIDINoChangePan + + Mov [MIDIPan+BX-1], AL + + Mov BX, MIDICOMMAND_CHANGEPAN + Call MIDITranslate + +UpdateMIDINoChangePan: ; Pitch changed? + Test DL, 32 + JZ UpdateMIDINoPitchChange + + Mov BX, MIDICOMMAND_CHANGEPITCH + Call MIDITranslate + +UpdateMIDINoPitchChange: + +UpdateMIDI4: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ UpdateMIDI3 + + Ret + +EndP UpdateMIDI + Assume DS:Nothing + +; + +Proc UpdateInstruments + Assume DS:Music ; Things to update: + ; 1) Volume envelope + ; 2) Fadeout + ; 3) FinalVolume + ; 4) Vibrato. + ; Turn off channel if + ; 1) Volume envelope is off & VEV = 0 or + ; 2) Fadeout = 0 + + Mov CX, MAXSLAVECHANNELS + Mov SI, Offset SlaveChannelInformationTable + Mov [DoMIDICycle], 0 + +UpdateInstruments1: + Test Byte Ptr [SI], 1 + JNZ UpdateInstruments16 ; Channel on!! + +UpdateInstruments2: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ UpdateInstruments1 + + Cmp [DoMIDICycle], 0 + JE UpdateInstrumentNoMIDICycle + + Call UpdateMIDI + +UpdateInstrumentNoMIDICycle: + Ret + +; UpdateInstruments14: +; Jmp UpdateInstruments5 ; Jump point + +UpdateInstruments16: + Push CX + + Mov CX, [SI] + + MovZX EDI, Word Ptr [SI+30h] ; ES:DI = instrument + + Cmp Byte Ptr [SI+33h], 0FFh ; No instrument? + JE UpdateInstruments5 ; Prev Intruments14 + + Mov BP, CX + And BP, 4 ; BP = sustain for envelope calls + +UpdatePitchEnvelope: + Test CH, 40h + JZ UpdatePitchEnvelopeApply + + Push SI + Push DI + + Add SI, 70h + Add DI, 1D4h + Call UpdateEnvelope + + Pop DI + Pop SI + + JNC UpdatePitchEnvelopeApply + + And CH, Not 40h + +UpdatePitchEnvelopeApply: + Test Byte Ptr [ES:DI+1D4h], 80h + JZ UpdatePitchEnvelopePitch + + Cmp Byte Ptr [SI+36h], 100 + JE UpdatePanEnvelope + +UpdatePitchEnvelopeFilter: + Mov BX, [SI+71h] + SAR BX, 6 ; Range -128 to +128 + Add BX, 128 ; Range 0 -> 256 + Cmp BH, 1 + AdC BL, -1 + Mov [SI+3Eh], BL + + Or CL, 64 ; Recalculate final volume + +; Test Byte Ptr [SI+3Ah], 80h +; JNZ UpdatePanEnvelope +; +; Call SetFilterCutoff +; + Jmp UpdatePanEnvelope + +UpdatePitchEnvelopePitch: + Mov BX, [SI+71h] + SAR BX, 3 + JZ UpdatePanEnvelope +IFE USEFPUCODE + JS UpdatePitchEnvDown +ENDIF + + Push DI + Mov DI, [SI+38h] + + Call PitchSlideUpLinear ; req: DS:SI points to table + ; DS:DI points to host channel + ; BX = magnintude + Pop DI +IFE USEFPUCODE + Jmp UpdatePostPitchEnvelope + +UpdatePitchEnvDown: + Neg BX + Call PitchSlideDownLinear + +UpdatePostPitchEnvelope: +ENDIF + Or CL, 32 ; Recalculate freq + +UpdatePanEnvelope: + Test CH, 20h + JZ UpdateVolumeEnvelope + + Or CL, 2 ; Recalculate pan + + Push SI + Push DI + + Add SI, 60h + Add DI, 182h + Call UpdateEnvelope + + Pop DI + Pop SI + + JNC UpdateVolumeEnvelope + + And CH, Not 20h + +UpdateVolumeEnvelope: + Test CH, 10h ; Volume envelope on? + JZ UpdateInstruments3 + + Or CL, 16 ; Recalculate volume + + Push SI + Push DI + + Add SI, 50h + Add DI, 130h + Call UpdateEnvelope + + Pop DI + Pop SI + + JC UpdateVolumeEnvelope1 + Test CL, 8 ; Note fade on? + JNZ UpdateInstruments13 + + ; Now, check if loop + sustain + ; off + Test BP, BP + JZ UpdateInstruments5 + + Test Byte Ptr [ES:DI+130h], 2 ; Normal vol env loop? + JNZ UpdateInstruments19 + Jmp UpdateInstruments5 ; Volume calculation + +UpdateVolumeEnvelope1: ; Envelope turned off... + And CH, Not 10h ; Turn off envelope flag + + Cmp Byte Ptr [SI+52h], 0 ; Turn off if end of loop is + JE UpdateInstruments17 ; reached + + Jmp UpdateInstruments19 + +UpdateInstruments3: + Test CL, 8 ; Note fade?? + JNZ UpdateInstruments13 + + ; Also apply fade if No vol env + ; AND sustain off + + Test CL, 4 ; Note off issued? + JZ UpdateInstruments5 + +UpdateInstruments19: + Or CL, 8 + +UpdateInstruments13: + Mov AX, [ES:DI+14h] ; AX = fadeout. + Sub [SI+26h], AX + JG UpdateInstruments4 + Mov Word Ptr [SI+26h], 0 + +UpdateInstruments17: ; Turn off channel + Test Byte Ptr [SI+3Ah], 80h + JNZ UpdateInstruments18 + + Or Byte Ptr [SI+3Ah], 80h + ; Host channel exists + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 + +UpdateInstruments18: +; Mov Word Ptr [SI], 200h +; Pop CX +; Jmp UpdateInstruments2 + Or CH, 2 + +UpdateInstruments4: + Or CL, 16 ; Recalc volume flag. + +UpdateInstruments5: + Test CL, 16 + JZ UpdateInstrument10 + ; Calculate volume + And CL, Not 16 + Mov DX, Word Ptr [SoloSample] ; DL = sample, DH = inst + + Or CL, 64 ; Recalc final volume + Mov AL, [SI+21h] ; Note volume.. + + Mul Byte Ptr [SI+23h] ; Channel volume + ; AX = (0->4096) + Cmp DL, 0FFh + JE UpdateInstrumentNoSampleSolo + + Cmp [SI+36h], DL + JNE UpdateInstrumentSolo + +UpdateInstrumentNoSampleSolo: + Cmp DH, 0FFh + JE UpdateInstrumentNoInstrumentSolo + + Cmp [SI+33h], DH + JE UpdateInstrumentNoInstrumentSolo + +UpdateInstrumentSolo: + Or CH, 8 + +UpdateInstrumentNoInstrumentSolo: + Mul Word Ptr [SI+26h] ; Fadeout Vol (0->1024) + ; DX:AX = 0->4194304 + SHRD AX, DX, 7 + ; AX = (0->32768) + Mov DL, [SI+24h] ; Sample volume + Mul DX ; DX:AX = 0->4194304 + + SHRD AX, DX, 7 ; AX = 0->32768 + + Mov DX, Word Ptr [SI+51h] ; VEV, 0->64*256 + Mul DX ; DX:AX = 0->536870912 + + SHRD AX, DX, 14 ; AX = 0->32768 + + Xor DH, DH + Mov DL, GlobalVolume + Mul DX ; DX:AX = 0->4194304 + + SHRD AX, DX, 7 + Mov [SI+20h], AH + Mov [SI+4Ah], AX + +UpdateInstrument10: + Test CL, 2 ; Change in panning? + JZ UpdateInstrument20 + + And CL, Not 2 + Or CH, 128 + + Mov DL, [SI+2Ah] ; DL = actual pan + Mov AL, DL + Cmp DL, 100 + JE UpdateInstrumentSurroundPan + + Mov AL, 32 + Sub AL, DL + CBW + Xor AL, AH + Sub AL, AH ; AL = |32-ActualPan| + + Neg AL + Add AL, 32 + IMul Byte Ptr [SI+62h] ; Pan envelope.. + SAR AX, 5 + Add AL, DL + + Mov [SI+25h], AL ; Value to show.. + + Sub AL, 32 + ; Pan = (Pan-32)* Separation/128 + 32 + Mov AH, [ES:34h] + ShR AH, 1 ; AH = 0->64 (Separation) + IMul AH ; AX = -2048->+2048 + ; ie. AH = -8->+8 + SAR AX, 6 ; AL = -32->+32 + + Cmp ReverseChannels, 0 + JE UpdateInstrumentPan3 + + Neg AL + +UpdateInstrumentPan3: + Add AL, 32 + Jmp UpdateInstrumentPan2 + +UpdateInstrumentSurroundPan: + Mov [SI+25h], AL + +UpdateInstrumentPan2: + Mov [SI+37h], AL + +UpdateInstrument20: + Mov [SI], CX + + Call UpdateVibrato + + Cmp Byte Ptr [SI+36h], 100 ; MIDI? + JNE UpdateInstrumentsNoMIDI + + Mov [DoMIDICycle], 1 + +UpdateInstrumentsNoMIDI: + Pop CX + + Jmp UpdateInstruments2 + +EndP UpdateInstruments + Assume DS:Nothing + +; + +Proc UpdateData + + Assume DS:Music + + Mov CX, 64 + Mov AX, PlayMode + Cmp AX, 1 + JE UpdateData_PlayMode1 + JB UpdateData_PlayMode0 + Jmp UpdateData_PlayMode2 + +UpdateData_PlayMode0: ; Step through each channel. + ; Check if on/updatemode OK + Mov DI, Offset HostChannelInformationTable + +UpdateData1: + Cmp Byte Ptr [DI+21h], 0 + JE PlayMode0UpdateVolume1 + + Dec Byte Ptr [DI+21h] ; Handle counter + JNZ UpdateData4 + + And Word Ptr [DI], Not 303h ; Turn off mode. + +UpdateData4: + Mov AX, [DI] + + Test AL, 4 ; Channel on? + JZ UpdateData2 + + Test AH, 1 + JZ UpdateData2 ; Don't update effect?? + +PlayMode0UpdateVolume2: + Push CX + + Mov BX, [DI+0Ah] + And BX, 7 + Add BX, BX + + Call Word Ptr [VolumeEffectTable+BX] + + Pop CX + + Mov AL, [DI] + +UpdateData2: + Test AL, 2 + JNZ UpdateData3 ; Update effect regardless.. + + Test AL, 4 ; Channel on? + JZ PlayMode0UpdateVolume1 + + Test AL, 1 + JZ PlayMode0UpdateVolume1 ; Don't update effect?? + +UpdateData3: ; OK. now handle counter. + Push CX + + Mov BX, [DI+6] + And BX, 31 + Add BX, BX + + Call Word Ptr [CommandTable+BX] + + Pop CX + +PlayMode0UpdateVolume1: + Add DI, HOSTCHANNELSIZE ; Progress to next channel + Dec CX + JNZ UpdateData1 + + Ret ; That's all! + +UpdateData_PlayMode1: + ; Pattern stuff.. + Dec ProcessTick + Dec CurrentTick + JZ UpdateData_Pattern1 + +UpdateData_NoNewRow: ; OK. call update command. + Mov DI, Offset HostChannelInformationTable + +UpdateData_NoNewRow1: + Mov AX, [DI] ; AX = host flags. + + Test AL, 4 + JZ UpdateData_NoNewRow5 + + Test AH, 1 + JZ UpdateData_NoNewRow5 + +UpdateData_NoNewRow4: + Push CX + + Mov BX, [DI+0Ah] + And BX, 7 + Add BX, BX + + Call Word Ptr [VolumeEffectTable+BX] + + Pop CX + + Mov AL, [DI] ; AX = host flags. + +UpdateData_NoNewRow5: + Test AL, 3 + JZ UpdateData_NoNewRow2 + + Test AL, 2 + JNZ UpdateData_NoNewRow3 + + Test AL, 4 + JZ UpdateData_NoNewRow2 + +UpdateData_NoNewRow3: + Push CX + + Mov BX, [DI+6] + And BX, 31 + Add BX, BX + + Call Word Ptr [CommandTable+BX] + + Pop CX + +UpdateData_NoNewRow2: + Add DI, HOSTCHANNELSIZE + Dec CX + JNZ UpdateData_NoNewRow1 + + Ret + +UpdateData_Pattern1: ; OK... have to update row. + Mov AX, CurrentSpeed + Mov CurrentTick, AX + Mov ProcessTick, AX + + Dec RowDelay + JNZ UpdateEffectData + + Mov Word Ptr RowDelay, 1 + + Mov AX, ProcessRow + Inc AX ; Progress to new row. + Cmp AX, NumberOfRows + JB UpdateData_Pattern2 + + Cmp StopEndOfPlaySection, 0 + JNE UpdateDataStopSong + ; Wrap row. + Xor AX, AX + XChg AX, BreakRow + +UpdateData_Pattern2: + Jmp UpdateData_Song1 +; Mov ProcessRow, AX +; Mov CurrentRow, AX +; +; ; Gotta get note data. +; Call UpdateNoteData +; Ret + +UpdateEffectData: + Mov DI, Offset HostChannelInformationTable + +UpdateEffectData1: + Test Byte Ptr [DI], 64 + JZ UpdateEffectData2 + + Mov AL, [DI+2] + Test AL, 88h + JZ UpdateEffectData2 + + Push AX + Push CX + + And AL, 88h + Mov [DI+2], AL + + Mov BL, [DI+6] + And BX, 31 + Add BX, BX + + Call Word Ptr [InitCommandTable + BX] ; Init note + + Pop CX + Pop AX + + Mov [DI+2], AL + +UpdateEffectData2: + Add DI, HOSTCHANNELSIZE + Dec CX + JNZ UpdateEffectData1 + Ret + +UpdateData_PlayMode2: + Dec ProcessTick + Dec CurrentTick + JNZ UpdateData_NoNewRow + ; Play song stuff... + + Mov AX, CurrentSpeed + Mov CurrentTick, AX + Mov ProcessTick, AX + + Dec RowDelay + JNZ UpdateEffectData + + Mov Word Ptr RowDelay, 1 + + Mov AX, ProcessRow + Inc AX + Cmp AX, NumberOfRows + JB UpdateData_Song1 + + Test OrderLockFlag, 1 + JNZ UpdateData_Song5 + + Mov BX, ProcessOrder ; Get new pattern. + Xor DX, DX + Inc BX + +UpdateData_Song2: + Cmp BX, 100h + JGE UpdateData_Song4 + + Mov CL, [ES:BX+100h] ; CL = next pattern. + Cmp CL, 200 + JB UpdateData_Song3 + + Inc BX + Cmp CL, 0FEh + JE UpdateData_Song2 + + Mov StopSong, 1 + + Cmp StopEndOfPlaySection, 0 + JE UpdateData_Song4 + +UpdateDataStopSong: + Call Music_Stop ; Optionally.. loop! + Ret + +UpdateData_Song4: + Test DX, DX + JNZ UpdateDataStopSong + + Inc DX + Xor BX, BX + Jmp UpdateData_Song2 + +UpdateData_Song3: + Mov ProcessOrder, BX + Mov CurrentOrder, BX + + Mov Byte Ptr CurrentPattern, CL + +UpdateData_Song5: + Xor AX, AX + XChg AX, BreakRow + +UpdateData_Song1: + Mov ProcessRow, AX + Mov CurrentRow, AX + + Call UpdateNoteData + Ret + +EndP UpdateData + Assume DS:Nothing + +; + +Proc Music_GetNumberOfSamples Far ; Returns AX + + Push CX + Push DS + Push SI + Push ES + Push DI + + Push CS + Pop DS + Assume DS:Music + + Mov ES, SongDataArea + Mov DI, 63912-160 + + Mov AX, 99 + +Music_GetNumberOfSamples1: + Mov CX, 80 + Mov SI, Offset SampleHeader + RepE CmpsB + JNE Music_GetNumberOfSamples2 + + Sub DI, 160 + Dec AX + JNZ Music_GetNumberOfSamples1 + +Music_GetNumberOfSamples2: + + Pop DI + Pop ES + Pop SI + Pop DS + Pop CX + + Ret + +EndP Music_GetNumberOfSamples + Assume DS:Nothing + +; + +Proc Music_GetNumberOfInstruments Far ; Returns AX + + Push CX + Push DS + Push SI + Push ES + Push DI + + Push CS + Pop DS + Assume DS:Music + + Mov ES, SongDataArea + Mov DI, 55912-554*2 + + Mov AX, 99 + +Music_GetNumberOfInstruments1: + Mov CX, 554 + Mov SI, Offset InstrumentHeader + RepE CmpsB + JNE Music_GetNumberOfInstruments2 + + Sub DI, 1108 + Dec AX + JNZ Music_GetNumberOfInstruments1 + +Music_GetNumberOfInstruments2: + + Pop DI + Pop ES + Pop SI + Pop DS + Pop CX + + Ret + +EndP Music_GetNumberOfInstruments + Assume DS:Nothing + +; + +Proc Music_GetSampleHeader Far ; AX = sample, 1 based + + Mov SI, AX + Mov DS, CS:SongDataArea + Add SI, SI + + Mov SI, [DS:64910+SI] + + Ret + +EndP Music_GetSampleHeader + ; Returns DS:SI + +; + +Proc Music_GetSampleLocation Far ; AX = sample (1based) + ; CH = page. + ; Returns DS:ESI + ; ECX = length + ; Carry if no sample. + ; Zero set if 8 bit + Mov CS:LastSample, AX + + Push AX + Push BX + Push DX + + Mov BX, AX + Add BX, BX + + Mov DS, CS:SongDataArea + Mov BX, [64910+BX] + Test Byte Ptr [BX+12h], 1 + JZ Music_GetSampleLocationEnd + +Music_GetSampleLocation3: + Mov AL, [BX+48h] + Test AL, AL + JZ Music_GetSampleLocationEnd + + Cmp AL, 2 + JA Music_GetSampleLocationEnd + JE Music_GetSampleLocation4 + + Mov AX, [BX+4Ah] + Xor CL, CL + ShL CX, 2 + Add AX, CX + + Jmp Music_GetSampleLocation2 + +Music_GetSampleLocation4: + Mov DX, [BX+4Ah] + Mov CL, [BX+49h] + Call E_MapEMSMemory + Call E_GetEMSPageFrame + +Music_GetSampleLocation2: + Xor ESI, ESI + Mov ECX, [BX+30h] + + Test Byte Ptr [BX+12h], 2 ; Zero flag for 8-bit. + + Mov DS, AX + +Music_GetSampleLocation5: + ClC + Jmp Music_GetSampleLocationEnd2 ; Need to preserve zero flag + +Music_GetSampleLocationEnd: + StC + +Music_GetSampleLocationEnd2: + Pop DX + Pop BX + Pop AX + + Ret + +EndP Music_GetSampleLocation + +; + +; Accessed via Int 3 +Proc Music_UpdateSampleLocation Far ; Reqs ESI. + + PushAD + + Mov AX, CS:LastSample + Mov ECX, ESI + ShR ECX, 8 + ShL CH, 2 + + Call Music_GetSampleLocation + + PopAD + IRet + +EndP Music_UpdateSampleLocation + +; + +Proc Music_FarUpdateSampleLocation Far + + PushF + + PushF + ClI + Call Far Ptr Music_UpdateSampleLocation + + PopF + + Ret + +EndP Music_FarUpdateSampleLocation + +; + +Proc Music_GetPlayMode Far + + Push DS + + Push CS + Pop DS + Assume DS:Music + + Mov AX, PlayMode + Mov BX, CurrentRow + Mov CX, CurrentPattern + Mov DX, CurrentOrder + Mov SI, NumberOfRows + + Pop DS + + Ret + Assume DS:Nothing + +EndP Music_GetPlayMode + +; + +Proc Music_GetPlayMode2 Far + + Push DS + + Push CS + Pop DS + Assume DS:Music + + Mov AX, PlayMode + Mov EBX, DWord Ptr CurrentOrder + Mov CX, CurrentRow + ShL ECX, 16 + Mov CX, CurrentTick + + Pop DS + Ret + +EndP Music_GetPlayMode2 + Assume DS:Nothing + +; + +Proc Music_PlayPattern Far ; AX = pattern, BX = number of rows + ; CX = row to start + + Push DS + + Call Music_Stop + + Push CS + Pop DS + Assume DS:Music + + Mov MIDIPitchDepthSent, 0 + Mov LastMIDIByte, 0FFh + + Mov CurrentPattern, AX + Mov CurrentRow, CX + Dec CX + Mov NumberOfRows, BX + Mov ProcessRow, CX + Mov PlayMode, 1 + + Pop DS + + Ret + +EndP Music_PlayPattern + Assume DS:Nothing + +; + +Proc Music_PlaySong Far ; AX = Order + + PushA + Push DS + + Call Music_Stop + + Push CS + Pop DS + Assume DS:Music + + Mov MIDIPitchDepthSent, 0 + Mov LastMIDIByte, 0FFh + + Mov CurrentOrder, AX + Dec AX + Mov ProcessOrder, AX + Mov ProcessRow, 0FFFEh + Mov PlayMode, 2 + + Call StartClock + + Mov BX, MIDICOMMAND_START + Mov SI, Offset SlaveChannelInformationTable + Call MIDITranslate + + Pop DS + PopA + Ret + +EndP Music_PlaySong + +; + +Proc Music_PlayPartSong Far ; AX = order, BX = row. + + Push AX + Push BX + Push DS + + Call Music_Stop + + Mov CS:NumberOfRows, 200 + Mov CS:ProcessOrder, AX + Mov CS:CurrentOrder, AX + Mov CS:CurrentRow, BX + Dec BX + Mov CS:ProcessRow, BX + + Mov BX, AX + + Mov DS, CS:SongDataArea + MovZX AX, Byte Ptr [DS:BX+100h] + Mov CS:CurrentPattern, AX + + Mov CS:PlayMode, 2 + + Call StartClock + + Pop DS + Pop BX + Pop AX + Ret + +EndP Music_PlayPartSong + +; + +Proc Music_KBPlaySong Far + + Xor AX, AX + Cmp CS:PlayMode, 2 + JNE Music_PlaySong + + Ret + +EndP Music_KBPlaySong + +; + +Proc Music_StopChannels + + Push CX + Push DS + Push SI + Push DI + + Push CS + Pop DS + Assume DS:Music + + Mov CX, 64 + Mov SI, Offset HostChannelInformationTable + +Music_StopChannels1: + Mov Word Ptr [SI], 0 + Mov Word Ptr [SI+26h], 0 + Add SI, HOSTCHANNELSIZE + Loop Music_StopChannels1 + + Mov CX, MAXSLAVECHANNELS + Mov SI, Offset SlaveChannelInformationTable + +Music_StopChannels2: + Test Byte Ptr [SI], 1 + JZ Music_StopChannelsNoMIDI + + Cmp Byte Ptr [SI+36h], 100 + JNE Music_StopChannelsNoMIDI + + PushF + ClI + Mov DI, [SI+38h] + Mov BX, MIDICOMMAND_STOPNOTE + Call MIDITranslate + PopF + +Music_StopChannelsNoMIDI: + Mov Word Ptr [SI], 200h + Add SI, SLAVECHANNELSIZE + Loop Music_StopChannels2 + + Pop DI + Pop SI + Pop DS + Pop CX + + Ret + +EndP Music_StopChannels + +; + +Proc Music_Stop Far + + PushA + PushF + Push DS + Push ES + + CLI + + Push CS + Pop DS + Assume DS:Music + +; Turn off MIDI channels first. + + Test OrderLockFlag, 1 + JZ Music_StopNoOrderLocked + + Call Music_ToggleOrderUpdate + +Music_StopNoOrderLocked: + Mov CX, MAXSLAVECHANNELS + Mov SI, Offset SlaveChannelInformationTable + +Music_StopMIDI1: + Test Byte Ptr [SI], 1 + JZ Music_StopNoMIDI + + Cmp Byte Ptr [SI+36h], 100 + JNE Music_StopNoMIDI + + Mov DI, [SI+38h] + Mov BX, MIDICOMMAND_STOPNOTE + Call MIDITranslate + +Music_StopNoMIDI: + Add SI, SLAVECHANNELSIZE + Loop Music_StopMIDI1 + + Mov BX, MIDICOMMAND_STOP ; Stop + Mov SI, Offset SlaveChannelInformationTable + Call MIDITranslate + + Mov PlayMode, 0 + + Mov DecodeExpectedPattern, 0FFFEh + Mov DecodeExpectedRow, 0FFFEh + Mov RowDelay, 1 + Mov CurrentRow, 0 + Mov CurrentOrder, 0 + Mov CurrentTick, 1 + Mov BreakRow, 0 + + Push CX + Push DS + Push SI + Push DI + + Push CS + Pop ES + + Mov DI, Offset MIDIPrograms + Mov CX, 32 + Mov AX, 0FFFFh + Rep StosW + + Mov DI, Offset HostChannelInformationTable + Mov DS, SongDataArea + Assume DS:Nothing + + Mov SI, 40h + Mov DX, 040h + Xor AX, AX + +Music_Clear1: + Mov CX, 16 + Rep StosW + Mov AL, DH + StosW + + Xor AX, AX + Mov CX, 6 + Rep StosW + + Mov AH, [SI+40h] + LodsB + And AL, 7Fh + StosW + Xor AX, AX + Mov CX, 16 + Rep StosW + + Inc DH + Dec DL + JNZ Music_Clear1 + + ; Now clear SlaveChannel + Mov DX, MAXSLAVECHANNELS + +Music_Clear2: + Mov AX, 200h + StosW + Mov CX, SLAVECHANNELSIZE/2-1 + Xor AX, AX + Rep StosW + Dec DX + JNZ Music_Clear2 + + Push DS + Pop ES ; ES = SongDataArea + + Pop DI + Pop SI + Pop DS + Pop CX + Assume DS:Music + + Mov AX, [ES:32h] ; AL = speed, AH = tempo + Mov BX, [ES:30h] ; BL = globalvol + + Xor DX, DX + Mov DL, AL + Mov GlobalVolume, BL + Mov CurrentSpeed, DX + Mov ProcessTick, DX + Mov Tempo, AH + + Call Music_InitTempo + Call MIDI_ClearTable + + Pop ES + Pop DS + PopF + PopA + + Ret + +EndP Music_Stop + Assume DS:Nothing, ES:Nothing + +; + +Proc Music_UpdatePatternOffset Far + + Mov CS:DecodeExpectedPattern, 0FFFEh + + Ret + +EndP Music_UpdatePatternOffset + +; + +Proc Music_PlayNote Far ; DS:SI points to 5-note struct + ; AX = channel + ; DH = +32 means ignore mute + ; settings + ; DH = +128 means to use central + ; pan and max volume. + PushAD + Push DS + Push ES + + Mov AH, HOSTCHANNELSIZE + Mul AH + Mov DI, Offset HostChannelInformationTable + Add DI, AX + + Mov ES, CS:SongDataArea + + Xor DL, DL ; DL = mask + + ClI + + LodsB + Cmp AL, NONOTE + JE Music_PlayNote1 + + Or DL, 1 + Mov [CS:DI+3], AL + +Music_PlayNote1: + LodsB + Test AL, AL + JZ Music_PlayNote2 + + Or DL, 2 + Mov [CS:DI+4], AL + +Music_PlayNote2: + LodsB + Cmp AL, 0FFh + JE Music_PlayNote3 + + Or DL, 4 + Mov [CS:DI+5], AL + +Music_PlayNote3: + LodsW + Test AX, AX + JZ Music_PlayNote4 + + Or DL, 8 + +Music_PlayNote4: + Push CS + Pop DS + Assume DS:Music + + Push DX + + And DH, 7Fh + Mov [DI+6], AX + Mov [DI+8], AX + Mov [DI+2], DL + And Word Ptr [DI], Not (3+32+64+256) + Or Byte Ptr [DI], DH ; Now for command update count + + Mov AX, CurrentSpeed + Mov [DI+21h], AL + + Call PreInitCommand + + Pop DX + + Test Byte Ptr [DI], 4 + JZ Music_PlayNote5 + + Test DH, 128 + JZ Music_PlayNote5 + + Mov SI, [DI+24h] + Mov Word Ptr [SI+2Ah], 2020h; Pan and pan set. + Mov Byte Ptr [SI+23h], 40h ; Full channel volume. + +Music_PlayNote5: + Mov DecodeExpectedRow, 0FFFEh + StI + + Pop ES + Pop DS + PopAD + + Ret + +EndP Music_PlayNote + Assume DS:Nothing + +; + +Proc Music_PlaySample Far + ; AL = Note + ; AH = sample number + ; CX = channel. + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Music + + Mov ES, SongDataArea + + Push AX + + Mov AX, HOSTCHANNELSIZE + Mul CX + Add AX, Offset HostChannelInformationTable + Mov DI, AX + + Pop AX + +; Mov DI, Offset HostChannelInformationTable + + ClI + + Mov Byte Ptr [DI+2], 3 ; Note & Sample + Mov [DI+3], AL ; Note... + Mov Byte Ptr [DI+4], 0FFh + Mov [DI+0Eh], AX + Or Word Ptr [DI], 8020h + + Call InitNoCommand + + Test Byte Ptr [DI], 4 + JZ Music_PlaySample1 + + Mov SI, [DI+24h] + Mov Word Ptr [SI+2Ah], 2020h + Mov Byte Ptr [SI+23h], 40h ; Full channel volume. + Mov Byte Ptr [SI+3Bh], 0 ; Note cut. + Mov Word Ptr [SI+28h], 0 + +Music_PlaySample1: + And Word Ptr [DI], Not 8000h + + Mov DecodeExpectedRow, 0FFFEh + StI + + Pop ES + Pop DS + PopAD + + Ret + +EndP Music_PlaySample + +; + +Proc Music_GetHostChannelInformationTable Far + + Push CS + Pop DS + Assume DS:Music + + Mov SI, Offset HostChannelInformationTable + + Ret + +EndP Music_GetHostChannelInformationTable + Assume DS:Nothing + +; + +Proc Music_GetSlaveChannelInformationTable Far + + Push CS + Pop DS + Assume DS:Music + + Mov SI, Offset SlaveChannelInformationTable + Mov CX, MAXSLAVECHANNELS + + Ret + +EndP Music_GetSlaveChannelInformationTable + Assume DS:Nothing + +; + +Proc Music_NextOrder Far + + Push DS + + Push CS + Pop DS + Assume DS:Music + + Cmp PlayMode, 2 + JNE Music_NextOrder1 + + Mov PlayMode, 0 + Call Music_StopChannels + Mov ProcessRow, 0FFFEh + Mov CurrentTick, 1 + Mov RowDelay, 1 + Mov PlayMode, 2 + +Music_NextOrder1: + Pop DS + Ret + +EndP Music_NextOrder + Assume DS:Nothing + +; + +Proc Music_LastOrder Far + + Push DS + + Push CS + Pop DS + Assume DS:Music + + Cmp PlayMode, 2 + JNE Music_NextOrder1 + + Mov AX, ProcessOrder + Cmp AX, 0 + JLE Music_LastOrder1 + + ClI + + Mov PlayMode, 0 + Call Music_StopChannels + Sub AX, 2 + Mov ProcessOrder, AX + Mov ProcessRow, 0FFFEh + Mov CurrentTick, 1 + Mov RowDelay, 1 + Mov PlayMode, 2 + + StI + +Music_LastOrder1: + Pop DS + Ret + +EndP Music_LastOrder + Assume DS:Nothing + +; + +Proc Music_SetGlobalVolume Far + + Push CX + Push DS + Push SI + + Push CS + Pop DS + Assume DS:Music + + Mov GlobalVolume, AL + Call RecalculateAllVolumes + + Pop SI + Pop DS + Pop CX + Ret + +EndP Music_SetGlobalVolume + Assume DS:Nothing + +; + +Proc Music_MuteChannel Far ; AX = channel number + + Push AX + Push CX + Push DS + Push SI + Push DI + + Push CS + Pop DS + Assume DS:Music + + Mov CX, NumChannels + Mov SI, Offset SlaveChannelInformationTable + +Music_MuteChannel1: + Test Byte Ptr [SI], 1 + JZ Music_MuteChannel2 + + Mov AH, [SI+3Ah] + And AH, 07Fh + Cmp AH, AL + JNE Music_MuteChannel2 + + Or Word Ptr [SI], 840h + +Music_MuteChannel2: + Add SI, SLAVECHANNELSIZE + Loop Music_MuteChannel1 + + Pop DI + Pop SI + Pop DS + Pop CX + Pop AX + Ret + +EndP Music_MuteChannel + Assume DS:Nothing + +; + +Proc Music_UnmuteChannel Far ; AX = channel number + + Push AX + Push CX + Push DS + Push SI + Push DI + + Push CS + Pop DS + Assume DS:Music + + Mov CX, NumChannels + Mov Word Ptr [SoloSample], 0FFFFh + Mov SI, Offset SlaveChannelInformationTable + +Music_UnmuteChannel1: + Test Byte Ptr [SI], 1 + JZ Music_UnmuteChannel2 + + Mov AH, [SI+3Ah] + And AH, 07Fh + Cmp AH, AL + JNE Music_UnmuteChannel2 + +Comment ~ +Music_UnmuteChannel3: + Test DL, DL + JS Music_UnmuteChannel5 + + Cmp [SI+36h], DL + JE Music_UnmuteChannel2 + +Music_UnmuteChannel4: + Test DH, DH + JS Music_UnmuteChannel5 + + Cmp [SI+33h], DH + JE Music_UnmuteChannel2 + +Music_UnmuteChannel5: +~ + And Byte Ptr [SI+1], Not 8 + Or Byte Ptr [SI], 64 + +Music_UnmuteChannel2: + Add SI, SLAVECHANNELSIZE + Loop Music_UnmuteChannel1 + + Pop DI + Pop SI + Pop DS + Pop CX + Pop AX + Ret + +EndP Music_UnmuteChannel + Assume DS:Nothing + +; + +Proc Music_ToggleChannel Far ; AX = channel number. + + Push BX + Push DS + + Mov BX, AX + Mov DS, CS:SongDataArea + + Test Byte Ptr [BX+40h], 80h + JZ Music_ToggleChannel1 + + And Byte Ptr [BX+40h], 7Fh + Call Music_UnmuteChannel + + Mov [CS:MuteChannelTable+BX], 0 + + Pop DS + Pop BX + Ret + +Music_ToggleChannel1: ; Mute channel + Xor [CS:MuteChannelTable+BX], 1 + Or Byte Ptr [BX+40h], 80h + Call Music_MuteChannel + + Pop DS + Pop BX + Ret + +EndP Music_ToggleChannel + +; + +Proc Music_UnmuteAll Far + + Push BX + Push CX + Push DX + Push DS + Push SI + + Jmp Music_SoloChannel3 + + +Proc Music_SoloChannel Far ; AX = channel + + Push BX + Push CX + Push DX + Push DS + Push SI + ; Check & count whether any playing. + + Mov BX, AX + + Mov DS, CS:SongDataArea + Mov SI, 40h + Mov CX, SI + Mov DX, CX + +Music_SoloChannel1: + LodsB + ShL AL, 1 + SbB DX, 0 + + Loop Music_SoloChannel1 + ; DX = num playing. + Cmp DX, 1 + JNE Music_SoloChannel6 + +Music_SoloChannel2: ; check whether it's the current + Test Byte Ptr [BX+40h], 80h + JZ Music_SoloChannel3 + +Music_SoloChannel6: + Mov CX, 64 ; 64 channel to step through + ; turn 'em all off. +Music_SoloChannel7: + Mov SI, CX + Dec SI + Cmp SI, BX + JE Music_SoloChannel9 + + Test Byte Ptr [SI+40h], 80h + JNZ Music_SoloChannel8 + +Music_SoloChannel10: + Mov AX, SI + Call Music_ToggleChannel + +Music_SoloChannel8: + Loop Music_SoloChannel7 + Jmp Music_SoloChannel11 + +Music_SoloChannel9: + Test Byte Ptr [SI+40h], 80h + JZ Music_SoloChannel8 + Jmp Music_SoloChannel10 + +Music_SoloChannel3: ; solo pressed on already soloed + ; channel -> turn everything on. + Mov CX, 64 + +Music_SoloChannel4: + Mov BX, CX + Dec BX + Cmp [CS:MuteChannelTable+BX], 1 + JNE Music_SoloChannel5 + + Mov AX, BX + Call Music_ToggleChannel + +Music_SoloChannel5: + Loop Music_SoloChannel4 + +Music_SoloChannel11: + Pop SI + Pop DS + Pop DX + Pop CX + Pop BX + + Ret + +EndP Music_SoloChannel +EndP Music_UnmuteAll + +; + +Proc Music_InitMuteTable Far + + Push AX + Push CX + Push ES + Push DI + + Mov DI, Offset MuteChannelTable + Mov CX, 32 + Push CS + Pop ES + + Xor AX, AX + Rep StosW + + Mov DWord Ptr [CS:SoloSample], 0FFFFh + + Pop DI + Pop ES + Pop CX + Pop AX + + Ret + +EndP Music_InitMuteTable + +; + +Proc Music_InitStereo Far + + Push DS + + Mov DS, CS:SongDataArea + Mov AL, [DS:2Ch] + And AL, 1 + + Call [DriverSetStereo] + + Push CS + Pop DS + Call RecalculateAllVolumes + + Pop DS + Ret + +EndP Music_InitStereo + +; + +Proc Music_IncreaseSpeed Far ; Returns AX = speed + + Mov AX, CS:CurrentSpeed + Cmp AX, 1 + JE Music_IncreaseSpeed1 + + Dec AX + Mov CS:CurrentSpeed, AX + Push DS + + Mov DS, SongDataArea + Mov [DS:32h], AL + + Pop DS + +Music_IncreaseSpeed1: + Ret + +EndP Music_IncreaseSpeed + +; + +Proc Music_DecreaseSpeed Far + + Mov AX, CS:CurrentSpeed + Cmp AX, 0FFh + JAE Music_DecreaseSpeed1 + + Inc AX + Mov CS:CurrentSpeed, AX + Push DS + + Mov DS, SongDataArea + Mov [DS:32h], AL + + Pop DS + + +Music_DecreaseSpeed1: + Ret + +EndP Music_DecreaseSpeed + +; + +Proc Music_SetSoundCard Far ; AL contains sound card num + + Xor AH, AH + + Push EBX + + Mov BX, CS + ShL EBX, 16 + + Mov BX, AX + Add BX, BX + Mov BX, [CS:DriverSoundCard+BX] + Add BX, BX + Mov BX, [CS:DriverNameTable+BX] + Mov [CS:DriverName], EBX + + Pop EBX + + Ret + +EndP Music_SetSoundCard + +; + +Proc Music_SetSoundCardDriver Far + + Mov Word Ptr [CS:DriverName], SI + Mov Word Ptr [CS:DriverName+2], DS + + Ret + +EndP Music_SetSoundCardDriver + +; + +Proc Music_SetDMA Far + + Xor AH, AH + Mov DMA, AX + + Ret + +EndP Music_SetDMA + +; + +Proc Music_SetMixSpeed Far + Assume DS:Nothing + + Mov CmdLineMixSpeed, CX + + Ret + +EndP Music_SetMixSpeed + +; + +Proc Music_SetIRQ Far + Assume DS:Nothing + + Mov IRQ, CX + + Ret + +EndP Music_SetIRQ + +; + +Proc Music_SetAddress Far + + Mov BasePort, DX + + Ret + +EndP Music_SetAddress + +; + +Proc Music_GetDisplayVariables Far + + Mov AX, CS:CurrentSpeed + MovZX BX, CS:Tempo + MovZX CX, CS:GlobalVolume + + Ret + +EndP Music_GetDisplayVariables + +; + +Proc Music_AssignSampleToInstrument Far ; BX = sample num + ; returns AX + + Push CX DX DS SI ES DI + + Push CS + Pop DS + Assume DS:Music + + Mov ES, SongDataArea + +; Check for sample-number's instrument first. + Mov AX, 554 + Mul BX + Mov DI, AX + Add DI, 512 + + LEA AX, [BX+1] + Mov SI, Offset InstrumentHeader + Mov CX, 554 + + RepE CmpsB + JE Music_AssignSampleToInstrument4 + +; Search + Mov CX, 99 + Mov DI, 512 ; Points to first inst. + Mov AX, 1 + +Music_AssignSampleToInstrument1: + Push CX + + Mov SI, Offset InstrumentHeader + Mov CX, 554 + + RepE CmpsB + JE Music_AssignSampleToInstrument2 + + Add DI, CX + Pop CX + Inc AX + Loop Music_AssignSampleToInstrument1 + + StC + +Music_AssignSampleToInstrumentEnd: + Pop DI ES SI DS DX CX + Ret + +Music_AssignSampleToInstrument2: + Pop CX ; Clear the stack + +Music_AssignSampleToInstrument4: +IF NETWORKENABLED + Call Network_GetSendQueue + JZ Music_AssignSampleNetwork + + Mov SI, AX + Mov AX, 400h + StosW + Mov AX, SI + Dec AX + StosB + +Music_AssignSampleNetwork: + Call Network_FinishedSendQueue +ENDIF + + Push ES + Pop DS + + Sub DI, 554-20h ; Points to name + Mov SI, BX + Mov SI, [64912+SI+BX] + Add SI, 14h + + Mov CX, 26 + Rep MovsB + + Add DI, 7 + + ; Now to fill in table. + Mov CX, 120 + Inc BX + +Music_AssignSampleToInstrument3: + Mov [DI], BL +; Add DI, 2 + ScasW + Loop Music_AssignSampleToInstrument3 + + ClC + Jmp Music_AssignSampleToInstrumentEnd + +EndP Music_AssignSampleToInstrument + Assume DS:Nothing + +; + +Proc Music_SetLimit Far + + Mov CS:CmdLineNumChannels, CX + Ret + +EndP Music_SetLimit + +; + +Proc Music_ReverseChannels Far + + Mov CS:ReverseChannels, 1 + Ret + +EndP Music_ReverseChannels + +; + +Proc Music_IncreaseVolume Far + + Push CX + Push DS + Push SI + + Push CS + Pop DS + Assume DS:Music + + Mov AL, GlobalVolume + And AX, 0FFh + Cmp AX, 128 + JAE Music_IncreaseVolume1 + + Inc AX + Mov GlobalVolume, AL + Call RecalculateAllVolumes + +Music_IncreaseVolume1: + Pop SI + Pop DS + Pop CX + + Ret + +EndP Music_IncreaseVolume + Assume DS:Nothing + +; + +Proc Music_DecreaseVolume Far + + Push CX + Push DS + Push SI + + Push CS + Pop DS + Assume DS:Music + + Mov AL, GlobalVolume + And AX, 0FFh + JZ Music_DecreaseVolume1 + + Dec AX + Mov GlobalVolume, AL + Call RecalculateAllVolumes + +Music_DecreaseVolume1: + Pop SI + Pop DS + Pop CX + + Ret + +EndP Music_DecreaseVolume + Assume DS:Nothing + +; + +Proc Music_RegetLoopInformation Far + + Push AX + Push BX + Push CX + Push DX + + Push DS + Push SI + Push ES + + Push CS + Pop DS ; DS setup + Assume DS:Music + + Mov ES, SongDataArea + + Mov CX, NumChannels + Mov SI, Offset SlaveChannelInformationTable + +Music_RegetLoopInformation1: + Test Byte Ptr [SI], 1 + JZ Music_RegetLoopInformation2 + + Push CX + ClI + + Call GetLoopInformation + + Or Byte Ptr [SI], 40h + + StI + Pop CX + +Music_RegetLoopInformation2: + Add SI, SLAVECHANNELSIZE + Loop Music_RegetLoopInformation1 + + + + Pop ES + Pop SI + Pop DS + + Pop DX + Pop CX + Pop BX + Pop AX + + Ret + +EndP Music_RegetLoopInformation + Assume DS:Nothing + +; + +Proc ResetSoundCardMemory Far + + Jmp [DriverResetMemory] + +EndP ResetSoundCardMemory + +; + +Proc Music_SoundCardLoadSample Far ; AX = sample number + ; (1 based) + ; Carry set if insuf mem + PushA + Call [DriverLoadSample] + PushF + + JC Music_SoundCardLoadSample1 + + Mov CX, 2 + Mov DI, Offset O1_OutOfSoundCardMemoryList + Call M_Object1List + +Music_SoundCardLoadSample1: + PopF + PopA + Ret + +EndP Music_SoundCardLoadSample + +; + +Proc Music_SoundCardLoadAllSamples Far + + PushAD + Push DS + + Call Music_Stop + Call S_SaveScreen + + Push 30 + Push 28 + Push 50 + Push 30 + Push 3 + Call S_DrawBox + Add SP, 10 + + Push CS + Pop DS + + Mov DI, (32+29*80)*2 + Mov SI, Offset PrepareSamplesMsg + Mov AH, 20h + Call S_DrawString + + Call S_UpdateScreen + + Call ResetSoundCardMemory + + Mov AX, 1 + +Music_SoundCardLoadAllSamples1: + Call Music_SoundCardLoadSample + JNC Music_SoundCardLoadAllSamples2 + + Inc AX + Cmp AX, 100 + JBE Music_SoundCardLoadAllSamples1 + +Music_SoundCardLoadAllSamples3: + Call S_RestoreScreen + +Music_SoundCardLoadAllSamples2: + Pop DS + PopAD + + Mov AX, 1 + Ret + +EndP Music_SoundCardLoadAllSamples + Assume DS:Nothing + +; + +Proc Music_GetFreeSoundCardMemory Far + + Call [DriverGetStatus] + Ret + +EndP Music_GetFreeSoundCardMemory + +; + +Proc Music_GetNumChannels Far + + Mov AX, CS:NumChannels + + Ret + +EndP Music_GetNumChannels + +; + +Proc Music_GetPitchTable Far ; Returns ES:DI to pitch table + + Push CS + Pop ES + Mov DI, Offset PitchTable + + Ret + +EndP Music_GetPitchTable + +; + +Proc Music_ToggleReverse Far + + Push CS + Pop DS + Assume DS:Music + + Xor ReverseChannels, 1 + Call ReCalculateAllVolumes + Mov SI, Offset ReverseMsg + Call SetInfoLine + + Ret + +EndP Music_ToggleReverse + Assume DS:Nothing + +; + +Proc Music_PatternStorage Far + + Mov CS:PatternStorage, AL + Ret + +EndP Music_PatternStorage + +; + +Proc Music_InitMixTable Far + + Push AX + Push DS + + Xor AX, AX + Mov DS, CS:SongDataArea + Mov AL, Byte Ptr [DS:31h] ; AL = 0->128 + + Call [DriverSetMixVolume] + + Pop DS + Pop AX + Ret + +EndP Music_InitMixTable + +; + +Proc Music_GetTempo Far + + Xor BH, BH + Mov BL, CS:Tempo + + Ret + +EndP Music_GetTempo + +; + +Proc Music_GetLastChannel Far ; Returns AX + + Push DS + + Mov DS, CS:SongDataArea + Xor SI, SI + Mov CX, 64 + Xor AX, AX + Xor DX, DX + +Music_GetLastChannel1: + Mov BL, [SI+40h] + ShR BL, 7 + Xor BL, [CS:MuteChannelTable+SI] + JNZ Music_GetLastChannel2 + + Mov AX, DX + +Music_GetLastChannel2: + Inc DX + Inc SI + Loop Music_GetLastChannel1 + + Pop DS + Ret + +EndP Music_GetLastChannel + +; + +Proc Music_GetDriverScreen Far + + Jmp [DriverSoundCardScreen] + +EndP Music_GetDriverScreen + +; + +Proc Music_GetDriverVariable Far + + Jmp [DriverGetVariable] + +EndP Music_GetDriverVariable + +; + +Proc Music_SetDriverVariable Far + + Jmp [DriverSetVariable] + +EndP Music_SetDriverVariable + +; + +Proc Music_SetNextOrder Far + + Dec AX + Mov CS:ProcessOrder, AX + + Ret + +EndP Music_SetNextOrder + +; + +Proc Music_GetDelay Far + + ClI + + Xor DX, DX + Mov CX, CS:PlayMode + Test CX, CX + JZ Music_GetDelay2 + + Mov DX, CS:CurrentSpeed + Cmp AX, CS:CurrentRow + JNE Music_GetDelay3 + + Sub DX, CS:ProcessTick + JZ Music_GetDelay2 + + Cmp DX, 0Fh + JAE Music_GetDelay4 + Jmp Music_GetDelay1 + +Music_GetDelay3: + Dec DX + Cmp DX, 0Fh + JBE Music_GetDelay1 + +Music_GetDelay4: + Mov DX, 0Fh + +Music_GetDelay1: + ShL DX, 8 + Or DX, 'S'-'@'+0D000h + +Music_GetDelay2: + StI + Ret + +EndP Music_GetDelay + +; +; + +StopSong DB 0 +TimerCounter DD 0 +TotalTimer DD 0 +TotalTimerHigh DD 0 +PleaseWaitMsg DB "Please Wait...", 0 + +Proc InternalTimer Far + + PushAD + + Mov EAX, 0C214h + Mov DX, 16h ; Ticks = (1193181/(2*0.4))/Tempo + Div BX + Add EAX, EAX + Mov CS:TimerCounter, EAX + + PopAD + Ret + +EndP InternalTimer + +; + +Proc Music_TimeSong Far ; Time song! + + Push CS + Pop DS + Assume DS:Music + + Call S_SaveScreen + + Mov AL, 1 + Call S_SetDirectMode + Call S_DrawSmallBox + + Mov SI, Offset PleaseWaitMsg + Mov AH, 20h + Mov DI, (33+26*80)*2 + Call S_DrawString + + Call Music_Stop + + Mov CX, 0FFFFh + +Music_TimeSong1: + In AL, 21h ; Delay mechanism + In AL, 0A1h ; Delay mechanism + Loop Music_TimeSong1 + + Mov StopSong, 0 + Mov TotalTimer, 0 + Mov TotalTimerHigh, 0 + + ClI + In AL, 0A1h + Mov AH, AL + In AL, 21h + Push AX + + Mov AL, 0FFh + Out 0A1h, AL + Out 21h, AL + + Push DWord Ptr [DriverSetTempo] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset InternalTimer + Mov [DriverSetTempo], EAX + + Push Word Ptr [NumChannels] + + Mov ES, SongDataArea + + Push Word Ptr [ES:2Ch] + And Byte Ptr [ES:2Ch], Not 4 + + Xor AX, AX + Call Music_PlaySong + +Music_TimeSong3: + Assume DS:Nothing + Call Update + + Cmp CS:StopSong, 0 + JNE Music_TimeSong4 + + Mov EAX, CS:TimerCounter + Add CS:TotalTimer, EAX + AdC CS:TotalTimerHigh, 0 + Jmp Music_TimeSong3 + +Music_TimeSong4: + Call Music_Stop + + Mov ES, CS:SongDataArea + + Pop Word Ptr [ES:2Ch] + Pop Word Ptr [CS:NumChannels] + Pop DWord Ptr [CS:DriverSetTempo] + + Pop AX + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + StI + + Mov AL, 0 + Call S_SetDirectMode + + Call S_RestoreScreen + + Mov CX, 0FFFFh + Mov DI, Offset O1_ShowTime + Call M_Object1List + + Mov AX, 1 + Ret + +EndP Music_TimeSong + +; + +Proc Music_ShowTime Far + + Call S_GetDestination + + Mov EDX, CS:TotalTimerHigh + Mov EAX, CS:TotalTimer + + SHRD EAX, EDX, 16 + + Mov DI, (43+27*80)*2 + Call D_ShowTime + + Ret + +EndP Music_ShowTime + +; + +Proc Music_GetPatternLength Far + + Mov AX, CS:NumberOfRows + Ret + +EndP Music_GetPatternLength + +; + +Proc Music_SaveMIDIConfig Far + + Call D_GotoStartingDirectory + + Push CS + Pop DS + Assume DS:Music + + Mov AH, 3Ch + Xor CX, CX + Mov DX, Offset MIDIConfigFileName + Int 21h + JC Music_SaveMIDIConfig1 + + Mov BX, AX + + Mov AH, 40h + Mov DS, CS:MIDIDataArea + Xor DX, DX + Mov CX, (128+16+9)*32 + Int 21h + + Mov AH, 3Eh + Int 21h + +Music_SaveMIDIConfig1: + Xor AX, AX + Ret + +EndP Music_SaveMIDIConfig + Assume DS:Nothing + +; + +Proc Music_GetMIDIDataArea Far + + Mov DS, CS:MIDIDataArea + Ret + +EndP Music_GetMIDIDataArea + +; + +Proc Music_ToggleOrderUpdate Far + + Push CS + Pop DS + Assume DS:Music + + Mov SI, Offset OrderUpdateEnabledMsg + Xor OrderLockFlag, 1 + JZ Music_ToggleOrderUpdate1 + + Mov SI, Offset OrderUpdateDisabledMsg + +Music_ToggleOrderUpdate1: + Call SetInfoLine + + Ret + +EndP Music_ToggleOrderUpdate + Assume DS:Nothing + +; + +Proc Music_ToggleSoloInstrument Far + + Mov SI, Offset SoloInstrumentMsg + Mov DI, Offset SoloInstrument + Mov BP, 1 + Jmp Music_ToggleSolo + +EndP Music_ToggleSoloInstrument + +; + +Proc Music_ToggleSoloSample Far + + Mov SI, Offset SoloSampleMsg + Mov DI, Offset SoloSample + Xor BP, BP + +EndP Music_ToggleSoloSample + +; + +Proc Music_ToggleSolo Far + + Push CS + Pop DS + Assume DS:Music + + Call PE_GetLastInstrument ; Returns BX + + Mov AX, BX + Add BX, BP + + Cmp [DI], BL + Mov Word Ptr [SoloSample], 0FFFFh + JE Music_ToggleSolo1 + + Inc AX + Mov Byte Ptr [DI], BL + + Jmp Music_ToggleSolo2 + +Music_ToggleSolo1: + Mov SI, Offset UnsoloMsg + +Music_ToggleSolo2: + Call SetInfoLine + + Mov CX, NumChannels + Mov SI, Offset SlaveChannelInformationTable + Xor BX, BX + + Mov ES, SongDataArea + +Music_ToggleSolo3: + Or Byte Ptr [SI], 18 + Mov BL, [SI+3Ah] ; BX = channel + + Test Byte Ptr [ES:BX+40h], 80h + JNZ Music_ToggleSolo4 + + And Word Ptr [SI], Not 800h + +Music_ToggleSolo4: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ Music_ToggleSolo3 + + Call RecalculateAllVolumes + + Mov AX, 1 + Ret + +EndP Music_ToggleSolo + Assume DS:Nothing + + +; + +EndS + +; + +End diff --git a/it/IT_M_EFF.INC b/it/IT_M_EFF.INC new file mode 100644 index 0000000..0bbc2be --- /dev/null +++ b/it/IT_M_EFF.INC @@ -0,0 +1,2945 @@ +; + +SlideTable DB 1, 4, 8, 16, 32, 64, 96, 128, 255 + +; + +Comment ~ + +Proc GetC5Speed + + Push BX + Push SI + Push BP + + Cmp Byte Ptr [DI+0Fh], 101 ; MIDI sample + JNE GetC5Speed1 + +; OK.. we have a MIDI sample +; Check whether the midi sample points to a valid sample +; And if so, use that sample's C5 speed. + Mov SI, [DS:DI+3] ; Not a note? + And SI, 0FFh + + Mov BP, [DS:DI+4] + And EBP, 0FFh + JZ GetC5Speed1 ; No sample? + + Add SI, SI + Mov BP, [ES:64710+EBP+EBP] + + Mov AX, [ES:BP+SI+40h] ; AL = note + ; AH = sample. + + Test AH, AH ; No sample? + JZ GetC5Speed1 + Mov SI, AX + ShR SI, 8 + + Add SI, SI + Mov SI, [ES:64910+SI] ; Sample offset + Test Byte Ptr [ES:SI+12h], 1 + JZ GetC5Speed1 + + Mov BX, SI + +GetC5Speed1: + Mov EAX, [ES:BX+3Ch] ; EAX = C5Spd + + Pop BP + Pop SI + Pop BX + + Ret + +EndP GetC5Speed + +~ + +; + +Proc InitVolumeEffect ; Done A, B, H + + Test Byte Ptr [DI+2], 44h + JNZ InitVolumeProcess + +InitVolumeEffectNoEffect: + Ret + +InitVolumeProcess: + Mov AL, [DI+5] + Mov AH, AL + + And AL, 7Fh + Sub AL, 65 + JC InitVolumeEffectNoEffect + + Test AH, 80h + JZ InitVolumeEffect1 + + Add AL, 60 + +InitVolumeEffect1: + Mov DL, 10 + Xor AH, AH + Div DL ; AL = effect number + ; AH = effect parameter + Mov [DI+0Ah], AL ; Store effect number + + ; Memory for effects A->D, (EFG)/H dont' share. + + ; Effects Ax and Bx (fine volume slide up and down) require immediate + ; handling. No flags required. (effect 0 and 1) + + ; Effects Cx, Dx, Ex, Fx (volume/pitch slides) require flag to be + ; set (effects 2->5) + + ; Effects Gx and Hx need init (handling) code + flags. + ; (effects 6 and 7). + + Test AH, AH + JZ InitVolumeEffectNoMemory + + Cmp AL, 4 + JB InitNormalMemory + + Cmp AL, 6 + JB InitSlideMemory + JA InitVolumeEffectNoMemory + + MovZX BX, AH + Mov DL, [SlideTable+BX-1] + + Test Byte Ptr [ES:2Ch], 20h ; Link command G? + JZ CommandGMemoryOldEffects + + Mov [DI+1Eh], DL + Jmp InitVolumeEffectNoMemory + +CommandGMemoryOldEffects: + Mov [DI+11h], DL + Jmp InitVolumeEffectNoMemory + +InitSlideMemory: + ShL AH, 2 + Mov [DI+11h], AH + Jmp InitVolumeEffectNoMemory + +InitNormalMemory: + Mov [DI+0Bh], AH + +InitVolumeEffectNoMemory: + Test Byte Ptr [DI], 4 ; Channel not on! + JZ InitVolumeEffect3 + Mov SI, [DI+24h] + + Cmp AL, 1 + JA InitVolumeEffect2 + Mov AL, [DI+0Bh] + JE InitVolumeEffectB + +InitVolumeEffectA: ; Fine volume slide up. + Add AL, [SI+22h] + Cmp AL, 64 + JBE InitVolumeEffectABEnd + Mov AL, 64 + Jmp InitVolumeEffectABEnd + +InitVolumeEffectB: ; Fine volume slide down + Sub AL, [SI+22h] + Neg AL + JNS InitVolumeEffectABEnd + Xor AL, AL + +InitVolumeEffectABEnd: + Jmp CommandD2 + +InitVolumeEffect2: + Or Word Ptr [DI], 100h + + Cmp AL, 6 + JA InitVolumeEffectH + JE InitVolumeEffectG + +InitVolumeEffectCDEF: +InitVolumeEffectEnd: + Ret + +InitVolumeEffect3: + Cmp AL, 7 ; Vibrato? + JNE InitVolumeEffectCDEF + +InitVolumeEffectH: + ShL AH, 2 + JZ InitVolumeEffectH1 + + Mov [DI+3Ah], AH + +InitVolumeEffectH1: + Test Byte Ptr [DI], 4 + JZ InitVolumeEffectCDEF + + Jmp InitVibrato + +InitVolumeEffectG: + Jmp InitCommandG11 + +EndP InitVolumeEffect + +; + +Proc VolumeCommandC + + Mov SI, [DI+24h] + Mov AL, [DI+0Bh] + Add AL, [SI+22h] + Cmp AL, 64 + JBE VolumeCommandC1 + + And Word Ptr [DI], Not 100h ; Turn off effect calling + Mov AL, 64 + +VolumeCommandC1: + Jmp CommandD2 + +EndP VolumeCommandC + +; + +Proc VolumeCommandD + + Mov SI, [DI+24h] + Mov AL, [SI+22h] + Sub AL, [DI+0Bh] + JNC VolumeCommandD1 + + And Word Ptr [DI], Not 100h ; Turn off effect calling + Xor AL, AL + +VolumeCommandD1: + Jmp CommandD2 + +EndP VolumeCommandD + +; + +Proc VolumeCommandE ; Pitch slide down + + Mov BX, [DI+11h] + And BX, 0FFh + ShL BX, 2 + Jmp CommandEChain + Ret + +EndP VolumeCommandE + +; + +Proc VolumeCommandF + + Mov BX, [DI+11h] + And BX, 0FFh + ShL BX, 2 + Jmp CommandFChain + +EndP VolumeCommandF + +; + +Proc VolumeCommandG + + Test Byte Ptr [DI], 16 + JZ VolumeCommandGEnd + + Mov BX, [DI+11h] + + Test Byte Ptr [ES:2Ch], 20h ; Command G linked? + JZ VolumeCommandGMemoryOldEffects + + Mov BX, [DI+1Eh] + +VolumeCommandGMemoryOldEffects: + And BX, 0FFh + JZ VolumeCommandGEnd + + ShL BX, 2 + + Mov SI, [DI+24h] + + Cmp Byte Ptr [DI+42h], 1 + JE VolumeCommandG1 + ; Slide down + Call PitchSlideDown + ; Check that frequency is above porta + ; to frequency. + Mov EAX, [SI+10h] + Cmp EAX, [DI+34h] + JA VolumeCommandG6 + +VolumeCommandG4: + Mov EAX, [DI+34h] + And Word Ptr [DI], Not (110h) ; Turn off calling + +VolumeCommandG3: + Mov [SI+10h], EAX + +VolumeCommandG6: + Mov [SI+14h], EAX + +VolumeCommandGEnd: + Ret + +VolumeCommandG1: ; Slide up! + Call PitchSlideUp + ; Check that + ; 1) Channel is on + ; 2) Frequency (set) is below porta to + ; frequency + Mov EAX, [SI+10h] + + Test Word Ptr [SI], 200h + JNZ VolumeCommandG5 + + Cmp EAX, [DI+34h] + JB VolumeCommandG6 + +VolumeCommandG5: + And Word Ptr [SI], Not 200h + Or Byte Ptr [DI], 4 ; Turn on. + Jmp VolumeCommandG4 + +EndP VolumeCommandG + +; + +InitNoCommand4: + Test CH, 4 + JZ InitNoCommand10 ; Taken if the channel's off. + + Mov SI, [DI+24h] + + Cmp AL, 0FEh + JA InitNoCommand5 ; Noteoff + JNE InitNoCommandNoteFade + + And CH, Not 4 + + Cmp Byte Ptr [SI+36h], 100 + JE MIDINoteCut + + Test Byte Ptr CS:DriverFlags, 2 + JNZ MIDINoteCut + + Mov Word Ptr [SI], 200h + Jmp NoOldEffect + +MIDINoteCut: +; And CH, Not 4 + Or Word Ptr [SI], 200h + +InitNoCommand10: ; Jump point. + Jmp NoOldEffect ; InitNoCommand1 + +InitNoCommandNoteFade: + Or Byte Ptr [SI], 8 ; Note fade + + Jmp NoOldEffect ; InitNoCommand1 + +InitNoCommand5: + Or Byte Ptr [SI], 4 ; Note off + +; Cmp Byte Ptr [SI+22h], 0 ; Volume = 0??? +; JE InitNoCommand13 + Jmp InitNoCommand11 + +Proc InitNoCommand ; DS:DI points to CIT area. + + Assume DS:Music + Mov CL, [DI+2] ; CL = mask + Mov CH, [DI] ; CH = channel info. + + Test CL, 33h + JZ NoOldEffect ; InitCommand1 + + ; Note here! + ; Check for noteoff. + Mov AL, [DI+0Eh] + Cmp AL, 120 + JAE InitNoCommand4 + + Test CH, 4 + JZ InitNoCommand9 + + Mov SI, [DI+24h] + Test CL, 11h + JNZ InitNoCommand9 + + Mov BX, [SI+32h] + Cmp BX, [DI+03h] + JE NoOldEffect ; InitNoCommand1 + +InitNoCommand9: + Test CL, 44h + JZ NoVolumePorta + + Cmp Byte Ptr [DI+5], 193 + JB NoVolumePorta + Cmp Byte Ptr [DI+5], 202 + JA NoVolumePorta + + Test Byte Ptr [DI], 4 + JNZ InitVolumeEffect + +NoVolumePorta: + Call AllocateChannel +; JC InitNoCommand1 + JC NoOldEffect + ; Channel allocated. + ; put volume + Mov BX, [SI+34h] ; Sample offset. + Mov AL, [DI+22h] + Mov AH, AL + Mov [SI+21h], AX ; Volset + + Test Byte Ptr [ES:2Ch], 4 ; Instrument mode? + JNZ InitNoCommandNoDefaultPan + + Mov AL, [ES:BX+2Fh] + Test AL, AL + JNS InitNoCommandNoDefaultPan + + Mov AH, AL + And AX, 7F7Fh + Mov [DI+2Eh], AL + Mov [SI+2Ah], AX + +InitNoCommandNoDefaultPan: + Mov EAX, [ES:BX+3Ch] ; EAX = C5Spd +; Call GetC5Speed + + Xor EBX, EBX + Mov [SI+2Ch], EBX + Mov [SI+48h], BX + Mov [SI+4Ch], EBX + ; Calculate frequency. + Mov BL, [DI+0Eh] ; BL = note. + + Mul [PitchTable+4*EBX] + SHRD EAX, EDX, 16 + Mov [SI+10h], EAX + Mov [SI+14h], EAX + + Or CH, 4 + And CH, Not 16 + +InitNoCommand11: + Push CX + Call GetLoopInformation + Pop CX + +InitNoCommand1: + Test CL, 22h+44h + JZ InitNoCommand3 + + Mov AH, [ES:2Ch] ; Instrument mode and old effects? + And AH, 14h + Cmp AH, 14h + JNE NoOldEffect +; Test AH, 4 +; JZ NoOldEffect + + Test CL, 22h + JZ NoOldEffect + + MovZX EBX, Byte Ptr [DI+4] + Cmp BL, 0FFh + JE NoOldEffect + + Mov Word Ptr [SI+26h], 0400h + Mov BX, [ES:EBX*2+64710] ; Instrument offset. + + Call InitPlayInstrument + +NoOldEffect: + Test CL, 44h + JZ InitNoCommand7 + + Mov AL, [DI+5] + Cmp AL, 64 + JBE InitNoCommand8 ; Volume set... + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JNC InitNoCommand7 + +InitNoCommandPanning: ; Panning set! + Mov [DI], CH + + Sub AL, 128 + Call InitCommandX2 ; Destroys (SI), AX + +InitNoCommand7: + Test CL, 22h ; Instrument present? -> + ; Change volume + JZ InitNoCommand3 + + Mov BL, [DI+0Fh] ; Get instrument offset. + And BX, 0FFh + JZ InitNoCommand3 + + Add BX, BX + Mov BX, [ES:64910+BX] + + Mov AL, [ES:BX+13h] ; Default volume + +InitNoCommand8: + Mov [DI+22h], AL + + Test CH, 4 + JZ InitNoCommand3 + + Mov SI, [DI+24h] + + Mov AH, AL + Mov [SI+21h], AX + Or Byte Ptr [SI], 10h ; recalc volume + +InitNoCommand3: ; Randomise volume if required. + Test Byte Ptr [DI], 80h + Mov [DI], CH + JZ InitNoCommandEnd + + Push CX + Call ApplyRandomValues + Pop CX + +InitNoCommandEnd: + Jmp InitVolumeEffect + +EndP InitNoCommand + Assume DS:Nothing + +; + +Proc InitCommandA + + Assume DS:Music + + Mov AL, [DS:DI+7] + And AX, 0FFh + JZ InitCommandA_1 + + Mov CX, CurrentSpeed + Sub CurrentTick, CX + Sub ProcessTick, CX + Add CurrentTick, AX + Add ProcessTick, AX + Mov CurrentSpeed, AX + +InitCommandA_1: + Jmp InitNoCommand + +EndP InitCommandA + Assume DS:Nothing + +; + +Proc InitCommandB + Assume DS:Music + + MovZX AX, Byte Ptr [DI+7] + Cmp AX, CurrentOrder + JA InitCommandB1 + + Mov StopSong, 1 + +InitCommandB1: + Dec AX + Mov ProcessOrder, AX + Mov ProcessRow, 0FFFEh + + Jmp InitNoCommand + +EndP InitCommandB + Assume DS:Nothing + +; + +Proc InitCommandC + + Assume DS:Music + + Cmp PatternLooping, 0 + JNE InitCommandC1 + + MovZX AX, Byte Ptr [DS:DI+7] + Mov BreakRow, AX + + Mov ProcessRow, 0FFFEh + +InitCommandC1: + Jmp InitNoCommand + +EndP InitCommandC + Assume DS:Nothing + +; + +Proc InitCommandD + Assume DS:Music + + Call InitNoCommand + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandD1 + + Mov [DI+10h], AL + +InitCommandD1: + Test Byte Ptr [DI], 4 + JZ InitCommandD6 + + Mov SI, [DI+24h] + +InitCommandD7: ; Jmp point for Lxx + Mov AL, [DI+10h] + Or Byte Ptr [SI], 16 ; Recalc vol + + Mov AH, AL + Test AH, 0Fh + JZ InitCommandD2 + Test AH, 0F0h + JZ InitCommandD3 + And AX, 0FF0h + Cmp AH, 0Fh + JE InitCommandD5 + Cmp AL, 0F0h + JE InitCommandD4 + +InitCommandD6: + Ret + +InitCommandD2: ; Slide up. + ShR AL, 4 + Mov [DI+30h], AL + + Or Byte Ptr [DI], 1 + Cmp AL, 0Fh + JE InitCommandD8 + + Ret + +InitCommandD8: + Jmp CommandD + +InitCommandD3: ; Slide down + Neg AL + Mov [DI+30h], AL + + Or Byte Ptr [DI], 1 + Cmp AL, -15 + JE InitCommandD9 + + Ret + +InitCommandD9: + Jmp CommandD + +InitCommandD4: ; Slide down (fine) + Mov Byte Ptr [DI+30h], 0 + Mov AL, [SI+22h] + Sub AL, AH ; Slide down + JNS InitCommandD4_1 + + Xor AL, AL + +InitCommandD4_1: + Mov AH, AL + Mov [SI+21h], AX + Mov [DI+22h], AL + Ret + +InitCommandD5: ; Slide up (fine) + Mov Byte Ptr [DI+30h], 0 + + ShR AL, 4 + Mov AH, [SI+22h] + Add AL, AH + Cmp AL, 64 + JBE InitCommandD4_1 + + Mov AL, 64 + Jmp InitCommandD4_1 + +EndP InitCommandD + Assume DS:Nothing + +; + +Proc InitCommandE + Assume DS:Music + + Call InitNoCommand + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandE2 + + Mov [DI+11h], AL + +InitCommandE2: + Test Byte Ptr [DI], 4 + JZ InitCommandE1 + + Mov SI, [DI+24h] + Mov AL, [DI+11h] + + Test AL, AL + JZ InitCommandE1 ; still no slide?? + + Mov AH, AL + And AH, 0F0h + Cmp AH, 0E0h + JB InitCommandE4 + + And AL, 0Fh + JZ InitCommandE1 + + Xor BX, BX + + Cmp AH, 0E0h + JE InitCommandE5 + + ShL AL, 2 + +InitCommandE5: + Mov BL, AL + Call PitchSlideDown + + Mov EAX, [SI+10h] + Mov [SI+14h], EAX + Ret + +InitCommandE4: + Xor AH, AH + ShL AX, 2 + Mov [DI+40h], AX + Or Byte Ptr [DI], 1 ; call update only if necess. + +InitCommandE1: + Ret + +EndP InitCommandE + Assume DS:Nothing + +; + +Proc InitCommandF + Assume DS:Music + + Call InitNoCommand + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandF2 + + Mov [DI+11h], AL + +InitCommandF2: + Test Byte Ptr [DI], 4 + JZ InitCommandF1 + + Mov SI, [DI+24h] + ; OK.. now processing is dependent + ; upon slide mode. + + Mov AL, [DI+11h] + Test AL, AL + JZ InitCommandF1 ; still no slide?? + + Mov AH, AL + And AH, 0F0h + Cmp AH, 0E0h + JB InitCommandF4 + + And AL, 0Fh + JZ InitCommandF1 + + Xor BX, BX + + Cmp AH, 0E0h + JE InitCommandF5 + + ShL AL, 2 + +InitCommandF5: + Mov BL, AL + Call PitchSlideUp + + Mov EAX, [SI+10h] ; Update frequency set field. + Mov [SI+14h], EAX + Ret + +InitCommandF4: + Xor AH, AH + ShL AX, 2 + Mov [DI+40h], AX + Or Byte Ptr [DI], 1 ; call update only if necess. + +InitCommandF1: + Ret + +EndP InitCommandF + Assume DS:Nothing + +; + +InitCommandG15: + Jmp InitNoCommand + +Proc InitCommandG + Assume DS:Music + ; Check whether channel on/owned + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandG6 + + Test Byte Ptr [ES:2Ch], 20h ; Compatibility Gxx? + JZ InitCommandGNotOldEffects1 + + Mov [DI+1Eh], AL + Jmp InitCommandG6 + +InitCommandGNotOldEffects1: + Mov [DI+11h], AL + +InitCommandG6: + Test Byte Ptr [DI], 4 + JZ InitCommandG15 + +InitcommandG11: ; Jumped to from Lxx + Mov SI, [DI+24h] + + Mov CL, [DI+2] ; CL = mask. + + Test CL, 22h + JZ InitCommandG17 + ; Checking for change of + ; Sample or instrument. + Mov AL, [DI+0Fh] ; Sample + And EAX, 0FFh + JZ InitCommandG17 + + Dec AX + + Mov DX, [DI+3] + Test Byte Ptr [ES:2Ch], 20h + JNZ InitGXXCompat1 + +; Don't overwrite note if MIDI! + Cmp Byte Ptr [DI+0Fh], 101 + JE InitCommandG13 + + Cmp [SI+33h], DH ; Ins the same? + Mov [SI+32h], DX ; Nte + Ins. + + JNE InitCommandG19 + + Cmp AL, [SI+36h] + JNE InitCommandG16 + +InitCommandG17: + Jmp InitCommandG13 + +InitCommandGNoSample: + Mov Word Ptr [SI], 200h + And Byte Ptr [DI], Not 4 + Ret + +InitGXXCompat1: + Mov AL, [SI+36h] + Inc AX + Mov [DI+0Fh], AL + + Mov BX, [ES:EAX+EAX+64910] + Mov AX, [ES:BX+11h] + Add AL, AL + Mov [SI+24h], AL + + Jmp InitCommandG18 + +InitCommandG19: + Cmp AL, [SI+36h] ; Sample the same? + JE InitCommandG18 + +InitCommandG16: + Mov BX, [ES:EAX+EAX+64912] + Mov Byte Ptr [SI+1], 1 + ; Now to update sample info. + Mov [SI+34h], BX ; Offset of sample + Mov [SI+36h], AL ; Sample num. + + Xor EAX, EAX + + Mov [SI+1Ah], AX ; Reset vibrato.. + Mov [SI+0Bh], AL ; Reset loop direction. + Mov [SI+2Ch], EAX + Mov [SI+48h], AX + Mov [SI+4Ch], EAX + + Mov AX, [ES:BX+11h] + Add AL, AL + Mov [SI+24h], AL + + Test AH, 1 + JZ InitCommandGNoSample + + And AH, 2 ; 16 bit... + ShR AX, 8 + Mov [SI+18h], AX + + Call GetLoopInformation + Mov CL, [DI+2] + +InitCommandG18: + Test Byte Ptr [ES:2Ch], 4 ; Instrument/sample mode? + JZ InitCommandG14 + ; Now for instruments + + Mov Word Ptr [SI+26h], 0400h + MovZX EBX, Byte Ptr [DI+4] + + Mov BX, [ES:EBX*2+64710] ; Instrument offset. + + Push Word Ptr [SI] + Call InitPlayInstrument + Pop AX + + Test AL, 1 + JZ InitCommandGXXCompat3 + + And Word Ptr [SI], Not 100h + +InitCommandGXXCompat3: + + Mov AL, [ES:BX+18h] + Mul Byte Ptr [SI+24h] + ShR AX, 7 + Mov [SI+24h], AL + + Jmp InitCommandG14 + +InitCommandG13: + Test CL, 11h + JZ InitCommandG1 + + ; OK. Time to calc freq. +InitCommandG14: + Mov AL, [DI+0Eh] + Cmp AL, 119 + JBE InitCommandG5 + +InitCommandG12: + Test Byte Ptr [DI], 4 + JZ InitCommandG1 + + Cmp AL, 0FEh + JA InitCommandGNoteOff + JNE InitCommandGNoteFade + + And Byte Ptr [DI], Not 4 ; Note cut! + Mov Word Ptr [SI], 200h ; Cut. + Jmp InitCommandG1 + +InitCommandGNoteOff: + Or Byte Ptr [SI], 4 ; Note off + Push CX + Call GetLoopInformation + Pop CX + Jmp InitCommandG1 + +InitcommandGNoteFade: + Or Byte Ptr [SI], 8 + Jmp InitCommandG1 + +InitCommandG5: +; Don't overwrite note if MIDI! + Cmp Byte Ptr [DI+0Fh], 101 + JE InitCommandGMIDI2 + + Mov [SI+32h], AL + +InitCommandGMIDI2: + Xor EDX, EDX + Mov BX, [SI+34h] + Mov DL, AL + Mov EAX, [ES:BX+3Ch] ; BP = C5Spd +; Call GetC5Speed + + Mul [PitchTable+EDX*4] + SHRD EAX, EDX, 16 + + Mov [DI+34h], EAX + Or Byte Ptr [DI], 16 + +InitCommandG1: + Test CL, 44h + JZ InitCommandG2 +; JZ InitCommandG3 + + Mov AL, [DI+5] + + Cmp AL, 64 + JBE InitCommandG4 + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JNC InitCommandG2 + +InitCommandGPanning: + Sub AL, 128 + Call InitCommandX2 ; Panning set... + +InitCommandG2: + Test CL, 22h + JZ InitCommandG3 + + Mov BX, [SI+34h] ; Sample memory offset. + Mov AL, [ES:BX+13h] + +InitCommandG4: + Or Byte Ptr [SI], 16 ; recalc volume. + Mov AH, AL + Mov [SI+21h], AX + Mov [DI+22h], AL + +InitCommandG3: + Test Byte Ptr [DI], 16 ; Slide on??? + JZ InitCommandGEnd + + MovZX AX, Byte Ptr [DI+11h] ; Work out magnitude + dirn + + Test Byte Ptr [ES:2Ch], 20h ; Command G memory + JZ InitCommandGNotOldEffects2 + + Mov AL, [DI+1Eh] + +InitCommandGNotOldEffects2: + ShL AX, 2 + JZ PrepareCommandGEnd + + Mov [DI+40h], AX + + Mov AX, [DI+34h] + Mov DX, [DI+36h] ; Port freq. + + Cmp DX, [SI+16h] + JA InitCommandG8 + JB InitCommandG9 + Cmp AX, [SI+14h] + JA InitCommandG8 + JB InitCommandG9 + ; equal?!?!? + ; then don't update effect. + Jmp PrepareCommandGEnd + +InitCommandG8: + Mov Byte Ptr [DI+42h], 1 ; slide up + Jmp InitCommandG10 + +InitCommandG9: + Mov Byte Ptr [DI+42h], 0 ; slide down. + +InitCommandG10: + Test Word Ptr [DI], 100h + JNZ PrepareCommandGEnd + + Or Byte Ptr [DI], 1 ; Update effect if necess. + +PrepareCommandGEnd: + +InitCommandGEnd: ; Don't call volume + ; effects if it has a Gxx! + Test Word Ptr [DI], 100h + JNZ InitCommandGNoVolEffect + + Jmp InitVolumeEffect + +InitCommandGNoVolEffect: + Ret + +EndP InitCommandG + Assume DS:Nothing + +; + +Proc InitCommandH + Assume DS:Music + + Test Byte Ptr Byte Ptr [DI+2], 11h + JZ InitCommandH2 + Cmp Byte Ptr [DI+3], 119 + JA InitCommandH2 + + Mov Byte Ptr [DI+39h], 0 + Mov Byte Ptr [DI+2Dh], 0 + +InitCommandH2: + Mov AL, [DI+7] + Mov AH, AL + And AX, 0FF0h ; AH = depth + + JZ InitCommandH4 + + ShR AL, 2 ; AL = speed. + JZ InitCommandH3 + + + Mov [DI+3Bh], AL + +InitCommandH3: + ShL AH, 2 ; Depth * 4 + JZ InitCommandH4 + + Test Byte Ptr [ES:2Ch], 10h + JZ InitCommandH5 + + Add AH, AH + +InitCommandH5: + Mov [DI+3Ah], AH + +InitCommandH4: + Call InitNoCommand + + Test Byte Ptr [DI], 4 + JZ InitCommandH1 + + Or Byte Ptr [DI], 1 ; Update mode. + + Jmp InitVibrato + +InitCommandH1: + Ret + +EndP InitCommandH + Assume DS:Nothing + +; + +Proc InitCommandI + + Call InitNoCommand + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandI2 + + Mov [DI+13h], AL + +InitCommandI2: + Test Byte Ptr [DI], 4 + JZ InitCommandI1 + ; OK.. now to handle tremor + Or Byte Ptr [DI], 1 + + Mov AL, [DI+13h] + Mov AH, AL + And AL, 0Fh + ShR AH, 4 + + Test Byte Ptr [ES:2Ch], 16 + JZ InitCommandI3 + + Add AX, 101h + +InitCommandI3: + Mov [DI+40h], AX ; AL = Offtime, AH = ontime + + Jmp CommandI + +InitCommandI1: + Ret + +EndP InitCommandI + +; + +Proc InitCommandJ + Assume DS:Music + + Call InitNoCommand + + Mov Word Ptr [DI+40h], 0 + Mov AL, [DI+7] + Test AL, AL + JNZ InitCommandJ2 + + Mov AL, [DI+14h] + Jmp InitCommandJ3 + +InitCommandJ2: + Mov [DI+14h], AL + +InitCommandJ3: + Test Byte Ptr [DI], 4 + JZ InitCommandJ1 + + Mov BL, AL + ShR AL, 4 + And EBX, 0Fh + + Or Byte Ptr [DI], 1 ; Update when channel on + + LEA DX, [EBX*4+PitchTable+240] + Mov BL, AL + Mov [DI+44h], DX + LEA DX, [EBX*4+PitchTable+240] + Mov [DI+42h], DX + +InitCommandJ1: + Ret + +EndP InitCommandJ + Assume DS:Nothing + +; + +Proc InitCommandK + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandK1 + + Mov [DI+10h], AL + +InitCommandK1: + Call InitNoCommand + + Test Byte Ptr [DI], 4 + JZ InitCommandKEnd + + Call InitVibrato + Call InitCommandD7 + Or Byte Ptr [DI], 2 ; Always update. + +InitCommandKEnd: + Ret + +EndP InitCommandK + +; + +Proc InitCommandL + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandL1 + + Mov [DI+10h], AL + +InitCommandL1: + Test Byte Ptr [DI], 4 + JZ InitCommandLEnd + + Call InitCommandG11 + Call InitCommandD7 + Or Byte Ptr [DI], 2 ; Always update. + +InitCommandLEnd: + Ret + +EndP InitCommandL + +; + +Proc InitCommandM + Assume DS:Music + + Call InitNoCommand + + Mov AL, [DI+7] ; AL = command val. + Cmp AL, 40h + JA InitCommandM3 + +InitCommandM2: + Test Byte Ptr [DI], 4 + JZ InitCommandM1 + + Mov SI, [DI+24h] + + Mov [SI+23h], AL + Or Byte Ptr [SI], 16 ; recalc volume + +InitCommandM1: + Mov [DI+2Fh], AL + +InitCommandM3: + Ret + +EndP InitCommandM + Assume DS:Nothing + +; + +Proc InitCommandN + Assume DS:Music + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandN1 + + Mov [DI+16h], AL + +InitCommandN1: + Call InitNoCommand + + Mov AL, [DI+16h] + Mov AH, AL + Test AH, 0Fh + JZ InitCommandN2 + Test AH, 0F0h + JZ InitCommandN3 + And AX, 0FF0h + Cmp AH, 0Fh + JE InitCommandN4 + Cmp AL, 0F0h + JE InitCommandN5 + Ret + +InitCommandN2: + ShR AL, 4 + Mov [DI+40h], AL + Or Byte Ptr [DI], 2 ; Always update effect + Ret + +InitCommandN3: + Neg AL + Mov [DI+40h], AL + Or Byte Ptr [DI], 2 + Ret + +InitCommandN4: + ShR AL, 4 + Add AL, [DI+2Fh] + Cmp AL, 64 + JBE InitCommandN6 + Mov AL, 64 + Jmp InitCommandM2 + +InitCommandN5: + Mov AL, [DI+2Fh] + Sub AL, AH + JNC InitCommandN6 + Xor AL, AL + +InitCommandN6: + Jmp InitCommandM2 + + +EndP InitCommandN + +; + +Proc InitCommandO + Assume DS:Music + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandO2 + + Mov [DI+12h], AL + +InitCommandO2: + Call InitNoCommand + +; Mov AL, [DI+2] +; Test AL, 22h +; JNZ InitCommandO1 + +; Test AL, 11h +; Test Byte Ptr [DI+2], 11h + Test Byte Ptr [DI+2], 33h + JZ InitCommandO1 + + Cmp Byte Ptr [DI+0Eh], 120 + JAE InitCommandO1 + +InitCommandO3: + Test Byte Ptr [DI], 4 + JZ InitCommandO1 + + Xor EAX, EAX + Mov SI, [DI+24h] + Mov AH, [DI+1Bh] + Mov AL, [DI+12h] + ShL EAX, 8 + + Cmp EAX, [SI+44h] ; End of sample/end of sample loop + JB InitCommandO4 + + Test Byte Ptr [ES:2Ch], 16 + JZ InitCommandO1 + + Mov EAX, [SI+44h] + Dec EAX + +InitCommandO4: + Mov [SI+4Ch], EAX + Mov [SI+2Ch], EAX + + Xor AX, AX + Mov [SI+48h], AX + Ret + +InitCommandO1: + Ret + +EndP InitCommandO + Assume DS:Nothing + +; + +Proc InitCommandP + Assume DS:Music + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandP1 + + Mov [DI+17h], AL + +InitCommandP1: + Call InitNoCommand + + Mov DL, [DI+2Eh] + Test Byte Ptr [DI], 4 + JZ InitCommandP8 + + Mov SI, [DI+24h] + Mov DL, [SI+2Bh] ; Pan set + +InitCommandP8: + Cmp DL, 100 ; Surround?? + JE InitCommandP7 + + Mov AL, [DI+17h] + Mov AH, AL + Test AH, 0Fh + JZ InitCommandP2 + Test AH, 0F0h + JZ InitCommandP3 + And AX, 0F00Fh + Cmp AL, 0Fh + JE InitCommandP4 + Cmp AH, 0F0h + JE InitCommandP5 + +InitCommandP7: + Ret + +InitCommandP2: + ShR AL, 4 + Neg AL + Mov [DI+40h], AL + Or Byte Ptr [DI], 2 ; Always update effect + Ret + +InitCommandP3: + Mov [DI+40h], AL + Or Byte Ptr [DI], 2 + Ret + +InitCommandP4: + ShR AH, 4 + Mov AL, DL + Sub AL, AH + JNC InitCommandP6 + Xor AL, AL + Jmp InitCommandX2 + +InitCommandP5: + Add AL, DL + Cmp AL, 64 + JBE InitCommandP6 + + Mov AL, 64 + +InitCommandP6: + Jmp InitCommandX2 + +EndP InitCommandP + Assume DS:Nothing + +; + +Proc InitCommandQ + + Call InitNoCommand + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandQ1 + + Mov [DI+18h], AL + +InitCommandQ1: + Test Byte Ptr [DI], 4 + JZ InitCommandQ2 + + Or Byte Ptr [DI], 1 + + Test Byte Ptr [DI+2], 11h + JZ InitCommandQ3 + + Mov AL, [DI+18h] + And AL, 0Fh ; AL = retrig count + Mov [DI+33h], AL ; retrig countdown + +InitCommandQ2: + Ret + +InitCommandQ3: + Jmp CommandQ + +EndP InitCommandQ + +; + +Proc InitCommandR + Assume DS:Music + + Mov AL, [DI+7] + Mov AH, AL + And AX, 0FF0h ; AH = depth + JZ InitCommandR4 + + ShR AL, 2 ; AL = speed. + JZ InitCommandR3 + + Mov [DI+3Fh], AL + +InitCommandR3: + ShL AH, 1 + JZ InitCommandR4 + + Mov [DI+3Eh], AH + +InitCommandR4: + Call InitNoCommand + + Test Byte Ptr [DI], 4 + JZ InitCommandR1 + + Or Byte Ptr [DI], 1 ; Update mode. + + Jmp InitTremelo + +InitCommandR1: + Ret + +EndP InitCommandR + Assume DS:Nothing + +; + +CommandSTable Label Word + DW Offset InitNoCommand ; 0 + DW Offset InitNoCommand ; 1 + DW Offset InitNoCommand ; 2 + DW Offset InitCommandS3x ; 3 - set vibrato waveform + DW Offset InitCommandS4x ; 4 - set tremelo waveform + DW Offset InitCommandS5x ; 5 - set panbrello waveform + DW Offset InitCommandS6x ; 6 - extra delay of x frames + DW Offset InitCommandS7x ; 7 - instrument functions + DW Offset InitCommandS8x ; 8 - set pan + DW Offset InitCommandS9x ; 9 - set surround + DW Offset InitCommandSAx ; A - Set high order offset + DW Offset InitCommandSBx ; B - loop control + DW Offset InitCommandSCx ; C - note cut + DW Offset InitCommandSDx ; D - note delay + DW Offset InitCommandSEx ; E - pattern delay + DW Offset InitCommandSFx ; F - MIDI Macro select + +CommandS7Table Label Word + DW Offset InitCommandS70 ; Past note cut + DW Offset InitCommandS71 ; Past note off + DW Offset InitCommandS72 ; Past note fade + DW Offset InitCommandS73 ; Set NNA to cut + DW Offset InitCommandS73 ; Set NNA to continue + DW Offset InitCommandS73 ; Set NNA to off + DW Offset InitCommandS73 ; Set NNA to fade + DW Offset InitCommandS77 ; Set volume envelope on + DW Offset InitCommandS78 ; Set volume envelope off + DW Offset InitCommandS79 ; Set panning envelope on + DW Offset InitCommandS7A ; Set panning envelope off + DW Offset InitCommandS7B ; Set pitch envelope on + DW Offset InitCommandS7C ; Set pitch envelope off + DW Offset InitNoCommand + DW Offset InitNoCommand + DW Offset InitNoCommand + +Proc InitCommandS + Assume DS:Music + + Mov AL, [DI+7] + Test AL, AL + JNZ @ICS1 + + Mov AL, [DI+1Ah] + +@ICS1: + Mov [DI+1Ah], AL + + Mov AH, AL + And AX, 0F00Fh + + Mov [DI+40h], AX ; Misc effects data. + + Mov BX, AX + ShR BX, 11 ; BX = (AH>>4)*2 + + Jmp [CommandSTable+BX] + +InitCommandS3x: + Cmp AL, 3 + JA @ICS2 + Mov [DI+38h], AL + +@ICS2: + Jmp InitNoCommand + +InitCommandS4x: + Cmp AL, 3 + JA @ICS3 + Mov [DI+3Ch], AL + +@ICS3: + Jmp InitNoCommand + +InitCommandS5x: + Cmp AL, 3 + JA @ICS4 + + Mov [DI+28h], AL + Mov Byte Ptr [DI+29h], 0 + +@ICS4: + Jmp InitNoCommand + +InitCommandS6x: + And AX, 0FFh + Add CurrentTick, AX + Add ProcessTick, AX + Jmp InitNoCommand + +InitCommandS7x: + Mov BL, AL + Add BL, BL + Jmp [CommandS7Table+BX] + +InitCommandS70: ; Past Note cut. + Call InitNoCommand + Mov SI, Offset SlaveChannelInformationTable + Mov CX, NumChannels + Mov AL, [DI+20h] + Or AL, 80h + +InitCommandS70_1: + Cmp AL, [SI+3Ah] + JNE @ICS5 + + Test Byte Ptr CS:DriverFlags, 2 + JZ @ICS70_2 + + Or Word Ptr [SI], 200h + Jmp @ICS5 + +@ICS70_2: + Mov Word Ptr [SI], 200h + +@ICS5: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ InitCommandS70_1 + + Ret + +InitCommandS71: ; Past note off + Call InitNoCommand + Mov AH, 4 + Jmp InitCommandS72_1 + +InitCommandS72: ; Past note fade. + Call InitNoCommand + Mov AH, 8 + +InitCommandS72_1: + Mov SI, Offset SlaveChannelInformationTable + Mov CX, NumChannels + Mov AL, [DI+20h] + Or AL, 80h + +InitCommandS72_2: + Cmp AL, [SI+3Ah] + JNE @ICS6 + + Or [SI], AH + + Push AX + Push CX + Call GetLoopInformation + Pop CX + Pop AX + +@ICS6: + Add SI, SLAVECHANNELSIZE + Dec CX + JNZ InitCommandS72_2 + + Ret + +InitCommandS73: + Push AX + Call InitNoCommand + Pop AX + + Test Byte Ptr [DI], 4 + JZ @ICS7 + + Sub AL, 3 + Mov SI, [DI+24h] + Mov [SI+3Bh], AL + +@ICS7: + Ret + +InitCommandS77: + Call InitNoCommand + Test Byte Ptr [DI], 4 + JZ @ICS9 + + Mov SI, [DI+24h] + And Word Ptr [SI], Not 1000h + +@ICS9: + Ret + +InitCommandS78: + Call InitNoCommand + Test Byte Ptr [DI], 4 + JZ @ICS9 + + Mov SI, [DI+24h] + Or Word Ptr [SI], 1000h + + Ret + +InitCommandS79: + Call InitNoCommand + Test Byte Ptr [DI], 4 + JZ @ICS9 + + Mov SI, [DI+24h] + And Word Ptr [SI], Not 2000h + + Ret + +InitCommandS7A: + Call InitNoCommand + Test Byte Ptr [DI], 4 + JZ @ICS10 + + Mov SI, [DI+24h] + Or Word Ptr [SI], 2000h + + Ret + +InitCommandS7B: + Call InitNoCommand + Test Byte Ptr [DI], 4 + JZ @ICS10 + + Mov SI, [DI+24h] + And Word Ptr [SI], Not 4000h + +@ICS10: + Ret + +InitCommandS7C: + Call InitNoCommand + Test Byte Ptr [DI], 4 + JZ @ICS10 + + Mov SI, [DI+24h] + Or Word Ptr [SI], 4000h + + Ret + +InitCommandS8x: + Mov AH, AL + ShL AH, 4 + Or AL, AH + And AX, 0FFh + Add AX, 2 + SHR AX, 2 + +InitCommandS8x_1: + Push AX + Call InitNoCommand + Pop AX + + Jmp InitCommandX2 + +InitCommandS9x: + Cmp AL, 1 + Mov AL, 100 + JE InitCommandS8x_1 + Jmp InitNoCommand + +InitCommandSAx: + Mov [DI+1Bh], AL + Jmp InitNoCommand + +InitCommandSBx: + Push AX + Call InitNoCommand + Pop AX + + Test AL, AL + JZ InitCommandSBx_1 + + Cmp Byte Ptr [DI+27h], 0 + JNE InitCommandSBx_2 + + Mov [DI+27h], AL + +InitCommandSBx_3: + MovZX AX, Byte Ptr [DI+26h] + + Dec AX + Mov ProcessRow, AX + Mov PatternLooping, 1 + + Ret + +InitCommandSBx_2: + Dec Byte Ptr [DI+27h] + JNZ InitCommandSBx_3 + Mov AX, CurrentRow + + Inc AX + Mov [DI+26h], AL + Ret + +InitCommandSBx_1: + Mov AX, CurrentRow + Mov [DI+26h], AL + Ret + +InitCommandSCx: + Or Byte Ptr [DI], 1 + Jmp InitNoCommand + +InitCommandSDx: + Or Byte Ptr [DI], 2 + Ret + +InitCommandSEx: + Cmp RowDelayOn, 0 + JNE @ICS8 + + Inc AX + Mov AH, 1 + Mov [Word Ptr RowDelay], AX + +@ICS8: + Jmp InitNoCommand + +InitCommandSFx: ; Set MIDI Macro + Mov [DI+1Fh], AL + Jmp InitNoCommand + +EndP InitCommandS + Assume DS:Nothing + +; + +Proc InitCommandT + Assume DS:Music + + Mov AL, [DI+7] + Test AL, AL + JZ InitCommandT2 + + Mov [DI+19h], AL + +InitCommandT2: + Mov AL, [DI+19h] + +InitCommandT3: + Cmp AL, 20h + JB InitCommandT1 + + Mov Tempo, AL + Call Music_InitTempo + Jmp InitNoCommand + +InitCommandT1: + Call InitNoCommand + Or Byte Ptr [DI], 2 ; Update mode + Ret + +EndP InitCommandT + Assume DS:Nothing + +; + +Proc InitCommandU + Assume DS:Music + + Test Byte Ptr Byte Ptr [DI+2], 11h + JZ InitCommandU2 + + Mov Byte Ptr [DI+39h], 0 + Mov Byte Ptr [DI+2Dh], 0 + +InitCommandU2: + Mov AL, [DI+7] + Mov AH, AL + And AX, 0FF0h ; AH = depth + + Test AL, AL + JZ InitCommandU3 + + ShR AL, 2 ; AL = speed. + + Mov [DI+3Bh], AL + +InitCommandU3: + Test AH, AH + JZ InitCommandU4 + + Test Byte Ptr [ES:2Ch], 16 + JZ InitCommandU5 + + Add AH, AH + +InitCommandU5: + Mov [DI+3Ah], AH + +InitCommandU4: + Call InitNoCommand + + Test Byte Ptr [DI], 4 + JZ InitCommandU1 + + Or Byte Ptr [DI], 1 ; Update mode. + + Jmp InitVibrato + +InitCommandU1: + Ret + +EndP InitCommandU + Assume DS:Nothing + +; + +Proc InitCommandV + Assume DS:Music + + Mov AL, [DI+7] + Cmp AL, 80h + JA InitCommandV1 + + Mov GlobalVolume, AL + Call RecalculateAllVolumes + +InitCommandV1: + Jmp InitNoCommand + +EndP InitCommandV + Assume DS:Nothing + +; + +Proc InitCommandW ; Global volume slides! + Assume DS:Music + + Call InitNoCommand + + Mov AL, [DI+7] + Test AL, AL + JNZ InitCommandW1 + + Mov AL, [DI+1Ch] + Jmp InitCommandW2 + +InitCommandW1: + Mov [DI+1Ch], AL + +InitCommandW2: + Mov AH, AL + And AX, 0F00Fh + JZ InitCommandW3 + Test AH, AH + JZ InitCommandW4 + Test AL, AL + JZ InitCommandW5 + Cmp AH, 0F0h + JE InitCommandW6 + Cmp AL, 0Fh + JE InitCommandW8 + + Ret + +InitCommandW4: + Neg AL + Mov [DI+40h], AL + Or Byte Ptr [DI], 2 + Ret + +InitCommandW5: + ShR AH, 4 + Mov [DI+40h], AH + Or Byte Ptr [DI], 2 + Ret + +InitCommandW6: + Mov AH, GlobalVolume + Sub AH, AL + JNC InitCommandW7 + + Xor AH, AH + +InitCommandW7: + Mov GlobalVolume, AH + + Call RecalculateAllVolumes + Ret + +InitCommandW8: + ShR AH, 4 + Mov AL, GlobalVolume + Add AL, AH + JNS InitCommandW9 + + Mov AL, 128 + +InitCommandW9: + Mov GlobalVolume, AL + + Call RecalculateAllVolumes + Ret + +InitCommandW3: + Ret + +EndP InitCommandW + Assume DS:Nothing + +; + +Proc InitCommandX + Assume DS:Music + + Call InitNoCommand + + MovZX AX, Byte Ptr [DI+7] ; AL = command val. + Add AX, 2 + SHR AX, 2 + +InitCommandX2: + Test Byte Ptr [DI], 4 + JZ InitCommandX1 + + Mov SI, [DI+24h] + Mov AH, AL + Mov [SI+2Ah], AX + + Or Byte Ptr [SI], 64+2 ; Recalculate pan + +InitCommandX1: + Mov [DI+2Eh], AL + Ret + +EndP InitCommandX + Assume DS:Nothing + +; + +Proc InitCommandY + Assume DS:Music + + Mov AL, [DI+7] + Mov AH, AL + And AX, 0FF0h ; AH = depth + JZ InitCommandY4 + + ShR AL, 4 + JZ InitCommandY3 + + Mov [DI+2Bh], AL + +InitCommandY3: + ShL AH, 1 + JZ InitCommandY4 + + Mov [DI+2Ah], AH + +InitCommandY4: + Call InitNoCommand + + Test Byte Ptr [DI], 4 + JZ InitCommandY1 + + Or Byte Ptr [DI], 1 ; Update mode. + + Jmp CommandY + +InitCommandY1: + Ret + +EndP InitCommandY + Assume DS:Nothing + +; + +Proc InitCommandZ ; Macros start at 120h, 320h + + Call InitNoCommand + + Mov BL, [DI+7] + Mov SI, [DI+24h] + + Test BL, BL + JS InitCommandZ1 + +; Test SI, SI +; JZ InitCommandZ2 + + Mov BL, [DI+1Fh] ; 0->7Fh + And BX, 0Fh ; BX = SFx number + ShL BX, 5 + Add BX, 120h + Jmp MIDITranslate + +InitCommandZ1: ; Macros! + And BX, 7Fh + ShL BX, 5 ; BX = (xx-80h)*20h + Add BX, 320h + Jmp MIDITranslate + +InitCommandZ2: + Ret + +EndP InitCommandZ + +; + +Proc NoCommand ; DS:DI points to CIT Area + + Ret + +EndP NoCommand + +; + +Proc CommandD + Assume DS:Music + + Mov SI, [DI+24h] + Mov AL, [DI+30h] + Add AL, [SI+22h] ; Volset. + JS CommandD1 + + Cmp AL, 64 + JBE CommandD2 + + And Byte Ptr [DI], Not 1 + + Mov AL, 64 + Jmp CommandD2 + +CommandD1: + And Byte Ptr [DI], Not 1 + Xor AL, AL + +CommandD2: + Mov [SI+21h], AL + Mov [SI+22h], AL + Mov [DI+22h], AL + Or Byte Ptr [SI], 16 ; Recalc vol + Ret + +EndP CommandD + Assume DS:Nothing + +; + +Proc CommandE + Assume DS:Music + + Mov BX, [DI+40h] + +CommandEChain: + Mov SI, [DI+24h] + Call PitchSlideDown + + Mov EAX, [SI+10h] + Mov [SI+14h], EAX + + Ret + +EndP CommandE + Assume DS:Nothing + +; + +Proc CommandF + Assume DS:Music + + Mov BX, [DI+40h] + +CommandFChain: + Mov SI, [DI+24h] + Call PitchSlideUp + + Mov EAX, [SI+10h] + Mov [SI+14h], EAX + + Ret + +EndP CommandF + Assume DS:Nothing + +; + +Proc CommandG + + Test Byte Ptr [DI], 16 + JZ CommandGEnd + + Mov BX, [DI+40h] + Mov SI, [DI+24h] + Cmp Byte Ptr [DI+42h], 1 + JE CommandG1 + ; Slide down + Call PitchSlideDown + ; Check that frequency is above porta + ; to frequency. + Mov EAX, [SI+10h] + Cmp EAX, [DI+34h] + JA CommandG6 + +CommandG4: + Mov EAX, [DI+34h] + And Byte Ptr [DI], Not (3 Or 16) ; Turn off calling + +CommandG3: + Mov [SI+10h], EAX + +CommandG6: + Mov [SI+14h], EAX + +CommandGEnd: + Ret + +CommandG1: ; Slide up! + Call PitchSlideUp + ; Check that + ; 1) Channel is on + ; 2) Frequency (set) is below porta to + ; frequency + Mov EAX, [SI+10h] + + Test Word Ptr [SI], 200h + JNZ CommandG5 + + Cmp EAX, [DI+34h] + JB CommandG6 + +CommandG5: +; Or Byte Ptr [SI], 1 +; And Byte Ptr [SI+1], Not 2 + And Word Ptr [SI], Not 200h + Or Byte Ptr [DI], 4 ; Turn on. + Jmp CommandG4 + +EndP CommandG + +; + +InitVibrato: + Test Byte Ptr [ES:2Ch], 10h + JZ CommandH + + Mov SI, [DI+24h] + Or Byte Ptr [SI], 32 ; Freq change... + Mov AL, [DI+2Dh] + Jmp CommandH5 + +Proc CommandH + + Mov SI, [DI+24h] + Or Byte Ptr [SI], 32 ; Freq change... + + Mov BL, [DI+39h] + Add BL, [DI+3Bh] ; Add speed. + Mov [DI+39h], BL ; Save value + Mov BH, [DI+38h] ; AL = waveform + + Cmp BH, 3 + JE CommandH1 + + Mov AL, [FineSineData+BX] ; AL = -64 -> 64 + + Jmp CommandH2 + +CommandH1: ; Random. + Call Random + And AL, 127 + Sub AL, 64 + +CommandH2: + Mov [DI+2Dh], AL ; Save last vibrato. + +CommandH5: + IMul Byte Ptr [DI+3Ah] + SAL AX, 2 + Add AX, 80h + + Test Byte Ptr [ES:2Ch], 16 + JZ CommandH9 + + Neg AH + +CommandH9: + MovZX BX, AH + ; AH = EEx/FEx command value + Test AH, AH + JS CommandH4 + JNS CommandH3 + Ret + +CommandH3: + Jmp PitchSlideUp + +CommandH4: + Neg BL + Jmp PitchSlideDown + Ret + +EndP CommandH + +; + +Proc CommandI + + Mov SI, [DI+24h] + + Or Byte Ptr [SI], 16 ; recalc volume + + Dec Byte Ptr [DI+31h] + JS CommandI2 + JZ CommandI2 + +CommandI1: + Cmp Byte Ptr [DI+32h], 1 + JE CommandI3 + + Mov Byte Ptr [SI+21h], 0 + +CommandI3: + Ret + +CommandI2: + Xor Byte Ptr [DI+32h], 1 + MovZX BX, Byte Ptr [DI+32h] + Mov AL, [DI+40h+BX] + Mov [DI+31h], AL + Jmp CommandI1 + +EndP CommandI + +; + +Proc CommandJ + Assume DS:Music + + Mov SI, [DI+24h] + Mov BX, [DI+40h] + + Or Byte Ptr [SI], 32 + + Add BX, 2 + Cmp BX, 6 + JB CommandJ1 + + Mov Word Ptr [DI+40h], 0 + Ret + +CommandJ1: + Push DI + + Mov [DI+40h], BX + Mov DI, [DI+BX+40h] ; DI points to freq mult. + + Mov EAX, [SI+10h] + Mul DWord Ptr [DI] + + Test EDX, 0FFFF0000h + JNZ CommandJ2 + + SHRD EAX, EDX, 16 + Mov [SI+10h], EAX + + Pop DI + Ret + +CommandJ2: + Xor EAX, EAX + Mov [SI+10h], EAX + + Pop DI + Ret + +EndP CommandJ + Assume DS:Nothing + +; + +Proc CommandK + + Call CommandH + Call CommandD + Ret + +EndP CommandK + +; + +Proc CommandL + + Test Byte Ptr [DI], 16 + JZ CommandL1 + + Call CommandG + Or Byte Ptr [DI], 1 + +CommandL1: + Call CommandD + Ret + +EndP CommandL + +; + +Proc CommandN + + Mov AL, [DI+2Fh] + Add AL, [DI+40h] + JNS CommandN1 + + Xor AL, AL + Jmp InitCommandM2 + +CommandN1: + Cmp AL, 64 + JBE CommandN2 + + Mov AL, 64 + +CommandN2: + Jmp InitCommandM2 + +EndP CommandN + +; + +Proc CommandP + + Mov AL, [DI+2Eh] + Test Byte Ptr [DI], 4 + JZ CommandP3 + + Mov SI, [DI+24h] + Mov AL, [SI+2Bh] ; Pan set + +CommandP3: + Add AL, [DI+40h] + JNS CommandP1 + + Xor AL, AL + Jmp InitCommandX2 + +CommandP1: + Cmp AL, 64 + JBE CommandP2 + + Mov AL, 64 + +CommandP2: + Jmp InitCommandX2 + +EndP CommandP + +; + +Proc CommandQ + + Dec Byte Ptr [DI+33h] + JS CommandQ1 + JZ CommandQ1 + + Ret + +CommandQ1: ; OK... reset counter. + Mov BL, [DI+18h] + Mov BH, BL + And BX, 0F00Fh + Mov [DI+33h], BL ; retrig count done. + + Mov SI, [DI+24h] + + Test Byte Ptr DriverFlags, 2 ; Hiqual? + JZ CommandQNoHiQual + + Push ES + Push DI + + Test Byte Ptr [ES:2Ch], 4 ; Instrument mode? + + Push DS + Pop ES + + JNZ CommandQHiqualInstruments + +CommandQHiqualSamples: + Lea DI, [SI+64*SLAVECHANNELSIZE] + + Mov CX, SLAVECHANNELSIZE/4 + Rep MovsD + Or Byte Ptr [DI-SLAVECHANNELSIZE+1], 2h ; Cut + Or Byte Ptr [DI-SLAVECHANNELSIZE+3Ah], 80h ; Disowned + Sub SI, SLAVECHANNELSIZE + + Pop DI + Jmp CommandQHiqualEnd + +CommandQHiqualInstruments: + Mov DI, Offset SlaveChannelInformationTable + Mov CX, NumChannels + +CommandQFindChannel: + Test Byte Ptr [DI], 1 + JZ CommandQHiqualCopy + + Add DI, SLAVECHANNELSIZE + Loop CommandQFindChannel + Pop DI + Jmp CommandQHiqualEnd + +CommandQHiqualCopy: + Mov CX, SLAVECHANNELSIZE/4 + Rep MovsD + + Or Byte Ptr [SI-SLAVECHANNELSIZE+1], 2h ; Cut + Or Byte Ptr [SI-SLAVECHANNELSIZE+3Ah], 80h ; Disowned + LEA SI, [DI-SLAVECHANNELSIZE] + Pop DI + + Mov [DI+24h], SI + +CommandQHiqualEnd: + Pop ES + +CommandQNoHiQual: + Xor EAX, EAX + Mov [SI+2Ch], EAX + Mov [SI+48h], AX + Mov [SI+4Ch], EAX + + Or Word Ptr [SI], 540h + + Mov AL, [SI+22h] + ShR BX, 11 + + Jmp [RetrigOffsets+BX] + +CommandQ_0: + Ret + +CommandQ_1: + Dec AL + Jmp CommandQCheckLow + +CommandQ_2: + Sub AL, 2 + Jmp CommandQCheckLow + +CommandQ_3: + Sub AL, 4 + Jmp CommandQCheckLow + +CommandQ_4: + Sub AL, 8 + Jmp CommandQCheckLow + +CommandQ_5: + Sub AL, 16 + Jmp CommandQCheckLow + +CommandQ_6: + ShL AL, 1 + Mov BL, 3 + Div BL + Jmp CommandQEnd + +CommandQ_7: + ShR AL, 1 + Jmp CommandQEnd + +CommandQ_8: + Ret + +CommandQ_9: + Inc AX + Jmp CommandQCheckHigh + +CommandQ_A: + Add AL, 2 + Jmp CommandQCheckHigh + +CommandQ_B: + Add AL, 4 + Jmp CommandQCheckHigh + +CommandQ_C: + Add AL, 8 + Jmp CommandQCheckHigh + +CommandQ_D: + Add AL, 16 + Jmp CommandQCheckHigh + +CommandQ_E: + Mov AH, AL + Add AL, AL + Add AL, AH + ShR AL, 1 + Jmp CommandQCheckHigh + +CommandQ_F: + ShL AL, 1 + Jmp CommandQCheckHigh + + +CommandQCheckLow: + JNS CommandQEnd + Xor AL, AL + Jmp CommandQEnd + +CommandQCheckHigh: + Cmp AL, 64 + JBE CommandQEnd + Mov AL, 64 + +CommandQEnd: + Mov [SI+21h], AL + Mov [SI+22h], AL + Mov [DI+22h], AL + Or Byte Ptr [SI], 16 ; recalc volume flag + + Cmp Byte Ptr [DI+0Fh], 101 ; MIDI sample + JNE CommandQNoMidi + + Mov BX, MIDICOMMAND_STOPNOTE + Call MIDITranslate + +CommandQNoMidi: + Ret + +EndP CommandQ + +; + +InitTremelo: + Test Byte Ptr [ES:2Ch], 10h + JZ CommandR + + Mov SI, [DI+24h] + Or Byte Ptr [SI], 64 ; Volume change... + Mov AL, [DI+23h] + Jmp CommandR2 + +Proc CommandR + + Mov SI, [DI+24h] + Or Byte Ptr [SI], 16 ; Volume change + + Mov BL, [DI+3Dh] + Add BL, [DI+3Fh] ; Add speed. + Mov [DI+3Dh], BL ; Save value + Mov BH, [DI+3Ch] ; AL = waveform + + Cmp BH, 3 + JE CommandR1 + + Mov AL, [FineSineData+BX] ; AL = -64 -> 64 + + Jmp CommandR5 + +CommandR1: ; Random. + Call Random + And AL, 127 + Sub AL, 64 + +CommandR5: + Mov [DI+23h], AL ; Save last tremelo + +CommandR2: + IMul Byte Ptr [DI+3Eh] + SAL AX, 2 + Add AX, 80h + MovZX BX, AH + ; AH = volume change + Mov AL, [SI+21h] ; AL = vol. + Add AL, AH + JNS CommandR3 + + Xor AL, AL + +CommandR3: + Cmp AL, 64 + JBE CommandR4 + + Mov AL, 64 + +CommandR4: + Mov [SI+21h], AL + Ret + +EndP CommandR + +; + +Proc CommandS ; Have to handle SDx, SCx + Assume DS:Music + + Mov AX, [DI+40h] ; AH = command, AL = value. + Cmp AH, 0D0h + JE CommandS1 + + Cmp AH, 0C0h + JE CommandS3 + +CommandS4: + Ret + +CommandS3: + Test Byte Ptr [DI], 4 + JZ CommandS4 + + Dec Byte Ptr [DI+40h] + JZ CommandS5 + JS CommandS5 + + Ret + +CommandS5: + Mov SI, [DI+24h] ; Note cut. + + Mov AL, [DI] + + And AL, Not 4 + Mov [DI], AL + + Cmp Byte Ptr [SI+36h], 100 + JE CommandS7 + + Test Byte Ptr CS:DriverFlags, 2 + JNZ CommandS7 + + Mov Word Ptr [SI], 200h + Ret + +CommandS7: + Or Word Ptr [SI], 200h + Ret + +CommandS1: + Dec Byte Ptr [DI+40h] + JS CommandS2 + JZ CommandS2 + + Ret + +CommandS2: + And Byte Ptr [DI], Not 3 + Call InitNoCommand + + Or Byte Ptr [DI], 64 + + MovZX BX, Byte Ptr [DI+20h] ; Check whether chn + ; is on + Test Byte Ptr [ES:BX+40h], 80h + JZ CommandS6 + + Test Byte Ptr [DI], 32 + JNZ CommandS6 + + Test Byte Ptr [DI], 4 + JZ CommandS6 ; Channel was off. + + Mov SI, [DI+24h] + Or Byte Ptr [SI+1], 8 + +CommandS6: + Ret + +EndP CommandS + Assume DS:Nothing + +; + +Proc CommandT + Assume DS:Music + + Mov AL, [DI+19h] + Mov BL, Tempo + Xor AH, AH + Xor BH, BH + + Test AL, 0F0h + JZ CommandT1 + ; Slide up + Add BX, AX + Sub BX, 10h + Cmp BX, 0FFh + JBE CommandT2 + Mov BL, 0FFh + Jmp CommandT2 + +CommandT1: ; Slide down + Sub BX, AX + Cmp BX, 20h + JGE CommandT2 + + Mov BL, 20h + +CommandT2: + Mov Tempo, BL + PushA + Call [DriverSetTempo] + PopA + Ret + +EndP CommandT + Assume DS:Nothing + +; + +Proc CommandW ; Global volume slide! + Assume DS:Music + + Xor BH, BH + MovSX AX, Byte Ptr [DI+40h] + Mov BL, GlobalVolume + + Add AX, BX + + JNS CommandW1 + + Xor AL, AL + +CommandW1: + Cmp AL, 128 + JBE CommandW2 + + Mov AL, 128 + +CommandW2: + Mov GlobalVolume, AL + + Call RecalculateAllVolumes + Ret + +EndP CommandW + Assume DS:Nothing + +; + +Proc CommandY + + Test Byte Ptr [DI], 4 + JZ CommandY5 + + Mov SI, [DI+24h] + + Mov BH, [DI+28h] ; AL = waveform + Cmp BH, 3 + JAE CommandY1 + + Mov BL, [DI+29h] ; Pos + Add BL, [DI+2Bh] ; Add speed. + Mov [DI+29h], BL ; Save value + + Mov AL, [FineSineData+BX] ; AL = -64 -> 64 + + Jmp CommandY2 + +CommandY1: ; Random panning make + ; speed the delay time. + Dec Byte Ptr [DI+29h] + JZ CommandY6 + JS CommandY6 + + Mov AL, [DI+2Ch] + Jmp CommandY2 + +CommandY6: + Mov BL, [DI+2Bh] + Mov [DI+29h], BL ; reset countdown. + + Call Random + And AL, 127 + Sub AL, 64 + + Mov [DI+2Ch], AL + +CommandY2: + IMul Byte Ptr [DI+2Ah] + SAL AX, 2 + Add AX, 80h + MovZX BX, AH + ; AH = panning change + Mov AL, [SI+2Bh] ; AL = panning + Cmp AL, 100 ; Surround? + JE CommandY5 + + Add AL, AH + JNS CommandY3 + + Xor AL, AL + +CommandY3: + Cmp AL, 64 + JBE CommandY4 + + Mov AL, 64 + +CommandY4: + Or Byte Ptr [SI], 2 ; Panning change + Mov [SI+2Ah], AL + +CommandY5: + Ret + +EndP CommandY + + diff --git a/it/IT_NET.ASM b/it/IT_NET.ASM new file mode 100644 index 0000000..570dd1a --- /dev/null +++ b/it/IT_NET.ASM @@ -0,0 +1,2722 @@ +;Ŀ +; Network Module +; + + Jumps + .386P + +include switch.inc + +IF NETWORKENABLED + +SHOWQUEUESIZE EQU 0 + +NUMREQUIREDVARIABLES EQU 16 ; Number of bytes required from IT.EXE by Driver +NUMREQUIREDFUNCTIONS EQU 32 ; Number of functions (DD Offsets) required by + ; Network driver +NUMPROVIDEDVARIABLES EQU 16 ; Number of bytes provided from driver to IT.EXE +NUMPROVIDEDFUNCTIONS EQU 16 ; Number of functions (DW Offsets) provided by + ; Network driver + +; Has to handle: +; 1. Loading the network driver +; 2. Messages to/from network driver/buffering, etc. + +; Interface + +;Ŀ +; Externals +; + + Extrn D_ClearFileName:Far + + Extrn E_AllocateEMS:Far + Extrn E_ReleaseEMS:Far + Extrn E_MapEMSMemory:Far + Extrn E_GetEMSPageFrame:Far + Extrn E_GetEMSVersion:Far +; Extrn E_SavePageFrame:Far +; Extrn E_RestorePageFrame:Far + + Extrn F_DrawHeader:Far + + Extrn Glbl_SetCurrentMode:Far + Extrn Glbl_GetCurrentMode:Far + + Extrn I_MapEnvelope:Far + + Extrn M_FunctionDivider:Far + Extrn M_FunctionHandler:Far + Extrn M_Object1List:Far + + Extrn Music_GetPatternLocation:Far ; Returns AX = handle + ; EBX = segment:offset + ; DL = type. + ; CX = pattern length + Extrn Music_GetPatternLocationNoCount:Far ; Returns AX = handle + ; EBX = segment:offset + ; DL = type. + Extrn Music_ReleasePattern:Far ; Requires AX = pattern + Extrn Music_AllocatePattern:Far ; SI = pattern, DX = length + Extrn Music_UpdatePatternOffset:Far + Extrn Music_ReleaseAllSamples:Far + Extrn Music_AllocateSample:Far + Extrn Music_Stop:Far + Extrn Music_ReleaseSample:Far + + Extrn IdleUpdateInfoLine:Far + Extrn SetInfoLine:Far + Extrn SetInfoLine2:Far + Extrn GetTimerCounter:Far + + Extrn O1_LoadNetworkDriver:Far + Extrn O1_NetworkErrorList:Far + Extrn GlobalKeyList + + Extrn PE_FillHeader:Far + Extrn PE_NewPattern:Far + Extrn PEFunction_OutOfMemoryMessage:Far + Extrn PEFunction_StoreCurrentPattern:Far + Extrn PE_GetLastInstrument:Far + + Extrn S_GetDestination:Far + Extrn S_DrawString:Far + Extrn S_SaveScreen:Far + Extrn S_RestoreScreen:Far + +Segment Object1 BYTE Public 'Data' +EndS + +Segment SongData PARA Public 'Data' +EndS + +Segment SongData PARA Public 'Data' +EndS + +; + + Public Network_DriverScreen + Public Network_DrawDriverScreen + Public Network_PreDriverScreen + Public Network_PostDriverScreen + Public Network_Shutdown + Public Network_Poll + Public Network_GetSendQueue ; Returns ES:DI + Public Network_FinishedSendQueue ; Finished with send queue + Public Network_AddWordToQueue + Public Network_UpdatePattern + Public Network_UpdatePatternIfIdle + Public Network_EnsureNoNetwork + Public Network_SendSampleHeader + Public Network_SendInstrumentHeader + Public Network_QueueSampleData + Public Network_SendSongDataInformation + +; +; +; Not used? +; +;Segment Network BYTE Public 'Code' USE16 +; Assume CS:Network, DS:Nothing, ES:Nothing +;EndS +; +; + +Segment DiskData PARA Public 'Data' +EndS + +; + +Segment Pattern BYTE Public 'Code' USE16 + Extrn PatternDataArea:Word + Extrn PatternNumber:Word + Extrn Modified:Byte + Extrn PatternModified:Byte + Extrn MaxRow:Word +EndS + +Segment Music BYTE Public 'Code' USE16 + Extrn CurrentOrder:Word + Extrn CurrentPattern:Word + Extrn CurrentRow:Word +EndS + +Segment Disk DWORD Public 'Code' USE16 + Assume CS:Disk, DS:Nothing, ES:Nothing + + Extrn DiskDataArea:Word + Extrn D_GotoStartingDirectory:Far + +; + +;******************** THESE BLOCKS CANNOT CHANGE ORDER ************************ + +Label NetworkRequiredVariables + DD DWord Ptr GlobalKeyList + DD DWord Ptr IdleUpdateInfoLine + DW DiskData + DB NUMREQUIREDVARIABLES - ($-Offset NetworkRequiredVariables) Dup (0) + +Label NetworkRequiredFunctions + DD DWord Ptr Network_UnloadDriver + DD DWord Ptr M_FunctionHandler + DD DWord Ptr M_FunctionDivider + DD DWord Ptr Network_ReceiveData + DD DWord Ptr Network_SendData + DD DWord Ptr Network_EstablishConnection + DD DWord Ptr D_GotoStartingDirectory + DD DWord Ptr GetTimerCounter + DD DWord Ptr SetInfoLine2 + DD DWord Ptr F_DrawHeader + DD DWord Ptr PE_FillHeader + DD DWord Ptr S_GetDestination + DD DWord Ptr S_DrawString + DD DWord Ptr S_SaveScreen + DD DWord Ptr S_RestoreScreen + DD DWord Ptr Glbl_GetCurrentMode + DD DWord Ptr Network_NewConnection + DD DWord Ptr Network_DecodeUserName + DD NUMREQUIREDFUNCTIONS - ($-Offset NetworkrequiredFunctions)/4 Dup (0) + +Label NetworkDriverVariables Byte + DB NUMPROVIDEDVARIABLES - ($-Offset NetworkDriverVariables) Dup (0) + +Label NetworkDriverFunctions DWord +NetworkDriver_Initialise DD Network_EmptyFunction +NetworkDriver_Shutdown DD Network_EmptyFunction +NetworkDriver_Screen DD Network_EmptyFunction +NetworkDriver_Update DD Network_EmptyFunction +NetworkDriver_ConnectionStatus DD Network_EmptyFunction + DD NUMPROVIDEDFUNCTIONS - ($-Offset NetworkDriverFunctions)/4 Dup (0) + +; + +DriverIdentification DB "Impulse Tracker Network Driver" +DriverMask DB "IT*.NET", 0 +NoDriverMsg DB "No Network Drivers Found", 0 +NetworkDriverUnloaded DB "Network driver unloaded", 0 + +IF SHOWQUEUESIZE +DebugMessage DB "SendQueueSize: ", 0FDh, "D", 0 +ENDIF +; NetworkOverflowMessage DB "Network Overflow: Driver Unloaded", 0 + +ALIGN 2 +NumDrivers DW 0 +CurrentDriver DW 0 +TopDriver DW 0 + +DriverSegment DW 0 + +EMS_SENDBUFFERPAGE EQU (0*100h + 4) + +LastReceiveCX DW 0 +NetworkEMSHandle DW 0 ; 384kb -> 64kb = receive buffer 1a + ; 64kb = receive buffer 1b + ; 64kb = receive buffer 2a + ; 64kb = receive buffer 2b + ; 64kb = receive buffer 3a + ; 64kb = receive buffer 3b +NetworkSendEMSHandle DW 0 ; 64kb, separated for Win9x's + ; inattention to the int-flag. + +SendQueueSegment DW 0 ; MUST be adjacent +SendDataQueueTail DW 0 ; MUST be adjacent +SendDataQueueHead DW 0 ; MUST be adjacent +Destination DB 0 ; MUST be adjacent +DriverValidated DB 0 ; MUST be adjacent +SendBufferRemaining DW 0 ; MUST be adjacent +SendBufferOffset DW 0 ; MUST be adjacent + +PatternDataUpdated DW 50 Dup (0) ; Bit table of pattern numbers + +Label NetworkKeys Byte + DB 0 + DW 1C8h ; Up arrow + DW Network_Up + + DB 0 + DW 1D0h ; Down arrow + DW Network_Down + + DB 0 + DW 11Ch + DW Network_LoadDriver + + DB 0FFh + +EMSTransferTable Label +TransferLength DW 0, 0 +SourceType DB 0 +SourceHandle DW 0 +SourceOffset DD 0 +DestinationType DB 0 +DestinationHandle DW 0 +DestinationOffset DD 0 + +PatternModifiedTable DB 200 Dup (0) ; Bit field for 200 patterns + +; + +Proc Network_EmptyFunction Far + + Xor AX, AX + Ret + +EndP Network_EmptyFunction + +; + +Proc Network_DriverScreen Far + +; If no network driver loaded, show load screen +; If driver loaded, then call driver's screen interface + + Mov AL, 24 + Call Glbl_SetCurrentMode + + Push CS + Pop DS + Assume DS:Disk + + Cmp [DriverSegment], 0 + JE Network_DriverScreen1 + + Jmp [NetworkDriver_Screen] + +Network_DriverScreen1: + Call D_GotoStartingDirectory +; Clear data area. + + Mov ES, [DiskDataArea] + Mov CX, 32768 + Xor DI, DI + Xor AX, AX + Rep StosW ; Clear diskdata Area... + + Mov [NumDrivers], AX + Mov [CurrentDriver], AX + Mov [TopDriver], AX + +; Now shift DTA to DS:64000 + + Push DS + + Push ES + Pop DS + + Mov DX, 64000 + Mov AH, 1Ah + Int 21h ; Shift DTA address.. + + Pop DS + +; Load file names. + + Mov DX, Offset DriverMask ; Wanna search for IT*.NET + Xor CX, CX ; Normal File types + Mov AH, 4Eh + +Network_DriverScreenLoadFileNames1: + Int 21h + JC Network_DriverScreenLoadFileNamesEnd + + Push DS + + Push ES + Pop DS ; DS = Diskdata + +; OK.. have the file. +; Open it and read the first 128 bytes in from it. +; Check for identification string. If all OK, then copy details into +; network list. + + Mov AX, 3D00h + Mov DX, 64000+1Eh ; Filename + Int 21h + JC Network_DriverScreenLoadFileNext + + Mov BX, AX ; File handle. + +; Read first 128 bytes of file + + Mov AH, 3Fh + Mov CX, 128 + Mov DX, 65000 + Mov DI, DX + + Int 21h ; Read file. + JC Network_DriverScreenLoadFileNextClose + +; Check for matching ID + + Mov SI, Offset DriverIdentification + Mov CX, 30 + + SegCS RepE CmpSB + JNE Network_DriverScreenLoadFileNextClose + +; Have a matching driver! +; Copy filename and Header. + + Mov DI, [CS:NumDrivers] + Inc [CS:NumDrivers] + ShL DI, 7 ; Deposit information at 128*DI + Mov CX, 13 + Mov SI, 64000+1Eh + Rep MovsB + Mov SI, 65000+64 + Mov CX, 32 + Rep MovsW + +Network_DriverScreenLoadFileNextClose: + Mov AH, 3Eh + Int 21h + +Network_DriverScreenLoadFileNext: + Pop DS + Mov AH, 4Fh + Jmp Network_DriverScreenLoadFileNames1 + +Network_DriverScreenLoadFileNamesEnd: +; OK.. jump to network screen list + + Mov AX, 5 + Mov SI, 1 + Mov CX, Object1 + + Mov DX, Offset O1_LoadNetworkDriver + Ret + +EndP Network_DriverScreen + +; + +Proc Network_DrawDriverScreen Far + + Push CS + Pop DS + Assume DS:Disk + + Call S_GetDestination ; Gets ES + + Cmp [NumDrivers], 0 + JNE Network_DrawDriverScreen1 + + Mov DI, (27+29*80)*2 ; (6, 13) + Mov SI, Offset NoDriverMsg + + Mov AH, 3 + Call S_DrawString + + Ret + +Network_DrawDriverScreen1: + Mov AX, 168+200h + Mov DI, (13*80+15)*2 + Mov CX, 36 + +Network_DrawDriverScreen2: + StosW + Add DI, 158 + Loop Network_DrawDriverScreen2 + + Mov SI, [TopDriver] + Mov DX, [NumDrivers] + Mov BX, [CurrentDriver] + +; Need to make sure they're within bounds. + Cmp BX, SI + JAE Network_DrawDriverScreenClip1 + + Mov SI, BX + +Network_DrawDriverScreenClip1: + LEA DI, [SI+35] + Cmp BX, DI + JBE Network_DrawDriverScreenClip2 + + LEA SI, [BX-35] + +Network_DrawDriverScreenClip2: + Mov DI, (13*80+2)*2 + Mov [TopDriver], SI + + Sub DX, SI + JZ Network_DrawDriverScreenEnd + + ShL SI, 7 + Mov DS, [DiskDataArea] + Assume DS:Nothing + + Cmp DX, 36 + JB Network_DrawDriverScreenClip + + Mov DX, 36 + +Network_DrawDriverScreenClip: + Mov AH, 3 + Mov CX, 13 + +Network_DrawDriverScreenFileNames: + LodsB + StosW + Loop Network_DrawDriverScreenFileNames + +; Add DI, 2 + ScasW + + Mov CX, 62 + +Network_DrawDriverScreenDriverName: + LodsB + StosW + Loop Network_DrawDriverScreenDriverName + + Add SI, 128-62-13 + Add DI, 8 + + Dec DX + JNZ Network_DrawDriverScreenClip + +Network_DrawDriverScreenEnd: + Ret + +EndP Network_DrawDriverScreen + Assume DS:Nothing + +; + +Proc Network_PreDriverScreen Far + + Push CS + Pop DS + Assume DS:Disk + + Cmp [NumDrivers], 0 + JE Network_PreDriverScreenEnd + + Mov AX, [CurrentDriver] + Sub AX, [TopDriver] + Add AX, 13 + Mov BX, 160 + Mul BX + + Call S_GetDestination + + LEA DI, [EAX+4] + Mov CX, 76 + +Network_PreDriverScreen1: + Mov AX, [ES:DI] + Mov AH, 30h + Cmp CX, 76-13 + JNE Network_PreDriverScreen2 + + Mov AH, 32h + +Network_PreDriverScreen2: + StosW + Loop Network_PreDriverScreen1 + +Network_PreDriverScreenEnd: + Ret + +EndP Network_PreDriverScreen + Assume DS:Nothing + +; + +Proc Network_Up Far + Assume DS:Disk + + Sub [CurrentDriver], 1 + AdC [CurrentDriver], 0 + + Mov AX, 1 + Ret + +EndP Network_Up + Assume DS:Nothing + +; + +Proc Network_Down Far + + Mov AX, [CurrentDriver] + Inc AX + Cmp AX, [NumDrivers] + JAE Network_Down1 + + Mov [CurrentDriver], AX + +Network_Down1: + Mov AX, 1 + Ret + +EndP Network_Down + +; + +Proc Network_PostDriverScreen Far + +; Has to handle up, down, Enter. + + Push CS + Pop DS + Assume DS:Disk + + Mov SI, Offset NetworkKeys + Call M_FunctionDivider + JC Network_PostDriverScreen1 + + Jmp [Word Ptr SI] + +Network_PostDriverScreen1: + Xor AX, AX + Ret + +EndP Network_PostDriverScreen + +; + +Proc Network_LoadDriver Far + Assume DS:Disk + +; Allocate EMS memory buffers first + + Cmp NetworkEMSHandle, 1 + JAE Network_LoadDriverMemoryAlreadyAllocated + + Call E_GetEMSVersion + Cmp AL, 40h + JB Network_LoadDriverInsufficientMemory + + ; Carry flag set -> essential allocation + StC + Mov EAX, 384*1024 + Call E_AllocateEMS + Test AX, AX + JNZ Network_LoadDriverMemoryOK + +Network_LoadDriverInsufficientMemory: + Jmp PEFunction_OutOfMemoryMessage + +Network_LoadDriverMemoryOK: + Mov NetworkEMSHandle, AX + +Network_LoadDriverMemoryAlreadyAllocated: + Cmp NetworkSendEMSHandle, 1 + JAE Network_LoadDriverSendEMSHandleAlreadyAllocated + + Mov EAX, 64*1024 + Call E_AllocateEMS + Test AX, AX + JZ Network_LoadDriverInsufficientMemory + + Mov NetworkSendEMSHandle, AX + +Network_LoadDriverSendEMSHandleAlreadyAllocated: + Cmp SendqueueSegment, 0 + JNE Network_LoadDriverMemoryAlreadyAllocated2 + + Mov AH, 48h + Mov BX, 1024 + Int 21h ; Allocate 16kb of memory for the SendQueue + JC Network_LoadDriverInsufficientMemory + + Mov SendQueueSegment, AX + +Network_LoadDriverMemoryAlreadyAllocated2: + Xor EAX, EAX + Mov DWord Ptr [SendDataQueueTail], EAX + Mov DWord Ptr [Destination], EAX + + Mov AX, [NumDrivers] + Mov DX, [CurrentDriver] + + Test AX, AX + JNZ Network_LoadDriver1 + + Ret + +Network_LoadDriver1: + ShL DX, 7 + Mov DS, [DiskDataArea] + Assume DS:Nothing + Mov DI, DX + +; Try allocating memory first. + Mov BX, [DI+13+62] ; Bytes to read + Mov AH, 48h + Add BX, 15 + ShR BX, 4 ; BX = number of parags required. + Int 21h + JNC Network_LoadDriver2 + + Jmp PEFunction_OutOfMemoryMessage + +Network_LoadDriver2: + Mov ES, AX + Mov [CS:DriverSegment], AX + + Mov AX, 3D00h + Int 21h ; Open file + JC Network_LoadDriver3 + + Mov BX, AX + Mov AX, 4200h + Xor CX, CX + Mov DX, 128 + Int 21h + JC Network_LoadDriver4 + + Mov AH, 3Fh + Mov CX, [DI+13+62] + Mov DS, [CS:DriverSegment] + Xor DX, DX + Int 21h ; Read driver + JC Network_LoadDriver4 + + Push CS + Pop DS + Assume DS:Disk + + Mov AH, 3Fh + Mov CX, NUMPROVIDEDVARIABLES + Mov DX, Offset NetworkDriverVariables + Int 21h + JC Network_LoadDriver4 + + Mov AH, 3Fh + Mov CX, NUMPROVIDEDFUNCTIONS*2 + Mov DX, Offset NetworkDriverFunctions+NUMPROVIDEDFUNCTIONS*2 + Int 21h + JC Network_LoadDriver4 + + Mov AH, 3Eh + Int 21h ; Close file. + +; Setup tables + Mov SI, Offset NetworkRequiredVariables + Xor DI, DI + Mov CX, NUMREQUIREDVARIABLES+4*NUMREQUIREDFUNCTIONS + Rep MovsB + + Mov AX, ES + Push DS + Pop ES + Mov SI, DX + Mov DI, Offset NetworkDriverFunctions + Mov CX, NUMPROVIDEDFUNCTIONS + ShL EAX, 16 + +Network_LoadDriver5: + LodsW + StosD + Loop Network_LoadDriver5 + +; Initialise Send/Receive buffers. + Mov DX, CS:NetworkEMSHandle + Mov CL, 512/16 + Mov CH, 28 + Call E_GetEMSPageFrame + Mov ES, AX + +Network_InitialiseBuffers1: + Call E_MapEMSMemory + Mov DWord Ptr [ES:65532], 0 + Sub CH, 4 + JNS Network_InitialiseBuffers1 + +; Should jump to network initialise function now. + + Jmp NetworkDriver_Initialise + Assume DS:Nothing + +Network_LoadDriver4: + Mov AH, 3Eh + Int 21h + +Network_LoadDriver3: + Jmp Network_UnloadDriver + +EndP Network_LoadDriver + Assume DS:Nothing + +; + +Proc Network_UnloadDriver Far + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:Disk + + Mov SI, Offset NetworkDriverUnloaded + Call SetInfoLine + + Mov AH, 49h + Mov ES, [DriverSegment] + Int 21h + + Mov [DriverSegment], 0 + + Mov AH, 49h + Mov ES, SendQueueSegment + Int 21h + + Mov SendQueueSegment, 0 + + Push CS + Pop ES + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset Network_EmptyFunction + Mov DI, Offset NetworkDriverFunctions + Mov CX, NUMPROVIDEDFUNCTIONS + Rep StosD + + Jmp Network_DriverScreen + +EndP Network_UnloadDriver + Assume DS:Nothing + +; + +; PatternCycle DW 0 + +Proc Network_Poll Far + +Comment ~ + Mov AX, CS:PatternCycle + Inc AX + Cmp AX, 200 + JB Network_Poll1 + + Xor AX, AX + +Network_Poll1: + Mov CS:PatternCycle, AX + + Call Network_UpdatePatternIfIdle +~ + Jmp NetworkDriver_Update + +EndP Network_Poll + +; + +Proc Network_DecodeUserName Far ; Given DS:SI = name + ; CX = count (including key) + + Test CX, CX + JZ Network_DecodeUserName3 + + Mov BX, CX + Xor DX, DX + +Network_DecodeUserName1: + LodsB + Add DL, AL + StosB + Xor DH, DL + Loop Network_DecodeUserName1 + + Add DX, 0FFFFh + JC Network_UnloadDriver + + Sub SI, BX + Mov CX, BX + + Xor AH, AH +Network_DecodeUserName2: + LodsB + Add AH, AL + XChg AL, AH + Xor AL, 0AAh + RoR AL, 2 + Mov [SI-1], AL + Loop Network_DecodeUserName2 + +Network_DecodeUserName3: + Mov CS:DriverValidated, 1 + +Network_DecodeUserNameEnd: + Ret + +EndP Network_DecodeUserName + +; + +Proc Network_Shutdown Far + + Mov AX, CS:NetworkEMSHandle + Test AX, AX + JZ Network_Shutdown1 + + Call E_ReleaseEMS + +Network_Shutdown1: + Mov AX, CS:NetworkSendEMSHandle + Test AX, AX + JZ Network_Shutdown2 + + Call E_ReleaseEMS + +Network_Shutdown2: + Jmp NetworkDriver_Shutdown + +EndP Network_Shutdown + +; +; +; Internal structures +; ------------------- +; +; SendBuffer is the raw data to transmit: +; Offset Size Contents Notes +; 0 DWord Block Header ID 'JLNP' - "J.L. Network Protocol" +; 4 Word Block Size Byte count, includes headers +; and CRC check. +; 6 Byte Block Type +; 7 <...> Data Maximum of 65000 bytes +; Word CRC Calculated +; +; Block types. +; +; SendQueue contains a queue of objects to transmit. +; Structure: +; Offset Size Contents Notes +; 0 Byte Destination 0=all, 1-3=specific, others=ignore +; 1 Byte Object Type +; 2 <> Data +; +; Object types: +; 0: Partial pattern data +; Extra data: Pattern Number (1), Bounding Box (4), Data +; 1: Entire pattern +; Extra data: Pattern Number (1), Data (Compressed) +; 2: Request pattern +; Extra data: Pattern Number (1) +; 3: SongData information (includes order list + song parameters) +; Extra data: Length (2), Offset (2) +; 4: Instrument information +; Extra data: Instrument Number (1) +; 5: Sample information +; Extra data: Sample Number (1) +; 6: Pattern Length +; Extra data: Pattern Number (1), New MaxRow (1) +; 7: Delete sample +; Extra data: Sample Number (1) +; 8: New sample - sends length also +; Extra data: Sample Number (1) +; 9: Sample Data +; Extra data: Sample Number (1), Offset (4) + + +; + +Proc Network_CalculateCRC + ; Calculates CRC and appends 6 byte header + + ; Given ES = EMSSegment + ; Given DI = end of data written + + Push DS + + Push ES + Pop DS + + Mov CX, DI + Xor SI, SI + LEA BX, [DI+2] + Xor DX, DX + Mov Word Ptr [SI+4], BX + Xor AX, AX + Mov DWord Ptr [SI], 'JLNP' + +Network_CalculateCRC1: + LodsB + Add DH, AL + Xor DL, DH + Loop Network_CalculateCRC1 + +; Have DH = sum, DL = xor of running sum. +; Want to have DX = 0 after next two bytes +; second last byte = DL-DH +; last byte = -DL + + Sub AH, DL ; AH = -DL + Sub DL, DH ; DL = DL-DH + Mov AL, DL ; AL = DL-DH + + StosW + Mov CS:SendBufferOffset, 0 + Mov CS:SendBufferRemaining, BX + + Pop DS + + Ret + +EndP Network_CalculateCRC + +; + +Proc Network_GetSendBufferPage Near + ; Returns AX = EMSPageFrame + + Push CX + Push DX + + Mov CX, EMS_SENDBUFFERPAGE + Mov DX, CS:NetworkSendEMSHandle + Call E_MapEMSMemory + Call E_GetEMSPageFrame + + Pop DX + Pop CX + + Ret + +EndP Network_GetSendBufferPage + +; + +; Send Procedure Jump Table +; Each procedure is given DS:SI = Send queue data +; ES:DI = Send buffer +; Each procedure only need write to ES:DI. +; Count of bytes is taken from return value of DI, CRC+Header will be appended +; Can use AX, BX, CX, DX, DS, SI +; Must update CS:SendDataQueueHead + +NUMBEROFBLOCKTYPES EQU 10 + +ConvertQueueObjectTypes DW Offset SendNetworkBlock0 + DW Offset SendNetworkBlock1 + DW Offset SendNetworkBlock2 + DW Offset SendNetworkBlock3 + DW Offset SendNetworkBlock4 + DW Offset SendNetworkBlock5 + DW Offset SendNetworkBlock6 + DW Offset SendNetworkBlock7 + DW Offset SendNetworkBlock8 + DW Offset SendNetworkBlock9 + +; Receive Procedure Jump Table +; Given DS = Receive buffer +; Can use any register + +InterpretObjectTypes DW Offset ReceiveNetworkBlock0 + DW Offset ReceiveNetworkBlock1 + DW Offset ReceiveNetworkBlock2 + DW Offset ReceiveNetworkBlock3 + DW Offset ReceiveNetworkBlock4 + DW Offset ReceiveNetworkBlock5 + DW Offset ReceiveNetworkBlock6 + DW Offset ReceiveNetworkBlock7 + DW Offset ReceiveNetworkBlock8 + DW Offset ReceiveNetworkBlock9 + +; +; +; Block Type 0 notes +; +; If first byte is between 80 and EF, then Val & 7F rows down are empty +; If first byte is between F0 and F7, then +; note field is empty, other fields are: +; Val & 1, ins present +; Val & 2, vol present +; Val & 4, eff present +; +; + +Proc SendNetworkBlock0 Near + +; Block type 0 +; Offset 0: Pattern Number +; 1: Channel +; 2: Row +; 3: Width +; 4: Height + + LodsB + StosB + Mov DX, AX ; DL = Pattern Number + LodsW + StosW + Mov CX, AX ; CL = Channel, CH = Row + LodsW + Mov BX, AX ; BL = Width, BH = Height + + Mov CS:SendDataQueueHead, SI + + Push Pattern + Pop DS + Assume DS:Pattern + + Cmp DL, Byte Ptr PatternNumber ; Still editing the pattern? + JE SendNetworkBlock0_0 + + Xor AX, AX + StosW + + Ret + +SendNetworkBlock0_0: + StosW + Mov DS, PatternDataArea + Assume DS:Nothing + + Mov AL, 64 + Mul CH + Add AL, CL + LEA ESI, [EAX*4+EAX] + +SendNetworkBlock0_1: + Push BX + Push SI + + Xor DX, DX ; DL = num empty rows + +SendNetworkBlock0_2: + Push SI + + Cmp Byte Ptr [SI], 0FDh + JNE SendNetworkBlock0_3 + Cmp DWord Ptr [SI+1], 0000FF00h + JNE SendNetworkBlock0_3 + + Inc DX + Cmp DL, 6Fh + JB SendNetworkBlock0_NextCell + + Mov AL, 80h + Add AL, DL + StosB + Xor DX, DX + Jmp SendNetworkBlock0_NextCell + +SendNetworkBlock0_3: + Test DX, DX + JZ SendNetworkBlock0_4 + + Mov AL, 80h + Add AL, DL + StosB + Xor DX, DX + +SendNetworkBlock0_4: + LodsB + Cmp AL, 0FDh ; Empty note? + JE SendNetworkBlock0_5 + + StosB + MovsD + Jmp SendNetworkBlock0_NextCell + +SendNetworkBlock0_5: + Push BX + + Mov BX, DI + StosB ; Increment.. needs to be filled later + + Mov CL, 0F0h + LodsB + Test AL, AL ; instrument + JZ SendNetworkBlock0_6 + + StosB + Or CL, 1 + +SendNetworkBlock0_6: ; Volume + LodsB + Cmp AL, 0FFh + JE SendNetworkBlock0_7 + + StosB + Or CL, 2 + +SendNetworkBlock0_7: ; Effect + LodsW + Test AX, AX + JZ SendNetworkBlock0_8 + + StosW + Or CL, 4 + +SendNetworkBlock0_8: + Mov [ES:BX], CL + + Pop BX + +SendNetworkBlock0_NextCell: + Pop SI + Add SI, 320 + + Dec BH + JNZ SendNetworkBlock0_2 + + Test DX, DX + JZ SendNetworkBlock0_9 + + Mov AL, 80h + Or AL, DL + StosB + +SendNetworkBlock0_9: + Pop SI + Pop BX + + Add SI, 5 ; Next column + + Dec BL + JNZ SendNetworkBlock0_1 + + Ret + +EndP SendNetworkBlock0 + Assume DS:Nothing + +; + +Proc ReceiveNetworkBlock0 Near + + Push Pattern + Pop ES + Assume ES:Pattern + + Mov [Word Ptr ES:Modified], 101h + + Mov AL, [DS:07h] ; AL = Pattern Number + + Cmp AL, [Byte Ptr ES:PatternNumber] + JNE ReceiveNetworkBlock0_1 + + Mov ES, [ES:PatternDataArea] + Assume ES:Nothing + + Mov CX, [DS:08h] ; CL = Channel, CH = Row + Mov BX, [DS:0Ah] ; BL = Width, BH = Height + + Test BX, BX + JZ ReceiveNetworkBlock0_1 + + Mov AL, 64 + Mul CH + Add AL, CL + LEA EDI, [EAX*4+EAX] + Mov AL, 5 + + Mul BL + Mov SI, 0Ch + +ReceiveNetworkBlock0_0: + Push BX + Push DI + +ReceiveNetworkBlock0_3: + LodsB + Cmp AL, 80h + JB ReceiveNetworkBlock0_4 + Cmp AL, 0F8h + JAE ReceiveNetworkBlock0_4 + + Cmp AL, 0F0h + JAE ReceiveNetworkBlock0_6 + +; Empty rows here. + And AL, 7Fh + Sub BH, AL + +ReceiveNetworkBlock0_11: + Mov Byte Ptr [ES:DI], 0FDh + Mov DWord Ptr [ES:DI+1], 0000FF00h + Add DI, 320 + Dec AL + JNZ ReceiveNetworkBlock0_11 + + Test BH, BH + JNZ ReceiveNetworkBlock0_3 + Jmp ReceiveNetworkBlock0_5 + +ReceiveNetworkBlock0_6: ; Partial row here. + Mov AH, AL + + Mov AL, 0FDh ; NONOTE + StosB + + Xor AL, AL + + Test AH, 1 + JZ ReceiveNetworkBlock0_7 + + LodsB + +ReceiveNetworkBlock0_7: + StosB + + Mov AL, 0FFh + Test AH, 2 + JZ ReceiveNetworkBlock0_8 + + LodsB + +ReceiveNetworkBlock0_8: + StosB + Test AH, 4 + Mov AX, 0 ; Don't erase flags + JZ ReceiveNetworkBlock0_9 + + LodsW + +ReceiveNetworkBlock0_9: + StosW + Jmp ReceiveNetworkBlock0_10 + +ReceiveNetworkBlock0_4: + StosB + MovsD + +ReceiveNetworkBlock0_10: + Add DI, 320-5 + + Dec BH + JNZ ReceiveNetworkBlock0_3 + +ReceiveNetworkBlock0_5: + + Pop DI + Pop BX + + Add DI, 5 + Dec BL + JNZ ReceiveNetworkBlock0_0 + + Ret + +ReceiveNetworkBlock0_1: ; Not the same, or zero width -> mark modified + +; DX = connection ID +; AL = Pattern number + + ; Sanity check + Cmp AL, 200 + JAE ReceiveNetworkBlock0_2 + + Mov BX, AX + Inc DX + And BX, 0FFh + Mov [CS:PatternModifiedTable+BX], DL + +ReceiveNetworkBlock0_2: + Ret + +EndP ReceiveNetworkBlock0 + Assume ES:Nothing + +; + +Proc SendNetworkBlock1 + +; Block type 1 +; Offset 0: Pattern number + + Push FS + + Push Pattern + Pop FS + Assume FS:Pattern + + LodsB + Mov CS:SendDataQueueHead, SI + StosB + + And AX, 0FFh + +; Check whether request should be sent off to another node instead. +; AL = Pattern number + + Mov BX, AX + + Mov DH, [CS:PatternModifiedTable+BX] + + Test DH, DH + JZ SendNetworkBlock1_1 + + Mov CS:Destination, DH + Mov Byte Ptr [ES:DI-2], 2 ; NETWORK_REQUESTPATTERNOBJECT + + Jmp SendNetworkBlock1_2 + +SendNetworkBlock1_1: + Cmp AL, [Byte Ptr FS:PatternNumber] + JNE SendNetworkBlock1_0 + + Mov [FS:PatternModified], 0 + + PushAD + Push DS + Push ES + + Call PEFunction_StoreCurrentPattern + + Pop ES + Pop DS + PopAD + +SendNetworkBlock1_0: + Call Music_GetPatternLocation + ; Returns AX = handle + ; EBX = offset/segment (or page/segment) + ; CX = length (not including header) + ; DL = 0 for conv, 1 for EMS + + Push CS + Pop DS + Assume DS:Disk + + Add CX, 8 +; Setup EMS transfer + Mov TransferLength, CX + + Mov SourceType, DL + Mov SourceHandle, AX + Mov SourceOffset, EBX + + Mov AX, NetworkSendEMSHandle + Mov DestinationType, 1 + Mov DestinationHandle, AX + Mov [Word Ptr DestinationOffset], DI + Mov [Word Ptr DestinationOffset+2], 0 + +; Data is ready to go! + Mov AX, 5700h + Mov SI, Offset EMSTransferTable + Int 67h + + Add DI, CX + +SendNetworkBlock1_2: + Call Network_GetSendBufferPage + Mov ES, AX + + Pop FS + + Ret + +EndP SendNetworkBlock1 + Assume DS:Nothing, FS:Nothing + +; + +Proc ReceiveNetworkBlock1 + + Push FS + + Push Music + Pop FS + Assume FS:Music + + Mov EDX, [DS:8] + Mov AL, [DS:7] + + And AX, 0FFh ; AX = Pattern Number + ; DX = length + +; Sanity check + Cmp AL, 200 + JAE ReceiveNetworkBlock1_2 + + Call Music_ReleasePattern + + Cmp EDX, 400040h + JE ReceiveNetworkBlock1_1 + + Push AX + + Add DX, 8 + Push DX + Push AX + + Mov SI, AX + Call Music_AllocatePattern + + Pop AX + Call Music_GetPatternLocationNoCount + +; Setup EMS transfer + Push CS + Pop DS + Assume DS:Disk + + Mov DestinationType, 1 + Mov DestinationHandle, AX + Mov DestinationOffset, EBX + + Pop DX + + Mov AX, NetworkEMSHandle + Mov CX, LastReceiveCX ; CH = page + Mov TransferLength, DX + ShR CX, 8 + Mov SourceType, 1 + Mov SourceHandle, AX + Mov [Word Ptr SourceOffset], 8 + Mov [Word Ptr SourceOffset+2], CX + +; Data is ready to go! + Mov AX, 5700h + Mov SI, Offset EMSTransferTable + Int 67h + + Pop AX + +; Mark it off as handled +; AX = Pattern number + +ReceiveNetworkBlock1_1: + Mov BX, AX + Mov [CS:PatternModifiedTable+BX], 0 + + Push Pattern + Pop DS + Assume DS:Pattern + + Cmp AL, [Byte Ptr DS:PatternNumber] + JNE ReceiveNetworkBlock1_0 + + Call PE_NewPattern + +ReceiveNetworkBlock1_0: + Cmp AL, [Byte Ptr FS:CurrentPattern] + JNE ReceiveNetworkBlock1_2 + + Call Music_UpdatePatternOffset + +ReceiveNetworkBlock1_2: + Pop FS + Ret + +EndP ReceiveNetworkBlock1 + Assume DS:Nothing + +; + +Proc SendNetworkBlock2 + + MovsB + Mov CS:SendDataQueueHead, SI + Ret + +EndP SendNetworkBlock2 + +; + +Proc ReceiveNetworkBlock2 + + Mov AH, [DS:7] ; AH = pattern + Mov AL, 1 ; NETWORK_ENTIREPATTERNOBJECT + + ; Sanity check + Cmp AH, 200 + JAE ReceiveNetworkBlock2_1 + + Call Network_AddWordToQueue + +ReceiveNetworkBlock2_1: + Ret + +EndP ReceiveNetworkBlock2 + +; + +Proc SendNetworkBlock3 + + LodsW ; Length + StosW + Mov CX, AX + LodsW + StosW + Mov CS:SendDataQueueHead, SI + + Push SongData + Pop DS + Mov SI, AX + + Rep MovsB + + Ret + +EndP SendNetworkBlock3 + +; + +Proc ReceiveNetworkBlock3 + + Push SongData + Pop ES + + Mov CX, [DS:7] + Mov DI, [DS:9] + Mov SI, 11 + + ; Sanity check + Mov AX, CX + Add AX, DI + + Cmp AX, 512 + JA ReceiveNetworkBlock3_1 + + Rep MovsB + +ReceiveNetworkBlock3_1: + Ret + +EndP ReceiveNetworkBlock3 + +; + +Proc SendNetworkBlock4 + + LodsB + StosB + And AX, 0FFh + Mov CS:SendDataQueueHead, SI + Add AX, AX + Mov SI, AX + + Push SongData + Pop DS + Mov SI, [64712+SI] + + Mov CX, 554/2 + Rep MovsW + +SendNetworkBlock4_1: + Ret + +EndP SendNetworkBlock4 + +; + +Proc ReceiveNetworkBlock4 + + Mov DI, [DS:7] + And DI, 0FFh + Mov AX, DI ; AX = instrument + + ; Sanity check + Cmp AX, 100 + JAE ReceiveNetworkBlock4_1 + + Add DI, DI + + Push SongData + Pop ES + + Mov DI, [ES:64712+DI] + Mov SI, 8 + Mov CX, 554/2 + Rep MovsW + + Call PE_GetLastInstrument + Cmp AX, BX + JNE ReceiveNetworkBlock4_1 + + Call Glbl_GetCurrentMode + Cmp AL, 4 + JNE ReceiveNetworkBlock4_1 + + Call I_MapEnvelope + +ReceiveNetworkBlock4_1: + + Ret + +EndP ReceiveNetworkBlock4 + +; + +Proc SendNetworkBlock5 ; Does not send length or + ; sample pointer. + + LodsB + StosB + And AX, 0FFh + Mov CS:SendDataQueueHead, SI + Add AX, AX + Mov SI, AX + + Push SongData + Pop DS + Mov SI, [64912+SI] + + Add SI, 4 + Mov CX, 2Ch/2 + Rep MovsW + LodsW ; Skip length + LodsW + Mov CX, 14h/2 + Rep MovsW + LodsW + LodsW + MovsW + MovsW + + Ret + +EndP SendNetworkBlock5 + +; + +Proc ReceiveNetworkBlock5 + + Mov DI, [DS:7] + And DI, 0FFh + + Cmp DI, 100 + JAE ReceiveNetworkBlock5_1 + + Add DI, DI + + Push SongData + Pop ES + + Mov DI, [ES:64912+DI] + Mov SI, 8 + ScasW + ScasW + Mov CX, 2Ch/2 + Rep MovsW + ScasW + ScasW + Mov CX, 14h/2 + Rep MovsW + ScasW + ScasW + MovsW + MovsW + +ReceiveNetworkBlock5_1: + Ret + +EndP ReceiveNetworkBlock5 + +; + +Proc SendNetworkBlock6 + + MovsW + Mov CS:SendDataQueueHead, SI + + Ret + +EndP SendNetworkBlock6 + +; + +Proc ReceiveNetworkBlock6 + + Mov AX, [DS:7] ; AL = pattern number, AH = numrows + + Push Pattern + Pop DS + Assume DS:Pattern + + Cmp AL, [Byte Ptr PatternNumber] + JNE ReceiveNetworkBlock6_1 + + Cmp AH, 200 + JAE ReceiveNetworkBlock6_2 + + Mov [Byte Ptr MaxRow], AH + +ReceiveNetworkBlock6_2: + Ret + +ReceiveNetworkBlock6_1: + Jmp ReceiveNetworkBlock0_1 ; Marks pattern as modified. + +EndP ReceiveNetworkBlock6 + Assume DS:Nothing + +; + +Proc SendNetworkBlock7 + + MovsB + Mov CS:SendDataQueueHead, SI + Ret + +EndP SendNetworkBlock7 + +; + +Proc ReceiveNetworkBlock7 + + Mov AL, [DS:7] + Mov AH, 1 + + Cmp AL, 100 + JAE ReceiveNetworkBlock7_1 + + Call Music_ReleaseSample + +ReceiveNetworkBlock7_1: + Ret + +EndP ReceiveNetworkBlock7 + +; + +Proc SendNetworkBlock8 ; New sample + + MovsB + MovsD + Mov CS:SendDataQueueHead, SI + + Ret + +EndP SendNetworkBlock8 + +; + +Proc ReceiveNetworkBlock8 ; New sample + +; Call Music_Stop + + Mov AX, [DS:7] + And AX, 0FFh ; AX = Sample number + + ; Sanity check + Cmp AX, 100 + JAE ReceiveNetworkBlock8_2 + + Mov SI, AX + Add SI, AX + Mov EDX, [DS:8] + + Push SongData + Pop DS + + Mov SI, [SI+64912] ; DS:SI = sample + Mov ECX, EDX + + Test Byte Ptr [SI+12h], 2 ; 16 bit? + JZ ReceiveNetworkBlock8_1 + + Add EDX, EDX + +ReceiveNetworkBlock8_1: + Call Music_AllocateSample + Mov [SI+30h], ECX + +ReceiveNetworkBlock8_2: + Ret + +EndP ReceiveNetworkBlock8 + +; + +Proc GetSampleLocation ; Given BX = EMS transfer structure + ; Given DX = sample number + ; Given ECX = offset + ; Returns carry if problem. + + PushAD + Push DS + + Push SongData + Pop DS + Mov SI, DX + Add SI, DX + Mov SI, [64912+SI] ; DS:SI = sample header + + Mov EAX, [SI+30h] + + Test Byte Ptr [SI+12h], 2 + JZ GetSampleLocation2 + + Add EAX, EAX + +GetSampleLocation2: + Cmp EAX, ECX + JB GetSampleLocation1 + + Mov EDX, EAX + Sub EDX, ECX + Cmp EDX, 32768 + JB GetSampleLocation6 + + Mov DX, 32768 + +GetSampleLocation6: + Mov [CS:TransferLength], DX + + Cmp Byte Ptr [SI+48h], 1 + JB GetSampleLocation1 + JA GetSampleLocation4 + +GetSampleLocation3: ; Conventional memory + Mov Byte Ptr [CS:BX], 0 ; type + Mov DWord Ptr [CS:BX+1], 0 ; handle,Offset + ShR ECX, 4 + Add CX, [SI+4Ah] + Mov Word Ptr [CS:BX+5], CX ; segment + + Jmp GetSampleLocation5 + +GetSampleLocation4: ; Expanded memory + Mov AX, [SI+4Ah] + Mov Byte Ptr [CS:BX], 1 + Mov Word Ptr [CS:BX+1], AX ; handle + Mov AX, CX + ShR ECX, 14 + And AX, 3FFFh + Mov [CS:BX+3], AX ; Offset + Mov [CS:BX+5], CX ; Page + + Jmp GetSampleLocation5 + +GetSampleLocation1: + StC + +GetSampleLocation5: + Pop DS + PopAD + + Ret + +EndP GetSampleLocation + +; + +Proc SendNetworkBlock9 + + LodsB + StosB + Mov DX, AX + LodsD + StosD + Mov ECX, EAX + And DX, 0FFh + Mov CS:SendDataQueueHead, SI + + Mov BX, Offset SourceType + Call GetSampleLocation + JC SendNetworkBlock9_1 + + Push CS + Pop DS + Assume DS:Disk + + Mov AX, NetworkSendEMSHandle + Mov DestinationType, 1 + Mov DestinationHandle, AX + Mov [Word Ptr DestinationOffset], DI + Mov [Word Ptr DestinationOffset+2], 0 + + Add DI, TransferLength + +; Data is ready to go! + Mov AX, 5700h + Mov SI, Offset EMSTransferTable + Int 67h + + Ret + +SendNetworkBlock9_1: + Sub DI, 5 + + Ret + +EndP SendNetworkBlock9 + Assume DS:Nothing + +; + +Proc ReceiveNetworkBlock9 + + Mov DX, [DS:7] + Mov ECX, [DS:8] + And DX, 0FFh + Mov BX, Offset DestinationType + Mov AX, NetworkEMSHandle + Mov SI, LastReceiveCX ; CH = page + + ; Sanity Check + Cmp DX, 100 + JAE ReceiveNetworkBlock9_1 + + Call GetSampleLocation + JC ReceiveNetworkBlock9_1 + + Push CS + Pop DS + Assume DS:Disk + + ShR SI, 8 + Mov SourceType, 1 + Mov SourceHandle, AX + Mov [Word Ptr SourceOffset], 12 + Mov [Word Ptr SourceOffset+2], SI + +; Data is ready to go! + Mov AX, 5700h + Mov SI, Offset EMSTransferTable + Int 67h + +ReceiveNetworkBlock9_1: + Ret + +EndP ReceiveNetworkBlock9 + Assume DS:Nothing + +; + +Proc Network_SendData Far +; Called by driver when it is able to send data +; +; Provided: AX = number of bytes it can send. +; ES:DI = buffer location +; +; Returns: CX = number of bytes to send, 0 if no data. +; DX = receiver's connection ID. 0 = all, 1->3 = specific. + + PushF + CLI + Push DS + Push ES + Push DI + + Push AX + Push DX + + Mov AH, 47h + Mov DX, CS:NetworkSendEMSHandle + Int 67h + + Test AH, AH + + Pop DX + Pop AX + + JNZ Network_SendDataError + + Cmp CS:DriverValidated, 1 + JNE Network_SendDataError + + Mov CX, CS:SendBufferRemaining + Test CX, CX + JNZ Network_SendData1 + +; Need to get a new block of data into the buffer. + +Network_SendData3: + Mov CX, CS:SendDataQueueTail + Mov SI, CS:SendDataQueueHead + + Sub CX, SI + JZ Network_SendDataEnd + + Mov DS, SendQueueSegment + Assume DS:Nothing + + Push AX + Push BX + Push BP + Push ES + Push DI + Push FS + +; Mov DX, CS:NetworkEMSHandle +; Call E_SavePageFrame + + Call Network_GetSendBufferPage + Mov ES, AX + Mov DI, 6 + + LodsB + Mov CS:Destination, AL + LodsB + StosB + Mov BL, AL + And BX, 0FFh + Add BX, BX + Call [CS:ConvertQueueObjectTypes+BX] + Call Network_CalculateCRC + + Cmp [CS:SendDataQueueHead], 16384-16 + JB Network_SendData4 + + Mov [CS:SendDataQueueHead], 0 + +Network_SendData4: + + Mov CX, BX ; CX = SendBufferRemaining + + Pop FS + Pop DI + Pop ES + Pop BP + Pop BX + Pop AX + +; Push DX +; Mov DX, CS:NetworkEMSHandle +; Call E_RestorePageFrame +; Pop DX + + Cmp CX, 9 + JA Network_SendData1 + + Mov DWord Ptr [CS:SendBufferRemaining], 0 + Jmp Network_SendData3 + +Network_SendData1: ; Send buffer has data remaining + Mov SI, CS:SendBufferOffset + + Cmp CX, AX + JB Network_SendData2 + + Mov CX, AX + +Network_SendData2: + Add CS:SendBufferOffset, CX + Sub CS:SendBufferRemaining, CX + + Call Network_GetSendBufferPage + Mov DS, AX + + Xor DX, DX + Push CX + Rep MovsB + Pop CX + Mov DL, CS:Destination + +Network_SendDataEnd: + Push DX + + Mov AH, 48h + Mov DX, CS:NetworkSendEMSHandle + Int 67h + + Pop DX + + Pop DI + Pop ES + Pop DS + PopF + + Ret + +Network_SendDataError: + Pop DI + Pop ES + Pop DS + PopF + + Xor CX, CX + Xor DX, DX + Ret + +EndP Network_SendData + + +; + +ReceiveToBlock DB 0, 8, 16 + +; EMS layout: +; EMS:65532: Check word +; EMS:65534: Buffer Offset + +Proc Network_ReceiveData Far +; Called by driver when data is received +; +; Provided: DS:SI = data block received +; BX = sender's connection ID (0->2) +; CX = byte count received + + PushF + CLI + Push CX + + Mov AH, 47h + Mov DX, CS:NetworkEMSHandle + Int 67h + + Test AH, AH + JNZ Network_ReceiveData3 +; Call E_SavePageFrame + + Cmp CS:DriverValidated, 1 + JNE Network_ReceiveData3 + + Mov CL, 512/16 + Mov CH, [CS:ReceiveToBlock+BX] + Mov CS:LastReceiveCX, CX + Call E_MapEMSMemory + + Call E_GetEMSPageFrame + + Pop CX + + Mov ES, AX + Mov DI, [ES:65534] + +; Consistency check -> if at start of block, make sure that the header contains +; 'JLNP' + + Test DI, DI + JNZ Network_ReceiveData1 + + Cmp DWord Ptr [SI], 'JLNP' + JNE Network_ReceiveDataEnd + +Network_ReceiveData1: + Mov DX, [ES:65532] + +; Assume OK.. now place data into buffer, updating check word. +Network_ReceiveData2: + LodsB + Add DL, AL + StosB + Xor DH, DL + Loop Network_ReceiveData2 + + Cmp DI, [ES:4] + JAE Network_ReceiveDataBlockFinished + + Mov [ES:65532], DX + Mov [ES:65534], DI + +Network_ReceiveDataEnd: + Mov AH, 48h + Mov DX, CS:NetworkEMSHandle + Int 67h +; Mov DX, CS:NetworkEMSHandle +; Call E_RestorePageFrame + + PopF + + ClC + + Ret + +Network_ReceiveDataBlockFinished: + Xor Byte Ptr [CS:ReceiveToBlock+BX], 4 + Mov DWord Ptr [ES:65532], 0 + Test DX, DX + JNZ Network_CRCFail ; CRC check failed + +; ********************* Need to handle block types here. + PushAD + Push DS + + Push ES + Pop DS + + Mov SI, [DS:6] + And SI, 0FFh + + Cmp SI, NUMBEROFBLOCKTYPES + JAE Network_ReceiveDataBlockError + + Add SI, SI + Mov DX, BX + Call [InterpretObjectTypes+SI] + +Network_ReceiveDataBlockError: + Pop DS + PopAD + Jmp Network_ReceiveDataEnd + +Network_CRCFail: + Mov AH, 48h + Mov DX, CS:NetworkEMSHandle + Int 67h + Push CX + +Network_ReceiveData3: + Pop CX + PopF + + StC + + Ret + +EndP Network_ReceiveData + +; + +Proc Network_GetSendQueue Far + + PushAD + PushF + Push DS + Push ES + + Sub SP, 4 + Push BP + Mov BP, SP + Mov EDI, [BP+44] + Mov [BP+2], EDI + Pop BP + + Push AX + Push DS + + ClI + + Push CS + Pop DS + Assume DS:Disk + +Comment ~ + This code is incomplete + Mov AX, SendDataQueueTail + Sub AX, SendDataQueueHead + Cmp AX, 16384-16 + JB Network_GetSendQueue2 + + Call [NetworkDriver_UnloadDriver] + + Xor AX, AX + Jmp Network_GetSendQueue1 + +Network_GetSendQueue2: +~ + Call [NetworkDriver_ConnectionStatus] + Mov DI, [SendQueueSegment] + Or AX, DI + Mov ES, DI + Mov DI, [SendDataQueueTail] + +Network_GetSendQueue1: + Pop DS + Pop AX + + Ret + +EndP Network_GetSendQueue + Assume DS:Nothing + +; + +Proc Network_FinishedSendQueue Far + + Cmp DI, 16384-16 ; 16 bytes slack area + JB Network_FinishedSendQueue1 + + Xor DI, DI + +Network_FinishedSendQueue1: + Mov [CS:SendDataQueueTail], DI + Mov BP, SP + Pop EAX + Mov [BP+42], EAX + +IF SHOWQUEUESIZE + Push CS + Pop DS + Mov AX, SendDataQueueTail + Sub AX, SendDataQueueHead + Mov SI, Offset DebugMessage + Call SetInfoLine +ENDIF + + Pop ES + Pop DS + PopF + PopAD + + Ret + +EndP Network_FinishedSendQueue + +; + +Proc Network_NewConnection Far ; Called when this computer + ; joins a group + + PushA + Push ES + + Push CS + Pop ES + + Mov CX, 200/2 ; Mark all patterns as requiring + ; update from host connection + Mov DI, Offset PatternModifiedTable + Mov AX, 101h + Rep StosW + + Call Music_Stop + Call D_ClearFileName + + Pop ES + PopA + Ret + + +EndP Network_NewConnection + +; + +Proc ResetDI + + Cmp DI, 16384-16 + JB ResetDI1 + + Xor DI, DI + +ResetDI1: + Ret + +EndP ResetDI + +; + +Proc Network_QueueSampleData Far ; Given CX = Sample number, 0 base + ; DL = ConnectionID + + Push EAX + Push EBX + Push ECX + Push DX + Push SI + Push DS + + Push SongData + Pop DS + + Call Network_GetSendQueue + JZ Network_QueueSampleData2 + + Mov SI, CX + Add SI, CX + Mov SI, [SI+64912] ; DS:SI = sample + + Test Byte Ptr [SI+12h], 1 + JZ Network_QueueSampleData2 + + Mov EBX, [SI+30h] + Test EBX, EBX + JZ Network_QueueSampleData2 + + Mov AL, DL + Mov AH, 8 + StosW + Mov AL, CL + StosB + Mov EAX, EBX ; Length + StosD + Call ResetDI + + Mov DH, CL + + Xor ECX, ECX + Test Byte Ptr [SI+12h], 2 + JZ Network_QueueSampleData1 + + Add EBX, EBX + +Network_QueueSampleData1: + Mov AL, DL + Mov AH, 9 + StosW + Mov AL, DH + StosB + Mov EAX, ECX + StosD + Call ResetDI + + Add ECX, 32768 + Cmp ECX, EBX + JB Network_QueueSampleData1 + +Network_QueueSampleData2: + Call Network_FinishedSendQueue + + Pop DS + Pop SI + Pop DX + Pop ECX + Pop EBX + Pop EAX + + Ret + +EndP Network_QueueSampleData + +; + +Proc Network_EstablishConnection Far ; Called when a connection is + ; made to this computer +; Called when a successful connection is made +; Given AL = new connection number + +; This basically adds all samples, instruments, patterns, +; and order list to the send queue (or requests to the appropriate nodes) + + PushA + Push DS + Push ES + + Mov ES, CS:SendQueueSegment + Mov DI, CS:SendDataQueueTail + +; Send Patterns + Xor CX, CX + Mov DX, AX + +Network_EstablishConnection1: ; 3 * 200 bytes + Mov AL, DL ; Destination + Mov AH, 1 ; NETWORK_ENTIREPATTERNOBJECT + StosW + Mov AL, CL + StosB + Call ResetDI + Inc CX + Cmp CX, 200 + JB Network_EstablishConnection1 + +; Send Instruments + Xor CX, CX + +Network_EstablishConnection2: ; 3 * 100 bytes + Mov AL, DL ; Destination + Mov AH, 4 + StosW + Mov AL, CL + StosB + Call ResetDI + Inc CX + Cmp CX, 100 + JB Network_EstablishConnection2 + +; Send Sample headers + Xor CX, CX + +Network_EstablishConnection3: ; 3 * 100 bytes + Mov AL, DL ; Destination + Mov AH, 5 + StosW + Mov AL, CL + StosB + Call ResetDI + Inc CX + Cmp CX, 100 + JB Network_EstablishConnection3 + +; Now send order list ; 6 bytes + Mov AL, DL ; Destination + Mov AH, 3 ; NETWORK_SONGDATAOBJECT + StosW + Mov AX, 512 ; Length + StosW + Xor AX, AX ; Offset + StosW + Call ResetDI + + Mov CS:SendDataQueueTail, DI + + Xor CX, CX + +Network_EstablishConnection4: + Call Network_QueueSampleData + + Inc CX + + Cmp CX, 100 + JB Network_EstablishConnection4 + +; Loop through patterns and make sure that no patterns are destined for new +; connection + + Push CS + Pop ES + + Mov CX, 200 + Mov DI, Offset PatternModifiedTable + +Network_EstablishConnection5: + Mov AL, [ES:DI] + Cmp AL, DL + JNE Network_EstablishConnection6 + + Xor AL, AL + +Network_EstablishConnection6: + StosB + Loop Network_EstablishConnection5 + + Pop ES + Pop DS + PopA + + Ret + +EndP Network_EstablishConnection + +; + +Proc Network_AddWordToQueue Far ; Given AX, broadcasts to all + + Call Network_GetSendQueue + JZ Network_AddWordToQueue0 + + Push AX + Xor AL, AL + StosB + Pop AX + StosW + +Network_AddWordToQueue0: + Call Network_FinishedSendQueue + Ret + +EndP Network_AddWordToQueue + +; + +Proc Network_UpdatePatternIfIdle Far + + Cmp CS:SendQueueSegment, 0 + JE Network_UpdatePatternEnd + + Push AX + Mov AX, CS:SendDataQueueTail + Cmp AX, CS:SendDataQueueHead + Pop AX + JNE Network_UpdatePatternEnd + +Proc Network_UpdatePattern Far + + PushA + ; AX = pattern number +; Check whether it is current. +; AL = Pattern number + + Mov BX, AX + And BX, 0FFh + Xor AX, AX + + XChg [CS:PatternModifiedTable+BX], AL + Test AL, AL + JZ Network_UpdatePattern1 + +; AL = connection request + Call Network_GetSendQueue + JZ Network_UpdatePattern2 + + StosB + Mov AL, 2 ; NETWORK_REQUESTPATTERNOBJECT + Mov AH, BL + StosW + +Network_UpdatePattern2: + Call Network_FinishedSendQueue + +Network_UpdatePattern1: + PopA + +Network_UpdatePatternEnd: + Ret + +EndP Network_UpdatePattern + +EndP Network_UpdatePatternIfIdle + +; + +Proc Network_EnsureNoNetwork Far + + Push AX + Call [CS:NetworkDriver_ConnectionStatus] + Test AL, AL + Pop AX + JZ Network_EnsureNoNetwork1 + + Mov DI, Offset O1_NetworkErrorList + Mov CX, 2 + Call M_Object1List + + Mov AX, 1 + Add SP, 4 + +Network_EnsureNoNetwork1: + Ret + +EndP Network_EnsureNoNetwork + +; + +Proc Network_SendSampleHeader Far + + Call Network_GetSendQueue + JZ Network_SendSampleHeader1 + + Mov AX, 500h ; Sample header, broadcast + StosW + Call PE_GetLastInstrument + Mov AL, BL + StosB + +Network_SendSampleHeader1: + Call Network_FinishedSendQueue + Ret + +EndP Network_SendSampleHeader + +; + +Proc Network_SendInstrumentHeader Far + + Call Network_GetSendQueue + JZ Network_SendInstrumentHeader1 + + Mov AX, 400h ; Instrument header, broadcast + StosW + Call PE_GetLastInstrument + Mov AL, BL + StosB + +Network_SendInstrumentHeader1: + Call Network_FinishedSendQueue + Ret + +EndP Network_SendInstrumentHeader + +; + +Proc Network_SendSongDataInformation Far ; CX = Count, DX = offset + + Call Network_GetSendQueue + JZ Network_SendSongDataInformation1 + + Mov AX, 300h + StosW + Mov AX, CX + StosW + Mov AX, DX + StosW + +Network_SendSongDataInformation1: + Call Network_FinishedSendQueue + Ret + +EndP Network_SendSongDataInformation + +; + +EndS + +ENDIF + +End diff --git a/it/IT_OBJ1.ASM b/it/IT_OBJ1.ASM new file mode 100644 index 0000000..c825fa7 --- /dev/null +++ b/it/IT_OBJ1.ASM @@ -0,0 +1,8902 @@ + Jumps + +include switch.inc + + Extrn D_SaveInstrument:Far + Extrn D_LSCheckLoopValues:Far + Extrn D_LSCheckSusLoopValues:Far + + Extrn D_PreLoadSampleWindow:Far + Extrn D_DrawLoadSampleWindow:Far + Extrn D_PostLoadSampleWindow:Far + + Extrn D_LSDrawDriveWindow:Far + Extrn D_LSPreDriveWindow:Far + Extrn D_LSPostDriveWindow:Far + + Extrn D_LIDrawDriveWindow:Far + Extrn D_LIPreDriveWindow:Far + Extrn D_LIPostDriveWindow:Far + + Extrn D_SaveSample:Far + Extrn D_SaveRawSample:Far + Extrn D_SaveST3Sample:Far + + Extrn D_GetFormatType:Far + + Extrn D_SlowSampleSort:Far + Extrn D_SlowInstrumentSort:Far + Extrn D_SaveDirectoryConfiguration:Far + Extrn D_LoadSampleNames:Far + Extrn D_LoadSongNames:Far + Extrn D_DrawFileWindow:Far + Extrn D_DrawDirectoryWindow:Far + Extrn D_DrawDriveWindow:Far + Extrn D_PreFileWindow:Far + Extrn D_SaveModule:Far + Extrn D_PostFileLoadWindow:Far + Extrn D_PostFileSaveWindow:Far + Extrn D_PreDirectoryWindow:Far + Extrn D_PostDirectoryWindow:Far + Extrn D_PostViewSampleLibrary:Far + Extrn D_PreDriveWindow:Far + Extrn D_PostDriveWindow:Far + Extrn D_PostSaveDriveWindow:Far + Extrn D_NewDirectory:Far + Extrn D_NewSpecifier:Far + +IF TUTORIAL +ELSE + Extrn D_LoadXM:Far + Extrn D_LoadS3M:Far + Extrn D_LoadMOD:Far + Extrn D_LoadIT:Far + Extrn D_LoadMTM:Far + Extrn D_Load669:Far +ENDIF + Extrn D_DrawHeader:Far + Extrn D_SaveIT:Far + Extrn D_SaveS3M:Far + Extrn D_SaveSong:Far + Extrn Quit:Far + + Extrn D_DrawLoadInstrument:Far + Extrn D_PreLoadInstrument:Far + Extrn D_PostLoadInstrument:Far + Extrn D_LoadInstrumentNames:Far + Extrn D_ViewInstrument:Far + +IF EMSDEBUG + + Extrn E_DumpEMSMemory:Far + +ENDIF + + Extrn LSWindow_Up:Far + Extrn LSWindow_Down:Far + + Extrn SongDirectory:Byte + Extrn FileSpecifier:Byte + + Extrn F_InstrumentButtonHandler:Far + + + Extrn F_DrawHeader:Far + Extrn F_Return0:Far + Extrn F_Return1:Far + Extrn F_ShowChannels:Far + Extrn F_RedrawScreen:Far + Extrn F_GotoEmptyList:Far + Extrn F_DrawSMCChannels:Far + Extrn F_Nothing:Far + Extrn F_CalculateLength:Far + + Extrn F_MainMenu:Far + Extrn F_Help:Far ; Menu functions + Extrn F_ViewVariables:Far + Extrn F_ViewOrderPan:Far + Extrn F_ViewPattern:Far + + Extrn F_FileMenu:Far + Extrn F_FileLoad:Far + Extrn F_FileNew:Far + Extrn F_FileSaveCurrent:Far + Extrn F_FileSaveAs:Far + Extrn F_FileDOSShell:Far + Extrn F_FileQuit:Far + + Extrn F_PlaybackMenu:Far + Extrn F_InfoPage:Far + Extrn F_PlaySong:Far + Extrn F_PlayPattern:Far + Extrn F_PlayOrder:Far + Extrn F_PlayMark:Far + Extrn F_Stop:Far + Extrn F_ReinitSoundCard:Far + Extrn F_DriverScreen:Far + Extrn F_CalculateLength:Far + + Extrn F_MessageEditor:Far + Extrn F_SampleMenu:Far + Extrn F_SampleList:Far + Extrn F_SampleLibrary:Far + Extrn F_ReloadGravis:Far + + Extrn F_Return64:Far + Extrn F_Return192:Far + + Extrn F_InstrumentMenu:Far + Extrn F_InstrumentList:Far + Extrn F_InstrumentLibrary:Far + + Extrn F_ShowMIDIZxxInput:Far + Extrn F_MIDI_Up:Far, F_MIDI_Down:Far + Extrn F_MIDI_PgUp:Far, F_MIDI_PgDn:Far + +IF SPECTRUMANALYSER + Extrn Fourier_Start:Far + Extrn Fourier_PreDrawScreen:Far + Extrn Fourier_DrawScreen:Far + Extrn Fourier_PostFunction:Far + Extrn Fourier_IdleList:Far + Extrn Fourier_ChangePalette:Far +ENDIF + + Extrn K_DrawTables:Far + Extrn K_ResetKeyboardTables:Far + Extrn K_ShowMIDIInput:Far + + Extrn PEFunction_IncreaseOctave:Far + Extrn PEFunction_DecreaseOctave:Far + + Extrn Glbl_DriverScreen:Far + Extrn Glbl_Ctrl_F1:Far + Extrn Glbl_Ctrl_F3:Far + Extrn Glbl_Ctrl_F4:Far + Extrn Glbl_Ctrl_F5:Far + Extrn Glbl_Ctrl_F12:Far + Extrn Glbl_F8:Far + Extrn Glbl_F9:Far + Extrn Glbl_F10:Far + Extrn Glbl_F11:Far + Extrn Glbl_F12:Far + Extrn Glbl_F2:Far + Extrn Glbl_F3:Far + Extrn Glbl_F4:Far + Extrn Glbl_F5:Far + Extrn Glbl_F6:Far + Extrn PE_F7:Far ; Global... + Extrn Glbl_Shift_F1:Far + Extrn Glbl_Shift_F6:Far + Extrn Glbl_Shift_F9:Far + Extrn Glbl_Alt_F1:Far + Extrn Glbl_Alt_F2:Far + Extrn Glbl_Alt_F3:Far + Extrn Glbl_Alt_F4:Far + Extrn Glbl_Alt_F5:Far + Extrn Glbl_Alt_F6:Far + Extrn Glbl_Alt_F7:Far + Extrn Glbl_Alt_F8:Far + Extrn Glbl_LoadSample:Far + Extrn Glbl_LoadInstrument:Far + Extrn Glbl_LeftBrace:Far + Extrn Glbl_RightBrace:Far + Extrn Glbl_LeftSquareBracket:Far + Extrn Glbl_RightSquareBracket:Far + +IF NETWORKENABLED + Extrn Network_DriverScreen:Far + Extrn Network_DrawDriverScreen:Far + Extrn Network_PreDriverScreen:Far + Extrn Network_PostDriverScreen:Far + + Public O1_LoadNetworkDriver +ENDIF + +IF TIMERSCREEN + Extrn Glbl_TimerScreen:Far + Extrn D_DrawTimer:Far, D_PostTimerList:Far +ENDIF + + Extrn H_HelpESC:Far + Extrn H_Help:Far + Extrn H_DrawHelp:Far + + Extrn H_HelpUp:Far + Extrn H_HelpDown:Far + Extrn H_HelpPgUp:Far + Extrn H_HelpPgDn:Far + + Extrn I_SelectScreen:Far + Extrn I_InstrumentListSpace:Far + Extrn I_InstrumentListNoteOff:Far + Extrn I_AmplifySample:Far + Extrn I_GetInstrumentScreen:Far + Extrn I_SampleButtonHandler:Far + Extrn I_CalculateC5Speed:Far + Extrn I_PrintC5Frequency:Far + + Extrn I_DoubleSampleSpeed:Far + Extrn I_HalveSampleSpeed:Far + Extrn I_SampleSpeedSemiUp:Far + Extrn I_SampleSpeedSemiDown:Far + + Extrn I_PlaySample:Far + Extrn I_PlayNote:Far + + Extrn I_DrawPitchPanCenter:Far + Extrn I_PrePitchPanCenter:Far + Extrn I_PostPitchPanCenter:Far + + Extrn I_IncreasePlayChannel:Far + Extrn I_DecreasePlayChannel:Far + + Extrn I_DeleteInstrument:Far + Extrn I_ReverseSample:Far + Extrn I_InvertSample:Far + Extrn I_CutSampleBeforeLoop:Far + Extrn I_ConvertSample:Far + Extrn I_DeleteSample:Far + Extrn I_CutSample:Far + Extrn I_ExchangeSamples:Far + Extrn I_SwapSamples:Far + Extrn I_ReplaceSample:Far + Extrn I_ReplaceInstrument:Far + Extrn I_SwapInstruments:Far + Extrn I_ResizeSample:Far + Extrn I_ResizeSampleNoInt:Far + Extrn I_UpdateInstrument:Far + Extrn I_ToggleSampleQuality:Far + Extrn I_CopyInstrument:Far + Extrn I_CenterSample:Far + Extrn I_ScaleInstrumentVolumes:Far + Extrn I_ScaleSampleVolumes:Far + + Extrn I_DrawInstrumentWindow:Far + Extrn I_PreInstrumentWindow:Far + Extrn I_PostInstrumentWindow:Far + Extrn I_ToggleMultiChannel:Far + + Extrn I_DrawNoteWindow:Far + Extrn I_PreNoteWindow:Far + Extrn I_PostNoteWindow:Far + + Extrn I_DrawEnvelope:Far + Extrn I_PreEnvelope:Far + Extrn I_PostEnvelope:Far + + Extrn I_ShowSampleInfo:Far + Extrn I_SampleUp:Far + Extrn I_SampleDown:Far + Extrn I_CheckLoopValues:Far + Extrn I_CheckSusLoopValues:Far + + Extrn I_DrawSampleList:Far + Extrn I_PreSampleList:Far + Extrn I_PostSampleList:Far + Extrn I_IdleUpdateEnvelope:Far + + Extrn Msg_DrawMessage:Far + Extrn Msg_PreMessage:Far + Extrn Msg_PostMessage:Far + + Extrn Music_SoundCardLoadAllSamples:Far + Extrn Music_ReinitSoundCard:Far + Extrn Music_SaveMIDIConfig:Far + Extrn Music_ShowAutodetectSoundcard:Far + Extrn Music_ToggleOrderUpdate:Far + + Extrn PE_FillHeader:Far + Extrn PE_SetCommandCursor:Far + Extrn PE_DrawPatternEdit:Far + Extrn PE_PrePatternEdit:Far + Extrn PE_PostPatternEdit:Far + + Extrn PEFunction_DrawUndo:Far + Extrn PEFunction_PreUndo:Far + Extrn PEFunction_PostUndo:Far + + Extrn S_UpdateScreen:Far + Extrn S_RestoreScreen:Far + + Extrn DrawDisplayData:Far + Extrn PostDisplayData:Far + Extrn DisplayUpdateScreen:Far + + Extrn BaseOctave + Extrn SkipValue + Extrn RowHiLight1 + Extrn RowHiLight2 + Extrn NumberOfRows:Word + Extrn Amplification + Extrn InstrumentAmplification + Extrn FastVolumeAmplification + Extrn SampleAmplification + Extrn CommandToValue + Extrn MultiChannelInfo + Extrn SampleNumberInput:Byte + Extrn SongDirectory:Byte + Extrn SampleDirectory:Byte + Extrn InstrumentDirectory:Byte + + Extrn IdleUpdateInfoLine:Far + Extrn DOSShell:Far + + Extrn I_ExchangeInstruments:Far + + Extrn F_ConfigButtonSetup:Far + Extrn F_SetControlInstrument:Far + Extrn F_SetControlSample:Far + Extrn F_SetMono:Far + Extrn F_SetStereo:Far + Extrn F_SetAmiga:Far + Extrn F_SetLinear:Far + + Extrn F_NewSong:Far + + Extrn AddressInput:Byte + Extrn NewSampleSize:Word + Extrn ThumbStringEnter:Byte + Extrn SampleName:Byte + +If MEMORYDEBUG + + Extrn F_PostDebug:Far + Extrn Glbl_Debug:Far + Extrn F_DrawDebug:Far + Extrn F_DebugUp:Far + Extrn F_DebugDown:Far + Extrn F_DebugPgUp:Far + Extrn F_DebugPgDn:Far + Extrn F_DebugStringInput:Far + Global O1_DebugList + +ENDIF + + Extrn PaletteDefs:Byte + + Extrn S_UsePresetPalette:Far + Extrn DisplayMinus:Far + Extrn DisplayPlus:Far + Extrn PatternSetLength, PatternLengthStart, PatternLengthEnd + + Extrn MouseToggle:Far + Extrn Refresh:Far + + Extrn MIDI_SetInstrument:Far, CentraliseCursor + Extrn MIDI_PlayNote:Far, MIDI_NoteOff:Far, MIDI_PlaySample:Far + Extrn MIDICentralNote, MIDIAmplification + + Extrn Music_TimeSong:Far, Music_ShowTime:Far + Extrn Flags + + Extrn Music_ToggleSoloInstrument:Far + Extrn Music_ToggleSoloSample:Far + +; + + Global O1_MIDIScreen + Global O1_LongMessageList + Global O1_MessageList + Global O1_ConfirmNoSave + + Global O1_MainMenu + Global O1_PlayBackMenu + Global O1_SampleMenu + Global O1_FileMenu + Global O1_InstrumentMenu + + Global O1_EditSampleName + + Global O1_AutoDetectList + + Global O1_ShowTime + Global O1_SampleCenterList + Global O1_ConfirmClearMessage + Global O1_SampleAmplificationList + Global O1_EnableInstrumentMode + Global O1_OutOfSoundCardMemoryList + Global O1_OutOfSamplesList + Global O1_NewSongList + Global O1_InitInstrument + Global O1_ThumbStringList + Global O1_ConfigureITList + Global O1_OrderVolumeList + Global O1_HelpList + Global O1_OrderPanningList + Global O1_PatternEditList + Global O1_PEConfigList + Global O1_OutOfMemoryList + Global O1_OutOfSoundCardMemoryList + Global O1_SwapOutOfRangeList + Global O1_OverlapBlockList + Global O1_NoBlockMarkedList + Global O1_NoBlockDataList + Global O1_GetAmpList + Global O1_GetInstrumentAmpList + Global O1_GetFastAmpList + +IF SHOWPATTERNLENGTH + Global O1_ShowPatternLengthList +ENDIF + + Global O1_C5FrequencyList + +IF SPECTRUMANALYSER + Global O1_FourierDisplay +ENDIF + Global O1_EMSWarningMessage +IF NETWORKENABLED + Global O1_NetworkErrorList +ENDIF + Global O1_TemplateErrorList + Global O1_PatternTooLongList + Global O1_SampleList + Global O1_LoadModuleList + Global O1_SaveModuleList + Global O1_SaveS3MList + Global O1_LoadS3MList + Global O1_LoadXMList + Global O1_LoadMODList + Global O1_Load669List + Global O1_LoadMTMList + Global O1_LoadITList + Global O1_SaveITList + Global O1_EmptyList + Global O1_ConfirmOverWriteList + Global O1_UnableToSaveList + Global O1_ConfirmQuit + Global O1_SelectMultiChannel + Global O1_ConfirmDelete + Global O1_ConfirmDelete2 + Global O1_ConfirmDelete3 + Global O1_ConfirmDeleteSample + Global O1_ConfirmDeleteInstrument + Global O1_ConfirmCutSample + Global O1_ConfirmConvertList + Global O1_ConfirmConvert2List + Global O1_ExchangeSampleList + Global O1_ExchangeInstrumentList + Global O1_ReplaceSampleList + Global O1_ReplaceInstrumentList + Global O1_LoadSampleList + Global O1_ConfirmSaveRenameList + Global O1_ConfirmResaveList + Global O1_ConfirmDiscardList + Global O1_InitialiseInstrumentList + Global O1_SwapSampleList + Global O1_SwapInstrumentList + Global O1_ResizeSampleList + Global O1_KeyboardList + Global O1_DisplayList + Global O1_FullDisplayList + Global O1_ViewSampleLibrary + Global O1_ConfigurePaletteList + Global O1_LoadInstrumentList + Global O1_ViewInstrumentLibrary + Global O1_ConfirmDeleteInstrument + Global O1_CopyInstrumentList + + Global O1_CrashRecovery + + Global O1_UndoList + + Global O1_InstrumentListGeneral + Global O1_InstrumentListVolume + Global O1_InstrumentListPanning + Global O1_InstrumentListPitch + Global O1_SetPatternLength + + Global O1_StereoSampleList + Global O1_PatternSizeMismatchList + + Global PatternLength + Global HelpKeyValue, OrderKeyValue + Global GlobalKeyList:Byte + Global LogoCharacter:Word + Global EMSErrorValue, EMSErrorValue2 + Global EMSErrorValue3, EMSErrorValue4 + Global EMSErrorValue5, EMSErrorValue6 + Global EMSErrorValue7, EMSErrorValue8 + +IF TIMERSCREEN + Public O1_TimerList +ENDIF + +; + +Segment Object1 BYTE Public 'Data' + +O1_AutoDetectList DW 6 + DW 0 + DW Near Ptr ESCContinueList + DW Near Ptr AboutBox + DW Near Ptr ImpulseLogo + DW Near Ptr AutoMiniBox + DW Near Ptr AboutText + DW Near Ptr AutoDetectText + DW Near Ptr CallAutoDetect + DW Near Ptr AutoContinueButton + DW 0 + +ESCContinueList DB 0 ; ESC + DW 101h + DD Glbl_F2 + + DB 0FFh + +O1_OrderPanningList DW 10 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr FillHeader ; 2 + DW Near Ptr OrderandPanningMsg ; 3 + DW Near Ptr OrderBox ; 4 + DW Near Ptr PanBox1 ; 5 + DW Near Ptr PanBox2 ; 6 + DW Near Ptr ShowChannelMsgs ; 7 + DW Near Ptr PanText1 ; 8 + DW Near Ptr PanText2 ; 9 + DW Near Ptr OrderList ; 10 + DW Near Ptr Channel1 ; 11 + DW Near Ptr Channel2 ; 12 + DW Near Ptr Channel3 ; 13 + DW Near Ptr Channel4 ; 14 + DW Near Ptr Channel5 ; 15 + DW Near Ptr Channel6 ; 16 + DW Near Ptr Channel7 ; 17 + DW Near Ptr Channel8 ; 18 + DW Near Ptr Channel9 ; 19 + DW Near Ptr Channel10 ; 20 + DW Near Ptr Channel11 ; 21 + DW Near Ptr Channel12 ; 22 + DW Near Ptr Channel13 ; 23 + DW Near Ptr Channel14 ; 24 + DW Near Ptr Channel15 ; 25 + DW Near Ptr Channel16 ; 26 + DW Near Ptr Channel17 + DW Near Ptr Channel18 + DW Near Ptr Channel19 + DW Near Ptr Channel20 + DW Near Ptr Channel21 + DW Near Ptr Channel22 + DW Near Ptr Channel23 + DW Near Ptr Channel24 + DW Near Ptr Channel25 + DW Near Ptr Channel26 + DW Near Ptr Channel27 + DW Near Ptr Channel28 + DW Near Ptr Channel29 + DW Near Ptr Channel30 + DW Near Ptr Channel31 + DW Near Ptr Channel32 + DW Near Ptr Channel33 + DW Near Ptr Channel34 + DW Near Ptr Channel35 + DW Near Ptr Channel36 + DW Near Ptr Channel37 + DW Near Ptr Channel38 + DW Near Ptr Channel39 + DW Near Ptr Channel40 + DW Near Ptr Channel41 + DW Near Ptr Channel42 + DW Near Ptr Channel43 + DW Near Ptr Channel44 + DW Near Ptr Channel45 + DW Near Ptr Channel46 + DW Near Ptr Channel47 + DW Near Ptr Channel48 + DW Near Ptr Channel49 + DW Near Ptr Channel50 + DW Near Ptr Channel51 + DW Near Ptr Channel52 + DW Near Ptr Channel53 + DW Near Ptr Channel54 + DW Near Ptr Channel55 + DW Near Ptr Channel56 + DW Near Ptr Channel57 + DW Near Ptr Channel58 + DW Near Ptr Channel59 + DW Near Ptr Channel60 + DW Near Ptr Channel61 + DW Near Ptr Channel62 + DW Near Ptr Channel63 + DW Near Ptr Channel64 + DW Near Ptr SetHelpContext0 + DW 0 + +O1_HelpList DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr HelpKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr FillHeader ; 2 + DW Near Ptr HelpMsg ; 3 + DW Near Ptr HelpBox ; 4 + DW Near Ptr ShowHelp ; 5 + DW Near Ptr HelpDoneButton ; 6 + DW 0 + +O1_PatternEditList DW 3 + DW Near Ptr InfoPageIdleList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr PatternEditMsg ; 2 + DW Near Ptr PatternEdit ; 3 + DW Near Ptr FillHeader ; 4 + DW Near Ptr SetHelpContext1 ; 5 + DW 0 + +O1_PEConfigList DW 14 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCF2&ReturnList + DW Near Ptr PEConfigBox ; 0 + DW Near Ptr PEConfigText ; 1 + DW Near Ptr PEConfigBsOctText ; 2 + DW Near Ptr PEConfigSkipValueText ; 3 + DW Near Ptr PEConfigRHLMinorText ; 4 + DW Near Ptr PEConfigRHLMajorText ;5 + DW Near Ptr PEConfigMaxRowsText ; 6 + DW Near Ptr PEConfigCommandCursor ; 7 + DW Near Ptr PECBox1 + DW Near Ptr PECBox2 + DW Near Ptr PECBox3 + DW Near Ptr PECBox4 + DW Near Ptr PECBox5 + DW Near Ptr PEConfigDoneButton ; 13 + DW Near Ptr PETBBaseOctave ; 14 + DW Near Ptr PETBSkipValue ; 15 + DW Near Ptr PETBRHLMinor ; 16 + DW Near Ptr PETBRHLMajor ; 17 + DW Near Ptr PETBMaxRow ; 18 + DW Near Ptr PECLinkButton ; 19 + DW Near Ptr PECSplitButton ; 20 + DW Near Ptr FillHeader + DW 0 + +O1_SetPatternLength DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr ESC&ReturnList + DW Near Ptr SetPatternLengthBox ; 0 + DW Near Ptr SetPatternLengthHeader + DW Near Ptr SetPatternLengthThumbBox1 + DW Near Ptr SetPatternLengthThumbBox2 + DW Near Ptr SetPatternLengthThumbBar ; 4 + DW Near Ptr SetPatternLengthStart ; 5 + DW Near Ptr SetPatternLengthEnd ; 6 + DW Near Ptr SetPatternLengthOKButton ; 7 + DW Near Ptr SetPatternLengthText + DW 0 + +SetPatternLengthBox DW 0 + DB 15, 19, 65, 33 + DB 3 + +SetPatternLengthHeader DW 1 + DB 31, 21 + DB 20h + DB "Set Pattern Length", 0 + +SetPatternLengthText DW 1 + DB 19, 24 + DB 20h + DB "Pattern Length", 13 + DB 13 + DB 13 + DB " Start Pattern", 13 + DB " End Pattern", 0 + +SetPatternLengthThumbBox1 DW 0 + DB 33, 23, 56, 25 + DB 25 + +SetPatternLengthThumbBox2 DW 0 + DB 33, 26, 60, 29 + DB 25 + +SetPatternLengthThumbBar DW 9 + DB 34, 24 + DW 32, 200 + DW 1, Offset PatternSetLength + DW 0FFFFh, 5, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +SetPatternLengthStart DW 9 + DB 34, 27 + DW 0, 199 + DW 1, Offset PatternLengthStart + DW 4, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +SetPatternLengthEnd DW 9 + DB 34, 28 + DW 0, 199 + DW 1, Offset PatternLengthEnd + DW 5, 7, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +SetPatternLengthOKButton DW 2 + DW 6, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 1 ; Returns 1 + DW 0, 0, 0, 0 + DB 35, 30, 44, 32 + DB 8 + DB 0 + DB " OK", 0 + +OKCancelList DB 8 ; 'O' + DW 'O' + DD DWord Ptr F_Return1 + + DB 8 ; 'C' + DW 'C' + DD DWord Ptr F_Return0 + + DB 8 ; 'Y' + DW 'Y' + DD DWord Ptr F_Return1 + + DB 8 ; 'N' + DW 'N' + DD DWord Ptr F_Return0 + +ESCReturnList DB 0 + DW 101h + DD DWord Ptr F_Return0 + + DB 5 + DW Near Ptr ChainMIDICommands + +O1_NoBlockMarkedList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr NBMText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_OutOfSoundCardMemoryList DW 2 + DW 0 + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr OOSoundCardMemoryText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_OutOfMemoryList DW 2 + DW 0 + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr OOMText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_PatternSizeMismatchList DW 2 + DW 0 + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr PSMText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_LongMessageList DW 2 + DW 0 + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr LongMsgText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_OutOfSamplesList DW 2 + DW 0 + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr OOSText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_OverlapBlockList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr OLBText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_SwapOutOfRangeList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr SOORText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_NoBlockDataList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr NBDText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_PatternTooLongList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr PatternTooLongText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_GetAmpList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr AmpExtraKeyList + DW Near Ptr AmpBox ; 0 + DW Near Ptr AmpText ; 1 + DW Near Ptr AmpTBBox ; 2 + DW Near Ptr AmpTB ; 3 + DW Near Ptr ConfirmOKButton ; 4 + DW Near Ptr ConfirmCancelButton ; 5 + DW Near Ptr FillHeader + DW 0 + +O1_GetInstrumentAmpList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr AmpExtraKeyList + DW Near Ptr AmpBox ; 0 + DW Near Ptr AmpText ; 1 + DW Near Ptr AmpTBBox ; 2 + DW Near Ptr InstrumentAmpTB ; 3 + DW Near Ptr ConfirmOKButton ; 4 + DW Near Ptr ConfirmCancelButton ; 5 + DW Near Ptr FillHeader + DW 0 + +O1_GetFastAmpList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr AmpExtraKeyList + DW Near Ptr AmpBox ; 0 + DW Near Ptr AmpText ; 1 + DW Near Ptr FastAmpTBBox ; 2 + DW Near Ptr FastAmpTB ; 3 + DW Near Ptr ConfirmOKButton ; 4 + DW Near Ptr ConfirmCancelButton ; 5 + DW Near Ptr FillHeader + DW 0 + +O1_SampleAmplificationList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr ESC&ReturnList + DW Near Ptr SampleAmpBox + DW Near Ptr SampleAmpText ; 1 + DW Near Ptr SampleAmpTBBox ; 2 + DW Near Ptr SampleAmpTB ; 3 + DW Near Ptr ConfirmOKButton ; 4 + DW Near Ptr ConfirmCancelButton ; 5 + DW Near Ptr FillHeader + DW 0 + +IF SHOWPATTERNLENGTH + +O1_ShowPatternLengthList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr PatternLengthText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +ENDIF + +O1_C5FrequencyList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr C5FrequencyText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +O1_EMSWarningMessage DW 2 + DW 0 + DW Near Ptr ESCReturnList + DW Near Ptr EMSErrorBox + DW Near Ptr EMSErrorText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +IF NETWORKENABLED +O1_NetworkErrorList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr TemplateErrorBox + DW Near Ptr NetworkErrorText + DW Near Ptr TemplateOKButton + DW Near Ptr FillHeader + DW 0 +ENDIF + +O1_TemplateErrorList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr TemplateErrorBox + DW Near Ptr TemplateErrorText + DW Near Ptr TemplateOKButton + DW Near Ptr FillHeader + DW 0 + +O1_CrashRecovery DW 2 + DW 0 + DW Near Ptr ESCReturnList + DW Near Ptr CrashRecoveryBox + DW Near Ptr CrashRecoveryText + DW Near Ptr CrashRecoveryOKButton + DW 0 + +O1_LoadSampleList DW 15 + DW Near Ptr SampleNameLoader + DW Near Ptr LoadSampleKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr LoadSampleHeader ; 2 + DW Near Ptr FillHeader ; 3 + DW Near Ptr LoadSampleBox + DW Near Ptr DriveSampleBox + DW Near Ptr LSInfoBox + DW Near Ptr LSInfoText + DW Near Ptr LSWaveFormBox + DW Near Ptr LSParametersBox + DW Near Ptr LSParametersText ; 10 + DW Near Ptr LSParametersVolBox ; 11 + DW Near Ptr LSParametersVibBox + DW Near Ptr LSFileInfoBox + DW Near Ptr LSFileInfoText + DW Near Ptr LoadSampleWindow ; 15 + DW Near Ptr LSDriveWindow ; 16 + DW Near Ptr LSFileNameInput ; 17 + DW Near Ptr LSSpeedInput + DW Near Ptr LSLoopToggle ; 19 + DW Near Ptr LSLoopBeginInput + DW Near Ptr LSLoopEndInput + DW Near Ptr LSSusLoopToggle ; 22 + DW Near Ptr LSSusLoopBeginInput + DW Near Ptr LSSusLoopEndInput + DW Near Ptr LSDefaultVolumeInput ; 25 + DW Near Ptr LSGlobalVolumeInput ; 26 + DW Near Ptr LSVibratoSpeedInput ; 27 + DW Near Ptr LSVibratoDepthInput ; 28 + DW Near Ptr LSVibratoRateInput ; 29 + DW Near Ptr SetHelpContext6 + DW 0 + +O1_ViewSampleLibrary DW 15 + DW Near Ptr SampleNameLoader + DW Near Ptr LoadSampleKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr ViewSampleHeader ; 2 + DW Near Ptr FillHeader ; 3 + DW Near Ptr LoadSampleBox + DW Near Ptr DriveSampleBox + DW Near Ptr LSInfoBox + DW Near Ptr LSInfoText + DW Near Ptr LSWaveFormBox + DW Near Ptr LSParametersBox + DW Near Ptr LSParametersText ; 10 + DW Near Ptr LSParametersVolBox ; 11 + DW Near Ptr LSParametersVibBox + DW Near Ptr LSFileInfoBox + DW Near Ptr LSFileInfoText + DW Near Ptr ViewSampleWindow ; 15 + DW Near Ptr LSDriveWindow ; 16 + DW Near Ptr LSFileNameInput ; 17 + DW Near Ptr LSSpeedInput + DW Near Ptr LSLoopToggle ; 19 + DW Near Ptr LSLoopBeginInput + DW Near Ptr LSLoopEndInput + DW Near Ptr LSSusLoopToggle ; 22 + DW Near Ptr LSSusLoopBeginInput + DW Near Ptr LSSusLoopEndInput + DW Near Ptr LSDefaultVolumeInput ; 25 + DW Near Ptr LSGlobalVolumeInput ; 26 + DW Near Ptr LSVibratoSpeedInput ; 27 + DW Near Ptr LSVibratoDepthInput ; 28 + DW Near Ptr LSVibratoRateInput ; 29 + DW Near Ptr SetHelpContext6 + DW 0 + + +LSFileNameInput DW 16 + DB 64, 13 + DW 3, 4 + DW 13 + DD 0 + DW 0FFFFh, 18, 25, 16 + +LSSpeedInput DW 18 + DB 64, 14 + DW 1, 3Ch + DD 0 + DW 17, 19, 25, 16 + +LSLoopToggle DW 17 + DB 64, 15 + DW 3, 12h + DB 16 + DW 18, 20, 25, 16 + +LSLoopBeginInput DW 18 + DB 64, 16 + DW 1, 34h + DD DWord Ptr D_LSCheckLoopValues + DW 19, 21, 25, 16 + +LSLoopEndInput DW 18 + DB 64, 17 + DW 1, 38h + DD DWord Ptr D_LSCheckLoopValues + DW 20, 22, 25, 16 + +LSSusLoopToggle DW 17 + DB 64, 18 + DW 3, 12h + DB 32 + DW 21, 23, 25, 16 + +LSSusLoopBeginInput DW 18 + DB 64, 19 + DW 1, 40h + DD DWord Ptr D_LSCheckSusLoopValues + DW 22, 24, 25, 16 + +LSSusLoopEndInput DW 18 + DB 64, 20 + DW 1, 44h + DD DWord Ptr D_LSCheckSusLoopValues + DW 23, 25, 25, 16 + +LSDefaultVolumeInput DW 9 + DB 63, 33 + DW 0, 64 + DW 5, 13h + DW 24, 26, 15, 17 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +LSGlobalVolumeInput DW 9 + DB 63, 34 + DW 0, 64 + DW 5, 11h + DW 25, 27, 15, 17 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +LSVibratoSpeedInput DW 9 + DB 63, 37 + DW 0, 64 + DW 5, 4Ch + DW 26, 28, 15, 17 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +LSVibratoDepthInput DW 14 + DB 63, 38 + DW 0, 32 + DW 5, 4Dh + DW 27, 29, 15, 17 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + DW 8 + +LSVibratoRateInput DW 14 + DB 63, 39 + DW 0, 255 + DW 5, 4Eh + DW 28, 0FFFFh, 15, 17 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + DW 8 + +SampleNameLoader DD DWord Ptr D_LoadSampleNames +IdleFunctionList DD DWord Ptr IdleUpdateInfoLine + DD 0 + +IdleInstrumentList DD DWord Ptr IdleUpdateInfoLine + DD DWord Ptr I_IdleUpdateEnvelope + DD 0 + +LoadSampleHeader DW 10 + DB "Load Sample", 0 + +ViewSampleHeader DW 10 + DB "Sample Library (Ctrl-F3)", 0 + +LoadSampleBox DW 0 + DB 5, 12, 44, 48 + DB 27 + +DriveSampleBox DW 0 + DB 45, 12, 54, 23 + DB 27 + +LSInfoBox DW 0 + DB 63, 12, 77, 23 + DB 27 + +LSInfoText DW 1 + DB 55, 13 + DB 20h + DB "Filename", 13 + DB " Speed", 13 + DB " Loop", 13 + DB " LoopBeg", 13 + DB " LoopEnd", 13 + DB " SusLoop", 13 + DB " SusLBeg", 13 + DB " SusLEnd", 13 + DB " Quality", 13 + DB " Length" + DB 0 + +LSWaveFormBox DW 0 + DB 45, 24, 77, 29 + DB 27 + +LSParametersBox DW 0 + DB 45, 30, 77, 42 + DB 9 + +LSParametersText DW 1 + DB 48, 33 + DB 20h + DB "Default Volume", 13 + DB " Global Volume", 13 + DB 13 + DB 13 + DB " Vibrato Speed", 13 + DB " Vibrato Depth", 13 + DB " Vibrato Rate" + DB 0 + +LSParametersVolBox DW 0 + DB 62, 32, 72, 35 + DB 25 + +LSParametersVibBox DW 0 + DB 62, 36, 72, 40 + DB 25 + +LSFileInfoBox DW 0 + DB 52, 43, 77, 48 + DB 27 + +LSFileInfoText DW 1 + DB 46, 44 + DB 20h + DB "Format", 13 + DB " Size", 13 + DB " Date", 13 + DB " Time" + DB 0 + +LoadSampleWindow DW 15 + DD DWord Ptr D_DrawLoadSampleWindow + DD DWord Ptr D_PreLoadSampleWindow + DD DWord Ptr D_PostLoadSampleWindow + +ViewSampleWindow DW 15 + DD DWord Ptr D_DrawLoadSampleWindow + DD DWord Ptr D_PreLoadSampleWindow + DD DWord Ptr D_PostViewSampleLibrary + +LSDriveWindow DW 15 + DD DWord Ptr D_LSDrawDriveWindow + DD DWord Ptr D_LSPreDriveWindow + DD DWord Ptr D_LSPostDriveWindow + +O1_SampleList DW 28 + DW Near Ptr IdleFunctionList + DW Near Ptr SampleGlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr SampleListHeader + DW Near Ptr SampleListBox + DW Near Ptr InstDVBox + DW Near Ptr InstDVText + DW Near Ptr InstDVTBBox + DW Near Ptr InstDVTB ; 7 + DW Near Ptr InstGVBox + DW Near Ptr InstGVText + DW Near Ptr InstGVTBBox + DW Near Ptr InstGVTB ; 11 + DW Near Ptr InstVSBox + DW Near Ptr InstVSText + DW Near Ptr InstVSTBBox + DW Near Ptr InstVSTB ; 15 + DW Near Ptr InstVDBox + DW Near Ptr InstVDText + DW Near Ptr InstVDTBBox + DW Near Ptr InstVDTB ; 19 + DW Near Ptr InstVRBox + DW Near Ptr InstVRText + DW Near Ptr InstVRTBBox + DW Near Ptr InstVRTB ; 23 + DW Near Ptr InstVWBox + DW Near Ptr InstVWText + DW Near Ptr InstParamBox + DW Near Ptr InstParamText + DW Near Ptr SampleList ; 28 + DW Near Ptr InstFileName ; 29 + DW Near Ptr InstSpeed + DW Near Ptr InstLoopToggle + DW Near Ptr InstLoopBegin + DW Near Ptr InstLoopEnd + DW Near Ptr InstSusLoopToggle + DW Near Ptr InstSusLoopBegin + DW Near Ptr InstSusLoopEnd ;36 + DW Near Ptr InstVibSine ; 37 + DW Near Ptr InstVibRamp ; 38 + DW Near Ptr InstVibSquare ; 39 + DW Near Ptr InstVibRandom ; 40 + DW Near Ptr InstWaveFormBox ; 41 + DW Near Ptr InstWaveFormText ; 42 + DW Near Ptr InstDPBox ; 43 + DW Near Ptr InstDPText + DW Near Ptr InstDPTBBox + DW Near Ptr InstDPToggle ; 46 + DW Near Ptr InstDPTB ; 47 + DW Near Ptr InstFillInfo + DW Near Ptr FillHeader + DW Near Ptr SetHelpContext2 + DW 0 + +O1_LoadModuleList DW 12 + DW Near Ptr SongNameModuleLoader + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr LoadModuleText + DW Near Ptr FileBox + DW Near Ptr DirBox ; 5 + DW Near Ptr DriveBox + DW Near Ptr SearchBox + DW Near Ptr FileInfoBox + DW Near Ptr FileNameBox + DW Near Ptr SearchText ; 10 + DW Near Ptr FileText + DW Near Ptr FileWindow ; 12 + DW Near Ptr DirectoryWindow + DW Near Ptr DriveWindow + DW Near Ptr FileNamePrompt ; 15 + DW Near Ptr SongDirectoryPrompt + DW Near Ptr SetHelpContext3 + DW 0 + +O1_SaveModuleList DW 15 + DW Near Ptr SongNameModuleLoader + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SaveModuleText + DW Near Ptr FileBox + DW Near Ptr DirBox ; 5 + DW Near Ptr DriveBox + DW Near Ptr SearchBox + DW Near Ptr FileInfoBox + DW Near Ptr FileNameBox + DW Near Ptr SearchText ; 10 + DW Near Ptr FileText + DW Near Ptr FileSaveWindow ; 12 + DW Near Ptr DirectoryWindow + DW Near Ptr SaveDriveWindow + DW Near Ptr FileNameSavePrompt ; 15 + DW Near Ptr SongDirectoryPrompt + DW Near Ptr ITFormatButton ; 17 + DW Near Ptr S3MFormatButton ; 18 + DW Near Ptr OldITFormatButton ; 19 +IF DDCOMPRESS + DW Near Ptr IT215FormatButton ; 20 +ENDIF + DW 0 + +IF NETWORKENABLED +O1_LoadNetworkDriver DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SaveModuleText + DW Near Ptr LoadNetworkText + DW Near Ptr LoadNetworkBox + DW Near Ptr LoadNetworkFunctions + DW 0 +ENDIF + +O1_SaveITList DW 7 + DW Near Ptr IdleFunctionGotoEmpty + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SaveModuleText + DW Near Ptr LoadBox + DW Near Ptr SaveITModuleText + DW Near Ptr DirectScreen ; 6 + DW Near Ptr SaveIT ; 7 + DW 0 + +O1_SaveS3MList DW 7 + DW Near Ptr IdleFunctionGotoEmpty + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SaveModuleText + DW Near Ptr LoadBox + DW Near Ptr SaveS3MModuleText + DW Near Ptr DirectScreen ; 6 + DW Near Ptr SaveS3M ; 7 + DW 0 + +IF TUTORIAL +ELSE + +O1_LoadS3MList DW 7 + DW Near Ptr IdleFunctionGotoEmpty + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr LoadModuleText + DW Near Ptr LoadBox + DW Near Ptr LoadS3MModuleText + DW Near Ptr DirectScreen ; 6 + DW Near Ptr LoadS3M ; 7 + DW 0 + +O1_LoadXMList DW 7 + DW Near Ptr IdleFunctionGotoEmpty + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr LoadModuleText + DW Near Ptr LoadBox + DW Near Ptr LoadXMModuleText + DW Near Ptr DirectScreen ; 6 + DW Near Ptr LoadXM ; 7 + DW 0 + +O1_LoadMTMList DW 7 + DW Near Ptr IdleFunctionGotoEmpty + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr LoadModuleText + DW Near Ptr LoadBox + DW Near Ptr LoadMTMModuleText + DW Near Ptr DirectScreen ; 6 + DW Near Ptr LoadMTM ; 7 + DW 0 + +O1_LoadMODList DW 7 + DW Near Ptr IdleFunctionGotoEmpty + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr LoadModuleText + DW Near Ptr LoadBox + DW Near Ptr LoadMODModuleText + DW Near Ptr DirectScreen ; 6 + DW Near Ptr LoadMOD ; 7 + DW 0 + +O1_Load669List DW 7 + DW Near Ptr IdleFunctionGotoEmpty + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr LoadModuleText + DW Near Ptr LoadBox + DW Near Ptr Load669ModuleText + DW Near Ptr DirectScreen ; 6 + DW Near Ptr Load669 ; 7 + DW 0 + +O1_LoadITList DW 7 + DW Near Ptr IdleFunctionGotoEmpty + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr LoadModuleText + DW Near Ptr LoadBox + DW Near Ptr LoadITModuleText + DW Near Ptr DirectScreen ; 6 + DW Near Ptr LoadIT ; 7 + DW 0 +ENDIF + +O1_EmptyList DW 0 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyList + DW Near Ptr InDirectScreen ; 0 + DW Near Ptr FullScreenBox ; 1 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr NoText + DW 0 + +ITFormatButton DW 2 + DW 0FFFFh, 18, 14, 15 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr D_GetFormatType + DW 0 + DW 0, 0 + DB 69, 12, 77, 14 + DB 8 + DB 0 + DB " IT214", 0 + +S3MFormatButton DW 2 + DW 17, 19, 14, 15 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr D_GetFormatType + DW 1 + DW 0, 0 + DB 69, 15, 77, 17 + DB 8 + DB 0 + DB " S3M", 0 + +IF DDCOMPRESS + +OldITFormatButton DW 2 + DW 18, 20, 14, 15 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr D_GetFormatType + DW 2 + DW 0, 0 + DB 69, 18, 77, 20 + DB 8 + DB 0 + DB " IT2xx", 0 + +IT215FormatButton DW 2 + DW 19, 15, 14, 15 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr D_GetFormatType + DW 3 + DW 0, 0 + DB 69, 21, 77, 23 + DB 8 + DB 0 + DB " IT215", 0 + + +ELSE + +OldITFormatButton DW 2 + DW 18, 15, 14, 15 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr D_GetFormatType + DW 2 + DW 0, 0 + DB 69, 18, 77, 20 + DB 8 + DB 0 + DB " IT2xx", 0 +ENDIF + + +NoText DW 10 + DB 0 + +LoadBox DW 0 + DB 1, 12, 78, 48 + DB 27 + +SaveITModuleText DW 1 + DB 3, 14 + DB 2h + DB "Saving Impulse 2 Module", 13 + DB 0FFh, 23, 129, 0 + +SaveS3MModuleText DW 1 + DB 3, 14 + DB 2h + DB "Saving Scream Tracker 3 Module", 13 + DB 0FFh, 30, 129, 0 + +LoadS3MModuleText DW 1 + DB 3, 14 + DB 2h + DB "Scream Tracker III Module", 13 + DB 0FFh, 25, 129, 0 + +LoadXMModuleText DW 1 + DB 3, 14 + DB 2h + DB "Fast Tracker II Module", 13 + DB 0FFh, 22, 129, 0 + +LoadMTMModuleText DW 1 + DB 3, 14 + DB 2h + DB "MultiTracker Module", 13 + DB 0FFh, 19, 129, 0 + +LoadMODModuleText DW 1 + DB 3, 14 + DB 2h + DB "MOD Format Module", 13 + DB 0FFh, 17, 129, 0 + +Load669ModuleText DW 1 + DB 3, 14 + DB 2h + DB "Composer 669 Module", 13 + DB 0FFh, 19, 129, 0 + +LoadITModuleText DW 1 + DB 3, 14 + DB 2h + DB "Impulse Tracker Module", 13 + DB 0FFh, 22, 129, 0 + +IdleFunctionGotoEmpty DD DWord Ptr F_GotoEmptyList + DD 0 + +IF TUTORIAL +ELSE + +LoadMOD DW 15 + DD DWord Ptr F_Return0 + DD DWord Ptr D_LoadMOD + DD DWord Ptr F_GotoEmptyList + +Load669 DW 15 + DD DWord Ptr F_Return0 + DD DWord Ptr D_Load669 + DD DWord Ptr F_GotoEmptyList + +LoadS3M DW 15 + DD DWord Ptr F_Return0 + DD DWord Ptr D_LoadS3M + DD DWord Ptr F_GotoEmptyList + +LoadXM DW 15 + DD DWord Ptr F_Return0 + DD DWord Ptr D_LoadXM + DD DWord Ptr F_GotoEmptyList + +LoadMTM DW 15 + DD DWord Ptr F_Return0 + DD DWord Ptr D_LoadMTM + DD DWord Ptr F_GotoEmptyList + +LoadIT DW 15 + DD DWord Ptr F_Return0 + DD DWord Ptr D_LoadIT + DD DWord Ptr F_GotoEmptyList + +ENDIF + +SaveIT DW 15 + DD DWord Ptr F_Return0 + DD DWord Ptr D_SaveIT + DD DWord Ptr F_GotoEmptyList + +SaveS3M DW 15 + DD DWord Ptr F_Return0 + DD DWord Ptr D_SaveS3M + DD DWord Ptr F_GotoEmptyList + +FileNamePrompt DW 16 + DB 13, 46 + DW 0 ; Disk segment + DW Offset FileSpecifier + DW 64 ; Length + DD D_NewSpecifier + DW 12, 16, 16, 14 + +FileNameSavePrompt DW 16 + DB 13, 46 + DW 0 ; Disk segment + DW Offset FileSpecifier + DW 64 ; Length + DD D_SaveModule + DW 12, 16, 16, 14 + +SongDirectoryPrompt DW 16 + DB 13, 47 + DW 0 + DW Offset SongDirectory + DW 64 + DD D_NewDirectory + DW 15, 12, 12, 15 + +SongNameModuleLoader Label DWord + DD DWord Ptr D_LoadSongNames + DD DWord Ptr IdleUpdateInfoLine + DD 0 + +FileWindow DW 15 + DD DWord Ptr D_DrawFileWindow + DD DWord Ptr D_PreFileWindow + DD DWord Ptr D_PostFileLoadWindow + +FileSaveWindow DW 15 + DD DWord Ptr D_DrawFileWindow + DD DWord Ptr D_PreFileWindow + DD DWord Ptr D_PostFileSaveWindow + +DirectoryWindow DW 15 + DD DWord Ptr D_DrawDirectoryWindow + DD DWord Ptr D_PreDirectoryWindow + DD DWord Ptr D_PostDirectoryWindow + +DriveWindow DW 15 + DD DWord Ptr D_DrawDriveWindow + DD DWord Ptr D_PreDriveWindow + DD DWord Ptr D_PostDriveWindow + +SaveDriveWindow DW 15 + DD DWord Ptr D_DrawDriveWindow + DD DWord Ptr D_PreDriveWindow + DD DWord Ptr D_PostSaveDriveWindow + +IF NETWORKENABLED +LoadNetworkText DW 10 + DB "Load Network Driver", 0 + +LoadNetworkBox DW 0 + DB 1, 12, 78, 49 + DB 27 + +LoadNetworkFunctions DW 15 + DD DWord Ptr Network_DrawDriverScreen + DD DWord Ptr Network_PreDriverScreen + DD DWord Ptr Network_PostDriverScreen + +ENDIF + +LoadModuleText DW 10 + DB "Load Module (F9)", 0 + +SaveModuleText DW 10 + DB "Save Module (F10)", 0 + +FileBox DW 0 + DB 2, 12, 41, 44 + DB 27 + +DirBox DW 0 + DB 43, 12, 56, 34 + DB 27 + +DriveBox DW 0 + DB 58, 12, 67, 34 + DB 27 + +SearchBox DW 0 + DB 50, 36, 77, 38 + DB 27 + +FileInfoBox DW 0 + DB 50, 39, 77, 44 + DB 27 + +FileNameBox DW 0 + DB 12, 45, 77, 48 + DB 27 + +SearchText DW 1 + DB 44, 37 + DB 20h + DB "Search", 13 + DB 13 + DB 13 + DB "Format", 13 + DB " Size", 13 + DB " Date", 13 + DB " Time", 0 + +FileText DW 1 + DB 3, 46 + DB 20h + DB " Filename", 13 + DB "Directory", 0 + +SampleListHeader DW 10 + DB "Sample List (F3)", 0 + +InstFillInfo DW 8 + DD DWord Ptr I_ShowSampleInfo + +InstFileName DW 16 + DB 64, 13 + DW 1 + DW 4 + DW 13 + DD 0 + DW 0FFFFh, 30, 28, 7 + +InstSpeed DW 18 + DB 64, 14 + DW 0 + DW 3Ch + DD DWord Ptr I_PlaySample + DW 29, 31, 28, 7 + +InstLoopToggle DW 17 + DB 64, 15 + DW 0 + DW 12h + DB 16 + DW 30, 32, 28, 7 + +InstLoopBegin DW 18 + DB 64, 16 + DW 0 + DW 34h + DD DWord Ptr I_CheckLoopValues + DW 31, 33, 28, 7 + +InstLoopEnd DW 18 + DB 64, 17 + DW 0 + DW 38h + DD DWord Ptr I_CheckLoopValues + DW 32, 34, 28, 7 + +InstSusLoopToggle DW 17 + DB 64, 18 + DW 0 + DW 12h + DB 32 + DW 33, 35, 28, 7 + +InstSusLoopBegin DW 18 + DB 64, 19 + DW 0 + DW 40h + DD DWord Ptr I_CheckSusLoopValues + DW 34, 36, 28, 7 + +InstSusLoopEnd DW 18 + DB 64, 20 + DW 0 + DW 44h + DD DWord Ptr I_CheckSusLoopValues + DW 35, 37, 28, 7 + +SetHelpContext0 DW 11 + DW 0 + +SetHelpContext1 DW 11 + DW 1 + +SetHelpContext2 DW 11 + DW 2 + +SetHelpContext3 DW 11 + DW 3 + +SetHelpContext4 DW 11 + DW 4 + +SetHelpContext5 DW 11 + DW 5 + +SetHelpContext6 DW 11 + DW 6 + +SetHelpContext7 DW 11 + DW 7 + +SetHelpContext8 DW 11 + DW 8 + +SetHelpContext9 DW 11 + DW 9 + +SetHelpContext10 DW 11 + DW 10 + +SetHelpContext11 DW 11 + DW 11 + +SetHelpContext12 DW 11 + DW 12 + +SetHelpContext13 DW 11 + DW 13 + +SampleListBox DW 0 + DB 4, 12, 35, 48 + DB 27 + +InstDVBox DW 0 + DB 36, 12, 53, 18 + DB 9 + +InstDVTBBox DW 0 + DB 37, 15, 47, 17 + DB 9 + +InstDVTB DW 9 + DB 38, 16 + DW 0, 64 + DW 2, 13h + DW 0FFFFh, 11, 29, 28 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +InstGVTBBox DW 0 + DB 37, 22, 47, 24 + DB 9 + +InstGVTB DW 9 + DB 38, 23 + DW 0, 64 + DW 2, 11h + DW 7, 46, 29, 28 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +InstDPTBBox DW 0 + DB 37, 29, 47, 32 + DB 25 + +InstDPToggle DW 17 + DB 38, 30 + DW 0, 2Fh + DB 80h + DW 11, 47, 29, 28 + +InstDPTB DW 9 + DB 38, 31 + DW 0, 64 + DW 2, 2Fh + DW 46, 15, 29, 28 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +InstVSTBBox DW 0 + DB 37, 38, 47, 40 + DB 9 + +InstVSTB DW 9 + DB 38, 39 + DW 0, 64 + DW 2, 4Ch + DW 47, 19, 37, 28 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +InstVDTBBox DW 0 + DB 37, 45, 47, 47 + DB 9 + +InstVDTB DW 14 + DB 38, 46 + DW 0, 32 + DW 2, 4Dh + DW 15, 0FFFFh, 23, 28 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + DW 8 + +InstVRTBBox DW 0 + DB 55, 45, 72, 47 + DB 9 + +InstVRTB DW 14 + DB 56, 46 + DW 0, 255 + DW 2, 4Eh + DW 39, 0FFFFh, 28, 19 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + DW 15 + +InstGVBox DW 0 + DB 36, 19, 53, 25 + DB 9 + +InstDPBox DW 0 + DB 36, 26, 53, 33 + DB 9 + +InstVSBox DW 0 + DB 36, 35, 53, 41 + DB 9 + +InstVDBox DW 0 + DB 36, 42, 53, 48 + DB 9 + +InstVRBox DW 0 + DB 54, 42, 77, 48 + DB 9 + +InstParamBox DW 0 + DB 63, 12, 77, 24 + DB 27 + +InstVWBox DW 0 + DB 54, 31, 77, 41 + DB 9 + +InstDVText DW 1 + DB 38, 14 + DB 20h + DB "Default Volume", 0 + +InstGVText DW 1 + DB 38, 21 + DB 20h + DB "Global Volume", 0 + +InstDPText DW 1 + DB 39, 28 + DB 20h + DB "Default Pan", 0 + +InstVSText DW 1 + DB 38, 37 + DB 20h + DB "Vibrato Speed", 0 + +InstVDText DW 1 + DB 38, 44 + DB 20h + DB "Vibrato Depth", 0 + +InstVRText DW 1 + DB 60, 44 + DB 20h + DB "Vibrato Rate", 0 + +InstVWText DW 1 + DB 58, 33 + DB 20h + DB "Vibrato Waveform", 0 + +InstParamText DW 1 + DB 55, 13 + DB 20h + DB "Filename", 13 + DB " Speed", 13 + DB " Loop", 13 + DB " LoopBeg", 13 + DB " LoopEnd", 13 + DB " SusLoop", 13 + DB " SusLBeg", 13 + DB " SusLEnd", 13 + DB 0FFh, 8, ' ', 0FEh, 21h, 146, 0FEh, 3, 0FFh, 13, 154, 0FEh, 20h, 13 + DB " Quality", 13 + DB " Length" + DB 0 + +InstVibSine DW 2 + DW 36, 39, 15, 38 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr I_SampleButtonHandler + DW 0, 4Fh, 0 + DB 56, 35, 65, 37 + DB 8 + DB 0 + DB " ", 185, 186, 0 + +InstVibRamp DW 2 + DW 36, 40, 37, 28 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr I_SampleButtonHandler + DW 1, 4Fh, 0 + DB 66, 35, 75, 37 + DB 8 + DB 0 + DB " ", 189, 190, 0 + +InstVibSquare DW 2 + DW 37, 23, 15, 40 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr I_SampleButtonHandler + DW 2, 4Fh, 0 + DB 56, 38, 65, 40 + DB 8 + DB 0 + DB " ", 187, 188, 0 + +InstVibRandom DW 2 + DW 38, 23, 39, 28 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr I_SampleButtonHandler + DW 3, 4Fh, 0 + DB 66, 38, 75, 40 + DB 8 + DB 0 + DB " Random", 0 + +InstWaveFormBox DW 0 + DB 54, 25, 77, 30 + DB 9 + +InstWaveFormText DW 1 + DB 55, 26 + DB 0Dh + DB 1, 2, 3, 4, 5, 6, 7, 8, 9, 0FFh, 1, 10, 11 + DB 12, 0FFh, 1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 13 + DB 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 + DB 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 13 + DB 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55 + DB 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 13 + DB 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77 + DB 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88 + DB 0 + +SampleList DW 15 + DD DWord Ptr I_DrawSampleList + DD DWord Ptr I_PreSampleList + DD DWord Ptr I_PostSampleList + +EMSErrorText DW 1 + DB 27, 26 + DB 20h + DB "Crash warning: EMS error", 13 + DB " Debug: ", 0FDh, "Xh, ", 0FDh, "D, ", 0FDh, "D, ", 0FDh, "X", 13 + DB 0FFh, 8, " " + DB 0FDh, "X:" + DB 0FDh, "X:" + DB 0FDh, "X:" + DB 0FDh, "X", 0 +EMSErrorValue7 DW 0 +EMSErrorValue6 DW 0 +EMSErrorValue5 DW 0 +EMSErrorValue4 DW 0 +EMSErrorValue8 DW 0 +EMSErrorValue3 DW 0 +EMSErrorValue2 DW 0 +EMSErrorValue DW 0 + +EMSErrorBox DW 0 + DB 25, 24, 54, 32 + DB 3 + +TemplateErrorBox DW 0 + DB 20, 23, 59, 34 + DB 3 + +TemplateErrorText DW 1 + DB 24, 25 + DB 20h + DB 0FFh, 9, " Template Error", 13, 13 + DB "No note in the top left position", 13 + DB " of the clipboard on which to", 13 + DB 0FFh, 7, " base translations.", 0 + +IF NETWORKENABLED +NetworkErrorText DW 1 + DB 23, 25 + DB 20h + DB 0FFh, 10, " Network Error", 13, 13 + DB "This function is not available in", 13 + DB " multi-composer mode. Disconnect", 13 + DB " from network mode to enable.", 0 +ENDIF + +CrashRecoveryBox DW 0 + DB 20, 19, 60, 30 + DB 3 + +CrashRecoveryText DW 1 + DB 22, 21 + DB 20h + DB 0FFh, 12, " Crash Recovery", 13, 13 + DB " Please save your work under a", 13 + DB " different filename, reboot your", 13 + DB "computer and rerun Impulse Tracker as", 13 + DB " the system is likely to be unstable", 0 + +IF SHOWPATTERNLENGTH + +PatternLengthText DW 1 + DB 27, 27 + DB 20h + DB "Pattern is ", 0FDh, 'D', " bytes long", 0 +PatternLength DW 0 + +ENDIF + +C5FrequencyText DW 8 + DD DWord Ptr I_PrintC5Frequency + +AmpExtraKeyList Label + DB 1 + DW 2400h ; Alt-J + DD DWord Ptr F_Return1 + + DB 0 ; ESC + DW 101h + DD DWord Ptr F_Return0 + + DB 0 ; Enter + DW 11Ch + DD DWord Ptr F_Return1 + + DB 0FFh + +AmpBox DW 0 + DB 22, 25, 57, 35 + DB 3 + +SampleAmpBox DW 0 + DB 9, 25, 69, 35 + DB 3 + +AmpText DW 1 + DB 27, 27 + DB " Volume Amplification %", 0 + +SampleAmpText DW 1 + DB 27, 27 + DB " Sample Amplification %", 0 + +AmpTBBox DW 0 + DB 25, 29, 52, 31 + DB 25 + +FastAmpTBBox DW 0 + DB 32, 29, 44, 31 + DB 25 + +SampleAmpTBBox DW 0 + DB 12, 29, 64, 31 + DB 25 + +AmpTB DW 9 + DB 26, 30 + DW 0, 200 + DW 1, Offset Amplification + DW 4, 4, 4, 4 + DW 0FFFFh, 0FFFFh + +InstrumentAmpTB DW 9 + DB 26, 30 + DW 0, 200 + DW 8, Offset InstrumentAmplification + DW 4, 4, 4, 4 + DW 0FFFFh, 0FFFFh + +FastAmpTB DW 9 + DB 33, 30 + DW 10, 90 + DW 1, Offset FastVolumeAmplification + DW 4, 4, 4, 4 + DW 0FFFFh, 0FFFFh + +SampleAmpTB DW 9 + DB 13, 30 + DW 0, 400 + DW 8, Offset SampleAmplification + DW 4, 4, 4, 4 + DW 0FFFFh, 0FFFFh + + +ConfirmOKButton DW 2 + DW 3, 3, 5, 5 + DW 0 + DW 0, 0 + DW 0 + DW 1 ; Returns 1 + DW 0, 0, 0, 0 + DB 30, 32, 39, 34 + DB 8 + DB 0 + DB " OK", 0 + +ConfirmCancelButton DW 2 + DW 3, 3, 4, 4 + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 40, 32, 49, 34 + DB 8 + DB 0 + DB " Cancel", 0 + +PatternTooLongText DW 1 + DB 28, 27 + DB 20h + DB "Pattern data exceeds 64k", 0 + +NBDText DW 1 + DB 30, 27 + DB 20h + DB "No data in clipboard", 0 + +OOSoundCardMemoryText DW 1 + DB 27, 27 + DB 20h + DB "Insufficient Soundcard RAM", 0 + +OOSText DW 1 + DB 31, 27 + DB 20h + DB "Too many samples!", 0 + + +OOMText DW 1 + DB 30, 27 + DB 20h + DB "Insufficient memory", 0 + +PSMText DW 1 + DB 27, 26 + DB 20h + DB " Crash Warning:", 13 + DB " Pattern Size Mismatch", 13 + DB "Fix: Remove corrupted data", 0 + +LongMsgText DW 1 + DB 29, 27 + DB 20h + DB "Song message too long!", 0 + +OLBText DW 1 + DB 30, 27 + DB 20h + DB "Swap blocks overlap", 0 + +SOORText DW 1 + DB 30, 27 + DB 20h + DB "Out of pattern range", 0 + +NBMBox DW 0 + DB 25, 25, 54, 32 + DB 3 + +NBMText DW 1 + DB 31, 27 + DB 20h + DB "No block is marked", 0 + +OKButton DW 2 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 35, 29, 44, 31 + DB 8 + DB 0 + DB " OK", 0 + + +CrashRecoveryOKButton DW 2 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 35, 27, 44, 29 + DB 8 + DB 0 + DB " OK", 0 + + +TemplateOKButton DW 2 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 35, 31, 44, 33 + DB 8 + DB 0 + DB " OK", 0 + + +PECLinkButton DW 2 + DW 18, 13, 20, 20 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr PE_SetCommandCursor + DW 1 + DW 0 + DW 0 + DB 39, 37, 50, 39 + DB 8 + DB 0 + DB " Link", 0 + +PECSplitButton DW 2 + DW 18, 13, 19, 19 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr PE_SetCommandCursor + DW 0 + DW 0 + DW 0 + DB 51, 37, 63, 39 + DB 8 + DB 0 + DB " Split", 0 + + +PECBox1 DW 0 + DB 39, 22, 42, 24 + DB 9 + +PECBox2 DW 0 + DB 39, 25, 43, 27 + DB 9 + +PECBox3 DW 0 + DB 39, 28, 45, 30 + DB 9 + +PECBox4 DW 0 + DB 39, 31, 57, 33 + DB 9 + +PECBox5 DW 0 + DB 39, 34, 62, 36 + DB 9 + +PEConfigBox DW 0 + DB 10, 18, 69, 43 + DB 3 + +PEConfigText DW 1 + DB 28, 19 + DB 20h + DB "Pattern Editor Options", 0 + +PEConfigBsOctText DW 1 + DB 28, 23 + DB 20h + DB "Base octave", 0 + +PEConfigSkipValueText DW 1 + DB 28, 26 + DB 20h + DB "Cursor step", 0 + +PEConfigRHLMinorText DW 1 + DB 22, 29 + DB 20h + DB "Row hilight minor", 0 + +PEConfigRHLMajorText DW 1 + DB 22, 32 + DB 20h + DB "Row hilight major", 0 + +PEConfigMaxRowsText DW 1 + DB 14, 35 + DB 20h + DB "Number of rows in pattern", 0 + +PEConfigCommandCursor DW 1 + DB 18, 38 + DB 20h + DB "Command/Value columns", 0 + +PEConfigDoneButton DW 2 + DW 19, 14, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 34, 40, 45, 42 + DB 8 + DB 0 + DB " Done", 0 + +PETBBaseOctave DW 9 + DB 40, 23 + DW 0, 8 + DW 1, Offset BaseOctave + DW 13, 15, 15, 13 + DW 0FFFFh, 0FFFFh + +PETBSkipValue DW 9 + DB 40, 26 + DW 0, 16 + DW 1, Offset SkipValue + DW 14, 16, 16, 14 + DW 0FFFFh, 0FFFFh + +PETBRHLMinor DW 9 + DB 40, 29 + DW 0, 32 + DW 1, Offset RowHiLight1 + DW 15, 17, 17, 15 + DW 0FFFFh, 0FFFFh + +PETBRHLMajor DW 9 + DB 40, 32 + DW 0, 128 + DW 1, Offset RowHiLight2 + DW 16, 18, 18, 16 + DW 0FFFFh, 0FFFFh + +PETBMaxRow DW 9 + DB 40, 35 + DW 32, 200 + DW 1, Offset NumberOfRows + DW 17, 19, 19, 17 + DW 0FFFFh, 0FFFFh + +PatternEdit DW 15 + DD DWord Ptr PE_DrawPatternEdit + DD DWord Ptr PE_PrePatternEdit + DD DWord Ptr PE_PostPatternEdit + +PatternEditMsg DW 10 + DB "Pattern Editor (F2)", 0 + +HelpKeyList DB 0 + DW 1C8h + DD DWord Ptr H_HelpUp + + DB 0 + DW 1D0h + DD DWord Ptr H_HelpDown + + DB 0 + DW 1C9h + DD DWord Ptr H_HelpPgUp + + DB 0 + DW 1D1h + DD DWord Ptr H_HelpPgDn + + DB 0 + DW 101h + DD DWord Ptr H_HelpESC + + DB 5 + DW Offset GlobalKeyChain + +ShowHelp DW 8 + DD DWord Ptr H_DrawHelp + +HelpBox DW 0 + DB 1, 12, 78, 45 + DW 27 + +HelpMsg DW 10 + DB "Help", 0 + +HelpDoneButton DW 2 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr H_HelpESC + DW 0, 0, 0 + DB 34, 46, 45, 48 + DB 8 + DB 0 + DB " Done", 0 + +SetHelpOrderPanning DW 11 + DW 0 + +OrderBox DW 0 + DB 5, 14, 9, 47 + DB 27 + +OrderList DW 12 + DB 2, 15 + DW 32 + DW 11, 43 + +ShowChannelMsgs DW 8 + DD DWord Ptr F_ShowChannels + +FillHeader DW 8 + DD DWord Ptr PE_FillHeader + +PanBox1 DW 0 + DB 30, 14, 40, 47 + DB 15 + +PanBox2 DW 0 + DB 64, 14, 74, 47 + DB 15 + +PanText1 DW 1 + DB 30, 14 + DB 23h + DB 146, 0FEh, 30h, "L M R", 0FEh, 23h, 145, 0 + +PanText2 DW 1 + DB 64, 14 + DB 23h + DB 146, 0FEh, 30h, "L M R", 0FEh, 23h, 145, 0 + +VolumeText1 DW 1 + DB 30, 14 + DB 23h + DB 146, 0FEh, 30h, " Volumes ", 0FEh, 23h, 145, 0 + +VolumeText2 DW 1 + DB 64, 14 + DB 23h + DB 146, 0FEh, 30h, " Volumes ", 0FEh, 23h, 145, 0 + + +Channel1 DW 9 ; Object 9 + DB 31, 15 ; x,y + DW 0, 64 ; Ranges + DW 0, 0 ; Pan/Channel 1 + DW 11, 12, 43, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 19 ; PgUp/PgDn + +Channel2 DW 9 + DB 31, 16 + DW 0, 64 + DW 0, 1 ; Pan/Channel 2 + DW 11, 13, 44, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 20 ; PgUp/PgDn + +Channel3 DW 9 ; Object 9 + DB 31, 17 ; x,y + DW 0, 64 ; Ranges + DW 0, 2 ; Pan/Channel 3 + DW 12, 14, 45, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 21 ; PgUp/PgDn + +Channel4 DW 9 + DB 31, 18 + DW 0, 64 + DW 0, 3 ; Pan/Channel 4 + DW 13, 15, 46, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 22 ; PgUp/PgDn + +Channel5 DW 9 ; Object 9 + DB 31, 19 ; x,y + DW 0, 64 ; Ranges + DW 0, 4 ; Pan/Channel 5 + DW 14, 16, 47, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 23 ; PgUp/PgDn + +Channel6 DW 9 + DB 31, 20 + DW 0, 64 + DW 0, 5 ; Pan/Channel 6 + DW 15, 17, 48, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 24 ; PgUp/PgDn + +Channel7 DW 9 ; Object 9 + DB 31, 21 ; x,y + DW 0, 64 ; Ranges + DW 0, 6 ; Pan/Channel 7 + DW 16, 18, 49, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 25 ; PgUp/PgDn + +Channel8 DW 9 + DB 31, 22 + DW 0, 64 + DW 0, 7 ; Pan/Channel 8 + DW 17, 19, 50, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 26 ; PgUp/PgDn + +Channel9 DW 9 ; Object 9 + DB 31, 23 ; x,y + DW 0, 64 ; Ranges + DW 0, 8 ; Pan/Channel 9 + DW 18, 20, 51, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 27 ; PgUp/PgDn + +Channel10 DW 9 + DB 31, 24 + DW 0, 64 + DW 0, 9 ; Pan/Channel 10 + DW 19, 21, 52, 10 ; Up/Down/Tab/Shift-Tab + DW 12, 28 ; PgUp/PgDn + +Channel11 DW 9 ; Object 9 + DB 31, 25 ; x,y + DW 0, 64 ; Ranges + DW 0, 10 ; Pan/Channel 11 + DW 20, 22, 53, 10 ; Up/Down/Tab/Shift-Tab + DW 13, 29 ; PgUp/PgDn + +Channel12 DW 9 + DB 31, 26 + DW 0, 64 + DW 0, 11 ; Pan/Channel 12 + DW 21, 23, 54, 10 ; Up/Down/Tab/Shift-Tab + DW 14, 30 ; PgUp/PgDn + +Channel13 DW 9 ; Object 9 + DB 31, 27 ; x,y + DW 0, 64 ; Ranges + DW 0, 12 ; Pan/Channel 13 + DW 22, 24, 55, 10 ; Up/Down/Tab/Shift-Tab + DW 15, 31 ; PgUp/PgDn + +Channel14 DW 9 + DB 31, 28 + DW 0, 64 + DW 0, 13 ; Pan/Channel 14 + DW 23, 25, 56, 10 ; Up/Down/Tab/Shift-Tab + DW 16, 32 ; PgUp/PgDn + +Channel15 DW 9 ; Object 9 + DB 31, 29 ; x,y + DW 0, 64 ; Ranges + DW 0, 14 ; Pan/Channel 15 + DW 24, 26, 57, 10 ; Up/Down/Tab/Shift-Tab + DW 17, 33 ; PgUp/PgDn + +Channel16 DW 9 + DB 31, 30 + DW 0, 64 + DW 0, 15 ; Pan/Channel 16 + DW 25, 27, 58, 10 ; Up/Down/Tab/Shift-Tab + DW 18, 34 ; PgUp/PgDn + +Channel17 DW 9 ; Object 9 + DB 31, 31 ; x,y + DW 0, 64 ; Ranges + DW 0, 16 ; Pan/Channel 17 + DW 26, 28, 59, 10 ; Up/Down/Tab/Shift-Tab + DW 19, 35 ; PgUp/PgDn + +Channel18 DW 9 + DB 31, 32 + DW 0, 64 + DW 0, 17 ; Pan/Channel 18 + DW 27, 29, 60, 10 ; Up/Down/Tab/Shift-Tab + DW 20, 36 ; PgUp/PgDn + +Channel19 DW 9 ; Object 9 + DB 31, 33 ; x,y + DW 0, 64 ; Ranges + DW 0, 18 ; Pan/Channel 19 + DW 28, 30, 61, 10 ; Up/Down/Tab/Shift-Tab + DW 21, 37 ; PgUp/PgDn + +Channel20 DW 9 + DB 31, 34 + DW 0, 64 + DW 0, 19 ; Pan/Channel 20 + DW 29, 31, 62, 10 ; Up/Down/Tab/Shift-Tab + DW 22, 38 ; PgUp/PgDn + +Channel21 DW 9 ; Object 9 + DB 31, 35 ; x,y + DW 0, 64 ; Ranges + DW 0, 20 ; Pan/Channel 21 + DW 30, 32, 63, 10 ; Up/Down/Tab/Shift-Tab + DW 23, 39 ; PgUp/PgDn + +Channel22 DW 9 + DB 31, 36 + DW 0, 64 + DW 0, 21 ; Pan/Channel 22 + DW 31, 33, 64, 10 ; Up/Down/Tab/Shift-Tab + DW 24, 40 ; PgUp/PgDn + +Channel23 DW 9 ; Object 9 + DB 31, 37 ; x,y + DW 0, 64 ; Ranges + DW 0, 22 ; Pan/Channel 23 + DW 32, 34, 65, 10 ; Up/Down/Tab/Shift-Tab + DW 25, 41 ; PgUp/PgDn + +Channel24 DW 9 + DB 31, 38 + DW 0, 64 + DW 0, 23 ; Pan/Channel 24 + DW 33, 35, 66, 10 ; Up/Down/Tab/Shift-Tab + DW 26, 42 ; PgUp/PgDn + +Channel25 DW 9 ; Object 9 + DB 31, 39 ; x,y + DW 0, 64 ; Ranges + DW 0, 24 ; Pan/Channel 25 + DW 34, 36, 67, 10 ; Up/Down/Tab/Shift-Tab + DW 27, 43 ; PgUp/PgDn + +Channel26 DW 9 + DB 31, 40 + DW 0, 64 + DW 0, 25 ; Pan/Channel 26 + DW 35, 37, 68, 10 ; Up/Down/Tab/Shift-Tab + DW 28, 44 ; PgUp/PgDn + +Channel27 DW 9 ; Object 9 + DB 31, 41 ; x,y + DW 0, 64 ; Ranges + DW 0, 26 ; Pan/Channel 27 + DW 36, 38, 69, 10 ; Up/Down/Tab/Shift-Tab + DW 29, 45 ; PgUp/PgDn + +Channel28 DW 9 + DB 31, 42 + DW 0, 64 + DW 0, 27 ; Pan/Channel 28 + DW 37, 39, 70, 10 ; Up/Down/Tab/Shift-Tab + DW 30, 46 ; PgUp/PgDn + +Channel29 DW 9 ; Object 9 + DB 31, 43 ; x,y + DW 0, 64 ; Ranges + DW 0, 28 ; Pan/Channel 29 + DW 38, 40, 71, 10 ; Up/Down/Tab/Shift-Tab + DW 31, 47 ; PgUp/PgDn + +Channel30 DW 9 + DB 31, 44 + DW 0, 64 + DW 0, 29 ; Pan/Channel 30 + DW 39, 41, 72, 10 ; Up/Down/Tab/Shift-Tab + DW 32, 48 ; PgUp/PgDn + +Channel31 DW 9 ; Object 9 + DB 31, 45 ; x,y + DW 0, 64 ; Ranges + DW 0, 30 ; Pan/Channel 31 + DW 40, 42, 73, 10 ; Up/Down/Tab/Shift-Tab + DW 33, 49 ; PgUp/PgDn + +Channel32 DW 9 + DB 31, 46 + DW 0, 64 + DW 0, 31 ; Pan/Channel 32 + DW 41, 43, 74, 10 ; Up/Down/Tab/Shift-Tab + DW 34, 50 ; PgUp/PgDn + +Channel33 DW 9 ; Object 9 + DB 65, 15 ; x,y + DW 0, 64 ; Ranges + DW 0, 32 ; Pan/Channel 33 + DW 42, 44, 10, 11 ; Up/Down/Tab/Shift-Tab + DW 35, 51 ; PgUp/PgDn + +Channel34 DW 9 + DB 65, 16 + DW 0, 64 + DW 0, 33 ; Pan/Channel 34 + DW 43, 45, 10, 12 ; Up/Down/Tab/Shift-Tab + DW 36, 52 ; PgUp/PgDn + +Channel35 DW 9 ; Object 9 + DB 65, 17 ; x,y + DW 0, 64 ; Ranges + DW 0, 34 ; Pan/Channel 35 + DW 44, 46, 10, 13 ; Up/Down/Tab/Shift-Tab + DW 37, 53 ; PgUp/PgDn + +Channel36 DW 9 + DB 65, 18 + DW 0, 64 + DW 0, 35 ; Pan/Channel 36 + DW 45, 47, 10, 14 ; Up/Down/Tab/Shift-Tab + DW 38, 54 ; PgUp/PgDn + +Channel37 DW 9 ; Object 9 + DB 65, 19 ; x,y + DW 0, 64 ; Ranges + DW 0, 36 ; Pan/Channel 37 + DW 46, 48, 10, 15 ; Up/Down/Tab/Shift-Tab + DW 39, 55 ; PgUp/PgDn + +Channel38 DW 9 + DB 65, 20 + DW 0, 64 + DW 0, 37 ; Pan/Channel 38 + DW 47, 49, 10, 16 ; Up/Down/Tab/Shift-Tab + DW 40, 56 ; PgUp/PgDn + +Channel39 DW 9 ; Object 9 + DB 65, 21 ; x,y + DW 0, 64 ; Ranges + DW 0, 38 ; Pan/Channel 39 + DW 48, 50, 10, 17 ; Up/Down/Tab/Shift-Tab + DW 41, 57 ; PgUp/PgDn + +Channel40 DW 9 + DB 65, 22 + DW 0, 64 + DW 0, 39 ; Pan/Channel 40 + DW 49, 51, 10, 18 ; Up/Down/Tab/Shift-Tab + DW 42, 58 ; PgUp/PgDn + +Channel41 DW 9 ; Object 9 + DB 65, 23 ; x,y + DW 0, 64 ; Ranges + DW 0, 40 ; Pan/Channel 41 + DW 50, 52, 10, 19 ; Up/Down/Tab/Shift-Tab + DW 43, 59 ; PgUp/PgDn + +Channel42 DW 9 + DB 65, 24 + DW 0, 64 + DW 0, 41 ; Pan/Channel 42 + DW 51, 53, 10, 20 ; Up/Down/Tab/Shift-Tab + DW 44, 60 ; PgUp/PgDn + +Channel43 DW 9 ; Object 9 + DB 65, 25 ; x,y + DW 0, 64 ; Ranges + DW 0, 42 ; Pan/Channel 43 + DW 52, 54, 10, 21 ; Up/Down/Tab/Shift-Tab + DW 45, 61 ; PgUp/PgDn + +Channel44 DW 9 + DB 65, 26 + DW 0, 64 + DW 0, 43 ; Pan/Channel 44 + DW 53, 55, 10, 22 ; Up/Down/Tab/Shift-Tab + DW 46, 62 ; PgUp/PgDn + +Channel45 DW 9 ; Object 9 + DB 65, 27 ; x,y + DW 0, 64 ; Ranges + DW 0, 44 ; Pan/Channel 45 + DW 54, 56, 10, 23 ; Up/Down/Tab/Shift-Tab + DW 47, 63 ; PgUp/PgDn + +Channel46 DW 9 + DB 65, 28 + DW 0, 64 + DW 0, 45 ; Pan/Channel 46 + DW 55, 57, 10, 24 ; Up/Down/Tab/Shift-Tab + DW 48, 64 ; PgUp/PgDn + +Channel47 DW 9 ; Object 9 + DB 65, 29 ; x,y + DW 0, 64 ; Ranges + DW 0, 46 ; Pan/Channel 47 + DW 56, 58, 10, 25 ; Up/Down/Tab/Shift-Tab + DW 49, 65 ; PgUp/PgDn + +Channel48 DW 9 + DB 65, 30 + DW 0, 64 + DW 0, 47 ; Pan/Channel 48 + DW 57, 59, 10, 26 ; Up/Down/Tab/Shift-Tab + DW 50, 66 ; PgUp/PgDn + +Channel49 DW 9 ; Object 9 + DB 65, 31 ; x,y + DW 0, 64 ; Ranges + DW 0, 48 ; Pan/Channel 49 + DW 58, 60, 10, 27 ; Up/Down/Tab/Shift-Tab + DW 51, 67 ; PgUp/PgDn + +Channel50 DW 9 + DB 65, 32 + DW 0, 64 + DW 0, 49 ; Pan/Channel 50 + DW 59, 61, 10, 28 ; Up/Down/Tab/Shift-Tab + DW 52, 68 ; PgUp/PgDn + +Channel51 DW 9 ; Object 9 + DB 65, 33 ; x,y + DW 0, 64 ; Ranges + DW 0, 50 ; Pan/Channel 51 + DW 60, 62, 10, 29 ; Up/Down/Tab/Shift-Tab + DW 53, 69 ; PgUp/PgDn + +Channel52 DW 9 + DB 65, 34 + DW 0, 64 + DW 0, 51 ; Pan/Channel 52 + DW 61, 63, 10, 30 ; Up/Down/Tab/Shift-Tab + DW 54, 70 ; PgUp/PgDn + +Channel53 DW 9 ; Object 9 + DB 65, 35 ; x,y + DW 0, 64 ; Ranges + DW 0, 52 ; Pan/Channel 53 + DW 62, 64, 10, 31 ; Up/Down/Tab/Shift-Tab + DW 55, 71 ; PgUp/PgDn + +Channel54 DW 9 + DB 65, 36 + DW 0, 64 + DW 0, 53 ; Pan/Channel 54 + DW 63, 65, 10, 32 ; Up/Down/Tab/Shift-Tab + DW 56, 72 ; PgUp/PgDn + +Channel55 DW 9 ; Object 9 + DB 65, 37 ; x,y + DW 0, 64 ; Ranges + DW 0, 54 ; Pan/Channel 55 + DW 64, 66, 10, 33 ; Up/Down/Tab/Shift-Tab + DW 57, 73 ; PgUp/PgDn + +Channel56 DW 9 + DB 65, 38 + DW 0, 64 + DW 0, 55 ; Pan/Channel 56 + DW 65, 67, 10, 34 ; Up/Down/Tab/Shift-Tab + DW 58, 74 ; PgUp/PgDn + +Channel57 DW 9 ; Object 9 + DB 65, 39 ; x,y + DW 0, 64 ; Ranges + DW 0, 56 ; Pan/Channel 57 + DW 66, 68, 10, 35 ; Up/Down/Tab/Shift-Tab + DW 59, 74 ; PgUp/PgDn + +Channel58 DW 9 + DB 65, 40 + DW 0, 64 + DW 0, 57 ; Pan/Channel 58 + DW 67, 69, 10, 36 ; Up/Down/Tab/Shift-Tab + DW 60, 74 ; PgUp/PgDn + +Channel59 DW 9 ; Object 9 + DB 65, 41 ; x,y + DW 0, 64 ; Ranges + DW 0, 58 ; Pan/Channel 59 + DW 68, 70, 10, 37 ; Up/Down/Tab/Shift-Tab + DW 61, 74 ; PgUp/PgDn + +Channel60 DW 9 + DB 65, 42 + DW 0, 64 + DW 0, 59 ; Pan/Channel 60 + DW 69, 71, 10, 38 ; Up/Down/Tab/Shift-Tab + DW 62, 74 ; PgUp/PgDn + +Channel61 DW 9 ; Object 9 + DB 65, 43 ; x,y + DW 0, 64 ; Ranges + DW 0, 60 ; Pan/Channel 61 + DW 70, 72, 10, 39 ; Up/Down/Tab/Shift-Tab + DW 63, 74 ; PgUp/PgDn + +Channel62 DW 9 + DB 65, 44 + DW 0, 64 + DW 0, 61 ; Pan/Channel 62 + DW 71, 73, 10, 40 ; Up/Down/Tab/Shift-Tab + DW 64, 74 ; PgUp/PgDn + +Channel63 DW 9 ; Object 9 + DB 65, 45 ; x,y + DW 0, 64 ; Ranges + DW 0, 62 ; Pan/Channel 63 + DW 72, 74, 10, 41 ; Up/Down/Tab/Shift-Tab + DW 65, 74 ; PgUp/PgDn + +Channel64 DW 9 + DB 65, 46 + DW 0, 64 + DW 0, 63 ; Pan/Channel 64 + DW 73, 74, 10, 42 ; Up/Down/Tab/Shift-Tab + DW 66, 74 ; PgUp/PgDn + +OrderAndPanningMsg DW 10 + DB "Order List and Panning (F11)", 0 + +OrderAndVolumeMsg DW 10 + DB "Order List and Channel Volume (F11)", 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 + DD DWord Ptr F_DrawHeader + +CallAutoDetect DW 8 + DD DWord Ptr Music_ShowAutoDetectSoundCard + +AutoMiniBox DW 0 + DB 25, 25, 55, 30 + DB 0 + +AutoDetectText DW 1 + DB 32, 26 + DB 20h + DB "Sound Card Setup", 0 + +LoadSampleKeyList DB 0 + DW 101h ; ESC + DD DWord Ptr Glbl_F3 + +ViewSampleKeyList Label + DB 0 + DW 1C9h ; PgUp + DD DWord Ptr LSWindow_Up + + DB 0 + DW 1D1h ; PgDn + DD DWord Ptr LSWindow_Down + + DB 1 ; Alt + DW 1F00h ; 'S' + DD DWord Ptr D_SlowSampleSort + + DB 5 ; Chain to... + DW Offset GlobalKeyList + + +LoadInstrumentKeyList DB 0 + DW 101h ; ESC + DD DWord Ptr Glbl_F4 + + DB 1 ; Alt + DW 1F00h ; 'S' + DD DWord Ptr D_SlowInstrumentSort + + DB 5 + DW Offset GlobalKeyList + +GlobalKeyList DB 0 ; F1 +HelpKeyValue DW 13Bh + DD DWord Ptr H_Help + +GlobalKeyChain: + DB 3 ; Ctrl... + DW 13Bh ; F1 + DD DWord Ptr Glbl_Ctrl_F1 + + DB 0 ; F2 + DW 13Ch + DD DWord Ptr Glbl_F2 + + DB 0 ; F3 + DW 13Dh + DD DWord Ptr Glbl_F3 + + DB 3 ; Ctrl... + DW 13Dh ; F3 + DD DWord Ptr Glbl_Ctrl_F3 + + DB 0 ; F4 + DW 13Eh + DD DWord Ptr Glbl_F4 + + DB 3 ; Ctrl... + DW 13Eh ; F4 + DD DWord Ptr Glbl_Ctrl_F4 + + DB 0 ; F5 + DW 13Fh + DD DWord Ptr Glbl_F5 + + DB 1 + DW 12h ; Ctrl 'R' + DD DWord Ptr Glbl_F9 + + DB 1 + DW 0Ch ; Ctrl 'L' + DD DWord Ptr Glbl_F9 + + DB 0 ; F9 + DW 142h + DD DWord Ptr Glbl_F8 + + DB 0 ; F9 + DW 143h + DD DWord Ptr Glbl_F9 + + DB 6 ; F9 + DW 143h + DD DWord Ptr Glbl_Shift_F9 + + DB 1 + DW 17h ; Ctrl 'W' + DD DWord Ptr Glbl_F10 + + DB 0 ; F10 + DW 144h + DD DWord Ptr Glbl_F10 + + DB 0 ; F11 +OrderKeyValue DW 157h + DD DWord Ptr Glbl_F11 + + DB 0 ; F12 + DW 158h + DD DWord Ptr Glbl_F12 + + DB 3 ; Ctrl.. + DW 158h ; F1 + DD DWord Ptr Glbl_Ctrl_F12 + + DB 0 ; ESC + DW 101h + DD DWord Ptr F_MainMenu + + DB 1 + DW 04h ; Ctrl 'D' + DD DWord Ptr DOSShell + + DB 1 + DW 05h ; Ctrl 'E' + DD DWord Ptr Refresh + + DB 1 + DW 13h ; Ctrl 'S' + DD DWord Ptr D_SaveSong + + DB 1 + DW 11h ; Ctrl 'Q' + DD DWord Ptr Quit + + DB 1 + DW 0Dh ; Ctrl 'M' + DD DWord Ptr MouseToggle + + DB 1 + DW 0Eh ; Ctrl 'N' + DD DWord Ptr F_NewSong + + DB 1 + DW 7h ; Ctrl 'G' + DD DWord Ptr Music_SoundCardLoadAllSamples + + DB 1 + DW 9 ; Ctrl 'I' + DD DWord Ptr Music_ReinitSoundCard + + DB 1 + DW 16 ; Ctrl 'P' + DD DWord Ptr Music_TimeSong + +IF MEMORYDEBUG + DB 0 + DW 15B7h ; Right shift+Ctrl+Printscreen + DD DWord Ptr Glbl_Debug +ENDIF + + DB 2 ; Alt.. + DW 13Bh ; F1 + DD DWord Ptr Glbl_Alt_F1 + + DB 2 ; Alt.. + DW 13Ch ; F2 + DD DWord Ptr Glbl_Alt_F2 + + DB 2 ; Alt.. + DW 13Dh ; F3 + DD DWord Ptr Glbl_Alt_F3 + + DB 2 ; Alt.. + DW 13Eh ; F4 + DD DWord Ptr Glbl_Alt_F4 + + DB 2 ; Alt.. + DW 13Fh ; F5 + DD DWord Ptr Glbl_Alt_F5 + + DB 2 ; Alt.. + DW 140h ; F6 + DD DWord Ptr Glbl_Alt_F6 + + DB 2 ; Alt.. + DW 141h ; F7 + DD DWord Ptr Glbl_Alt_F7 + + DB 2 ; Alt.. + DW 142h ; F8 + DD DWord Ptr Glbl_Alt_F8 + + DB 2 ; Alt.. + DW 157h ; F11 + DD DWord Ptr Music_ToggleOrderUpdate + +IF NETWORKENABLED + DB 6 ; Shift + DW 101h ; ESC + DD DWord Ptr Network_DriverScreen +ENDIF + + DB 6 ; Shift F1 + DW 13Bh + DD DWord Ptr Glbl_Shift_F1 + + DB 6 ; Shift F5 + DW 13Fh + DD DWord Ptr Glbl_DriverScreen + +IF TIMERSCREEN + DB 0 ; Left shift, left+right alt + DW 73C6h ; Right ctrl + Pause + DD DWord Ptr Glbl_TimerScreen +ENDIF + +IF EMSDEBUG + DB 0 ; Left shift, Left alt, right alt + DW 6329h ; + ~ + DD DWord Ptr E_DumpEMSMemory +ENDIF + +PlayCommandChain: + DB 3 ; Ctrl... + DW 13Fh ; F5 + DD DWord Ptr Glbl_Ctrl_F5 + + DB 0 ; F6 + DW 140h + DD DWord Ptr Glbl_F6 + + DB 6 ; F6 + DW 140h + DD DWord Ptr Glbl_Shift_F6 + + DB 0 + DW 141h ; F7 + DD DWord Ptr PE_F7 + + DB 3 ; Ctrl + DW 1CBh ; Left + DD DWord Ptr DisplayMinus + + DB 3 ; Ctrl + DW 1CDh ; Right + DD DWord Ptr DisplayPlus + + DB 0 + DW 1B5h + DD DWord Ptr PEFunction_DecreaseOctave + + DB 0 + DW 137h + DD DWord Ptr PEFunction_IncreaseOctave + + DB 6 + DW 1B5h + DD DWord Ptr PEFunction_DecreaseOctave + + DB 6 + DW 137h + DD DWord Ptr PEFunction_IncreaseOctave + + DB 1 + DW '{' + DD DWord Ptr Glbl_LeftBrace + + DB 1 + DW '}' + DD DWord Ptr Glbl_RightBrace + + DB 1 + DW '[' + DD DWord Ptr Glbl_LeftSquareBracket + + DB 1 + DW ']' + DD DWord Ptr Glbl_RightSquareBracket + +ChainMIDICommands: + DB 9 ; MIDI Message + DW 08000h + DD DWord Ptr MIDI_NoteOff + + DB 9 ; MIDI Message + DW 09000h + DD DWord Ptr MIDI_PlayNote + + DB 9 ; MIDI Message + DW 0C000h + DD DWord Ptr MIDI_SetInstrument + + DB 0FFh ; End of list + +ESCExitList DB 0 ; ESC + DW 101h + DD DWord Ptr F_Return0 + + DB 5 + DW Near Ptr ChainMIDICommands + +SampleGlobalKeyList Label +IF ENABLESOLO + DB 1 + DW '`' + DD DWord Ptr Music_ToggleSoloSample +ENDIF + + DB 0 + DW 1C9h + DD DWord Ptr I_SampleUp + + DB 0 + DW 1D1h + DD DWord Ptr I_SampleDown + + DB 1 + DW '<' + DD DWord Ptr I_DecreasePlayChannel + + DB 1 + DW '>' + DD DWord Ptr I_IncreasePlayChannel + + DB 1 + DW ',' + DD DWord Ptr I_DecreasePlayChannel + + DB 1 + DW '.' + DD DWord Ptr I_IncreasePlayChannel + + DB 1 + DW 1E00h ; Alt 'A' + DD DWord Ptr I_ConvertSample + + DB 1 + DW 3000h ; Alt 'B' + DD DWord Ptr I_CutSampleBeforeLoop + + DB 1 + DW 2000h ; Alt 'D' + DD DWord Ptr I_DeleteSample + + DB 1 + DW 1200h ; Alt 'E' + DD DWord Ptr I_ResizeSample + + DB 1 + DW 2100h ; Alt 'F' + DD DWord Ptr I_ResizeSampleNoInt + + DB 1 + DW 2200h ; Alt 'G' + DD DWord Ptr I_ReverseSample + + DB 1 + DW 2300h ; Alt 'H' + DD DWord Ptr I_CenterSample + + DB 1 + DW 1700h ; Alt 'I' + DD DWord Ptr I_InvertSample + + DB 1 ; Alt 'J' + DW 2400h + DD DWord Ptr I_ScaleSampleVolumes + + DB 1 + DW 2600h ; Alt 'L' + DD DWord Ptr I_CutSample + + DB 1 + DW 3200h ; Alt 'M' + DD DWord Ptr I_AmplifySample + + DB 1 + DW 3100h ; Alt 'N' + DD DWord Ptr I_ToggleMultiChannel + + DB 1 + DW 1800h ; Alt 'O' + DD DWord Ptr D_SaveSample + + DB 1 + DW 1000h ; Alt 'Q' + DD DWord Ptr I_ToggleSampleQuality + + DB 1 + DW 1300h ; Alt 'R' + DD DWord Ptr I_ReplaceSample + + DB 1 + DW 1F00h ; Alt 'S' + DD DWord Ptr I_SwapSamples + + DB 1 + DW 1400h ; Alt 'T' + DD DWord Ptr D_SaveST3Sample + + DB 1 + DW 1100h ; Alt 'W' + DD DWord Ptr D_SaveRawSample + + DB 1 + DW 2D00h ; Alt 'X' + DD DWord Ptr I_ExchangeSamples + + DB 1 ; Alt 'Y' + DW 1500h + DD DWord Ptr I_CalculateC5Speed + + + DB 2 ; Alt... + DW 14Eh ; Grey plus + DD DWord Ptr I_DoubleSampleSpeed + + DB 2 ; Alt... + DW 14Ah ; Grey minus + DD DWord Ptr I_HalveSampleSpeed + + DB 3 + DW 14Eh + DD DWord Ptr I_SampleSpeedSemiUp + + DB 3 + DW 14Ah + DD DWord Ptr I_SampleSpeedSemiDown + + DB 9 + DW 9000h + DD DWord Ptr MIDI_PlaySample + + DB 0 ; Enter... to load sample! + DW 11Ch + DD DWord Ptr Glbl_LoadSample + + DB 5 + DW Offset GlobalKeyList + +ScreenBox DW 0 ; Object type 0 + DB 0, 0, 79, 49 ; Coordinates + DB 7 ; Box style + +AboutBox DW 0 ; Object type 0 + DB 11, 16, 68, 34 ; Coordinates + DB 0 ; Box style + +AboutText DW 1 ; Object type 1 + DB 24, 19 + DB 02Bh + DB 0FFh, 1, 0, 4, 8, 0FFh, 8, 55, 37, 41, 0FFh, 5, 55, 56, 58, 62, 66, 0FFh, 6, 55, 88, 92, 13 + DB 1, 5, 9, 12, 15, 18, 22, 25, 28, 31, 34, 38, 42, 45, 48, 51, 55, 55, 57, 59, 63, 67, 70, 73, 76, 79, 82, 85, 89, 93, 96, 99, 102, 105, 13 + DB 2, 6, 0FFh, 1, 10, 0FFh, 1, 13, 16, 19, 23, 26, 29, 32, 35, 39, 43, 46, 49, 52, 54, 55, 55, 60, 64, 68, 71, 74, 77, 80, 83, 86, 90, 94, 97, 100, 103, 106, 13 + DB 3, 7, 11, 14, 17, 20, 24, 27, 30, 33, 36, 40, 44, 47, 50, 53, 55, 55, 55, 61, 65, 69, 72, 75, 78, 81, 84, 87, 91, 95, 98, 101, 104, 107, 13 + DB 0FFh, 5, 55, 21, 0 +; DB 0FEh, 20h +; DB " http://www.citenet.net/noise/it", 0 + +AutoContinueButton DW 2 ; Object type 2 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 ; Button usage type + DW 0, 0 ; ???? + DW 4 ; New List + DD DWord Ptr Glbl_F9 + DW 0, 0, 0 ; ???? + DB 32, 31, 47, 33 ; Left/Top/Right/Bottom + DB 8 ; Box initial style + DB 0 ; Button Up + DB " Continue", 0 + +UpdateScreen DW 8 + DD DWord Ptr S_UpdateScreen + +Exit DW 4 ; Object type 4 + DW 0 ; Return value + +DirectScreen DW 5 ; Object type 5 + DB 1 + +InDirectScreen DW 5 ; Object type 5 + DB 0 + +ImpulseLogo DW 6 ; Object type 6 +LogoCharacter DW 256 ; First char to define + DW 108 + DB 0, 0, 0, 0, 1, 7, 15, 31 ; 0 + DB 63, 127, 127, 254, 252, 255, 255, 126 ; 1 + DB 24, 0, 0, 0, 0, 0, 0, 0 ; 2 + DB 0, 1, 3, 3, 3, 1, 0, 0 ; 3 + DB 7, 31, 63, 255, 255, 254, 248, 240 ; 4 + DB 192, 128, 0, 1, 1, 131, 3, 7 ; 5 + DB 7, 15, 14, 30, 60, 60, 120, 240 ; 6 + DB 240, 224, 224, 224, 224, 192, 0, 0 ; 7 + DB 240, 240, 248, 248, 248, 120, 56, 120 ; 8 + DB 112, 240, 240, 224, 224, 192, 192, 131 ; 9 + DB 7, 15, 31, 31, 62, 60, 61, 63 ; 10 + DB 63, 63, 62, 28, 8, 0, 0, 0 ; 11 + DB 0, 0, 0, 0, 0, 0, 193, 227 ; 12 + DB 199, 223, 191, 127, 247, 239, 207, 159 ; 13 + DB 31, 31, 63, 60, 24, 0, 0, 0 ; 14 + DB 0, 0, 0, 0, 0, 240, 240, 240 ; 15 + DB 241, 227, 239, 223, 191, 251, 247, 231 ; 16 + DB 159, 159, 31, 31, 14, 0, 0, 0 ; 17 + DB 0, 0, 0, 0, 0, 48, 112, 248 ; 18 + DB 248, 240, 224, 192, 193, 131, 7, 30 ; 19 + DB 252, 240, 225, 131, 3, 7, 7, 15 ; 20 + DB 15, 30, 30, 28, 8, 0, 0, 0 ; 21 + DB 0, 0, 0, 1, 3, 3, 7, 15 ; 22 + DB 31, 63, 127, 255, 191, 190, 124, 126 ; 23 + DB 255, 255, 255, 255, 199, 128, 128, 0 ; 24 + DB 60, 124, 248, 240, 224, 192, 135, 159 ; 25 + DB 127, 255, 223, 143, 30, 60, 56, 113 ; 26 + DB 255, 255, 252, 240, 192, 0, 0, 0 ; 27 + DB 0, 0, 0, 0, 0, 0, 128, 129 ; 28 + DB 131, 135, 15, 15, 30, 60, 124, 253 ; 29 + DB 191, 31, 31, 14, 0, 0, 0, 0 ; 30 + DB 0, 0, 0, 0, 0, 112, 248, 240 ; 31 + DB 225, 195, 135, 15, 31, 63, 127, 255 ; 32 + DB 239, 223, 159, 15, 14, 0, 0, 0 ; 33 + DB 0, 0, 0, 0, 24, 56, 124, 248 ; 34 + DB 248, 241, 225, 193, 129, 131, 15, 31 ; 35 + DB 249, 241, 225, 192, 0, 0, 0, 0 ; 36 + DB 0, 0, 0, 0, 0, 0, 1, 3 ; 37 + DB 7, 15, 30, 61, 57, 123, 119, 254 ; 38 + DB 252, 248, 240, 224, 192, 192, 192, 225 ; 39 + DB 247, 255, 254, 252, 0, 0, 0, 0 ; 40 + DB 0, 0, 24, 56, 120, 248, 248, 240 ; 41 + DB 112, 96, 224, 192, 192, 128, 0, 1 ; 42 + DB 3, 7, 14, 28, 56, 112, 248, 252 ; 43 + DB 255, 127, 63, 31, 7, 0, 0, 0 ; 44 + DB 0, 0, 0, 48, 120, 120, 248, 248 ; 45 + DB 252, 124, 124, 120, 120, 112, 241, 231 ; 46 + DB 142, 252, 248, 224, 128, 0, 0, 0 ; 47 + DB 0, 0, 0, 0, 0, 0, 3, 7 ; 48 + DB 15, 30, 60, 63, 127, 254, 252, 60 ; 49 + DB 126, 63, 63, 31, 6, 0, 0, 0 ; 50 + DB 0, 0, 0, 0, 60, 254, 254, 222 ; 51 + DB 30, 60, 248, 224, 128, 1, 7, 14 ; 52 + DB 124, 248, 224, 192, 0, 0, 0, 0 ; 53 + DB 0, 0, 0, 0, 128, 128, 0, 0 ; 54 + DB 0, 0, 0, 0, 0, 0, 0, 0 ; 55 + DB 0, 0, 7, 31, 63, 127, 127, 255 ; 56 + DB 255, 252, 127, 0, 0, 0, 0, 0 ; 57 + DB 3, 255, 255, 255, 255, 255, 255, 252 ; 58 + DB 128, 0, 0, 0, 0, 0, 0, 0 ; 59 + DB 0, 0, 0, 1, 1, 3, 3, 7 ; 60 + DB 7, 15, 31, 31, 31, 30, 0, 0 ; 61 + DB 255, 255, 255, 255, 255, 255, 255, 0 ; 62 + DB 0, 1, 3, 7, 7, 15, 31, 62 ; 63 + DB 60, 124, 248, 248, 240, 240, 224, 224 ; 64 + DB 192, 192, 128, 128, 0, 0, 0, 0 ; 65 + DB 128, 224, 240, 240, 248, 248, 248, 112 ; 66 + DB 240, 224, 192, 192, 128, 6, 15, 31 ; 67 + DB 63, 127, 127, 112, 33, 97, 195, 131 ; 68 + DB 7, 7, 7, 3, 1, 0, 0, 0 ; 69 + DB 0, 0, 0, 0, 0, 0, 252, 254 ; 70 + DB 254, 252, 248, 240, 224, 193, 195, 199 ; 71 + DB 223, 253, 240, 224, 128, 0, 0, 0 ; 72 + DB 0, 0, 0, 0, 0, 0, 0, 3 ; 73 + DB 15, 31, 63, 124, 248, 240, 225, 195 ; 74 + DB 199, 254, 252, 120, 48, 0, 0, 0 ; 75 + DB 0, 0, 0, 0, 0, 31, 255, 255 ; 76 + DB 255, 255, 191, 63, 126, 252, 248, 184 ; 77 + DB 63, 127, 127, 126, 124, 48, 0, 0 ; 78 + DB 0, 0, 0, 0, 0, 0, 128, 128 ; 79 + DB 129, 3, 7, 15, 15, 31, 62, 126 ; 80 + DB 239, 207, 143, 7, 3, 0, 0, 0 ; 81 + DB 0, 0, 0, 0, 0, 15, 63, 255 ; 82 + DB 255, 255, 238, 204, 0, 0, 0, 3 ; 83 + DB 15, 255, 254, 248, 224, 0, 0, 0 ; 84 + DB 0, 0, 0, 0, 0, 193, 195, 131 ; 85 + DB 135, 15, 15, 31, 63, 127, 255, 255 ; 86 + DB 190, 60, 28, 24, 0, 0, 0, 0 ; 87 + DB 0, 0, 0, 0, 0, 1, 3, 7 ; 88 + DB 15, 31, 63, 126, 252, 248, 240, 227 ; 89 + DB 199, 223, 188, 112, 225, 199, 254, 252 ; 90 + DB 252, 126, 127, 63, 31, 0, 0, 0 ; 91 + DB 0, 12, 60, 124, 248, 248, 240, 224 ; 92 + DB 192, 128, 0, 0, 0, 48, 248, 248 ; 93 + DB 248, 120, 241, 225, 195, 3, 15, 31 ; 94 + DB 59, 243, 227, 129, 0, 0, 0, 0 ; 95 + DB 0, 0, 0, 0, 1, 15, 31, 62 ; 96 + DB 120, 241, 231, 239, 252, 240, 192, 192 ; 97 + DB 227, 255, 255, 252, 112, 0, 0, 0 ; 98 + DB 0, 0, 0, 0, 192, 240, 241, 243 ; 99 + DB 231, 207, 143, 14, 12, 28, 56, 112 ; 100 + DB 225, 193, 1, 0, 0, 0, 0, 0 ; 101 + DB 0, 0, 0, 0, 0, 192, 255, 255 ; 102 + DB 255, 255, 254, 60, 120, 112, 240, 241 ; 103 + DB 247, 255, 252, 248, 96, 0, 0, 0 ; 104 + DB 0, 0, 0, 0, 0, 0, 0, 128 ; 105 + DB 128, 0, 0, 0, 0, 0, 0, 192 ; 106 + DB 192, 0, 0, 0, 0, 0, 0, 0 ; 107 + +O1_ConfirmConvertList DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmConvertSampleText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmConvert2List DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmConvertSampleText + DW Near Ptr ConfirmConvertYesButton + DW Near Ptr ConfirmConvertNoButton + DW 0 + +O1_SampleCenterList DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmCenterSampleText + DW Near Ptr ConfirmConvertYesButton + DW Near Ptr ConfirmConvertNoButton + DW 0 + +O1_EnableInstrumentMode DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr EnableInstrumentModeText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + + +O1_InitInstrument DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr InitInstrumentText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmInitialiseNoButton + DW 0 + +O1_ConfirmOverWriteList DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmOverWriteText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_InitialiseInstrumentList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmInitialiseText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmInitialiseNoButton + DW 0 + +O1_ConfirmDelete DW 4 + DW Near Ptr SongNameModuleLoader + DW Near Ptr OKCancelList + DW Near Ptr DrawFileNameWindow + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmDeleteText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmDelete2 DW 4 + DW Near Ptr SampleNameLoader + DW Near Ptr OKCancelList + DW Near Ptr DrawLoadSampleWindow + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmDeleteText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmDelete3 DW 4 + DW Near Ptr InstrumentNameLoader + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmDeleteText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + + +O1_ConfirmSaveRenameList DW 3 + DW Near Ptr SampleNameLoader + DW Near Ptr OKCancelList + DW Near Ptr DrawLoadSampleWindow + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmSaveRenameText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmResaveList DW 3 + DW Near Ptr SampleNameLoader + DW Near Ptr OKCancelList + DW Near Ptr DrawLoadSampleWindow + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmResaveText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmDiscardList DW 3 + DW Near Ptr SampleNameLoader + DW Near Ptr OKCancelList + DW Near Ptr DrawLoadSampleWindow + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmDiscardText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmCutSample DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmCutSampleText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmDeleteSample DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmDeleteSampleText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmDeleteInstrument DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmDeleteInstrumentText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmClearMessage DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmClearMessageText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_ConfirmNoSave DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmNoSaveBox + DW Near Ptr ConfirmNoSaveMessage + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +EmptyObject DW 8 + DD DWord Ptr F_Nothing + +DrawFileNameWindow DW 8 + DD DWord Ptr D_DrawFileWindow + +DrawLoadSampleWindow DW 8 + DD DWord Ptr D_DrawLoadSampleWindow + +DrawLoadInstrumentWindow DW 8 + DD DWord Ptr D_DrawLoadInstrument + +ConfirmOverWriteBox DW 0 ; Box Object + DB 26, 25, 54, 32 + DB 3 + +ConfirmNosaveBox DW 0 ; Box Object + DB 20, 25, 60, 32 + DB 3 + +EnableInstrumentModeText DW 1 + DB 29, 27 + DB 20h + DB "Enable Instrument mode?", 0 + +ConfirmCenterSampleText DW 1 + DB 31, 27 + DB 20h + DB "Centralise sample?", 0 + +ConfirmOverWriteText DW 1 + DB 33, 27 + DB 20h + DB "Overwrite file?", 0 + +ConfirmDeleteText DW 1 + DB 35, 27 + DB 20h + DB "Delete file?", 0 + +ConfirmDeleteSampleText DW 1 + DB 34, 27 + DB 20h + DB "Delete sample?", 0 + +ConfirmDeleteInstrumentText DW 1 + DB 32, 27 + DB 20h + DB "Delete instrument?", 0 + +ConfirmClearMessageText DW 1 + DB 31, 27 + DB 20h + DB "Clear song message?", 0 + +ConfirmNoSaveMessage DW 1 + DB 23, 27 + DB 20h + DB "Current module not saved. Proceed?", 0 + +ConfirmSaveRenameText DW 1 + DB 31, 27 + DB 20h + DB "Save/Rename sample?", 0 + +ConfirmDiscardText DW 1 + DB 33, 27 + DB 20h + DB "Discard changes?", 0 + +ConfirmResaveText DW 1 + DB 35, 27 + DB 20h + DB "Save sample?", 0 + +InitInstrumentText DW 1 + DB 29, 27 + DB 20h + DB "Create host instrument?", 0 + +ConfirmConvertSampleText DW 1 + DB 33, 27 + DB 20h + DB "Convert sample?", 0 + +ConfirmInitialiseText DW 1 + DB 29, 27 + DB 20h + DB "Initialise instruments?", 0 + +ConfirmCutSampleText DW 1 + DB 35, 27 + DB 20h + DB "Cut sample?", 0 + +ConfirmQuitText DW 1 + DB 30, 27 + DB 20h + DB "Exit Impulse Tracker?", 0 + +ConfirmOverWriteOKButton DW 2 + DW 0FFFFh, 0FFFFh, 4, 4 + DW 0 + DW 0, 0 + DW 0 + DW 1 ; Return OK to overwrite + DW 0, 0, 0, 0 + DB 30, 29, 39, 31 + DB 8 + DB 0 + DB " OK", 0 + +ConfirmOverWriteCancelButton DW 2 + DW 0FFFFh, 0FFFFh, 3, 3 + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 41, 29, 50, 31 + DB 8 + DB 0 + DB " Cancel", 0 + +ConfirmConvertYesButton DW 2 + DW 0FFFFh, 0FFFFh, 4, 4 + DW 0 + DW 0, 0 + DW 0 + DW 1 ; Return 1 + DW 0, 0, 0, 0 + DB 29, 29, 39, 31 + DB 8 + DB 0 + DB " Yes", 0 + +ConfirmConvertNoButton DW 2 + DW 0FFFFh, 0FFFFh, 3, 3 + DW 0 + DW 0, 0 + DW 0 + DW 2 ; Returns 2 + DW 0, 0, 0, 0 + DB 41, 29, 50, 31 + DB 8 + DB 0 + DB " No", 0 + +ConfirmInitialiseNoButton DW 2 + DW 0FFFFh, 0FFFFh, 3, 3 + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 41, 29, 50, 31 + DB 8 + DB 0 + DB " No", 0 + +O1_UnableToSaveList DW 2 + DW 0 + DW Near Ptr ESCReturnList + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr UnableToSaveText + DW Near Ptr NoSaveOKButton + DW 0 + +UnableToSaveText DW 1 + DB 31, 27 + DB 20h + DB "Unable to save file", 0 + +NoSaveOKButton DW 2 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 1 + DW 0, 0, 0, 0 + DB 36, 29, 45, 31 + DB 8 + DB 0 + DB " OK", 0 + +O1_ConfirmQuit DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr EmptyObject + DW Near Ptr ConfirmOverWriteBox + DW Near Ptr ConfirmQuitText + DW Near Ptr ConfirmOverWriteOKButton + DW Near Ptr ConfirmOverWriteCancelButton + DW 0 + +O1_SelectMultiChannel DW 7 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr SMCBox ; 0 + DW Near Ptr SMCText ; 1 + DW Near Ptr SMCInBox1 ; 2 + DW Near Ptr SMCInBox2 ; 3 + DW Near Ptr SMCInBox3 ; 4 + DW Near Ptr SMCInBox4 ; 5 + DW Near Ptr SMCDrawChannel ; 6 + DW Near Ptr SMCChannel00Toggle ; 7 + DW Near Ptr SMCChannel01Toggle + DW Near Ptr SMCChannel02Toggle + DW Near Ptr SMCChannel03Toggle + DW Near Ptr SMCChannel04Toggle + DW Near Ptr SMCChannel05Toggle + DW Near Ptr SMCChannel06Toggle + DW Near Ptr SMCChannel07Toggle + DW Near Ptr SMCChannel08Toggle + DW Near Ptr SMCChannel09Toggle + DW Near Ptr SMCChannel10Toggle + DW Near Ptr SMCChannel11Toggle + DW Near Ptr SMCChannel12Toggle + DW Near Ptr SMCChannel13Toggle + DW Near Ptr SMCChannel14Toggle + DW Near Ptr SMCChannel15Toggle + DW Near Ptr SMCChannel16Toggle + DW Near Ptr SMCChannel17Toggle + DW Near Ptr SMCChannel18Toggle + DW Near Ptr SMCChannel19Toggle + DW Near Ptr SMCChannel20Toggle + DW Near Ptr SMCChannel21Toggle + DW Near Ptr SMCChannel22Toggle + DW Near Ptr SMCChannel23Toggle + DW Near Ptr SMCChannel24Toggle + DW Near Ptr SMCChannel25Toggle + DW Near Ptr SMCChannel26Toggle + DW Near Ptr SMCChannel27Toggle + DW Near Ptr SMCChannel28Toggle + DW Near Ptr SMCChannel29Toggle + DW Near Ptr SMCChannel30Toggle + DW Near Ptr SMCChannel31Toggle + DW Near Ptr SMCChannel32Toggle + DW Near Ptr SMCChannel33Toggle + DW Near Ptr SMCChannel34Toggle + DW Near Ptr SMCChannel35Toggle + DW Near Ptr SMCChannel36Toggle + DW Near Ptr SMCChannel37Toggle + DW Near Ptr SMCChannel38Toggle + DW Near Ptr SMCChannel39Toggle + DW Near Ptr SMCChannel40Toggle + DW Near Ptr SMCChannel41Toggle + DW Near Ptr SMCChannel42Toggle + DW Near Ptr SMCChannel43Toggle + DW Near Ptr SMCChannel44Toggle + DW Near Ptr SMCChannel45Toggle + DW Near Ptr SMCChannel46Toggle + DW Near Ptr SMCChannel47Toggle + DW Near Ptr SMCChannel48Toggle + DW Near Ptr SMCChannel49Toggle + DW Near Ptr SMCChannel50Toggle + DW Near Ptr SMCChannel51Toggle + DW Near Ptr SMCChannel52Toggle + DW Near Ptr SMCChannel53Toggle + DW Near Ptr SMCChannel54Toggle + DW Near Ptr SMCChannel55Toggle + DW Near Ptr SMCChannel56Toggle + DW Near Ptr SMCChannel57Toggle + DW Near Ptr SMCChannel58Toggle + DW Near Ptr SMCChannel59Toggle + DW Near Ptr SMCChannel60Toggle + DW Near Ptr SMCChannel61Toggle + DW Near Ptr SMCChannel62Toggle + DW Near Ptr SMCChannel63Toggle ; 70 + DW Near Ptr SMCOKButton ; 71 + DW 0 + +SMCBox DW 0 + DB 7, 18, 72, 42 + DB 3 + +SMCInBox1 DW 0 + DB 19, 21, 23, 38 + DB 27 + +SMCInBox2 DW 0 + DB 35, 21, 39, 38 + DB 27 + +SMCInBox3 DW 0 + DB 51, 21, 55, 38 + DB 27 + +SMCInBox4 DW 0 + DB 67, 21, 71, 38 + DB 27 + +SMCText DW 1 + DB 29, 19 + DB 23h + DB "Multichannel Selection", 0 + +SMCDrawChannel DW 8 + DD DWord Ptr F_DrawSMCChannels + +SMCChannel00Toggle DW 17 + DB 20, 22 + DW 1 + DW Offset MultiChannelInfo+00 + DB 1 + DW 71, 8, 23, 55 + +SMCChannel01Toggle DW 17 + DB 20, 23 + DW 1 + DW Offset MultiChannelInfo+01 + DB 1 + DW 7, 9, 24, 56 + +SMCChannel02Toggle DW 17 + DB 20, 24 + DW 1 + DW Offset MultiChannelInfo+02 + DB 1 + DW 8, 10, 25, 57 + +SMCChannel03Toggle DW 17 + DB 20, 25 + DW 1 + DW Offset MultiChannelInfo+03 + DB 1 + DW 9, 11, 26, 58 + +SMCChannel04Toggle DW 17 + DB 20, 26 + DW 1 + DW Offset MultiChannelInfo+04 + DB 1 + DW 10, 12, 27, 59 + +SMCChannel05Toggle DW 17 + DB 20, 27 + DW 1 + DW Offset MultiChannelInfo+05 + DB 1 + DW 11, 13, 28, 60 + +SMCChannel06Toggle DW 17 + DB 20, 28 + DW 1 + DW Offset MultiChannelInfo+06 + DB 1 + DW 12, 14, 29, 61 + +SMCChannel07Toggle DW 17 + DB 20, 29 + DW 1 + DW Offset MultiChannelInfo+07 + DB 1 + DW 13, 15, 30, 62 + +SMCChannel08Toggle DW 17 + DB 20, 30 + DW 1 + DW Offset MultiChannelInfo+08 + DB 1 + DW 14, 16, 31, 63 + +SMCChannel09Toggle DW 17 + DB 20, 31 + DW 1 + DW Offset MultiChannelInfo+09 + DB 1 + DW 15, 17, 32, 64 + +SMCChannel10Toggle DW 17 + DB 20, 32 + DW 1 + DW Offset MultiChannelInfo+10 + DB 1 + DW 16, 18, 33, 65 + +SMCChannel11Toggle DW 17 + DB 20, 33 + DW 1 + DW Offset MultiChannelInfo+11 + DB 1 + DW 17, 19, 34, 66 + +SMCChannel12Toggle DW 17 + DB 20, 34 + DW 1 + DW Offset MultiChannelInfo+12 + DB 1 + DW 18, 20, 35, 67 + +SMCChannel13Toggle DW 17 + DB 20, 35 + DW 1 + DW Offset MultiChannelInfo+13 + DB 1 + DW 19, 21, 36, 68 + +SMCChannel14Toggle DW 17 + DB 20, 36 + DW 1 + DW Offset MultiChannelInfo+14 + DB 1 + DW 20, 22, 37, 69 + +SMCChannel15Toggle DW 17 + DB 20, 37 + DW 1 + DW Offset MultiChannelInfo+15 + DB 1 + DW 21, 71, 38, 70 + +SMCChannel16Toggle DW 17 + DB 36, 22 + DW 1 + DW Offset MultiChannelInfo+16 + DB 1 + DW 71, 24, 39, 7 + +SMCChannel17Toggle DW 17 + DB 36, 23 + DW 1 + DW Offset MultiChannelInfo+17 + DB 1 + DW 23, 25, 40, 8 + +SMCChannel18Toggle DW 17 + DB 36, 24 + DW 1 + DW Offset MultiChannelInfo+18 + DB 1 + DW 24, 26, 41, 9 + +SMCChannel19Toggle DW 17 + DB 36, 25 + DW 1 + DW Offset MultiChannelInfo+19 + DB 1 + DW 25, 27, 42, 10 + +SMCChannel20Toggle DW 17 + DB 36, 26 + DW 1 + DW Offset MultiChannelInfo+20 + DB 1 + DW 26, 28, 43, 11 + +SMCChannel21Toggle DW 17 + DB 36, 27 + DW 1 + DW Offset MultiChannelInfo+21 + DB 1 + DW 27, 29, 44, 12 + +SMCChannel22Toggle DW 17 + DB 36, 28 + DW 1 + DW Offset MultiChannelInfo+22 + DB 1 + DW 28, 30, 45, 13 + +SMCChannel23Toggle DW 17 + DB 36, 29 + DW 1 + DW Offset MultiChannelInfo+23 + DB 1 + DW 29, 31, 46, 14 + +SMCChannel24Toggle DW 17 + DB 36, 30 + DW 1 + DW Offset MultiChannelInfo+24 + DB 1 + DW 30, 32, 47, 15 + +SMCChannel25Toggle DW 17 + DB 36, 31 + DW 1 + DW Offset MultiChannelInfo+25 + DB 1 + DW 31, 33, 48, 16 + +SMCChannel26Toggle DW 17 + DB 36, 32 + DW 1 + DW Offset MultiChannelInfo+26 + DB 1 + DW 32, 34, 49, 17 + +SMCChannel27Toggle DW 17 + DB 36, 33 + DW 1 + DW Offset MultiChannelInfo+27 + DB 1 + DW 33, 35, 50, 18 + +SMCChannel28Toggle DW 17 + DB 36, 34 + DW 1 + DW Offset MultiChannelInfo+28 + DB 1 + DW 34, 36, 51, 19 + +SMCChannel29Toggle DW 17 + DB 36, 35 + DW 1 + DW Offset MultiChannelInfo+29 + DB 1 + DW 35, 37, 52, 20 + +SMCChannel30Toggle DW 17 + DB 36, 36 + DW 1 + DW Offset MultiChannelInfo+30 + DB 1 + DW 36, 38, 53, 21 + +SMCChannel31Toggle DW 17 + DB 36, 37 + DW 1 + DW Offset MultiChannelInfo+31 + DB 1 + DW 37, 71, 54, 22 + +SMCChannel32Toggle DW 17 + DB 52, 22 + DW 1 + DW Offset MultiChannelInfo+32 + DB 1 + DW 71, 40, 55, 23 + +SMCChannel33Toggle DW 17 + DB 52, 23 + DW 1 + DW Offset MultiChannelInfo+33 + DB 1 + DW 39, 41, 56, 24 + +SMCChannel34Toggle DW 17 + DB 52, 24 + DW 1 + DW Offset MultiChannelInfo+34 + DB 1 + DW 40, 42, 57, 25 + +SMCChannel35Toggle DW 17 + DB 52, 25 + DW 1 + DW Offset MultiChannelInfo+35 + DB 1 + DW 41, 43, 58, 26 + +SMCChannel36Toggle DW 17 + DB 52, 26 + DW 1 + DW Offset MultiChannelInfo+36 + DB 1 + DW 42, 44, 59, 27 + +SMCChannel37Toggle DW 17 + DB 52, 27 + DW 1 + DW Offset MultiChannelInfo+37 + DB 1 + DW 43, 45, 60, 28 + +SMCChannel38Toggle DW 17 + DB 52, 28 + DW 1 + DW Offset MultiChannelInfo+38 + DB 1 + DW 44, 46, 61, 29 + +SMCChannel39Toggle DW 17 + DB 52, 29 + DW 1 + DW Offset MultiChannelInfo+39 + DB 1 + DW 45, 47, 62, 30 + +SMCChannel40Toggle DW 17 + DB 52, 30 + DW 1 + DW Offset MultiChannelInfo+40 + DB 1 + DW 46, 48, 63, 31 + +SMCChannel41Toggle DW 17 + DB 52, 31 + DW 1 + DW Offset MultiChannelInfo+41 + DB 1 + DW 47, 49, 64, 32 + +SMCChannel42Toggle DW 17 + DB 52, 32 + DW 1 + DW Offset MultiChannelInfo+42 + DB 1 + DW 48, 50, 65, 33 + +SMCChannel43Toggle DW 17 + DB 52, 33 + DW 1 + DW Offset MultiChannelInfo+43 + DB 1 + DW 49, 51, 66, 34 + +SMCChannel44Toggle DW 17 + DB 52, 34 + DW 1 + DW Offset MultiChannelInfo+44 + DB 1 + DW 50, 52, 67, 35 + +SMCChannel45Toggle DW 17 + DB 52, 35 + DW 1 + DW Offset MultiChannelInfo+45 + DB 1 + DW 51, 53, 68, 36 + +SMCChannel46Toggle DW 17 + DB 52, 36 + DW 1 + DW Offset MultiChannelInfo+46 + DB 1 + DW 52, 54, 69, 37 + +SMCChannel47Toggle DW 17 + DB 52, 37 + DW 1 + DW Offset MultiChannelInfo+47 + DB 1 + DW 53, 71, 70, 38 + +SMCChannel48Toggle DW 17 + DB 68, 22 + DW 1 + DW Offset MultiChannelInfo+48 + DB 1 + DW 71, 56, 7, 39 + +SMCChannel49Toggle DW 17 + DB 68, 23 + DW 1 + DW Offset MultiChannelInfo+49 + DB 1 + DW 55, 57, 8, 40 + +SMCChannel50Toggle DW 17 + DB 68, 24 + DW 1 + DW Offset MultiChannelInfo+50 + DB 1 + DW 56, 58, 9, 41 + +SMCChannel51Toggle DW 17 + DB 68, 25 + DW 1 + DW Offset MultiChannelInfo+51 + DB 1 + DW 57, 59, 10, 42 + +SMCChannel52Toggle DW 17 + DB 68, 26 + DW 1 + DW Offset MultiChannelInfo+52 + DB 1 + DW 58, 60, 11, 43 + +SMCChannel53Toggle DW 17 + DB 68, 27 + DW 1 + DW Offset MultiChannelInfo+53 + DB 1 + DW 59, 61, 12, 44 + +SMCChannel54Toggle DW 17 + DB 68, 28 + DW 1 + DW Offset MultiChannelInfo+54 + DB 1 + DW 60, 62, 13, 45 + +SMCChannel55Toggle DW 17 + DB 68, 29 + DW 1 + DW Offset MultiChannelInfo+55 + DB 1 + DW 61, 63, 14, 46 + +SMCChannel56Toggle DW 17 + DB 68, 30 + DW 1 + DW Offset MultiChannelInfo+56 + DB 1 + DW 62, 64, 15, 47 + +SMCChannel57Toggle DW 17 + DB 68, 31 + DW 1 + DW Offset MultiChannelInfo+57 + DB 1 + DW 63, 65, 16, 48 + +SMCChannel58Toggle DW 17 + DB 68, 32 + DW 1 + DW Offset MultiChannelInfo+58 + DB 1 + DW 64, 66, 17, 49 + +SMCChannel59Toggle DW 17 + DB 68, 33 + DW 1 + DW Offset MultiChannelInfo+59 + DB 1 + DW 65, 67, 18, 50 + +SMCChannel60Toggle DW 17 + DB 68, 34 + DW 1 + DW Offset MultiChannelInfo+60 + DB 1 + DW 66, 68, 19, 51 + +SMCChannel61Toggle DW 17 + DB 68, 35 + DW 1 + DW Offset MultiChannelInfo+61 + DB 1 + DW 67, 69, 20, 52 + +SMCChannel62Toggle DW 17 + DB 68, 36 + DW 1 + DW Offset MultiChannelInfo+62 + DB 1 + DW 68, 70, 21, 53 + +SMCChannel63Toggle DW 17 + DB 68, 37 + DW 1 + DW Offset MultiChannelInfo+63 + DB 1 + DW 69, 71, 22, 54 + +SMCOKButton DW 2 + DW 22, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 0 + DW 0, 0, 0, 0 + DB 35, 39, 44, 41 + DB 8 + DB 0 + DB " OK ", 0 + +O1_ExchangeSampleList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr ExchangeSampleBox + DW Near Ptr ExchangeSampleText + DW Near Ptr ExchangeSampleInputBox + DW Near Ptr ExchangeSampleInput ; 3 + DW Near Ptr CancelExchangeButton ; 4 + DW 0 + +O1_ReplaceSampleList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr ExchangeSampleBox + DW Near Ptr ReplaceSampleText + DW Near Ptr ExchangeSampleInputBox + DW Near Ptr ExchangeSampleInput ; 3 + DW Near Ptr CancelExchangeButton ; 4 + DW 0 + +O1_ReplaceInstrumentList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr ExchangeSampleBox + DW Near Ptr ReplaceInstrumentText + DW Near Ptr ExchangeSampleInputBox + DW Near Ptr ExchangeSampleInput ; 3 + DW Near Ptr CancelExchangeButton ; 4 + DW 0 + +O1_SwapSampleList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr ExchangeSampleBox + DW Near Ptr SwapSampleText + DW Near Ptr ExchangeSampleInputBox + DW Near Ptr ExchangeSampleInput ; 3 + DW Near Ptr CancelExchangeButton ; 4 + DW 0 + +O1_SwapInstrumentList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr ExchangeSampleBox + DW Near Ptr SwapInstrumentText + DW Near Ptr ExchangeSampleInputBox + DW Near Ptr ExchangeSampleInput ; 3 + DW Near Ptr CancelExchangeButton ; 4 + DW 0 + +O1_CopyInstrumentList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr ExchangeSampleBox + DW Near Ptr CopyInstrumentText + DW Near Ptr ExchangeSampleInputBox + DW Near Ptr ExchangeSampleInput ; 3 + DW Near Ptr CancelExchangeButton ; 4 + DW 0 + +O1_ExchangeInstrumentList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr OKCancelList + DW Near Ptr ExchangeSampleBox + DW Near Ptr ExchangeInstrumentText + DW Near Ptr ExchangeSampleInputBox + DW Near Ptr ExchangeSampleInput ; 3 + DW Near Ptr CancelExchangeButton ; 4 + DW 0 + +O1_ResizeSampleList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr ESC&ReturnList + DW Near Ptr ResizeSampleBox ; 0 + DW Near Ptr ResizeSampleText ; 1 + DW Near Ptr ResizeSampleInputBox ; 2 + DW Near Ptr ResizeSampleInput ; 3 + DW Near Ptr CancelExchangeButton + DW 0 + +ESCF2&ReturnList DB 0 + DW 13Ch + DD DWord Ptr F_Return0 + +ESC&ReturnList DB 0 + DW 101h + DD DWord Ptr F_Return0 + + DB 0 + DW 11Ch + DD DWord Ptr F_Return1 + + DB 5 + DW Near Ptr ChainMIDICommands + +ExchangeSampleBox DW 0 + DB 26, 23, 54, 32 + DB 3 + +ExchangeSampleText DW 1 + DB 30, 25 + DB 20h + DB "Exchange sample with:", 13 + DB 13 + DB 0FFh, 5, " Sample", 0 + +ResizeSampleBox DW 0 + DB 26, 22, 54, 32 + DB 3 + +ResizeSampleText DW 1 + DB 31, 24 + DB 23h + DB " Resize Sample", 13, 13 + DB 13, 0FEh, 20h + DB "New Length", 0 + +ResizeSampleInputBox DW 0 + DB 41, 26, 49, 28 + DB 27 + +ResizeSampleInput DW 18 + DB 42, 27 + DW 2 + DW Offset NewSampleSize + DD 0 + DW 0FFFFh, 4, 4, 0FFFFh + +SwapSampleText DW 1 + DB 32, 25 + DB 20h + DB "Swap sample with:", 13 + DB 13 + DB " Sample", 0 + +SwapInstrumentText DW 1 + DB 29, 25 + DB 20h + DB "Swap instrument with:", 13 + DB 13 + DB " Instrument", 0 + +CopyInstrumentText DW 1 + DB 31, 25 + DB 20h + DB " Copy instrument:", 13 + DB 13 + DB "Instrument", 0 + +ReplaceSampleText DW 1 + DB 30, 25 + DB 20h + DB "Replace sample with:", 13 + DB 13 + DB 0FFh, 5, " Sample", 0 + +ReplaceInstrumentText DW 1 + DB 28, 25 + DB 20h + DB "Replace instrument with:", 13 + DB 13 + DB " Instrument", 0 + +ExchangeInstrumentText DW 1 + DB 28, 25 + DB 20h + DB "Exchange instrument with:", 13 + DB 13 + DB " Instrument", 0 + +ExchangeSampleInputBox DW 0 + DB 41, 26, 45, 28 + DB 27 + +ExchangeSampleInput DW 16 + DB 42, 27 + DW 2 + DW Offset SampleNumberInput + DW 3 + DD DWord Ptr F_Return1 + DW 0FFFFh, 4, 4, 0FFFFh + +CancelExchangeButton DW 2 + DW 3, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 35, 29, 44, 31 + DB 8 + DB 0 + DB " Cancel", 0 + + +O1_OrderVolumeList DW 10 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr FillHeader ; 2 + DW Near Ptr OrderandVolumeMsg ; 3 + DW Near Ptr OrderBox ; 4 + DW Near Ptr PanBox1 ; 5 + DW Near Ptr PanBox2 ; 6 + DW Near Ptr ShowChannelMsgs ; 7 + DW Near Ptr VolumeText1 ; 8 + DW Near Ptr VolumeText2 ; 9 + DW Near Ptr OrderList ; 10 + DW Near Ptr ChannelVol1 ; 11 + DW Near Ptr ChannelVol2 ; 12 + DW Near Ptr ChannelVol3 ; 13 + DW Near Ptr ChannelVol4 ; 14 + DW Near Ptr ChannelVol5 ; 15 + DW Near Ptr ChannelVol6 ; 16 + DW Near Ptr ChannelVol7 ; 17 + DW Near Ptr ChannelVol8 ; 18 + DW Near Ptr ChannelVol9 ; 19 + DW Near Ptr ChannelVol10 ; 20 + DW Near Ptr ChannelVol11 ; 21 + DW Near Ptr ChannelVol12 ; 22 + DW Near Ptr ChannelVol13 ; 23 + DW Near Ptr ChannelVol14 ; 24 + DW Near Ptr ChannelVol15 ; 25 + DW Near Ptr ChannelVol16 ; 26 + DW Near Ptr ChannelVol17 + DW Near Ptr ChannelVol18 + DW Near Ptr ChannelVol19 + DW Near Ptr ChannelVol20 + DW Near Ptr ChannelVol21 + DW Near Ptr ChannelVol22 + DW Near Ptr ChannelVol23 + DW Near Ptr ChannelVol24 + DW Near Ptr ChannelVol25 + DW Near Ptr ChannelVol26 + DW Near Ptr ChannelVol27 + DW Near Ptr ChannelVol28 + DW Near Ptr ChannelVol29 + DW Near Ptr ChannelVol30 + DW Near Ptr ChannelVol31 + DW Near Ptr ChannelVol32 + DW Near Ptr ChannelVol33 + DW Near Ptr ChannelVol34 + DW Near Ptr ChannelVol35 + DW Near Ptr ChannelVol36 + DW Near Ptr ChannelVol37 + DW Near Ptr ChannelVol38 + DW Near Ptr ChannelVol39 + DW Near Ptr ChannelVol40 + DW Near Ptr ChannelVol41 + DW Near Ptr ChannelVol42 + DW Near Ptr ChannelVol43 + DW Near Ptr ChannelVol44 + DW Near Ptr ChannelVol45 + DW Near Ptr ChannelVol46 + DW Near Ptr ChannelVol47 + DW Near Ptr ChannelVol48 + DW Near Ptr ChannelVol49 + DW Near Ptr ChannelVol50 + DW Near Ptr ChannelVol51 + DW Near Ptr ChannelVol52 + DW Near Ptr ChannelVol53 + DW Near Ptr ChannelVol54 + DW Near Ptr ChannelVol55 + DW Near Ptr ChannelVol56 + DW Near Ptr ChannelVol57 + DW Near Ptr ChannelVol58 + DW Near Ptr ChannelVol59 + DW Near Ptr ChannelVol60 + DW Near Ptr ChannelVol61 + DW Near Ptr ChannelVol62 + DW Near Ptr ChannelVol63 + DW Near Ptr ChannelVol64 ; 74 + DW Near Ptr SetHelpContext4 + DW 0 + +ChannelVol1 DW 9 ; Object 9 + DB 31, 15 ; x,y + DW 0, 64 ; Ranges + DW 4, 0+64 ; Volume/Channel 1 + DW 11, 12, 43, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 19 ; PgUp/PgDn + +ChannelVol2 DW 9 + DB 31, 16 + DW 0, 64 + DW 4, 1+64 ; Volume/Channel 2 + DW 11, 13, 44, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 20 ; PgUp/PgDn + +ChannelVol3 DW 9 ; Object 9 + DB 31, 17 ; x,y + DW 0, 64 ; Ranges + DW 4, 2+64 ; Volume/Channel 3 + DW 12, 14, 45, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 21 ; PgUp/PgDn + +ChannelVol4 DW 9 + DB 31, 18 + DW 0, 64 + DW 4, 3+64 ; Volume/Channel 4 + DW 13, 15, 46, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 22 ; PgUp/PgDn + +ChannelVol5 DW 9 ; Object 9 + DB 31, 19 ; x,y + DW 0, 64 ; Ranges + DW 4, 4+64 ; Volume/Channel 5 + DW 14, 16, 47, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 23 ; PgUp/PgDn + +ChannelVol6 DW 9 + DB 31, 20 + DW 0, 64 + DW 4, 5+64 ; Volume/Channel 6 + DW 15, 17, 48, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 24 ; PgUp/PgDn + +ChannelVol7 DW 9 ; Object 9 + DB 31, 21 ; x,y + DW 0, 64 ; Ranges + DW 4, 6+64 ; Volume/Channel 7 + DW 16, 18, 49, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 25 ; PgUp/PgDn + +ChannelVol8 DW 9 + DB 31, 22 + DW 0, 64 + DW 4, 7+64 ; Volume/Channel 8 + DW 17, 19, 50, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 26 ; PgUp/PgDn + +ChannelVol9 DW 9 ; Object 9 + DB 31, 23 ; x,y + DW 0, 64 ; Ranges + DW 4, 8+64 ; Volume/Channel 9 + DW 18, 20, 51, 10 ; Up/Down/Tab/Shift-Tab + DW 11, 27 ; PgUp/PgDn + +ChannelVol10 DW 9 + DB 31, 24 + DW 0, 64 + DW 4, 9+64 ; Volume/Channel 10 + DW 19, 21, 52, 10 ; Up/Down/Tab/Shift-Tab + DW 12, 28 ; PgUp/PgDn + +ChannelVol11 DW 9 ; Object 9 + DB 31, 25 ; x,y + DW 0, 64 ; Ranges + DW 4, 10+64 ; Volume/Channel 11 + DW 20, 22, 53, 10 ; Up/Down/Tab/Shift-Tab + DW 13, 29 ; PgUp/PgDn + +ChannelVol12 DW 9 + DB 31, 26 + DW 0, 64 + DW 4, 11+64 ; Volume/Channel 12 + DW 21, 23, 54, 10 ; Up/Down/Tab/Shift-Tab + DW 14, 30 ; PgUp/PgDn + +ChannelVol13 DW 9 ; Object 9 + DB 31, 27 ; x,y + DW 0, 64 ; Ranges + DW 4, 12+64 ; Volume/Channel 13 + DW 22, 24, 55, 10 ; Up/Down/Tab/Shift-Tab + DW 15, 31 ; PgUp/PgDn + +ChannelVol14 DW 9 + DB 31, 28 + DW 0, 64 + DW 4, 13+64 ; Volume/Channel 14 + DW 23, 25, 56, 10 ; Up/Down/Tab/Shift-Tab + DW 16, 32 ; PgUp/PgDn + +ChannelVol15 DW 9 ; Object 9 + DB 31, 29 ; x,y + DW 0, 64 ; Ranges + DW 4, 14+64 ; Volume/Channel 15 + DW 24, 26, 57, 10 ; Up/Down/Tab/Shift-Tab + DW 17, 33 ; PgUp/PgDn + +ChannelVol16 DW 9 + DB 31, 30 + DW 0, 64 + DW 4, 15+64 ; Volume/Channel 16 + DW 25, 27, 58, 10 ; Up/Down/Tab/Shift-Tab + DW 18, 34 ; PgUp/PgDn + +ChannelVol17 DW 9 ; Object 9 + DB 31, 31 ; x,y + DW 0, 64 ; Ranges + DW 4, 16+64 ; Volume/Channel 17 + DW 26, 28, 59, 10 ; Up/Down/Tab/Shift-Tab + DW 19, 35 ; PgUp/PgDn + +ChannelVol18 DW 9 + DB 31, 32 + DW 0, 64 + DW 4, 17+64 ; Volume/Channel 18 + DW 27, 29, 60, 10 ; Up/Down/Tab/Shift-Tab + DW 20, 36 ; PgUp/PgDn + +ChannelVol19 DW 9 ; Object 9 + DB 31, 33 ; x,y + DW 0, 64 ; Ranges + DW 4, 18+64 ; Volume/Channel 19 + DW 28, 30, 61, 10 ; Up/Down/Tab/Shift-Tab + DW 21, 37 ; PgUp/PgDn + +ChannelVol20 DW 9 + DB 31, 34 + DW 0, 64 + DW 4, 19+64 ; Volume/Channel 20 + DW 29, 31, 62, 10 ; Up/Down/Tab/Shift-Tab + DW 22, 38 ; PgUp/PgDn + +ChannelVol21 DW 9 ; Object 9 + DB 31, 35 ; x,y + DW 0, 64 ; Ranges + DW 4, 20+64 ; Volume/Channel 21 + DW 30, 32, 63, 10 ; Up/Down/Tab/Shift-Tab + DW 23, 39 ; PgUp/PgDn + +ChannelVol22 DW 9 + DB 31, 36 + DW 0, 64 + DW 4, 21+64 ; Volume/Channel 22 + DW 31, 33, 64, 10 ; Up/Down/Tab/Shift-Tab + DW 24, 40 ; PgUp/PgDn + +ChannelVol23 DW 9 ; Object 9 + DB 31, 37 ; x,y + DW 0, 64 ; Ranges + DW 4, 22+64 ; Volume/Channel 23 + DW 32, 34, 65, 10 ; Up/Down/Tab/Shift-Tab + DW 25, 41 ; PgUp/PgDn + +ChannelVol24 DW 9 + DB 31, 38 + DW 0, 64 + DW 4, 23+64 ; Volume/Channel 24 + DW 33, 35, 66, 10 ; Up/Down/Tab/Shift-Tab + DW 26, 42 ; PgUp/PgDn + +ChannelVol25 DW 9 ; Object 9 + DB 31, 39 ; x,y + DW 0, 64 ; Ranges + DW 4, 24+64 ; Volume/Channel 25 + DW 34, 36, 67, 10 ; Up/Down/Tab/Shift-Tab + DW 27, 43 ; PgUp/PgDn + +ChannelVol26 DW 9 + DB 31, 40 + DW 0, 64 + DW 4, 25+64 ; Volume/Channel 26 + DW 35, 37, 68, 10 ; Up/Down/Tab/Shift-Tab + DW 28, 44 ; PgUp/PgDn + +ChannelVol27 DW 9 ; Object 9 + DB 31, 41 ; x,y + DW 0, 64 ; Ranges + DW 4, 26+64 ; Volume/Channel 27 + DW 36, 38, 69, 10 ; Up/Down/Tab/Shift-Tab + DW 29, 45 ; PgUp/PgDn + +ChannelVol28 DW 9 + DB 31, 42 + DW 0, 64 + DW 4, 27+64 ; Volume/Channel 28 + DW 37, 39, 70, 10 ; Up/Down/Tab/Shift-Tab + DW 30, 46 ; PgUp/PgDn + +ChannelVol29 DW 9 ; Object 9 + DB 31, 43 ; x,y + DW 0, 64 ; Ranges + DW 4, 28+64 ; Volume/Channel 29 + DW 38, 40, 71, 10 ; Up/Down/Tab/Shift-Tab + DW 31, 47 ; PgUp/PgDn + +ChannelVol30 DW 9 + DB 31, 44 + DW 0, 64 + DW 4, 29+64 ; Volume/Channel 30 + DW 39, 41, 72, 10 ; Up/Down/Tab/Shift-Tab + DW 32, 48 ; PgUp/PgDn + +ChannelVol31 DW 9 ; Object 9 + DB 31, 45 ; x,y + DW 0, 64 ; Ranges + DW 4, 30+64 ; Volume/Channel 31 + DW 40, 42, 73, 10 ; Up/Down/Tab/Shift-Tab + DW 33, 49 ; PgUp/PgDn + +ChannelVol32 DW 9 + DB 31, 46 + DW 0, 64 + DW 4, 31+64 ; Volume/Channel 32 + DW 41, 43, 74, 10 ; Up/Down/Tab/Shift-Tab + DW 34, 50 ; PgUp/PgDn + +ChannelVol33 DW 9 ; Object 9 + DB 65, 15 ; x,y + DW 0, 64 ; Ranges + DW 4, 32+64 ; Volume/Channel 33 + DW 42, 44, 10, 11 ; Up/Down/Tab/Shift-Tab + DW 35, 51 ; PgUp/PgDn + +ChannelVol34 DW 9 + DB 65, 16 + DW 0, 64 + DW 4, 33+64 ; Volume/Channel 34 + DW 43, 45, 10, 12 ; Up/Down/Tab/Shift-Tab + DW 36, 52 ; PgUp/PgDn + +ChannelVol35 DW 9 ; Object 9 + DB 65, 17 ; x,y + DW 0, 64 ; Ranges + DW 4, 34+64 ; Volume/Channel 35 + DW 44, 46, 10, 13 ; Up/Down/Tab/Shift-Tab + DW 37, 53 ; PgUp/PgDn + +ChannelVol36 DW 9 + DB 65, 18 + DW 0, 64 + DW 4, 35+64 ; Volume/Channel 36 + DW 45, 47, 10, 14 ; Up/Down/Tab/Shift-Tab + DW 38, 54 ; PgUp/PgDn + +ChannelVol37 DW 9 ; Object 9 + DB 65, 19 ; x,y + DW 0, 64 ; Ranges + DW 4, 36+64 ; Volume/Channel 37 + DW 46, 48, 10, 15 ; Up/Down/Tab/Shift-Tab + DW 39, 55 ; PgUp/PgDn + +ChannelVol38 DW 9 + DB 65, 20 + DW 0, 64 + DW 4, 37+64 ; Volume/Channel 38 + DW 47, 49, 10, 16 ; Up/Down/Tab/Shift-Tab + DW 40, 56 ; PgUp/PgDn + +ChannelVol39 DW 9 ; Object 9 + DB 65, 21 ; x,y + DW 0, 64 ; Ranges + DW 4, 38+64 ; Volume/Channel 39 + DW 48, 50, 10, 17 ; Up/Down/Tab/Shift-Tab + DW 41, 57 ; PgUp/PgDn + +ChannelVol40 DW 9 + DB 65, 22 + DW 0, 64 + DW 4, 39+64 ; Volume/Channel 40 + DW 49, 51, 10, 18 ; Up/Down/Tab/Shift-Tab + DW 42, 58 ; PgUp/PgDn + +ChannelVol41 DW 9 ; Object 9 + DB 65, 23 ; x,y + DW 0, 64 ; Ranges + DW 4, 40+64 ; Volume/Channel 41 + DW 50, 52, 10, 19 ; Up/Down/Tab/Shift-Tab + DW 43, 59 ; PgUp/PgDn + +ChannelVol42 DW 9 + DB 65, 24 + DW 0, 64 + DW 4, 41+64 ; Volume/Channel 42 + DW 51, 53, 10, 20 ; Up/Down/Tab/Shift-Tab + DW 44, 60 ; PgUp/PgDn + +ChannelVol43 DW 9 ; Object 9 + DB 65, 25 ; x,y + DW 0, 64 ; Ranges + DW 4, 42+64 ; Volume/Channel 43 + DW 52, 54, 10, 21 ; Up/Down/Tab/Shift-Tab + DW 45, 61 ; PgUp/PgDn + +ChannelVol44 DW 9 + DB 65, 26 + DW 0, 64 + DW 4, 43+64 ; Volume/Channel 44 + DW 53, 55, 10, 22 ; Up/Down/Tab/Shift-Tab + DW 46, 62 ; PgUp/PgDn + +ChannelVol45 DW 9 ; Object 9 + DB 65, 27 ; x,y + DW 0, 64 ; Ranges + DW 4, 44+64 ; Volume/Channel 45 + DW 54, 56, 10, 23 ; Up/Down/Tab/Shift-Tab + DW 47, 63 ; PgUp/PgDn + +ChannelVol46 DW 9 + DB 65, 28 + DW 0, 64 + DW 4, 45+64 ; Volume/Channel 46 + DW 55, 57, 10, 24 ; Up/Down/Tab/Shift-Tab + DW 48, 64 ; PgUp/PgDn + +ChannelVol47 DW 9 ; Object 9 + DB 65, 29 ; x,y + DW 0, 64 ; Ranges + DW 4, 46+64 ; Volume/Channel 47 + DW 56, 58, 10, 25 ; Up/Down/Tab/Shift-Tab + DW 49, 65 ; PgUp/PgDn + +ChannelVol48 DW 9 + DB 65, 30 + DW 0, 64 + DW 4, 47+64 ; Volume/Channel 48 + DW 57, 59, 10, 26 ; Up/Down/Tab/Shift-Tab + DW 50, 66 ; PgUp/PgDn + +ChannelVol49 DW 9 ; Object 9 + DB 65, 31 ; x,y + DW 0, 64 ; Ranges + DW 4, 48+64 ; Volume/Channel 49 + DW 58, 60, 10, 27 ; Up/Down/Tab/Shift-Tab + DW 51, 67 ; PgUp/PgDn + +ChannelVol50 DW 9 + DB 65, 32 + DW 0, 64 + DW 4, 49+64 ; Volume/Channel 50 + DW 59, 61, 10, 28 ; Up/Down/Tab/Shift-Tab + DW 52, 68 ; PgUp/PgDn + +ChannelVol51 DW 9 ; Object 9 + DB 65, 33 ; x,y + DW 0, 64 ; Ranges + DW 4, 50+64 ; Volume/Channel 51 + DW 60, 62, 10, 29 ; Up/Down/Tab/Shift-Tab + DW 53, 69 ; PgUp/PgDn + +ChannelVol52 DW 9 + DB 65, 34 + DW 0, 64 + DW 4, 51+64 ; Volume/Channel 52 + DW 61, 63, 10, 30 ; Up/Down/Tab/Shift-Tab + DW 54, 70 ; PgUp/PgDn + +ChannelVol53 DW 9 ; Object 9 + DB 65, 35 ; x,y + DW 0, 64 ; Ranges + DW 4, 52+64 ; Volume/Channel 53 + DW 62, 64, 10, 31 ; Up/Down/Tab/Shift-Tab + DW 55, 71 ; PgUp/PgDn + +ChannelVol54 DW 9 + DB 65, 36 + DW 0, 64 + DW 4, 53+64 ; Volume/Channel 54 + DW 63, 65, 10, 32 ; Up/Down/Tab/Shift-Tab + DW 56, 72 ; PgUp/PgDn + +ChannelVol55 DW 9 ; Object 9 + DB 65, 37 ; x,y + DW 0, 64 ; Ranges + DW 4, 54+64 ; Volume/Channel 55 + DW 64, 66, 10, 33 ; Up/Down/Tab/Shift-Tab + DW 57, 73 ; PgUp/PgDn + +ChannelVol56 DW 9 + DB 65, 38 + DW 0, 64 + DW 4, 55+64 ; Volume/Channel 56 + DW 65, 67, 10, 34 ; Up/Down/Tab/Shift-Tab + DW 58, 74 ; PgUp/PgDn + +ChannelVol57 DW 9 ; Object 9 + DB 65, 39 ; x,y + DW 0, 64 ; Ranges + DW 4, 56+64 ; Volume/Channel 57 + DW 66, 68, 10, 35 ; Up/Down/Tab/Shift-Tab + DW 59, 74 ; PgUp/PgDn + +ChannelVol58 DW 9 + DB 65, 40 + DW 0, 64 + DW 4, 57+64 ; Volume/Channel 58 + DW 67, 69, 10, 36 ; Up/Down/Tab/Shift-Tab + DW 60, 74 ; PgUp/PgDn + +ChannelVol59 DW 9 ; Object 9 + DB 65, 41 ; x,y + DW 0, 64 ; Ranges + DW 4, 58+64 ; Volume/Channel 59 + DW 68, 70, 10, 37 ; Up/Down/Tab/Shift-Tab + DW 61, 74 ; PgUp/PgDn + +ChannelVol60 DW 9 + DB 65, 42 + DW 0, 64 + DW 4, 59+64 ; Volume/Channel 60 + DW 69, 71, 10, 38 ; Up/Down/Tab/Shift-Tab + DW 62, 74 ; PgUp/PgDn + +ChannelVol61 DW 9 ; Object 9 + DB 65, 43 ; x,y + DW 0, 64 ; Ranges + DW 4, 60+64 ; Volume/Channel 61 + DW 70, 72, 10, 39 ; Up/Down/Tab/Shift-Tab + DW 63, 74 ; PgUp/PgDn + +ChannelVol62 DW 9 + DB 65, 44 + DW 0, 64 + DW 4, 61+64 ; Volume/Channel 62 + DW 71, 73, 10, 40 ; Up/Down/Tab/Shift-Tab + DW 64, 74 ; PgUp/PgDn + +ChannelVol63 DW 9 ; Object 9 + DB 65, 45 ; x,y + DW 0, 64 ; Ranges + DW 4, 62+64 ; Volume/Channel 63 + DW 72, 74, 10, 41 ; Up/Down/Tab/Shift-Tab + DW 65, 74 ; PgUp/PgDn + +ChannelVol64 DW 9 + DB 65, 46 + DW 0, 64 + DW 4, 63+64 ; Volume/Channel 64 + DW 73, 74, 10, 42 ; Up/Down/Tab/Shift-Tab + DW 66, 74 ; PgUp/PgDn + +O1_ConfigureITList DW 14 ; Song name input + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr FillHeader ; 2 + DW Near Ptr ConfigureListHeader + DW Near Ptr DivisionLine + DW Near Ptr SongVarText1 + DW Near Ptr SongNameBox + DW Near Ptr InitialSpeedBox + DW Near Ptr VolumeBox + DW Near Ptr SongVarText2 + DW Near Ptr LinkCommandGToggle ; 10 + DW Near Ptr DirectoryText1 + DW Near Ptr DirectoryText2 + DW Near Ptr DirectoryInputBox + DW Near Ptr SongNameInput ; 14 + DW Near Ptr InitialTempoInput ; 15 + DW Near Ptr InitialSpeedInput ; 16 + DW Near Ptr GlobalVolumeInput ; 17 + DW Near Ptr MixingVolumeInput ; 18 + DW Near Ptr SeparationInput ; 19 + DW Near Ptr OldEffectsModeToggle ; 20 + DW Near Ptr ConfigSetupButtons ; 21 + DW Near Ptr ControlInstrumentButton ; 22 + DW Near Ptr ControlSampleButton ; 23 + DW Near Ptr PlayBackStereoButton ; 24 + DW Near Ptr PlayBackMonoButton ; 25 + DW Near Ptr SlideLinearButton ; 26 + DW Near Ptr SlideAmigaButton ; 27 + DW Near Ptr SongDirectoryInput ; 28 + DW Near Ptr SampleDirectoryInput ; 29 + DW Near Ptr InstrumentDirectoryInput ; 30 + DW Near Ptr SaveDirectoryConfigButton ; 31 + DW Near Ptr LinkCommandGToggle ; 32 + DW Near Ptr SetHelpContext5 + DW 0 + +ConfigureListHeader DW 10 + DB "Song Variables & Directory Configuration (F12)", 0 + +DivisionLine DW 1 + DB 1, 39 + DB 21h + DB 0FFh, 78, 129, 0 + +SongVarText1 DW 1 + DB 33, 13 + DB 23h + DB "Song Variables", 0 + +SongNameBox DW 0 + DB 16, 15, 43, 17 + DB 25 + +InitialSpeedBox DW 0 + DB 16, 18, 50, 21 + DB 9 + +VolumeBox DW 0 + DB 16, 22, 34, 28 + DB 25 + +SongVarText2 DW 1 + DB 2, 16 + DB 20h + DB 0FFh, 5, " Song Name", 13 + DB 13 + DB 13 + DB " Initial Tempo", 13 + DB " Initial Speed", 13 + DB 13 + DB 13 + DB " Global Volume", 13 + DB " Mixing Volume", 13 + DB 0FFh, 4, " Separation", 13 + DB " Old Effects", 13 + DB "Compatible Gxx", 13 + DB 13 + DB 13 + DB 0FFh, 7, " Control", 13 + DB 13 + DB 13 + DB 0FFh, 6, " Playback", 13 + DB 13 + DB 13 + DB " Pitch Slides" + DB 0 + +DirectoryText1 DW 1 + DB 34, 40 + DB 23h + DB "Directories", 0 + +DirectoryText2 DW 1 + DB 2, 42 + DB 20h + DB 0FFh, 4, " Module", 13 + DB 0FFh, 4, " Sample", 13 + DB "Instrument", 13 + DB 0 + +DirectoryInputBox DW 0 + DB 12, 41, 78, 45 + DB 27 + +SongNameInput DW 16 + DB 17, 16 + DW 4, 4 ; Song seg, Song name + DW 26 + DD 0 + DW 0FFFFh, 15, 15, 0FFFFh + +InitialTempoInput DW 14 + DB 17, 19 + DW 31, 255 + DW 3, 33h ; Init. Tempo=Music:33h + DW 14, 16, 16, 14 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + DW 32 + +InitialSpeedInput DW 14 + DB 17, 20 + DW 1, 255 + DW 3, 32h ; Init. Tempo=Music:33h + DW 15, 17, 17, 15 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + DW 32 + +GlobalVolumeInput DW 9 + DB 17, 23 + DW 0, 128 + DW 3, 30h + DW 16, 18, 18, 16 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +MixingVolumeInput DW 9 + DB 17, 24 + DW 0, 128 + DW 3, 31h + DW 17, 19, 19, 17 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +SeparationInput DW 9 + DB 17, 25 + DW 0, 128 + DW 3, 34h + DW 18, 20, 20, 18 + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + +OldEffectsModeToggle DW 17 + DB 17, 26 + DW 2 + DW 2Ch ; Offset of 'Flags' + DB 16 + DW 19, 10, 10, 19 + +LinkCommandGToggle DW 17 + DB 17, 27 + DW 2 + DW 2Ch ; Offset of 'Flags' + DB 32 + DW 20, 22, 22, 20 + +ConfigSetupButtons DW 8 + DD DWord Ptr F_ConfigButtonSetup + +ControlInstrumentButton DW 2 + DW 10, 24, 23, 23 + DW 0 + DW 0, 0 ; Empty Data... + DW 2 ; Call Function + DD DWord Ptr F_SetControlInstrument + DW 0, 0, 0 ; Empty data... + DB 16, 29, 30, 31 + DB 8 + DB 0 + DB " Instruments", 0 + +ControlSampleButton DW 2 + DW 10, 25, 22, 22 + DW 0 + DW 0, 0 ; Empty Data... + DW 2 ; Call Function + DD DWord Ptr F_SetControlSample + DW 0, 0, 0 ; Empty data... + DB 31, 29, 45, 31 + DB 8 + DB 0 + DB " Samples", 0 + +PlayBackStereoButton DW 2 + DW 22, 26, 25, 25 + DW 0 + DW 0, 0 ; Empty Data... + DW 2 ; Call Function + DD DWord Ptr F_SetStereo + DW 0, 0, 0 ; Empty data... + DB 16, 32, 30, 34 + DB 8 + DB 0 + DB " Stereo", 0 + +PlayBackMonoButton DW 2 + DW 23, 27, 24, 24 + DW 0 + DW 0, 0 ; Empty Data... + DW 2 ; Call Function + DD DWord Ptr F_SetMono + DW 0, 0, 0 ; Empty data... + DB 31, 32, 45, 34 + DB 8 + DB 0 + DB " Mono", 0 + +SlideLinearButton DW 2 + DW 24, 28, 27, 27 + DW 0 + DW 0, 0 ; Empty Data... + DW 2 ; Call Function + DD DWord Ptr F_SetLinear + DW 0, 0, 0 ; Empty data... + DB 16, 35, 30, 37 + DB 8 + DB 0 + DB " Linear", 0 + +SlideAmigaButton DW 2 + DW 25, 28, 26, 26 + DW 0 + DW 0, 0 ; Empty Data... + DW 2 ; Call Function + DD DWord Ptr F_SetAmiga + DW 0, 0, 0 ; Empty data... + DB 31, 35, 45, 37 + DB 8 + DB 0 + DB " Amiga", 0 + + + +SongDirectoryInput DW 16 + DB 13, 42 + DW 0, Offset SongDirectory + DW 65 + DD 0 + DW 26, 29, 29, 26 + +SampleDirectoryInput DW 16 + DB 013, 43 + DW 0, Offset SampleDirectory + DW 65 + DD 0 + DW 28, 30, 30, 28 + +InstrumentDirectoryInput DW 16 + DB 13, 44 + DW 0, Offset InstrumentDirectory + DW 65 + DD 0 + DW 29, 31, 31, 29 + +SaveDirectoryConfigButton DW 2 + DW 30, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 ; Press... no data reqd + DW 2 + DD DWord Ptr D_SaveDirectoryConfiguration + DW 0, 0, 0 ; Unused data.. + DB 27, 46, 52, 48 + DB 8 ; Thin box up + DB 0 ; Button up + DB " Save all Preferences", 0 + +O1_KeyboardList DW 8 + DW Near Ptr IdleKeyboardFunctionList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr FillHeader ; 2 + DW Near Ptr KeyboardHeader ; 3 + DW Near Ptr KeyboardBox1 ; 4 + DW Near Ptr KeyboardBox2 ; 5 + DW Near Ptr KeyboardText1 ; 6 + DW Near Ptr KeyboardText2 ; 7 + DW Near Ptr KBClearTableButton ; 8 + DW Near Ptr KBDrawTables + DW Near Ptr SetHelpContext8 + DW 0 + +IdleKeyboardFunctionList DD DWord Ptr IdleUpdateInfoLine + DD DWord Ptr K_DrawTables + DD 0 + +KBDrawTables DW 8 + DD DWord Ptr K_DrawTables + +KeyboardHeader DW 10 + DB "Keyboard Information (Ctrl-F1)", 0 + +KeyboardBox1 DW 0 + DB 1, 14, 25, 47 + DB 27 + +KeyboardBox2 DW 0 + DB 28, 14, 52, 47 + DB 27 + +KeyboardText1 DW 1 + DB 2, 13 + DB 20h + DB "Keyboard Queue", 0 + +KeyboardText2 DW 1 + DB 29, 13 + DB 20h + DB "Keypress Table", 0 + +KBClearTableButton DW 2 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 2 + DD DWord Ptr K_ResetKeyboardTables + DW 0, 0, 0 + DB 53, 14, 77, 16 + DB 8 + DB 0 + DB " Clear Keyboard Tables", 0 + + +O1_InstrumentListGeneral DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr InstrumentGlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr InstrumentListHeader ; 2 + DW Near Ptr InstrumentNameBox ; 3 + DW Near Ptr InstrumentWindow ; 4 + DW Near Ptr GInstrumentGeneralButton ; 5 + DW Near Ptr GInstrumentVolumeButton ; 6 + DW Near Ptr GInstrumentPanningButton ; 7 + DW Near Ptr GInstrumentPitchButton ; 8 + DW Near Ptr InstrumentTranslateBox ; 9 + DW Near Ptr InstrumentNoteWindow ; 10 + DW Near Ptr InstrumentFileDivision + DW Near Ptr InstrumentDCTDivision + DW Near Ptr InstrumentGeneralNNAText + DW Near Ptr InstrumentGeneralDCTText + DW Near Ptr InstrumentGeneralFileNameText ; 15 + DW Near Ptr NNAButtonCut ; 16 + DW Near Ptr NNAButtonContinue ; 17 + DW Near Ptr NNAButtonOff ;18 + DW Near Ptr NNAButtonFade ; 19 + DW Near Ptr DCTButtonOff ; 20 + DW Near Ptr DCTButtonNote ; 21 + DW Near Ptr DCTButtonSample ; 22 + DW Near Ptr DCTButtonInstrument ; 23 + DW Near Ptr DCAButtonCut ; 24 + DW Near Ptr DCAButtonOff ; 25 + DW Near Ptr DCAButtonFade ; 26 + DW Near Ptr InstrumentFilenameBox ; 27 + DW Near Ptr InstrumentFilename ; 28 + DW Near Ptr InstrumentNNADivision + DW Near Ptr FillHeader + DW Near Ptr SetHelpContext7 + DW 0 + +InstrumentDCTDivision DW 1 + DB 44, 30 + DB 20h + DB 0FFh, 35, 134, 0 + +InstrumentFileDivision DW 1 + DB 44, 45 + DB 20h + DB 0FFh, 35, 154, 0 + +InstrumentNNADivision DW 1 + DB 44, 15 + DB 20h + DB 0FFh, 35, 134, 0 + +NNAButtonCut DW 2 + DW 6, 17, 10, 4 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 0 ; Set to 0 + DW 11h + DW 0 ; Unused + DB 45, 18, 77, 20, 8 + DB 0 + DB " Note Cut", 0 + +NNAButtonContinue DW 2 + DW 16, 18, 10, 4 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 1 ; Set to 1 + DW 11h + DW 0 ; Unused + DB 45, 21, 77, 23, 8 + DB 0 + DB " Continue", 0 + +NNAButtonOff DW 2 + DW 17, 19, 10, 4 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 2 + DW 11h + DW 0 ; Unused + DB 45, 24, 77, 26, 8 + DB 0 + DB " Note Off", 0 + +NNAButtonFade DW 2 + DW 18, 20, 10, 4 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 3 + DW 11h + DW 0 ; Unused + DB 45, 27, 77, 29, 8 + DB 0 + DB " Note Fade", 0 + +DCTButtonOff DW 2 + DW 19, 21, 10, 24 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 0 ; Set to 0 + DW 12h + DW 0 ; Unused + DB 45, 33, 60, 35, 8 + DB 0 + DB " Disabled", 0 + +DCTButtonNote DW 2 + DW 20, 22, 10, 25 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 1 + DW 12h + DW 0 ; Unused + DB 45, 36, 60, 38, 8 + DB 0 + DB " Note", 0 + +DCTButtonSample DW 2 + DW 21, 23, 10, 26 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 2 + DW 12h + DW 0 ; Unused + DB 45, 39, 60, 41, 8 + DB 0 + DB " Sample", 0 + +DCTButtonInstrument DW 2 + DW 22, 28, 10, 0FFFFh + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 3 + DW 12h + DW 0 ; Unused + DB 45, 42, 60, 44, 8 + DB 0 + DB " Instrument", 0 + +DCAButtonCut DW 2 + DW 19, 25, 20, 4 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 0 ; Set to 0 + DW 13h + DW 0 ; Unused + DB 61, 33, 77, 35, 8 + DB 0 + DB " Note Cut", 0 + +DCAButtonOff DW 2 + DW 24, 26, 21, 4 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 1 ; Set to 0 + DW 13h + DW 0 ; Unused + DB 61, 36, 77, 38, 8 + DB 0 + DB " Note Off", 0 + +DCAButtonFade DW 2 + DW 25, 28, 22, 4 + DW 0 + DW 0, 0 + DW 5 + DD DWord Ptr F_InstrumentButtonHandler + DW 2 ; Set to 0 + DW 13h + DW 0 ; Unused + DB 61, 39, 77, 41, 8 + DB 0 + DB " Note Fade", 0 + + +InstrumentGeneralNNAText DW 1 + DB 54, 17 + DB 20h + DB "New Note Action", 0 + +InstrumentGeneralDCTText DW 1 + DB 47, 32 + DB 20h + DB "Duplicate Check Type & Action", 0 + +InstrumentGeneralFileNameText DW 1 + DB 47, 47 + DB 20h + DB "Filename", 0 + +InstrumentFilenameBox DW 0 + DB 55, 46, 73, 48 + DB 27 + +InstrumentFileName DW 16 + DB 56, 47 + DW 6, 4 + DW 13 + DD 0 + DW 22, 0FFFFh, 4, 10 + +GInstrumentGeneralButton DW 2 + DW 0FFFFh, 10, 4, 6 + DW 0, 0, 0 + DW 6 + DD I_GetInstrumentScreen + DW 0 + DD I_SelectScreen + DB 31, 12, 41, 14 + DB 8, 0 + DB " General", 0 + +GInstrumentVolumeButton DW 2 + DW 0FFFFh, 16, 5, 7 + DW 0, 0, 0 + DW 6 + DD I_GetInstrumentScreen + DW 1 + DD I_SelectScreen + DB 43, 12, 53, 14 + DB 8, 0 + DB " Volume", 0 + +GInstrumentPanningButton DW 2 + DW 0FFFFh, 16, 6, 8 + DW 0, 0, 0 + DW 6 + DD I_GetInstrumentScreen + DW 2 + DD I_SelectScreen + DB 55, 12, 65, 14 + DB 8, 0 + DB " Panning", 0 + +GInstrumentPitchButton DW 2 + DW 0FFFFh, 16, 7, 4 + DW 0, 0, 0 + DW 6 + DD I_GetInstrumentScreen + DW 3 + DD I_SelectScreen + DB 67, 12, 77, 14 + DB 8, 0 + DB " Pitch", 0 + + +O1_InstrumentListVolume DW 4 + DW Near Ptr IdleInstrumentList + DW Near Ptr InstrumentGlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr InstrumentListHeader ; 2 + DW Near Ptr InstrumentNameBox ; 3 + DW Near Ptr InstrumentWindow ; 4 + DW Near Ptr VInstrumentGeneralButton ; 5 + DW Near Ptr VInstrumentVolumeButton ; 6 + DW Near Ptr VInstrumentPanningButton ; 7 + DW Near Ptr VInstrumentPitchButton ; 8 + DW Near Ptr InstrumentEnvelopeBox ; 9 + DW Near Ptr InstrumentEnvelope ; 10 + DW Near Ptr InstrumentVEBox ; 11 + DW Near Ptr InstrumentVELBox ; 12 + DW Near Ptr InstrumentVESLBox ; 13 + DW Near Ptr InstrumentVEText ; 14 + DW Near Ptr InstrumentVELText ; 15 + DW Near Ptr InstrumentVESLText ; 16 + DW Near Ptr InstrumentVEToggle ; 17 + DW Near Ptr InstrumentVELToggle ; 18 + DW Near Ptr InstrumentVELBeg ; 19 + DW Near Ptr InstrumentVELEnd ; 20 + DW Near Ptr InstrumentVESLToggle ; 21 + DW Near Ptr InstrumentVESLBeg ; 22 + DW Near Ptr InstrumentVESLEnd ; 23 + DW Near Ptr InstrumentGlobalVolumeBox ; 24 + DW Near Ptr InstrumentGlobalVolumeText ; 25 + DW Near Ptr InstrumentVolume2 ; 26 + DW Near Ptr InstrumentFadeOut2 ; 27 + DW Near Ptr InstrumentRandomVolBox ; 28 + DW Near Ptr InstrumentRandomVolBar ; 29 + DW Near Ptr InstrumentVECToggle ; 30 + DW Near Ptr FillHeader + DW Near Ptr SetHelpContext7 + DW 0 + +InstrumentVEBox DW 0 + DB 53, 27, 63, 30 + DB 27 + +InstrumentVEText DW 1 + DB 38, 28 + DB 20h + DB "Volume Envelope", 13 + DB " Carry", 0 + +InstrumentVEToggle DW 17 + DB 54, 28 + DW 4, 130h + DB 1 + DW 10, 30, 4, 4 + +InstrumentVECToggle DW 17 + DB 54, 29 + DW 4, 130h + DB 8 + DW 17, 18, 4, 4 + +InstrumentVELBox DW 0 + DB 53, 31, 63, 35 + DB 27 + +InstrumentVELToggle DW 17 + DB 54, 32 + DW 4, 130h + DB 2 + DW 30, 19, 4, 4 + +InstrumentVELBeg DW 13 + DB 54, 33 + DW 0, 132h + DD 0 + DW 18, 20, 4, 4 + +InstrumentVELEnd DW 13 + DB 54, 34 + DW 0, 133h + DD 0 + DW 19, 21, 4, 4 + +InstrumentVELText DW 1 + DB 40, 32 + DB 20h + DB "Envelope Loop", 13 + DB " Loop Begin", 13 + DB 0FFh, 5, " Loop End", 0 + +InstrumentVESLBox DW 0 + DB 53, 36, 63, 40 + DB 27 + +InstrumentVESLText DW 1 + DB 40, 37 + DB 20h + DB " Sustain Loop", 13 + DB "SusLoop Begin", 13 + DB " SusLoop End", 0 + +InstrumentVESLToggle DW 17 + DB 54, 37 + DW 4, 130h + DB 4 + DW 20, 22, 4, 4 + +InstrumentVESLBeg DW 13 + DB 54, 38 + DW 0, 134h + DD 0 + DW 21, 23, 4, 4 + +InstrumentVESLEnd DW 13 + DB 54, 39 + DW 0, 135h + DD 0 + DW 22, 26, 4, 4 + +InstrumentEnvelopeBox DW 0 + DB 31, 17, 77, 26 + DB 27 + +InstrumentGlobalVolumeBox DW 0 + DB 53, 41, 71, 44 + DB 27 + +InstrumentGlobalVolumeText DW 1 + DB 39, 42 + DB 20h + DB " Global Volume", 13 + DB 0FFh, 7, " Fadeout", 13 + DB 13 + DB 13 + DB "Volume Swing %", 0 + +InstrumentRandomVolBox DW 0 + DB 53, 45, 71, 47 + DB 27 + +InstrumentRandomVolBar DW 14 + DB 54, 46 + DW 0, 100 + DW 6, 1Ah + DW 27, 0FFFFh, 4, 4 + DW 0FFFFh, 0FFFFh + DW 16 + +InstrumentVolume2 DW 9 + DB 54, 42 + DW 0, 128 + DW 6, 18h + DW 23, 27, 4, 4 + DW 0FFFFh, 0FFFFh + +InstrumentFadeOut2 DW 14 + DB 54, 43 + DW 0, 256 + DW 6, 14h + DW 26, 29, 4, 4 + DW 0FFFFh, 0FFFFh + DW 16 + +InstrumentEnvelope DW 15 + DD DWord Ptr I_DrawEnvelope + DD DWord Ptr I_PreEnvelope + DD DWord Ptr I_PostEnvelope + +VInstrumentGeneralButton DW 2 + DW 0FFFFh, 10, 4, 6 + DW 0, 0, 0 + DW 6 + DD I_GetInstrumentScreen + DW 0 + DD I_SelectScreen + DB 31, 12, 41, 14 + DB 8, 0 + DB " General", 0 + +VInstrumentVolumeButton DW 2 + DW 0FFFFh, 10, 5, 7 + DW 0, 0, 0 + DW 6 + DD I_GetInstrumentScreen + DW 1 + DD I_SelectScreen + DB 43, 12, 53, 14 + DB 8, 0 + DB " Volume", 0 + +VInstrumentPanningButton DW 2 + DW 0FFFFh, 10, 6, 8 + DW 0, 0, 0 + DW 6 + DD I_GetInstrumentScreen + DW 2 + DD I_SelectScreen + DB 55, 12, 65, 14 + DB 8, 0 + DB " Panning", 0 + +VInstrumentPitchButton DW 2 + DW 0FFFFh, 10, 7, 4 + DW 0, 0, 0 + DW 6 + DD I_GetInstrumentScreen + DW 3 + DD I_SelectScreen + DB 67, 12, 77, 14 + DB 8, 0 + DB " Pitch", 0 + +O1_InstrumentListPanning DW 4 + DW Near Ptr IdleInstrumentList + DW Near Ptr InstrumentGlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr InstrumentListHeader ; 2 + DW Near Ptr InstrumentNameBox ; 3 + DW Near Ptr InstrumentWindow ; 4 + DW Near Ptr VInstrumentGeneralButton ; 5 + DW Near Ptr VInstrumentVolumeButton ; 6 + DW Near Ptr VInstrumentPanningButton ; 7 + DW Near Ptr VInstrumentPitchButton ; 8 + DW Near Ptr InstrumentEnvelopeBox ; 9 + DW Near Ptr InstrumentEnvelope ; 10 + DW Near Ptr InstrumentVEBox ; 11 + DW Near Ptr InstrumentVELBox ; 12 + DW Near Ptr InstrumentVESLBox ; 13 + DW Near Ptr InstrumentPanText ; 14 + DW Near Ptr InstrumentVELText ; 15 + DW Near Ptr InstrumentVESLText ; 16 + DW Near Ptr InstrumentPanToggle ; 17 + DW Near Ptr InstrumentPanLToggle ; 18 + DW Near Ptr InstrumentPanLBeg ; 19 + DW Near Ptr InstrumentPanLEnd ; 20 + DW Near Ptr InstrumentPanSLToggle ; 21 + DW Near Ptr InstrumentPanSLBeg ; 22 + DW Near Ptr InstrumentPanSLEnd ; 23 + DW Near Ptr InstrumentDefaultPanBox ; 24 + DW Near Ptr InstrumentDefaultPanText ; 25 + DW Near Ptr InstrumentDefaultPanToggle ; 26 + DW Near Ptr InstrumentDefaultPanValue ; 27 + DW Near Ptr InstrumentPitchPanCenter ; 28 + DW Near Ptr InstrumentPitchPanSeparation ; 29 + DW Near Ptr InstrumentPanSwing ; 30 + DW Near Ptr InstrumentPanBoxFiller + DW Near Ptr InstrumentPanCToggle ; 32 + DW Near Ptr FillHeader + DW Near Ptr SetHelpContext7 + DW 0 + +InstrumentPanBoxFiller DW 1 + DB 54, 44 + DB 2 + DB 0FFh, 9, 09Ah, 0 + +InstrumentPanText DW 1 + DB 37, 28 + DB 20h + DB "Panning Envelope", 13 + DB " Carry", 0 + +InstrumentPanToggle DW 17 + DB 54, 28 + DW 4, 182h + DB 1 + DW 10, 32, 4, 4 + +InstrumentPanCToggle DW 17 + DB 54, 29 + DW 4, 182h + DB 8 + DW 17, 18, 4, 4 + +InstrumentPanLToggle DW 17 + DB 54, 32 + DW 4, 182h + DB 2 + DW 32, 19, 4, 4 + +InstrumentPanLBeg DW 13 + DB 54, 33 + DW 0, 184h + DD 0 + DW 18, 20, 4, 4 + +InstrumentPanLEnd DW 13 + DB 54, 34 + DW 0, 185h + DD 0 + DW 19, 21, 4, 4 + +InstrumentPanSLToggle DW 17 + DB 54, 37 + DW 4, 182h + DB 4 + DW 20, 22, 4, 4 + +InstrumentPanSLBeg DW 13 + DB 54, 38 + DW 0, 186h + DD 0 + DW 21, 23, 4, 4 + +InstrumentPanSLEnd DW 13 + DB 54, 39 + DW 0, 187h + DD 0 + DW 22, 26, 4, 4 + +InstrumentDefaultPanBox DW 0 + DB 53, 41, 63, 48 + DB 27 + +InstrumentDefaultPanText DW 1 + DB 33, 42 + DB 20h + DB 0FFh, 9, " Default Pan", 13 + DB 0FFh, 11, " Pan Value", 13, 13 + DB 0FFh, 4, " Pitch-Pan Center", 13 + DB "Pitch-Pan Separation", 13 + DB 0FFh, 11, " Pan swing", 0 + +InstrumentDefaultPanToggle DW 17 + DB 54, 42 + DW 4, 19h + DB 80h + DW 23, 27, 4, 4 + +InstrumentDefaultPanValue DW 9 + DB 54, 43 + DW 0, 64 + DW 6, 19h + DW 26, 28, 4, 4 + DW 0FFFFh, 0FFFFh + +InstrumentPitchPanCenter DW 15 + DD DWord Ptr I_DrawPitchPanCenter + DD DWord Ptr I_PrePitchPanCenter + DD DWord Ptr I_PostPitchPanCenter + +InstrumentPitchPanSeparation DW 9 + DB 54, 46 + DW -32, 32 + DW 6, 16h + DW 28, 30, 4, 4 + DW 0FFFFh, 0FFFFh + +InstrumentPanSwing DW 9 + DB 54, 47 + DW 0, 64 + DW 6, 1Bh + DW 29, 0FFFFh, 4, 4 + DW 0FFFFh, 0FFFFh + +O1_InstrumentListPitch DW 4 + DW Near Ptr IdleInstrumentList + DW Near Ptr InstrumentGlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr InstrumentListHeader ; 2 + DW Near Ptr InstrumentNameBox ; 3 + DW Near Ptr InstrumentWindow ; 4 + DW Near Ptr VInstrumentGeneralButton ; 5 + DW Near Ptr VInstrumentVolumeButton ; 6 + DW Near Ptr VInstrumentPanningButton ; 7 + DW Near Ptr VInstrumentPitchButton ; 8 + DW Near Ptr InstrumentEnvelopeBox ; 9 + DW Near Ptr InstrumentEnvelope ; 10 + DW Near Ptr InstrumentVEBox ; 11 + DW Near Ptr InstrumentVELBox ; 12 + DW Near Ptr InstrumentVESLBox ; 13 + DW Near Ptr InstrumentPitchText ; 14 + DW Near Ptr InstrumentVELText ; 15 + DW Near Ptr InstrumentVESLText ; 16 + DW Near Ptr InstrumentPitchToggle ; 17 + DW Near Ptr InstrumentPitchLToggle ; 18 + DW Near Ptr InstrumentPitchLBeg ; 19 + DW Near Ptr InstrumentPitchLEnd ; 20 + DW Near Ptr InstrumentPitchSLToggle ; 21 + DW Near Ptr InstrumentPitchSLBeg ; 22 + DW Near Ptr InstrumentPitchSLEnd ; 23 + DW Near Ptr InstrumentMIDIBox1 ; 24 + DW Near Ptr InstrumentMIDIChannel ; 25 + DW Near Ptr InstrumentMIDIProgram ; 26 + DW Near Ptr InstrumentMIDIBank1 ; 27 + DW Near Ptr InstrumentMIDIBank2 ; 28 + DW Near Ptr InstrumentPitchCToggle ; 29 +IF FILTERENVELOPES + DW Near Ptr InstrumentFilterCutoff ; 30 + DW Near Ptr InstrumentFilterResonance ; 31 +ENDIF + DW Near Ptr InstrumentMIDIText + DW Near Ptr FillHeader + DW Near Ptr SetHelpContext7 + DW 0 + +InstrumentMIDIText DW 1 + DB 36, 42 + DB 20h + +IF FILTERENVELOPES + DB "Default Cutoff", 13 + DB "Default Resonance", 13 +ENDIF + DB "MIDI Channel", 13 + DB "MIDI Program", 13 + DB "MIDI Bank Low", 13 + DB "MIDI Bank High", 0 + +InstrumentPitchText DW 1 + DB 35, 28 + DB 20h + DB "Frequency Envelope", 13 + DB " Carry", 0 + +InstrumentPitchToggle DW 17 + DB 54, 28 + DW 4, 1D4h + DB 1 + DW 10, 29, 4, 4 + +InstrumentPitchCToggle DW 17 + DB 54, 29 + DW 4, 1D4h + DB 8 + DW 17, 18, 4, 4 + +InstrumentPitchLToggle DW 17 + DB 54, 32 + DW 4, 1D4h + DB 2 + DW 29, 19, 4, 4 + +InstrumentPitchLBeg DW 13 + DB 54, 33 + DW 0, 1D6h + DD 0 + DW 18, 20, 4, 4 + +InstrumentPitchLEnd DW 13 + DB 54, 34 + DW 0, 1D7h + DD 0 + DW 19, 21, 4, 4 + +InstrumentPitchSLToggle DW 17 + DB 54, 37 + DW 4, 1D4h + DB 4 + DW 20, 22, 4, 4 + +InstrumentPitchSLBeg DW 13 + DB 54, 38 + DW 0, 1D8h + DD 0 + DW 21, 23, 4, 4 + +InstrumentPitchSLEnd DW 13 + DB 54, 39 + DW 0, 1D9h + DD 0 +IF FILTERENVELOPES + DW 22, 30, 4, 4 +ELSE + DW 22, 25, 4, 4 +ENDIF + +InstrumentMIDIChannel DW 14 +IF FILTERENVELOPES + DB 54, 44 +ELSE + DB 54, 42 +ENDIF + DW 0, 17 + DW 6, 3Ch +IF FILTERENVELOPES + DW 30, 26, 4, 4 +ELSE + DW 23, 26, 4, 4 +ENDIF + + DW 0FFFFh, 0FFFFh + DW 16 + +InstrumentFilterCutoff DW 14 + DB 54, 42 + DW 0, 127 + DW 6, 3Ah + DW 23, 31, 4, 4 + DW 0FFFFh, 0FFFFh + DW 16 + +InstrumentFilterResonance DW 14 + DB 54, 43 + DW 0, 127 + DW 6, 3Bh + DW 30, 25, 4, 4 + DW 0FFFFh, 0FFFFh + DW 16 + +InstrumentMIDIProgram DW 14 +IF FILTERENVELOPES + DB 54, 45 +ELSE + DB 54, 43 +ENDIF + DW -1, 127 + DW 6, 3Dh + DW 25, 27, 4, 4 + DW 0FFFFh, 0FFFFh + DW 16 + +InstrumentMIDIBank1 DW 14 +IF FILTERENVELOPES + DB 54, 46 +ELSE + DB 54, 44 +ENDIF + DW -1, 127 + DW 6, 3Eh + DW 26, 28, 4, 4 + DW 0FFFFh, 0FFFFh + DW 16 + +InstrumentMIDIBank2 DW 14 +IF FILTERENVELOPES + DB 54, 47 +ELSE + DB 54, 45 +ENDIF + DW -1, 127 + DW 6, 3Fh + DW 27, 0FFFFh, 4, 4 + DW 0FFFFh, 0FFFFh + DW 16 + +InstrumentListHeader DW 10 + DB "Instrument List (F4)", 0 + +InstrumentNameBox DW 0 + DB 4, 12, 30, 48 + DB 27 + +InstrumentTranslateBox DW 0 + DB 31, 15, 42, 48 + DB 27 + +InstrumentMIDIBox1 DW 0 +IF FILTERENVELOPES + DB 53, 41, 71, 48 +ELSE + DB 53, 41, 71, 46 +ENDIF + DB 27 + +InstrumentWindow DW 15 + DD DWord Ptr I_DrawInstrumentWindow + DD DWord Ptr I_PreInstrumentWindow + DD DWord Ptr I_PostInstrumentWindow + +InstrumentNoteWindow DW 15 + DD DWord Ptr I_DrawNoteWindow + DD DWord Ptr I_PreNoteWindow + DD DWord Ptr I_PostNoteWindow + +InstrumentGlobalKeyList Label +IF ENABLESOLO + DB 1 + DW '`' + DD DWord Ptr Music_ToggleSoloInstrument +ENDIF + + DB 3 ; Ctrl + DW 1C9h + DD DWord Ptr I_SampleUp + + DB 3 ; Ctrl. + DW 1D1h + DD DWord Ptr I_SampleDown + + DB 0 + DW 1C9h + DD DWord Ptr I_SampleUp + + DB 0 + DW 1D1h + DD DWord Ptr I_SampleDown + + DB 1 + DW '<' + DD DWord Ptr I_DecreasePlayChannel + + DB 1 + DW '>' + DD DWord Ptr I_IncreasePlayChannel + + DB 1 + DW ',' + DD DWord Ptr I_DecreasePlayChannel + + DB 1 + DW '.' + DD DWord Ptr I_IncreasePlayChannel + + DB 1 + DW 2000h ; Alt 'D' + DD DWord Ptr I_DeleteInstrument + + DB 1 + DW 1300h ; Alt 'R' + DD DWord Ptr I_ReplaceInstrument + + DB 1 + DW 1F00h ; Alt 'S' + DD DWord Ptr I_SwapInstruments + + DB 1 + DW 1800h ; Alt 'O' + DD DWord Ptr D_SaveInstrument + + DB 1 + DW 1900h ; Alt 'P' + DD DWord Ptr I_CopyInstrument + + DB 1 + DW 1600h ; Alt 'U' + DD DWord Ptr I_UpdateInstrument + + DB 1 ; Alt 'J' + DW 2400h + DD DWord Ptr I_ScaleInstrumentVolumes + + DB 1 + DW 2D00h ; Alt 'X' + DD DWord Ptr I_ExchangeInstruments + + DB 1 + DW 3100h ; Alt 'N' + DD DWord Ptr I_ToggleMultiChannel + + DB 0 + DW 139h + DD DWord Ptr I_InstrumentListSpace + + DB 0 + DW 039h + DD DWord Ptr I_InstrumentListNoteOff + + DB 0 ; Enter... to load sample! + DW 11Ch + DD DWord Ptr Glbl_LoadInstrument + + DB 4 ; Always call function + DW 0 + DD DWord Ptr I_PlayNote + + DB 5 + DW Offset GlobalKeyList + +O1_DisplayList DW 4 + DW Near Ptr InfoPageIdleList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr FillHeader ; 2 + DW Near Ptr DisplayHeader ; 3 + DW Near Ptr DisplayObject ; 4 + DW Near Ptr SetHelpContext9 + DW 0 + +O1_FullDisplayList DW 1 + DW Near Ptr InfoPageIdleList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr DisplayObject ; 1 + DW Near Ptr SetHelpContext9 + DW 0 + +InfoPageIdleList Label DWord + DD DWord Ptr DisplayUpdateScreen + DD 0 + +DisplayHeader DW 10 + DB "Info Page (F5)", 0 + +DisplayObject DW 15 + DD DWord Ptr DrawDisplayData + DD DWord Ptr F_Nothing + DD DWord Ptr PostDisplayData + +O1_ThumbStringList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr ESC&ReturnList + DW Near Ptr ThumbBox + DW Near Ptr ThumbInputText + DW Near Ptr ThumbInputBox + DW Near Ptr ThumbInput + DW 0 + +ThumbBox DW 0 + DB 29, 24, 50, 28 + DB 3 + +ThumbInputText DW 1 + DB 32, 26 + DB 23h + DB "Enter Value", 0 + +ThumbInputBox DW 0 + DB 43, 25, 48, 27 + DB 27 + +ThumbInput DW 16 + DB 44, 26 + DW 5, Offset ThumbStringEnter + DW 4 + DD 0 ; No function + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +O1_NewSongList DW 11 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr NewSongBox ; 0 + DW Near Ptr NewSongText ; 1 + DW Near Ptr NewSongText2 ; 2 + DW Near Ptr KeepPatternButton ; 3 + DW Near Ptr ClearPatternButton ; 4 + DW Near Ptr KeepSampleButton ; 5 + DW Near Ptr ClearSampleButton ; 6 + DW Near Ptr KeepInstrumentButton ; 7 + DW Near Ptr ClearInstrumentButton ; 8 + DW Near Ptr KeepOrderListButton ; 9 + DW Near Ptr ClearOrderListButton ; 10 + DW Near Ptr NewSongOKButton ; 11 + DW Near Ptr NewSongCancelButton ; 12 + + DW 0 + +NewSongBox DW 0 + DB 21, 20, 58, 38 + DB 3 + +NewSongText DW 1 + DB 36, 21 + DB 23h + DB "New Song", 0 + +NewSongText2 DW 1 + DB 23, 24 + DB 20h + DB " Patterns", 13 + DB 13 + DB 13 + DB 0FFh, 4, " Samples", 13 + DB 13 + DB 13 + DB "Instruments", 13 + DB 13 + DB 13 + DB " Order List", 0 + +KeepPatternButton DW 2 + DW 0FFFFh, 5, 4, 4 + DW 2 + DW 3, 4 + DW 3 ; Set var! + DW 3, 0 + DW 0, 0, 0 + DB 34, 23, 43, 25 + DB 8 + DB 0 + DB " Keep", 0 + +ClearPatternButton DW 2 + DW 4, 6, 3, 3 + DW 2 + DW 3, 4 + DW 3 + DW 3, 1 ; Clear pattern flag + DW 0, 0, 0 + DB 44, 23, 54, 25 + DB 8 + DB 3 ; Default to down + DB " Clear", 0 + +KeepSampleButton DW 2 + DW 3, 7, 6, 6 + DW 2 + DW 5, 6 + DW 3 ; Set var! + DW 4, 0 + DW 0, 0, 0 + DB 34, 26, 43, 28 + DB 8 + DB 0 + DB " Keep", 0 + +ClearSampleButton DW 2 + DW 4, 8, 5, 5 + DW 2 + DW 5, 6 + DW 3 + DW 4, 1 ; Clear pattern flag + DW 0, 0, 0 + DB 44, 26, 54, 28 + DB 8 + DB 3 ; Default to down + DB " Clear", 0 + +KeepInstrumentButton DW 2 + DW 5, 9, 8, 8 + DW 2 + DW 7, 8 + DW 3 ; Set var! + DW 5, 0 + DW 0, 0, 0 + DB 34, 29, 43, 31 + DB 8 + DB 0 + DB " Keep", 0 + +ClearInstrumentButton DW 2 + DW 6, 10, 7, 7 + DW 2 + DW 7, 8 + DW 3 + DW 5, 1 ; Clear pattern flag + DW 0, 0, 0 + DB 44, 29, 54, 31 + DB 8 + DB 3 ; Default to down + DB " Clear", 0 + +KeepOrderListButton DW 2 + DW 7, 11, 10, 10 + DW 2 + DW 9, 10 + DW 3 ; Set var! + DW 6, 0 + DW 0, 0, 0 + DB 34, 32, 43, 34 + DB 8 + DB 0 + DB " Keep", 0 + +ClearOrderListButton DW 2 + DW 8, 12, 9, 9 + DW 2 + DW 9, 10 + DW 3 + DW 6, 1 ; Clear pattern flag + DW 0, 0, 0 + DB 44, 32, 54, 34 + DB 8 + DB 3 ; Default to down + DB " Clear", 0 + +NewSongOKButton DW 2 + DW 9, 0FFFFh, 12, 12 + DW 0 ; Press. + DW 0, 0 + DW 0 ; Return value. + DW 1 ; Return OK. + DW 0, 0, 0, 0 + DB 27, 35, 38, 37 + DB 8 + DB 0 + DB " OK", 0 + +NewSongCancelButton DW 2 + DW 9, 0FFFFh, 11, 11 + DW 0 + DW 0, 0 + DW 0 + DW 0 + DW 0, 0, 0, 0 + DB 40, 35, 51, 37 + DB 8 + DB 0 + DB " Cancel", 0 + +; + +O1_MainMenu DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr MainMenuBox1 ; 0 + DW Near Ptr MainMenuBox2 ; 1 + DW Near Ptr MainMenuText ; 2 + DW Near Ptr MainMenuFile ; 3 + DW Near Ptr MainMenuPlayBack ; 4 + DW Near Ptr MainMenuViewPatterns ; 5 + DW Near Ptr MainMenuViewSamples ; 6 + DW Near Ptr MainMenuViewInstruments; 7 + DW Near Ptr MainMenuViewOrderPan ; 8 + DW Near Ptr MainMenuViewVariables ; 9 + DW Near Ptr MainMenuMessage + DW Near Ptr MainMenuHelp ; 11 + + DW 0 + +MainMenuBox1 DW 0 + DB 6, 14, 38, 46 + DB 3 + +MainMenuBox2 DW 0 + DB 7, 15, 37, 45 + DB 0 + +MainMenuText DW 1 + DB 12, 16 + DB 23h + DB "Main Menu", 0 + +MainMenuFile DW 2 + DW 0FFFFh, 4, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 2 + DD DWord Ptr F_FileMenu + DW 0, 0, 0 + DB 8, 18, 36, 20 + DB 28 + DB 0 + DB " File Menu...", 0 + +MainMenuPlayBack DW 2 + DW 3, 5, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 2 + DD DWord Ptr F_PlayBackMenu + DW 0, 0, 0 + DB 8, 21, 36, 23 + DB 28 + DB 0 + DB " Playback Menu...", 0 + +MainMenuViewPatterns DW 2 + DW 4, 6, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 ; Jump to function + DD DWord Ptr F_ViewPattern + DW 0, 0, 0 + DB 8, 24, 36, 26 + DB 28 + DB 0 + DB " View Patterns (F2)", 0 + +MainMenuViewSamples DW 2 + DW 5, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 2 + DD DWord Ptr F_SampleMenu + DW 0, 0, 0 + DB 8, 27, 36, 29 + DB 28 + DB 0 + DB " Sample Menu...", 0 + +MainMenuViewInstruments DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 2 + DD DWord Ptr F_InstrumentMenu + DW 0, 0, 0 + DB 8, 30, 36, 32 + DB 28 + DB 0 + DB " Instrument Menu...", 0 + +MainMenuViewOrderPan DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_ViewOrderPan + DW 0, 0, 0 + DB 8, 33, 36, 35 + DB 28 + DB 0 + DB " View Orders/Panning (F11)", 0 + +MainMenuViewVariables DW 2 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_ViewVariables + DW 0, 0, 0 + DB 8, 36, 36, 38 + DB 28 + DB 0 + DB " View Variables (F12)", 0 + +MainMenuMessage DW 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_MessageEditor + DW 0, 0, 0 + DB 8, 39, 36, 41 + DB 28 + DB 0 + DB " Message Editor (Shift-F9)", 0 + +MainMenuHelp DW 2 + DW 10, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_Help + DW 0, 0, 0 + DB 8, 42, 36, 44 + DB 28 + DB 0 + DB " Help! (F1)", 0 + +O1_FileMenu DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr FileBox1 ; 0 + DW Near Ptr FileBox2 ; 1 + DW Near Ptr FileMenuText ; 2 + DW Near Ptr FileLoad ; 3 + DW Near Ptr FileNew + DW Near Ptr FileSaveCurrent + DW Near Ptr FileSaveAs + DW Near Ptr FileDOSShell + DW Near Ptr FileQuit + DW 0 + +FileBox1 DW 0 + DB 25, 16, 54, 39 + DB 1 + +FileBox2 DW 0 + DB 26, 17, 53, 38 + DB 0 + +FileMenuText DW 1 + DB 30, 18 + DB 23h + DB "File Menu", 0 + +FileLoad DW 2 + DW 0FFFFh, 4, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_FileLoad + DW 0, 0, 0 + DB 27, 20, 52, 22 + DB 28 + DB 0 + DB " Load... (F9)", 0 + +FileNew DW 2 + DW 3, 5, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_FileNew + DW 0, 0, 0 + DB 27, 23, 52, 25 + DB 28 + DB 0 + DB " New... (Ctrl-N)", 0 + +FileSaveCurrent DW 2 + DW 4, 6, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_FileSaveCurrent + DW 0, 0, 0 + DB 27, 26, 52, 28 + DB 28 + DB 0 + DB " Save Current (Ctrl-S)", 0 + +FileSaveAs DW 2 + DW 5, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_FileSaveAs + DW 0, 0, 0 + DB 27, 29, 52, 31 + DB 28 + DB 0 + DB " Save As... (F10)", 0 + +FileDOSShell DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_FileDOSShell + DW 0, 0, 0 + DB 27, 32, 52, 34 + DB 28 + DB 0 + DB " Shell to DOS (Ctrl-D)", 0 + +FileQuit DW 2 + DW 7, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_FileQuit + DW 0, 0, 0 + DB 27, 35, 52, 37 + DB 28 + DB 0 + DB " Quit (Ctrl-Q)", 0 + +O1_PlayBackMenu DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr PlayBackBox1 ; 0 + DW Near Ptr PlayBackBox2 ; 1 + DW Near Ptr PlayBackText ; 2 + DW Near Ptr PlayBackShowInfoPage ; 3 + DW Near Ptr PlayBackSong ; 4 + DW Near Ptr PlayBackPattern ; 5 + DW Near Ptr PlayBackOrder ; 6 + DW Near Ptr PlayBackMark ; 7 + DW Near Ptr PlayBackStop ; 8 + DW Near Ptr PlayBackReinit ; 9 + DW Near Ptr PlayBackDriverScreen ; 10 + DW Near Ptr PlayBackCalculateLength ; 11 + DW 0 + +PlayBackBox1 DW 0 + DB 25, 16, 59, 48 + DB 1 + +PlayBackBox2 DW 0 + DB 26, 17, 58, 47 + DB 0 + +PlayBackText DW 1 + DB 31, 18 + DB 23h + DB "Playback Menu", 0 + +PlayBackShowInfoPage DW 2 + DW 0FFFFh, 4, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_InfoPage + DW 0, 0, 0 + DB 27, 20, 57, 22 + DB 28 + DB 0 + DB " Show Infopage (F5)", 0 + +PlayBackSong DW 2 + DW 3, 5, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_PlaySong + DW 0, 0, 0 + DB 27, 23, 57, 25 + DB 28 + DB 0 + DB " Play Song (Ctrl-F5)", 0 + +PlayBackPattern DW 2 + DW 4, 6, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_PlayPattern + DW 0, 0, 0 + DB 27, 26, 57, 28 + DB 28 + DB 0 + DB " Play Pattern (F6)", 0 + +PlayBackOrder DW 2 + DW 5, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_PlayOrder + DW 0, 0, 0 + DB 27, 29, 57, 31 + DB 28 + DB 0 + DB " Play from Order (Shift-F6)", 0 + +PlayBackMark DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_PlayMark + DW 0, 0, 0 + DB 27, 32, 57, 34 + DB 28 + DB 0 + DB " Play from Mark/Cursor (F7)", 0 + +PlayBackStop DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_Stop + DW 0, 0, 0 + DB 27, 35, 57, 37 + DB 28 + DB 0 + DB " Stop (F8)", 0 + +PlayBackReinit DW 2 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_ReinitSoundCard + DW 0, 0, 0 + DB 27, 38, 57, 40 + DB 28 + DB 0 + DB " Reinit Soundcard (Ctrl-I)", 0 + +PlayBackDriverScreen DW 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_DriverScreen + DW 0, 0, 0 + DB 27, 41, 57, 43 + DB 28 + DB 0 + DB " Driver Screen (Shift-F5)", 0 + +PlayBackCalculateLength DW 2 + DW 10, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_CalculateLength + DW 0, 0, 0 + DB 27, 44, 57, 46 + DB 28 + DB 0 + DB " Calculate Length (Ctrl-P)", 0 + + +O1_SampleMenu DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr SampleBox1 ; 0 + DW Near Ptr SampleBox2 ; 1 + DW Near Ptr SampleText ; 2 + DW Near Ptr SampleMenuList ; 3 + DW Near Ptr SampleLibrary ; 4 + DW Near Ptr ReloadGravis ; 5 + + DW 0 + +SampleBox1 DW 0 + DB 25, 23, 57, 37 + DB 1 + + +SampleBox2 DW 0 + DB 26, 24, 56, 36 + DB 0 + +SampleText DW 1 + DB 30, 25 + DB 23h + DB "Sample Menu", 0 + +SampleMenuList DW 2 + DW 0FFFFh, 4, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_SampleList + DW 0, 0, 0 + DB 27, 27, 55, 29 + DB 28 + DB 0 + DB " Sample List (F3)", 0 + +SampleLibrary DW 2 + DW 3, 5, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_SampleLibrary + DW 0, 0, 0 + DB 27, 30, 55, 32 + DB 28 + DB 0 + DB " Sample Library (Ctrl-F3)", 0 + +ReloadGravis DW 2 + DW 4, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_ReloadGravis + DW 0, 0, 0 + DB 27, 33, 55, 35 + DB 28 + DB 0 + DB " Reload Soundcard (Ctrl-G)", 0 + +O1_InstrumentMenu DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturnList + DW Near Ptr InstrumentBox1 ; 0 + DW Near Ptr InstrumentBox2 ; 1 + DW Near Ptr InstrumentText ; 2 + DW Near Ptr InstrumentMenuList ; 3 + DW Near Ptr InstrumentLibrary ; 4 + DW 0 + +InstrumentBox1 DW 0 + DB 20, 23, 56, 34 + DB 1 + + +InstrumentBox2 DW 0 + DB 21, 24, 55, 33 + DB 0 + +InstrumentText DW 1 + DB 25, 25 + DB 23h + DB "Instrument Menu", 0 + +InstrumentMenuList DW 2 + DW 0FFFFh, 4, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_InstrumentList + DW 0, 0, 0 + DB 22, 27, 54, 29 + DB 28 + DB 0 + DB " Instrument List (F4)", 0 + +InstrumentLibrary DW 2 + DW 3, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DD DWord Ptr F_InstrumentLibrary + DW 0, 0, 0 + DB 22, 30, 54, 32 + DB 28 + DB 0 + DB " Instrument Library (Ctrl-F4)", 0 + +; + +O1_EditSampleName DW 3 + DW IdleFunctionList + DW ESCReturnList + DW EditSampleNameBox ; 0 + DW EditSampleNameText ; 1 + DW EditSampleNameInputBox ; 2 + DW EditSampleNameInput ;3 + DW 0 + +EditSampleNameBox DW 0 + DB 23, 25, 56, 31 + DB 3 + +EditSampleNameText DW 1 + DB 32, 26 + DB 23h + DB "Edit Sample Name", 0 + +EditSampleNameInputBox DW 0 + DB 26, 28, 53, 30 + DB 27 + +EditSampleNameInput DW 16 + DB 27, 29 + DW 0, Offset SampleName + DW 26 + DD DWord Ptr F_Return1 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +; + +IF MEMORYDEBUG + +O1_DebugList DW 5 + DW Near Ptr IdleDebugFunctionList + DW Near Ptr DebugKeyList + DW Near Ptr FullScreenBox + DW Near Ptr ScreenHeader + DW Near Ptr DebugBox + DW Near Ptr DebugText + DW Near Ptr DebugInputBox + DW Near Ptr DebugAddressInput + DW Near Ptr DebugInfo + DW Near Ptr FillHeader + DW Near Ptr DebugHeader + DW 0 + + +DebugInfo DW 8 +IdleDebugFunctionList DD DWord Ptr F_DrawDebug + DD DWord Ptr IdleUpdateInfoLine + DD 0 + +DebugKeyList Label + DB 4 + DW 0 + DD DWord Ptr F_PostDebug + + DB 0 + DW 1C8h + DD DWord Ptr F_DebugUp + + DB 0 + DW 1D0h + DD DWord Ptr F_DebugDown + + DB 0 + DW 1C9h + DD DWord Ptr F_DebugPgUp + + DB 0 + DW 1D1h + DD DWord Ptr F_DebugPgDn + + DB 5 + DW Offset GlobalKeyList + + +DebugBox DW 0 + DB 1, 14, 78, 45 + DB 27 + +DebugText DW 1 + DB 4, 47 + DB 20h + DB "Address", 0 + +DebugInputBox DW 0 + DB 11, 46, 30, 48 + DB 25 + +DebugAddressInput DW 16 + DB 12, 47 + DW 5, Offset AddressInput + DW 18 + DD DWord Ptr F_DebugStringInput + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +DebugHeader DW 10 + DB "Debug", 0 + +ENDIF + +; + +O1_ConfigurePaletteList DW 53 + DW IdleFunctionList + DW GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr FillHeader ; 2 + DW Near Ptr ConfigurePaletteHeader ; 3 + DW Near Ptr SetHelpContext10 + DW Near Ptr PaletteColourBorder1 + DW Near Ptr PaletteColourBorder2 + DW Near Ptr PaletteColourBorder3 + DW Near Ptr PaletteColourBorder4 + DW Near Ptr PaletteColourBorder5 + DW Near Ptr PaletteColourBorder6 ; 10 + DW Near Ptr PaletteColourBorder7 + DW Near Ptr PaletteColourBorder8 + DW Near Ptr PaletteColourBorder9 + DW Near Ptr PaletteColourBorder10 + DW Near Ptr PaletteColourBorder11 + DW Near Ptr PaletteColourBorder12 + DW Near Ptr PaletteColourBorder13 + DW Near Ptr PaletteColourBorder14 + DW Near Ptr PaletteColourBorder15 + DW Near Ptr PaletteColourBorder16 ; 20 + DW Near Ptr PaletteColourBox1 + DW Near Ptr PaletteColourBox2 + DW Near Ptr PaletteColourBox3 + DW Near Ptr PaletteColourBox4 + DW Near Ptr PaletteColourBox5 + DW Near Ptr PaletteColourBox6 + DW Near Ptr PaletteColourBox7 + DW Near Ptr PaletteColourBox8 + DW Near Ptr PaletteColourBox9 + DW Near Ptr PaletteColourBox10 ; 30 + DW Near Ptr PaletteColourBox11 + DW Near Ptr PaletteColourBox12 + DW Near Ptr PaletteColourBox13 + DW Near Ptr PaletteColourBox14 + DW Near Ptr PaletteColourBox15 + DW Near Ptr PaletteColourBox16 + DW Near Ptr PaletteInputBox1 + DW Near Ptr PaletteInputBox2 + DW Near Ptr PaletteInputBox3 + DW Near Ptr PaletteInputBox4 ; 40 + DW Near Ptr PaletteInputBox5 + DW Near Ptr PaletteInputBox6 + DW Near Ptr PaletteInputBox7 + DW Near Ptr PaletteInputBox8 + DW Near Ptr PaletteInputBox9 + DW Near Ptr PaletteInputBox10 + DW Near Ptr PaletteInputBox11 + DW Near Ptr PaletteInputBox12 + DW Near Ptr PaletteInputBox13 + DW Near Ptr PaletteInputBox14 ; 50 + DW Near Ptr PaletteInputBox15 + DW Near Ptr PaletteInputBox16 + DW Near Ptr Colour0RedInput ; 53 + DW Near Ptr Colour0GreenInput + DW Near Ptr Colour0BlueInput + DW Near Ptr Colour1RedInput ; 56 + DW Near Ptr Colour1GreenInput + DW Near Ptr Colour1BlueInput + DW Near Ptr Colour2RedInput + DW Near Ptr Colour2GreenInput ; 60 + DW Near Ptr Colour2BlueInput + DW Near Ptr Colour3RedInput + DW Near Ptr Colour3GreenInput + DW Near Ptr Colour3BlueInput + DW Near Ptr Colour4RedInput + DW Near Ptr Colour4GreenInput + DW Near Ptr Colour4BlueInput + DW Near Ptr Colour5RedInput + DW Near Ptr Colour5GreenInput + DW Near Ptr Colour5BlueInput ; 70 + DW Near Ptr Colour6RedInput + DW Near Ptr Colour6GreenInput + DW Near Ptr Colour6BlueInput + DW Near Ptr Colour7RedInput ; 74 + DW Near Ptr Colour7GreenInput + DW Near Ptr Colour7BlueInput + DW Near Ptr Colour8RedInput + DW Near Ptr Colour8GreenInput + DW Near Ptr Colour8BlueInput + DW Near Ptr Colour9RedInput ; 80 + DW Near Ptr Colour9GreenInput + DW Near Ptr Colour9BlueInput + DW Near Ptr Colour10RedInput + DW Near Ptr Colour10GreenInput + DW Near Ptr Colour10BlueInput + DW Near Ptr Colour11RedInput + DW Near Ptr Colour11GreenInput + DW Near Ptr Colour11BlueInput + DW Near Ptr Colour12RedInput + DW Near Ptr Colour12GreenInput ; 90 + DW Near Ptr Colour12BlueInput + DW Near Ptr Colour13RedInput + DW Near Ptr Colour13GreenInput + DW Near Ptr Colour13BlueInput + DW Near Ptr Colour14RedInput + DW Near Ptr Colour14GreenInput + DW Near Ptr Colour14BlueInput + DW Near Ptr Colour15RedInput + DW Near Ptr Colour15GreenInput + DW Near Ptr Colour15BlueInput ; 100 + DW Near Ptr PredefinedPaletteMsg + DW Near Ptr PredefinedPalette1 + DW Near Ptr PredefinedPalette2 + DW Near Ptr PredefinedPalette3 + DW Near Ptr PredefinedPalette4 + DW Near Ptr PredefinedPalette5 + DW Near Ptr PredefinedPalette6 + DW Near Ptr PredefinedPalette7 + DW 0 + +ConfigurePaletteHeader DW 10 + DB "Palette Configuration (Ctrl-F12)", 0 + +PaletteColourBorder1 DW 0 + DB 2, 13, 8, 17 + DB 11 + +PaletteColourBorder2 DW 0 + DB 2, 18, 8, 22 + DB 11 + +PaletteColourBorder3 DW 0 + DB 2, 23, 8, 27 + DB 11 + +PaletteColourBorder4 DW 0 + DB 2, 28, 8, 32 + DB 11 + +PaletteColourBorder5 DW 0 + DB 2, 33, 8, 37 + DB 11 + +PaletteColourBorder6 DW 0 + DB 2, 38, 8, 42 + DB 11 + +PaletteColourBorder7 DW 0 + DB 2, 43, 8, 47 + DB 11 + +PaletteColourBorder8 DW 0 + DB 29, 13, 35, 17 + DB 11 + +PaletteColourBorder9 DW 0 + DB 29, 18, 35, 22 + DB 11 + +PaletteColourBorder10 DW 0 + DB 29, 23, 35, 27 + DB 11 + +PaletteColourBorder11 DW 0 + DB 29, 28, 35, 32 + DB 11 + +PaletteColourBorder12 DW 0 + DB 29, 33, 35, 37 + DB 11 + +PaletteColourBorder13 DW 0 + DB 29, 38, 35, 42 + DB 11 + +PaletteColourBorder14 DW 0 + DB 29, 43, 35, 47 + DB 11 + +PaletteColourBorder15 DW 0 + DB 56, 13, 62, 17 + DB 11 + +PaletteColourBorder16 DW 0 + DB 56, 18, 62, 22 + DB 11 + +PaletteColourBox1 DW 1 + DB 3, 14 + DB 00h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox2 DW 1 + DB 3, 19 + DB 10h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox3 DW 1 + DB 3, 24 + DB 20h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox4 DW 1 + DB 3, 29 + DB 30h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox5 DW 1 + DB 3, 34 + DB 40h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox6 DW 1 + DB 3, 39 + DB 50h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox7 DW 1 + DB 3, 44 + DB 60h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox8 DW 1 + DB 30, 14 + DB 70h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox9 DW 1 + DB 30, 19 + DB 80h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox10 DW 1 + DB 30, 24 + DB 90h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox11 DW 1 + DB 30, 29 + DB 0A0h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox12 DW 1 + DB 30, 34 + DB 0B0h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox13 DW 1 + DB 30, 39 + DB 0C0h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox14 DW 1 + DB 30, 44 + DB 0D0h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox15 DW 1 + DB 57, 14 + DB 0E0h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteColourBox16 DW 1 + DB 57, 19 + DB 0F0h + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 13 + DB 0FFh, 5, " ", 0 + +PaletteInputBox1 DW 0 + DB 9, 13, 19, 17 + DB 27 + +PaletteInputBox2 DW 0 + DB 9, 18, 19, 22 + DB 27 + +PaletteInputBox3 DW 0 + DB 9, 23, 19, 27 + DB 27 + +PaletteInputBox4 DW 0 + DB 9, 28, 19, 32 + DB 27 + +PaletteInputBox5 DW 0 + DB 9, 33, 19, 37 + DB 27 + +PaletteInputBox6 DW 0 + DB 9, 38, 19, 42 + DB 27 + +PaletteInputBox7 DW 0 + DB 9, 43, 19, 47 + DB 27 + +PaletteInputBox8 DW 0 + DB 36, 13, 46, 17 + DB 27 + +PaletteInputBox9 DW 0 + DB 36, 18, 46, 22 + DB 27 + +PaletteInputBox10 DW 0 + DB 36, 23, 46, 27 + DB 27 + +PaletteInputBox11 DW 0 + DB 36, 28, 46, 32 + DB 27 + +PaletteInputBox12 DW 0 + DB 36, 33, 46, 37 + DB 27 + +PaletteInputBox13 DW 0 + DB 36, 38, 46, 42 + DB 27 + +PaletteInputBox14 DW 0 + DB 36, 43, 46, 47 + DB 27 + +PaletteInputBox15 DW 0 + DB 63, 13, 73, 17 + DB 27 + +PaletteInputBox16 DW 0 + DB 63, 18, 73, 22 + DB 27 + +Colour0RedInput DW 9 + DB 10, 14 + DW 0, 63 + DW 7, Offset PaletteDefs + DW 0FFFFh, 54, 74, 95, 0FFFFh, 56 + +Colour0GreenInput DW 9 + DB 10, 15 + DW 0, 63 + DW 7, Offset PaletteDefs+1 + DW 53, 55, 75, 96, 0FFFFh, 57 + +Colour0BlueInput DW 9 + DB 10, 16 + DW 0, 63 + DW 7, Offset PaletteDefs+2 + DW 54, 56, 76, 97, 0FFFFh, 58 + +Colour1RedInput DW 9 + DB 10, 19 + DW 0, 63 + DW 7, Offset PaletteDefs+3 + DW 55, 57, 77, 98, 53, 59 + +Colour1GreenInput DW 9 + DB 10, 20 + DW 0, 63 + DW 7, Offset PaletteDefs+4 + DW 56, 58, 78, 99, 54, 60 + +Colour1BlueInput DW 9 + DB 10, 21 + DW 0, 63 + DW 7, Offset PaletteDefs+5 + DW 57, 59, 79, 100, 55, 61 + +Colour2RedInput DW 9 + DB 10, 24 + DW 0, 63 + DW 7, Offset PaletteDefs+6 + DW 58, 60, 80, 0FFFFh, 56, 62 + +Colour2GreenInput DW 9 + DB 10, 25 + DW 0, 63 + DW 7, Offset PaletteDefs+7 + DW 59, 61, 81, 0FFFFh, 57, 63 + +Colour2BlueInput DW 9 + DB 10, 26 + DW 0, 63 + DW 7, Offset PaletteDefs+8 + DW 60, 62, 82, 0FFFFh, 58, 64 + +Colour3RedInput DW 9 + DB 10, 29 + DW 0, 63 + DW 7, Offset PaletteDefs+9 + DW 61, 63, 83, 0FFFFh, 59, 65 + +Colour3GreenInput DW 9 + DB 10, 30 + DW 0, 63 + DW 7, Offset PaletteDefs+10 + DW 62, 64, 84, 0FFFFh, 60, 66 + +Colour3BlueInput DW 9 + DB 10, 31 + DW 0, 63 + DW 7, Offset PaletteDefs+11 + DW 63, 65, 85, 0FFFFh, 61, 67 + +Colour4RedInput DW 9 + DB 10, 34 + DW 0, 63 + DW 7, Offset PaletteDefs+12 + DW 64, 66, 86, 0FFFFh, 62, 68 + +Colour4GreenInput DW 9 + DB 10, 35 + DW 0, 63 + DW 7, Offset PaletteDefs+13 + DW 65, 67, 87, 0FFFFh, 63, 69 + +Colour4BlueInput DW 9 + DB 10, 36 + DW 0, 63 + DW 7, Offset PaletteDefs+14 + DW 66, 68, 88, 0FFFFh, 64, 70 + +Colour5RedInput DW 9 + DB 10, 39 + DW 0, 63 + DW 7, Offset PaletteDefs+15 + DW 67, 69, 89, 0FFFFh, 65, 71 + +Colour5GreenInput DW 9 + DB 10, 40 + DW 0, 63 + DW 7, Offset PaletteDefs+16 + DW 68, 70, 90, 0FFFFh, 66, 72 + +Colour5BlueInput DW 9 + DB 10, 41 + DW 0, 63 + DW 7, Offset PaletteDefs+17 + DW 69, 71, 91, 0FFFFh, 67, 73 + +Colour6RedInput DW 9 + DB 10, 44 + DW 0, 63 + DW 7, Offset PaletteDefs+18 + DW 70, 72, 92, 0FFFFh, 68, 74 + +Colour6GreenInput DW 9 + DB 10, 45 + DW 0, 63 + DW 7, Offset PaletteDefs+19 + DW 71, 73, 93, 0FFFFh, 69, 75 + +Colour6BlueInput DW 9 + DB 10, 46 + DW 0, 63 + DW 7, Offset PaletteDefs+20 + DW 72, 74, 94, 0FFFFh, 70, 76 + +Colour7RedInput DW 9 + DB 37, 14 + DW 0, 63 + DW 7, Offset PaletteDefs+21 + DW 73, 75, 95, 53, 71, 77 + +Colour7GreenInput DW 9 + DB 37, 15 + DW 0, 63 + DW 7, Offset PaletteDefs+22 + DW 74, 76, 96, 54, 72, 78 + +Colour7BlueInput DW 9 + DB 37, 16 + DW 0, 63 + DW 7, Offset PaletteDefs+23 + DW 75, 77, 97, 55, 73, 79 + +Colour8RedInput DW 9 + DB 37, 19 + DW 0, 63 + DW 7, Offset PaletteDefs+24 + DW 76, 78, 98, 56, 74, 80 + +Colour8GreenInput DW 9 + DB 37, 20 + DW 0, 63 + DW 7, Offset PaletteDefs+25 + DW 77, 79, 99, 57, 75, 81 + +Colour8BlueInput DW 9 + DB 37, 21 + DW 0, 63 + DW 7, Offset PaletteDefs+26 + DW 78, 80, 100, 58, 76, 82 + +Colour9RedInput DW 9 + DB 37, 24 + DW 0, 63 + DW 7, Offset PaletteDefs+27 + DW 79, 81, 102, 59, 77, 83 + +Colour9GreenInput DW 9 + DB 37, 25 + DW 0, 63 + DW 7, Offset PaletteDefs+28 + DW 80, 82, 102, 60, 78, 84 + +Colour9BlueInput DW 9 + DB 37, 26 + DW 0, 63 + DW 7, Offset PaletteDefs+29 + DW 81, 83, 102, 61, 79, 85 + +Colour10RedInput DW 9 + DB 37, 29 + DW 0, 63 + DW 7, Offset PaletteDefs+30 + DW 82, 84, 102, 62, 80, 86 + +Colour10GreenInput DW 9 + DB 37, 30 + DW 0, 63 + DW 7, Offset PaletteDefs+31 + DW 83, 85, 102, 63, 81, 87 + +Colour10BlueInput DW 9 + DB 37, 31 + DW 0, 63 + DW 7, Offset PaletteDefs+32 + DW 84, 86, 102, 64, 82, 88 + +Colour11RedInput DW 9 + DB 37, 34 + DW 0, 63 + DW 7, Offset PaletteDefs+33 + DW 85, 87, 102, 65, 83, 89 + +Colour11GreenInput DW 9 + DB 37, 35 + DW 0, 63 + DW 7, Offset PaletteDefs+34 + DW 86, 88, 102, 66, 84, 90 + +Colour11BlueInput DW 9 + DB 37, 36 + DW 0, 63 + DW 7, Offset PaletteDefs+35 + DW 87, 89, 102, 67, 85, 91 + +Colour12RedInput DW 9 + DB 37, 39 + DW 0, 63 + DW 7, Offset PaletteDefs+36 + DW 88, 90, 102, 68, 86, 92 + +Colour12GreenInput DW 9 + DB 37, 40 + DW 0, 63 + DW 7, Offset PaletteDefs+37 + DW 89, 91, 102, 69, 87, 93 + +Colour12BlueInput DW 9 + DB 37, 41 + DW 0, 63 + DW 7, Offset PaletteDefs+38 + DW 90, 92, 102, 70, 88, 94 + +Colour13RedInput DW 9 + DB 37, 44 + DW 0, 63 + DW 7, Offset PaletteDefs+39 + DW 91, 93, 102, 71, 89, 95 + +Colour13GreenInput DW 9 + DB 37, 45 + DW 0, 63 + DW 7, Offset PaletteDefs+40 + DW 92, 94, 102, 72, 90, 96 + +Colour13BlueInput DW 9 + DB 37, 46 + DW 0, 63 + DW 7, Offset PaletteDefs+41 + DW 93, 95, 102, 73, 91, 97 + +Colour14RedInput DW 9 + DB 64, 14 + DW 0, 63 + DW 7, Offset PaletteDefs+42 + DW 94, 96, 53, 74, 92, 98 + +Colour14GreenInput DW 9 + DB 64, 15 + DW 0, 63 + DW 7, Offset PaletteDefs+43 + DW 95, 97, 54, 75, 93, 99 + +Colour14BlueInput DW 9 + DB 64, 16 + DW 0, 63 + DW 7, Offset PaletteDefs+44 + DW 96, 98, 55, 76, 94, 100 + +Colour15RedInput DW 9 + DB 64, 19 + DW 0, 63 + DW 7, Offset PaletteDefs+45 + DW 97, 99, 56, 77, 95, 102 + +Colour15GreenInput DW 9 + DB 64, 20 + DW 0, 63 + DW 7, Offset PaletteDefs+46 + DW 98, 100, 57, 78, 96, 102 + +Colour15BlueInput DW 9 + DB 64, 21 + DW 0, 63 + DW 7, Offset PaletteDefs+47 + DW 99, 102, 58, 79, 97, 102 + +PredefinedPaletteMsg DW 1 + DB 57, 25 + DB 20h + DB "Predefined Palettes", 0 + +PredefinedPalette1 DW 2 + DW 100, 103, 82, 61 + DW 0 + DW 0, 0 + DW 4 ; Jump to function + DD DWord Ptr S_UsePresetPalette + DW 0 ; First palette + DW 0, 0 ; Unused data + DB 55, 27, 77, 29 + DB 8 + DB 0 + DB " Light Blue", 0 + +PredefinedPalette2 DW 2 + DW 102, 104, 85, 64 + DW 0 + DW 0, 0 + DW 4 ; Jump to function + DD DWord Ptr S_UsePresetPalette + DW 1 ; First palette + DW 0, 0 ; Unused data + DB 55, 30, 77, 32 + DB 8 + DB 0 + DB " Gold", 0 + +PredefinedPalette3 DW 2 + DW 103, 105, 86, 65 + DW 0 + DW 0, 0 + DW 4 ; Jump to function + DD DWord Ptr S_UsePresetPalette + DW 2 ; First palette + DW 0, 0 ; Unused data + DB 55, 33, 77, 35 + DB 8 + DB 0 + DB " Camouflage", 0 + +PredefinedPalette4 DW 2 + DW 104, 106, 88, 67 + DW 0 + DW 0, 0 + DW 4 ; Jump to function + DD DWord Ptr S_UsePresetPalette + DW 3 + DW 0, 0 ; Unused data + DB 55, 36, 77, 38 + DB 8 + DB 0 + DB " Midnight Tracking", 0 + +PredefinedPalette5 DW 2 + DW 105, 107, 90, 69 + DW 0 + DW 0, 0 + DW 4 ; Jump to function + DD DWord Ptr S_UsePresetPalette + DW 4 + DW 0, 0 ; Unused data + DB 55, 39, 77, 41 + DB 8 + DB 0 + DB " Pine Colours", 0 + +PredefinedPalette6 DW 2 + DW 106, 108, 91, 70 + DW 0 + DW 0, 0 + DW 4 ; Jump to function + DD DWord Ptr S_UsePresetPalette + DW 5 + DW 0, 0 ; Unused data + DB 55, 42, 77, 44 + DB 8 + DB 0 + DB " Soundtracker", 0 + +PredefinedPalette7 DW 2 + DW 107, 0FFFFh, 94, 73 + DW 0 + DW 0, 0 + DW 4 ; Jump to function + DD DWord Ptr S_UsePresetPalette + DW 6 + DW 0, 0 ; Unused data + DB 55, 45, 77, 47 + DB 8 + DB 0 + DB " Volcanic", 0 + +O1_LoadInstrumentList DW 5 + DW Near Ptr InstrumentNameLoader ; Idlekey + DW Near Ptr LoadInstrumentKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr LoadInstrumentHeader ; 2 + DW Near Ptr FillHeader ; 3 + DW Near Ptr LoadInstrumentWindow + DW Near Ptr LoadInstrument ; 5 + DW Near Ptr LoadInstrumentDriveWindow + DW Near Ptr LoadInstrumentDrive + DW Near Ptr SetHelpContext11 + DW 0 + +LoadInstrumentDriveWindow DW 0 + DB 63, 15, 72, 48 + DB 27 + +LoadInstrumentDrive DW 15 + DD DWord Ptr D_LIDrawDriveWindow + DD DWord Ptr D_LIPreDriveWindow + DD DWord Ptr D_LIPostDriveWindow + +O1_ViewInstrumentLibrary DW 5 + DW Near Ptr InstrumentNameLoader ; Idlekey + DW Near Ptr LoadInstrumentKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr InstrumentLibraryHeader ; 2 + DW Near Ptr FillHeader ; 3 + DW Near Ptr LoadInstrumentWindow + DW Near Ptr ViewInstrument ; 5 + DW Near Ptr LoadInstrumentDriveWindow + DW Near Ptr LoadInstrumentDrive + DW Near Ptr SetHelpContext11 + DW 0 + +LoadInstrumentHeader DW 10 + DB "Load Instrument", 0 + +InstrumentLibraryHeader DW 10 + DB "Instrument Library (Ctrl-F4)", 0 + +LoadInstrumentWindow DW 0 + DB 5, 12, 62, 48 + DB 27 + +LoadInstrument DW 15 + DD DWord Ptr D_DrawLoadInstrument + DD DWord Ptr D_PreLoadInstrument + DD DWord Ptr D_PostLoadInstrument + +ViewInstrument DW 15 + DD DWord Ptr D_DrawLoadInstrument + DD DWord Ptr D_PreLoadInstrument + DD DWord Ptr D_ViewInstrument + +InstrumentNameLoader DD DWord Ptr D_LoadInstrumentNames + DD DWord Ptr IdleUpdateInfoLine + DD 0 + +O1_UndoList DW 3 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCExitList + DW Near Ptr UndoBox1 + DW Near Ptr UndoBox2 + DW Near Ptr UndoText + DW Near Ptr UndoSelector + DW 0 + +UndoBox1 DW 0 + DB 16, 21, 63, 36 + DB 3 + +UndoBox2 DW 0 + DB 19, 23, 60, 34 + DB 27 + +UndoText DW 1 + DB 38, 22 + DB 23h + DB "Undo", 0 + +UndoSelector DW 15 + DD DWord Ptr PEFunction_DrawUndo + DD DWord Ptr PEFunction_PreUndo + DD DWord Ptr PEFunction_PostUndo + +; + +O1_MessageList DW 4 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr MessageBox + DW Near Ptr MessageObject + DW Near Ptr MessageHeader + DW Near Ptr SetHelpContext12 + DW 0 + +MessageBox DW 0 + DB 1, 12, 78, 48 + DB 27 + +MessageObject DW 15 + DD DWord Ptr Msg_DrawMessage + DD DWord Ptr Msg_PreMessage + DD DWord Ptr Msg_PostMessage + +MessageHeader DW 10 + DB "Message Editor (Shift-F9)", 0 + +; + +O1_MIDIOutputScreen DW 9 + DW Near Ptr IdleFunctionList + DW Near Ptr MIDIOutKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr MIDIOutputHeader + DW Near Ptr MIDIOutputMainConfigText + DW Near Ptr MIDIOutputSFxConfigText + DW Near Ptr MIDIOutputMainConfigBox + DW Near Ptr MIDIOutputSFxConfigBox + DW Near Ptr MIDIOutputZxxConfigBox ; 8 + DW Near Ptr MIDIStartInput ; 9 + DW Near Ptr MIDIStopInput ; 10 + DW Near Ptr MIDITickInput ; 11 + DW Near Ptr MIDINoteOnInput ; 12 + DW Near Ptr MIDINoteOffInput ; 13 + DW Near Ptr MIDIChangeVolumeInput ; 14 + DW Near Ptr MIDIChangePanInput ; 15 + DW Near Ptr MIDIBankSelectInput ; 16 + DW Near Ptr MIDIProgramChangeInput ; 17 + DW Near Ptr MIDISF0Input + DW Near Ptr MIDISF1Input + DW Near Ptr MIDISF2Input + DW Near Ptr MIDISF3Input + DW Near Ptr MIDISF4Input + DW Near Ptr MIDISF5Input + DW Near Ptr MIDISF6Input + DW Near Ptr MIDISF7Input + DW Near Ptr MIDISF8Input + DW Near Ptr MIDISF9Input + DW Near Ptr MIDISFAInput + DW Near Ptr MIDISFBInput + DW Near Ptr MIDISFCInput + DW Near Ptr MIDISFDInput + DW Near Ptr MIDISFEInput + DW Near Ptr MIDISFFInput ; 33 + DW Near Ptr MIDIZ1Input + DW Near Ptr MIDIZ2Input + DW Near Ptr MIDIZ3Input + DW Near Ptr MIDIZ4Input + DW Near Ptr MIDIZ5Input + DW Near Ptr MIDIZ6Input + DW Near Ptr MIDIZ7Input + DW Near Ptr MIDIZxxNumbering + DW 0 + +MIDIOutputHeader DW 10 + DB "MIDI Output Configuration", 0 + +MIDIZxxNumbering DW 8 + DD DWord Ptr F_ShowMIDIZxxInput + +MIDIOutKeyList DB 0 + DW 1C8h + DD DWord Ptr F_MIDI_Up + + DB 0 + DW 1D0h + DD DWord Ptr F_MIDI_Down + + DB 0 + DW 1C9h + DD DWord Ptr F_MIDI_PgUp + + DB 0 + DW 1D1h + DD DWord Ptr F_MIDI_PgDn + + DB 5 + DW Offset GlobalKeyChain + +MIDIOutputMainConfigText DW 1 + DB 2, 13 + DB 20h + DB 0FFh, 4, " MIDI Start", 13 + DB 0FFh, 5, " MIDI Stop", 13 + DB 0FFh, 5, " MIDI Tick", 13 + DB 0FFh, 7, " Note On", 13 + DB 0FFh, 6, " Note Off", 13 + DB " Change Volume", 13 + DB 0FFh, 4, " Change Pan", 13 + DB " Bank Select", 13 + DB "Program Change", 13 + DB 13 + DB 13 + DB " Macro", 13 + DB " Setup", 0 + +MIDIOutputSFxConfigText DW 1 + DB 13, 24 + DB 20h + DB "SF0", 13 + DB "SF1", 13 + DB "SF2", 13 + DB "SF3", 13 + DB "SF4", 13 + DB "SF5", 13 + DB "SF6", 13 + DB "SF7", 13 + DB "SF8", 13 + DB "SF9", 13 + DB "SFA", 13 + DB "SFB", 13 + DB "SFC", 13 + DB "SFD", 13 + DB "SFE", 13 + DB "SFF", 0 + +MIDIOutputMainConfigBox DW 0 + DB 16, 12, 60, 22 + DB 27 + +MIDIOutputSFxConfigBox DW 0 + DB 16, 23, 60, 40 + DB 27 + +MIDIOutputZxxConfigBox DW 0 + DB 16, 41, 60, 49 + DB 27 + + +MIDIStartInput DW 16 + DB 17, 13 + DW 7, 0 + DW 32 + DD 0 + DW 9, 10, 0FFFFh, 0FFFFh + +MIDIStopInput DW 16 + DB 17, 14 + DW 7, 20h + DW 32 + DD 0 + DW 9, 11, 0FFFFh, 0FFFFh + +MIDITickInput DW 16 + DB 17, 15 + DW 7, 40h + DW 32 + DD 0 + DW 10, 12, 0FFFFh, 0FFFFh + +MIDINoteOnInput DW 16 + DB 17, 16 + DW 7, 60h + DW 32 + DD 0 + DW 11, 13, 0FFFFh, 0FFFFh + +MIDINoteOffInput DW 16 + DB 17, 17 + DW 7, 80h + DW 32 + DD 0 + DW 12, 14, 0FFFFh, 0FFFFh + +MIDIChangeVolumeInput DW 16 + DB 17, 18 + DW 7, 0A0h + DW 32 + DD 0 + DW 13, 15, 0FFFFh, 0FFFFh + +MIDIChangePanInput DW 16 + DB 17, 19 + DW 7, 0C0h + DW 32 + DD 0 + DW 14, 16, 0FFFFh, 0FFFFh + +MIDIBankSelectInput DW 16 + DB 17, 20 + DW 7, 0E0h + DW 32 + DD 0 + DW 15, 17, 0FFFFh, 0FFFFh + +MIDIProgramChangeInput DW 16 + DB 17, 21 + DW 7, 100h + DW 32 + DD 0 + DW 16, 18, 0FFFFh, 0FFFFh + +MIDISF0Input DW 16 + DB 17, 24 + DW 7, 120h + DW 32 + DD 0 + DW 17, 19, 0FFFFh, 0FFFFh + +MIDISF1Input DW 16 + DB 17, 25 + DW 7, 140h + DW 32 + DD 0 + DW 18, 20, 0FFFFh, 0FFFFh + +MIDISF2Input DW 16 + DB 17, 26 + DW 7, 160h + DW 32 + DD 0 + DW 19, 21, 0FFFFh, 0FFFFh + +MIDISF3Input DW 16 + DB 17, 27 + DW 7, 180h + DW 32 + DD 0 + DW 20, 22, 0FFFFh, 0FFFFh + +MIDISF4Input DW 16 + DB 17, 28 + DW 7, 1A0h + DW 32 + DD 0 + DW 21, 23, 0FFFFh, 0FFFFh + +MIDISF5Input DW 16 + DB 17, 29 + DW 7, 1C0h + DW 32 + DD 0 + DW 22, 24, 0FFFFh, 0FFFFh + +MIDISF6Input DW 16 + DB 17, 30 + DW 7, 1E0h + DW 32 + DD 0 + DW 23, 25, 0FFFFh, 0FFFFh + +MIDISF7Input DW 16 + DB 17, 31 + DW 7, 200h + DW 32 + DD 0 + DW 24, 26, 0FFFFh, 0FFFFh + +MIDISF8Input DW 16 + DB 17, 32 + DW 7, 220h + DW 32 + DD 0 + DW 25, 27, 0FFFFh, 0FFFFh + +MIDISF9Input DW 16 + DB 17, 33 + DW 7, 240h + DW 32 + DD 0 + DW 26, 28, 0FFFFh, 0FFFFh + +MIDISFAInput DW 16 + DB 17, 34 + DW 7, 260h + DW 32 + DD 0 + DW 27, 29, 0FFFFh, 0FFFFh + +MIDISFBInput DW 16 + DB 17, 35 + DW 7, 280h + DW 32 + DD 0 + DW 28, 30, 0FFFFh, 0FFFFh + +MIDISFCInput DW 16 + DB 17, 36 + DW 7, 2A0h + DW 32 + DD 0 + DW 29, 31, 0FFFFh, 0FFFFh + +MIDISFDInput DW 16 + DB 17, 37 + DW 7, 2C0h + DW 32 + DD 0 + DW 30, 32, 0FFFFh, 0FFFFh + +MIDISFEInput DW 16 + DB 17, 38 + DW 7, 2E0h + DW 32 + DD 0 + DW 31, 33, 0FFFFh, 0FFFFh + +MIDISFFInput DW 16 + DB 17, 39 + DW 7, 300h + DW 32 + DD 0 + DW 32, 34, 0FFFFh, 0FFFFh + +MIDIZ1Input DW 16 + DB 17, 42 + DW 7, 8320h + DW 32 + DD 0 + DW 0FFFFh, 35, 0FFFFh, 0FFFFh + +MIDIZ2Input DW 16 + DB 17, 43 + DW 7, 8340h + DW 32 + DD 0 + DW 34, 36, 0FFFFh, 0FFFFh + +MIDIZ3Input DW 16 + DB 17, 44 + DW 7, 8360h + DW 32 + DD 0 + DW 35, 37, 0FFFFh, 0FFFFh + +MIDIZ4Input DW 16 + DB 17, 45 + DW 7, 8380h + DW 32 + DD 0 + DW 36, 38, 0FFFFh, 0FFFFh + +MIDIZ5Input DW 16 + DB 17, 46 + DW 7, 83A0h + DW 32 + DD 0 + DW 37, 39, 0FFFFh, 0FFFFh + +MIDIZ6Input DW 16 + DB 17, 47 + DW 7, 83C0h + DW 32 + DD 0 + DW 38, 40, 0FFFFh, 0FFFFh + +MIDIZ7Input DW 16 + DB 17, 48 + DW 7, 83E0h + DW 32 + DD 0 + DW 39, 0FFFFh, 0FFFFh, 0FFFFh + +O1_MIDIScreen DW 7 + DW Near Ptr MIDIIdleList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr MIDIHeader + DW Near Ptr ShowMIDIInput + DW Near Ptr MIDIOptionsBox ; 5 + DW Near Ptr MIDIOptions ; 6 + DW Near Ptr ProgramChangeToggle ; 7 + DW Near Ptr Program1Toggle ; 8 + DW Near Ptr RecordNoteOffToggle ; 9 + DW Near Ptr RecordVelocityToggle ; 10 + DW Near Ptr RecordAfterTouchToggle ; 11 + DW Near Ptr MIDITranslateBox ; 12 + DW Near Ptr MIDIAmplificationTB ; 13 + DW Near Ptr MIDICentralNoteTB ; 14 + DW Near Ptr MIDIOutputButton ; 15 + DW Near Ptr MIDISaveConfigButton ; 16 + DW Near Ptr MIDINoteOffCut ; 17 + DW Near Ptr MIDIPitchBox ; 18 + DW Near Ptr MIDIPitchToggle ; 19 + DW Near Ptr MIDIPWDInput ; 20 + DW Near Ptr MIDIEmbedBox + DW NEar Ptr MIDIEmbedToggle + DW Near Ptr SetHelpContext13 + DW 0 + +MIDIHeader DW 10 + DB "MIDI Screen (Shift-F1)", 0 + +MIDIPitchToggle DW 17 + DB 25, 27 + DW 2 + DW 2Ch ; Offset of 'Flags' + DB 64 + DW 14, 20, 0FFFFh, 0FFFFh + +MIDIEmbedToggle DW 17 + DB 25, 31 + DW 2 + DW 2Ch ; Offset of 'Flags' + DB 128 + DW 20, 15, 0FFFFh, 0FFFFh + +MIDIPWDInput DW 14 + DB 25, 28 + DW 0, 32 + DW 3, 35h + DW 19, 22, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh ; PgUp/PgDn + DW 25 + +MIDIOutputButton DW 2 + DW 22, 16, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 1 + DD DWord Ptr O1_MIDIOutputScreen + DW 0, 0, 0 + DB 2, 34, 32, 36 + DB 8 + DB 0 + DB " MIDI Output Configuration", 0 + +MIDISaveConfigButton DW 2 + DW 15, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 2 + DD DWord Ptr Music_SaveMIDIConfig + DW 0, 0, 0 + DB 2, 37, 32, 39 + DB 8 + DB 0 + DB " Save Output Configuration", 0 + +ShowMIDIInput DW 8 +MIDIIdleList DD DWord Ptr K_ShowMIDIInput + DD DWord Ptr IdleUpdateInfoLine + DD 0 + +MIDIOptionsBox DW 0 + DB 24, 14, 30, 21 + DB 27 + +MIDITranslateBox DW 0 + DB 24, 22, 51, 25 + DB 27 + +MIDIPitchBox DW 0 + DB 24, 26, 51, 29 + DB 27 + +MIDIEmbedBox DW 0 + DB 24, 30, 51, 32 + DB 27 + +MIDIOptions DW 1 + DB 7, 15 + DB 20h + DB 0FFh, 4, " Tick quantize", 13 + DB " Base Program 1", 13 + DB " Record Note-Off", 13 + DB " Record Velocity", 13 + DB "Record Aftertouch", 13 + DB 0FFh, 5, " Cut note off", 13 + DB 13 + DB 13 + DB 0FFh, 4, " Amplification", 13 + DB " C-5 Note-value", 13 + DB 13 + DB 13 + DB "Output MIDI pitch", 13 + DB "Pitch wheel depth", 13 + DB 13 + DB 13 + DB " Embed MIDI data", 0 + +ProgramChangeToggle DW 17 + DB 25, 15 + DW 1, Offset CentraliseCursor + DB 8 + DW 0FFFFh, 8, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +Program1Toggle DW 17 + DB 25, 16 + DW 1, Offset CentraliseCursor + DB 16 + DW 7, 9, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +RecordNoteOffToggle DW 17 + DB 25, 17 + DW 1, Offset CentraliseCursor + DB 32 + DW 8, 10, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +RecordVelocityToggle DW 17 + DB 25, 18 + DW 1, Offset CentraliseCursor + DB 64 + DW 9, 11, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +RecordAfterTouchToggle DW 17 + DB 25, 19 + DW 1, Offset CentraliseCursor + DB 128 + DW 10, 17, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +MIDINoteOffCut DW 17 + DB 25, 20 + DW 1, Offset Flags + DB 2 + DW 11, 13, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +MIDIAmplificationTB DW 9 + DB 25, 23 + DW 0, 200 + DW 1, Offset MIDIAmplification + DW 17, 14, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +MIDICentralNoteTB DW 14 + DB 25, 24 + DW 0, 127 + DW 1, Offset MIDICentralNote + DW 13, 19, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 25 + +; + +IF TIMERSCREEN + +O1_TimerList DW 5 + DW Near Ptr InfoPageIdleList + DW Near Ptr GlobalKeyList + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader ; 1 + DW Near Ptr FillHeader ; 2 + DW Near Ptr TimerHeader + DW Near Ptr TimerText ; 4 + DW Near Ptr DrawTimer + DW Near Ptr Divider + DW Near Ptr SetHelpContext0 + DW 0 + +TimerHeader DW 10 + DB "Time Information", 0 + +TimerText DW 1 + DB 2, 13 + DB 20h + DB 0FFh, 4, " Module time:", 13 + DB "Current session:", 13 + DB 13 + DB 0FFh, 5, " Total time:", 0 + +DrawTimer DW 15 + DD DWord Ptr D_DrawTimer + DD DWord Ptr F_Nothing + DD DWord Ptr D_PostTimerList + +Divider DW 1 + DB 1, 18 + DB 20h + DB 0FFh, 78, 09Ah, 0 + +ENDIF + +; + +O1_StereoSampleList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr LRKeyList + DW Near Ptr StereoSampleBox ; 0 + DW Near Ptr StereoSampleText + DW Near Ptr StereoButtonLeft ; 2 + DW Near Ptr StereoButtonRight ; 3 + DW 0 + +LRKeyList DB 8 + DW 'L' + DD DWord Ptr F_Return64 + + DB 8 + DW 'R' + DD DWord Ptr F_Return192 + + DB 0FFh + +StereoSampleBox DW 0 + DB 26, 22, 54, 29 + DB 3 + +StereoSampleText DW 1 + DB 30, 24 + DB 20h + DB "Loading Stereo Sample", 0 + +StereoButtonLeft DW 2 + DW 0FFFFh, 0FFFFh, 3, 3 + DW 0 + DW 0, 0 ; Unused + DW 0 ; Return + DW 64 + DW 0, 0, 0, 0 ; Unused + DB 30, 26, 39, 28 + DB 8 + DB 0 + DB " Left", 0 + +StereoButtonRight DW 2 + DW 0FFFFh, 0FFFFh, 2, 2 + DW 0 + DW 0, 0 ; Unused + DW 0 ; Return + DW 64+128 + DW 0, 0, 0, 0 ; Unused + DB 40, 26, 50, 28 + DB 8 + DB 0 + DB " Right", 0 + +; + +O1_ShowTime DW 2 + DW 0 + DW Near Ptr ESCReturnList + DW Near Ptr NBMBox + DW Near Ptr ShowTime + DW Near Ptr OKButton + DW Near Ptr SongLengthText + DW 0 + +SongLengthText DW 1 + DB 27, 27 + DB 20h + DB "Total song time: ", 0 + +ShowTime DW 8 + DD Music_ShowTime + +; + +IF SPECTRUMANALYSER +O1_FourierDisplay DW 0 +; DW Near Ptr FourierIdleList + DW Near Ptr InfoPageIdleList + DW Near Ptr FourierKeyList + DW Near Ptr FourierDisplay + DW 0 + +;FourierIdleList DD DWord Ptr Fourier_IdleList +; DD 0 + +FourierKeyList DB 1 + DW '-' + DD DWord Ptr DisplayMinus + + DB 1 + DW '+' + DD DWord Ptr DisplayPlus + + DB 0 + DW 13Fh + DD DWord Ptr Glbl_Ctrl_F5 + + DB 1 + DW 'p' + DD DWord Ptr Fourier_ChangePalette + + DB 5 + DW Near Ptr PlayCommandChain + +FourierDisplay DW 15 + DD DWord Ptr Fourier_PreDrawScreen + DD DWord Ptr Fourier_DrawScreen + DD DWord Ptr Fourier_PostFunction + +ENDIF + +; + +EndS + +End diff --git a/it/IT_PE.ASM b/it/IT_PE.ASM new file mode 100644 index 0000000..cba174d --- /dev/null +++ b/it/IT_PE.ASM @@ -0,0 +1,12312 @@ +;Ŀ +; PatternEdit module +; + + Jumps + .386 + +include switch.inc + +include network.inc + +;Ŀ +; Externals +; + +Segment Object1 BYTE Public 'Data' +EndS + +Segment Disk BYTE Public 'Code' +EndS + +Segment Inst BYTE Public 'Code' + Extrn InstrumentEdit:Byte + Extrn NodeHeld:Byte +EndS + + Extrn E_GetFreeEMS:Far + Extrn E_UnInitEMS:Far + Extrn E_ReleaseEMS:Far + Extrn E_AllocateEMS:Far + Extrn E_MapAvailableEMSMemory:Far + Extrn E_GetEMSPageFrame:Far + + Extrn Glbl_F2:Far, Glbl_F6:Far + Extrn Glbl_GetHeaderMode:Far + Extrn Glbl_LeftBrace:Far, Glbl_RightBrace:Far + Extrn Glbl_LeftSquareBracket:Far, Glbl_RightSquareBracket:Far + + Extrn I_ClearTables:Far + + Extrn K_UnInitKeyBoard:Far + Extrn K_SetScrollLock:Far + Extrn K_IsKeyDown:Far + + Extrn M_FunctionHandler:Far + Extrn M_Object1List:Far + Extrn M_FunctionDivider:Far + + Extrn Music_PlayPartSong:Far + Extrn Music_GetSongSegment:Far + Extrn Music_UnInitMusic:Far + Extrn Music_ReleasePattern:Far + Extrn Music_AllocatePattern:Far + Extrn Music_GetPattern:Far + Extrn Music_GetInstrumentMode:Far + Extrn Music_UpdatePatternOffset:Far + Extrn Music_PlayNote:Far + Extrn Music_InitMixTable:Far + Extrn Music_InitMuteTable:Far + Extrn Music_InitStereo:Far + Extrn Music_ToggleChannel:Far + Extrn Music_SoloChannel:Far + Extrn Music_GetPlayMode:Far + Extrn Music_PlayPattern:Far + Extrn Music_GetLastChannel:Far + Extrn Music_SetNextOrder:Far + Extrn Music_NextOrder:Far + Extrn Music_LastOrder:Far + Extrn Music_Stop:Far + + Extrn Music_UnmuteAll:Far + + Extrn Music_SoundCardLoadSample:Far + Extrn Music_SoundCardLoadAllSamples:Far + Extrn Music_GetDisplayVariables:Far + + Extrn Network_UpdatePattern:Far + + Extrn FileName:Byte + + Extrn O1_ConfirmNoSave:Far + Extrn O1_NoBlockMarkedList:Far + Extrn O1_SwapOutOfRangeList:Far + Extrn O1_OverlapBlockList:Far + Extrn O1_OutOfMemoryList:Far + Extrn O1_NoBlockDataList:Far + Extrn O1_GetAmpList:Far + Extrn O1_GetFastAmpList:Far + +IF SHOWPATTERNLENGTH + Extrn O1_ShowPatternLengthList:Far +ENDIF + + Extrn O1_TemplateErrorList:Far + Extrn O1_PatternTooLongList:Far + Extrn O1_SelectMultiChannel:Far + Extrn O1_UndoList:Far + Extrn O1_SetPatternLength:Far + Extrn O1_PatternSizeMismatchList:Far + + Extrn S_UnInitScreen:Far + Extrn S_DrawBox:Far + Extrn S_DrawString:Far + Extrn S_GetDestination:Far + Extrn S_SaveScreen:Far + Extrn S_RestoreScreen:Far + Extrn S_SetDirectMode:Far + Extrn S_DrawSmallBox:Far + Extrn S_InvertCursor:Far + + Extrn PatternLength + + Extrn UpdateInfoLine:Far + Extrn SetInfoLine:Far + Extrn MouseUpdateDisable:Far + Extrn UpdateWAVEForm:Far + + Extrn MIDI_AllocateChannel:Far, MIDI_FindChannel:Far + Extrn Music_GetDelay:Far, MIDI_GetChannel:Far + +;Ŀ +; Globals +; + + Global PE_ClearUndoBuffer:Far + + Global PE_ShowOrder:Far + Global PE_NewPattern:Far + + Global PE_InitPatternEdit:Far + Global PE_UnInitPatternEdit:Far + Global PE_DrawOrderList:Far + Global PE_FillHeader:Far + Global PE_PreOrderList:Far + Global PE_PostOrderList:Far + Global PE_ConvAX2Num:Far + Global PE_GetCurrentPattern:Far + Global PE_GetMaxPattern:Far + Global PE_FillSpeedTempo:Far + + Global PE_SetPatternModified:Far + Global PE_GetLastInstrument:Far + Global PE_DrawPatternEdit:Far + Global PE_PrePatternEdit:Far + Global PE_PostPatternEdit:Far + Global PE_SetCommandCursor:Far + Global PEFunction_IncreaseOctave:Far + Global PEFunction_DecreaseOctave:Far + + Global PE_F7:Far + + Global PE_GetPatternConfigOffset:Far + + Global PE_SwapInstruments:Far + Global PE_GetMaxOrder:Far + Global PE_GotoPattern:Far + Global PECheckModified:Far + + Global PE_TranslateXMPattern:Far + Global PE_TranslateS3MPattern:Far + Global PE_TranslateMODPattern:Far + Global PE_TranslateMTMPattern:Far + Global PE_Translate669Pattern:Far + Global PE_ResetOrderPattern:Far + Global PEFunction_OutOfMemoryMessage:Far + Global PE_UpdateInstruments:Far + + Global PEFunction_DrawUndo:Far + Global PEFunction_PreUndo:Far + Global PEFunction_PostUndo:Far + Global PEResetModified:Far + + Global PE_SaveCurrentPattern:Far + Global PE_RestoreCurrentPattern:Far + Global PEFunction_StoreCurrentPattern:Far + + Global BaseOctave + Global SkipValue + Global RowHiLight1:Byte + Global RowHiLight2:Byte + Global MaxRow:Word + Global NumberOfRows:Word + Global Amplification + Global FastVolumeAmplification + Global CommandToValue:Byte + Global LastInstrument:Byte + Public MultiChannelInfo + Public PatternDataArea + Public Order, CentraliseCursor + Public PatternSetLength, PatternLengthStart, PatternLengthEnd + Public MIDI_SetInstrument, PE_TranslateMIDI + Public MIDIAmplification, MIDICentralNote, PE_RestoreMIDINote + Public PE_InsertInstrument, PE_DeleteInstrument + Public Flags, Modified, PatternModified + + Public LastKeyBoard1, PatternNumber + +; + +Segment Pattern WORD Public 'Code' USE16 + Assume CS:Pattern, DS:Nothing + +CREATENEWLOGFILE EQU 0 +include debug.inc + +;Ŀ +; Variables +; + +NONOTE EQU 0FDh +MAXNOTE EQU 119 + +;PatternSize DW 0 +;PatternEnd DW 0 +PatternDataArea DW PatternData + +TempVariableArea DW 0 +TempVariableArea2 DW 0 +TempVariableArea3 DW 0 +TempVariableArea4 DW 0 +TempVariableArea5 DW 0 +TempVariableArea6 DW 0 + +TopOrder DW 0 +Order DW 0 +OrderCursor DW 0 +PatternNumber DW 0 +TopRow DW 0 +Row DW 0 +MaxRow DW 63 +NumberOfRows DW 64 + +LeftChannel DW 0 +Channel DW 0 +MIDIChannel DW 0 +PatternCursor DW 0 +BaseOctave DW 4 +SkipValue DW 1 +MultiChannelInfo DB 64 Dup (0) +BlockMark DW 0 ; 0 if no block marked, 1 if block is marked +BlockLeft DW 0 +BlockTop DW 0 +BlockRight DW 0 +BlockBottom DW 0 +BlockDataArea DW 0 +BlockAnchorChannel DW 0 +BlockAnchorRow DW 0 +BlockReset DW 0 +LastKeyBoard1 DW 0, 0 +LastKeyBoard2 DW 0, 0 +LastKeyBoard3 DW 0, 0 + +EmptyRow DB 64 Dup ( NONOTE, 0, 0FFh, 0, 0 ) + +KeyBoardTable DW 12Ch, 0, 11Fh, 1, 12Dh, 2, 120h, 3, 12Eh, 4 + DW 12Fh, 5, 122h, 6, 130h, 7, 123h, 8, 131h, 9 + DW 124h, 10, 132h, 11, 110h, 12, 103h, 13, 111h, 14 + DW 104h, 15, 112h, 16, 113h, 17, 106h, 18, 114h, 19 + DW 107h, 20, 115h, 21, 108h, 22, 116h, 23, 117h, 24 + DW 10Ah, 25, 118h, 26, 10Bh, 27, 119h, 28 + DW 0FFFFh + +MODPeriodTable DW 1712, 1616, 1525, 1440, 1357, 1281 ; Octave 0 + DW 1209, 1141, 1077, 1017, 961, 907 + DW 856, 808, 762, 720, 678, 640 ; Octave 1 + DW 604, 570, 538, 508, 480, 453 + DW 428, 404, 381, 360, 339, 320 ; Octave 2 + DW 302, 285, 269, 254, 240, 226 + DW 214, 202, 190, 180, 170, 160 ; Octave 3 + DW 151, 143, 135, 127, 120, 113 + DW 107, 101, 95, 90, 85, 80 ; Octave 4 + DW 75, 71, 67, 63, 60, 56 + DW 53, 50, 47, 45, 42, 40 ; Octave 5 + DW 37, 35, 33, 31, 30, 28 + +Amplification DW 100 + +PlayMarkPattern DW 0 +PlayMarkRow DW 0 +PlayMarkOn DB 0 +VolumePan DB 0 + +UndoBuffer DW 20 Dup (0) ; Word for segment, word for + ; type: + +UndoBufferTypes Label Word + DW Offset UndoBufferType0, Offset UndoBufferType1 + DW Offset UndoBufferType2, Offset UndoBufferType3 + DW Offset UndoBufferType4, Offset UndoBufferType5 + DW Offset UndoBufferType6, Offset UndoBufferType7 + DW Offset UndoBufferType8, Offset UndoBufferType9 + DW Offset UndoBufferType10, Offset UndoBufferType11 + DW Offset UndoBufferType12, Offset UndoBufferType13 + DW Offset UndoBufferType14, Offset UndoBufferType15 + DW Offset UndoBufferType16, Offset UndoBufferType17 + DW Offset UndoBufferType18, Offset UndoBufferType19 + DW Offset UndoBufferType20, Offset UndoBufferType21 + DW Offset UndoBufferType22 + +UndoBufferType0 DB "Empty", 0 +UndoBufferType1 DB "Undo revert pattern data (Alt-BkSpace)", 0 +UndoBufferType2 DB "Undo transposition up", 0FFh, 10, " (Alt-Q)", 0 +UndoBufferType3 DB "Undo transposition down", 0FFh, 8, " (Alt-A)", 0 +UndoBufferType4 DB "Undo block length double", 0FFh, 7, " (Alt-F)", 0 +UndoBufferType5 DB "Undo block length halve", 0FFh, 8, " (Alt-G)", 0 +UndoBufferType6 DB "Undo volume amplification", 0FFh, 6, " (Alt-J)", 0 +UndoBufferType7 DB "Undo volume or panning slide (Alt-K)", 0 +UndoBufferType8 DB "Recover volumes/pannings", 0FFh, 5, " (2*Alt-K)", 0 +UndoBufferType9 DB "Replace mixed data", 0FFh, 13, " (Alt-M)", 0 +UndoBufferType10 DB "Replace overwritten data", 0FFh, 7, " (Alt-O)", 0 +UndoBufferType11 DB "Undo paste data", 0FFh, 16, " (Alt-P)", 0 +UndoBufferType12 DB "Undo set sample/instrument", 0FFh, 5, " (Alt-S)", 0 +UndoBufferType13 DB "Undo set volume/panning", 0FFh, 8, " (Alt-V)", 0 +UndoBufferType14 DB "Replace extra volumes/pannings (Alt-W)", 0 +UndoBufferType15 DB "Undo effect data slide", 0FFh, 9, " (Alt-X)", 0 +UndoBufferType16 DB "Recover effects/effect data (2*Alt-X)", 0 +UndoBufferType17 DB "Undo swap block", 0FFh, 16, " (Alt-Y)", 0 +UndoBufferType18 DB "Undo block cut", 0FFh, 17, " (Alt-Z)", 0 +UndoBufferType19 DB "Remove inserted row(s)", 0FFh, 4, " (Alt-Insert)", 0 +UndoBufferType20 DB "Replace deleted row(s)", 0FFh, 4, " (Alt-Delete)", 0 +UndoBufferType21 DB "Redo", 0FFh, 28, " (Undo)", 0 +UndoBufferType22 DB "Pattern ", 0FDh, "D", 0 + +SelectUndo DW 0 +ShiftPressed DB 0 +NoteEntered DB 0 + +PreviewNote DB 0, 0, 0FFh, 0, 0 + +Modified DB 0 ; } Order important +PatternModified DB 0 ; } + +MIDIPlayTrigger DB 0 ; 0 = nothing, 1 = play + ; pattern, 2 = play song. + +CompleteMsg DB 0FDh, "D% Complete", 0 +Template DB 0 +TemplateMsg1 DB "Template, Overwrite", 0 +TemplateMsg2 DB "Template, Mix - Pattern data precedence", 0 +TemplateMsg3 DB "Template, Mix - Clipboard data precedence", 0 +TemplateMsg4 DB "Template, Notes only", 0 +TriggerMsg1 DB "No MIDI Trigger", 0 +TriggerMsg2 DB "Pattern MIDI Trigger", 0 +TriggerMsg3 DB "Song MIDI Trigger", 0 +NextOrderMsg DB "Playing order ", 0FDh, "D next", 0 +CursorStepMSg DB "Cursor step set to ", 0FDh, "D", 0 + +EncodingInfo DB 384 Dup (0) +PatternSetLength DW 64 +PatternLengthStart DW 0 +PatternLengthEnd DW 0 +TempData DB 320 Dup (0) + +PEFunctions Label Word + DB 0 + DW 11Ch ; Enter + DW Offset PEFunction_PickUp + +IF SHOWPATTERNLENGTH + DB 0 + DW 111Ch ; Right Ctrl+Enter + DW Offset PE_ShowPatternLength +ENDIF + + DB 1 + DW '{' + DW Near Ptr PE_LeftBrace + + DB 1 + DW '}' + DW Near Ptr PE_RightBrace + + DB 1 + DW '[' + DW Near Ptr PE_LeftSquareBracket + + DB 1 + DW ']' + DW Near Ptr PE_RightSquareBracket + + DB 0 + DW 1C8h + DW Offset PEFunction_Up + + DB 0 + DW 1D0h + DW Offset PEFunction_Down + + DB 0 + DW 1CBh + DW Offset PEFunction_Left + + DB 0 + DW 1CDh + DW Offset PEFunction_Right + + DB 0 + DW 1C9h + DW PEFunction_PgUp + + DB 0 + DW 1D1h + DW PEFunction_PgDn + + DB 2 + DW 1C7h + DW Offset PEFunction_Alt_Home + + DB 2 + DW 1CFh + DW Offset PEFunction_Alt_End + + DB 0 + DW 1C7h + DW Offset PEFunction_Home + + DB 0 + DW 1CFh + DW Offset PEFunction_End + + DB 3 + DW 1C9h + DW PEFunction_Ctrl_PgUp + + DB 3 + DW 1D1h + DW PEFunction_Ctrl_PgDn + + DB 2 ; Alt... + DW 1CBh ; Left Arrow + DW Offset PEFunction_AltLeft + + DB 2 ; Alt... + DW 1CDh ; Right Arrow + DW Offset PEFunction_AltRight + + DB 3 ; Ctrl... + DW 1CBh ; Left Arrow + DW Offset PEFunction_ViewLeft + + DB 3 + DW 1CDh + DW Offset PEFunction_ViewRight + + DB 2 ; Alt... + DW 1C8h ; Up Arrow + DW Offset PEFunction_AltUp + + DB 2 + DW 1D0h + DW Offset PEFunction_AltDown + + DB 3 + DW 1C7h + DW Offset PEFunction_Ctrl_Home + + DB 3 + DW 1CFh + DW Offset PEFunction_Ctrl_End + + DB 4 + DW 1C8h + DW Offset PEFunction_Up + + DB 4 + DW 1D0h + DW Offset PEFunction_Down + + DB 4 + DW 1CBh + DW Offset PEFunction_AltLeft + + DB 4 + DW 1CDh + DW Offset PEFunction_AltRight + + DB 4 + DW 1C9h + DW PEFunction_ShiftPgUp + + DB 4 + DW 1D1h + DW PEFunction_ShiftPgDn + + DB 4 + DW 1C7h + DW Offset PEFunction_Home + + DB 4 + DW 1CFh + DW Offset PEFunction_End + + DB 4 + DW 12Ah + DW Offset PEFunction_Press_Shift + + DB 4 + DW 136h + DW Offset PEFunction_Press_Shift + + DB 0 + DW 2Ah + DW Offset PEFunction_Release_Shift + + DB 0 + DW 36h + DW Offset PEFunction_Release_Shift + + DB 0 + DW 10Fh + DW Offset PEFunction_Tab + + DB 4 + DW 10Fh + DW Offset PEFunction_ShiftTab + + DB 1 + DW ',' + DW Offset PEFunction_SetMask + + DB 0 + DW 1D2h + DW Offset PEFunction_Insert + + DB 0 + DW 1D3h ; Delete + DW Offset PEFunction_Delete + + DB 2 ; Alt... + DW 1D2h ; Insert + DW Offset PEFunction_RowInsert + + DB 2 ; Alt... + DW 1D3h ; Delete + DW Offset PEFunction_RowDelete + + DB 3 ; Ctrl... + DW 1D2h ; Insert + DW Offset PEFunction_RollDown + + DB 3 ; Ctrl... + DW 1D3h ; Delete + DW Offset PEFunction_RollUp + + DB 0 + DW 10Eh + DW Offset PEFunction_BackSpace + + DB 3 ; Ctrl... + DW 10Eh ; Backspace + DW Offset PEFunction_Undo + + DB 1 + DW '<' + DW Offset PEFunction_DecreaseInstrument + + DB 1 + DW '>' + DW Offset PEFunction_IncreaseInstrument + + DB 1 + DW ';' + DW Offset PEFunction_DecreaseInstrument + + DB 1 + DW "'" + DW Offset PEFunction_IncreaseInstrument + + DB 3 ; Ctrl + DW 1C8h + DW Offset PEFunction_DecreaseInstrument + + DB 3 + DW 1D0h + DW Offset PEFunction_IncreaseInstrument + + DB 1 + DW 3000h ; Alt 'B' + DW Offset PEFunction_MarkBeginBlock + + DB 1 + DW 3100h ; Alt 'N' + DW Offset PEFunction_ToggleMultiChannel + + DB 1 + DW 1200h ; Alt 'E' + DW Offset PEFunction_MarkEndBlock + + DB 1 + DW 1600h ; Alt 'U' + DW Offset PEFunction_UnMarkBlock + + DB 1 + DW 1700h ; Alt 'I' + DW Offset PEFunction_ToggleTemplate + + DB 1 + DW ':' + DW Offset PEFunction_TemplateOff + + DB 1 + DW 2000h ; Alt 'D' + DW Offset PEFunction_AltD + + DB 1 + DW 1F00h ; Alt 'S' + DW Offset PEFunction_AltS + + DB 1 + DW 2500h ; Alt 'K' + DW Offset PEFunction_AltK + + DB 1 + DW 2C00h ; Alt 'Z' + DW Offset PEFunction_WipeBlock + + DB 1 + DW 2600h ; Alt 'L' + DW Offset PEFunction_AltL + + DB 1 + DW 1800h ; Alt 'O' + DW Offset PEFunction_BlockOverwrite + + DB 1 + DW 1900h ; Alt 'P' + DW Offset PEFunction_BlockPaste + + DB 1 + DW 2E00h ; Alt 'C' + DW Offset PEFunction_BlockCopy + + DB 1 + DW 3h ; Ctrl 'C' + DW Offset PEFunction_ToggleCentralise + + DB 0 + DW 146h ; Scroll Lock + DW Offset PEFunction_ToggleTrace + + DB 2 ; Alt Scroll Lock + DW 146h + DW Offset MIDIInputToggle + + DB 1 + DW 3200h ; Alt 'M' + DW Offset PEFunction_BlockMix + + DB 1 + DW 1000h ; Alt 'Q' + DW Offset PEFunction_SemiUp + + DB 1 + DW 1E00h ; Alt 'A' + DW Offset PEFunction_SemiDown + + DB 1 + DW 2D00h ; Alt 'X' + DW Offset PEFunction_WipeCommands + + DB 1 + DW 2400h ; Alt 'J' + DW Offset PEFunction_VolumeAmp + + DB 1 ; Ctrl... + DW 0Ah ; 'J' + DW Offset ToggleFastVolume + + DB 1 + DW 2F00h ; Alt 'V' + DW Offset PEFunction_BlockVolume + + DB 1 + DW 1100h ; Alt 'W' + DW Offset PEFunction_WipeExcessVolumes + + DB 1 + DW 1400h ; Alt 'T' + DW Offset PEFunction_ViewTrack + + DB 1 ; Ctrl... + DW 14h ; 'T' + DW Offset PEFunction_ToggleTracking + + DB 1 ; Ctrl... + DW 8h ; 'H' + DW Offset PEFunction_ToggleRowHilight + + DB 1 + DW 2300h ; Alt 'H' + DW Offset PEFunction_ToggleDivision + + DB 1 + DW 1300h ; Alt 'R' + DW Offset PEFunction_ClearViews + + DB 1 + DW 1500h ; Alt 'Y' + DW Offset PEFunction_BlockSwap + + DB 1 + DW 2200h ; Alt 'G' + DW Offset PEFunction_BlockHalve + + DB 1 + DW 2100h ; Alt 'F' + DW Offset PEFunction_BlockDouble + +; DB 0 +; DW 14Eh ; Grey Plus +; DW Offset PEFunction_NextPattern +; +; DB 0 +; DW 14Ah ; Grey Minus +; DW Offset PEFunction_LastPattern + + DB 4 ; Shift + DW 14Eh + DW Offset PEFunction_Next4Patterns + + DB 4 + DW 14Ah + DW Offset PEFunction_Last4Patterns + + DB 3 ; Ctrl.. + DW 14Eh ; Grey Plus + DW Offset PEFunction_NextOrderPattern + + DB 3 ; Ctrl.. + DW 14Ah ; Grey Minus + DW Offset PEFunction_LastOrderPattern + + DB 1 + DW '+' + DW Offset PEFunction_NextPattern + + DB 1 + DW '-' + DW Offset PEFunction_LastPattern + + DB 3 ; Ctrl + DW 141h ; F7 + DW Offset PEFunction_SetPlayMark + + DB 2 + DW 10Bh + DW Offset PEFunction_Alt0 + + DB 2 ; Alt Backspace + DW 10Eh + DW Offset PEFunction_RestoreData + + DB 2 ; Alt.. + DW 11Ch ; Enter + DW Offset PEFunction_StoreCurrentPattern + + DB 0 + DW 0B02h ; Left-Shift, Left-Ctrl '1' + DW Offset PEFunction_Ctrl_Shift1 + + DB 0 + DW 0B03h ; Left-Shift, Left-Ctrl '2' + DW Offset PEFunction_Ctrl_Shift2 + + DB 0 + DW 0B04h ; Left-Shift, Left-Ctrl '3' + DW Offset PEFunction_Ctrl_Shift3 + + DB 0 + DW 0B05h ; Left-Shift, Left-Ctrl '4' + DW Offset PEFunction_Ctrl_Shift4 + + DB 3 ; Ctrl.. + DW 10Bh ; '0' + DW Offset PEFunction_Ctrl0 + + DB 3 ; Ctrl... + DW 102h ; '1' + DW Offset PEFunction_Ctrl1 + + DB 3 ; Ctrl... + DW 103h ; '2' + DW Offset PEFunction_Ctrl2 + + DB 3 ; Ctrl... + DW 104h ; '3' + DW Offset PEFunction_Ctrl3 + + DB 3 ; Ctrl... + DW 105h ; '4' + DW Offset PEFunction_Ctrl4 + + DB 3 ; Ctrl... + DW 106h ; '5' + DW Offset PEFunction_Ctrl5 + + DB 1 + DW '\' + DW Offset PEFunction_Alt_F9 + + DB 0 + DW 135h + DW Offset PEFunction_MuteNext + + DB 1 + DW '?' + DW Offset PEFunction_MutePrevious + + DB 2 ; Alt + DW 143h ; F9 + DW Offset PEFunction_Alt_F9 + + DB 1 + DW '|' + DW Offset PEFunction_SoloGotoNext + + DB 2 ; Alt \ + DW 12Bh + DW Offset PEFunction_UnmuteAll + + DB 2 ; Alt + DW 144h ; F10 + DW Offset PEFunction_Alt_F10 + + DB 3 ; Ctrl + DW 140h ; F6 + DW Offset PE_PlayCurrentPosition + + DB 3 ; Ctrl + DW 13Ch ; F2 + DW Offset PE_SetPatternLength + + DB 1 ; Ctrl 'V' + DW 16h + DW Offset PE_ToggleDefaultVolume + + DB 1 ; Ctrl 'Z' + DW 1Ah + DW Offset PE_CycleMIDIPlayTrigger + + DB 6 ; MIDI message + DW 8000h + DW Offset PE_MIDINoteOff + + DB 6 ; MIDI message + DW 9000h + DW Offset PE_MIDINote + + DB 6 ; MIDI message + DW 0A000h + DW Offset PE_MIDIAftertouch + + DB 0FFh + +CursorPositions DB 0, 2, 4, 5, 7, 8, 10, 11, 12 + DB 0, 2, 3, 4, 5, 6, 7, 8, 9 + DB 0, 2, 3, 3, 4, 4, 5, 6, 6 + + DB 20h, 2, 1, 2, 1, 2, 0, 1, 2 + DB 10h, 1, 0, 1, 0, 1, 0, 1, 1 + +MaskChange DB 0, 0, 1, 1, 2, 2, 4, 4, 4 +ChannelMsg DB " Channel xx ", 0 +ChannelMsg2 DB "Channel xx", 0 +ChannelMsg3 DB " Chnl xx", 0 +ChannelMsg4 DB " xx", 0 +ChannelMsg5 DB "xx", 0 +ChannelMsg6 DB "Ch xx", 0 +ChannelMsg7 DB "Chnl xx", 0 + +NoteNames Label Byte + DB "C-C#D-D#E-F-F#G-G#A-A#B-" ; Cmaj +StartChannelEdit DW 5 + + +; +; Don't change order of variables within here!!!! + +KeySignature DW 0 +NumChannelsEdit DW 5 + +RowHiLight1 DB 4 +RowHiLight2 DB 16 + +EditMask DB 3 ; Bit 0 = ins + ; Bit 1 = vol + ; Bit 2 = commands +ViewDivision DB 1 +ViewWidth DW 0 +ViewChannels DW 100 Dup (0FFFFh) ; Contains channel/viewmethod +ViewChannelTracking DB 0 +CommandToValue DB 0 +CentraliseCursor DB 0E8h ; Bit 0 = centralise cursor + ; Bit 1 = hilight row + ; Bit 2 = fast volume changes + ; Bit 3 = Record tick base + ; Bit 4 = Program base 1 + ; Bit 5 = Record note off + ; Bit 6 = Record velocity + ; Bit 7 = Record aftertouch +MIDIAmplification DB 100 +MIDICentralNote DB 60 +FastVolumeAmplification DW 67 +Flags DB 0 ; Extra flags + ; Bit 0 = display defaults. + ; Bit 1 = Record note cuts. + +; + +ViewMethodInfo Label + DW Offset ViewFull + DW 13 ; Width + + DW Offset ViewCompress + DW 10 ; Width + + DW Offset ViewAllSmall + DW 7 + + DW Offset ViewNote + DW 3 + + DW Offset ViewTiny + DW 2 + +EmptyData DB 253, 0, 255, 0, 0 + +TempNumbers DB 3 Dup (0) + +ErrorMsg DB "Unable to allocate memory for pattern edit area.", 13, 10 + DB "Sorry, more conventional memory is required to run this program.", 13, 10, "$" + +ViewChannelTrackingMsg DB "View-Channel cursor tracking enabled", 0 +NoViewChannelTrackingMsg DB "View-Channel cursor tracking disabled", 0 +CentraliseCursorMsg DB "Centralise cursor enabled", 0 +NoCentraliseCursorMsg DB "Centralise cursor disabled", 0 +TraceMsg DB "Playback tracing enabled", 0 +NoTraceMsg DB "Playback tracing disabled", 0 +PanningControlSetMsg DB "Panning control set", 0 +VolumeControlSetMsg DB "Volume control set", 0 +NoRowHilightMsg DB "Row hilight disabled", 0 +RowHilightMsg DB "Row hilight enabled", 0 +NoFastVolumeMsg DB "Alt-I / Alt-J fast volume changes disabled", 0 +FastVolumeMsg DB "Alt-I / Alt-J fast volume changes enabled", 0 +FastVolumeNotEnabledMsg DB "Alt-I / Alt-J fast volume changes not enabled", 0 +DefaultVolumeOn DB "Default volumes enabled", 0 +DefaultVolumeOff DB "Default volumes disabled", 0 +MIDIInputDisabledMsg DB "MIDI Input Disabled", 0 +MIDIInputEnabledMsg DB "MIDI Input Enabled", 0 +MIDIInputEnabled DB 1 + +LastNote DB 60 +LastInstrument DB 1 +LastVolume DB 0FFh +LastCommand DB 0 +LastCommandValue DB 0 +TracePlayback DB 0 + +OrderListKeys Label + +IF ORDERSORT + DB 1 + DW 1300h ; Alt-R + DW Offset PE_PostOrderListReorder +ENDIF + + DB 0 + DW 10Fh + DW Offset PE_PostOrderList20 + + DB 1 + DW 0F00h + DW Offset PE_PostOrderList21 + + DB 3 ; Ctrl-F7 + DW 141h + DW Offset PE_PostOrderListNextOrder + + DB 1 ; Spacebar + DW ' ' + DW Offset PE_PostOrderListNextOrder + + DB 0 + DW 1C8h ; Up + DW Offset PE_PostOrderList1 + + DB 0 + DW 1D0h ; Down + DW Offset PE_PostOrderList3 + + DB 0 + DW 1C9h ; PgUp + DW Offset PE_PostOrderList4 + + DB 0 + DW 1D1h ; PgDn + DW Offset PE_PostOrderList6 + + DB 0 + DW 1CBh ; Left + DW Offset PE_PostOrderList7 + + DB 0 + DW 1CDh ; Right + DW Offset PE_PostOrderList9 + + DB 5 + DW 'G' + DW Offset PE_PostOrderList24 + + DB 1 + DW '-' + DW Offset PE_PostOrderList16 + + DB 1 + DW '+' + DW Offset PE_PostOrderList17 + + DB 0 + DW 1D3h ; Insert + DW Offset PE_PostOrderList18 + + DB 0 + DW 1D2h ; Delete + DW Offset PE_PostOrderList19 + + DB 0 + DW 1CFh ; End + DW PE_PostOrderListEndKey + + DB 0 + DW 1C7h + DW PE_PostOrderListHomeKey + + DB 5 + DW 'N' + DW PE_PostOrderList22 + + DB 0FFh + +;Ŀ +; Functions +; + +Proc PE_ConvAX2Num Far ; ES:DI points to screen + ; CH = colour + ; AX = number + + Push AX + Push BX + Push DX + + Mov BX, 10 + + And AX, AX + JNS PE_ConvAX2Num1 + + Mov Byte Ptr [ES:DI], '-' + Inc DI + Neg AX + Mov [ES:DI], CH + Inc DI + Jmp PE_ConvAX2Num2 + +PE_ConvAX2Num1: + Xor DX, DX + Div BX + Add DL, '0' + Mov DH, CH + Mov [ES:DI+4], DX + +PE_ConvAX2Num2: + Xor DX, DX + Div BX + Add DL, '0' + Mov DH, CH + Mov [ES:DI+2], DX + + Xor DX, DX + Div BX + Add DL, '0' + Mov DH, CH + Mov [ES:DI], DX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP PE_ConvAX2Num + +; + +Proc PE_ConvHexAL Near + + Cmp AL, 10 + SBB AL, 69h + DAS + StosW + + Ret + +EndP PE_ConvHexAL + +; + +Proc PE_GetMaxOrder Far ; Returns AX with max order + + Push CX + Push ES + Push DI + + Call Music_GetSongSegment + Mov ES, AX + Mov DI, 256 + Mov CX, 257 + Mov AL, 0FFh + RepNE ScasB + Mov AX, 256 + Sub AX, CX + + And AX, AX + JZ PE_GetMaxOrder1 + + Dec AX + +PE_GetMaxOrder1: + Pop DI + Pop ES + Pop CX + + Ret + +EndP PE_GetMaxOrder + +; + +Proc ClearEncodingInfo ; Encoding info + ; 1.Mask, 2.Instrument, 3.Volume, 4.Cmd + ; 5.CmdVal, 6.Note + + Push CS + Pop ES + + Mov DI, Offset EncodingInfo + + Mov CX, 64 + +ClearEncodingInfo1: + Mov AX, NONOTE*100h ; Mask&Note + StosW + Mov AH, 0FFh ; Ins&Vol + StosW + Xor AX, AX ; Cmd&Value + StosW + + Loop ClearEncodingInfo1 + + Ret + +EndP ClearEncodingInfo + +; + +IF ORDERSORT + +Proc PE_PostOrderListSwapPatterns ; Given BX = pattern 1 + ; DX = Pattern 2 + + PushA + + Mov AX, CS:PatternNumber + + Cmp AX, BX + JNE PE_PostOrderListSwapPatterns1 + Mov AX, DX + Jmp PE_PostOrderLIstSwapPatterns2 + +PE_PostOrderListSwapPatterns1: + Cmp AX, DX + JNE PE_PostOrderListSwapPatterns2 + Mov AX, BX + +PE_PostOrderListSwapPatterns2: + Mov CS:PatternNumber, AX + +; Search through order list and swap BX with DX + + Mov SI, 100h + Mov CX, SI + +PE_PostOrderListSwapPatterns3: + LodsB + + Cmp AL, BL + JNE PE_PostOrderListSwapPatterns4 + + Mov [SI-1], DL + Jmp PE_PostOrderListSwapPatterns5 + +PE_PostOrderListSwapPatterns4: + Cmp AL, DL + JNE PE_PostOrderListSwapPatterns5 + + Mov [SI-1], BL + +PE_PostOrderListSwapPatterns5: + Loop PE_PostOrderListSwapPatterns3 + +; Now swap memory references to patterns. + + LEA BX, [EBX*4+63912] + LEA DI, [EDX*4+63912] + + Mov EAX, [BX] + XChg EAX, [DI] + Mov [BX], EAX + +; Finished! + + PopA + Ret + +EndP PE_PostOrderListSwapPatterns + +; + +Proc PE_PostOrderListReorder Far + + EnsureNoNetwork + + Call Music_Stop + + Call Music_GetSongSegment + Mov DS, AX ; DS:100h = order list. + ; DS:63912 (4) = pattern data + Mov SI, 100h + Xor DX, DX ; DX = min pattern + Mov CX, SI + Xor BX, BX + +PE_PostOrderListReorder1: + LodsB + Cmp AL, 200 + JAE PE_PostOrderListReorder2 + + Cmp AL, DL + JB PE_PostOrderListReorder2 + JE PE_PostOrderListReorder3 + + Mov BL, AL + Call PE_PostOrderListSwapPatterns + +PE_PostOrderListReorder3: + Inc DX + +PE_PostOrderListReorder2: + Loop PE_PostOrderListReorder1 + +PE_PostOrderListReorderExit: + Mov AX, 1 + Ret + +EndP PE_PostOrderListReorder + Assume DS:Nothing + +ENDIF ; ORDERSORT + +; + +Proc PE_ResetOrderPattern Far + + Push CS + Pop DS + Assume DS:Pattern + + Xor AX, AX + Mov Order, AX + Mov OrderCursor, AX + Mov Channel, AX + Mov PatternCursor, AX + Mov LastInstrument, 1 + Mov PlayMarkOn, 0 + + Mov BX, AX + + Call Music_GetSongSegment + Mov ES, AX + MovZX AX, Byte Ptr [ES:BX+256] + + Cmp AX, 199 + JBE PE_ResetOrderPattern1 + + Xor AX, AX + +PE_ResetOrderPattern1: + Mov PatternNumber, AX + Call NewPattern + Mov Word Ptr [CS:Modified], 0 + + Call Music_InitMixTable ; Here 'cos it's called + ; on file loading. + Call Music_InitMuteTable ; ditto. + Call Music_InitStereo + Call Music_SoundCardLoadAllSamples + Call PE_ClearUndoBuffer + + Mov AX, Inst + Mov DS, AX + Assume DS:Inst + Mov NodeHeld, 0 + Mov InstrumentEdit, 0 + + Ret + +EndP PE_ResetOrderPattern + Assume DS:Nothing + +; + +Proc PE_GetMaxPattern Far ; Assumes DS:SongData + + Push CX + Push DS + Push SI + Push DI + + Call Music_GetSongSegment + Mov DS, AX + + Mov SI, 63912 + + Xor AX, AX + Xor DI, DI + Mov CX, 200 + +PE_GetMaxPattern1: + Cmp Word Ptr [SI], 0 + JE PE_GetMaxPattern2 + + Mov AX, DI + +PE_GetMaxPattern2: + Inc DI + Add SI, 4 + Loop PE_GetMaxPattern1 + + Pop DI + Pop SI + Pop DS + Pop CX + Ret + +EndP PE_GetMaxPattern + +; + +Proc PE_FillHeader Far + + Call Music_GetSongSegment + Mov DS, AX + Call S_GetDestination + Mov SI, 4 + Mov DI, (12+3*80)*2 + Mov CX, 25 + Mov AH, 5 + +PE_FillHeader1: + LodsB + Cmp AL, 226 + JB PE_FillHeader14 + + Mov AL, ' ' + +PE_FillHeader14: + StosW + Loop PE_FillHeader1 + + Push DS + + Mov AX, Disk + Mov DS, AX + Mov SI, Offset FileName + Mov DI, (12+4*80)*2 + Mov AH, 5 + +PE_FillHeader11: + LodsB + StosW + And AL, AL + JNZ PE_FillHeader11 + + Pop DS + + Mov CH, AH + Mov AX, Order + Mov DI, (12+5*80)*2 + Call PE_ConvAX2Num + + Call PE_GetMaxOrder + Mov DI, (16+5*80)*2 + Call PE_ConvAX2Num + + Mov AX, PatternNumber + Mov DI, (12+6*80)*2 + Call PE_ConvAX2Num + + Call PE_GetMaxPattern + Mov DI, (16+6*80)*2 + Call PE_ConvAX2Num + + Mov AX, Row + Mov DI, (12+7*80)*2 + Call PE_ConvAX2Num + + Mov AX, MaxRow + Mov DI, (16+7*80)*2 + Call PE_ConvAX2Num + + Call Glbl_GetHeaderMode + ; AL = inst + ; AH = mode. + Mov DI, (50+3*80)*2 + And AL, AL + JNZ PE_FillHeader6 + + Mov AX, 5*256+'.' + StosW + StosW + ScasW +; Add DI, 2 + Mov AL, '.' + Mov CX, 25 + Rep StosW + Jmp PE_FillHeader7 + +PE_FillHeader6: + Push AX + + Mov DL, 10 + Xor AH, AH + Mov CX, AX + Div DL + Add AX, 3030h + Mov DL, AH + Mov AH, 5 + StosW + Mov AL, DL + StosW + ScasW +; Add DI, 2 + + Pop AX + + Dec CX + And AH, AH ; CX = ins number + JZ PE_FillHeader8 + + ; Complex instrument mode + Mov AX, 554 + Mul CX + Add AX, 544 + Jmp PE_FillHeader9 + +PE_FillHeader8: ; Simple instrument mode + Mov AX, 80 + Mul CX + Add AX, 55932 + +PE_FillHeader9: + Mov SI, AX + Mov CX, 25 + Mov AH, 5 + +PE_FillHeader10: + LodsB + Cmp AL, 226 + JB PE_FillHeader13 + + Mov AL, ' ' + +PE_FillHeader13: + StosW + Loop PE_FillHeader10 + +PE_FillHeader7: +; Mov AL, LastVolume + + Call PE_FillSpeedTempo + +; Cmp AL, 0FFh +; JNE PE_FillHeader4 +; +; Mov AX, 5*256+'.' +; StosW +; StosW +; Jmp PE_FillHeader5 +; +;PE_FillHeader4: +; Xor AH, AH +; Mov CL, 10 +; Div CL +; Add AX, 3030h +; Mov DL, AH +; Mov AH, 5 +; StosW +; Mov AL, DL +; StosW + +PE_FillHeader5: + Mov AX, BaseOctave + Add AL, '0' + Mov AH, 5 + Mov [ES:((50+5*80)*2)], AX + +; Mov AH, 48h +; Mov BX, 0FFFFh +; Int 21h +; Mov AX, BX +; Mov CX, 2006h +; ShR AX, CL +; Mov DI, (71+6*80)*2 +; Call PE_ConvAX2Num +; +; Call E_GetFreeEMS +; Xor DX, DX +; Mov BX, 1000 +; Div BX +; +; Add AL, '0' +; Mov AH, CH +; Mov [ES:(70+7*80)*2], AX +; Mov AX, DX +; Mov DI, (71+7*80)*2 +; Call PE_ConvAX2Num + + +; Call K_GetCaps +; Mov AH, 21h +; And AL, AL +; JZ PE_FillHeader2 +; +; Mov AH, 23h +; +;PE_FillHeader2: +; Mov DI, (75+10*80)*2 +; Mov SI, Offset CapsMsg +; Mov CX, 4 +; +;PE_FillHeader3: +; SegCS LodsB +; StosW +; Loop PE_FillHeader3 + + Call UpdateInfoLine + + Ret + +EndP PE_FillHeader + +; + +Proc PE_FillSpeedTempo Far + + Call S_GetDestination + + Call Music_GetDisplayVariables ; AX = current speed. + Mov CH, 5 + Mov DI, (50+4*80)*2 + Call PE_ConvAX2Num + + Mov AX, BX + Mov DI, (54+4*80)*2 + Call PE_ConvAX2Num + + Ret + +EndP PE_FillSpeedTempo + +; + +Proc PE_DrawOrderList Far + + Mov AL, 80 + Mul Byte Ptr [SI+3] + Add AL, [SI+2] + AdC AH, 0 + Add AX, AX + Mov DI, AX + Mov CX, [SI+4] + + Push CS + Pop DS + Assume DS:Pattern + + Mov AX, TopOrder ; Bounds checking... + Mov BX, Order + Cmp AX, BX + JBE PE_DrawOrderList1 + + Mov AX, BX + +PE_DrawOrderList1: + Mov DX, AX + Add DX, CX + Cmp DX, BX + JA PE_DrawOrderList2 + + LEA AX, [BX+1] + Sub AX, CX + +PE_DrawOrderList2: + Mov TopOrder, AX + Mov BX, AX + + Call S_GetDestination + Push CX + Push DI + +PE_DrawOrderList3: + Push CX + + Mov CH, 20h + Call PE_ConvAX2Num + + Add DI, 160 + Inc AX + + Pop CX + Loop PE_DrawOrderList3 + + Pop DI + Pop CX + Add DI, 8 ; BX = toporder, DI = order area + + Call Music_GetSongSegment + Mov DS, AX + Add BX, 256 + +PE_DrawOrderList4: + Push CX + + Mov CH, 2 + MovZX AX, Byte Ptr [BX] + Cmp AX, 0FEh + JB PE_DrawOrderList5 + + Mov CL, '-' + Cmp AL, 0FEh + JNE PE_DrawOrderList7 + + Mov CL, '+' + +PE_DrawOrderList7: + Mov AX, CX + StosW + StosW + StosW + Sub DI, 6 + + Jmp PE_DrawOrderList6 + + +PE_DrawOrderList5: + Call PE_ConvAX2Num + +PE_DrawOrderList6: + Pop CX + Inc BX + Add DI, 160 + Loop PE_DrawOrderList4 + + Call Music_GetPlayMode + Cmp AX, 2 + JNE PE_DrawOrderList8 + + Jmp PE_ShowOrder + +PE_DrawOrderList8: + Ret + +EndP PE_DrawOrderList + Assume DS:Nothing + +; + +Proc PE_PreOrderList Far + + Mov AL, 80 + Mov BX, Order + Sub BX, TopOrder + Add BL, [SI+3] + Mul BL + Add AL, [SI+2] + AdC AH, 0 + Add AX, 4 + Add AX, OrderCursor + Add AX, AX + Mov DI, AX + + Call S_GetDestination + Inc DI + Mov Byte Ptr [ES:DI], 30h + + Ret + +EndP PE_PreOrderList + +; + +Proc NetworkOrderList Near + +IF NETWORKENABLED + Call Network_GetSendQueue + JZ NetworkOrderList1 + + Mov AX, NETWORK_SONGDATAOBJECT*100h ; Destination ALL + StosW + Mov AX, 256 + StosW + StosW + +NetworkOrderList1: + Call Network_FinishedSendQueue +ENDIF + Ret + +EndP NetworkOrderList + +; + +Proc PE_PostOrderList Far + + Push ES + Pop DS + Mov SI, [BX] + + Push BX + + Mov AL, 80 + Mov BX, Order + Sub BX, TopOrder + Add BL, [SI+3] + Mul BL + Add AL, [SI+2] + AdC AH, 0 + Add AX, 4 + + Pop BX + +; Push ES +; Push DI + + Push CS + Pop DS + Assume DS:Pattern + + Push ES + Pop FS + + Call Music_GetSongSegment + Mov ES, AX + + Mov SI, Offset OrderListKeys + Call M_FunctionDivider + Mov AX, Order + JC PE_NoKeyFound + + Jmp [SI] + +PE_NoKeyFound: + Test CH, Not 1 + JNZ PE_PostOrderList10 + + Cmp DX, '0' + JB PE_PostOrderList10 + + Cmp DX, '9' + JBE PE_PostOrderList11 + +PE_PostOrderList10: + Xor AX, AX + Ret + +PE_PostOrderListNextOrder: + Call Music_GetPlayMode + Cmp AX, 2 + JNE PE_PostOrderListNextOrderEnd + + Mov AX, Order + Mov SI, Offset NextOrderMsg + Call SetInfoLine + + Call Music_SetNextOrder + +PE_PostOrderListNextOrderEnd: + Mov AX, 1 + Ret + +PE_PostOrderListHomeKey: + Mov Order, 0 + Jmp PE_PostOrderList2 + +PE_PostOrderListEndKey: + Call Music_GetSongSegment + Mov DS, AX + Mov SI, 100h + +PE_PostOrderListEndKeyLoop: + LodsB + Cmp AL, 0FFh + JE PE_postOrderListEndKeyLoopEnd + + Cmp SI, 100h+255 + JBE PE_PostOrderListEndKeyLoop + +PE_PostOrderListEndKeyLoopEnd: + Sub SI, 101h + Mov CS:Order, SI + + Jmp PE_PostOrderList2 + +PE_PostOrderList20: + Push FS + Pop DS + Mov SI, [BX] + + Mov AX, [SI+6] + Mov [DI], AX + Jmp PE_PostOrderList2 + +PE_PostOrderList21: + Push FS + Pop DS + Mov SI, [BX] + + Mov AX, [SI+8] + Mov [DI], AX + Jmp PE_PostOrderList2 + +PE_PostOrderList1: ; Up + And AX, AX + JZ PE_PostOrderList2 + + Dec AX + Mov Order, AX + +PE_PostOrderList2: + Mov AX, 1 + Ret + +PE_PostOrderList3b: + Call NetworkOrderList + +PE_PostOrderList3: ; Down + Cmp AX, 255 + JAE PE_PostOrderList2 + Inc AX + Mov Order, AX + Jmp PE_PostOrderList2 + +PE_PostOrderList4: ; PgUp + Sub AX, 16 + JNS PE_PostOrderList5 + + Xor AX, AX + +PE_PostOrderList5: + Mov Order, AX + Jmp PE_PostOrderList2 + +PE_PostOrderList6: ; PgDn + Add AX, 16 + And AH, AH + JZ PE_PostOrderList5 + + Mov AX, 255 + Jmp PE_PostOrderList5 + +PE_PostOrderList7: ; Left + Mov AX, OrderCursor + Dec AX + JNS PE_PostOrderList8 + + Mov AX, 2 + +PE_PostOrderList8: + Mov OrderCursor, AX + Jmp PE_PostOrderList2 + +PE_PostOrderList9: ; Right + Mov AX, OrderCursor + Inc AX + Cmp AX, 2 + JBE PE_PostOrderList8 + + Xor AX, AX + Jmp PE_PostOrderList8 + +PE_PostOrderList11: + Mov SI, AX + MovZX AX, Byte Ptr [ES:SI+256] ; AX = pattern number + Cmp AL, 199 + JBE PE_PostOrderList15 + + Xor AL, AL + +PE_PostOrderList15: ; Number + Mov CL, 10 + Div CL + Mov [TempNumbers+2], AH + Xor AH, AH + Div CL + Mov [TempNumbers+1], AH + Xor AH, AH + Div CL + Mov [TempNumbers], AH + + Mov BX, OrderCursor + Sub DX, '0' + Mov TempNumbers[BX], DL + + Mov AL, [TempNumbers] + Mul CL + Add AL, [TempNumbers+1] + Mul CL + Add AL, [TempNumbers+2] + + Cmp AX, 199 + JBE PE_PostOrderList12 + + Mov AX, 199 + +PE_PostOrderList12: + Mov [ES:SI+256], AL + Call NetworkOrderList + + Inc BX + Cmp BX, 2 + JBE PE_PostOrderList13 + + Cmp SI, 255 + JE PE_PostOrderList2 + + Xor BX, BX + Inc Order + +PE_PostOrderList13: + Mov OrderCursor, BX + Jmp PE_PostOrderList2 + + +PE_PostOrderList16: ; '-' + Mov SI, AX + Mov Byte Ptr [ES:SI+256], 0FFh + Mov OrderCursor, 0 + + Jmp PE_PostOrderList3b + +PE_PostOrderList17: ; '+' + Mov SI, AX + Mov Byte Ptr [ES:SI+256], 0FEh + Mov OrderCursor, 0 + + Jmp PE_PostOrderList3b + +PE_PostOrderList18: ; Del + Mov SI, AX + Add SI, 256 + Mov DI, SI + Inc SI + + Push ES + Pop DS + + Mov CX, 512 + Sub CX, SI + Rep MovsB + Mov AL, 0FFh + StosB + + Call NetworkOrderList + Jmp PE_PostOrderList2 + +PE_PostOrderList19: ; Ins + Mov CX, 255 + Mov DI, 511 + Mov SI, DI + Sub CX, AX + Dec SI + + Push ES + Pop DS + + StD + Rep MovsB + ClD + Mov AL, 0FFh + StosB + + Call NetworkOrderList + Jmp PE_PostOrderList2 + +PE_PostOrderList22: + Mov SI, Order + And SI, SI + JZ PE_PostOrderList23 + + Mov AL, [ES:SI+255] + Cmp AL, 198 + JA PE_PostOrderList23 + + Inc AX + Mov [ES:SI+256], AL + + Mov AX, SI + Jmp PE_PostOrderList3b + +PE_PostOrderList23: + Xor AX, AX + Ret + +PE_PostOrderList24: ; 'G' + Mov BX, AX + MovZX AX, Byte Ptr [ES:BX+256] + Cmp AL, 200 + JAE PE_PostOrderList23 + + Jmp PE_GotoPattern2 + +EndP PE_PostOrderList + Assume DS:Nothing + +; + +Proc PE_UnInitPatternEdit Far + + Mov AX, CS:BlockDataArea + And AX, AX + JZ PE_UnInitPatternEdit1 + + Mov ES, AX + Mov AH, 49h + Int 21h + +PE_UnInitPatternEdit1: + Call PE_ClearUndoBuffer + + Ret + +EndP PE_UnInitPatternEdit + +; + +Proc PE_ClearPatternData + + Push CX DX DS SI ES DI + + Push CS + Pop DS + Assume DS:Pattern + + Mov ES, PatternDataArea + Xor DI, DI + + Mov DX, 200 + +PE_ClearPatternData1: + Mov CX, 320/4 + Mov SI, Offset EmptyRow + Rep MovsD + + Dec DX + JNZ PE_ClearPatternData1 + + Pop DI ES SI DS DX CX + Ret + +EndP PE_ClearPatternData + Assume DS:Nothing + +; + +Proc PE_InitPatternEdit Far + + Trace " - Initialising pattern data area" + + Call PE_ClearPatternData + Ret + +EndP PE_InitPatternEdit + +; + +include it_pe_v.inc + +; + +Proc PE_DrawPatternEdit Far + + Push CS + Pop DS + Assume DS:Pattern + + Cmp TracePlayback, 0 + JE PE_TraceOff + + Call Music_GetPlayMode ; AX = playmode + ; BX = current row + ; CX = current pattern + ; DX = order. + Cmp AX, 1 + JB PE_TraceOff + JE PE_NoTraceOrder + + Mov Order, DX + +PE_NoTraceOrder: + Cmp BX, Row + JE PE_SetMIDIChannel + + Mov AX, Channel + Mov MIDIChannel, AX + + Mov Row, BX + +PE_SetMIDIChannel: + Cmp CX, PatternNumber + JE PE_TraceOff + + Push CX ; Pattern number + Push CS + Push Offset PE_TraceTurnOffError + + Cmp PatternModified, 0 + JE PE_NoStoreRequired + + Call PEFunction_StorePattern + +PE_NoStoreRequired: + Pop AX + Pop AX + Pop AX + + Mov PatternNumber, AX + Call NewPattern + Jmp PE_TraceOff + +PE_TraceTurnOffError: + Pop AX + +PE_TraceTurnOff: + Mov CS:TracePlayback, 0 + +PE_TraceOff: + Push CS + Pop DS + + Call S_GetDestination + Mov AL, Template + Cmp AL, 1 + JB PE_DrawPAtternEdit30 + + Mov SI, Offset TemplateMsg1 + JE PE_DrawPatternEdit31 + + Mov SI, Offset TemplateMsg2 + Cmp AL, 3 + JB PE_DrawPatternEdit31 + + Mov SI, Offset TemplateMsg3 + JE PE_DrawPatternEdit31 + + Mov SI, Offset TemplateMsg4 + +PE_DrawPatternEdit31: + Mov DI, (2+12*80)*2 + Mov AH, 23h + Call S_DrawString + +PE_DrawPatternEdit30: + Test CentraliseCursor, 1 + JZ PE_NoCentraliseCursor + + Call PE_CentraliseCursor + +PE_NoCentraliseCursor: + Mov AX, MaxRow + Cmp AX, Row + JAE PE_DrawPatternEdit27 + + Mov Row, AX + +PE_DrawPatternEdit27: + Mov BX, BlockTop + Cmp BX, AX + JLE PE_DrawPatternEdit28 + + Mov BlockTop, AX + +PE_DrawPatternEdit28: + Mov BX, BlockBottom + Cmp BX, AX + JLE PE_DrawPatternEdit29 + + Mov BlockBottom, AX + +PE_DrawPatternEdit29: + Mov BX, ViewWidth + Test BX, BX + JZ PE_DrawPatternEdit1 + + Mov CX, 3 + Cmp NumChannelsEdit, 0 + JE PE_DrawPatternEditNoEditChannels + + Xor CX, CX + +PE_DrawPatternEditNoEditChannels: + Mov AX, 1 + Add AX, CX + Push AX + Push 14 + Mov AX, BX + Add AX, CX + Push AX + Push 47 + Push 27 + Call S_DrawBox + Add SP, 10 + +PE_DrawPatternEdit1: + Cmp NumChannelsEdit, 0 + JE PE_DrawPatternEdit34 + + Mov CX, 4 + Add CX, BX + Push CX + Mov AX, 14 + Push AX + Mul NumChannelsEdit + Add AX, CX + Push AX + Push 47 + Push 27 + Call S_DrawBox + Add SP, 10 + + Mov AX, LeftChannel + Mov CX, Channel + + Cmp AX, CX + JLE PE_DrawPatternEdit21 + + Mov AX, CX + +PE_DrawPatternEdit21: + Mov DX, AX + Add DX, NumChannelsEdit + Cmp DX, CX + JG PE_DrawPatternEdit22 + + Mov AX, CX + Sub AX, NumChannelsEdit + Inc AX + +PE_DrawPatternEdit22: + Mov LeftChannel, AX + ; Channel markers. + Mov DX, AX ; DL = left channel + Mov AX, 5+14*80 + Add AX, ViewWidth + Add AX, AX + Mov DI, AX + Mov DH, 10 + + Mov CX, NumChannelsEdit + +PE_DrawPatternEdit23: + Push CX + + MovZX AX, DL + Inc AX + Div DH + Add AX, 3030h + Mov SI, Offset ChannelMsg + Mov [SI+9], AX + + Push DS + Push SI + + Call Music_GetSongSegment + Mov DS, AX + + Mov SI, DX + And SI, 0FFh + Add SI, 40h + Mov AH, 13h + Test Byte Ptr [SI], 80h + JZ PE_DrawPatternEdit32 + + Mov AH, 10h + +PE_DrawPatternEdit32: + Pop SI + Pop DS + + Mov CX, 12 + +PE_DrawPatternEdit24: + LodsB + StosW + Loop PE_DrawPatternEdit24 + + Pop CX + Add DI, 4 + Inc DX + Loop PE_DrawPatternEdit23 + +PE_DrawPatternEdit34: + Cmp ViewChannelTracking, 0 + JE PE_DrawPatternEditNormal + + ; OK.. using view windows ONLY. + ; now to perform scrolling if necessary. + Mov SI, Offset ViewChannels + Mov DL, [SI] + + Cmp DL, 0FFh + JE PE_DrawPatternEditNormal + + Mov DH, DL ; DL = min channel, DH = max channel + Mov CX, Channel ; Also check + +PE_DrawPatternViewChannelOnly1: + LodsW + + Cmp AL, CL + JE PE_DrawPatternEditNormalJP + + Cmp AL, 0FFh + JE PE_DrawPatternViewChannelOnly2 + + Cmp AL, DL + JB PE_DrawPatternViewChannelOnly3 + + Cmp AL, DH + JA PE_DrawPatternViewChannelOnly4 + + Jmp PE_DrawPatternViewChannelOnly1 + +PE_DrawPatternViewChannelOnly3: + Mov DL, AL + Jmp PE_DrawPatternViewChannelOnly1 + +PE_DrawPatternViewChannelOnly4: + Mov DH, AL + Jmp PE_DrawPatternViewChannelOnly1 + +PE_DrawPatternEditNormalJP: + Jmp PE_DrawPatternEditNormal + +PE_DrawPatternViewChannelOnly2: ; OK.. so channel is not in list, + ; DL = min channel, DH = max channel. + Mov CH, CL + Sub CH, DH ; CH = curchannel-maxchannel + + Cmp DH, CL + JBE PE_DrawPatternViewChannelOnly5 + + Mov CH, CL + Sub CH, DL + +PE_DrawPatternViewChannelOnly5: ; CH = modifier. + + Mov SI, Offset ViewChannels + +PE_DrawPatternViewChannelOnly6: + LodsW + Cmp AL, 0FFh + JE PE_DrawPatternEditNormal + + Add AL, CH + JS PE_DrawPatternViewChannelOnly7 + + Cmp AL, 63 + JBE PE_DrawPatternViewChannelOnly8 + + Mov AL, 63 + Jmp PE_DrawPatternViewChannelOnly8 + +PE_DrawPatternViewChannelOnly7: + Xor AL, AL + +PE_DrawPatternViewChannelOnly8: + Mov [SI-2], AL + Jmp PE_DrawPatternViewChannelOnly6 + +PE_DrawPatternEditNormal: + Mov AX, TopRow + Mov CX, Row + + Cmp AX, CX + JLE PE_DrawPatternEdit2 + + Mov AX, CX ; if row < toprow, toprow = row + +PE_DrawPatternEdit2: + LEA DX, [EAX+32] + Cmp DX, CX + JG PE_DrawPatternEdit3 + + LEA AX, [ECX-31] + +PE_DrawPatternEdit3: + Mov TopRow, AX + + Mov CX, MaxRow + Sub CX, 31 + Cmp AX, CX + JBE PE_DrawPatternEdit35 + + Mov TopRow, CX + Mov AX, CX + +PE_DrawPatternEdit35: + Mov DI, (1+15*80)*2 + Cmp NumChannelsEdit, 0 + JNE PE_DrawPatternEditAllView + + Xor BX, BX + +PE_DrawPatternEditAllView: + LEA DI, [EDI+EBX*2] + + Xor BX, BX + Cmp PlayMarkOn, 0 + JE PE_DrawPlayMark + + Mov CX, PlayMarkPattern + Cmp CX, PatternNumber + JNE PE_DrawPlayMark + + Mov BX, 1 ; Check to draw playmark + +PE_DrawPlayMark: + Push DI + + Mov DX, 32 + +PE_DrawPatternEdit4: + Push DI + + Mov CH, 20h + And BX, BX + JZ PE_DrawPatternEditRowNumber + + Cmp AX, PlayMarkRow + JNE PE_DrawPatternEditRowNumber + + Mov CH, 0B0h + +PE_DrawPatternEditRowNumber: + Call PE_ConvAX2Num + + Pop DI + Inc AX + Add DI, 160 + + Dec DX + JNZ PE_DrawPatternEdit4 + + Mov BX, Offset NoteNames ; CS:BX points to notenames + + Push DS + ; Viewing columns... + Mov SI, Offset ViewChannels + Mov DI, (15*80+2)*2 + Cmp NumChannelsEdit, 0 + JNE PE_DrawviewColumnStart + + Add DI, 6 + +PE_DrawViewColumnStart: + LodsW + Cmp AL, 0FFh + JE PE_DrawViewColumn2 + +PE_DrawViewColumn1: + ; AL = channel, AH = view method. + Mov DL, AL + MovZX CX, AH + LEA BP, [ViewMethodInfo+ECX*4] + + Push DS + Push SI + Push ES + Push DI + Push BP + + Mov SI, 5 + Xor AH, AH + Push DX + Mul SI + Mov SI, AX + Mov AX, 320 + Mov CX, TopRow + Mul CX + Pop DX + Mov DS, PatternDataArea + Add SI, AX ; DS:SI points to appropriate data. + ; CS:BX points to note type. + ; ES:DI points to screen area. + ; DL = Channel number + ; CX = Row number + + Call [Near Ptr CS:BP] + + Pop BP + Pop DI + Pop ES + Pop SI + Pop DS + + LodsW + Cmp AL, 0FFh + JE PE_DrawViewColumn2 + + Push AX + + Mov CX, [CS:BP+2] + Add DI, CX + Add DI, CX + + Cmp ViewDivision, 0 + JE PE_DrawViewColumn4 + + Mov CX, 32 + Push DI + + Mov AX, 2A8h + +PE_DrawViewColumn3: + StosW + Add DI, 158 + Loop PE_DrawViewColumn3 + + Pop DI + StosW ; Just to do: Add DI, 2 + +PE_DrawViewColumn4: + Pop AX + Jmp PE_DrawViewColumn1 + +PE_DrawViewColumn2: + Pop DS + Pop DI + Add DI, 8 + + Cmp NumChannelsEdit, 0 + JE PE_DrawPatternHilightRow + +PE_DrawPatternEdit33: + Mov AX, 320 + Mov BP, TopRow + Mul BP + Mov SI, AX + Mov AX, 5 + Mul LeftChannel + Add SI, AX ; SI contains offset to channel data + Mov DX, NumChannelsEdit + + Mov CX, 32 ; 32 rows + Mov DS, PatternDataArea + Assume DS:Nothing + +PE_DrawPatternEdit5: + Push CX + Push DX + Push SI + Push DI + Push BP + + Mov CX, 60Ch + + Mov AX, BP + Cmp RowHiLight2, 0 + JZ PE_DrawPatternEdit8 + Div RowHiLight2 + And AH, AH + JNZ PE_DrawPatternEdit8 + + Mov CH, 0E6h + Jmp PE_DrawPatternEdit6 + +PE_DrawPatternEdit8: + Mov AX, BP + Cmp RowHiLight1, 0 + JZ PE_DrawPatternEdit6 + Div RowHiLight1 + And AH, AH + JNZ PE_DrawPatternEdit6 + + Mov CH, 0F6h + +PE_DrawPatternEdit6: ; CH = colour, CL = 12 (for division) + Push CX + Push DX + + Cmp CS:BlockMark, 0 + JE PE_DrawPatternEdit25 + + Cmp BP, CS:BlockTop + JB PE_DrawPatternEdit25 + + Cmp BP, CS:BlockBottom + JA PE_DrawPatternEdit25 + + Mov AX, CS:LeftChannel + Add AX, CS:NumChannelsEdit + Sub AX, DX + + Cmp AX, CS:BlockLeft + JB PE_DrawPatternEdit25 + + Cmp AX, CS:BlockRight + JA PE_DrawPatternEdit25 + + Test CH, 80h + JZ PE_DrawPatternEdit26 + + Mov CH, 93h + Jmp PE_DrawPatternHilight1 + +PE_DrawPatternEdit26: + Mov CH, 83h + Jmp PE_DrawPatternHilight1 + +PE_DrawPatternEdit25: + Cmp BP, Row + JNE PE_DrawPatternHilight1 + + Test CentraliseCursor, 2 + JZ PE_DrawPatternHilight1 + + Mov CH, 016h + +PE_DrawPatternHilight1: + LodsB + + Call Draw_3Note + + Mov AL, 20h + StosW ; Note->Instrument space + + Mov DL, 10 + LodsB + + Call Draw_2Instrument + + Mov AL, 20h + StosW + + LodsB + Cmp AL, 0FFh + JNE PE_DrawPattern16 + + Test CS:Flags, 1 + JZ PE_DrawPatternNoDefaultVolume + + Cmp Byte Ptr [SI-3], MAXNOTE + JA PE_DrawPatternNoDefaultVolume + Cmp Byte Ptr [SI-2], 0 + JE PE_DrawPatternNoDefaultVolume + + Sub DI, 2 + Mov AL, 191 + StosW + + Push BX + + Call Music_GetSongSegment + Mov FS, AX + Mov BL, [SI-2] ; Sample/Instrument + And BX, 0FFh + Add BX, BX + + Test Byte Ptr [FS:2Ch], 4 ; Sample mode? + JZ DefaultVolumeSample + +DefaultVolumeInstrument: + Push DI + + Mov BX, [FS:64710+BX] ; Instrument pointer + Mov DI, [SI-3] + And DI, 0FFh ; DI = Note + Add DI, DI + Mov BX, [FS:BX+DI+41h] ; BL = sample + + Pop DI + And BX, 0FFh + Add BX, BX + JZ DefaultVolumeNoSample + +DefaultVolumeSample: + Mov BX, [FS:64910+BX] ; Sample + Mov AL, [FS:BX+13h] ; Default volume + + Pop BX + Mov DL, 10 + Xor AH, AH + Div DL + Add AX, '00' + Mov DH, AH + Mov AH, CH + StosW + Mov AL, DH + StosW + Mov AL, 192 + StosW + Jmp PE_DrawPatternEffect + +DefaultVolumeNoSample: + Pop BX + + Mov AH, CH + Mov AL, 173 ; Replace with default volume + StosW + StosW + Mov AL, 192 + StosW + Jmp PE_DrawPatternEffect + +PE_DrawPatternNoDefaultVolume: + Mov AL, 173 ; '.' + StosW + StosW + Jmp PE_DrawPattern17 + +PE_DrawPattern16: + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC PE_DrawPatternNoVEffect + + Test AL, 80h + JZ PE_DrawPatternVEffect1 + + Add AH, 60 + +PE_DrawPatternVEffect1: + Mov AL, AH + Xor AH, AH + Div DL + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov DH, AH + Mov AH, CH + StosW + Mov AL, DH + StosW + + Jmp PE_DrawPattern17 + +PE_DrawPatternNoVEffect: + Mov CL, CH + + Test AL, 80h + JZ PE_DrawPatternNoPan + + And CL, 0F0h + Or CL, 2 + And AL, 7Fh ; Filter out panning stuff. + + +PE_DrawPatternNoPan: + Xor AH, AH + Div DL + ; AH = units, AL = tens + Mov DH, AH + Mov AH, CL + Add AL, '0' + StosW + Mov AL, DH + Add AL, '0' + StosW + + Mov AH, CH + +PE_DrawPattern17: + Mov AL, 20h + StosW + +PE_DrawPatternEffect: + LodsB + Add AL, 64 + Cmp AL, 64 + JNE PE_DrawPattern18 + + Mov AL, '.' + +PE_DrawPattern18: + StosW + LodsB ; Commandvalue + Mov DH, AL + ShR AL, 4 + + Call PE_ConvHexAL + + Mov AL, DH + And AL, 15 + Call PE_ConvHexAL + + Pop DX + Pop CX + Dec DX + JZ PE_DrawPatternEdit9 + + And AX, 0F000h + Or AX, 2A8h + Cmp AH, 80h + JB PE_DrawDiv1 + Cmp AH, 0A0h + JAE PE_DrawDiv1 + + Mov AX, 2A8h + +PE_DrawDiv1: + StosW + Jmp PE_DrawPatternEdit6 + +PE_DrawPatternEdit9: + Pop BP + Pop DI + Pop SI + Pop DX + Pop CX + Add DI, 160 ; Screen + Add SI, 320 ; PatternData + Inc BP ; Row + Loop PE_DrawPatternEdit5 + +PE_DrawPatternHilightRow: + Call Music_GetPlayMode + Test AX, AX + JZ PE_DrawPattern40 + + Cmp CX, CS:PatternNumber + JNE PE_DrawPattern40 + + Sub BX, CS:TopRow + JC PE_DrawPattern40 + Cmp BL, 32 + JAE PE_DrawPattern40 + Mov AL, 80 + Mul BL + + Mov DI, AX + Add DI, 1+15*80 + Cmp CS:NumChannelsEdit, 0 + JE PE_DrawPattern41 + + Add DI, CS:ViewWidth + +PE_DrawPattern41: + Add DI, DI + + Push ES + Pop DS + + Mov CL, 3 + +PE_DrawPattern42: + Inc DI + Mov AL, [DI] + And AL, 0F0h + Or AL, 3 + StosB + + Dec CL + JNZ PE_DrawPattern42 + +PE_DrawPattern40: + Ret + +EndP PE_DrawPatternEdit + Assume DS:Nothing + +; + +Proc PE_PrePatternEdit Far + + Push CS + Pop DS + Assume DS:Pattern + + Cmp NumChannelsEdit, 0 + JNE PE_PrePatternEdit18 + + Ret + +PE_PrePatternEdit18: + Call S_GetDestination + + Mov AX, 80 + Mov BX, 15 + Add BX, Row + Sub BX, TopRow + Mul BL + Add AX, ViewWidth + Add AX, 5 + Mov BX, PatternCursor + Add AL, [CursorPositions+BX] + AdC AH, 0 + Mov DI, AX + Mov AL, 14 + Mov BX, Channel + Sub BX, LeftChannel + Mul BL + Add DI, AX + Add DI, DI + Inc DI + Mov Byte Ptr [ES:DI], 30h + + Mov DI, 8+47*80 + Add DI, ViewWidth + Add DI, DI + Mov SI, LeftChannel + Mov DX, NumChannelsEdit + +PE_PrePatternEdit16: + Cmp [MultiChannelInfo+SI], 0 ; Put the 'M's in. + JE PE_PrePatternEdit17 + + Mov Byte Ptr [ES:DI], 172 + +PE_PrePatternEdit17: + Inc SI + Add DI, 28 + Dec DX + JNZ PE_PrePatternEdit16 + + Mov DI, 5+47*80 + Add DI, ViewWidth + Mov AL, 14 + Mov BX, Channel + Sub BX, LeftChannel + Mul BL + Add DI, AX + Add DI, DI ; Points to bottom of channel. + + Mov DX, 1 + Cmp Template, 0 + JE PE_PrePatternEditLoop +; Test CL, CL +; JZ PE_PrePatternEditLoop + Cmp BlockDataArea, 0 + JE PE_PrePatternEditLoop + + Mov FS, BlockDataArea + Mov AX, [FS:0] ; Block width + Mov DX, NumChannelsEdit + Add DX, LeftChannel + Sub DX, Channel + Cmp DX, AX + JB PE_PrePatternEditLoop + + Mov DX, AX + +PE_PrePatternEditLoop: + Push DI + + Mov AX, 23A9h + Mov CX, PatternCursor + Mov CH, EditMask + + Test CL, CL + JZ PE_PrePatternEdit1 + + Mov AL, 0AAh + +PE_PrePatternEdit1: + StosW + StosW + StosW +; Add DI, 2 + ScasW + + Test CH, 1 + JZ PE_PrePatternEdit2 + + StosW + StosW + Jmp PE_PrePatternEdit3 + +PE_PrePatternEdit2: + Add DI, 4 + +PE_PrePatternEdit3: +; Add DI, 2 + ScasW + + Test CH, 2 + JZ PE_PrePatternEdit4 + + StosW + StosW + Jmp PE_PrePatternEdit5 + +PE_PrePatternEdit4: + Add DI, 4 + +PE_PrePatternEdit5: +; Add DI, 2 + ScasW + + Test CH, 4 + JZ PE_PrePatternEdit6 + + StosW + StosW + StosW + +PE_PrePatternEdit6: + Pop DI ; Mark in the actual channels + Mov AL, 0A9h + Test CL, CL + JNZ PE_PrePatternEdit7 + + Mov AL, 0ABh + StosW + StosW + StosW + + Add DI, 22 + Dec DX + JNZ PE_PrePatternEditLoop + + Ret + +PE_PrePatternEdit7: + Cmp CL, 1 + JA PE_PrePatternEdit8 + + Mov AL, 0ABh + Add DI, 4 + StosW + Ret + +PE_PrePatternEdit8: + Cmp CL, 3 + JA PE_PrePatternEdit10 + + Test CH, 1 + JZ PE_PrePatternEdit9 + + Mov AL, 0ABh + +PE_PrePatternEdit9: + Add DI, 8 + StosW + StosW + Ret + +PE_PrePatternEdit10: + Cmp CL, 5 + JA PE_PrePatternEdit12 + + Test CH, 2 + JZ PE_PrePatternEdit11 + + Mov AL, 0ABh + +PE_PrePatternEdit11: + + Add DI, 14 + StosW + StosW + Ret + +PE_PrePatternEdit12: + Cmp CL, 6 + JA PE_PrePatternEdit14 + + Test CH, 4 + JZ PE_PrePatternEdit13 + + Mov AL, 0ABh + +PE_PrePatternEdit13: + Add DI, 20 + StosW + Ret + +PE_PrePatternEdit14: + Test CH, 4 + JZ PE_PrePatternEdit15 + + Mov AL, 0ABh + +PE_PrePatternEdit15: + Add DI, 22 + StosW + StosW + Ret + +EndP PE_PrePatternEdit + Assume DS:Nothing + +; + +Proc GetPatternOffset + + Assume DS:Pattern + + Push AX + Push BX + Push DX + + Mov AX, 64 + Mul Row + Add AX, Channel + Mov BX, 5 + Mul BX + Mov DI, AX + Mov ES, PatternDataArea + + Pop DX + Pop BX + Pop AX + Ret + +EndP GetPatternOffset + Assume DS:Nothing + +; + +Proc NetworkPatternBlock Near ; CL = width, CH = Height, BL = Channel, BH = Row + +IF NETWORKENABLED + Call Network_GetSendQueue + JZ PE_GotoNextInputNoNetwork + + Mov AX, NETWORK_PARTIALPATTERNOBJECT*100h ; Destination ALL + StosW + Mov AL, Byte Ptr PatternNumber + StosB + Mov AX, BX + StosW + Mov AX, CX + StosW + +PE_GotoNextInputNoNetwork: + Call Network_FinishedSendQueue + + Ret +ENDIF + +EndP NetworkPatternBlock + +; + +Proc NetworkPartialPattern Near ; CL = width, CH = Height + +IF NETWORKENABLED + Push BX + Mov BL, Byte Ptr Channel + Mov BH, Byte Ptr Row + Call NetworkPatternBlock + Pop BX +ENDIF + Ret + +EndP NetworkPartialPattern + +; + +Proc NetworkBlock Near + +IF NETWORKENABLED + Mov BL, Byte Ptr BlockLeft + Mov BH, Byte Ptr BlockTop + Mov CL, Byte Ptr BlockRight + Mov CH, Byte Ptr BlockBottom + Sub CX, BX + Add CX, 101h + Call NetworkPatternBlock +ENDIF + Ret + +EndP NetworkBlock + +; + +PatternCursorJumpTable DW Offset PE_PatternCursorPos0 + DW Offset PE_PatternCursorPos1 + DW Offset PE_PatternCursorPos2 + DW Offset PE_PatternCursorPos3 + DW Offset PE_PatternCursorPos4 + DW Offset PE_PatternCursorPos5 + DW Offset PE_PatternCursorPos6 + DW Offset PE_PatternCursorPos7 + DW Offset PE_PatternCursorPos8 + +Proc PE_PostPatternEdit Far + + Push CS + Pop DS + Assume DS:Pattern + + Test CH, 1 + JZ PE_PostPatternEdit17 + + Mov EAX, [DWord Ptr LastKeyBoard1] + Mov EBX, [DWord Ptr LastKeyBoard2] + + Mov [DWord Ptr LastKeyBoard2], EAX + Mov [DWord Ptr LastKeyBoard3], EBX + + Mov [LastKeyBoard1], CX + Mov [LastKeyBoard1+2], DX + +PE_PostPatternEdit17: + Mov AL, CH + Mov SI, Offset PEFunctions + And AL, 6 + Mov ShiftPressed, AL + + Test CH, 6 + PushF + Call M_FunctionDivider + JC PE_PostPatternEdit1 + + PopF + JNZ PE_PostPatternEditShift + +PE_PostPatternEditNotShift: + Jmp [SI] + +PE_PostPatternEditShift: + Cmp Byte Ptr [SI-3], 6 ; MIDI message + JE PE_PostPatternEditNotshift + + Mov AX, [SI-2] + + Cmp AX, 10Fh ; Shift Tab + JE PE_PostPatternEditNotShift + + Cmp AX, '?' + JE PE_PostPatternEditNotShift + + Cmp AX, '|' + JE PE_PostPatternEditNotShift + + Push [Row] + Push [Channel] + + Push CS + + Call [SI] + + Push CS + Pop DS + +; Mov CX, BlockAnchorRow +; Mov DX, BlockAnchorChannel + Pop DX + Pop CX + + Cmp CX, Row + JNE PE_PostPatternEditShift1 + + Cmp DX, Channel + JE PE_PostPatternEditShift2 + +PE_PostPatternEditShift1: + Cmp BlockReset, 0 + JE PE_PostPatternEditShift3 + + Mov BlockReset, 0 + Mov BlockMark, 0 + +PE_PostPatternEditShift3: + ; Set block marks. + Mov AX, BlockAnchorChannel + Mov BX, BlockAnchorRow + + Push CS + Call PEFunction_MarkBeginBlockChain + Jmp PEFunction_MarkEndBlock + +PE_PostPatternEditShift2: + Mov AX, 1 + Ret + +PE_PostPatternEdit1: + PopF + Test CH, 60h + JNZ PE_PostPatternEdit6 + + Call GetPatternOffset + Mov BX, PatternCursor + Add BX, BX + Jmp [PatternCursorJumpTable+BX] + +PE_PostPatternEdit6: + Mov AX, CX + And AX, 1FFh + Cmp AX, 10Ah + JA PE_PostPatternEdit7 + + Cmp AX, 102h + JB PE_PostPatternEdit7 + ; Alt-1 -> Alt-9 + Sub AX, 101h +; Dec AL +; Dec AH + Mov SkipValue, AX + + Mov SI, Offset CursorStepMsg + Call SetInfoLine + + Mov AX, 1 + Ret + +PE_PostPatternEdit7: + Xor AX, AX + Ret + +EndP PE_PostPatternEdit + +; + +Proc PEFunction_Ctrl_PgUp Far + + Mov Row, 0 + + Mov AX, 1 + Ret + +EndP PEFunction_Ctrl_PgUp + +; + +Proc PEFunction_Ctrl_PgDn Far + + Mov AX, MaxRow + Mov Row, AX + + Mov AX, 1 + Ret + +EndP PEFunction_Ctrl_PgDn + +; + +Proc PEFunction_Up Far + + Mov BX, SkipValue + And BX, BX + JNZ PEFunction_Up2 + + Mov BX, 1 + +PEFunction_Up2: + Mov AX, Row + Sub AX, BX + JS PEFunction_Up1 + + Mov Row, AX + +PEFunction_Up1: + Mov AX, 1 + Ret + +EndP PEFunction_Up + +; + +Proc PEFunction_Down Far + + Push CS + Pop DS + + Mov BX, SkipValue + And BX, BX + JNZ PEFunction_Down2 + + Mov BX, 1 + +PEFunction_Down2: + Mov AX, Row + Add AX, BX + Cmp AX, MaxRow + JA PEFunction_Down1 + + Mov Row, AX + +PEFunction_Down1: + Mov AX, 1 + Ret + +EndP PEFunction_Down + +; + +Proc PEFunction_Left Far + + Mov CX, PatternCursor + Mov BX, Channel + Dec CX + JNS PEFunction_Left1 + + Mov CX, 8 + Dec BX + JS PEFunction_Left2 + + Mov Channel, BX + + Cmp CommandToValue, 0 + JE PEFunction_Left1 + + Call GetPatternOffset +; Mov ES, PatternDataArea +; Mov AX, 64 +; Mul Row +; Add AX, BX +; Mov DX, 5 +; Mul DX +; Mov DI, AX + Cmp Word Ptr [ES:DI+3], 0 + JNE PEFunction_Left1 + + Mov CX, 6 + +PEFunction_Left1: + Mov PatternCursor, CX + +PEFunction_Left2: + Mov AX, 1 + Ret + +EndP PEFunction_Left + +; + +Proc PEFunction_Right Far ; If there is no + ; command value... skip! + + Mov CX, PatternCursor + Mov BX, Channel + Inc CX + Cmp CX, 6 + JBE PEFunction_Right1 + + Cmp CommandToValue, 0 + JE PEFunction_Right4 + + Call GetPatternOffset +; Mov ES, PatternDataArea +; Mov AX, 64 +; Mul Row +; Add AX, Channel +; Mov DX, 5 +; Mul DX +; Mov DI, AX + Cmp Word Ptr [ES:DI+3], 0 + JE PEFunction_Right3 + +PEFunction_Right4: + Cmp CX, 9 + JB PEFunction_Right1 + +PEFunction_Right3: + Xor CX, CX + Inc BX + Cmp BX, 64 + JAE PEFunction_Right2 + +PEFunction_Right1: + Mov PatternCursor, CX + Mov Channel, BX + +PEFunction_Right2: + Mov AX, 1 + Ret + +EndP PEFunction_Right + +; + +Proc PEFunction_Press_Shift Far + + Mov AX, Channel + Mov BX, Row + + Mov BlockAnchorChannel, AX + Mov BlockAnchorRow, BX + Mov BlockReset, 1 + Mov NoteEntered, 0 + + Xor AX, AX + Ret + +EndP PEFunction_Press_Shift + +; + +Proc PEFunction_Release_Shift Far + + Cmp NoteEntered, 0 + JE PEFunction_Release_Shift1 + + Mov AX, BlockAnchorChannel + Mov BX, BlockAnchorRow + + Mov Channel, AX + Mov Row, BX + + Call PE_GotoNextInput + +PEFunction_Release_Shift1: + Xor AX, AX + Ret + +EndP PEFunction_Release_Shift + +; + +Proc PEFunction_Alt_Home Far + Mov BL, RowHilight1 + Jmp PEFunction_PgUpChain + +Proc PEFunction_PgUp Far + + Mov BL, RowHiLight2 + +PEFunction_PgUpChain: + Mov AX, Row + Mov CX, MaxRow + Mov DX, SkipValue + And DX, 0FFh + JNZ PEFunction_PgUp3 + + Mov DL, 1 + +PEFunction_PgUp3: + And BX, 0FFh + + JNZ PEFunction_PgUp2 + + Mov BX, 16 + +PEFunction_PgUp2: + Sub CX, DX ; Sub maxrow, skipvalue + Cmp CX, AX + JAE PEFunction_PgUp4 + + Dec AX + Div BL + Mul BL + Jmp PEFunction_PgUp1 + +PEFunction_PgUp4: + Sub AX, BX + JNS PEFunction_PgUp1 + + Xor AX, AX + +PEFunction_PgUp1: + Mov Row, AX + + Mov AX, 1 + Ret + +EndP PEFunction_PgUp + +EndP PEFunction_Alt_Home + +; + +Proc PE_CentraliseCursor + + Mov AX, Row + Sub AX, 16 + JNC PE_CentraliseCursor1 + + Xor AX, AX + +PE_CentraliseCursor1: + Mov TopRow, AX + Ret + +EndP PE_CentraliseCursor + +; + + +Proc PEFunction_Alt_End Far + Mov BL, RowHilight1 + Jmp PEFunction_PgDnChain + +Proc PEFunction_PgDn Far + + Mov BL, RowHiLight2 + +PEFunction_PgDnChain: + Mov AX, Row + And BX, 0FFh + JNZ PEFunction_PgDn2 + + Mov BX, 16 + +PEFunction_PgDn2: + Add AX, BX + Cmp AX, MaxRow + JBE PEFunction_PgDn1 + + Mov AX, MaxRow + +PEFunction_PgDn1: + Mov Row, AX + + Mov AX, 1 + Ret + +EndP PEFunction_PgDn + +EndP PEFunction_Alt_End + +; + +Proc PEFunction_ShiftPgUp Far + + Call PEFunction_PgUp + Call PE_CentraliseCursor + + Mov AX, 1 + Ret + +EndP PEFunction_ShiftPgUp + +; + +Proc PEFunction_ShiftPgDn Far + + Call PEFunction_PgDn + Call PE_CentraliseCursor + + Mov AX, 1 + Ret + +EndP PEFunction_ShiftPgDn + +; + +Proc PEFunction_Home Far + + Cmp PatternCursor, 0 + JE PEFunction_Home1 + + Mov PatternCursor, 0 + Jmp PEFunction_Home3 + +PEFunction_Home1: + Cmp Channel, 0 + JE PEFunction_Home2 + + Mov Channel, 0 + Jmp PEFunction_Home3 + +PEFunction_Home2: + Mov Row, 0 + +PEFunction_Home3: + Mov AX, 1 + Ret + +EndP PEFunction_Home + +; + +Proc PEFunction_End Far + + Cmp PatternCursor, 8 + JE PEFunction_End1 + + Mov PatternCursor, 8 + Jmp PEFunction_End3 + +PEFunction_End1: + Call Music_GetLastChannel + + Cmp Channel, AX + JE PEFunction_End2 + + Mov Channel, AX + Jmp PEFunction_End3 + +PEFunction_End2: + Mov AX, MaxRow + Mov Row, AX + +PEFunction_End3: + Mov AX, 1 + Ret + +EndP PEFunction_End + +; + +Proc PEFunction_Tab Far + + Mov AX, Channel + Cmp AX, 63 + JAE PEFunction_Tab1 + + Mov PatternCursor, 0 + Inc Channel + +PEFunction_Tab1: + Mov AX, 1 + Ret + +EndP PEFunction_Tab + +; + +Proc PEFunction_ShiftTab Far + + Cmp PatternCursor, 0 + JNE PEFunction_ShiftTab2 + + Mov AX, Channel + And AX, AX + JZ PEFunction_ShiftTab1 + + Dec Channel + +PEFunction_ShiftTab2: + Mov PatternCursor, 0 + +PEFunction_ShiftTab1: + Mov AX, 1 + Ret + +EndP PEFunction_ShiftTab + +; + +Proc PEFunction_SetMask Far + + Mov BX, PatternCursor + Mov AL, [MaskChange+BX] + Xor EditMask, AL + + Mov AX, 1 + Ret + +EndP PEFunction_SetMask + +; + +Proc PEFunction_ToggleMultiChannel Far + + Mov BX, Channel + Xor [MultiChannelInfo+BX], 1 + + Cmp [Word Ptr LastKeyBoard2+2], 3100h + JNE PEFunction_ToggleMultiChannel1 + + Mov CX, 7 + Add CX, Channel + Mov DI, Offset O1_SelectMultiChannel + Call M_Object1List + +PEFunction_ToggleMultiChannel1: + Mov AX, 1 + Ret + +EndP PEFunction_ToggleMultiChannel + +; + +Proc PEFunction_BackSpace Far + + Xor CX, CX + + Mov AX, Row + Mov BX, Channel + Sub AX, SkipValue + JS PEFunction_BackSpace3 + + Mov Row, AX + Cmp [MultiChannelInfo+BX], 0 + JE PEFunction_BackSpace5 + + Mov DX, BX + +PEFunction_BackSpace1: + Dec BX + JNS PEFunction_BackSpace4 + + And AX, AX + JZ PEFunction_BackSpace3 + + Inc CX + +PEFunction_BackSpace4: + And BX, 63 + Cmp BX, DX + JE PEFunction_BackSpace2 + + Cmp [MultiChannelInfo+BX], 0 + JE PEFunction_BackSpace1 + +PEFunction_BackSpace2: + Mov Channel, BX + Cmp SkipValue, 0 + JNE PEFunction_BackSpace3 + + And CX, CX + JZ PEFunction_BackSpace3 + + And AX, AX + JZ PEFunction_BackSpace3 + + Dec Row + Jmp PEFunction_BackSpace3 + +PEFunction_BackSpace5: ; AX = row + Cmp SkipValue, 0 + JNE PEFunction_BackSpace3 + + Mov BX, Channel + Dec BX + JNS PEFunction_BackSpace6 + + And AX, AX + JZ PEFunction_BackSpace3 + Dec AX + +PEFunction_BackSpace6: + And BX, 63 + Mov Row, AX + Mov Channel, BX + +PEFunction_BackSpace3: + Mov AX, 1 + Ret + +EndP PEFunction_BackSpace + +; + +Proc PEFunction_PickUp Far + + Cmp Template, 4 + JE PEFunction_PickUp2 + + Mov Template, 0 ; Turn off templates + +PEFunction_PickUp2: + Call GetPatternOffset + Mov EAX, [ES:DI] + + Test AH, AH + JNZ PEFunction_PickUp1 + + Mov AH, LastInstrument + +PEFunction_PickUp1: + Mov DWord Ptr [LastNote], EAX + Mov AL, [ES:DI+4] + Mov LastCommandValue, AL + + Mov AX, 1 + Ret + +EndP PEFunction_PickUp + +; + +Proc PE_PatternCursorPos1 Far + + Test CL, CL + JZ PE_PatternCursorPos1_1 + + Cmp DX, '0' + JB PE_PatternCursorPos1_1 + + Cmp DX, '9' + JA PE_PatternCursorPos1_1 + + Mov AL, [ES:DI] + Cmp AL, 120 + JA PE_PatternCursorPos1_2 + + AAM 12 ; AH = octave, AL = note + Mov AH, DL + Sub AH, '0' + AAD 12 + StosB + +PE_PatternCursorPos1_2: + Mov CX, 101h + Call NetworkPartialPattern + + Jmp PE_GotoNextInput + +PE_PatternCursorPos1_1: + Xor AX, AX + Ret + +EndP PE_PatternCursorPos1 + +; + +Proc PE_PatternCursorPos0 Far + + Test CL, CL + JZ PE_PatternCursorPos0_4 + + Push CX + Mov SI, Offset KeyBoardTable + + And CH, Not 6 ; Remove shift mask. + +PE_PatternCursorPos0_1: + LodsW + Cmp AX, 0FFFFh + JE PE_PatternCursorPos0_3 + + Cmp AX, CX + JNE PE_PatternCursorPos0_2 + + Pop CX + + Mov BX, 3Ah + Call K_IsKeyDown + JNZ PE_PatternCursorPreview + + Jmp PE_NewNote + +PE_PatternCursorPreview: + Mov AX, 12 + Mul BaseOctave + Mov BX, AX + LodsW + Add AX, BX + + Mov SI, Offset PreviewNote + + Cmp AX, MAXNOTE + JA PE_PatternCursorPos0_4 + + Mov AH, LastInstrument + Mov [SI], AX + + Mov AX, CS:Channel + Mov DH, 32 + Call Music_PlayNote + + Xor AX, AX + Ret + +PE_PatternCursorPos0_2: + LodsW ; Add SI, 2 + Jmp PE_PatternCursorPos0_1 + +PE_PatternCursorPos0_3: + Pop CX + + Mov AL, NONOTE + Cmp DX, '.' + JE WipeNote + + Inc AX + Cmp DX, '1' + JE WipeNote + Cmp DX, '!' + JE WipeNote + + Inc AX + Cmp DX, '`' + JE WipeNote + Cmp DX, '~' + JE WipeNote + + Cmp DX, ' ' + JE NoteSpace + + Cmp DX, '4' + JE PEFunction_PlayCurrentNote + Cmp DX, '$' + JE PEFunction_PlayCurrentNote + + Cmp DX, '8' + JE PEFunction_PlayCurrentRow + +PE_PatternCursorPos0_4: + Xor AX, AX + Ret + +EndP PE_PatternCursorPos0 + +; + +Proc NoteSpace Far + + Mov AL, LastNote + Jmp PE_NewNote4 + +EndP NoteSpace + +; + +Proc WipeNote Far + + Mov AH, EditMask + + Mov BP, 1 + Cmp Template, 0 + JE WipeNote4 + + Cmp BlockDataArea, 0 + JE WipeNote4 + + Mov FS, BlockDataArea + Cmp Word Ptr [FS:2], 1 + JNE WipeNote4 + + Mov BP, [FS:0] + +WipeNote4: + Mov CX, BP + Mov CH, 1 + Call NetworkPartialPattern + +WipeNote5: + Mov [ES:DI], AL + Mov LastNote, AL + Test AH, 1 + JZ WipeNote1 + + Mov Byte Ptr [ES:DI+1], 0 + +WipeNote1: + Test AH, 2 + JZ WipeNote2 + + Mov Byte Ptr [ES:DI+2], 0FFh + +WipeNote2: + Test AH, 4 + JZ WipeNote3 + + Mov Word Ptr [ES:DI+3], 0 + +WipeNote3: + Add DI, 5 + Dec BP + JNZ WipeNote5 + +IF CHORDENTRY + Cmp ShiftPressed, 0 + JE PE_GotoNextInput + + Push SkipValue + Mov SkipValue, 0 + Mov NoteEntered, 1 + + Call PE_GotoNextInput + Pop SkipValue + + Mov AX, 1 + Ret +ELSE + Jmp PE_GotoNextInput +ENDIF + +EndP WipeNote + +; + +Proc PE_GotoNextInput Far + + + Mov CX, PatternCursor + And CX, CX + JZ PE_GotoNextInput4 + + Cmp CX, 1 + JE PE_GotoNextInput4 + + Cmp CX, 2 + JNE PE_GotoNextInput5 + +PE_GotoNextInput7: + Inc PatternCursor + Jmp PE_GotoNextInput3 + +PE_GotoNextInput5: + Cmp CX, 3 + JNE PE_GotoNextInput6 + +PE_GotoNextInput8: + Dec PatternCursor + Jmp PE_GotoNextInput4 + +PE_GotoNextInput6: + Cmp CX, 4 + JE PE_GotoNextInput7 + + Cmp CX, 5 + JE PE_GotoNextInput8 + + Cmp CX, 6 + JNE PE_GotoNextInput9 + + Cmp CommandToValue, 0 + JZ PE_GotoNextInput4 + + Jmp PE_GotoNextInput7 + +PE_GotoNextInput9: + Cmp CX, 7 + JE PE_GotoNextInput7 + + Cmp CommandToValue, 0 + JE PE_GotoNextInput8 + + Sub PatternCursor, 2 + +PE_GotoNextInput4: + Mov AX, Row + Mov BX, Channel + Add AX, SkipValue + Cmp AX, MaxRow + JA PE_GotoNextInput3 + + Mov Row, AX + Cmp PatternCursor, 0 + JNE PE_GotoNextInput10 + + Cmp [MultiChannelInfo+BX], 0 + JE PE_GotoNextInput10 + + Mov DX, BX + Xor CX, CX + +PE_GotoNextInput1: + Inc BX + Cmp BX, 63 + JBE PE_GotoNextInput11 + + Inc CX + +PE_GotoNextInput11: + And BX, 63 + Cmp DX, BX + JE PE_GotoNextInput2 + + Cmp [MultiChannelInfo+BX], 0 + JE PE_GotoNextInput1 + +PE_GotoNextInput2: + Mov Channel, BX + Cmp SkipValue, 0 + JNE PE_GotoNextInput3 + + And CX, CX + JZ PE_GotoNextInput3 + + Mov Word Ptr [Modified], 101h + + Jmp PEFunction_Down + +PE_GotoNextInput10: + Cmp SkipValue, 0 + JNE PE_GotoNextInput3 + + Mov AX, Channel + Mov CX, Row + Inc AX + Cmp AX, 63 + JBE PE_GotoNextInput12 + Cmp CX, MaxRow + JAE PE_GotoNextInput3 + + Inc CX + +PE_GotoNextInput12: + And AX, 63 + Mov Row, CX + Mov Channel, AX + +PE_GotoNextInput3: + Mov Word Ptr [Modified], 101h + + Mov AX, 1 + Ret + +EndP PE_GotoNextInput + +; + +Proc TemplateSetup + + Mov AH, AL + Push AX + + Mov BX, Channel + Mov AX, 320 + Mov BP, MaxRow + Inc BP + Mul BP + Mov BP, AX ; BP = max offset. + + Mov AX, 64 + Mul Row + Add AX, BX + Mov CX, 5 + Mul CX + + Mov DI, AX ; DI = pattern offset. + Mov ES, PatternDataArea + Mov DS, BlockDataArea + Xor SI, SI + + LodsW + Mov DX, AX ; DX = width + LodsW + Mov CX, AX ; CX = height + + Pop AX ; AH = note. + Sub AH, [DS:4] + + Ret + +EndP TemplateSetup + +; + +Proc PE_TemplateOverwrite ; AX = note + + Push DS + Push ES + + Call TemplateSetup + +PE_TemplateOverWrite1: + Push BX + Push CX + Push DI + + Mov CX, DX + +PE_TemplateOverWrite2: + Cmp BX, 64 + JAE PE_TemplateOverWrite3 + + LodsB + Cmp AL, MAXNOTE + JA PE_TemplateOverWrite6 + + Add AL, AH + Cmp AL, MAXNOTE + JBE PE_TemplateOverWrite6 + + Mov AL, NONOTE + +PE_TemplateOverWrite6: + StosB + MovsW + MovsW + Jmp PE_TemplateOverWrite4 + +PE_TemplateOverWrite3: + Add SI, 5 + Add DI, 5 + +PE_TemplateOverWrite4: + Inc BX + Loop PE_TemplateOverWrite2 + + Pop DI + Pop CX + Pop BX + Add DI, 320 + Cmp DI, BP + JAE PE_TemplateOverWrite5 + + Loop PE_TemplateOverWrite1 + +PE_TemplateOverWrite5: + Pop ES + Pop DS + Ret + +EndP PE_TemplateOverWrite + +; + +Proc PE_TemplateMixPattern ; AX = note + + Push DS + Push ES + + Call TemplateSetup + +PE_TemplateMixPattern1: + Push BX + Push CX + Push DI + + Mov CX, DX + +PE_TemplateMixPattern2: + Cmp BX, 64 + JAE PE_TemplateMixPattern3 + + Mov AL, [DS:SI] + Cmp AL, MAXNOTE + JA PE_TemplateMixPattern6 + + Add AL, AH + Cmp AL, MAXNOTE + JBE PE_TemplateMixPattern6 + + Mov AL, NONOTE + +PE_TemplateMixPattern6: + Cmp Byte Ptr [ES:DI], NONOTE + JNE PE_TemplateMixPattern7 + + Mov [ES:DI], AL + +PE_TemplateMixPattern7: + Cmp Byte Ptr [ES:DI+1], 0 + JNE PE_TemplateMixPattern8 + + Mov AL, [DS:SI+1] + Mov [ES:DI+1], AL + +PE_TemplateMixPattern8: + Cmp Byte Ptr [ES:DI+2], 0FFh + JNE PE_TemplateMixPattern9 + + Mov AL, [DS:SI+2] + Mov [ES:DI+2], AL + +PE_TemplateMixPattern9: + Cmp Word Ptr [ES:DI+3], 0 + JNE PE_TemplateMixPattern3 + + Push AX + Mov AX, [DS:SI+3] + Mov [ES:DI+3], AX + Pop AX + +PE_TemplateMixPattern3: + Add SI, 5 + Add DI, 5 + +PE_TemplateMixPattern4: + Inc BX + Loop PE_TemplateMixPattern2 + + Pop DI + Pop CX + Pop BX + Add DI, 320 + Cmp DI, BP + JAE PE_TemplateMixPattern5 + + Loop PE_TemplateMixPattern1 + +PE_TemplateMixPattern5: + Pop ES + Pop DS + Ret + +EndP PE_TemplateMixPattern + +; + +Proc PE_TemplateMixClipBoard ; AX = note + + Push DS + Push ES + + Call TemplateSetup + +PE_TemplateMixClipBoard1: + Push BX + Push CX + Push DI + + Mov CX, DX + +PE_TemplateMixClipBoard2: + Cmp BX, 64 + JAE PE_TemplateMixClipBoard3 + + Mov AL, [DS:SI] + Cmp AL, MAXNOTE + JA PE_TemplateMixClipBoard6 + + Add AL, AH + Cmp AL, MAXNOTE + JBE PE_TemplateMixClipBoard6 + + Mov AL, NONOTE + +PE_TemplateMixClipBoard6: + Cmp Byte Ptr [DS:SI], NONOTE + JE PE_TemplateMixClipBoard7 + + Mov [ES:DI], AL + +PE_TemplateMixClipBoard7: + Cmp Byte Ptr [DS:SI+1], 0 + JE PE_TemplateMixClipBoard8 + + Mov AL, [DS:SI+1] + Mov [ES:DI+1], AL + +PE_TemplateMixClipBoard8: + Cmp Byte Ptr [DS:SI+2], 0FFh + JE PE_TemplateMixClipBoard9 + + Mov AL, [DS:SI+2] + Mov [ES:DI+2], AL + +PE_TemplateMixClipBoard9: + Cmp Word Ptr [DS:SI+3], 0 + JE PE_TemplateMixClipBoard3 + + Push AX + Mov AX, [DS:SI+3] + Mov [ES:DI+3], AX + Pop AX + +PE_TemplateMixClipBoard3: + Add SI, 5 + Add DI, 5 + +PE_TemplateMixClipBoard4: + Inc BX + Loop PE_TemplateMixClipBoard2 + + Pop DI + Pop CX + Pop BX + Add DI, 320 + Cmp DI, BP + JAE PE_TemplateMixClipBoard5 + + Loop PE_TemplateMixClipBoard1 + +PE_TemplateMixClipBoard5: + Pop ES + Pop DS + Ret + +EndP PE_TemplateMixClipBoard + +; + +Proc PE_TemplateNotesOnly + + Push DS + Push ES + + Call TemplateSetup + +PE_TemplateNotesOnly1: + Push BP + Push BX + Push CX + Push DI + + Mov CX, DX + Mov BP, Word Ptr [CS:EditMask] + +PE_TemplateNotesOnly2: + Cmp BX, 64 + JAE PE_TemplateNotesOnly3 + + Or BP, 8 + Mov AL, [SI] + Cmp AL, MAXNOTE + JA PE_TemplateNotesOnly7 + + Add AL, AH + And BP, Not 8 + Cmp AL, MAXNOTE + JA PE_TemplateNotesOnly3 + +PE_TemplateNotesOnly7: + Mov [ES:DI], AL + + Test BP, 8 + JNZ PE_TemplateNotesOnly3 + Test BP, 1 + JZ PE_TemplateNotesOnly5 + + Mov AL, CS:LastInstrument + Mov [ES:DI+1], AL + +PE_TemplateNotesOnly5: + Test BP, 2 + JZ PE_TemplateNotesOnly6 + + Mov AL, CS:LastVolume + Mov [ES:DI+2], AL + +PE_TemplateNotesOnly6: + Test BP, 4 + JZ PE_TemplateNotesOnly3 + + Mov AX, [Word Ptr CS:LastCommand] + Mov [ES:DI+3], AX + +PE_TemplateNotesOnly3: + Add SI, 5 + Add DI, 5 + + Inc BX + Loop PE_TemplateNotesOnly2 + + Pop DI + Pop CX + Pop BX + Pop BP + + Add DI, 320 + Cmp DI, BP + JAE PE_TemplateNotesOnly4 + + Loop PE_TemplateNotesOnly1 + +PE_TemplateNotesOnly4: + Pop ES + Pop DS + + Ret + +EndP PE_TemplateNotesOnly + +; + +Proc PE_Template Far ; AX = note. + + Mov BX, BlockDataArea + Test BX, BX + JZ PEFunction_NoBlockData + + Mov ES, BX + Cmp Byte Ptr [ES:4], 119 + JBE PE_Template3 + + Mov DI, Offset O1_TemplateErrorList + Mov CX, 2 + Call M_Object1List + + Mov AX, 1 + Ret + +PE_Template3: + Mov Word Ptr [Modified], 101h + + Mov BL, Template + Cmp BL, 2 + JE PE_Template1 + JA PE_Template2 + + Call PE_TemplateOverWrite + Jmp PE_Template4 + +PE_Template1: + Call PE_TemplateMixPattern + Jmp PE_Template4 + +PE_Template2: + Cmp BL, 4 + JE PE_Template6 + + Call PE_TemplateMixClipBoard + Jmp PE_Template4 + +PE_Template6: + Call PE_TemplateNotesOnly + +PE_Template4: ; Play notes, if clipboard height = 1 + Mov CL, [ES:0] + Mov CH, [ES:2] + Call NetworkPartialPattern + + Cmp Word Ptr [ES:2], 1 ; height + JNE PE_TemplateNoPlay + + Mov AX, 64 + Mul Row + Add AX, Channel + Mov DX, 5 + Mul DX + Mov SI, AX + + Mov CX, [ES:0] ; CX = Width + Mov AX, Channel + Push DS + Mov DS, PatternDataArea + Mov DH, 32 + +PE_TemplatePlay: + Call Music_PlayNote + + Add SI, 5 + Inc AX + Dec CX + JNZ PE_TemplatePlay + + Pop DS + +PE_TemplateNoPlay: + Cmp SkipValue, 0 + JNE PE_GotoNextInput + + Mov AX, Row + Mov BX, MaxRow + Add AX, [ES:2] + Cmp AX, BX + JBE PE_Template5 + + Mov AX, BX + +PE_Template5: + Mov Row, AX + + Mov AX, 1 + Ret + +EndP PE_Template + +; + +Proc PE_NewNote Far + + Mov AX, 12 + Mul BaseOctave + Mov BX, AX + LodsW + Add AX, BX + + Cmp AX, MAXNOTE + JBE PE_NewNote5 + + Mov AX, 1 + Ret + +PE_NewNote5: + Cmp Template, 0 + JNE PE_Template + +PE_NewNote4: + Mov AH, EditMask + + Mov SI, DI + + Mov LastNote, AL + StosB + + Test AH, 1 + JZ PE_NewNote1 + + Mov AL, LastInstrument + Mov [ES:DI], AL + +PE_NewNote1: + Test AH, 2 + JZ PE_NewNote2 + + Mov AL, LastVolume + Mov [ES:DI+1], AL + +PE_NewNote2: + Test AH, 4 + JZ PE_NewNote3 + + Mov AL, LastCommand + Mov AH, LastCommandValue + Mov [ES:DI+2], AX + +PE_NewNote3: ; Play routine reqd here... + Push DS + + Push ES + Pop DS ; DS = patterndatasegment + + Mov AX, CS:Channel + Mov DH, 32 + Call Music_PlayNote + + Pop DS + + Mov CX, 101h + Call NetworkPartialPattern + +IF CHORDENTRY + Cmp ShiftPressed, 0 + JE PE_GotoNextInput + + Push SkipValue + Mov SkipValue, 0 + Mov NoteEntered, 1 + + Call PE_GotoNextInput + Pop SkipValue + + Mov AX, 1 + Ret +ELSE + Jmp PE_GotoNextInput +ENDIF + +EndP PE_NewNote + +; + +Proc PEFunction_Delete Far + + Mov Word Ptr [Modified], 101h + + Mov AX, 320 + Mul MaxRow + + Call GetPatternOffset + + Mov BP, 1 + Cmp Template, 0 + JE PEFunction_Delete3 + + Cmp PatternCursor, 0 + JNE PEFunction_Delete3 + + Cmp BlockDataArea, 0 + JE PEFunction_Delete3 + + Mov FS, BlockDataArea + Cmp Word Ptr [FS:2], 1 + JNE PEFunction_Delete3 + + Mov BP, [FS:0] + +PEFunction_Delete3: + Mov CX, BP + Mov CH, Byte Ptr MaxRow + Sub CH, Byte Ptr Row + Inc CH + Call NetworkPartialPattern + + Push AX DI + + Mov SI, DI + Push ES + Pop DS ; DS:SI and ES:DI point to pat + + Add SI, 320 + Mov DX, 315 + +PEFunction_Delete1: + Cmp DI, AX + JAE PEFunction_Delete2 + + Mov CX, 5 + Rep MovsB + Add SI, DX + Add DI, DX + Jmp PEFunction_Delete1 + +PEFunction_Delete2: + Mov AX, NONOTE + StosW + Mov AL, 0FFh + StosB + Xor AX, AX + StosW + + Pop DI AX + Add DI, 5 + + Dec BP + JNZ PEFunction_Delete3 + + Mov AX, 1 + Ret + +EndP PEFunction_Delete + +; + +Proc PEFunction_Insert Far + + Mov BP, 1 + Cmp Template, 0 + JE PEFunction_Insert3 + + Cmp PatternCursor, 0 + JNE PEFunction_Insert3 + + Cmp BlockDataArea, 0 + JE PEFunction_Insert3 + + Mov FS, BlockDataArea + Cmp Word Ptr [FS:2], 1 + JNE PEFunction_Insert3 + + Mov BP, [FS:0] + +PEFunction_Insert3: + Mov Word Ptr [Modified], 101h + + Mov CX, BP + Mov CH, Byte Ptr MaxRow + Sub CH, Byte Ptr Row + Inc CH + Call NetworkPartialPattern + + Mov AX, 64 + Mul MaxRow + Add AX, Channel + Mov BX, 5 + Mul BX + Mov SI, AX + Call GetPatternOffset + Push ES + Pop DS + Mov BX, DI + Mov DX, -325 + +PEFunction_Insert4: + Push SI + + Mov DI, SI + Sub SI, 320 + +PEFunction_Insert1: + Cmp DI, BX + JBE PEFunction_Insert2 + + Mov CX, 5 + Rep MovsB + Add SI, DX + Add DI, DX + Jmp PEFunction_Insert1 + +PEFunction_Insert2: + Mov AX, NONOTE + StosW + Mov AL, 0FFh + StosB + Xor AX, AX + StosW + + Pop SI + Add SI, 5 + Add BX, 5 + + Dec BP + JNZ PEFunction_Insert4 + + Mov AX, 1 + Ret + +EndP PEFunction_Insert + +; + +Proc PEFunction_RowDelete Far + + Cmp Byte Ptr LastKeyBoard2, 0D3h + JE PEFunction_RowDelete2 + + Mov DI, 20 + Call PE_AddToUndoBuffer + +PEFunction_RowDelete2: + Mov AX, 320 + Mul Row + Mov DI, AX + + Mov CX, MaxRow + Sub CX, Row + Mov AX, 320 + Mul CX + Mov CX, AX + + Mov DS, PatternDataArea + Push DS + Pop ES + Mov SI, DI + Add SI, 320 + Rep MovsB + + Mov DX, 64 + + Push CS + Pop DS + +PEFunction_RowDelete1: + Mov CX, 5 + Mov SI, Offset EmptyData + Rep MovsB + + Dec DX + JNZ PEFunction_RowDelete1 + + Mov BL, 0 + Mov BH, Byte Ptr Row + Mov CL, 64 + Mov CH, Byte Ptr MaxRow + Sub CH, Byte Ptr Row + Inc CH + Call NetworkPatternBlock + + Mov AX, 1 + Ret + +EndP PEFunction_RowDelete + + +; + +Proc PEFunction_RowInsert Far + + Cmp Byte Ptr LastKeyBoard2, 0D2h + JE PEFunction_RowInsert2 + + Mov DI, 19 + Call PE_AddToUndoBuffer + +PEFunction_RowInsert2: + Mov AX, 320 + Mul MaxRow + Add AX, 63*5 + Mov DI, AX + + Mov CX, MaxRow + Sub CX, Row + Mov AX, 320 + Mul CX + Mov CX, AX + + Mov DS, PatternDataArea + Push DS + Pop ES + Mov SI, DI + Sub SI, 320 + StD + Rep MovsB + ClD + + Push CS + Pop DS + + Mov AX, 320 + Mul Row + Mov DI, AX + + Mov DX, 64 + + +PEFunction_RowInsert1: + Mov CX, 5 + Mov SI, Offset EmptyData + Rep MovsB + + Dec DX + JNZ PEFunction_RowInsert1 + + Mov BL, 0 + Mov BH, Byte Ptr Row + Mov CL, 64 + Mov CH, Byte Ptr MaxRow + Sub CH, BH + Inc CH + Call NetworkPatternBlock + + Mov AX, 1 + Ret + +EndP PEFunction_RowInsert + +; + +Proc PEFunction_DecreaseInstrument Far + + Sub LastInstrument, 1 + AdC LastInstrument, 0 + + Mov AX, 1 + Ret + +EndP PEFunction_DecreaseInstrument + +; + +Proc PEFunction_IncreaseInstrument Far + + Cmp LastInstrument, 99 + AdC LastInstrument, 0 + + Mov AX, 1 + Ret + +EndP PEFunction_IncreaseInstrument + +; + +Proc PEFunction_DecreaseOctave Far + + Push CS + Pop DS + + Sub BaseOctave, 1 + AdC BaseOctave, 0 + + Mov AX, 1 + Ret + +EndP PEFunction_DecreaseOctave + +; + +Proc PEFunction_IncreaseOctave Far + + Push CS + Pop DS + + Cmp BaseOctave, 9 + AdC BaseOctave, 0 + + Mov AX, 1 + Ret + +EndP PEFunction_IncreaseOctave + +; + +Proc PE_PatternCursorPos2 Far ; Tens column of ins. + + Test CL, CL + JZ PE_PatternCursorPos2_1 + + Mov BX, Offset PE_GotoNextInput4 + Mov AL, LastInstrument + Cmp DX, ' ' + JE PE_PatternCursorPos2_2 + + Xor AL, AL + Cmp DX, '.' + JE PE_PatternCursorPos2_2 + + Cmp DX, '0' + JB PE_PatternCursorPos2_1 + + Cmp DX, '9' + JA PE_PatternCursorPos2_1 + + MovZX AX, Byte Ptr [ES:DI+1] + Mov CL, 10 + Div CL + ; AH = units/AL = tens + Mov BL, AH + Mov AL, DL + Sub AL, '0' + + Mul CL + Add AL, BL + + Mov BX, Offset PE_GotoNextInput + + Mov LastInstrument, AL + +PE_PatternCursorPos2_2: + Mov [ES:DI+1], AL + + Mov CX, 101h + Call NetworkPartialPattern + + Jmp BX + +PE_PatternCursorPos2_1: + Xor AX, AX + Ret + +EndP PE_PatternCursorPos2 + +; + +Proc PE_PatternCursorPos3 Far ; Unit column of ins. + + Test CL, CL + JZ PE_PatternCursorPos3_1 + + Mov BX, Offset PE_GotoNextInput4 + Mov AL, LastInstrument + Cmp DX, ' ' + JE PE_PatternCursorPos3_2 + + Xor AL, AL + Cmp DX, '.' + JE PE_PatternCursorPos3_2 + + Cmp DX, '0' + JB PE_PatternCursorPos3_1 + + Cmp DX, '9' + JA PE_PatternCursorPos3_1 + + MovZX AX, Byte Ptr [ES:DI+1] + Mov CL, 10 + Div CL + ; AH = units/AL = tens + Mul CL + Sub DL, '0' + Add AL, DL + + Mov BX, Offset PE_GotoNextInput + Mov LastInstrument, AL + +PE_PatternCursorPos3_2: + Mov [ES:DI+1], AL + + Mov CX, 101h + Call NetworkPartialPattern + + Jmp BX + +PE_PatternCursorPos3_1: + Xor AX, AX + Ret + +EndP PE_PatternCursorPos3 + +; + +Proc PE_PatternCursorPos4 Far ; Tens column of vol. + + Test CL, CL + JZ PE_PatternCursorPos4_1 + + Cmp DX, '`' + JE PE_VolumePan + + Mov BX, Offset PE_GotoNextInput4 + Mov AL, LastVolume + Cmp DX, ' ' + JE PE_PatternCursorPos4_9 + + Mov AL, 0FFh + Cmp DX, '.' + JE PE_PatternCursorPos4_9 + + Mov BX, Offset PE_GotoNextInput + Mov AL, [ES:DI+2] + Cmp AL, 255 + JNE PE_PatternCursorPos4_2 + + Xor AL, AL + +PE_PatternCursorPos4_2: + And AX, 7Fh + Cmp AL, 65 + JB PE_PatternCursorPos4_4 + + Sub AL, 65 + +PE_PatternCursorPos4_4: + Cmp DX, '0' + JB PE_PatternCursorPos4_5 + + Cmp DX, '9' + JA PE_PatternCursorPos4_5 + + Mov CL, 10 + Div CL + ; AH = units/AL = tens + Mov DH, AH + Mov AL, DL + Sub AL, '0' + + Mul CL + Add AL, DH + + Cmp AL, 64 + JBE PE_PatternCursorPos4_3 + + Mov AL, 64 + +PE_PatternCursorPos4_3: + Or AL, VolumePan ; Panning flag. + +PE_PatternCursorPos4_9: + Mov [ES:DI+2], AL + Mov LastVolume, AL + + Mov CX, 101h + Call NetworkPartialPattern + + Jmp BX + +PE_PatternCursorPos4_5: + Cmp DX, 'A' + JB PE_PatternCursorPos4_6 + Cmp DX, 'H' + JA PE_PatternCursorPos4_6 + Sub DX, 'A' + Jmp PE_PatternCursorPos4_7 + +PE_PatternCursorPos4_6: + Cmp DX, 'a' + JB PE_PatternCursorPos4_1 + Cmp DX, 'h' + JA PE_PatternCursorPos4_1 + + Sub DX, 'a' + +PE_PatternCursorPos4_7: + Mov CL, 10 + Div CL + Mov CH, AH + Mov AL, DL + Mul CL ; AL = tens. + + Cmp AL, 60 + JB PE_PatternCursorPos4_8 + + Add AL, 128-60 + +PE_PatternCursorPos4_8: + Add AL, 65 + Add AL, CH + Jmp PE_PatternCursorPos4_9 + +PE_PatternCursorPos4_1: + Xor AX, AX + Ret + +EndP PE_PatternCursorPos4 + +; + +Proc PE_VolumePan Far + + Xor VolumePan, 80h + Mov SI, Offset PanningControlSetMsg + + JNZ PE_VolumePan1 + + Mov SI, Offset VolumeControlSetMsg + +PE_VolumePan1: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP PE_VolumePan + +; + +Proc PE_PatternCursorPos5 Far ; Unit column of vol. + + Test CL, CL + JZ PE_PatternCursorPos5_1 + + Cmp DX, '`' + JE PE_VolumePan + + Mov BX, Offset PE_GotoNextInput4 + Mov AL, LastVolume + Cmp DX, ' ' + JE PE_PatternCursorPos5_6 + + Mov AL, 0FFh + Cmp DX, '.' + JE PE_PatternCursorPos5_6 + + Mov BX, Offset PE_GotoNextInput + Cmp DX, '0' + JB PE_PatternCursorPos5_1 + + Cmp DX, '9' + JA PE_PatternCursorPos5_1 + + Mov AL, [ES:DI+2] + Cmp AL, 255 + JNE PE_PatternCursorPos5_2 + + Xor AL, AL + +PE_PatternCursorPos5_2: + And AX, 7Fh + Cmp AL, 65 + JB PE_PatternCursorPos5_4 + + Sub AL, 65 + +PE_PatternCursorPos5_4: + Mov CL, 10 + Div CL + ; AH = units/AL = tens + Mul CL + Sub DL, '0' + Add AL, DL + + Mov AH, [ES:DI+2] + Cmp AH, 255 + JE PE_PatternCursorPos5_5 + And AH, 7Fh + Cmp AH, 64 + JBE PE_PatternCursorPos5_5 + + Add AL, 65 + Test Byte Ptr [ES:DI+2], 80h + JZ PE_PatternCursorPos5_6 + Add AL, 128 + Jmp PE_PatternCursorPos5_6 + +PE_PatternCursorPos5_5: + Cmp AL, 64 + JBE PE_PatternCursorPos5_3 + + Mov AL, 64 + +PE_PatternCursorPos5_3: + Or AL, VolumePan + +PE_PatternCursorPos5_6: + Mov [ES:DI+2], AL + Mov LastVolume, AL + + Mov CX, 101h + Call NetworkPartialPattern + + Jmp BX + +PE_PatternCursorPos5_1: + Xor AX, AX + Ret + +EndP PE_PatternCursorPos5 + +; + +Proc PE_PatternCursorPos6 Far + + Test CL, CL + JZ PE_PatternCursorPos6_2 + + Mov AL, LastCommand + Cmp DX, ' ' + JE PE_PatternCursorPos6_3 + + Xor AL, AL + Cmp DX, '.' + JE PE_PatternCursorPos6_3 + + Mov AX, DX + + Cmp AX, 'a' + JB PE_PatternCursorPos6_1 + + Cmp AX, 'z' + JA PE_PatternCursorPos6_1 + + Sub AX, 32 + +PE_PatternCursorPos6_1: + Cmp AX, 'A' + JB PE_PatternCursorPos6_2 + + Cmp AX, 'Z' + JA PE_PatternCursorPos6_2 + + Sub AL, '@' + +PE_PatternCursorPos6_3: + Mov LastCommand, AL + Mov [ES:DI+3], AL + + Mov CX, 101h + Call NetworkPartialPattern + + Jmp PE_GotoNextInput + +PE_PatternCursorPos6_2: + Xor AX, AX + Ret + +EndP PE_PatternCursorPos6 + +; + +Proc PE_PatternCursorPos7 Far + + Test CL, CL + JZ PE_PatternCursorPos7_3 + + Mov BX, Offset PE_GotoNextInput4 + Xor AL, AL + Cmp DX, '.' + JE PE_PatternCursorPos7_5 + + Mov AL, LastCommandValue + Cmp DX, ' ' + JE PE_PatternCursorPos7_5 + + Mov BX, Offset PE_GotoNextInput + Mov AX, DX + Cmp AX, 'a' + JB PE_PatternCursorPos7_1 + + Cmp AX, 'f' + JA PE_PatternCursorPos7_1 + + Sub AX, 32 + +PE_PatternCursorPos7_1: + Cmp AX, 'A' + JB PE_PatternCursorPos7_2 + + Cmp AX, 'F' + JA PE_PatternCursorPos7_2 + + Sub AX, 'A'-10 + Jmp PE_PatternCursorPos7_4 + +PE_PatternCursorPos7_2: + Cmp AX, '0' + JB PE_PatternCursorPos7_3 + + Cmp AX, '9' + JA PE_PatternCursorPos7_3 + + Sub AX, '0' + +PE_PatternCursorPos7_4: + Mov AH, AL + Mov AL, [ES:DI+4] + SHL AH, 4 + And AL, 0Fh + Or AL, AH + +PE_PatternCursorPos7_5: + Mov [ES:DI+4], AL + Mov LastCommandValue, AL + + Mov CX, 101h + Call NetworkPartialPattern + + Jmp BX + +PE_PatternCursorPos7_3: + Xor AX, AX + Ret + +EndP PE_PatternCursorPos7 + +; + +Proc PE_PatternCursorPos8 Far + + Test CL, CL + JZ PE_PatternCursorPos8_3 + + Mov BX, Offset PE_GotoNextInput4 + Xor AH, AH + Cmp DX, '.' + JE PE_PatternCursorPos8_5 + + Mov AH, LastCommandValue + Cmp DX, ' ' + JE PE_PatternCursorPos8_5 + + Mov BX, Offset PE_GotoNextInput + Mov AX, DX + Cmp AX, 'a' + JB PE_PatternCursorPos8_1 + + Cmp AX, 'f' + JA PE_PatternCursorPos8_1 + + Sub AX, 32 + +PE_PatternCursorPos8_1: + Cmp AX, 'A' + JB PE_PatternCursorPos8_2 + + Cmp AX, 'F' + JA PE_PatternCursorPos8_2 + + Sub AX, 'A'-10 + Jmp PE_PatternCursorPos8_4 + +PE_PatternCursorPos8_2: + Cmp AX, '0' + JB PE_PatternCursorPos7_3 + + Cmp AX, '9' + JA PE_PatternCursorPos7_3 + + Sub AX, '0' + +PE_PatternCursorPos8_4: + Mov AH, [ES:DI+4] + And AH, 0F0h + Or AH, AL + +PE_PatternCursorPos8_5: + Mov [ES:DI+4], AH + Mov LastCommandValue, AH + + Mov CX, 101h + Call NetworkPartialPattern + + Jmp BX + +PE_PatternCursorPos8_3: + Xor AX, AX + Ret + +EndP PE_PatternCursorPos8 + +; + +Proc PE_SetCommandCursor Far + + Push CS + Pop ES + Mov DI, Offset CommandToValue +; Mov AL, [SI+24] +; Mov CS:CommandToValue, AL + + Ret + +EndP PE_SetCommandCursor + +; + +Proc PEFunction_MarkBeginBlock Far + + Mov AX, Channel + Mov BX, Row + +PEFunction_MarkBeginBlockChain: + Cmp BlockMark, 0 + JNE PEFunction_MarkBeginBlock1 + + Mov BlockMark, 1 + Mov BlockLeft, AX + Mov BlockRight, AX + Mov BlockTop, BX + Mov BlockBottom, BX + Jmp PEFunction_MarkBeginBlock5 + +PEFunction_MarkBeginBlock1: + Cmp AX, BlockRight + JBE PEFunction_MarkBeginBlock2 + + Mov CX, BlockRight + Mov BlockRight, AX + Mov BlockLeft, CX + Jmp PEFunction_MarkBeginBlock3 + +PEFunction_MarkBeginBlock2: + Mov BlockLeft, AX + +PEFunction_MarkBeginBlock3: + Cmp BX, BlockBottom + JBE PEFunction_MarkBeginBlock4 + + Mov CX, BlockBottom + Mov BlockBottom, BX + Mov BlockTop, CX + Jmp PEFunction_MarkBeginBlock5 + +PEFunction_MarkBeginBlock4: + Mov BlockTop, BX + +PEFunction_MarkBeginBlock5: + Mov AX, 1 + Ret + +EndP PEFunction_MarkBeginBlock + +; + +Proc PEFunction_MarkEndBlock Far + + Mov AX, Channel + Mov BX, Row + +PEFunction_MarkEndChain: + Cmp BlockMark, 0 + JNE PEFunction_MarkEndBlock1 + + Mov BlockMark, 1 + Mov BlockLeft, AX + Mov BlockRight, AX + Mov BlockTop, BX + Mov BlockBottom, BX + Jmp PEFunction_MarkEndBlock5 + +PEFunction_MarkEndBlock1: + Cmp AX, BlockLeft + JAE PEFunction_MarkEndBlock2 + + Mov CX, BlockLeft + Mov BlockLeft, AX + Mov BlockRight, CX + Jmp PEFunction_MarkEndBlock3 + +PEFunction_MarkEndBlock2: + Mov BlockRight, AX + +PEFunction_MarkEndBlock3: + Cmp BX, BlockTop + JAE PEFunction_MarkEndBlock4 + + Mov CX, BlockTop + Mov BlockTop, BX + Mov BlockBottom, CX + Jmp PEFunction_MarkEndBlock5 + +PEFunction_MarkEndBlock4: + Mov BlockBottom, BX + +PEFunction_MarkEndBlock5: + Mov AX, 1 + Ret + +EndP PEFunction_MarkEndBlock + +; + +Proc PEFunction_AltD Far + + Mov AX, Channel + Mov BX, Row + MovZX DX, RowHiLight2 + + Cmp Word Ptr [LastKeyBoard2+2], 2000h + JNE PEFunction_AltD1 + ; OK, at least 1 Alt-D already.. + ; Now double length... + Mov DX, BlockBottom + Sub DX, BlockTop + Inc DX + Add DX, DX + Add DX, BlockTop + Dec DX + Cmp DX, MaxRow + JBE PEFunction_AltD3 + + Mov DX, MaxRow + +PEFunction_AltD3: + Mov BlockBottom, DX + Jmp PEFunction_AltD4 + +PEFunction_AltD1: + Dec DX + Mov BlockTop, BX + Mov BlockLeft, AX + Mov BlockRight, AX + + Add BX, DX + Cmp BX, MaxRow + JBE PEFunction_AltD2 + + Mov BX, MaxRow + +PEFunction_AltD2: + Mov BlockBottom, BX + Mov BlockMark, 1 + +PEFunction_AltD4: + Mov AX, 1 + Ret + +EndP PEFunction_AltD + +; + +Proc PEFunction_AltS Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Cmp [Word Ptr LastKeyBoard2+2], 1F00h + JE PEFunction_AltS5 + Call NetworkBlock + + Mov DI, 12 + Call PE_AddToUndoBuffer + +PEFunction_AltS5: + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + + Mov SI, AX + Inc SI + + Mov AH, LastInstrument + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + Mov CX, BlockBottom + Sub CX, BlockTop + Inc CX + + Mov DS, PatternDataArea + +PEFunction_AltS1: + Push SI + Push CX + + Mov CX, DX + +PEFunction_AltS2: + Cmp Byte Ptr [SI], 0 + JE PEFunction_AltS3 + + Mov [SI], AH + +PEFunction_AltS3: + Add SI, 5 + Loop PEFunction_AltS2 + + Pop CX + Pop SI + Add SI, 320 + Loop PEFunction_AltS1 + +PEFunction_AltS4: + Mov AX, 1 + Ret + +EndP PEFunction_AltS + +; + +Proc PEGetVolume ; Given DL = note, DH = instrument + ; Returns DL, Carry if none + + Push AX BX DI DS + + Cmp DL, MAXNOTE + JA PEGetVolumeError + + Call Music_GetSongSegment + Mov DS, AX + + Mov BL, DH + And BX, 0FFh + JZ PEGetVolumeError + Add BX, BX + + Test Byte Ptr [DS:2Ch], 4 + JZ PEGetVolumeSample + + Mov DI, DX + Mov BX, [DS:64710+BX] + And DI, 0FFh ; Note + Add DI, DI + Mov BX, [DS:BX+DI+41h] + And BX, 0FFh ; BX = sample + JZ PEGetVolumeError + Add BX, BX + +PEGetVolumeSample: + Mov BX, [DS:64910+BX] + Mov DL, [BX+13h] + + DB 85h ; +PEGetVolumeError: ; + StC ; + +PEGetVolumeEnd: + Pop DS DI BX AX + Ret + +EndP PEGetVolume + +; + +Proc PEFunction_AltK Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Cmp [Word Ptr LastKeyBoard2+2], 2500h + JNE PEFunction_AltK7 + + Cmp [Word Ptr LastKeyBoard3+2], 2500h + JE PEFunction_AltK11 + + Mov DI, 8 + Call PE_AddToUndoBuffer + Call NetworkBlock + + ; OK.. wipe volume data... + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + Mov DI, AX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov CX, BlockBottom + Sub CX, BlockTop + Inc CX + + Mov ES, PatternDataArea +; Add DI, 2 + ScasW + + Mov AL, 0FFh + +PEFunction_AltK12: + Push CX + Push DI + + Mov CX, DX + +PEFunction_AltK13: + StosB + Add DI, 4 + Loop PEFunction_AltK13 + + Pop DI + Pop CX + Add DI, 320 + Loop PEFunction_AltK12 + +PEFunction_AltK11: + Mov AX, 1 + Ret + +PEFunction_AltK7: + Mov DI, 7 + Call PE_AddToUndoBuffer + Call NetworkBlock + + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + Mov SI, AX + + Mov AX, 64 + Mul BlockBottom + Add AX, BlockLeft + Mul BX + Mov DI, AX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov CX, BlockBottom + Sub CX, BlockTop + JZ PEFunction_AltK2 ; CX contains number of rows + +; Add SI, 2 +; Add DI, 2 + LodsW + ScasW + Mov DS, PatternDataArea + +PEFunction_AltK1: + Push CX + Push DX + Push SI + +; AltK6 = don't slide. + + MovZX AX, Byte Ptr [DI] + Cmp AL, 0FFh + JNE PEFunction_KVolume1 + + Mov DX, [DI-2] + Call PEGetVolume + JC PEFunction_AltK6 + MovZX AX, DL + +PEFunction_KVolume1: + MovZX BX, Byte Ptr [SI] + Cmp BL, 0FFh + JNE PEFunction_KVolume2 + + Mov DX, [SI-2] + Call PEGetVolume + JC PEFunction_AltK6 + MovZX BX, DL + +PEFunction_KVolume2: ; Now BOTH AL and BL are pan + ; Or BOTH AL and BL are volume + Mov DL, AL + Mov DH, BL + + And DX, 7F7Fh + Cmp DL, 64 + JA PEFunction_AltK6 + Cmp DH, 64 + JA PEFunction_AltK6 + + Mov DL, AL + Mov DH, BL + + And DX, 8080h + JZ PEFunction_AltK14 + Cmp DX, 8080h + JNE PEFunction_AltK6 + +PEFunction_AltK14: + Mov [DI], AL + Mov [SI], BL + + Sub AX, BX ; AX = change. + JS PEFunction_AltK4 + + Div CL + Mov BH, AL + Xor AL, AL + Div CL + Mov BL, AL + + Xor AL, AL + Jmp PEFunction_AltK5 + + +PEFunction_AltK4: + Neg AX + Div CL + Mov BH, AL + Xor AL, AL + Div CL + Mov BL, AL + Neg BX + + Mov AL, 0FFh + +PEFunction_AltK5: + Mov AH, [SI] + +PEFunction_AltK3: + Mov [SI], AH + + Add AX, BX + Add SI, 320 + Loop PEFunction_AltK3 + +PEFunction_AltK6: + Pop SI + Pop DX + Pop CX + Add SI, 5 + Add DI, 5 + Dec DX + JNZ PEFunction_AltK1 + +PEFunction_AltK2: + Mov AX, 1 + Ret + +EndP PEFunction_AltK + +; + +Proc PEFunction_AltL Far + + Call Music_GetLastChannel ; AX = max channel. + Mov BX, MaxRow + + Cmp [Word Ptr LastKeyBoard2+2], 2600h + JNE PEFunction_AltL1 + + Xor CX, CX + Cmp CX, BlockTop + JNE PEFunction_AltL2 + Cmp CX, BlockLeft + JNE PEFunction_AltL2 + Cmp BlockRight, AX + JNE PEFunction_AltL2 + Cmp BX, BlockBottom + JNE PEFunction_AltL2 + Jmp PEFunction_AltL1 + +PEFunction_AltL2: + Xor CX, CX + Mov BlockTop, CX + Mov BlockLeft, CX + Mov BlockRight, AX + Mov BlockBottom, BX + Jmp PEFunction_AltL3 + +PEFunction_AltL1: + Mov AX, Channel + Mov BlockTop, 0 + Mov BlockLeft, AX + Mov BlockRight, AX + Mov BlockBottom, BX + +PEFunction_AltL3: + Mov BlockMark, 1 + + Mov AX, 1 + Ret + +EndP PEFunction_AltL + +; + +Proc PEFunction_WipeBlock Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Cmp [Word Ptr LastKeyBoard2+2], 2C00h + JE PEFunction_WipeBlock1 + + Mov DI, 18 + Call PE_AddToUndoBuffer + Call NetworkBlock + + Cmp Template, 0 + JNE PEFunction_WipeBlock4 + + Push DS + Call PEFunction_BlockCopy + Pop DS + +PEFunction_WipeBlock4: + + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + Mov DI, AX + + Mov CX, BlockBottom + Sub CX, BlockTop + Inc CX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov ES, PatternDataArea + +PEFunction_WipeBlock2: + Push DI + Push CX + + Mov CX, DX + +PEFunction_WipeBlock3: + Mov AX, NONOTE + StosW + Mov AL, 0FFh + StosB + Xor AX, AX + StosW + Loop PEFunction_WipeBlock3 + + Pop CX + Pop DI + Add DI, 320 + Loop PEFunction_WipeBlock2 + +PEFunction_WipeBlock1: + Mov AX, 1 + Ret + +EndP PEFunction_WipeBlock + +; + +Proc PEFunction_RollUp Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + Mov SI, AX + + Mov BP, BlockBottom + Sub BP, BlockTop + JZ PEFunction_RollUpEnd + + Call NetworkBlock + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + Mov AX, 5 + Mul DX + + Mov CX, AX + + Push CS + Pop ES + Mov DI, Offset TempData + Mov DS, PatternDataArea + + Push SI + Rep MovsB + Pop DI + + Push DS + Pop ES + LEA SI, [DI+320] + +PEFunction_RollUp1: + Push SI + Push DI + + Mov CX, AX + Rep MovsB + + Pop DI + Pop SI + Add SI, 320 + Add DI, 320 + + Dec BP + JNZ PEFunction_RollUp1 + + Push CS + Pop DS + Mov SI, Offset TempData + Mov CX, AX + Rep MovsB + +PEFunction_RollUpEnd: + Mov AX, 1 + Ret + +EndP PEFunction_RollUp + +; + +Proc PEFunction_RollDown Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Mov AX, 64 + Mul BlockBottom + Add AX, BlockLeft + Mov BX, 5 + Mul BX + Mov SI, AX + + Mov BP, BlockBottom + Sub BP, BlockTop + JZ PEFunction_RollDownEnd + + Call NetworkBlock + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + Mov AX, 5 + Mul DX + + Mov CX, AX + + Push CS + Pop ES + Mov DI, Offset TempData + Mov DS, PatternDataArea + + Push SI + Rep MovsB + Pop DI + + Push DS + Pop ES + LEA SI, [DI-320] + +PEFunction_RollDown1: + Push SI + Push DI + + Mov CX, AX + Rep MovsB + + Pop DI + Pop SI + Sub SI, 320 + Sub DI, 320 + + Dec BP + JNZ PEFunction_RollDown1 + + Push CS + Pop DS + Mov SI, Offset TempData + Mov CX, AX + Rep MovsB + +PEFunction_RollDownEnd: + Mov AX, 1 + Ret + +EndP PEFunction_RollDown + +; + +Proc PEFunction_BlockHalve Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Mov DI, 5 + Call PE_AddToUndoBuffer + + Mov BL, Byte Ptr BlockLeft + Mov BH, Byte Ptr BlockTop + Mov CH, Byte Ptr MaxRow + Mov CL, Byte Ptr BlockRight + Sub CX, BX + Add CX, 101h + Call NetworkPatternBlock + + Mov AX, 320 + Mul BlockTop + Mov BX, AX + Mov AX, 5 + Mul BlockLeft + Add BX, AX + Mov SI, BX + Mov DI, BX + + Mov DX, BlockBottom + Sub DX, BlockTop + Inc DX + + Mov CX, BlockRight + Sub CX, BlockLeft + Inc CX + + Mov AX, BlockTop + + Mov DS, PatternDataArea + Push DS + Pop ES + +PEFunction_BlockHalve1: + Push AX + Push CX + Push DX + Push SI + Push DI + + Cmp AX, CS:MaxRow + JBE PEFunction_BlockHalve3 + +PEFunction_BlockHalve2: + Mov AX, NONOTE + StosW + Mov AL, 0FFh + StosB + Xor AX, AX + StosW + Loop PEFunction_BlockHalve2 + + Jmp PEFunction_BlockHalve4 + +PEFunction_BlockHalve3: + Mov AX, 5 + Mul CX + Mov CX, AX + Rep MovsB + +PEFunction_BlockHalve4: + + Pop DI + Pop SI + Pop DX + Pop CX + Pop AX + Add SI, 640 + Add DI, 320 + Add AX, 2 + Dec DX + JNZ PEFunction_BlockHalve1 + + Mov AX, 1 + Ret + +EndP PEFunction_BlockHalve + +; + +Proc PEFunction_BlockDouble Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Mov DI, 4 + Call PE_AddToUndoBuffer + + Mov BL, Byte Ptr BlockLeft + Mov BH, Byte Ptr BlockTop + Mov CH, Byte Ptr MaxRow + Mov CL, Byte Ptr BlockRight + Sub CX, BX + Add CX, 101h + Call NetworkPatternBlock + + Mov AX, 320 + Mov CX, BlockBottom + Mul CX + Mov SI, AX + Add CX, CX ; CX = 2*number of rows+2*top + Sub CX, BlockTop ; CX = 2*number of rows+top + Inc CX + Mov AX, 320 + Mul CX + Mov DI, AX + + Push CX ; CX = output row. + + Mov CX, BlockRight + Sub CX, BlockLeft + Inc CX + + Mov AX, 5 + Mul BlockLeft + Add SI, AX + Add DI, AX + + Pop DX ; DX = output row + + Mov DS, PatternDataArea + Push DS + Pop ES + +PEFunction_BlockDouble1: + Push DI + + Cmp DX, CS:MaxRow + JA PEFunction_BlockDouble2 + ; Empty stuff now.. + Push CX + +PEFunction_BlockDouble4: + Mov AX, NONOTE + StosW + Mov AL, 0FFh + StosB + Xor AX, AX + StosW + Loop PEFunction_BlockDouble4 + + Pop CX + +PEFunction_BlockDouble2: + Pop DI + Sub DI, 320 + Dec DX + + Push SI + Push DI + Cmp DX, CS:MaxRow + JA PEFunction_BlockDouble3 + + Push CX + Push DX + + Mov AX, 5 + Mul CX + Mov CX, AX + Rep MovsB + + Pop DX + Pop CX + +PEFunction_BlockDouble3: + Pop DI + Pop SI + Sub SI, 320 + Sub DI, 320 + + Cmp DX, CS:BlockTop + JBE PEFunction_BlockDouble5 + + Dec DX + Jmp PEFunction_BlockDouble1 + +PEFunction_BlockDouble5: + Mov AX, 1 + Ret + +EndP PEFunction_BlockDouble + +; + +Proc PEFunction_BlockSwap Far ; Alt-H... sorry. + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + ; Check that boundaries + ; are OK.. + + ; 1. Check that vertices of new block + ; don't lie in old block. + ; 2. Check that 2nd block < channels + ; and 2nd block < maxrow. + + Mov AX, Channel + Mov BX, Row + Call Near Ptr PEFunction_BlockSwap1 + Add AX, BlockRight + Sub AX, BlockLeft + Call Near Ptr PEFunction_BlockSwap1 + Add BX, BlockBottom + Sub BX, BlockTop + Call Near Ptr PEFunction_BlockSwap1 + Mov AX, Channel + Call Near Ptr PEFunction_BlockSwap1 + Jmp PEFunction_BlockSwap3 + +PEFunction_BlockSwap1: + Cmp AX, BlockLeft + JB PEFunction_BlockSwap2 + Cmp AX, BlockRight + JA PEFunction_BlockSwap2 + + Cmp BX, BlockTop + JB PEFunction_BlockSwap2 + Cmp BX, BlockBottom + JA PEFunction_BlockSwap2 + + ; Uh oh... cursor is in block. + + Mov DI, Offset O1_OverlapBlockList + Mov CX, 2 + Call M_Object1List + + Pop AX ; Clear stack + Mov AX, 1 + RetF + +PEFunction_BlockSwap2: + RetN + +PEFunction_BlockSwap3: + Mov DI, 17 + Call PE_AddToUndoBuffer + Call NetworkBlock + + Mov BL, Byte Ptr Channel + Mov BH, Byte Ptr Row + Mov CL, Byte Ptr BlockRight + Mov CH, Byte Ptr BlockBottom + Sub CL, Byte Ptr BlockLeft + Sub CH, Byte Ptr BlockTop + Add CX, 101h + Call NetworkPatternBlock + + + Mov AX, Channel + Mov BX, Row + + Mov CX, BlockRight + Sub CX, BlockLeft + Inc CX ; CX = block width. + Add AX, CX + Cmp AX, 64 + JA PEFunction_BlockSwap4 + + Mov DX, BlockBottom + Sub DX, BlockTop ; DX = block height-1. + Add BX, DX + Cmp BX, MaxRow + JBE PEFunction_BlockSwap5 + +PEFunction_BlockSwap4: + Mov DI, Offset O1_SwapOutOfRangeList + Mov CX, 2 + Call M_Object1List + + Mov AX, 1 + Ret + +PEFunction_BlockSwap5: ; Do swap. + Mov AX, 320 + Mul BlockTop + Mov BX, AX + Mov AX, 5 + Mul BlockLeft + Add BX, AX + Mov SI, BX ; SI = "marked" block + + Call GetPatternOffset ; DI = implied block +; Mov AX, 320 +; Mul Row +; Mov BX, AX +; Mov AX, 5 +; Mul Channel +; Add BX, AX +; Mov SI, BX ; SI = implied block. + + Mov CX, BlockRight + Sub CX, BlockLeft + Inc CX ; CX = width of block. + Mov AX, 5 + Mul CX + Mov CX, AX + + Mov DX, BlockBottom + Sub DX, BlockTop + Inc DX ; DX = height of block + +; Mov ES, PatternDataArea + Push ES + Pop DS + +PEFunction_BlockSwap6: + Push CX + Push DX + Push SI + Push DI + +PEFunction_BlockSwap7: + Mov AL, [DS:DI] + MovsB + Mov [DS:SI-1], AL + Loop PEFunction_BlockSwap7 + + Pop DI + Pop SI + Pop DX + Pop CX + Add SI, 320 + Add DI, 320 + Dec DX + JNZ PEFunction_BlockSwap6 + + Mov AX, 1 + Ret + +EndP PEFunction_BlockSwap + +; + +Proc PEFunction_BlockCopy Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Mov AX, BlockDataArea + And AX, AX + JZ PEFunction_BlockCopy1 + + Mov ES, AX + Mov AH, 49h + Int 21h + +PEFunction_BlockCopy1: + Mov AX, BlockBottom + Sub AX, BlockTop + Inc AX + + Mov BX, BlockRight + Sub BX, BlockLeft + Inc BX + Mul BX + Mov BX, 5 + Mul BX + ; AX = size of block + Mov BX, AX + Add BX, 19 ; + space for width/height + ShR BX, 4 + Mov AH, 48h + Int 21h + JNC PEFunction_BlockCopy2 + + Jmp PEFunction_OutOfMemoryMessage + +PEFunction_BlockCopy2: + Mov BlockDataArea, AX + Xor DI, DI + Mov ES, AX + + Mov AX, BlockRight + Sub AX, BlockLeft + Inc AX + StosW + Mov BX, 5 + Mul BX + Mov DX, AX ; DX = width*5 + + Mov AX, BlockBottom + Sub AX, BlockTop + Inc AX + StosW + Mov CX, AX ; CX = height + + Push DX + + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mul BX + Mov SI, AX + + Pop DX + Mov DS, PatternDataArea + +PEFunction_BlockCopy3: + Push SI + Push CX + + Mov CX, DX + Rep MovsB + + Pop CX + Pop SI + Add SI, 320 + Loop PEFunction_BlockCopy3 + + Mov AX, 1 + Ret + +EndP PEFunction_BlockCopy + +; + +Proc PEFunction_NoBlockMarkedMessage Far + + Mov DI, Offset O1_NoBlockMarkedList + Mov CX, 2 + Call M_Object1List + + Mov AX, 1 + Ret + +EndP PEFunction_NoBlockMarkedMessage + +; + +Proc PEFunction_OutOfMemoryMessage Far + + Call PE_FillHeader + Call S_SaveScreen + + Mov DI, Offset O1_OutOfMemoryList + Mov CX, 2 + Call M_Object1List + + Call S_RestoreScreen + + Mov AX, 1 + Ret + +EndP PEFunction_OutOfMemoryMessage + +; + +Proc PEFunction_NoBlockData Far + + Mov DI, Offset O1_NoBlockDataList + Mov CX, 2 + Call M_Object1List + + Mov AX, 1 + Ret + +EndP PEFunction_NoBlockData + +; + +Proc PEFunction_BlockOverWrite Far + + Mov AX, BlockDataArea + And AX, AX + JZ PEFunction_NoBlockData + + Cmp [Word Ptr LastKeyBoard2+2], 1800h + JE PEFunction_BlockOverWrite5 + + Mov DI, 10 + Call PE_AddToUndoBuffer + + Mov ES, AX + Mov CL, [ES:0] + Mov CH, [ES:2] + Call NetworkPartialPattern + +PEFunction_BlockOverWrite6: + + Mov BP, MaxRow + Mov BX, Row + Mov CX, Channel + + Call GetPatternOffset + + Mov DS, AX + + Mov SI, 4 ; DS:SI points to block + + Mov AX, CX + Mov DX, [DS:0] + Mov CX, [DS:2] ; DX = width, CX = height + +PEFunction_BlockOverWrite1: + Push AX + Push CX + Push DX + Push DI + +PEFunction_BlockOverWrite2: + Cmp AX, 63 + JA PEFunction_BlockOverWrite3 + + Mov CX, 5 + Rep MovsB + + Jmp PEFunction_BlockOverWrite4 + +PEFunction_BlockOverWrite3: + Add SI, 5 + +PEFunction_BlockOverWrite4: + Inc AX ; AX = channel + Dec DX + JNZ PEFunction_BlockOverWrite2 + + Pop DI + Pop DX + Pop CX + Pop AX + Add DI, 320 + Inc BX + Cmp BX, BP + JA PEFunction_BlockOverWrite5 + + Loop PEFunction_BlockOverWrite1 + +PEFunction_BlockOverWrite5: + Mov AX, 1 + Ret + +EndP PEFunction_BlockOverWrite + +; + +Proc PEFunction_BlockPaste Far + + Mov AX, BlockDataArea + And AX, AX + JZ PEFunction_NoBlockData + + Cmp [Word Ptr LastKeyBoard2+2], 1900h + JE PEFunction_BlockPaste6 + + Mov DI, 11 + Call PE_AddToUndoBuffer + +PEFunction_BlockPaste6: + Push DS + Mov BP, MaxRow + + Mov ES, AX + + Mov CH, Byte Ptr MaxRow + Sub CH, Byte Ptr Row + Inc CH + Mov CL, [ES:0] + Call NetworkPartialPattern + + Mov BX, [ES:0] ; width + Mov CX, [ES:2] ; height + +; Condition: +; If Row == 0 && Channel == 0 && height > MaxRow && width > 1, then set maxrow = height + Cmp CX, BP + JB PEFunction_BlockPaste7 + + Mov AX, Channel + Or AX, Row + JNZ PEFunction_BlockPaste7 + + Cmp BX, 1 + JBE PEFunction_BlockPaste7 + + Mov BP, CX + Dec BP + Mov MaxRow, BP + +PEFunction_BlockPaste7: + Mov AX, 64 + Mul BP + Add AX, Channel + Mov DX, 5 + Mul DX + Mov SI, AX + Mov DI, AX + + Mov AX, 320 + Mul CX + Add DI, AX ; DI has destination... + + Mov AX, Channel + Mov DS, PatternDataArea + Push DS + Pop ES + +PEFunction_BlockPaste1: + Push AX + Push CX + Push SI + Push DI + + Mov AX, CS:Row + Add AX, CX + Mov DX, BP + Add DX, CX + +PEFunction_BlockPaste5: + Cmp DX, BP + JA PEFunction_BlockPaste3 + + Mov CX, 5 + Rep MovsB + Sub SI, 325 + Sub DI, 325 + + Jmp PEFunction_BlockPaste4 + +PEFunction_BlockPaste3: + Sub SI, 320 + Sub DI, 320 + +PEFunction_BlockPaste4: + Dec DX + Cmp DX, AX + JAE PEFunction_BlockPaste5 + + Pop DI + Pop SI + Pop CX + Pop AX + + Add SI, 5 + Add DI, 5 + Inc AX + Cmp AX, 63 + JA PEFunction_BlockPaste2 + + Dec BX + JNZ PEFunction_BlockPaste1 + +PEFunction_BlockPaste2: + Pop DS + + Mov AX, BlockDataArea + Jmp PEFunction_BlockOverWrite6 + +EndP PEFunction_BlockPaste + +; + +Proc PEFunction_SecondBlockMix Far + + Mov BP, MaxRow + Mov BX, Row + Mov CX, Channel + + Call GetPatternOffset + + Mov DS, BlockDataArea + + Mov SI, 4 ; DS:SI points to block + + Mov AX, CX + + Mov CL, [DS:0] + Mov CH, [DS:2] + Call NetworkPartialPattern + + Mov DX, [DS:0] + Mov CX, [DS:2] ; DX = width, CX = height + +PEFunction_SecondBlockMix1: + Push AX + Push CX + Push DX + Push DI + +PEFunction_SecondBlockMix2: + Cmp AX, 63 + JA PEFunction_SecondBlockMix3 + + Cmp Byte Ptr [ES:DI], NONOTE ; Note + JNE PEFunction_SecondBlockMix7 + + Mov CL, [DS:SI] + Mov [ES:DI], CL + +PEFunction_SecondBlockMix7: + Inc SI + Inc DI + + Cmp Byte Ptr [ES:DI], 0 ; Instrument + JNE PEFunction_SecondBlockMix8 + + Mov CL, [DS:SI] + Mov [ES:DI], CL + +PEFunction_SecondBlockMix8: + Inc SI + Inc DI + + Cmp Byte Ptr [ES:DI], 0FFh ; Volume + JNE PEFunction_SecondBlockMix9 + + Mov CL, [DS:SI] + Mov [ES:DI], CL + +PEFunction_SecondBlockMix9: + Inc SI + Inc DI + + Cmp Byte Ptr [ES:DI], 0 ; Command + JNE PEFunction_SecondBlockMix10 + + Mov CL, [DS:SI] + Mov [ES:DI], CL + +PEFunction_SecondBlockMix10: + Inc SI + Inc DI + + Cmp Byte Ptr [ES:DI], 0 ; Commandvalue + JNE PEFunction_SecondBlockMix11 + + Mov CL, [DS:SI] + Mov [ES:DI], CL + +PEFunction_SecondBlockMix11: + Inc SI + Inc DI + Jmp PEFunction_SecondBlockMix4 + +PEFunction_SecondBlockMix3: + Add SI, 5 + +PEFunction_SecondBlockMix4: + Inc AX ; AX = channel + Dec DX + JNZ PEFunction_SecondBlockMix2 + + Pop DI + Pop DX + Pop CX + Pop AX + Add DI, 320 + Inc BX + Cmp BX, BP + JA PEFunction_SecondBlockMix5 + + Loop PEFunction_SecondBlockMix1 + +PEFunction_SecondBlockMix5: + Mov AX, 1 + Ret + +EndP PEFunction_SecondBlockMix + +; + +Proc PEFunction_BlockMix Far + + Cmp BlockDataArea, 0 + JE PEFunction_NoBlockData + + Cmp [Word Ptr LastKeyBoard2+2], 3200h + JNE PEFunction_BlockMix1 + + Cmp [Word Ptr LastKeyboard3+2], 3200h + JE PEFunction_BlockMix6 + + Jmp PEFunction_SecondBlockMix + +PEFunction_BlockMix1: + Mov DI, 9 + Call PE_AddToUndoBuffer + Call NetworkBlock + + Mov BP, MaxRow + Mov BX, Row + Mov CX, Channel + + Call GetPatternOffset + + Mov DS, BlockDataArea + Mov SI, 4 ; DS:SI points to block + + Mov AX, CX + + Mov CL, [DS:0] + Mov CH, [DS:2] + Call NetworkPartialPattern + + Mov DX, [DS:0] + Mov CX, [DS:2] ; DX = width, CX = height + +PEFunction_BlockMix2: + Push AX + Push CX + Push DX + Push DI + +PEFunction_BlockMix3: + Cmp AX, 63 + JA PEFunction_BlockMix4 + + Cmp DWord Ptr [ES:DI], NONOTE + 0FF0000h + JNE PEFunction_BlockMix7 + Cmp Byte Ptr [ES:DI+4], 0 + JNE PEFunction_BlockMix7 + + Mov CX, 5 + Rep MovsB + + Jmp PEFunction_BlockMix5 + +PEFunction_BlockMix7: + Add DI, 5 + +PEFunction_BlockMix4: + Add SI, 5 + +PEFunction_BlockMix5: + Inc AX ; AX = channel + Dec DX + JNZ PEFunction_BlockMix3 + + Pop DI + Pop DX + Pop CX + Pop AX + Add DI, 320 + Inc BX + Cmp BX, BP + JA PEFunction_BlockMix6 + + Loop PEFunction_BlockMix2 + +PEFunction_BlockMix6: + Mov AX, 1 + Ret + +EndP PEFunction_BlockMix + +; + +Proc PEFunction_UnMarkBlock Far + + Cmp BlockMark, 0 + JZ PEFunction_UnMarkBlock1 + + Mov BlockMark, 0 + Jmp PEFunction_UnMarkBlock2 + +PEFunction_UnMarkBlock1: + Mov AX, BlockDataArea + And AX, AX + JZ PEFunction_NoBlockData + + Mov ES, AX + Mov AH, 49h + Int 21h + + Mov BlockDataArea, 0 +PEFunction_UnMarkBlock2: + Mov AX, 1 + Ret + +EndP PEFunction_UnMarkBlock + +; + +Proc PEFunction_SemiUp Far + + Cmp [Word Ptr LastKeyBoard2+2], 1000h + JE PEFunction_SemiUp6 + + Mov DI, 2 + Call PE_AddToUndoBuffer + +PEFunction_SemiUp6: + Cmp BlockMark, 0 + JNE PEFunction_SemiUp4 + + Mov CX, 101h + Call NetworkPartialPattern + + Mov AX, 64 + Mul Row + Add AX, Channel + Mov BX, 5 + Mul BX + Mov SI, AX + Mov CX, 1 + Mov DX, CX + Jmp PEFunction_SemiUp5 + +PEFunction_SemiUp4: + Call NetworkBlock + + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX ; AX = start offset + + Mov SI, AX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov CX, BlockBottom + Sub CX, BlockTop + Inc CX + +PEFunction_SemiUp5: + Mov DS, PatternDataArea + +PEFunction_SemiUp1: + Push DX + Push SI + +PEFunction_SemiUp2: + Cmp Byte Ptr [SI], 119 + JAE PEFunction_SemiUp3 + + Inc Byte Ptr [SI] + +PEFunction_SemiUp3: + Add SI, 5 + Dec DX + JNZ PEFunction_SemiUp2 + + Pop SI + Pop DX + Add SI, 320 + Loop PEFunction_SemiUp1 + + Mov AX, 1 + Ret + +EndP PEFunction_SemiUp + +; + +Proc PEFunction_SemiDown Far + + Cmp [Word Ptr LastKeyBoard2+2], 1E00h + JE PEFunction_SemiDown6 + + Mov DI, 3 + Call PE_AddToUndoBuffer + +PEFunction_SemiDown6: + Cmp BlockMark, 0 + JNE PEFunction_SemiDown4 + + Mov CX, 101h + Call NetworkPartialPattern + + Mov AX, 64 + Mul Row + Add AX, Channel + Mov BX, 5 + Mul BX + Mov SI, AX + Mov CX, 1 + Mov DX, CX + Jmp PEFunction_SemiDown5 + +PEFunction_SemiDown4: + Call NetworkBlock + + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX ; AX = start offset + + Mov SI, AX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov CX, BlockBottom + Sub CX, BlockTop + Inc CX + +PEFunction_SemiDown5: + Mov DS, PatternDataArea + +PEFunction_SemiDown1: + Push DX + Push SI + +PEFunction_SemiDown2: + Cmp Byte Ptr [SI], 0 + JLE PEFunction_SemiDown3 + + Dec Byte Ptr [SI] + +PEFunction_SemiDown3: + Add SI, 5 + Dec DX + JNZ PEFunction_SemiDown2 + + Pop SI + Pop DX + Add SI, 320 + Loop PEFunction_SemiDown1 + + Mov AX, 1 + Ret + +EndP PEFunction_SemiDown + +; + +Proc PEFunction_SlideCommand Far + + Mov DI, 15 + Call PE_AddToUndoBuffer + Call NetworkBlock + + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + Mov SI, AX + + Mov AX, 64 + Mul BlockBottom + Add AX, BlockLeft + Mul BX + Mov DI, AX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov CX, BlockBottom + Sub CX, BlockTop + JZ PEFunction_AltX2 ; CX contains number of rows + + Add SI, 4 + Add DI, 4 + Mov DS, PatternDataArea + +PEFunction_AltX1: + Push CX + Push DX + Push SI + + MovZX AX, Byte Ptr [DI] + MovZX BX, Byte Ptr [SI] + Sub AX, BX ; AX = change. + JS PEFunction_AltX4 + + Div CL + Mov BH, AL + Xor AL, AL + Div CL + Mov BL, AL + + Xor AL, AL + Jmp PEFunction_AltX5 + + +PEFunction_AltX4: + Neg AX + Div CL + Mov BH, AL + Xor AL, AL + Div CL + Mov BL, aL + Neg BX + + Mov AL, 0FFh + +PEFunction_AltX5: + Mov AH, [SI] + +PEFunction_AltX3: + Mov [SI], AH + + Add AX, BX + Add SI, 320 + Loop PEFunction_AltX3 + + Pop SI + Pop DX + Pop CX + Add SI, 5 + Add DI, 5 + Dec DX + JNZ PEFunction_AltX1 + +PEFunction_AltX2: + Mov AX, 1 + Ret + +EndP PEFunction_SlideCommand + +; + +Proc PEFunction_WipeCommands Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Cmp [Word Ptr LastKeyBoard2+2], 2D00h + JE PEFunction_WipeCommands4 + + Jmp PEFunction_SlideCommand + +PEFunction_WipeCommands4: + Cmp [Word Ptr LastKeyBoard3+2], 2D00h + JE PEFunction_WipeCommands6 + + Mov DI, 16 + Call PE_AddToUndoBuffer + Call NetworkBlock + +PEFunction_WipeCommands6: + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + Mov DI, AX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov CX, BlockBottom + Sub CX, BlockTop + Inc CX + + Mov ES, PatternDataArea + Add DI, 3 + + Xor AX, AX + +PEFunction_WipeCommands2: + Push CX + Push DI + + Mov CX, DX + +PEFunction_WipeCommands3: + StosW + Add DI, 3 + Loop PEFunction_WipeCommands3 + + Pop DI + Pop CX + Add DI, 320 + Loop PEFunction_WipeCommands2 + +PEFunction_WipeCommands1: + Mov AX, 1 + Ret + +EndP PEFunction_WipeCommands + +; + +Proc PEFunction_VolumeAmp Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Test CentraliseCursor, 4 + JZ PENoFast1 + + Mov AX, FastVolumeAmplification + Mov Amplification, AX + Jmp PEFastVolumeAmp + +PENoFast1: + Cmp Amplification, 200 + JBE PENoFast2 + + Mov Amplification, 200 + +PENoFast2: + Push DS + + Mov DI, Offset O1_GetAmpList + Mov CX, 3 + Call M_Object1List + + Pop DS + + Cmp DX, 1 + JNE PEFunction_VolumeAmp1 + +PEFastVolumeAmp: + Mov DI, 6 + Call PE_AddToUndoBuffer + Call NetworkBlock + + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + Mov SI, AX + + Mov CX, BlockBottom + Sub CX, BlockTop + Inc CX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov BP, Amplification + Mov BX, 100 +; Mov BH, 100 ; For division + + Mov DS, PatternDataArea + Add SI, 2 + + Call Music_GetSongSegment + Mov ES, AX + +PEFunction_VolumeAmp2: + Push CX + Push DX + Push SI + + Mov CX, DX + +PEFunction_VolumeAmp3: + Mov AL, [SI] + Cmp AL, 0FFh + JNE PEFunction_VolumeAmp6 + + Mov DI, [SI-1] + And DI, 0FFh + JZ PEFunction_VolumeAmp4 + ; OK.. find whether inst/sample + ; then get default vol. + Call Music_GetInstrumentMode + JZ PEFunction_VolumeAmp7 + + Add DI, DI + Mov DI, [ES:64712+DI-2] + Mov AL, [SI-2] + And AX, 0FFh + JZ PEFunction_VolumeAmp4 + Add AX, AX + Add DI, AX + Mov DI, [ES:DI+41h] + And DI, 0FFh + JZ PEFunction_VolumeAmp4 + +PEFunction_VolumeAmp7: + Dec DI + Add DI, DI + Mov DI, [ES:64912+DI] + Mov AL, [ES:DI+13h] + +PEFunction_VolumeAmp6: + Cmp AL, 64 + JA PEFunction_VolumeAmp4 + + Xor AH, AH + Push DX + + Mul BP + Div BX + + Pop DX + + Cmp AX, 64 + JBE PEFunction_VolumeAmp5 + + Mov AL, 64 + +PEFunction_VolumeAmp5: + Mov [SI], AL + +PEFunction_VolumeAmp4: + Add SI, 5 + Loop PEFunction_VolumeAmp3 + + Pop SI + Pop DX + Pop CX + Add SI, 320 + Loop PEFunction_VolumeAmp2 + +PEFunction_VolumeAmp1: + Mov AX, 1 + Ret + +EndP PEFunction_VolumeAmp + +; + +Proc GetPatternLength + + Push AX + Push BX + Push CX + Push DS + Push SI + Push ES + Push DI + + Call ClearEncodingInfo + ; OK, masks are reset. + + Mov CX, CS:MaxRow + Inc CX + Mov DX, CX ; DX = count of bytes. + ; End of row bytes added. + + Mov DS, CS:PatternDataArea + Xor SI, SI ; SI = pattern area. + + Mov DI, Offset EncodingInfo ; ES:DI points to encoding info + +GetPatternLength1: + Push CX + Push DI + + Mov CX, 64 + +GetPatternLength2: + Cmp Word Ptr [SI], NONOTE + JNE GetPatternLength4 + Cmp Byte Ptr [SI+2], 0FFh + JNE GetPatternLength4 + Cmp Word Ptr [SI+3], 0 + JE GetPatternLength3 + +GetPatternLength4: + Inc DX ; 1 byte for channel + ; indication + JZ GetPatternLength13 + ; AH will be mask + MovZX AX, Byte Ptr [SI] ; Note + Cmp AL, NONOTE + JE GetPatternLength5 + Cmp AL, [ES:DI+1] ; 5 is note. + JE GetPatternLength12 + + Mov [ES:DI+1], AL + Inc DX + JZ GetPatternLength13 + Or AH, 1 + Jmp GetPatternLength5 + +GetPatternLength12: + Or AH, 16 + +GetPatternLength5: + Mov AL, [SI+1] ; Instrument + And AL, AL + JZ GetPatternLength7 + + Cmp AL, [ES:DI+2] + JE GetPatternLength6 + + Mov [ES:DI+2], AL + Inc DX + JZ GetPatternLength13 + Or AH, 2 + Jmp GetPatternLength7 + +GetPatternLength6: + Or AH, 32 + +GetPatternLength7: + Mov AL, [SI+2] ; Volume + Cmp AL, 0FFh + JE GetPatternLength8 + + Cmp AL, [ES:DI+3] + JE GetPatternLength9 + + Mov [ES:DI+3], AL + Inc DX + JZ GetPatternLength13 + Or AH, 4 + Jmp GetPatternLength8 + +GetPatternLength9: + Or AH, 64 + +GetPatternLength8: + Mov BX, [SI+3] + And BX, BX + JZ GetPatternLength11 + Cmp BX, [ES:DI+4] + JE GetPatternLength10 + + Mov [ES:DI+4], BX + + Inc DX + JZ GetPatternLength13 + Inc DX + JZ GetPatternLength13 + Or AH, 8 + + Jmp GetPatternLength11 + +GetPatternLength10: + Or AH, 128 + +GetPatternLength11: + Cmp AH, [ES:DI] + JE GetPatternLength3 + + Inc DX + JZ GetPatternLength13 + Mov [ES:DI], AH + +GetPatternLength3: + + Add SI, 5 + Add DI, 6 + Loop GetPatternLength2 + + Pop DI + Pop CX + Loop GetPatternLength1 + + Pop DI + Pop ES + Pop SI + Pop DS + Pop CX + Pop BX + Pop AX + + Ret + +GetPatternLength13: + Mov DI, Offset O1_PatternTooLongList + Mov CX, 2 + Call M_Object1List + + Add SP, 22 ; yes! + Mov AX, 1 + RetF + +EndP GetPatternLength + +; + +IF SHOWPATTERNLENGTH + +Proc PE_ShowPatternLength Far + + Push AX ; Just for stack length.. + Call GetPatternLength + Pop AX + + Mov AX, Object1 + Push AX + Mov DS, AX + Mov AX, Offset O1_ShowPatternLengthList + Push AX + Mov SI, Offset PatternLength + Mov [SI], DX + Call M_FunctionHandler + + Mov AX, 1 + Ret + +EndP PE_ShowPatternLength + +ENDIF + +; + +DecodePatternBytes DW 0 +DecodePatternOffset DW 0 + +Proc DecodePattern ; DS:SI points to pattern info to decode + + PushA + Push DS + Push ES + +; Call ClearEncodingInfo ; Should be unnecess. + + + Push CS + Pop ES + Mov BX, Offset EncodingInfo + + LodsW ; AX = number of bytes + Mov CS:DecodePatternBytes, AX + LodsW ; AX = maxrow + Mov CX, AX + Dec AX + Mov CS:MaxRow, AX + LodsW + LodsW + + Mov CS:DecodePatternOffset, SI + + Call PE_ClearPatternData + + Mov ES, CS:PatternDataArea + Xor DI, DI + +DecodePattern1: + Push CX + +DecodePattern5: + LodsB ; AL = channel byte. + Test AL, AL + JZ DecodePattern2 + + Push BX + Push DI + + Mov CX, AX + Dec CX + And CX, 63 + + ; DI = DI + Channel*5 + ; BX = EncodingInfo + Channel*6 + + LEA BX, [ECX*4+ECX] + LEA DI, [DI+BX] + LEA BX, [EBX+ECX+EncodingInfo] + + Test AL, 128 + JZ DecodePattern3 + + Mov DL, [SI] + Inc SI + + Mov [CS:BX], DL + Jmp DecodePattern4 + +DecodePattern3: + Mov DL, [CS:BX] ; DL = mask + +DecodePattern4: + Test DL, 1 + JZ DecodePattern13 + + LodsB + + Mov [ES:DI], AL + Mov [CS:BX+1], AL + Jmp DecodePattern6 + +DecodePattern13: + Test DL, 16 + JZ DecodePattern6 + + Mov AL, [CS:BX+1] + Mov [ES:DI], AL + +DecodePattern6: + Test DL, 2 + JZ DecodePattern7 + + LodsB + + Mov [ES:DI+1], AL + Mov [CS:BX+2], AL + Jmp DecodePattern8 + +DecodePattern7: + Test DL, 32 + JZ DecodePattern8 + + Mov AL, [CS:BX+2] + Mov [ES:DI+1], AL + +DecodePattern8: + Test DL, 4 + JZ DecodePattern9 + + LodsB + + Mov [ES:DI+2], AL + Mov [CS:BX+3], AL + Jmp DecodePattern10 + +DecodePattern9: + Test DL, 64 + JZ DecodePattern10 + + Mov AL, [CS:BX+3] + Mov [ES:DI+2], AL + +DecodePattern10: + Test DL, 8 + JZ DecodePattern11 + + LodsW + + Mov [ES:DI+3], AX + Mov [CS:BX+4], AX + Jmp DecodePattern12 + +DecodePattern11: + Test DL, 128 + JZ DecodePattern12 + + Mov AX, [CS:BX+4] + Mov [ES:DI+3], AX + +DecodePattern12: + Pop DI + Pop BX + Jmp DecodePattern5 + +DecodePattern2: + Pop CX + Add DI, 320 + Loop DecodePattern1 + + Sub SI, CS:DecodePatternOffset + Cmp SI, CS:DecodePatternBytes + JE DecodePatternEnd + + Mov CX, 0FFFFh + Mov DI, Offset O1_PatternSizeMismatchList + Call M_Object1List + +DecodePatternEnd: + Pop ES + Pop DS + PopA + + Call Music_UpdatePatternOffset + + Ret + +EndP DecodePattern + +; + +Proc EncodePattern ; ES:DI points to area to deposit data + ; DX = length of data + + Push AX + Push BX + Push CX + Push DX + Push DS + Push SI + + Push ES + Push DI + + Call ClearEncodingInfo + + Pop DI + Pop ES + + Mov BX, Offset EncodingInfo + + Mov AX, DX + StosW + + Mov CX, CS:MaxRow + Inc CX + + Mov AX, CX + StosW + + Xor AX, AX + StosW + StosW ; This is the header. + + Xor SI, SI + Mov DS, CS:PatternDataArea + +EncodePattern1: + Push BX + Push CX + + Xor DX, DX ; DL = channelnumber + ; DH is used as mask val. + Mov CX, 64 + +EncodePattern2: + Cmp Word Ptr [SI], NONOTE + JNE EncodePattern3 + Cmp Byte Ptr [SI+2], 0FFh + JNE EncodePattern8 + Cmp Word Ptr [SI+3], 0 + JE EncodePattern4 + Jmp EncodePattern10 + +EncodePattern3: + Mov AL, [SI] + Cmp AL, NONOTE + JE EncodePattern5 + Cmp AL, [CS:BX+1] ; 1=note + JE EncodePattern6 + + Mov [CS:BX+1], AL + Or DH, 1 + Jmp EncodePattern5 + +EncodePattern6: + Or DH, 16 + +EncodePattern5: + Mov AL, [SI+1] + And AL, AL + JZ EncodePattern8 + Cmp AL, [CS:BX+2] ; 2=ins + JE EncodePattern7 + + Mov [CS:BX+2], AL + Or DH, 2 + Jmp EncodePattern8 + +EncodePattern7: + Or DH, 32 + +EncodePattern8: + Mov AL, [SI+2] + Cmp AL, 0FFh + JE EncodePattern10 + Cmp AL, [CS:BX+3] ; 3=vol + JE EncodePattern9 + + Mov [CS:BX+3], AL + Or DH, 4 + Jmp EncodePattern10 + +EncodePattern9: + Or DH, 64 + +EncodePattern10: + Mov AX, [SI+3] + Test AX, AX + JZ EncodePattern12 + Cmp AX, [CS:BX+4] ; 4=effect + JE EncodePattern11 + + Mov [CS:BX+4], AX + Or DH, 8 + Jmp EncodePattern12 + +EncodePattern11: + Or DH, 128 + +EncodePattern12: + Mov AL, DL + Inc AX + + Cmp [CS:BX], DH ; 0 = mask + JE EncodePattern13 + + Mov [CS:BX], DH + Or AL, 128 ; read another mask... + StosB + Mov AL, DH + StosB + Jmp EncodePattern14 + +EncodePattern13: + StosB + +EncodePattern14: + Test DH, 1 + JZ EncodePattern15 + + Mov AL, [SI] + StosB + +EncodePattern15: + Test DH, 2 + JZ EncodePattern16 + + Mov AL, [SI+1] + StosB + +EncodePattern16: + Test DH, 4 + JZ EncodePattern17 + + Mov AL, [SI+2] + StosB + +EncodePattern17: + Test DH, 8 + JZ EncodePattern18 + + Mov AX, [SI+3] + StosW + +EncodePattern18: + Xor DH, DH + +EncodePattern4: + Add SI, 5 + Add BX, 6 + Inc DX + Loop EncodePattern2 + + Pop CX + Pop BX + Xor AL, AL + StosB + Loop EncodePattern1 + + Pop SI + Pop DS + Pop DX + Pop CX + Pop BX + Pop AX + Ret + +EndP EncodePattern + +; + +Proc PEFunction_StorePattern + +IF NETWORKENABLED + Cmp PatternModified, 0 + JE PEFunction_StorePattern5 + + Mov AX, PatternNumber + ShL AX, 8 + Add AX, NETWORK_ENTIREPATTERNOBJECT + Call Network_AddWordToQueue + +PEFunction_StorePattern5: +ENDIF + + Mov AX, PatternNumber + Mov SI, AX + Call Music_ReleasePattern + + Call GetPatternLength + Cmp DX, 64 + JNE PEFunction_StorePattern1 + Cmp CS:MaxRow, 63 + JE PEFunction_StorePattern2 + +PEFunction_StorePattern1: + Add DX, 8 + JC PEFunction_StorePattern4 + + ClI + + Call Music_AllocatePattern + Mov AX, ES + And AX, AX + JZ PEFunction_StorePattern3 + Sub DX, 8 + Call EncodePattern + + StI + +PEFunction_StorePattern2: + Ret + +PEFunction_StorePattern3: + StI + + Add SP, 2 + Jmp PEFunction_OutOfMemoryMessage + +PEFunction_StorePattern4: + Mov DI, Offset O1_PatternTooLongList + Mov CX, 2 + Call M_Object1List + + Pop AX + Mov AX, 1 + RetF + +EndP PEFunction_StorePattern + +; + +Proc PEFunction_StoreCurrentPattern Far + + Push CS + Pop DS + Call PEFunction_StorePattern + + Mov AX, 1 + Ret + +EndP PEFunction_StoreCurrentPattern + +; + +Proc NewPattern ; Reqs. AX = pattern + +IF NETWORKENABLED + Call Network_UpdatePattern +ENDIF + Call Music_GetPattern + Call DecodePattern + + Mov CS:PatternModified, 0 + Mov AH, CS:Byte Ptr PatternNumber + Mov AL, 22 + Mov DI, AX +; Mov DI, 22 + Call PE_AddToUndoBuffer + + Ret + +EndP NewPattern + +; + +Proc PE_GotoPattern Far ; AX = pattern. + + Push CS + Pop DS + + Mov Row, BX + Mov Channel, CX + +PE_GotoPattern2: + Cmp PatternModified, 0 + JE PE_GotoPattern1 + + Mov TempVariableArea, AX + Call PEFunction_StorePattern + Mov AX, TempVariableArea + +PE_GotoPattern1: + Mov PatternNumber, AX + Call NewPattern + + Jmp Glbl_F2 + +EndP PE_GotoPattern + +; + +include pe_trans.inc + +; + +Proc PEFunction_NextPattern Far + + Cmp TracePlayback, 0 + JE PEFunction_NextPatternNoTrace + + Call Music_GetPlayMode + Cmp AX, 1 + JE PEFunction_NextPattern1 + JB PEFunction_NextPatternNoTrace + + Call Music_NextOrder + Jmp PEFunction_NextPattern1 + +PEFunction_NextPatternNoTrace: + Cmp PatternNumber, 199 + JAE PEFunction_NextPattern1 + + Cmp PatternModified, 0 + JE PEFunction_NextPattern2 + + Call PEFunction_StorePattern + +PEFunction_NextPattern2: + Inc PatternNumber + Mov AX, PatternNumber + + Call NewPattern + +PEFunction_NextPattern1: + Mov AX, 1 + Ret + +EndP PEFunction_NextPattern + +; + +Proc PEFunction_LastPattern Far + + Cmp TracePlayback, 0 + JE PEFunction_LastPatternNoTrace + + Call Music_GetPlayMode + Cmp AX, 1 + JE PEFunction_LastPattern1 + JB PEFunction_LastPatternNoTrace + + Call Music_LastOrder + Jmp PEFunction_LastPattern1 + +PEFunction_LastPatternNoTrace: + Cmp PatternNumber, 0 + JE PEFunction_LastPattern1 + + Cmp PatternModified, 0 + JE PEFunction_LastPattern2 + + Call PEFunction_StorePattern + +PEFunction_LastPattern2: + Dec PatternNumber + Mov AX, PatternNumber + + Call NewPattern + +PEFunction_LastPattern1: + Mov AX, 1 + Ret + +EndP PEFunction_LastPattern +; + +Proc PEFunction_Next4Patterns Far + + Cmp PatternModified, 0 + JE PEFunction_Next4Patterns2 + + Call PEFunction_StorePattern + +PEFunction_Next4Patterns2: + Mov AX, PatternNumber + Add AX, 4 + Cmp AX, 199 + JBE PEFunction_Next4Patterns1 + + Mov AX, 199 + +PEFunction_Next4Patterns1: + Mov PatternNumber, AX + + Call NewPattern + + Mov AX, 1 + Ret + +EndP PEFunction_Next4Patterns + +; + +Proc PEFunction_Last4Patterns Far + + Cmp PatternModified, 0 + JE PEFunction_Last4Patterns2 + + Call PEFunction_StorePattern + +PEFunction_Last4Patterns2: + Mov AX, PatternNumber + Sub AX, 4 + JNS PEFunction_Last4Patterns1 + + Xor AX, AX + +PEFunction_Last4Patterns1: + Mov PatternNumber, AX + + Call NewPattern + + Mov AX, 1 + Ret + +EndP PEFunction_Last4Patterns + +; + +Proc PEFunction_LastOrderPattern Far + + Cmp PatternModified, 0 + JE PEFunction_LastOrderPattern3 + + Call PEFunction_StorePattern + +PEFunction_LastOrderPattern3: + Call Music_GetSongSegment + Mov ES, AX + + Mov BX, Order + And BX, BX + JZ PEFunction_LastOrderPattern2 + + Cmp Byte Ptr [ES:BX+0FFh], 200 + JAE PEFunction_LastOrderPattern2 + + Dec BX + Mov Order, BX + +PEFunction_LastOrderPattern2: + MovZX AX, Byte Ptr [ES:BX+0100h] + Cmp AL, 200 + JAE PEFunction_LastOrderPattern1 + + Mov PatternNumber, AX + + Call NewPattern + +PEFunction_LastOrderPattern1: + Mov AX, 1 + Ret + +EndP PEFunction_LastOrderPattern + +; + +Proc PEFunction_NextOrderPattern Far + + Cmp PatternModified, 0 + JE PEFunction_NextOrderPattern3 + + Call PEFunction_StorePattern + +PEFunction_NextOrderPattern3: + Mov BX, Order + + Cmp BX, 0FFh + JAE PEFunction_NextOrderPattern1 + + Call Music_GetSongSegment + Mov ES, AX + Cmp Byte Ptr [ES:BX+101h], 200 + JAE PEFunction_NextOrderPattern2 + + Inc BX + Mov Order, BX + +PEFunction_NextOrderPattern2: + MovZX AX, Byte Ptr [ES:BX+100h] + Cmp AL, 200 + JAE PEFunction_NextOrderPattern1 + + Mov PatternNumber, AX + + Call NewPattern + +PEFunction_NextOrderPattern1: + Mov AX, 1 + Ret + +EndP PEFunction_NextOrderPattern + +; + +Proc PEFunction_Alt0 Far + + Xor AX, AX + Mov SkipValue, AX + Mov SI, Offset CursorStepMsg + Call SetInfoLine + + Inc AX + + Ret + +EndP PEFunction_Alt0 + +; + +Proc PEFunction_BlockVolume Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Cmp [Word Ptr LastKeyBoard2], 2F00h + JE PEFunction_BlockVolume3 + + Mov DI, 13 + Call PE_AddToUndoBuffer + Call NetworkBlock + +PEFunction_BlockVolume3: + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + + Mov SI, AX + Mov CX, BlockBottom + Sub CX, BlockTop + Inc CX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov AL, LastVolume + + Mov DS, PatternDataArea + Add SI, 2 + +PEFunction_BlockVolume1: + Push CX + Push SI + + Mov CX, DX + +PEFunction_BlockVolume2: + Mov [SI], AL + + Add SI, 5 + Loop PEFunction_BlockVolume2 + + Pop SI + Pop CX + Add SI, 320 + Loop PEFunction_BlockVolume1 + + Mov AX, 1 + Ret + +EndP PEFunction_BlockVolume + +; + +Proc PEFunction_WipeExcessVolumes Far + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + Cmp [Word Ptr LastKeyBoard2+2], 1100h + JE PEFunction_WipeExcessVolumesEnd + + Mov DI, 14 + Call PE_AddToUndoBuffer + Call NetworkBlock + + Mov AX, 64 + Mul BlockTop + Add AX, BlockLeft + Mov BX, 5 + Mul BX + Mov SI, AX + + Mov CX, BlockBottom + Sub CX, BlockTop + Inc CX + + Mov DX, BlockRight + Sub DX, BlockLeft + Inc DX + + Mov DS, PatternDataArea + Mov AL, 0FFh + +PEFunction_WipeExcessVolumes1: + Push CX + Push SI + + Mov CX, DX + +PEFunction_WipeExcessVolumes2: + Cmp Byte Ptr [SI+1], 0 + JNE PEFunction_WipeExcessVolumes3 + + Cmp Byte Ptr [SI], NONOTE + JAE PEFunction_WipeExcessVolumes4 + +PEFunction_WipeExcessVolumes3: + Add SI, 5 + Loop PEFunction_WipeExcessVolumes2 + + Pop SI + Pop CX + Add SI, 320 + Loop PEFunction_WipeExcessVolumes1 + +PEFunction_WipeExcessVolumesEnd: + Mov AX, 1 + Ret + +PEFunction_WipeExcessVolumes4: + Mov [SI+2], AL + Jmp PEFunction_WipeExcessVolumes3 + +EndP PEFunction_WipeExcessVolumes + +; + +Proc PEFunction_PlayCurrentNote Far + + Mov AX, 64 + Mul Row + Add AX, Channel + Mov BX, 5 + Mul BX + Mov SI, AX + Mov AX, Channel + Mov DS, PatternDataArea + Mov DH, 32 + Call Music_PlayNote + +IF CHORDENTRY + Push CS + Pop DS + + Cmp ShiftPressed, 0 + JE PE_GotoNextInput + + Push SkipValue + Mov SkipValue, 0 + Mov NoteEntered, 1 + + Call PE_GotoNextInput + Pop SkipValue + + Mov AX, 1 + Ret +ELSE + Jmp PEFunction_Down +ENDIF + +EndP PEFunction_PlayCurrentNote + +; + +Proc PEFunction_PlayCurrentRow Far + + Mov CX, 64 + Mov DS, PatternDataArea + + Mov AX, 320 + Mul CS:Row + Mov SI, AX + Xor AX, AX + +PEFunction_PlayCurrentRow1: +; Push CX + +; Dec CX +; Mov AX, 64 +; Mul CS:Row +; Add AX, CX +; Mov BX, 5 +; Mul BX +; Mov SI, AX +; Mov AX, CX + Xor DH, DH + Call Music_PlayNote + +; Pop CX + Inc AX + Add SI, 5 + Loop PEFunction_PlayCurrentRow1 + + Jmp PEFunction_Down + +EndP PEFunction_PlayCurrentRow + +; + +Proc PEFunction_RestoreData Far + +; Mov PatternModified, 0 + + Cmp Byte Ptr LastKeyBoard2, 0Eh + JE PEFunction_RestoreData1 + + Mov DI, 1 + Call PE_AddToUndoBuffer + +PEFunction_RestoreData1: + Mov AX, PatternNumber + + Call Music_GetPattern + Call DecodePattern + + Xor BX, BX + Mov CL, 64 + Mov CH, Byte Ptr [CS:MaxRow] + Inc CH + Call NetworkPatternBlock + + Mov AX, 1 + Ret + + Ret + +EndP PEFunction_RestoreData + +; + +Proc PE_ToggleDefaultVolume Far + + Xor Flags, 1 + Mov SI, Offset DefaultVolumeOn + Test Flags, 1 + JNZ PEFunction_ToggleDefaultVolume1 + + Mov SI, Offset DefaultVolumeOff + +PEFunction_ToggleDefaultVolume1: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP PE_ToggleDefaultVolume + +; + +Proc PEFunction_ToggleTemplate Far + + Test CentraliseCursor, 4 + JZ ToggleTemplate2 + + Cmp BlockMark, 0 + JE PEFunction_NoBlockMarkedMessage + + ; Amplification = 1/(FastVolumeAmplification/100) + ; = 10050/FastvolumeAmplification + Mov AX, 10050 + Xor DX, DX + Div FastVolumeAmplification + Mov Amplification, AX + Jmp PEFastVolumeAmp + +ToggleTemplate2: + Mov AL, Template + Inc AX + Cmp AL, 4 + JBE PEFunction_ToggleTemplate1 + +Proc PEFunction_TemplateOff Far + + Xor AL, AL + +PEFunction_ToggleTemplate1: + Mov Template, AL + + Mov AX, 1 + Ret + +EndP PEFunction_TemplateOff + +EndP PEFunction_ToggleTemplate + +; + +Proc PE_GetCurrentPattern Far + + Mov AX, CS:PatternNumber + Mov BX, CS:MaxRow + Inc BX + Mov DS, CS:PatternDataArea + + Ret + +EndP PE_GetCurrentPattern + +; + +Proc PE_CheckWidth + + Xor DX, DX ; Time to work out width + Xor CX, CX ; Count of channels. + Mov SI, Offset ViewChannels + +PE_CheckWidth1: + LodsW + Cmp AL, 0FFh + JE PE_CheckWidth2 + + MovZX BX, AH + ShL BX, 2 + Add DX, [ViewMethodInfo+BX+2] + Inc CX + Jmp PE_CheckWidth1 + +PE_CheckWidth2: + And CX, CX + JZ PE_CheckWidth3 + + Add DX, 2 + + Cmp ViewDivision, 0 + JE PE_CheckWidth3 + + Dec CX + Add DX, CX + +PE_CheckWidth3: + Cmp DX, 76 ; Too big to fit screen? + JAE PE_CheckWidth5 + + Mov ViewWidth, DX + Xor AX, AX + Cmp DX, 74 + JAE PE_CheckWidth4 + + Mov AX, 74 + Sub AX, DX + Mov BL, 14 + Div BL + Xor AH, AH + +PE_CheckWidth4: + Mov NumChannelsEdit, AX + + DB 85h ; +PE_CheckWidth5: ; + StC ; + Ret + +EndP PE_CheckWidth + +; + +Proc PEFunction_ViewTrack Far + + Mov DX, Channel + Mov SI, Offset ViewChannels + +PEFunction_ViewTrack2: + LodsW + Cmp AL, 0FFh ; No more in list?? + JE PEFunction_ViewTrack1 + + Cmp AL, DL + JNE PEFunction_ViewTrack2 + +PEFunction_ViewTrack1: + Sub SI, 2 + + Mov CX, AX ; Store old value. + Mov AL, DL + Inc AH + Cmp AH, 4 ; Number of view methods + JBE PEFunction_ViewTrack3 + + LodsW + +PEFunction_ViewTrack8: + LodsW + Mov [SI-4], AX + Cmp AX, 0FFFFh + JNE PEFunction_ViewTrack8 + + Jmp PEFunction_ViewTrack9 + +PEFunction_ViewTrack3: + Mov [SI], AX ; Update... + +PEFunction_ViewTrack9: + Push CX + Push SI + + Call PE_CheckWidth + JC PEFunction_ViewTrack7 + + Add SP, 4 + Mov AX, 1 + Ret + +PEFunction_ViewTrack7: + Pop SI + Pop CX + Mov AX, [SI] + Inc AH + Cmp AH, 4 ; Number of view methods + JE PEFunction_ViewTrack10 + + Mov [SI], AX + + Jmp PEFunction_ViewTrack9 + +PEFunction_ViewTrack10: + Mov [SI], CX + + Mov AX, 1 + Ret + +EndP PEFunction_ViewTrack + +; + +Proc PEFunction_ClearViews Far + + Push CS + Pop ES + Mov DI, Offset ViewChannels + Mov CX, 100 + Mov AX, 0FFFFh + Rep StosW + + Mov ViewWidth, 0 + Mov AX, StartChannelEdit + Mov NumChannelsEdit, AX + Mov ViewChannelTracking, 0 + + Mov AX, 1 + Ret + +EndP PEFunction_ClearViews + +; + +Proc PE_SelectColour Near + + MovZX AX, CL ; AL = row number + + Mov CH, 0E6h + Cmp CS:RowHilight2, 0 + JE PE_SelectColour4 + Div CS:RowHilight2 + And AH, AH + JZ PE_SelectColour1 + +PE_SelectColour4: + MovZX AX, CL + Mov CH, 0F6h + Cmp CS:RowHilight1, 0 + JE PE_SelectColour5 + Div CS:RowHiLight1 + And AH, AH + JZ PE_SelectColour1 + +PE_SelectColour5: + Mov CH, 6 + +PE_SelectColour1: ; Check for block, CL = rownum, BP = ch + MovZX AX, CL ; AX = row number + Cmp CS:BlockMark, 0 + JE PE_SelectColour3 + Cmp BP, CS:BlockLeft + JB PE_SelectColour3 + Cmp BP, CS:BlockRight + JA PE_SelectColour3 + Cmp AX, CS:BlockTop + JB PE_SelectColour3 + Cmp AX, CS:BlockBottom + JA PE_SelectColour3 + + Test CH, 80h + JZ PE_SelectColour2 + + Mov CH, 96h + Ret + +PE_SelectColour2: + Mov CH, 86h + Ret + +PE_SelectColour3: + Cmp AX, CS:Row + JNE PE_SelectColour6 + + Test CS:CentraliseCursor, 2 + JZ PE_SelectColour6 + + Mov CH, 16h + +PE_SelectColour6: + Ret + +EndP PE_SelectColour + +; + +Proc PE_HilightCursor Near + + Mov AX, [ES:DI] + And AH, 8 + Or AH, 30h + StosW + + Ret + +EndP PE_HilightCursor + +; + +Proc PE_HilightView Near + + Mov AX, 1 + Cmp CS:Template, 0 + JE PE_HilightView1 + + Cmp CS:ShiftPressed, 0 + JNE PE_HilightView1 + + Cmp CS:PatternCursor, 0 + JNE PE_HilightView1 + + Cmp CS:BlockDataArea, 0 + JE PE_HilightView1 + + Mov FS, CS:BlockDataArea + Mov AX, [FS:0] + +PE_HilightView1: + Mov CX, CS:Channel + Cmp DX, CX + JB PE_HilightViewEnd + Add CX, AX + Cmp DX, CX + JAE PE_HilightViewEnd + + Sub DI, (32*160) + Mov AL, 160 + Mov CX, CS:Row + Sub CX, CS:TopRow + Mul CL + Add DI, AX + Add BP, CS:PatternCursor + + Mov CL, Byte Ptr [CS:BP] + Mov AX, CX + And AX, 0Fh + + Add AX, AX + Add DI, AX + + Mov DX, [ES:DI] + Test DH, 8 + JNZ PE_HilightView4 + Cmp DL, 184 + JE PE_HilightView4 + Cmp DL, 226 + JB PE_HilightView2 + Cmp DL, 246 + JAE PE_HilightView2 + +PE_HilightView4: + Mov AH, 0Fh ; mask value + Cmp CL, Byte Ptr [CS:BP+1] + JE PE_HilightView3 + + Mov AH, 0F0h + +PE_HilightView3: + Call S_InvertCursor + + Mov AX, 246+3000h + StosW + +PE_HilightViewEnd: + Ret + +PE_HilightView2: + Mov AX, [ES:DI] + Mov AH, 30h + StosW + + Sub CL, 10h + JNC PE_HilightView2 + + Ret + +EndP PE_HilightView + +; + +Proc PE_GetChannelColour ; Puts colour in AH + ; Param: BP = channel + + Push DS + + Call Music_GetSongSegment + Mov DS, AX + + Mov AH, 13h + Test Byte Ptr [DS:BP+40h], 80h + JZ PE_GetChannelColour1 + + Mov AH, 10h + +PE_GetChannelColour1: + Pop DS + + Ret + +EndP PE_GetChannelColour + +; + +Proc ViewCommon + + Push DS + Push ES + Push DI + + Mov BP, DX + And BP, 0FFh + + Push CS + Pop DS + MovZX AX, DL + Inc AX + Mov DX, 0A0Ch + Div DH +; Mov DL, 10 +; Div DL + + Add AX, 3030h + Mov [SI+BX], AX + Sub DI, 160 + Call PE_GetChannelColour + Call S_DrawString + + Pop DI + Pop ES + Pop DS + +; Mov DX, 0A0Ch ; DH = 10, DL = 12 (for div.) + + Mov CH, 32 + + Ret + +EndP ViewCommon + +; + + +Proc ViewFull ; DS:SI = pattern data + ; ES:DI = screen pointer + ; CS:BX = note data + ; CX = row number + ; DL = channel number. + + Push SI + Push BX + + Mov SI, Offset ChannelMsg + Mov BX, 9 + Call ViewCommon + + Pop BX + Pop SI + +ViewFull1: + Push CX + Push DX + Push DI + + Call PE_SelectColour + + LodsB + Call Draw_3Note + Mov AL, 20h + StosW + + LodsB ; Instrument + Call Draw_2Instrument + Mov AL, 20h + StosW + + LodsB ; Volume + Cmp AL, 0FFh + JNE ViewFull8 + + Mov AL, 173 + StosW + StosW + + Jmp ViewFull9 + +ViewFull8: + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC ViewFullNoVEffect + + Test AL, 80h + JZ ViewFullVEffect1 + + Add AH, 60 + +ViewFullVEffect1: + Mov AL, AH + Xor AH, AH + Div DH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov CL, AH + Mov AH, CH + StosW + Mov AL, CL + StosW + + Jmp ViewFull9 + +ViewFullNoVEffect: + Mov DL, CH + + Test AL, 80h + JZ ViewFull12 + + And DL, 0F0h + Or DL, 2 + And AL, 7Fh ; Filter out panning stuff. + +ViewFull12: + Xor AH, AH + Div DH + Add AX, 3030h + Mov CL, AH + Mov AH, DL + StosW + Mov AL, CL + StosW + + Mov AH, CH + +ViewFull9: + Mov AL, 20h + StosW + + LodsB ; Command + And AL, AL + JNZ ViewFull10 + + Mov AL, '.' + StosW + Jmp ViewFull11 + +ViewFull10: + Add AL, '@' + StosW + +ViewFull11: + LodsB ; Command value + + AAM 16 ; AH = High nibble, AL = low nibble + Mov CL, AL + Mov AL, AH + Mov AH, CH + Call PE_ConvHexAL + + Mov AL, CL + Call PE_ConvHexAL + + Add SI, 315 + Pop DI + Add DI, 160 + Pop DX + Pop CX + Inc CX + Dec CH + JNZ ViewFull1 + + Mov DX, BP + Mov BP, Offset CursorPositions + Jmp PE_HilightView + +EndP ViewFull + +; + +Proc ViewCompress ; DS:SI = pattern data + ; ES:DI = screen pointer + ; CS:BX = note data + ; CX = row number + ; DL = channel number. + + Push SI + Push BX + + Mov SI, Offset ChannelMsg2 + Mov BX, 8 + Call ViewCommon + + Pop BX + Pop SI + +ViewCompress1: + Push CX + Push DX + Push DI + + Call PE_SelectColour + + LodsB + + Call Draw_3Note + + LodsB ; Instrument + Sub CH, 4 + Call Draw_2Instrument + Add CH, 4 + + LodsB ; Volume + Mov AH, CH + + Cmp AL, 0FFh + JNE ViewCompress8 + + Mov AL, 173 + StosW + StosW + + Jmp ViewCompress9 + +ViewCompress8: + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC ViewCompressNoVEffect + + Test AL, 80h + JZ ViewCompressVEffect1 + + Add AH, 60 + +ViewCompressVEffect1: + Mov AL, AH + Xor AH, AH + Div DH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov CL, AH + Mov AH, CH + StosW + Mov AL, CL + StosW + + Jmp ViewCompress9 + +ViewCompressNoVEffect: + Mov DL, CH + + Test AL, 80h + JZ ViewCompress12 + + And DL, 0F0h + Or DL, 2 + And AL, 7Fh ; Filter out panning stuff. + +ViewCompress12: + Xor AH, AH + Div DH + Add AX, 3030h + Mov CL, AH + Mov AH, DL + StosW + Mov AL, CL + StosW + Mov AH, CH + +ViewCompress9: + LodsB ; Command + Sub AH, 4 + And AL, AL + JNZ ViewCompress10 + + Mov AL, '.' + StosW + Jmp ViewCompress11 + +ViewCompress10: + Add AL, '@' + StosW + +ViewCompress11: + LodsB ; Command value + AAM 16 ; AH = High nibble, AL = low nibble + Mov CL, AL + Mov AL, AH + Mov AH, CH + Sub AH, 4 + Call PE_ConvHexAL + + Mov AL, CL + Call PE_ConvHexAL + + Add SI, 315 + Pop DI + Add DI, 160 + Pop DX + Pop CX + Inc CX + Dec CH + JNZ ViewCompress1 + + Mov DX, BP + Mov BP, Offset CursorPositions+9 + Jmp PE_HilightView + +EndP ViewCompress + +; + +Proc ViewAllSmall ; DS:SI = pattern data + ; ES:DI = screen pointer + ; CS:BX = note data + ; CX = row number + ; DL = channel number. + + Push SI + Push BX + + Mov SI, Offset ChannelMsg7 + Mov BX, 5 + Call ViewCommon + + Pop BX + Pop SI + +ViewAllSmall1: + Push CX + Push DI + + Call PE_SelectColour + + LodsB + Call Draw_3Note + + LodsB ; Instrument + And AL, AL + JNZ ViewAllSmall6 + + Mov AL, 184 + Sub AH, 4 + StosW + Jmp ViewAllSmall7 + +ViewAllSmall6: + Xor AH, AH + Div DH + ShL AL, 4 + Or AL, AH + Mov AH, CH + Add AH, 4 + StosW + +ViewAllSmall7: + LodsB ; Volume + Cmp AL, 0FFh + JNE ViewAllSmall8 + + Mov AL, 184 + Mov AH, CH + StosW + + Jmp ViewAllSmall9 + +ViewAllSmall8: + Mov CL, CH + Add CL, 6 + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC ViewAllSmallNoVEffect + + Test AL, 80h + JZ ViewAllSmallVEffect1 + + Mov AL, AH + Add AL, 226 + Mov AH, CH + StosW + Jmp ViewAllSmall9 + +ViewAllSmallVEffect1: + Mov AL, AH + Mov AH, 0 + Div DH + ; AL = effect, AH = num + Add AL, 0Ah + ShL AL, 4 + Or AL, AH + Mov AH, CL + StosW + + Jmp ViewAllSmall9 + +ViewAllSmallNoVEffect: + Test AL, 80h + JZ ViewAllSmall12 + + Sub CL, 2 + And AL, 7Fh ; Filter out panning stuff. + +ViewAllSmall12: + Xor AH, AH + Div DH + ShL AL, 4 + Or AL, AH + Mov AH, CL + StosW + +ViewAllSmall9: + LodsB ; Command + Mov AH, CH + Sub AH, 4 + + And AL, AL + JNZ ViewAllSmall10 + + Mov AL, '.' + StosW + Jmp ViewAllSmall11 + +ViewAllSmall10: + Add AL, '@' + StosW + +ViewAllSmall11: + LodsB ; Command value + Add AH, 8 + StosW + + Add SI, 315 + Pop DI + Add DI, 160 + Pop CX + Inc CX + Dec CH + JNZ ViewAllSmall1 + + Mov DX, BP + Mov BP, Offset CursorPositions+18 + Jmp PE_HilightView + +EndP ViewAllSmall + +; + +Proc ViewNote ; DS:SI = pattern data + ; ES:DI = screen pointer + ; CS:BX = note data + ; CX = row number + ; DL = channel number. + + Push SI + Push BX + + Mov SI, Offset ChannelMsg4 + Mov BX, 1 + Call ViewCommon + + Pop BX + Pop SI + +ViewNote1: + Push CX + Push SI + Push DI + + Call PE_SelectColour + + LodsB + Cmp AL, NONOTE + JE ViewNote4 + + Call Draw_3Note + Jmp ViewNoteEnd + +ViewNote4: + LodsB + + Test AL, AL + JZ ViewNote5 + + Push AX + + Mov AH, CH + Mov AL, 20h + StosW + + Pop AX + + Call Draw_2Instrument + Jmp ViewNoteEnd + +ViewNote5: ; Volume + LodsB + Cmp AL, 0FFh + JE ViewNote6 + + Push AX + Mov AH, CH + Sub AH, 4 + Mov AL, 20h + StosW + Pop AX + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC ViewNoteNoVEffect + + Test AL, 80h + JZ ViewNoteVEffect1 + + Add AH, 60 + +ViewNoteVEffect1: + Mov AL, AH + Xor AH, AH + Div DH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov CL, AH + Mov AH, CH + StosW + Mov AL, CL + StosW + + Jmp ViewNoteEnd + +ViewNoteNoVEffect: + Mov CL, CH + Sub CL, 4 + + Test AL, 80h + JZ ViewNote25 + + Dec CX + And AL, 7Fh + +ViewNote25: + Xor AH, AH + Div DH + Add AX, 3030h + XChg CL, AH + StosW + Mov AL, CL + StosW + + Jmp ViewNoteEnd + +ViewNote6: + LodsW + And AX, AX + JZ ViewNote11 + + Mov CL, AH + And AL, AL + JZ ViewNote7 + + Add AL, '@' + Jmp ViewNote8 + +ViewNote7: + Mov AL, '.' + +ViewNote8: + Mov AH, CH + Sub AH, 4 + StosW + + Mov AL, CL + AAM 16 ; AH = High nibble, AL = low nibble + Mov CL, AL + Mov AL, AH + Mov AH, CH + Sub AH, 4 + Call PE_ConvHexAL + + Mov AL, CL + Call PE_ConvHexAL + + Jmp ViewNoteEnd + +ViewNote11: ; Nothing to show except dots... + Mov AH, CH + Mov AL, 173 + StosW + StosW + StosW + +ViewNoteEnd: + + Pop DI + Add DI, 160 + Pop SI + Add SI, 320 + Pop CX + Inc CX + Dec CH + JNZ ViewNote1 + + Cmp BP, CS:Channel + JE ViewNote12 + + Mov DX, BP + Mov BP, Offset CursorPositions+27 + Jmp PE_HilightView + + Ret + +ViewNote12: + Push DI + + Sub SI, (320*32) + Sub DI, (32*160) + Mov AL, 160 + Mov DX, CS:Row + Sub DX, CS:TopRow + + Mul DL + Add DI, AX + Add AX, AX + Add SI, AX + + Mov CX, CS:Row + Call PE_SelectColour ; CH = colour. + + Mov DX, CS:PatternCursor + +ViewNote13: + LodsB + Cmp DL, 1 + JA ViewNote16 + + Cmp AL, NONOTE + JNE ViewNote15 + + Mov AH, CH + Mov AL, 173 + StosW + StosW + StosW + +ViewNote15: + Jmp ViewNoteEndHilight + +ViewNote16: + LodsB + Cmp DL, 3 + JA ViewNote19 + + Mov DH, AL + + Mov AH, CH + Mov AL, 20h + StosW + And DH, DH + JZ ViewNote17 + + MovZX AX, DH + Mov DH, 10 + Div DH + + Add AX, 3030h + Mov DH, AH + Mov AH, CH + StosW + Mov AL, DH + StosW + Jmp ViewNoteEndHilight + +ViewNote17: + Mov AL, 173 + StosW + StosW + Jmp ViewNoteEndHilight + +ViewNote19: + LodsB + Cmp DL, 5 + JA ViewNote22 + + Mov DH, AL + + Mov AH, CH + Sub AH, 4 + Mov AL, 20h + StosW + + Cmp DH, 0FFh + JE ViewNote20 + + Mov AH, DH + And AH, 7Fh + Sub AH, 65 + JC ViewNoteNoVEffect2 + + Test DH, 80h + JZ ViewNoteVEffect2 + + Add AH, 60 + +ViewNoteVEffect2: + Mov AL, AH + Xor AH, AH + Mov DH, 10 + Div DH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov CL, AH + Mov AH, CH + StosW + Mov AL, CL + StosW + + Jmp ViewNoteEndHilight + +ViewNoteNoVEffect2: + Sub CH, 4 + + Test DH, 80h + JZ ViewNote26 + + Dec CH + And DH, 7Fh + +ViewNote26: + MovZX AX, DH + Mov DH, 10 + Div DH + + Add AX, 3030h + XChg CH, AH + StosW + Mov AL, CH + StosW + Jmp ViewNoteEndHilight + +ViewNote20: + Mov AL, 173 + StosW + StosW + Jmp ViewNoteEndHilight + +ViewNote22: + LodsB + Mov AH, CH + Sub AH, 4 + And AL, AL + JNZ ViewNote23 + + Mov AL, '.' + Jmp ViewNote24 + +ViewNote23: + Add AL, '@' + +ViewNote24: + Mov AH, CH + Sub AH, 4 + StosW + + LodsB + AAM 16 ; AH = High nibble, AL = low nibble + Mov CL, AL + Mov AL, AH + Mov AH, CH + Sub AH, 4 + Call PE_ConvHexAL + + Mov AL, CL + Call PE_ConvHexAL + +ViewNoteEndHilight: + Pop DI + + Mov DX, BP + Mov BP, Offset CursorPositions+27 + Jmp PE_HilightView + + +EndP ViewNote + +; + +Proc ViewTiny ; DS:SI = pattern data + ; ES:DI = screen pointer + ; CS:BX = note data + ; CX = row number + ; DL = channel number. + + Push SI + Push BX + + Mov SI, Offset ChannelMsg5 + Mov BX, 0 + Call ViewCommon + + Pop BX + Pop SI + +ViewTiny1: + Push CX + Push SI + Push DI + + Call PE_SelectColour + + LodsB + Cmp AL, NONOTE + JE ViewTiny4 + + Call Draw_2Note + Jmp ViewTinyEnd + +ViewTiny4: + LodsB + Test AL, AL + JZ ViewTiny5 + + Call Draw_2Instrument + Jmp ViewTinyEnd + +ViewTiny5: ; Volume + LodsB + Cmp AL, 0FFh + JE ViewTiny6 + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC ViewTinyNoVEffect + + Test AL, 80h + JZ ViewTinyVEffect1 + + Add AH, 60 + +ViewTinyVEffect1: + Mov AL, AH + Xor AH, AH + Div DH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov CL, AH + Mov AH, CH + StosW + Mov AL, CL + StosW + + Jmp ViewTinyEnd + +ViewtinyNoVEffect: + Mov CL, CH + Sub CL, 4 + + Test AL, 80h + JZ ViewTiny27 + + Dec CX + And AL, 7Fh + +ViewTiny27: + Xor AH, AH + Div DH + Add AX, 3030h + XChg AH, CL + StosW + Mov AL, CL + StosW + + Jmp ViewTinyEnd + +ViewTiny6: + LodsW + And AX, AX + JZ ViewTiny11 + + Mov CL, AH + And AL, AL + JZ ViewTiny7 + + Add AL, '@' + Jmp ViewTiny8 + +ViewTiny7: + Mov AL, '.' + +ViewTiny8: + Mov AH, CH + Sub AH, 4 + StosW + Add AH, 8 + Mov AL, CL + StosW + + Jmp ViewTinyEnd + +ViewTiny11: ; Nothing to show except dots... + Mov AH, CH + Mov AL, 173 + StosW + StosW + +ViewTinyEnd: + + Pop DI + Pop SI + Pop CX + + Add DI, 160 + Inc CX + Add SI, 320 + + Dec CH + JNZ ViewTiny1 + + Cmp BP, CS:Channel + JE ViewTiny14 + + Mov DX, BP + Mov BP, Offset CursorPositions+36 + Jmp PE_HilightView + +ViewTiny14: + Push DI + + Sub SI, (32*320) + Sub DI, (32*160) + Mov AL, 160 + Mov CX, CS:Row + Sub CX, CS:TopRow + Mul CL + Add DI, AX + Add AX, AX + Add SI, AX + + Mov CX, CS:Row + Call PE_SelectColour ; CH = colour. + + Mov DX, CS:PatternCursor + LodsB + Cmp DL, 1 + JA ViewTiny17 + + Cmp AL, NONOTE + JE ViewTinyDots + + Jmp ViewTinyEndHilight + +ViewTiny17: + LodsB ; Instrument + Cmp DL, 3 + JA ViewTiny20 + + And AL, AL + JZ ViewTinyDots + + Mov DH, 10 + Xor AH, AH + Div DH + Add AX, 3030h + Mov DH, AH + Mov AH, CH + StosW + Mov AL, DH + StosW + Jmp ViewTinyEndHilight + +ViewTiny20: + LodsB ; Volume + Cmp DL, 5 + JA ViewTiny23 + + Cmp AL, 0FFh + JE ViewTiny21 + + Mov AH, AL + And AH, 7Fh + Sub AH, 65 + JC ViewTinyNoVEffect2 + + Test AL, 80h + JZ ViewTinyVEffect2 + + Add AH, 60 + +ViewTinyVEffect2: + Mov AL, AH + Xor AH, AH + Mov DH, 10 + Div DH + ; AL = effect, AH = num + Add AX, 'A'+'0'*256 + Mov CL, AH + Mov AH, CH + StosW + Mov AL, CL + StosW + + Jmp ViewTinyEndHilight + +ViewTinyNoVEffect2: + Sub CH, 4 + Test AL, 80h + JZ ViewTiny28 + + Dec CH + And AL, 7Fh + +ViewTiny28: + Mov DH, 10 + Xor AH, AH + Div DH + Add AX, 3030h + XChg CH, AH + StosW + Mov AL, CH + StosW + Jmp ViewTinyEndHilight + +ViewTiny21: + Sub CH, 4 + +ViewTinyDots: + Mov AH, CH + Mov AL, 173 + StosW + StosW + Jmp ViewTinyEndHilight + +ViewTiny23: + LodsB ; CommandValue. + And AL, AL + JNZ ViewTiny24 + + Mov AL, '.' + Jmp ViewTiny25 + +ViewTiny24: + Add AL, '@' + +ViewTiny25: + Mov AH, CH + Sub AH, 4 + StosW + + Add AH, 8 + LodsB + StosW + +ViewTinyEndHilight: + Pop DI + + Mov DX, BP + Mov BP, Offset CursorPositions+36 + Jmp PE_HilightView + +EndP ViewTiny + +; + +Proc PEFunction_ToggleDivision Far + + Xor ViewDivision, 1 + + Call PE_CheckWidth + JC PEFunction_ToggleDivision1 + + Mov AX, 1 + Ret + +PEFunction_ToggleDivision1: + Xor ViewDivision, 1 + + Mov AX, 1 + Ret + +EndP PEFunction_ToggleDivision + +; + +Proc PEFunction_Ctrl0 Far + + Mov AX, 0 + Jmp PE_FastView + +EndP PEFunction_Ctrl0 + +; + +Proc PEFunction_Ctrl1 Far + + Mov AX, 1 + Jmp PE_FastView + +EndP PEFunction_Ctrl1 + +; + +Proc PEFunction_Ctrl2 Far + + Mov AX, 2 + Jmp PE_FastView + +EndP PEFunction_Ctrl2 + +; + +Proc PEFunction_Ctrl3 Far + + Mov AX, 3 + Jmp PE_FastView + +EndP PEFunction_Ctrl3 + +; + +Proc PEFunction_Ctrl4 Far + + Mov AX, 4 + Jmp PE_FastView + +EndP PEFunction_Ctrl4 + +; + +Proc PEFunction_Ctrl5 Far + + Mov AX, 5 + Jmp PE_FastView + +EndP PEFunction_Ctrl5 + +; + +Proc PEFunction_QuickViewSetup Far ; CX = num with div + ; BX = num without div + ; AH = type. + Cmp ViewDivision, 0 + JNE PEFunction_QuickViewSetup1 + + Mov CX, BX + Mov BX, 100 + Sub BX, CX + +PEFunction_QuickViewSetup1: + Push CS + Pop ES + Mov DI, Offset ViewChannels + +PEFunction_QuickViewSetup3: + StosW + + Inc AL + Loop PEFunction_QuickViewSetup3 + + Mov CX, BX + Mov AX, 0FFFFh + Rep StosW + + Call PE_CheckWidth + + Cmp ViewChannelTracking, 0 + JNE PEFunction_QuickViewSetup2 + + Call PEFunction_ToggleTracking + +PEFunction_QuickViewSetup2: + + Mov AX, 1 + Ret + +EndP PEFunction_QuickViewSetup + +; + +Proc PEFunction_Ctrl_Shift1 Far + + Mov AX, 100h + Mov BX, 7 + Mov CX, 6 + Jmp PEFunction_QuickViewSetup + +EndP PEFunction_Ctrl_Shift1 + +; + +Proc PEFunction_Ctrl_Shift2 Far + + Mov AX, 200h + Mov BX, 10 + Mov CX, 9 + Jmp PEFunction_QuickViewSetup + +EndP PEFunction_Ctrl_Shift2 + +; + +Proc PEFunction_Ctrl_Shift3 Far + + Mov AX, 300h + Mov BX, 24 + Mov CX, 18 + Jmp PEFunction_QuickViewSetup + +EndP PEFunction_Ctrl_Shift3 + +; + +Proc PEFunction_Ctrl_Shift4 Far + + Mov AX, 400h + Mov BX, 36 + Mov CX, 24 + Jmp PEFunction_QuickViewSetup + +EndP PEFunction_Ctrl_Shift4 + +; + +Proc PE_FastView Far + + Dec AX ; AL = viewmethod + Mov CL, AL + Mov BX, Channel + Mov SI, Offset ViewChannels + + Cmp CL, 0FFh + JE PE_FastView4 + +PE_FastView1: + LodsW + Cmp AL, 0FFh + JE PE_FastView2 + + Cmp AL, BL + JE PE_FastView2 + Jmp PE_FastView1 + +PE_FastView2: + Sub SI, 2 + Push AX + Push SI + + Mov AL, BL + Mov AH, CL + Mov [SI], AX + + Call PE_CheckWidth + JC PE_FastView3 + + Add SP, 4 + Mov AX, 1 + Ret + +PE_FastView3: + Pop SI + Pop AX + Mov [SI], AX + + Mov AX, 1 + Ret + +PE_FastView4: + LodsW + Cmp AL, 0FFh + JE PE_FastView6 + + Cmp AL, BL + JNE PE_FastView4 + +PE_FastView5: + LodsW + Mov [SI-4], AX + Cmp AX, 0FFFFh + JNE PE_FastView5 + + Call PE_CheckWidth + +PE_FastView6: + Mov AX, 1 + Ret + +EndP PE_FastView + +; + +Proc PEFunction_ViewLeft Far + ; First find current channel. + Mov DX, Channel + Mov SI, Offset ViewChannels + +PEFunction_ViewLeft1: + LodsW + Cmp AL, 0FFh + JE PEFunction_ViewLeft2 + + Cmp AL, DL + JNE PEFunction_ViewLeft1 + + Cmp SI, Offset ViewChannels+2 + JE PEFunction_ViewLeft2 + + Mov DL, [SI-4] + Mov Channel, DX + +PEFunction_ViewLeft2: ; Else decrease channel + Mov AX, 1 + Ret + +EndP PEFunction_ViewLeft + +; + +Proc PEFunction_ViewRight Far + + Mov DX, Channel + Mov SI, Offset ViewChannels + +PEFunction_ViewRight1: + LodsW + Cmp AL, 0FFh + JE PEFunction_ViewRight2 + + Cmp AL, DL + JNE PEFunction_ViewRight1 + + LodsW + Cmp AL, 0FFh + JE PEFunction_ViewRight2 + + Xor AH, AH + Mov Channel, AX + +PEFunction_ViewRight2: + Mov AX, 1 + Ret + +EndP PEFunction_ViewRight + +; + +Proc PEFunction_AltRight Far + + Mov AX, Channel + Inc AX + Cmp AX, 64 + JAE PEFunction_AltRight1 + + Mov Channel, AX + +PEFunction_AltRight1: + Mov AX, 1 + Ret + +EndP PEFunction_AltRight + +; + +Proc PEFunction_AltLeft Far + + Mov AX, Channel + And AX, AX + JZ PEFunction_AltLeft1 + + Dec AX + Mov Channel, AX + +PEFunction_AltLeft1: + Mov AX, 1 + Ret + +EndP PEFunction_AltLeft + +; + +Proc PEFunction_Ctrl_Home Far + + Mov AX, Row + Sub AL, 1 + AdC AL, 0 + Mov Row, AX + + Mov AX, 1 + Ret + +EndP PEFunction_Ctrl_Home + +; + +Proc PEFunction_Ctrl_End Far + + Mov AX, Row + Cmp AX, MaxRow + AdC AX, 0 + Mov Row, AX + + Mov AX, 1 + Ret + +EndP PEFunction_Ctrl_End + +; + +Proc PEFunction_AltUp Far + + Mov AX, TopRow + Mov BX, Row + Test AX, AX + JZ PEFunction_AltUp1 + + Dec AX + Mov TopRow, AX + Sub BX, AX + Cmp BX, 32 + JB PEFunction_AltUp1 + + Dec Row + +PEFunction_AltUp1: + Mov AX, 1 + Ret + +EndP PEFunction_AltUp + +; + +Proc PEFunction_AltDown Far + + Mov AX, TopRow + Mov BX, MaxRow + + Inc AX + Sub BX, AX + Cmp BX, 31 + JB PEFunction_AltDown1 + + Mov TopRow, AX + Cmp AX, Row + JBE PEFunction_AltDown1 + + Mov Row, AX + +PEFunction_AltDown1: + Mov AX, 1 + Ret + +EndP PEFunction_AltDown + +; + +Proc PE_GetLastInstrument Far + + MovZX BX, [CS:LastInstrument] + Dec BX + Ret + +EndP PE_GetLastInstrument + +; + +Proc PE_SwapInstruments Far ; DH/DL = instruments + ; to swap. + Call Music_GetSongSegment + Mov DS, AX + Push CS + Pop DS + Assume DS:Pattern + + Mov TempVariableArea2, DX + Mov AX, PatternNumber + Mov TempVariableArea, AX + Call PEFunction_StorePattern + + Call PE_GetMaxPattern + Inc AX + Mov TempVariableArea4, AX ; 1=OldPattern + ; 2=Instrument swap + ; 3=Current pattern + ; 4=Max pattern + + ; OK... + Mov AL, 1 + Call S_SetDirectMode + + ; Draw Box first... + Call S_DrawSmallBox + + Mov TempVariableArea3, 0 + Assume DS:Nothing + +PE_SwapInstruments1: ; Draw % Complete on screen first + Mov AX, 100 + Mul TempVariableArea3 + Div TempVariableArea4 ; AX = percentage + + Push AX + + Push CS + Pop DS + Assume DS:Pattern + + Mov SI, Offset CompleteMsg + Mov DI, (34+26*80)*2 + Mov AH, 20h + Call S_DrawString + Add SP, 2 ; OK message is on screen. + + + Mov AX, TempVariableArea3 + Mov PatternNumber, AX + Assume DS:Nothing + + Call Music_GetPattern + Call DecodePattern ; Next pattern should be in mem + + Mov AX, MaxRow + Inc AX + Mov CX, 64 + Mul CX + ; AX = number of "blocks" + Mov CX, AX + Mov DX, TempVariableArea2 + + Mov DS, PatternDataArea + Mov SI, 1 + +PE_SwapInstruments3: + Mov AL, [SI] + Cmp AL, DL + JNE PE_SwapInstruments4 + + Mov AL, DH + And AL, 7Fh + Mov [SI], AL + Jmp PE_SwapInstruments5 + +PE_SwapInstruments4: + Test DH, 80h + JNZ PE_SwapInstruments5 + + Cmp AL, DH + JNE PE_SwapInstruments5 + + Mov [SI], DL + +PE_SwapInstruments5: + Add SI, 5 + Loop PE_SwapInstruments3 + + Push CS + Pop DS + + Mov AX, TempVariableArea3 + Call PEFunction_StorePattern + ; OK.. onto next pattern + + Mov AX, TempVariableArea3 + Inc AX + Cmp AX, TempVariableArea4 + JAE PE_SwapInstruments2 + + Mov TempVariableArea3, AX + Jmp PE_SwapInstruments1 + +PE_SwapInstruments2: + Mov AL, 0 + Call S_SetDirectMode + + Push CS + Pop DS + Assume DS:Pattern + + Mov AX, TempVariableArea + Mov PatternNumber, AX + Call Music_GetPattern + Call DecodePattern + + Ret + +EndP PE_SwapInstruments + Assume DS:Nothing + +; + +Proc PE_InsertInstrument Far ; DL = instrument + + Push CS + Pop DS + Assume DS:Pattern + + Mov TempVariableArea2, DX + Mov AX, PatternNumber + Mov TempVariableArea, AX + Call PEFunction_StorePattern + + Call PE_GetMaxPattern + Inc AX + Mov TempVariableArea4, AX ; 1=OldPattern + ; 2=Instrument swap + ; 3=Current pattern + ; 4=Max pattern + + ; OK... + Mov AL, 1 + Call S_SetDirectMode + + ; Draw Box first... + Call S_DrawSmallBox + + Mov TempVariableArea3, 0 + Assume DS:Nothing + +PE_InsertInstrument1: ; Draw % Complete on screen first + Mov AX, 100 + Mul TempVariableArea3 + Div TempVariableArea4 ; AX = percentage + + Push AX + + Push CS + Pop DS + Assume DS:Pattern + + Mov SI, Offset CompleteMsg + Mov DI, (34+26*80)*2 + Mov AH, 20h + Call S_DrawString + Add SP, 2 ; OK message is on screen. + + + Mov AX, TempVariableArea3 + Mov PatternNumber, AX + Assume DS:Nothing + + Call Music_GetPattern + Call DecodePattern ; Next pattern should be in mem + + Mov AX, MaxRow + Inc AX + Mov CX, 64 + Mul CX + ; AX = number of "blocks" + Mov CX, AX + Mov DX, TempVariableArea2 + + Mov DS, PatternDataArea + Mov SI, 1 + +PE_InsertInstrument3: + Cmp [SI], DL + JB PE_InsertInstrument4 + + Cmp Byte Ptr [SI], 99 + JAE PE_InsertInstrument4 + + Inc Byte Ptr [SI] + +PE_InsertInstrument4: + Add SI, 5 + Loop PE_InsertInstrument3 + + Push CS + Pop DS + + Mov AX, TempVariableArea3 + Call PEFunction_StorePattern + ; OK.. onto next pattern + + Mov AX, TempVariableArea3 + Inc AX + Cmp AX, TempVariableArea4 + JAE PE_InsertInstrument2 + + Mov TempVariableArea3, AX + Jmp PE_InsertInstrument1 + +PE_InsertInstrument2: + Mov AL, 0 + Call S_SetDirectMode + + Push CS + Pop DS + Assume DS:Pattern + + Mov AX, TempVariableArea + Mov PatternNumber, AX + Call Music_GetPattern + Call DecodePattern + + Ret + +EndP PE_InsertInstrument + Assume DS:Nothing + +; + +Proc PE_DeleteInstrument Far ; DL = instrument + + Push CS + Pop DS + Assume DS:Pattern + + Mov TempVariableArea2, DX + Mov AX, PatternNumber + Mov TempVariableArea, AX + Call PEFunction_StorePattern + + Call PE_GetMaxPattern + Inc AX + Mov TempVariableArea4, AX ; 1=OldPattern + ; 2=Instrument swap + ; 3=Current pattern + ; 4=Max pattern + + ; OK... + Mov AL, 1 + Call S_SetDirectMode + + ; Draw Box first... + Call S_DrawSmallBox + + Mov TempVariableArea3, 0 + Assume DS:Nothing + +PE_DeleteInstrument1: ; Draw % Complete on screen first + Mov AX, 100 + Mul TempVariableArea3 + Div TempVariableArea4 ; AX = percentage + + Push AX + + Push CS + Pop DS + Assume DS:Pattern + + Mov SI, Offset CompleteMsg + Mov DI, (34+26*80)*2 + Mov AH, 20h + Call S_DrawString + Add SP, 2 ; OK message is on screen. + + + Mov AX, TempVariableArea3 + Mov PatternNumber, AX + Assume DS:Nothing + + Call Music_GetPattern + Call DecodePattern ; Next pattern should be in mem + + Mov AX, MaxRow + Inc AX + Mov CX, 64 + Mul CX + ; AX = number of "blocks" + Mov CX, AX + Mov DX, TempVariableArea2 + + Mov DS, PatternDataArea + Mov SI, 1 + +PE_DeleteInstrument3: + Cmp [SI], DL + JB PE_DeleteInstrument4 + + Dec Byte Ptr [SI] + +PE_DeleteInstrument4: + Add SI, 5 + Loop PE_DeleteInstrument3 + + Push CS + Pop DS + + Mov AX, TempVariableArea3 + Call PEFunction_StorePattern + ; OK.. onto next pattern + + Mov AX, TempVariableArea3 + Inc AX + Cmp AX, TempVariableArea4 + JAE PE_DeleteInstrument2 + + Mov TempVariableArea3, AX + Jmp PE_DeleteInstrument1 + +PE_DeleteInstrument2: + Mov AL, 0 + Call S_SetDirectMode + + Push CS + Pop DS + Assume DS:Pattern + + Mov AX, TempVariableArea + Mov PatternNumber, AX + Call Music_GetPattern + Call DecodePattern + + Ret + +EndP PE_DeleteInstrument + Assume DS:Nothing + +; + +Proc PE_UpdateInstruments Far ; ES:DI = instrument table + ; DL = instrument number + Push CS + Pop DS + Assume DS:Pattern + + Mov Byte Ptr TempVariableArea2, DL + Mov AX, PatternNumber + Mov TempVariableArea, AX + Mov TempVariableArea5, ES + Mov TempVariableArea6, DI + Call PEFunction_StorePattern + + Call PE_GetMaxPattern + Inc AX + Mov TempVariableArea4, AX ; 1=OldPattern + ; 2=Instrument + ; 3=Current pattern + ; 4=Max pattern + ; 5=ES + ; 6=DI + + Mov AL, 1 + Call S_SetDirectMode + + ; Draw Box first... + Call S_DrawSmallBox + + Mov TempVariableArea3, 0 + Assume DS:Nothing + +PE_UpdateInstruments1: ; Draw % Complete on screen first + Mov AX, 100 + Mul TempVariableArea3 + Div TempVariableArea4 ; AX = percentage + + Push AX + + Push CS + Pop DS + Assume DS:Pattern + + Mov SI, Offset CompleteMsg + Mov DI, (34+26*80)*2 + Mov AH, 20h + Call S_DrawString + Pop AX ; Remove AX from stack + + Mov AX, TempVariableArea3 + Mov PatternNumber, AX + Assume DS:Nothing + + Call Music_GetPattern + Call DecodePattern ; Next pattern should be in mem + + Mov AX, MaxRow + Inc AX + Mov CX, 64 + Mul CX + ; AX = number of "blocks" + Mov CX, AX + Mov BL, CS:Byte Ptr TempVariableArea2 + Mov ES, CS:TempVariableArea5 + + Mov DS, PatternDataArea + Xor SI, SI + +PE_UpdateInstruments3: + LodsW + Cmp AL, NONOTE + JAE PE_UpdateInstrument4 + + And AH, AH ; AH = instrument + JZ PE_UpdateInstrument4 + + Xor DX, DX + Mov DI, CS:TempVariableArea6 + +PE_UpdateInstrument5: + Cmp AX, [ES:DI] + JE PE_UpdateInstrument7 + +; Add DI, 2 + ScasW + Inc DX ; Not it... + Cmp DX, 120 + JB PE_UpdateInstrument5 + + Jmp PE_UpdateInstrument4 + +PE_UpdateInstrument7: + Mov DH, BL + Mov [DS:SI-2], DX + + +PE_UpdateInstrument4: + Add SI, 3 + Loop PE_UpdateInstruments3 + + Push CS + Pop DS + + Mov AX, TempVariableArea3 + Call PEFunction_StorePattern + ; OK.. onto next pattern + + Mov AX, TempVariableArea3 + Inc AX + Cmp AX, TempVariableArea4 + JAE PE_UpdateInstruments2 + + Mov TempVariableArea3, AX + Jmp PE_UpdateInstruments1 + +PE_UpdateInstruments2: + Mov AL, 0 + Call S_SetDirectMode + + Push CS + Pop DS + Assume DS:Pattern + + Mov AX, TempVariableArea + Mov PatternNumber, AX + Call Music_GetPattern + Call DecodePattern + + Ret + +EndP PE_UpdateInstruments + Assume DS:Nothing + +; + +Proc PEFunction_Alt_F9 Far + Assume DS:Pattern + + Mov AX, Channel + Call Music_ToggleChannel + + Mov AX, 1 + Ret + +EndP PEFunction_Alt_F9 + Assume DS:Nothing + +; + +Proc PEFunction_MuteNext Far + Assume DS:Pattern + + Call PEFunction_Alt_F9 + Jmp PEFunction_Tab + +EndP PEFunction_MuteNext + +; + +Proc PEFunction_MutePrevious Far + Assume DS:Pattern + + Sub Channel, 1 + AdC Channel, 0 + Jmp PEFunction_Alt_F9 + +EndP PEFunction_MutePrevious + +; + +Proc PEFunction_Alt_F10 Far + Assume DS:Pattern + + Mov AX, Channel + Call Music_SoloChannel + + Mov AX, 1 + Ret + +EndP PEFunction_Alt_F10 + Assume DS:Nothing + +; + +Proc PEFunction_SoloGotoNext Far + + Call PEFunction_Alt_F10 + Jmp PEFunction_Tab + +EndP PEFunction_SoloGotoNext + +; + +Proc PEFunction_UnmuteAll Far + + Call Music_UnmuteAll + + Mov AX, 1 + Ret + +EndP PEFunction_UnmuteAll + +; + +Proc PE_ShowOrder Far ; DX = order. + + Call S_GetDestination + Mov CX, 32 + + Mov DI, (2+15*80)*2+1 + Mov BX, TopOrder + +PE_ShowOrder1: + Mov AL, 23h + Cmp BX, DX + JE PE_ShowOrder2 + + Mov AL, 20h + +PE_ShowOrder2: + StosB + Inc DI + StosB + Inc DI + StosB + + Add DI, 155 + Inc BX + Loop PE_ShowOrder1 + + Ret + +EndP PE_ShowOrder + +; + +Proc PE_PlayCurrentPosition Far + Assume DS:Pattern + + Call I_ClearTables + + Mov AX, PatternNumber + Mov BX, MaxRow + Inc BX + Mov CX, Row + + Call Music_PlayPattern + + Mov AX, 1 + Ret + +EndP PE_PlayCurrentPosition + Assume DS:Nothing + +; + +Proc PEFunction_SetPlayMark Far + Assume DS:Pattern + + Cmp PlayMarkOn, 1 ; If on.. + JNE PEFunction_SetPlayMarkNew + + Mov AX, PatternNumber + Cmp AX, PlayMarkPattern + JNE PEFunction_SetPlayMarkNew + + Mov AX, Row + Cmp AX, PlayMarkRow + JNe PEFunction_SetPlayMarkNew + + Mov PlayMarkOn, 0 + Jmp PEFunction_SetPlayMarkEnd + +PEFunction_SetPlayMarkNew: + Mov PlayMarkOn, 1 + Mov AX, PatternNumber + Mov PlayMarkPattern, AX + Mov AX, Row + Mov PlayMarkRow, AX + +PEFunction_SetPlayMarkEnd: + Mov AX, 1 + Ret + +EndP PEFunction_SetPlayMark + Assume DS:Nothing + +; + +Proc PE_F7 Far ; If no mark is set, use + ; current pattern & row + Call I_ClearTables + + Push CS + Pop DS + Assume DS:Pattern + + Mov CX, PatternNumber + Mov BX, Row + + Cmp PlayMarkOn, 1 + JNE PE_F7_1 + + Mov CX, PlayMarkPattern + Mov BX, PlayMarkRow + +PE_F7_1: + Mov SI, Order + + Call Music_GetSongSegment + Mov ES, AX + + Cmp CL, [ES:SI+100h] + JNE PE_F7_3 + + Mov AX, SI + Jmp PE_F7_4 + +PE_F7_3: + Mov AL, CL ; AL = pattern. + Mov DI, 100h + Mov CX, 256 + + RepNE ScasB + JNE PE_F7_2 + + Mov AX, DI + Sub AX, 101h ; AX = order. + +PE_F7_4: + Call Music_PlayPartSong + + Mov AX, 1 + Ret + +PE_F7_2: + Mov CX, BX + + Mov AX, PatternNumber + Mov BX, MaxRow + Inc BX + Call Music_PlayPattern + + Mov AX, 1 + Ret + +EndP PE_F7 + +; + +Proc PEFunction_ToggleTracking Far + Assume DS:Pattern + + Mov SI, Offset NoViewChannelTrackingMsg + Xor ViewChannelTracking, 1 + JZ PEFunction_ToggleTracking1 + + Mov SI, Offset ViewChannelTrackingMsg + +PEFunction_ToggleTracking1: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP PEFunction_ToggleTracking + Assume DS:Nothing + +; + +Proc PEFunction_ToggleRowHilight Far + Assume DS:Pattern + + Mov SI, Offset NoRowHilightMsg + Xor CentraliseCursor, 2 + Test CentraliseCursor, 2 + JZ PEFunction_ToggleRowHilight1 + + Mov SI, Offset RowHilightMsg + +PEFunction_ToggleRowHilight1: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP PEFunction_ToggleRowHilight + Assume DS:Nothing + +; + +Proc PEFunction_ToggleCentralise Far + Assume DS:Pattern + + Mov SI, Offset NoCentraliseCursorMsg + Xor CentraliseCursor, 1 + Test CentraliseCursor, 1 + JZ PEFunction_ToggleCentralise1 + + Mov SI, Offset CentraliseCursorMsg + +PEFunction_ToggleCentralise1: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP PEFunction_ToggleCentralise + Assume DS:Nothing + +; + +Proc PEFunction_ToggleTrace Far + Assume DS:Pattern + + Mov SI, Offset NoTraceMsg + Xor TracePlayback, 1 + JZ PEFunction_ToggleTrace1 + + Mov SI, Offset TraceMsg + +PEFunction_ToggleTrace1: + Call SetInfoLine + + Mov AL, TracePlayback + Call K_SetScrollLock + + Mov AX, 1 + Ret + +EndP PEFunction_ToggleTrace + Assume DS:Nothing + +; + +Proc PE_GetPatternConfigOffset Far + + Push CS + Pop DS + + Mov DX, Offset KeySignature + + Ret + +EndP PE_GetPatternConfigOffset + +; + +Proc ReleaseUndoMemory + + Test AX, AX + JZ ReleaseUndoMemoryEnd + + Push AX + And AH, 0F0h + Cmp AH, 0A0h + Pop AX + JE ReleaseUndoMemoryEMS + +ReleaseUndoMemoryConventional: + Push ES + + Mov ES, AX + Mov AH, 49h + Int 21h + + Pop ES + Ret + +ReleaseUndoMemoryEMS: + And AX, 0FFFh + Call E_ReleaseEMS + +ReleaseUndoMemoryEnd: + Ret + +EndP ReleaseUndoMemory + +; + +Proc PE_AddToUndoBuffer Far ; 1) Release oldest data. + ; 2) Shift all stuff down. + ; 3) Store newest data. + + ; Parameter: DI = buffer TYPE. + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Pattern + + Mov AX, DI + Cmp AL, 22 + JE PE_NotModified + + Mov Word Ptr [Modified], 101h + +PE_NotModified: + ; Error maintenance... sorta + Push CS + Push Offset PE_AddToUndoBufferEnd + Push AX ; Just for stack alignment + + Call GetPatternLength ; Get's pattern length in DX + + Add SP, 6 + ; For GetPatternLength's error stuff.. + + Add DX, 8 + JNC PE_AddToUndoBuffer3 + + Mov DI, Offset O1_PatternTooLongList + Mov CX, 2 + Call M_Object1List + Jmp PE_AddToUndoBufferEnd + +PE_AddToUndoBuffer3: +; ClC ; Carry already not set to get here - for + ; Non essential EMS allocation + MovZX EAX, DX + Call E_AllocateEMS + Test AX, AX + JZ PE_AddToUndoBuffer1 ; No EMS allocated? + + Call E_MapAvailableEMSMemory + + Or AH, 0A0h ; EMS tag + Push AX + Call E_GetEMSPageFrame + Push AX + Jmp PE_AddToUndoBuffer4 + +PE_AddToUndoBuffer1: + Mov BX, DX ; BX = length of pattern. + Add BX, 15 + RCR BX, 1 + ShR BX, 3 + + Mov AH, 48h + Int 21h + JC PE_AddToUndoBufferEnd + + Push AX ; Handle + Push AX ; Memory region + +PE_AddToUndoBuffer4: + Mov SI, Offset UndoBuffer+36 + Mov AX, [SI] + Call ReleaseUndoMemory + + Mov CX, 9 + +PE_AddToUndoBuffer2: + Mov EAX, [SI-4] + Mov [SI], EAX + + Sub SI, 4 + Loop PE_AddToUndoBuffer2 + + Pop ES + Pop AX + + Mov [SI], AX + Mov [SI+2], DI + + Sub DX, 8 + Xor DI, DI ; ES:DI points to data, DX = length + + Call EncodePattern + +PE_AddToUndoBufferEnd: + Pop ES + Pop DS + PopA + + Ret + +EndP PE_AddToUndoBuffer + Assume DS:Nothing + +; + +Proc PE_ClearUndoBuffer Far + + Push EAX + Push CX + Push DS + Push SI + + Push CS + Pop DS + Assume DS:Pattern + + Mov CX, 10 + Mov SI, Offset UndoBuffer + +PE_ClearUndoBuffer1: + Mov AX, [SI] + Call ReleaseUndoMemory + + Xor EAX, EAX + Mov [SI], EAX + + Add SI, 4 + + Loop PE_ClearUndoBuffer1 + + Pop SI + Pop DS + Pop CX + Pop EAX + + Ret + +EndP PE_ClearUndoBuffer + Assume DS:Nothing + +; + +Proc PEFunction_Undo Far + + Mov SelectUndo, 0 + + Mov DI, Offset O1_UndoList + Mov CX, 3 + Call M_Object1List + + Mov AX, 1 + Ret + +EndP PEFunction_Undo + +; + +Proc PEFunction_DrawUndo Far + + Assume DS:Pattern + Push CS + Pop DS + + Call S_GetDestination + Mov CX, 10 + Mov DI, (21+24*80)*2 + Mov BX, Offset UndoBuffer+2 + +PEFunction_DrawUndo1: + Push DI + + Mov SI, [BX] + Mov AX, SI + And SI, 0FFh + Add SI, SI + + MovZX AX, AH + + Push AX + Mov SI, [UndoBufferTypes+SI] + Mov AH, 2 + Call S_DrawString + Pop AX + + Add BX, 4 + Pop DI + Add DI, 160 + Loop PEFunction_DrawUndo1 + + Ret + +EndP PEFunction_DrawUndo + Assume DS:Nothing + +; + +Proc PEFunction_PreUndo Far + + Push CS + Pop DS + Assume DS:Pattern + + Call S_GetDestination + Mov AX, 160 + Mul SelectUndo + Add AX, (20+24*80)*2+1 + Mov DI, AX + + Mov CX, 40 + Mov AL, 30h + +PEFunction_PreUndo1: + StosB + Inc DI + Loop PEFunction_PreUndo1 + + Ret + +EndP PEFunction_PreUndo + Assume DS:Nothing + +; + +Proc PEFunction_PostUndo Far + + Push CS + Pop DS + Assume DS:Pattern + + Mov BX, SelectUndo + + Cmp CX, 1C8h + JE PEFunction_PostUndoUp + + Cmp CX, 1D0h + JE PEFunction_PostUndoDown + + Cmp CX, 11Ch ; Enter + JE PEFunction_PostUndoEnter + + Xor AX, AX + Ret + +PEFunction_PostUndoUp: + Sub BL, 1 + AdC BL, 0 + Jmp PEFunction_PostUndoShift + +PEFunction_PostUndoDown: + Cmp BX, 8 + JA PEFunction_PostUndoShift + + Inc BX + +PEFunction_PostUndoShift: + Mov SelectUndo, BX + + Mov AX, 1 + Ret + +PEFunction_PostUndoEnter: + ShL BX, 2 + Add BX, Offset UndoBuffer + + Mov CX, [BX+2] + JCXZ PEFunction_PostUndoEnd + + Push Word Ptr [BX] + + Mov DI, 21 + Call PE_AddToUndoBuffer + + Pop AX + Mov CH, AH + And CH, 0F0h + Cmp CH, 0A0h + JNE PEFunction_PostUndoEnterEnd + +PEFunction_PostUndoEMS: + And AX, 0FFFh + Call E_MapAvailableEMSMemory + Call E_GetEMSPageFrame + +PEFunction_PostUndoEnterEnd: + Mov DS, AX + Assume DS:Nothing + Xor SI, SI + Call DecodePattern + + Xor BX, BX + Mov CL, 64 + Mov CH, Byte Ptr [CS:MaxRow] + Inc CH + Call NetworkPatternBlock + +PEFunction_PostUndoEnd: + Mov AX, 4 + Ret + +EndP PEFunction_PostUndo + +; + +Proc ToggleFastVolume Far + Assume DS:Pattern + + Mov SI, Offset NoFastVolumeMsg + Xor CentraliseCursor, 4 + Test CentraliseCursor, 4 + JZ ToggleFastVolume3 + + Push DS + + Mov DI, Offset O1_GetFastAmpList + Mov CX, 3 + Call M_Object1List + + Pop DS + + Cmp DX, 1 + JNE ToggleFastVolume2 + + Mov SI, Offset FastVolumeMsg + Jmp ToggleFastVolume3 + +ToggleFastVolume2: + And CentraliseCursor, Not 4 + Mov SI, Offset FastVolumeNotEnabledMsg + +ToggleFastVolume3: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP ToggleFastVolume + Assume DS:Nothing + +; + +Proc PECheckModified Far + + Cmp CS:Modified, 0 + JE PECheckModified1 + + Mov CX, 4 + Mov DI, Offset O1_ConfirmNoSave + Call M_Object1List + + And DX, DX + JNZ PECheckModified1 + + Add SP, 4 + + Mov AX, 1 + +PECheckModified1: + Ret + +EndP PECheckModified + +; + +Proc PEResetModified Far + + Mov CS:Modified, 0 + + Ret + +EndP PEResetModified + +; + +Proc PE_SetPatternLength Far + Assume DS:Pattern + +; Mov AX, MaxRow +; Inc AX +; Mov PatternSetLength, AX + Mov AX, PatternNumber + Mov PatternLengthStart, AX + Mov PatternLengthEnd, AX + + Assume DS:Nothing + + Mov CX, 4 + Mov DI, Offset O1_SetPatternLength + Call M_Object1List + + Test DX, DX + JZ PE_SetPatternLength2 + + Push CS + Pop DS + Assume DS:Pattern + + Call PEFunction_StorePattern + + Mov AX, PatternNumber + Mov TempVariableArea, AX + + Mov AX, PatternLengthStart + Mov TempVariableArea2, AX + +PE_SetPatternLength3: + Mov AX, TempVariableArea2 + Cmp AX, PatternLengthEnd + JA PE_SetPatternLength4 + + Mov PatternNumber, AX + Assume DS:Nothing + + Call Music_GetPattern + Call DecodePattern ; Next pattern should be in mem + + Push CS + Pop DS + Assume DS:Pattern + + Mov AX, PatternSetLength + Mov PatternModified, 1 + Dec AX + Mov MaxRow, AX + Call PEFunction_StorePattern + + Inc TempVariableArea2 + Jmp PE_SetPatternLength3 + +PE_SetPatternLength4: ; Cleanup + Mov AX, TempVariableArea + Mov PatternNumber, AX + Call Music_GetPattern + Call DecodePattern + +PE_SetPatternLength2: + Mov AX, 1 + Ret + +EndP PE_SetPatternLength + Assume DS:Nothing + +; + +Proc PE_LeftBrace Far + + Jmp Glbl_LeftBrace + +EndP PE_LeftBrace + +; + +Proc PE_RightBrace Far + + Jmp Glbl_RightBrace + +EndP PE_RightBrace + +; + +Proc PE_LeftSquareBracket Far + + Jmp Glbl_LeftSquareBracket + +EndP PE_LeftSquareBracket + +; + +Proc PE_RightSquareBracket Far + + Jmp Glbl_RightSquareBracket + +EndP PE_RightSquareBracket + +; + +Proc MIDI_SetInstrument Far + + Test Byte Ptr CS:CentraliseCursor, 16 + JZ MIDI_SetInstrument2 + + Inc DX + +MIDI_SetInstrument2: + Cmp DX, 99 + JA MIDI_SetInstrument1 + + Mov CS:LastInstrument, DL + + Test DL, DL + JZ MIDI_SetInstrument1 + + Call UpdateWAVEForm + +MIDI_SetInstrument1: + Mov AX, 1 + Ret + +EndP MIDI_SetInstrument + +; + +Proc PE_MIDIAfterTouch Far + Assume DS:Pattern + + Cmp MIDIInputEnabled, 0 + JNE PE_MIDIAfterTouch2 + + Xor AX, AX + Ret + +PE_MIDIAfterTouch2: + Test CentraliseCursor, 128 + + MovZX BX, DL + Call MIDI_GetChannel + ; Returns AX + Sub AL, 1 + JC PE_MIDIAfterTouch1 +; Cmp AL, 0FFh +; JE PE_MIDIAfterTouch1 + + Call PE_TranslateMIDI + ; DL = note, DH = volume + + Mov AH, 5 + Mul AL + Mov SI, AX + Mov BL, DH + Mov AX, 320 + Mul Row + Mov Word Ptr [Modified], 101h + Add SI, AX + Mov DS, PatternDataArea + Assume DS:Nothing + Cmp SI, 64000 + JAE PE_MIDIAfterTouch1 + + Mov [SI+2], BL + +PE_MIDIAfterTouch1: + Mov AX, 1 + Ret + +EndP PE_MIDIAfterTouch + Assume DS:Nothing + +; + +Proc PE_MIDINoteOff Far + Assume DS:Pattern + + Cmp MIDIInputEnabled, 0 + JNE PE_MIDINoteOff1 + + Xor AX, AX + Ret + +PE_MIDINoteOff1: + MovSX BX, DL + Call MIDI_FindChannel ; Returns AX + Cmp AL, 0FFh + JE PE_MIDINoteOff2 + + Test CentraliseCursor, 32 + JZ PE_MIDINoteOff2 ; Dont' record note-offs + + Cmp TracePlayback, 0 + JE PE_MIDINoteOff2 + + Push AX + Mov AX, Row + Call Music_GetDelay ; DX = delay value + ; CX = playmode + Pop AX + + Test CX, CX + JZ PE_MIDINoteOff2 + + Push DX + Push AX + + Mov AH, 5 + Mul AH + Mov SI, AX + Mov AX, 320 + Mul Row + Add SI, AX + Cmp SI, 64000 + JAE PE_MIDINoteOff3 + + Mov DS, PatternDataArea + Assume DS:Nothing + + Cmp Word Ptr [SI], NONOTE + JE PE_MIDINoteOff4 + ; check next spot. + Mov AX, Row + Cmp AX, MaxRow + JAE PE_MIDINoteOff3 ; Already at end of pattern + + Add SI, 320 ; Try very next spot. + Cmp SI, 64000 + JAE PE_MIDINoteOff3 + + Xor DX, DX ; Tick 0 + Cmp Word Ptr [SI], NONOTE + JNE PE_MIDINoteOff3 + +PE_MIDINoteOff4: + Mov BX, 0FFh + + Mov [SI+2], BX + Mov [SI+4], BH + Test [CS:Flags], 2 + JZ PE_MIDINoteOffCut + + Dec BX + +PE_MIDINoteOffCut: + Mov [SI], BX + + Mov Word Ptr [CS:Modified], 101h + + Pop AX + Mov DL, 32 + Call Music_PlayNote + Pop DX + + Test CS:CentraliseCursor, 8 + JZ PE_MIDINoteOff2 + + Mov [SI+3], DX + +PE_MIDINoteOff2: + Mov AX, 1 + Ret + +PE_MIDINoteOff3: + Pop AX + Pop AX + Mov AX, 1 + Ret + +EndP PE_MIDINoteOff + Assume DS:Nothing + +; + +Proc PE_MIDINote Far + Assume DS:Pattern + + Cmp MIDIInputEnabled, 0 + JNE PE_MIDINote6 + + Xor AX, AX + Ret + +PE_MIDINote6: + Push DX + Call Music_GetLastChannel + Mov DI, AX + Pop DX + + Call PE_TranslateMIDI + JC PE_MIDINote1 ; Note out of range? + JZ PE_MIDINoteOff1 ; Note off? + + Mov BL, DH + Test CentraliseCursor, 64 + JNZ PE_MIDINote3 + + Mov BL, LastVolume + Test EditMask, 2 + JNZ PE_MIDINote3 + + Mov BL, 0FFh + +PE_MIDINote3: + ; If TracePlayback = 1 *AND* Playmode > 1, then + ; Basechannel = MIDIChannel, else + ; Basechannel = Channel + Push DX + + Mov AX, Row + Call Music_GetDelay ; CX = playmode + ; DX = delay value + PushA + + Cmp MIDIPlayTrigger, 1 + JB PE_MIDINoteTriggerEnd + JA MIDIPlayTriggerSong + +MIDIPlayTriggerPattern: + Mov Row, 0 + + Call Glbl_F6 + Jmp PE_MIDINoteTriggerCleanup + +MIDIPlayTriggerSong: + + Call PE_F7 + +PE_MIDINoteTriggerCleanup: + Push CS + Pop DS + + Mov AX, Channel + Mov MIDIChannel, AX + + Mov TracePlayback, 1 + Mov MIDIPlayTrigger, 0 + +PE_MIDINoteTriggerEnd: + PopA + + Mov AX, Channel + Test CX, CX + JZ PE_MIDINote2 + + Cmp TracePlayback, 0 + JE PE_MIDINote2 + + Mov AX, MIDIChannel + +PE_MIDINote2: + Pop CX ; CX = note/volume + Xor CH, CH + Test EditMask, 1 + JZ PE_MIDINote4 + + Mov CH, LastInstrument + +PE_MIDINote4: + + XChg CX, DX + ; CX = delay + ; DX = note/ins + + Push DX + Call PE_RestoreMIDINote + Call MIDI_AllocateChannel ; Returns AX = channel to use + Pop DX + + XChg CX, DX + + Push DX + Push AX + + Inc AX + Cmp AX, 63 + JA PE_MIDINote5 + + Mov MIDIChannel, AX +PE_MIDINote5: + Dec AX + + Mov AH, 5 + Mul AH + Mov SI, AX + Mov AX, 320 + Mul Row + Add SI, AX + + Pop AX + Cmp SI, 64000 + JAE PE_MIDINote1 + + Mov DS, PatternDataArea + Assume DS:Nothing + + Mov [SI], CX + Mov [SI+2], BL + Mov Word Ptr [SI+3], 0 + + Mov DH, 32 + Call Music_PlayNote + Pop DX + + Mov Word Ptr [CS:Modified], 101h + + Test CS:CentraliseCursor, 8 + JZ PE_MIDINote1 + + Mov [SI+3], DX + +PE_MIDINote1: + Mov AX, 1 + Ret + +EndP PE_MIDINote + Assume DS:Nothing + +; + +Proc PE_TranslateMIDI Far + ; Given DL = 0->127, return DL = 0->127 + ; Given DH = 0->127, return DH=0->64 + + ; Apply note swing. Return carry + ; if note out of range. + + ; Apply volume swing. Return zero + ; flag set if note off. + Push AX + + Test DH, DH + JZ PE_TranslateMIDIVolumeEnd + + MovSX BX, DL + MovSX AX, CS:MIDICentralNote + Add AX, BX + Sub AX, 60 + JS PE_TranslateMIDIError1 + +PE_TranslateMIDIPitch1: + Cmp AX, 119 + JBE PE_TranslateMIDIPitch2 + +PE_TranslateMIDIError1: + StC + Pop AX + Ret + +PE_TranslateMIDIPitch2: + Mov DL, AL + ; OK.. pitch done. + Mov AL, DH + Mul CS:MIDIAmplification + ; AX = (Volume*VolumeAmp) + ; = 0->127*200 + ; = 0->25400 + ; Req AX = 0->128 + ; ie. Div AX 198.4 + ; or Mul AX, 331 + ; >> 16 + + Mov BL, DL ; Note + Mov DX, 331 + Mul DX + Mov DH, DL + Mov DL, BL + Cmp DH, 64 + JB PS_TranslateMIDIVolume1 + + Mov DH, 64 + +PS_TranslateMIDIVolume1: + Test DL, DL ; Clear zero flag + carry. + +PE_TranslateMIDIVolumeEnd: + Pop AX + Ret + +EndP PE_TranslateMIDI + +; + +Proc PE_RestoreMIDINote Far + + Add DL, 60 + Sub DL, CS:MIDICentralNote + + Ret + +EndP PE_RestoreMIDINote + +; + +Proc PE_CycleMIDIPlayTrigger Far + Assume DS:Pattern + + Mov AL, MIDIPlayTrigger + Inc AX + Cmp AL, 2 + JBE PE_CycleMIDIPlayTrigger1 + + Xor AL, AL + Mov SI, Offset TriggerMsg1 + Jmp PE_CycleMIDIPlayTriggerEnd + +PE_CycleMIDIPlayTrigger1: + Mov SI, Offset TriggerMsg2 + Cmp AL, 1 + JE PE_CycleMIDIPlayTriggerEnd + + Mov SI, Offset TriggerMsg3 + +PE_CycleMIDIPlayTriggerEnd: + Mov MIDIPlayTrigger, AL + + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP PE_CycleMIDIPlayTrigger + Assume DS:Nothing + +; + +Proc MIDIInputToggle Far ; Ctrl-Scroll Lock + Assume DS:Pattern + + Mov SI, Offset MIDIInputEnabledMsg + Xor MIDIInputEnabled, 1 + JNZ MIDIInputToggle1 + Mov SI, Offset MIDIInputDisabledMsg + +MIDIInputToggle1: + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP MIDIInputToggle + Assume DS:Nothing + +; + +Proc PE_SetPatternModified Far + + Mov Word Ptr [CS:Modified], 101h + Ret + +EndP PE_SetPatternModified + +; + +Proc PE_SaveCurrentPattern Far + + PushAD + Push DS + Push ES + + Call PEFunction_StoreCurrentPattern + + Mov AX, 0FFFFh + XChg AX, CS:PatternNumber + Mov Word Ptr CS:TempNumbers, AX + + Call Music_UpdatePatternOffset + + Pop ES + Pop DS + PopAD + Ret + +EndP PE_SaveCurrentPattern + +; + +Proc PE_RestoreCurrentPattern Far + + PushAD + Push DS + Push ES + Mov AX, Word Ptr CS:TempNumbers + Mov CS:PatternNumber, AX + Call Music_GetPattern + Call DecodePattern + Pop ES + Pop DS + PopAD + Ret + +EndP PE_RestoreCurrentPattern + +; + +Proc PE_NewPattern Far + + Mov AX, CS:PatternNumber + Call Music_GetPattern + Call DecodePattern + + Mov CS:PatternModified, 0 + Ret + +EndP PE_NewPattern + +; + +EndS + +; + +Segment PatternData PARA Public 'Data' + DB 64000 Dup (?) +EndS + + +; + +End diff --git a/it/IT_PE_V.INC b/it/IT_PE_V.INC new file mode 100644 index 0000000..b021381 --- /dev/null +++ b/it/IT_PE_V.INC @@ -0,0 +1,140 @@ +; +; Pattern edit view functions +; + +; + +Proc Draw_3Note Near ; Given AL = note. + + Cmp AL, NONOTE + JB Draw_3Note2 + + Mov CL, AL + Mov AL, 173 ; '.' + JE Draw_3Note1 + + Mov AL, '^' + Cmp CL, 0FEh + JE Draw_3Note1 + + Mov AL, '' + Cmp CL, 0FFh + JE Draw_3Note1 + + Mov AL, '!' + +Draw_3Note1: + Mov AH, CH + StosW + StosW + StosW + + Ret + +Draw_3Note2: + Push SI + + AAM 12 ; AH = octave, AL = note + Mov CL, AH + And AX, 0FFh + LEA SI, [EBX+EAX*2] + + Mov AH, CH + SegCS LodsB + StosW + SegCS LodsB + StosW + Mov AL, CL + Add AL, 30h + StosW + + Pop SI + + Ret + +EndP Draw_3Note + +; + +Proc Draw_2Note Near ; Given AL = note. + + Cmp AL, NONOTE + JB Draw_2Note2 + + Mov DL, AL + Mov AL, 173 ; '.' + JE Draw_2Note1 + + Mov AL, '^' + Cmp DL, 0FEh + JE Draw_2Note1 + + Mov AL, '' + Cmp DL, 0FFh + JE Draw_2Note1 + + Mov AL, '!' + +Draw_2Note1: + Mov AH, CH + StosW + StosW + + Ret + +Draw_2Note2: + Push SI + + AAM 12 ; AH = octave, AL = note + Mov CL, AH + And AX, 0FFh + LEA SI, [EBX+EAX*2] + + SegCS LodsW + Cmp AH, '-' + JNE Draw_2Note3 + + Add AL, 'a'-'A' + +Draw_2Note3: + Mov AH, CH + StosW + Mov AL, CL + Add AL, 30h + StosW + + Pop SI + + Ret + +EndP Draw_2Note + +; + +Proc Draw_2Instrument + + Test AL, AL + JNZ Draw_2Instrument1 + + Mov AL, 173 ; '.' + Mov AH, CH + + StosW + StosW + Ret + +Draw_2Instrument1: + AAM 10 + Add AX, '00' + + Mov CL, AL + Mov AL, AH + Mov AH, CH + StosW + Mov AL, CL + StosW + + Ret + +EndP Draw_2Instrument + diff --git a/it/IT_S.ASM b/it/IT_S.ASM new file mode 100644 index 0000000..a0b9de7 --- /dev/null +++ b/it/IT_S.ASM @@ -0,0 +1,1685 @@ +;Ŀ +; Screen Module +; + +include switch.inc + + Jumps + .386 + +Segment Mouse BYTE Public 'Code' + Extrn MouseCharacterGenerationOffset:Word +EndS + + Extrn E_UnInitEMS:Far + Extrn DrawMouse:Far, RestoreMouse:Far, ForceMouseRestore:Far + Extrn RestoreMouseGraphics:Far, NewCharacterSet:Far + Extrn MouseSecondSetEnable:Far, MouseSecondSetDisable:Far + Extrn MouseUpdateEnable:Far, MouseUpdateDisable:Far + +;Ŀ +; Globals +; + + Global S_InitScreen:Far + Global S_SetPalette:Far + Global S_UnInitScreen:Far + Global S_DrawBox:Far + Global S_UpdateScreen:Far + Global S_OverrideVGADetection:Far + Global S_SetDirectMode:Far + Global S_DrawString:Far + Global S_DirectDrawString:Far + Global S_HiLight:Far + Global S_ClearScreen:Far + Global S_GetDestination:Far + Global S_GetGenerationTableOffset:Far + Global S_GenerateCharacters:Far + Global S_SaveScreen:Far + Global S_RestoreScreen:Far + Global S_DefineSmallNumbers:Far + Global S_DefineHiASCII:Far + Global S_DrawSmallBox:Far + Global S_GetPaletteOffset:Far + Global S_SetPalette2:Far + Global S_UsePresetPalette:Far + Global S_InvertCursor:Far + + Global S_SetSequencer:Far, S_ResetSequencer:Far + + Global CharacterGenerationOffset:Word + + Public PaletteDefs + Public S_RedefineCharacters + Public VGAFlags + +; + +Segment Screen BYTE Public 'Code' USE16 + Assume CS:Screen, DS:Screen + +CREATENEWLOGFILE EQU 0 +include debug.inc + +;Ŀ +; Variables +; + +STORESCREENADDRESS EQU 0BA00h + +NoVGAMsg DB "Sorry, this program requires VGA", 13, 10 + DB "$" + +ScreenDataArea DW ScreenData + +PaletteDefs Label Byte + ; Default to camouflage + DB 0, 0, 0, 31, 22, 17, 45, 37, 30, 58, 58, 50 + DB 44, 0, 21, 63, 63, 21, 17, 38, 18, 19, 3, 6 + DB 8, 21, 0, 6, 29, 11, 14, 39, 29, 55, 58, 56 + DB 40, 40, 40, 35, 5, 21, 22, 16, 15, 13, 12, 11 + +PresetPalettes Label Byte + ; Light Blue palette + DB 0, 0, 0, 10, 25, 45, 30, 40, 55, 51, 58, 63 + DB 63, 21, 21, 21, 63, 21, 44, 44, 44, 22, 22, 22 + DB 0, 0, 32, 0, 0, 42, 30, 40, 55, 51, 58, 63 + DB 44, 44, 44, 21, 63, 21, 18, 16, 15, 12, 11, 10 ; Greyish brown + + ; Gold + DB 0, 0, 0, 20, 17, 10, 41, 36, 21, 63, 55, 33 + DB 63, 21, 21, 18, 53, 18, 38, 37, 36, 22, 22, 22 + DB 0, 0, 32, 0, 0, 42, 41, 36, 21, 48, 49, 46 + DB 44, 44, 44, 21, 50, 21, 18, 16, 15, 12, 11, 10 + + ; Camouflage / Jari Karppinen + DB 0, 0, 0, 31, 22, 17, 45, 37, 30, 58, 58, 50 + DB 44, 0, 21, 63, 63, 21, 17, 38, 18, 19, 3, 6 + DB 8, 21, 0, 6, 29, 11, 14, 39, 29, 55, 58, 56 + DB 40, 40, 40, 35, 5, 21, 22, 16, 15, 13, 12, 11 + + ; Midnight Tracking palette + DB 0, 0, 0, 0, 8, 16, 0, 19, 32, 16, 28, 48 + DB 63, 21, 21, 0, 48, 36, 32, 32, 32, 22, 22, 22 + DB 0, 0, 24, 0, 0, 32, 0, 18, 32, 40, 40, 40 + DB 32, 32, 32, 28, 0, 24, 4, 13, 20, 6, 7, 11 + + Comment ~ + ; Cool Hot Colours - Zoner / EPI / XLM + DB 11, 0, 18, 0, 0, 22, 42, 35, 33, 53, 45, 41 + DB 51, 0, 0, 34, 22, 35, 34, 33, 52, 22, 22, 22 + DB 26, 26, 32, 32, 32, 42, 41, 36, 21, 48, 49, 46 + DB 44, 44, 44, 21, 40, 21, 27, 16, 24, 21, 11, 19 + ~ + + ; Pine colours - Jari Karppinen + DB 0, 0, 0, 2, 16, 13, 21, 32, 29, 51, 58, 63 + DB 63, 34, 0, 52, 51, 33, 42, 41, 33, 31, 22, 22 + DB 12, 10, 16, 18, 0, 24, 30, 40, 55, 58, 58, 33 + DB 44, 44, 44, 49, 39, 21, 13, 15, 14, 14, 11, 14 + + ; Soundtracker - Chris Jarvis + DB 0, 0, 0, 18, 24, 28, 35, 42, 47, 51, 56, 60 + DB 63, 21, 21, 21, 63, 22, 0, 35, 63, 22, 22, 22 + DB 32, 13, 38, 37, 16, 62, 27, 40, 55, 51, 58, 63 + DB 44, 44, 44, 21, 63, 21, 18, 16, 17, 13, 14, 13 + + ; Volcanic + DB 0, 0, 0, 25, 9, 0, 40, 14, 0, 51, 23, 0 + DB 63, 8, 16, 0, 39, 5, 32, 32, 32, 0, 20, 20 + DB 21, 0, 0, 28, 0, 0, 32, 32, 32, 62, 31, 0 + DB 40, 40, 40, 0, 28, 38, 10, 16, 27, 8, 11, 19 + + Comment ~ + ; Atlantic - Delta X / NOiSE + DB 0, 0, 0, 2, 0, 30, 8, 18, 43, 21, 43, 63 + DB 63, 8, 16, 27, 32, 63, 0, 54, 63, 10, 15, 35 + DB 0, 0, 30, 0, 0, 36, 0, 18, 32, 40, 40, 40 + DB 18, 52, 63, 21, 50, 21, 10, 16, 27, 8, 11, 19 + ~ + ; Original Palette +; DB 0, 0, 0, 10, 25, 45, 30, 40, 55, 51, 58, 63 +; DB 63, 21, 21, 21, 63, 21, 44, 44, 44, 22, 22, 22 +; DB 0, 0, 32, 0, 0, 42, 30, 40, 55, 51, 58, 63 +; DB 44, 44, 44, 21, 63, 21, 18, 16, 15, 12, 11, 10 ; Greyish brown + +CharacterDefinitions Label Byte + DB 255, 128, 128, 128, 128, 128, 128, 128 ; 128 + DB 255, 0, 0, 0, 0, 0, 0, 0 ; 129 + DB 255, 1, 1, 1, 1, 1, 1, 1 ; 130 + DB 128, 128, 128, 128, 128, 128, 128, 128 ; 131 + DB 1, 1, 1, 1, 1, 1, 1, 1 ; 132 + DB 128, 128, 128, 128, 128, 128, 128, 255 ; 133 + DB 0, 0, 0, 0, 0, 0, 0, 255 ; 134 + DB 1, 1, 1, 1, 1, 1, 1, 255 ; 135 + DB 128, 0, 0, 0, 0, 0, 0, 0 ; 136 + DB 1, 0, 0, 0, 0, 0, 0, 0 ; 137 + DB 0, 0, 0, 0, 0, 0, 0, 128 ; 138 + DB 0, 0, 0, 0, 0, 0, 0, 1 ; 139 + DB 128, 192, 224, 240, 248, 252, 254,255 ; 140 + DB 255, 127, 63, 31, 15, 7, 3, 1 ; 141 + DB 255, 255, 192, 192, 192, 192, 192, 192 ; 142 + DB 255, 255, 0, 0, 0, 0, 0, 0 ; 143 + DB 255, 255, 3, 3, 3, 3, 3, 3 ; 144 + DB 192, 192, 192, 192, 192, 192, 192, 192 ; 145 + DB 3, 3, 3, 3, 3, 3, 3, 3 ; 146 + DB 192, 192, 192, 192, 192, 192, 255, 255 ; 147 + DB 0, 0, 0, 0, 0, 0, 255, 255 ; 148 + DB 3, 3, 3, 3, 3, 3, 255, 255 ; 149 + DB 192, 192, 0, 0, 0, 0, 0, 0 ; 150 + DB 3, 3, 0, 0, 0, 0, 0, 0 ; 151 + DB 0, 0, 0, 0, 0, 0, 192, 192 ; 152 + DB 0, 0, 0, 0, 0, 0, 3, 3 ; 153 + DB 0, 0, 0, 85, 0, 0, 0, 0 ; 154 +; DB 251, 155, 138, 138, 138, 138, 155, 251 ; 155 +; DB 239, 40, 41, 41, 41, 41, 40, 239 ; 156 +; DB 255, 0, 157, 85, 85, 157, 0, 255 ; 157 +; DB 255, 0, 29, 29, 20, 220, 0, 255 ; 158 +; DB 255, 0, 65, 67, 129, 131, 0, 255 ; 159 +; DB 255, 0, 171, 42, 171, 58, 0, 255 ; 160 +; DB 255, 0, 51, 170, 50, 171, 0, 255 ; 161 +; DB 255, 0, 170, 171, 171, 170, 0, 255 ; 162 +; DB 255, 1, 177, 169, 169, 177, 1, 255 ; 163 + + DB 0, 252, 252, 252, 252, 252, 252, 0 ; 155 + DB 0, 126, 126, 126, 126, 126, 126, 0 ; 156 + DB 0, 63, 63, 63, 63, 63, 63, 0 ; 157 + DB 0, 31, 31, 31, 31, 31, 31, 0 ; 158 + DB 0, 15, 15, 15, 15, 15, 15, 0 ; 159 + DB 0, 7, 7, 7, 7, 7, 7, 0 ; 160 + DB 0, 3, 3, 3, 3, 3, 3, 0 ; 161 + DB 0, 1, 1, 1, 1, 1, 1, 0 ; 162 + DB 0, 128, 128, 128, 128, 128, 128, 0 ; 163 + DB 0, 192, 192, 192, 192, 192, 192, 0 ; 164 + DB 0, 224, 224, 224, 224, 224, 224, 0 ; 165 + DB 0, 240, 240, 240, 240, 240, 240, 0 ; 166 + DB 0, 248, 248, 248, 248, 248, 248, 0 ; 167 + DB 126, 126, 126, 126, 126, 126, 126, 126 ; 168 + DB 255, 255, 0, 24, 60, 126, 255, 0 ; 169 + DB 255, 255, 0, 0, 0, 0, 24, 24 ; 170 + DB 255, 255, 0, 24, 60, 126, 255, 24 ; 171 + DB 255, 255, 0, 66, 102, 90, 66, 66 ; 172 + DB 0, 0, 0, 24, 24, 0, 0, 0 ; 173 + DB 0, 192, 192, 192, 192, 192, 192, 192 ; 174 + DB 0, 216, 216, 216, 216, 216, 216, 216 ; 175 + DB 0, 219, 219, 219, 219, 219, 219, 219 ; 176 + DB 0, 96, 96, 96, 96, 96, 96, 96 ; 177 + DB 0, 108, 108, 108, 108, 108, 108, 108 ; 178 + DB 0, 109, 109, 109, 109, 109, 109, 109 ; 179 + DB 0, 128, 128, 128, 128, 128, 128, 128 ; 180 + DB 0, 176, 176, 176, 176, 176, 176, 176 ; 181 + DB 0, 182, 182, 182, 182, 182, 182, 182 ; 182 + DB 0, 0, 24, 60, 60, 24, 0, 0 ; 183 + DB 0, 0, 0, 66h, 0, 0, 0, 0 ; 184 + DB 0, 1Eh, 21h, 40h, 0, 0, 0, 0 ; 185Sine + DB 0, 0, 0, 82h, 44h, 38h, 0, 0 ; 186 + DB 0, 3Eh, 22h, 22h, 22h, 22h, 63h, 0 ; 187Square + DB 0, 3Eh, 22h, 22h, 22h, 22h, 0E3h, 0 ; 188 + DB 0, 30h, 2Ch, 23h, 20h, 20h, 20h, 0 ; 189RampDown + DB 0, 4, 4, 4, 0C4h, 34h, 0Ch, 0 ; 190 + DB 0, 6, 4, 4, 4, 4, 6, 0 ; 191, Left bracket + DB 0, 0C0h, 40h, 40h, 40h, 40h, 0C0h, 0 ; 192, Right bracket + DB 0, 0, 0, 18h, 18h, 0, 0, 0 ; 193, Notedots + DB 0, 0, 18h, 3Ch, 3Ch, 18h, 0, 0 ; 194 + DB 0, 0, 18h, 3Ch, 3Ch, 18h, 0, 0 ; 195 + DB 0, 0, 3Ch, 3Ch, 3Ch, 3Ch, 0, 0 ; 196 + DB 0, 0, 3Ch, 3Ch, 3Ch, 3Ch, 0, 0 ; 197 + DB 0, 18h, 3Ch, 7Eh, 7Eh, 3Ch, 18h, 0 ; 198 + DB 0, 18h, 3Ch, 7Eh, 7Eh, 3Ch, 18h, 0 ; 199 + DB 0, 3Ch, 7Eh, 7Eh, 7Eh, 7Eh, 3Ch, 0 ; 200 + DB 0, 3Ch, 7Eh, 7Eh, 7Eh, 7Eh, 3Ch, 0 ; 201, end note dots + + Comment & + ; Volume bars + DB 0, 0, 0, 0, 0, 0, 0, 254 + DB 0, 0, 0, 0, 0, 254, 0, 254 + DB 0, 0, 0, 254, 0, 254, 0, 254 + DB 0, 254, 0, 254, 0, 254, 0, 254 + + Comment & + +EndCharacterDefinitions Label Byte + +HexNumeralDefinitions Label Byte + DB 4, 10, 10, 10, 10, 10, 4 ; '0' + DB 0, 4, 12, 4, 4, 4, 4, 14 ; '1' + DB 0, 4, 10, 2, 4, 4, 8, 14 ; '2' + DB 0, 12, 2, 2, 4, 2, 2, 12 ; '3' + DB 0, 10, 10, 10, 14, 2, 2, 2 ; '4' + DB 0, 14, 8, 8, 12, 2, 2, 12 ; '5' + DB 0, 4, 10, 8, 12, 10, 10, 4 ; '6' + DB 0, 14, 2, 2, 2, 2, 2, 2 ; '7' + DB 0, 4, 10, 10, 4, 10, 10, 4 ; '8' + DB 0, 14, 10, 10, 14, 2, 2, 2 ; '9' + DB 0, 4, 10, 10, 14, 10, 10, 10 ; 'A' + DB 0, 12, 10, 10, 12, 10, 10, 12 ; 'B' + DB 0, 6, 8, 8, 8, 8, 8, 6 ; 'C' + DB 0, 12, 10, 10, 10, 10, 10, 12 ; 'D' + DB 0, 14, 8, 8, 12, 8, 8, 14 ; 'E' + DB 0, 14, 8, 8, 12, 8, 8, 8 ; 'F' + DB 0, 6, 8, 8, 10, 10, 10, 6 ; 'G' + DB 0, 10, 10, 10, 14, 10, 10, 10 ; 'H' + + +BoxDefinitions Label Byte + DB 128,21h,129,21h,130,21h,131,21h,32,23h,132,21h,133,21h,134,21h,135,21h + DB 128,23h,129,23h,130,23h,131,23h,32,23h,132,23h,133,23h,134,23h,135,23h + DB 142,21h,143,21h,144,21h,145,21h,32,23h,146,21h,147,21h,148,21h,149,21h + DB 142,23h,143,23h,144,23h,145,23h,32,23h,146,23h,147,23h,148,23h,149,23h + DB 128,23h,129,23h,129,23h,131,23h,32,23h, 32,23h,131,23h, 32,23h, 32,23h + DB 128,21h,129,21h,129,21h,131,21h,32,23h, 32,21h,131,21h, 32,21h, 32,21h + DB 142,23h,143,23h,143,23h,145,23h,32,23h, 32,23h,145,23h, 32,23h, 32,23h + DB 142,21h,143,21h,143,21h,145,21h,32,23h, 32,21h,145,21h, 32,21h, 32,21h + DB 139,23h,134,23h,138,21h,132,23h,32,23h,131,21h,137,21h,129,21h,136,21h + DB 139,21h,134,21h,138,23h,132,21h,32,23h,131,23h,137,23h,129,23h,136,23h + DB 153,23h,148,23h,152,21h,146,23h,32,23h,145,21h,151,21h,143,21h,150,21h + DB 153,21h,148,21h,152,23h,146,21h,32,23h,145,23h,151,23h,143,23h,150,23h ; 11 + DB 139,21h,134,21h,138,21h,132,21h,32, 3h,131,21h,137,21h,129,21h,136,21h + DB 139,23h,134,23h,138,23h,132,23h,32, 3h,131,23h,137,23h,129,23h,136,23h + DB 153,21h,148,21h,152,21h,146,21h,32, 3h,145,21h,151,21h,143,21h,150,21h + DB 153,23h,148,23h,152,23h,146,23h,32, 3h,145,23h,151,23h,143,23h,150,23h + DB 128,21h,129,21h,130,21h,131,21h,32, 3h,132,21h,133,21h,134,21h,135,21h + DB 128,23h,129,23h,130,23h,131,23h,32, 3h,132,23h,133,23h,134,23h,135,23h + DB 142,21h,143,21h,144,21h,145,21h,32, 3h,146,21h,147,21h,148,21h,149,21h + DB 142,23h,143,23h,144,23h,145,23h,32, 3h,146,23h,147,23h,148,23h,149,23h + DB 128,23h,129,23h,129,23h,131,23h,32, 3h, 32,23h,131,23h, 32,23h, 32,23h + DB 128,21h,129,21h,129,21h,131,21h,32, 3h, 32,21h,131,21h, 32,21h, 32,21h + DB 142,23h,143,23h,143,23h,145,23h,32, 3h, 32,23h,145,23h, 32,23h, 32,23h + DB 142,21h,143,21h,143,21h,145,21h,32, 3h, 32,21h,145,21h, 32,21h, 32,21h + DB 139,23h,134,23h,138,21h,132,23h,32, 3h,131,21h,137,21h,129,21h,136,21h + DB 139,21h,134,21h,138,23h,132,21h,32, 3h,131,23h,137,23h,129,23h,136,23h + DB 153,23h,148,23h,152,21h,146,23h,32, 3h,145,21h,151,21h,143,21h,150,21h + DB 153,21h,148,21h,152,21h,146,21h,32, 3h,145,23h,151,21h,143,23h,150,23h ; 27 + DB 128,23h,129,23h,141,21h,131,23h,32,23h,132,21h,140,21h,134,21h,135,21h + DB 128,21h,129,21h,141,21h,131,21h,32,23h,132,23h,140,21h,134,23h,135,23h +IF TUTORIAL + DB 128,13h,129,13h,130,13h,131,13h,32,13h,132,13h,133,13h,134,13h,135,13h +ENDIF + +CharacterGenerationOffset DW 512*32 +VGAFlags DB 0 ; Bit 0 = override VGA detection + ; Bit 1 = PreserveRetrace + ; Bit 2 = Wait for VRetrace +DirectVideo DB 0 +TestBytes DB 'CHARACTERTEST' + +;Ŀ +; Functions +; + +; InitScreen - Sets up buffer area for screen functions & character generation +; - Sets up 50 line mode +; - Sets up palette +; - Defines basic characters (128->163) +; - AX returns non-zero if error occurs + +Proc S_InitScreen Far + + Push DS + + Push CS + Pop DS + Assume DS:Screen + + Mov DirectVideo, 0 + + Test VGAFlags, 1 + JNZ S_InitScreen4 + + Trace " - VGA Detection" + +; Check for VGA + Mov AX, 1A00h + Int 10h + + Cmp BL, 8 + JGE S_InitScreen5 + + Mov DX, Offset NoVGAMsg + Mov AH, 9 + Int 21h + + Call E_UnInitEMS + + Mov AX, 4C01h ; Return to DOS with errorlevel + Int 21h + +S_InitScreen5: + Trace " - Matrox-error detection" + + Mov AX, 3 + Int 10h + + Mov AX, 1100h + Mov BX, 1001h + Mov CX, 1 + Xor DX, DX + Push CS + Pop ES + Mov BP, Offset TestBytes + Int 10h + + Call S_SetSequencer + + Push 0A000h + Pop ES + + Mov DI, 4000h + Mov SI, Offset TestBytes + + Mov CX, 4 + RepE CmpSD + JE S_InitScreen8 + + Mov CharacterGenerationOffset, 2000h + + Push Mouse + Pop FS + Assume FS:Mouse + + Mov FS:MouseCharacterGenerationOffset, 2000h + Assume FS:Nothing + +S_InitScreen8: + Call S_ResetSequencer + +S_InitScreen4: + Trace " - Screen Mode Setup" + + Call S_Set80x50Mode + + Trace " - Screen Palette Setup" + + Call S_SetPalette + + ; OK.. save all characters above 128 + + Trace " - Character Generation Setup" + + Call S_SetSequencer + + Mov AX, 0A000h + Mov DS, AX + Mov ES, AX + + Mov AX, 16 + Xor SI, SI + Mov DX, 256 + Mov DI, AX + +S_InitScreen6: + Mov CX, 4 + Rep MovsD + + Add SI, AX + Add DI, AX + + Dec DX + JNZ S_InitScreen6 + + Call S_ResetSequencer + + Push CS + Pop DS + + Mov SI, Offset CharacterDefinitions + Mov BX, (EndCharacterDefinitions-CharacterDefinitions+7) / 8 + Mov AX, 128 + Call S_RedefineCharacters + + Call S_UpdateScreen + + Pop DS + Ret + +EndP S_InitScreen + Assume DS:Nothing + +; + +Proc S_SaveScreen Far + + PushF + PushAD + Push DS + Push ES + + ClD + Push 0B800h + Push STORESCREENADDRESS + Pop ES + Pop DS + Xor SI, SI + Xor DI, DI + +IF USE32BITSCREENCOPY + Mov CX, 2000 + Rep MovsD +ELSE + Mov CX, 4000 + Rep MovsW +ENDIF + + Call ForceMouseRestore + + Pop ES + Pop DS + PopAD + PopF + + Ret + +EndP S_SaveScreen + +; + +Proc S_RestoreScreen Far + + PushF + PushAD + Push DS + Push ES + + ClD + + Call S_GetDestination + + Push STORESCREENADDRESS + Pop DS + Xor SI, SI + Xor DI, DI +IF USE32BITSCREENCOPY + Mov CX, 2000 + Rep MovsD +ELSE + Mov CX, 4000 + Rep MovsW +ENDIF + + Call ForceMouseRestore + + Pop ES + Pop DS + PopAD + PopF + + Call S_UpdateScreen + + Ret + +EndP S_RestoreScreen + +; + +Proc S_Set80x50Mode Far + + Push AX + Push DX + + Mov AX, 3 + Int 10h + + Mov AX, 1112h + Xor BX, BX + Int 10h + + Mov AH, 1 + Mov CH, 20h + Int 10h + + Mov AX, 1003h + Xor BX, BX + Int 10h + + Mov DX, 03C4h ; Character Map + Mov AX, 0403h + Out DX, AX + + Test CS:VGAFlags, 2 + JNZ S_Set80x50Mode1 + + Mov AX, 0101h + Out DX, AX + + Mov DX, 03C2h + Mov AL, 63h + Out DX, AL + + Mov DX, 03DAh + In AL, DX + + Mov DX, 03C0h + Mov AL, 13h + Out DX, AL + Xor AL, AL + Out DX, AL + Mov AL, 32h + Out DX, AL + +S_Set80x50Mode1: + Pop DX + Pop AX + + Ret + +EndP S_Set80x50Mode + +; + +Proc S_SetPalette2 Far + + PushA + Push DS + + Jmp SP3 + +EndP S_SetPalette2 + +; + +Proc S_SetPalette Far + + PushA + Push DS + + Mov CX, 16 + +SP1: + Mov AX, 1000h + Mov BL, CL + Dec BX + Mov BH, BL +; And BH, 7 + Int 10h + + Loop SP1 + +SP3: + Mov DX, 3C8h + Xor AL, AL + Out DX, AL + + Inc DX + + Mov CX, 16*3 + + Push CS + Pop DS + + Assume DS:Screen + Mov SI, Offset PaletteDefs + +SP2: + LodsB + Out DX, AL + Loop SP2 + + Pop DS + + Assume DS:Nothing + PopA + + Ret + +EndP S_SetPalette + +; + +SequencerSemaphore DB 0FFh + +Proc S_SetSequencer Far + + Inc [CS:SequencerSemaphore] + JNZ S_SetSequencer1 + + Push AX + Push DX + + Mov DX, 3C4h ; Sequencer + Mov AX, 704h + Out DX, AX + + Mov AX, 402h + Out DX, AX + + Mov DX, 3CEh ; Controller + Mov AX, 204h + Out DX, AX + Mov AX, 5 + Out DX, AX + Mov AX, 406h + Out DX, AX + + Pop DX + Pop AX + +S_SetSequencer1: + Ret + +EndP S_SetSequencer + +; + +Proc S_ResetSequencer Far + + Dec [CS:SequencerSemaphore] + JNS S_ResetSequencer1 + + Push AX + Push DX + + Mov DX, 3C4h ; Sequencer + Mov AX, 302h + Out DX, AX + Mov AX, 304h + Out DX, AX + + Mov DX, 3CEh ; Controller + Mov AX, 4 + Out DX, AX + Mov AX, 1005h + Out DX, AX + Mov AX, 0E06h + Out DX, AX + + Pop DX + Pop AX + +S_ResetSequencer1: + Ret + +EndP S_ResetSequencer + +; + +Proc S_RedefineCharacters Far + ; DS:SI = Offset to characterdefs + ; BX = Number of characters + ; AX = First character + Push CX + Push DS + Push SI + Push ES + Push DI + + Call MouseUpdateDisable + Call NewCharacterSet + + Mov DI, 0A000h + Mov ES, DI + + Mov DI, AX + Mov CL, 5 + ShL DI, CL + + Cmp AX, 256 + JB RedefineCharacters2 + + Sub DI, 256*32 + Add DI, CS:CharacterGenerationOffset + +RedefineCharacters2: + Call S_SetSequencer + +RedefineCharacters1: + Mov CX, 8 + Rep MovsB + + Add DI, (32-8) + Dec BX + JNZ RedefineCharacters1 + + Call S_ResetSequencer + Call MouseUpdateEnable + + Pop DI + Pop ES + Pop SI + Pop DS + Pop CX + + Ret + +EndP S_RedefineCharacters + +; + +Proc S_DefineSmallNumbers Far + + Push DS + Push SI + Push ES + Push DI + + Call MouseUpdateDisable + + Push CS + Pop DS + Mov DI, 0A000h + Mov ES, DI + + Call S_SetSequencer + + Xor DX, DX + Mov DI, CharacterGenerationOffset + +S_DefineSmallNumbers1: + Mov AL, DL + Mov AH, AL + And AX, 0FF0h + ShL AH, 4 + ShR AX, 1 + Mov BL, AH + Xor BH, BH + Mov SI, AX + And SI, 0FFh + Add BX, Offset HexNumeralDefinitions + Add SI, Offset HexNumeralDefinitions + + Mov CH, 8 + +S_DefineSmallNumbers2: + Mov AH, [BX] + Inc BX + LodsB + ShL AL, 4 + Or AL, AH + StosB + Dec CH + JNZ S_DefineSmallNumbers2 + + Inc DX + Add DI, 24 + Cmp DX, 256 + JB S_DefineSmallNumbers1 + + ; Have to define G0->G9,H0->H9 + Mov DH, 2 + Mov BX, Offset HexNumeralDefinitions+16*8 + Mov DI, 226*32 ; start at char 226. + +S_DefineSmallNumbers3: + Mov SI, Offset HexNumeralDefinitions + Mov DL, 10 + +S_DefineSmallNumbers4: + Push BX + + Mov CH, 8 + +S_DefineSmallNumbers5: + Mov AH, [BX] + ShL AH, 4 + Inc BX + LodsB + Or AL, AH + StosB + Dec CH + JNZ S_DefineSmallNumbers5 + + Pop BX + Add DI, 24 + + Dec DL + JNZ S_DefineSmallNumbers4 + + Add BX, 8 + + Dec DH + JNZ S_DefineSmallNumbers3 + + Call S_ResetSequencer + + Pop DI + Pop ES + Pop SI + Pop DS + + Call NewCharacterSet + Call MouseSecondSetDisable + Call MouseUpdateEnable + + Ret + +EndP S_DefineSmallNumbers + +; + +Proc S_UnInitScreen Far + + Push ES + + Mov AH, 49h + Mov ES, ScreenDataArea + Int 21h + + Pop ES + + Mov AX, 3 + Int 10h + + Ret + +EndP S_UnInitScreen + +; + +Proc S_GetDestination Far + + Mov ES, CS:ScreenDataArea + + Cmp CS:DirectVideo, 0 + JE S_GetDestination1 + + Push AX + Mov AX, 0B800h + Mov ES, AX + Pop AX + +S_GetDestination1: + Ret + +EndP S_GetDestination + +; + +Proc S_ClearScreen Far + + Push CX + Push ES + Push DI + + Call S_GetDestination +IF USE32BITSCREENCOPY + Mov CX, 2000 + Mov EAX, 03000300h + Xor DI, DI + Rep StosD +ELSE + Mov CX, 4000 + Mov AX, 300h + Xor DI, DI + Rep StosW +ENDIF + Pop DI + Pop ES + Pop CX + + Ret + +EndP S_ClearScreen + +; + +; Style - Low byte: Box style number +; - High byte: Flags - Bit 0: Filled box/empty box; on = don't fill + +Proc S_DrawBox Far + ARG Style, Bottom, Right, Top, Left + + Push BP + Mov BP, SP + + PushA + Push DS + Push ES + + Push CS + Pop DS + + Call S_GetDestination + Mov DX, Style ; SI = Box Style + Mov AL, 18 + Mul DL ; AX = Box Style*18 + Mov SI, AX + Add SI, Offset BoxDefinitions + + Mov AX, 80 + Mul Top + Add AX, Left + Add AX, AX + + Mov DI, AX ; ES:DI points to top left + MovsW + + LodsW + Mov CX, Right + Sub CX, Left + Dec CX + Mov DX, CX ; DX = width + + Rep StosW + + MovsW ; OK.... top line drawn + + Mov BX, Bottom + Sub BX, Top + +DrawBox1: + Add DI, 156 + Sub DI, DX + Sub DI, DX + + Dec BX + JZ DrawBox3 + + Push SI + + MovsW + + LodsW + + Test Style, 100h + JNZ DrawBox2 + + Mov CX, DX + Rep StosW + + MovsW + Pop SI + + Jmp DrawBox1 + +DrawBox2: + Add DI, DX + Add DI, DX + + MovsW + + Pop SI + Jmp DrawBox1 + +DrawBox3: + Add SI, 6 + + MovsW + + LodsW + Mov CX, DX + Rep StosW + + MovsW + + Pop ES + Pop DS + PopA + + Pop BP + Ret + +EndP S_DrawBox + +; + +Proc S_UpdateScreen Far + + Cmp CS:DirectVideo, 0 + JNE S_UpdateScreen1 + + PushAD + Push DS + Push ES + + Call MouseUpdateDisable ; * + + Mov ES, CS:ScreenDataArea + Call RestoreMouse + Call RestoreMouseGraphics + + + Test CS:VGAFlags, 4 ; Wait for vertical retrace? + JZ S_UpdateScreen2 + + Mov DX, 3DAh + +S_UpdateScreen3: + In AL, DX + Test AL, 8 + JZ S_UpdateScreen3 + +S_UpdateScreen2: + Mov ES, CS:ScreenDataArea + Call DrawMouse + + Xor SI, SI + Xor DI, DI + + Mov DS, CS:ScreenDataArea + Mov CX, 0B800h + Mov ES, CX +IF USE32BITSCREENCOPY + Mov CX, 2000 + Rep MovsD +ELSE + Mov CX, 4000 + Rep MovsW +ENDIF + + Mov ES, CS:ScreenDataArea + Call RestoreMouse + + Call MouseUpdateEnable ; * + + Pop ES + Pop DS + PopAD + +S_UpdateScreen1: + Ret + +EndP S_UpdateScreen + +; + +Proc S_SetDirectMode Far + + Cmp CS:DirectVideo, AL + JE S_SetDirectMode2 + + And AL, AL + JZ S_SetDirectMode1 + + Call S_UpdateScreen + Jmp S_SetDirectMode2 + +S_SetDirectMode1: + PushAD + Push DS + Push ES + + Call MouseUpdateDisable + + Mov ES, CS:ScreenDataArea + Mov CX, 0B800h + Mov DS, CX + Xor SI, SI + Xor DI, DI +IF USE32BITSCREENCOPY + Mov CX, 2000 + Rep MovsD +ELSE + Mov CX, 4000 + Rep MovsW +ENDIF + + Call RestoreMouse + + Call MouseUpdateEnable ; * + + Pop ES + Pop DS + PopAD + +S_SetDirectMode2: + Mov CS:DirectVideo, AL + Ret + +EndP S_SetDirectMode + +; + +Proc S_HiLight Far ; DI points to offset + ; AL = colour + ; CX = number of characters + Push ES + Push CX + Push DI + + Call S_GetDestination + +HiLight1: + Inc DI + StosB + Loop HiLight1 + + Pop DI + Pop CX + Pop ES + + Ret + +EndP S_HiLight + +; + +Proc S_DirectDrawString Far + + Push BP + Mov BP, SP + Add BP, 6 + + Push AX + Push BX + Push CX + Push DX + Push SI + Push ES + + Mov DX, 0B800h + Mov ES, DX + Mov DX, DI + + Jmp DrawString001 + +EndP S_DirectDrawString + +; + +Proc S_DrawString Far ; DS:SI points to string + ; DI points to offset + ; AH = colour + + ; 0 = End of string + ; 13 = Next line + ; 10 = Toggle character sets + ; 0FFh, x, n = repeat character n 'x' times + ; 0FEh, x = set colour to x + ; 0FDh, 'D' = show decimal number + ; 0FDh, 'X' = show hex number + ; 0FDh, 'S' = show signed number + ; 0FDh, 'L' = show long number + + + Push BP + Mov BP, SP + Add BP, 6 + + Push AX + Push BX + Push CX + Push DX + Push SI + Push ES + + Call S_GetDestination + + Mov DX, DI + +DrawString001: + LodsB + And AL, AL + JZ DrawString002 + + Cmp AL, 0FDh + JE DrawString007 + + Cmp AL, 13 + JE DrawString003 + + Cmp AL, 10 + JE DrawString004 + + Cmp AL, 0FEh + JAE DrawString005 + + StosW + Jmp DrawString001 + +DrawString002: + Pop ES + Pop SI + Pop DX + Pop CX + Pop BX + Pop AX + Pop BP + + Ret + +DrawString003: ; Next line + Add DX, 160 + Mov DI, DX + Jmp DrawString001 + +DrawString004: ; Toggle character sets + Xor AH, 8h + Jmp DrawString001 + +DrawString005: + Cmp AL, 0FEH + JE DrawString006 + + LodsB ; RepeatCharacters + Mov CL, AL + Xor CH, CH + + LodsB + Rep StosW + Jmp DrawString001 + +DrawString006: + LodsB ; New Colour + Mov AH, AL + Jmp DrawString001 + +DrawString007: + LodsB + Cmp AL, 'D' + JE DrawString008 + + Cmp AL, 'X' + JE DrawString012 + + Cmp AL, 'L' + JE DrawString015 + + Cmp AL, 'S' + JE DrawStringSigned + + Push AX + Mov AL, 0FDh + StosW + Pop AX + StosW + Jmp DrawString001 + +DrawStringSigned: + Push AX + Push BX + Push CX + Push DX + + Mov CH, AH + + Push 0FFFFh + + Mov AX, [BP] + Mov BX, 10 + + And AX, AX + JNS DrawString009 + + Neg AX + Mov CL, '-' + Mov [ES:DI], CX + ScasW +; Add DI, 2 + Jmp DrawString009 + +DrawString008: + Push AX + Push BX + Push CX + Push DX + + Mov CH, AH + + Push 0FFFFh + + Mov AX, [BP] + Mov BX, 10 + +DrawString009: + Xor DX, DX + Div BX + + Push DX + And AX, AX + JNZ DrawString009 + +DrawString010: + Pop AX + Cmp AX, 0FFFFh + JE DrawString011 + + Mov AH, CH + Add AL, '0' + StosW + Jmp DrawString010 + +DrawString011: + Add BP, 2 + + Pop DX + Pop CX + Pop BX + Pop AX + Jmp DrawString001 + +DrawString012: + Push AX + Push BX + Push DX + + Push 0FFFFh + + Mov DX, [BP] + Add BP, 2 + +DrawString013: + Mov AL, DL + And AL, 0Fh + Cmp AL, 10 + SBB AL, 69h + DAS + Push AX + + ShR DX, 4 + JNZ DrawString013 + + Pop AX + +DrawString014: + StosW + + Pop AX + Cmp AX, 0FFFFh + JNE DrawString014 + + Pop DX + Pop BX + Pop AX + Jmp DrawString001 + +DrawString015: + Push EAX + Push EBX + Push ECX + Push EDX + + Mov CH, AH + + Push 0FFFFh + + Mov EAX, [BP] + Mov EBX, 10 + +DrawString016: + Xor EDX, EDX + Div EBX + + Push DX + And EAX, EAX + JNZ DrawString016 + +DrawString017: + Pop AX + Cmp AX, 0FFFFh + JE DrawString018 + + Mov AH, CH + Add AL, '0' + StosW + Jmp DrawString017 + +DrawString018: + Add BP, 4 + + Pop EDX + Pop ECX + Pop EBX + Pop EAX + Jmp DrawString001 + + +EndP S_DrawString + +; + +Proc S_GetGenerationTableOffset Far ; returns ES:DI + + Mov ES, CS:ScreenDataArea + Mov DI, 8000 + + Ret + +EndP S_GetGenerationTableOffset + +; + +Proc S_GenerateCharacters Far ; AX = starting char. + ; BX = chars per row. + ; CX = number of rows. + PushAD + Push DS + Push ES + + Push AX + Push BX + Push CX + + Call MouseUpdateDisable + Call NewCharacterSet + + Pop CX + Pop BX + Pop AX + + Call MouseSecondSetEnable + + Call S_SetSequencer + + Mov DL, 32 + Mul DL ; AX = starting offset. + Mov DI, AX + Add DI, CharacterGenerationOffset + + Push 0A000h + Pop ES + + Mov DS, CS:ScreenDataArea + Mov SI, 8000 + + Mov DX, BX + +S_GenerateCharacters1: + Push CX + Push SI + +S_GenerateCharacters5: + Push DI + Push SI + Mov CX, 8 + +S_GenerateCharacters4: + Xor AH, AH + Mov BP, 8 + +S_GenerateCharacters2: + LodsB + + ShR AL, 1 + RCL AH, 1 + Dec BP + JNZ S_GenerateCharacters2 + + Mov AL, AH + StosB + + Mov AX, DX + ShL AX, 3 + Add SI, AX ; Add SI, 8*BX + Sub SI, 8 + Loop S_GenerateCharacters4 + + Pop SI + Add SI, 8 + + Pop DI + Add DI, 32 + + Dec BX + JNZ S_GenerateCharacters5 + + Pop SI + Mov BX, DX + + Mov AX, BX + Mov CL, 6 + ShL AX, CL + Add SI, AX + + Pop CX + + Loop S_GenerateCharacters1 ; Rows.. + + Call S_ResetSequencer + + Call MouseUpdateEnable + + Pop ES + Pop DS + PopAD + + Ret + +EndP S_GenerateCharacters + +; + +Proc S_DrawSmallBox Far + + Mov AX, 30 + Push AX + Mov AX, 25 + Push AX + Mov AX, 49 + Push AX + Mov AX, 27 + Push AX + Mov AX, 3 + Push AX + Call S_DrawBox + Add SP, 10 + + Ret + +EndP S_DrawSmallBox + +; + +Proc S_GetPaletteOffset Far + + Push CS + Pop DS + Mov DX, Offset PaletteDefs + + Ret + +EndP S_GetPaletteOffset + +; + +Proc S_UsePresetPalette Far + + Mov AL, 48 + Mul Byte Ptr [DS:SI+22] + Mov SI, AX + + Mov AX, CS + Mov DS, AX + Mov ES, AX + Assume DS:Screen + + Add SI, Offset PresetPalettes + Mov DI, Offset PaletteDefs + Mov CX, 48 + Rep MovsB + + Call S_SetPalette2 + + Mov AX, 1 + Ret + +EndP S_UsePresetPalette + Assume DS:Nothing + +; + +Proc S_DefineHiASCII Far + + Call MouseUpdateDisable + + Call S_SetSequencer + + + Push DS + Push ES + + Mov AX, 0A000h + Mov DS, AX + Mov ES, AX + + Mov AX, 16 + Mov DI, CS:CharacterGenerationOffset + Mov SI, AX + + Xor DX, DX + +S_DefineHIASCII1: + Mov CX, AX + Rep MovsB + + Add SI, AX + Add DI, AX + Dec DL + JNZ S_DefineHIASCII1 + + Pop ES + Pop DS + + Call S_ResetSequencer + + Call NewCharacterSet + Call MouseSecondSetDisable + Call MouseUpdateEnable + + Ret + +EndP S_DefineHiASCII + +; + +Proc S_InvertCursor Far ; AL = char, AH = mask. + + PushA + Push DS + Push ES + + Mov SI, 0A000h + Mov DS, SI + Mov ES, SI + + Mov SI, DX + And SI, 0FFh + ShL SI, 5 + Test DH, 8 + JZ S_InvertCursor2 + + Add SI, CS:CharacterGenerationOffset + +S_InvertCursor2: + ClI + Call S_SetSequencer + Mov CX, 8 + Mov DI, (246*32) + +S_InvertCursor1: + LodsB + Xor AL, AH + StosB + Loop S_InvertCursor1 + + Call S_ResetSequencer + StI + + Pop ES + Pop DS + PopA + Ret + +EndP S_InvertCursor + +; + +Segment ScreenData PARA Public 'Data' + DB 1542 * 16 Dup (0) +EndS + +; + +EndS + +; + +End diff --git a/it/IT_TIMER.INC b/it/IT_TIMER.INC new file mode 100644 index 0000000..2c4d844 --- /dev/null +++ b/it/IT_TIMER.INC @@ -0,0 +1,90 @@ + +Proc GetCurrentTime + + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Disk + + Cmp TimerData, 0 + JE GetCurrentTimeEnd + + Mov ES, TimerData + Mov DI, NumTimerData + ShL DI, 3 + + Mov AH, 2Ah + Int 21h ; Get Date + Mov AX, CX ; Now to get date in yyyyyyym mmmddddd + Sub AX, 1980 + ShL AX, 9 ; Year + Or AL, DL ; Day + Xor DL, DL + ShR DX, 3 + Or AX, DX ; Month + StosW + + Mov AH, 2Ch + Int 21h ; Get time + Mov AX, CX ; Now to get time in hhhhhmmm mmmsssss + ShL AL, 2 ; AX = ...hhhhh mmmmmm.. + ShL AX, 3 ; AX = hhhhhmmm mmm..... + ShR DH, 1 ; DH = ...sssss + Or AL, DH + StosW + +GetCurrentTimeEnd: + Pop ES + Pop DS + Ret + +EndP GetCurrentTime + Assume DS:Nothing + +; + +Proc CheckTimerData + Assume DS:Disk + + Cmp TimerData, 0 + JNE CheckTimerData1 + + Mov NumTimerData, 0 + Mov AH, 48h + Mov BX, 1 + Int 21h + JC CheckTimerData1 + + Mov TimerData, AX + Call GetCurrentTime + +CheckTimerData1: + Ret + +EndP CheckTimerData + Assume DS:Nothing + +; + +Proc ReleaseTimerData + + Mov AX, CS:TimerData + Test AX, AX + JZ ReleaseTimerData1 + + Mov ES, AX + Mov AH, 49h + Int 21h + Xor AX, AX + +ReleaseTimerData1: + Mov CS:TimerData, AX + Mov CS:NumTimerData, AX + + Ret + +EndP ReleaseTimerData + +; diff --git a/it/IT_TUTE.ASM b/it/IT_TUTE.ASM new file mode 100644 index 0000000..40aafb3 --- /dev/null +++ b/it/IT_TUTE.ASM @@ -0,0 +1,519 @@ + + Jumps + .386 + +include switch.inc + +IF TUTORIAL + + Extrn S_DrawBox:Far + Extrn S_DrawString:Far + Extrn Music_GetSongSegment:Far + Extrn Music_GetPlayMode:Far + Extrn PE_GetLastInstrument:Far ; Returns BX = LastInst-1 + +Segment Pattern BYTE Public 'Code' + Extrn PatternDataArea:Word + Extrn LastKeyBoard1:Word + Extrn LastKeyBoard2:Word +EndS + +Segment Disk Byte Public 'Code' USE16 + Extrn SamplesInModule:Byte + Extrn InSampleFileName:Byte +EndS + + Public Glbl_TutorialHandler + +Segment Glbl BYTE Public 'Code' USE16 + Assume CS:Glbl, DS:Nothing, GS:Pattern + +Extrn CurrentMode:Byte + +TutorialState DW 0 + + +; TutorialInfo structure: +; DW Offset function +; DB x, y (top left) +; DB x, y (bottom right) +; DB colour +; DB Message, 0 + +TutorialFunctionArray Label Word + DW Offset Tute_State0 + DW Offset Tute_State1 + DW Offset Tute_State2 + DW Offset Tute_State3 + DW Offset Tute_State4 + DW Offset Tute_State5 + DW Offset Tute_State6 + DW Offset Tute_State7 + DW Offset Tute_State8 + DW Offset Tute_State9 + DW Offset Tute_State10 + DW Offset Tute_State1 + DW Offset Tute_State12 + DW Offset Tute_State2 + DW Offset Tute_State14 + DW Offset Tute_State5 + DW Offset Tute_State16 + DW Offset Tute_State9 + DW Offset Tute_State18 + DW Offset Tute_State19 + DW Offset Tute_StateEnd + +MAXTUTESTATE = ($-Offset TutorialFunctionArray)/2 + + +TutorialInfoArray Label Word + DW Offset TutorialDisplayState0 + DW Offset TutorialDisplayState1 + DW Offset TutorialDisplayState2 + DW Offset TutorialDisplayState3 + DW Offset TutorialDisplayState4 + DW Offset TutorialDisplayState5 + DW Offset TutorialDisplayState6 + DW Offset TutorialDisplayState7 + DW Offset TutorialDisplayState8 + DW Offset TutorialDisplayState9 + DW Offset TutorialDisplayState10 + DW Offset TutorialDisplayState11 + DW Offset TutorialDisplayState12 + DW Offset TutorialDisplayState13 + DW Offset TutorialDisplayState14 + DW Offset TutorialDisplayState15 + DW Offset TutorialDisplayState16 + DW Offset TutorialDisplayState17 + DW Offset TutorialDisplayState18 + DW Offset TutorialDisplayState19 + DW Offset TutorialDisplayState20 + DW Offset TutorialDisplayStatexx + +TutorialDisplayState0 DB 0, 40, 79, 49 + DB 0FFh, 20, " Welcome to the Impulse Tracker Tutorial!", 13, 13 + DB "This tutorial was designed to provide you with a basic understanding of how", 13 + DB "this program works. Everything that you learn here is exactly the same as in", 13 + DB "the main program. By the end of this tutorial, you should be able to compose", 13 + DB "your own modules!", 13, 13 + DB "Good luck! (Press Enter to continue)", 0 + +TutorialDisplayState1 DB 0, 0, 79, 4 + DB "This is the load-module screen that Impulse Tracker will normally begin with.", 13 + DB "As we will start a song afresh, switch to the sample list screen by pressing", 13 + DB "F3.", 0 + +TutorialDisplayState2 DB 36, 1, 78, 13 + DB "There are two basic elements to an", 13 + DB "Impulse Tracker module: patterns and", 13 + DB "samples. Samples provide all the 'real'", 13 + DB "sound information to the program. These", 13 + DB "sounds can be instruments, voices, WAV", 13 + DB "files - anything you like! IT understands", 13 + DB "a wide variety of sound files and even", 13 + DB "allows you to take sounds directly from", 13 + DB "other modules. Since there are no samples", 13 + DB "currently loaded, press Enter to switch", 13 + DB "to the load sample screen.", 0 + +TutorialDisplayState3 DB 0, 0, 79, 5 + DB "A file called TUTE.IT was included with this tutorial. You should be able to", 13 + DB "see it highlighted in the listing below. IT will hilight any file that it", 13 + DB "recognises as a sound file. You can also navigate through your directories", 13 + DB "from this menu. Select TUTE.IT and step into it by pressing Enter.", 0 + +TutorialDisplayState4 DB 2, 28, 45, 39 + DB "Here you can see a list of all the samples", 13 + DB "that are contained within TUTE.IT. To have", 13 + DB "a listen to how they sound, press the down", 13 + DB "arrow once to hilight the first sample and", 13 + DB "press 'Q'. Try moving to the other samples", 13 + DB "and playing them. Try pressing 'W', 'E',", 13 + DB "'R'. You will notice that the samples are", 13 + DB "played at a different pitch. Once you've", 13 + DB "heard all of the samples, select the Bass", 13 + DB "Drum and press Enter.", 0 + +TutorialDisplayState5 DB 36, 14, 78, 20 + DB "OK! You have now loaded the Bass Drum", 13 + DB "into memory. This means that you can use", 13 + DB "it in your songs. Lets do that now!", 13, 13 + DB "Press F2 to go to the pattern editor.", 0 + +TutorialDisplayState6 DB 33, 16, 78, 19 + DB "The pattern editor is where you set out the", 13 + DB "notes that you want to play. Press 'Q'", 0 + +TutorialDisplayState7 DB 33, 16, 78, 35 + DB "So what does this mean?", 13, 13 + DB "C-5 01 ", 173, 173, " .00", 13, 13 + DB "C-5 means to play the note C at octave 5.", 13 + DB "01 means to use sample number 1.", 13, 13 + DB "If this doesn't make sense now, don't worry!", 13 + DB "All of this will be explained later in this", 13 + DB "tutorial.", 13, 13 + DB "For now, try to enter a Bass Drum every four", 13 + DB "rows in Channel 1 (ie. on row 4, 8, 12, ...)", 13, 13 + DB "Continue to use 'Q' to enter the notes. The", 13 + DB "arrow keys may be of assistance. If you make", 13 + DB "a mistake, use the '.' key to blank out the", 13 + DB "entry.", 0 + +TutorialDisplayState8 DB 33, 16, 78, 21 + DB "OK, that's enough!", 13, 13 + DB "Lets take a listen to what you've done.", 13 + DB "Press F6 to play what you've entered.", 0 + +TutorialDisplayState9 DB 33, 16, 78, 23 + DB "As the pattern is played to you, you will", 13 + DB "notice that a cursor on the left hand side", 13 + DB "of the screen indicates the current playback", 13 + DB "position. Press F6 to watch that again.", 13, 13 + DB "When you're ready, press F8 to stop playback", 0 + +TutorialDisplayState10 DB 33, 16, 78, 25 + DB "To finish off the task of entering the Bass", 13 + DB "Drum, move up one row to row 16 and press", 13 + DB "Alt-4. This will cause the cursor to step", 13 + DB "4 rows after every note that you enter", 13 + DB "instead of 1.", 13, 13 + DB "Hold down 'Q' until Channel 1 has a Bass", 13 + DB "Drum every 4 rows until row 60.", 0 + +TutorialDisplayState11 DB 33, 16, 78, 21 + DB "Now we'll add in a snare drum. Before we do", 13 + DB "that though, set the cursor step back to", 13 + DB "a single row at a time. Press Alt-1, then", 13 + DB "F3 to go back to the sample list.", 0 + +TutorialDisplayState12 DB 36, 14, 78, 18 + DB "To load a sample into the second sample", 13 + DB "slot, first press the down arrow a single", 13 + DB "time so that sample two is hilighted.", 0 + +TutorialDisplayState13 DB 36, 14, 72, 17 + DB "Now press Enter to call up the Load", 13 + DB "Sample screen.", 0 + +TutorialDisplayState14 DB 7, 25, 42, 28 + DB "Select the Snare Drum and load it", 13 + DB "(by pressing Enter).", 0 + +TutorialDisplayState15 DB 36, 14, 74, 17 + DB "And now return to the Pattern Editor", 13 + DB "(F2)", 0 + +TutorialDisplayState16 DB 36, 16, 78, 24 + DB "Press Ctrl-PgUp to move to the top of", 13 + DB "the pattern and enter a snare drum in", 13 + DB "every 4th row starting at line 2.", 13 + DB 13 + DB "Use C-5 again, and to make it easier, you", 13 + DB "can set the skip to 4 once you've moved", 13 + DB "to line 2.", 0 + +TutorialDisplayState17 DB 34, 16, 78, 19 + DB "Have a listen to what you've just created!", 13 + DB "(Press F6)", 0 + +TutorialDisplayState18 DB 36, 16, 78, 28 + DB "As part of this tutorial, we'll try out", 13 + DB "one of the block functions that IT", 13 + DB "offers. Our goal is to halve the speed", 13 + DB "at which this plays just by modifying", 13 + DB "the pattern data. IT has two functions", 13 + DB "that will automatically halve or double", 13 + DB "the length of a hilighted block.", 13, 13 + DB "First, hilight channel 1.", 13 + DB "Move to the top of the channel first", 13 + DB "by pressing Ctrl-PgUp, then press Alt-L", 0 + +TutorialDisplayState19 DB 36, 16, 78, 26 + DB "Alt-L is a function which will mark the", 13 + DB "entire channel that your cursor is", 13 + DB "currently on. Pressing it twice will", 13 + DB "mark the entire pattern. For now, we", 13 + DB "only need the first channel so you do", 13 + DB "not need to press it a second time.", 13 + DB 13 + DB "Now that the block is marked, press", 13 + DB "Alt-G to actually double the block size!", 0 + +TutorialDisplayState20 DB 36, 16, 78, 33 + DB "Uhhh. Ooops!! That was supposed to be", 13 + DB "Alt-F. No matter - the automatic undo", 13 + DB "in IT will be able to recover our data.", 13 + DB "(Yes, we could just double it twice and", 13 + DB "everything would be perfectly fine, but", 13 + DB "this is meant to teach you about IT,", 13 + DB "right? [smile])", 13 + DB 13 + DB "Whenever you do a block function in IT", 13 + DB "the contents of the entire pattern is", 13 + DB "saved first. IT will store up to 10 of", 13 + DB "these in memory so that you can recover", 13 + DB "from any mistakes that you make.", 13 + DB 13 + DB "Press Ctrl-Backspace to pull up the", 13 + DB "undo menu.", 0 + +TutorialDisplayStatexx DB 33, 16, 78, 21 + DB "Incomplete...", 0 + +TuteFileName DB "TUTE.IT" +BassDrumText DB "Bass Drum" +SnareDrumText DB "Snare Drum" + +; + +Proc Tute_State0 + + Cmp AL, 9 + Ret + +EndP Tute_State0 + +; + +Proc Tute_State1 + + Cmp AL, 3 + Ret + +EndP Tute_State1 + +; + +Proc Tute_State2 + + Cmp AL, 13 + Ret + +EndP Tute_State2 + +; + +Proc Tute_State3 + + Push Disk + Pop ES + Assume ES:Disk + + Cmp ES:SamplesInModule, 1 + JNE Tute_State3a + + Mov DI, Offset InSampleFileName + Mov SI, Offset TuteFileName + Mov CX, 7 + RepE CmpsB + +Tute_State3a: + Ret + +EndP Tute_State3 + +; + +Proc Tute_State4 + + Call Music_GetSongSegment + Mov ES, AX + Mov DI, [ES:64912] + Mov SI, Offset BassDrumText + Add DI, 14h + Mov CX, 9 + RepE CmpSB + Ret + +EndP Tute_State4 + +; + +Proc Tute_State5 + + Cmp AL, 2 + Ret + +EndP Tute_State5 + +; + +Proc Tute_State6 + + Cmp Word Ptr [FS:0], 13Ch + Ret + +EndP Tute_State6 + +; + +Proc Tute_State7 + + Cmp Word Ptr [FS:320*16], 13Ch + Ret + +EndP Tute_State7 + +; + +Proc Tute_State8 + + Call Music_GetPlayMode + Cmp AX, 1 + + Ret + +EndP Tute_State8 + +; + +Proc Tute_State9 + + Call Music_GetPlayMode + Test AX, AX + Ret + +EndP Tute_State9 + +; + +Proc Tute_State10 + + Cmp Word Ptr [FS:60*320], 13Ch + Ret + +EndP Tute_State10 + +; + +Proc Tute_State12 + + Call PE_GetLastInstrument + Cmp BX, 1 + Ret + +EndP Tute_State12 + +; + +Proc Tute_State14 + + Call Music_GetSongSegment + Mov ES, AX + Mov DI, [ES:64914] + Mov SI, Offset SnareDrumText + Add DI, 14h + Mov CX, 10 + RepE CmpSB + Ret + +EndP Tute_State14 + +; + +Proc Tute_StateEnd + + Inc AX ; Ensure zero flag is not set. + Ret + +EndP Tute_StateEnd + +; + +Proc Tute_State16 + + Cmp Word Ptr [FS:62*320], 23Ch + Ret + +EndP Tute_State16 + +; + +Proc Tute_State18 + + Cmp [Word Ptr GS:LastKeyboard1+2], 2600h + Ret + +EndP Tute_State18 + +; + +Proc Tute_State19 + + Cmp [Word Ptr GS:LastKeyboard1+2], 2200h + Ret + +EndP Tute_State19 + +; + +Proc Glbl_TutorialHandler Far + + PushAD + Push DS + + Push CS + Pop DS + Assume DS:Glbl + + Push Pattern + Pop GS + + Mov FS, [GS:PatternDataArea] + Assume FS:Nothing + + Mov BX, [TutorialState] + Mov AL, CurrentMode + LEA SI, [EBX+EBX] + + Push BX + Call [TutorialFunctionArray+SI] + Pop BX + JNE Glbl_TutorialHandler1 + + Inc BX + +Glbl_TutorialHandler1: + Mov [TutorialState], BX + + Cmp BX, MAXTUTESTATE + JAE Tute_TuteFinished + + Xor AX, AX + LEA SI, [EBX+EBX] + Mov SI, [TutorialInfoArray+SI] + LodsB + Push AX + LodsB + Push AX + LodsB + Push AX + LodsB + Push AX + Mov AL, 30 + Push AX + + Call S_DrawBox + Add SP, 10 + Mov AL, 80 + Mul Byte Ptr [SI-3] ; y*80 + Add AL, Byte Ptr [SI-4] + AdC AH, 0 + LEA DI, [EAX+EAX] + Add DI, (80+1)*2 + Mov AH, 13h + Call S_DrawString + +Tute_TuteFinished: + Pop DS + PopAD + Ret + +EndP Glbl_TutorialHandler + Assume DS:Nothing, FS:Nothing + +EndS + +ENDIF + +End diff --git a/it/IT_VESA.ASM b/it/IT_VESA.ASM new file mode 100644 index 0000000..4565ddb --- /dev/null +++ b/it/IT_VESA.ASM @@ -0,0 +1,226 @@ +;Ŀ +; Vesa Module +;Ĵ +; Functions provided: +; DetectVESA +; SetVESAMode +; +;Ĵ +; DetectVESA +; - No parameters required +; - Detects the presence of a VESA driver +; - Returns carry SET if no VESA driver found +; - Returns carry CLEAR if VESA driver found +; - All registers preserved +;Ĵ +; SetVESAMode +; - Requires AX = VESA Mode +; - Returns carry SET if VESA Mode isn't supported +; - Returns carry CLEAR if VESA mode change OK +; - All registers preserved +;Ĵ +; VESAGetInfo +; - Requires AX = VESA Mode to get information on +; - Returns carry SET if VESA Mode isn't supported +; - Returns carry clear if information is OK +; - Returns ES:DI to Table, all other registers preserved +; +; + + Jumps + .386P + +include switch.inc + +IF SPECTRUMANALYSER + +;Ŀ +; Externals +; + + +;Ŀ +; Globals +; + + +; + +Segment Vesa BYTE Public 'Code' USE16 + Assume CS:Vesa, DS:Nothing + +;Ŀ +; Variables +; + +VESAInformationTable Label +VESASignature DB 4 Dup (0) +VESAVersion DW 0 +VESAOEMStringPrt DD 0 +VESACapabilities DD 0 +VESAVideoModePtr DD 0 +VESATotalMemory DW 0 + DB 256-($-VESAInformationTable) Dup(0) + +VESAModeInformationTable Label + DB 256-($-VESAModeInformationTable) Dup (0) + +ModeInformationStructure Struc + ModeAtributes DW ? + WindowAAtributes DB ? + WindowBAttributes DB ? + WindowGranularity DW ? + WindowSize DW ? + WindowASegment DW ? + WindowBSegment DW ? + WindowFunction DD ? + BytesPerScanLine DW ? + + XResolution DW ? + YResolution DW ? + XCharacterSize DB ? + YCharacterSize DB ? + NumberOfPlanes DB ? + BitsPerPixel DB ? + NumberOfBanks DB ? + MemoryModel DB ? + BankSize DB ? + NumberOfImagePages DB ? + Reserved DB ? + + RedMaskSize DB ? + RedFieldPosition DB ? + GreenMaskSize DB ? + GreenFieldPosition DB ? + BlueMaskSize DB ? + BlueFieldPosition DB ? + RSVDMaskSize DB ? + DirectColourModeInfo DB ? + +ModeInformationStructure EndS + +;Ŀ +; Functions +; + +Proc VESA_Detect Far +Public VESA_Detect + + PushA + Push ES + + Mov AX, 4F00h + Push CS + Pop ES + Mov DI, Offset VESAInformationTable + Int 10h + + Cmp AX, 4Fh + JNE DetectVESA1 + Cmp [DWord Ptr ES:DI], "ASEV" ; 'VESA' identification + JNE DetectVESA1 + + DB 85h + +DetectVESA1: + StC + + Pop ES + PopA + Ret + +EndP VESA_Detect + +; + +Proc VESA_SetMode Far +Public VESA_SetMode + + PushA + Push DS + Push ES + + Call VESA_GetInfo + JC VESA_SetMode3 + + Mov BX, AX + Mov AX, 4F02h ; Set Mode + Int 10h + Cmp AX, 4Fh + JE VESA_SetMode3 + + StC + +VESA_SetMode3: + Pop ES + Pop DS + PopA + + Mov CX, [VESAModeInformationTable.XResolution] + Mov DX, [VESAModeInformationTable.YResolution] + + Ret + +EndP VESA_SetMode + +; + +Proc VESA_GetInfo +Public VESA_GetInfo + + Push AX + Push CX + + Mov CX, AX + + Push CS + Pop ES + Mov DI, Offset VESAModeInformationTable + Mov AX, 4F01h + Int 10h + + Cmp AX, 4Fh + JE VESA_GetInfo1 + + StC + +VESA_GetInfo1: + Pop CX + Pop AX + + Ret + +EndP VESA_GetInfo + +; + +Proc VESA_SetBlock Far ; Gives access to a 64kb block +Public VESA_SetBlock ; Given AX = block number. + + PushA + Push AX + + Mov AX, 64 + Xor DX, DX + Div Word Ptr [VESAModeInformationTable.WindowGranularity] + Mov DX, AX + Pop AX + Mul DX + Mov DX, AX + Xor BX, BX + Call DWord Ptr [VESAModeInformationTable.WindowFunction] + + PopA + Ret + +EndP VESA_SetBlock + +; + +EndS + +; + +ENDIF + +End diff --git a/it/InternalDocumentation/CHANNEL.TXT b/it/InternalDocumentation/CHANNEL.TXT new file mode 100644 index 0000000..ba79c60 --- /dev/null +++ b/it/InternalDocumentation/CHANNEL.TXT @@ -0,0 +1,279 @@ + Host Channel Structure + + 0 1 2 3 4 5 6 7 8 9 A B C D E F + Ŀ +0000: Flags MskNteInsVolCmd&ValOCm&ValVCm&ValMChMPrNt2Smp + Ĵ +0010:DKLEFGO00I00J00M00N00P00Q00T00S00OxHW00VCEGOESFx GOE = Gxx + Ĵ with old +0020:HCNCUCVSeLTrSCOffstPLRPLCPWFPPoPDpPSpLPnLViCP CV effects + Ĵ +0030:VChTCDTooRTCPorta FrequencyVWFVPoVDpVSpTWFTPoTDpTSp + Ĵ +0040: Misc Effect Data............................................. + + + Flags: + Update Mode + 2 Bits (0-3) + 0: Don't update effect + 1: Update effect if channel is on + 2: Always update effect + + Channel On + 1 Bit (4) + 0: Channel is off + 1: Channel is on + + Channel Cut ; No longer implemented + 1 Bit (8) + 0: No Channel Cut command + 1: Channel Cut command issued + + Slide in progress (Commands G/L) + 1 Bit (16) + 0: No slide in progress + 1: Slide in progress + + Freeplay note (ie. Don't check channel on/off) + 1 Bit (32) + 0: Not freeplay -> Check channel + 1: Freeplay -> Don't check channel + + +64 = row updated. + + + 128 = Apply random volume + + +256 Volume column effect requires updating if channel on + +512 Volume column effect requires updating always. + +32768 = Dont' touch in interrupt! + + Decoding Data + Msk, Nte, Ins, Vol, Cmd&Val, ONt, OIn, OVl, OCm&Val + Msk = Read mask: Bit 0 or 4 = Note read + Bit 1 or 5 = Instrument read + Bit 2 or 6 = Volume read + Bit 3 or 7 = Command/Command Value read + + Smp & Nt2 + Sample Number (zero based) and Note (after translation if using inst.) + + CP. = Channel Pan + CV. = Channel Volume + + SCN = Slave Channel Number + CUC = Command Update Count. For playmode 0 + SCOffst = Slave channel number offset + + VWF = Vibrato wave form + TWF = Tremelo wave form + PWF = Panning wave form + + PLR = Pattern loop row + PLC = pattern loop count. + + VSe = Volume set + + LVi = Last vibrato. + LTr = Last tremelo. + Dir = Porta direction + RTC = Retrig count + Too = tremor on/off ; on = 1 + TCD = tremor count down + + OxH = High order Offset for yxx00h + + VCh = Volume change (For Command D) + + + + Slave Channel Structure + + 0 1 2 3 4 5 6 7 8 9 A B C D E F + Ŀ +0000: Flags Device specific...............LpMLpD Left Volume + Ĵ +0010: Frequency Frequency Set BitViPViDepth RVol/MIDIFSet + Ĵ +0020:FV VolVS CVlSVlFP FadeOutDCTDCAPanPS OldSampleOffset + Ĵ +0030:InsOffsNteInsSmpOffsSmpFPPHCOffstHCNNNAMChMPr MBank + Ĵ +0040: Loop Beginning Loop End SmpErr.16bVol Sample Offset + Ĵ +0050:VEnvelopeValue VEnvelopeDelta VEnvPosCurVEnNNextVETfiltera + Ĵ +0060:PEnvelopeValue PEnvelopeDelta PEnvPosCurVEnNNextPETfilterb + Ĵ +0070:PtEnvelopeValuePtEnvelopeDeltaPtEvPosCurPtENNxtPtETfilterc + + + For MIDI, [SI+0Bh] = Pattern note + + Reqd values: VEnvValue (DWord), VEnvDelta (DWord), VEnvPos (Word), NextVEnvNode + PEnvValue (DWord), PEnvDelta (DWord), PEnvPos (Word), NextPEnvNode + PtEnvValue (DWord), PtEnvDelta (DWord), PtEnvPos (Word), NextPtEnv + + Reqd flags: VolEnvOn, PEnvOn, PtEnvOn + + FP = final pan. + FPP = final playing pan, taking into account reverse. + + MBank also doubled as Filter freq, resonance + + Flags: + Channel On + 1 Bit (1) + 0: Channel is off + 1: Channel is on + Recalculate panning (2) + + Note Off (ie. Sustain) + 1 Bit (4) + 0: No Note Off command (ie. Sustain on) + 1: Note Off command issued (ie. Sustain off) + FadeOut + 1 Bit (8) + 0: No FadeOut command + 1: Apply FadeOut + Recalculate volume + 1 Bit (16) + 0: Volume doesn't need to be calculated + 1: Volume needs to be recalculated + Frequency change + 1 Bit (32) + 0: Frequency has NOT changed + 1: Frequency HAS changed + Recalculate Final volume... + 1 Bit (64) + 0: Final volume does not need to be calculated + 1: Final volume DOES need to be calculated. + + Central pan... + 1 Bit (128) + 0: Use whatever is given. + 1: Always use central pan (for sample list/instrument list) + + New note! + 1 Bit (256) + 0: No new note + 1: New note to play. + + Note stop (cut) ; IMPORTANT FOR GUS!!! + 1 Bit (512) + 0: note NOT cut + 1: Note CUT + + Loop changed. (1024) + + Channel muted (2048) ; 2^11 + + Vol Envelope on (4096) ; 1000h + Pan Envelope on (8192) ; 2000h + Pitch Envelope on (16384) ; 4000h + + Pan value changed ; 8000h + Recalculate final pan + + LpM + LoopMode + 0: No Loop + 8: Forwards Loop + 24: Ping Pong Loop ; Values are just for GUS convenience + + LpD + LoopDirection (for ping pong), ; 0 = forwards, 1 = backwards. + + FadeOut = Fadeout Count (0-255) + CVl = Channel Volume + HCN = Host Channel Number. +128 if "disowned" + Smp = Sample number + Pan: 0->64, 100 = Surround, >= 128 = muted. + FnV: Final Volume + + Bit: 2 = 16, 0 = 8. + + ViD: Vibrato Depth + ViS: Vibrato Speed + + VEP: Volume Envelope position + VEV: Volume Envelope value + + Ins: Instrument number (0 based, 0FFh if none) + Smp: Sample number (0 based) + + Frequency = Final note frequency. Incorportes vibrato + Frequency Set = Calculated Frequency of note. Calculated once when played + Altered by effects E,F,G,L + + VS = Volume Set. Similar to Frequency Set. Affected by D,K,L + Vol = Volume. Altered by effects R,I + + + + Sound Blaster Output Structure + + 0 1 2 3 4 5 6 7 8 9 + +0000:(Flags) Skip Value Vol x MixMode + + + For non-looped samples, 44h is LENGTH. + + Sound Blaster Pro Output Structure + + 0 1 2 3 4 5 6 7 8 9 + +0000:(Flags) Skip Value LVlRVlMixMode + + + Skip Value + 16.16 bit fixed point + + Vol/LVl/RVl + Output Volume / Left Volume / Right Volume + Accounts for: + Channel Volume + Global Volume + Sample Global Volume + Fade Out + + MMd: 0 If Left only + 1 If right only + 2 if Left = Right + 3 if Panned + 4 if Surround + 5 if position update. + + + +32 for 16 bit samples + +8 for looped + +24 for ping pong. + + UltraSound Output Structure + + 0 1 2 3 4 5 6 7 8 9 + +0000:(Flags)LastVolFreqval + + + Frequency Value used in dynamic GUS drivers + + AWE32 Output Structure + + 0 1 2 3 4 5 6 7 8 9 + +0000:(Flags) x x Freqvalue + + + Frequency Value used in floating point AWE32 drivers + + SAM Output Structure + + 0 1 2 3 4 5 6 7 8 9 + +0000:(Flags)opn x + + + opn = 1 if voice is opened, 0 if not. + diff --git a/it/InternalDocumentation/CONFIG.TXT b/it/InternalDocumentation/CONFIG.TXT new file mode 100644 index 0000000..17d12a6 --- /dev/null +++ b/it/InternalDocumentation/CONFIG.TXT @@ -0,0 +1,54 @@ +Configuration file for IT.EXE + +Offset Length Meaning +0 70 Module directory +70 70 Sample directory +140 70 Instrument directory +210 1 Keyboard style + +211 3*16 Palette information + +259 50 Display window setup + Structure is 6*8 bytes, followed by 1 word = number of windows + Structure of each 8 byte record is: + Word: Method. (0 = volume bars, 1 = 5 track view, etc) + Byte: Top channel + Byte: Top line on screen + Word: Length of window + Word: Display memory offset of top left of window. + +309 217 bytes so far Pattern edit setup. + + Offset (W = word, B = byte) + + 309 W - MUST be 0 (key signatures not defined) + 311 W - number of channels to edit (5, but recalculated + whenever the screen changes) + 313 B - Row hilight minor (eg. every 4) + 314 B - Row hilight major (eg. every 16) + 315 B - Edit mask. Bit 0 = edit ins, 1 = edit vol, 2 = edit FX + 316 B - View division (1= show divisions) + 317 W - Number of 'viewed' channels + 319 100W - Channel viewmethods. First word = channel + Second word = method + Methods: 0 = full edit + 1 = compressed edit + 2 = extra compressed edit + 3 = 3-character selective edit + 4 = 2 character selective edit + + 0FFFFh indicates end of list + + 519 B - View-channel cursor tracking (1 = on) + 520 B - Effect/Effectvalue link (1 = on) + 521 B - Flags. Bit 0 = centralise cursor + Bit 1 = hilight current row + Bit 2 = fast volume changes + Bit 3 = MIDI Quantize to tick + Bit 4 = MIDI program base 1 + Bit 5 = MIDI record note-offs + Bit 6 = MIDI record velocity + Bit 7 = MIDI Record aftertouch + 522 B - MIDIAmplification + 523 B - MIDICentral note + 524 W - Fast volume amplification diff --git a/it/InternalDocumentation/MMTECH.TXT b/it/InternalDocumentation/MMTECH.TXT new file mode 100644 index 0000000..085e4ca --- /dev/null +++ b/it/InternalDocumentation/MMTECH.TXT @@ -0,0 +1,143 @@ + +Here's something that might help you... I wrote it quite fast but it should +be accurate ;) However, there's probably a lot of stuff here that you don't +need/understant for now... but keep all this, you'll need it soon ;) + +--> This is NOT the "official" Tehcnical stuff.... + +File Header: + + offset type/size comment + ------ --------- --------------------------------- + 0 char[8] Signature: 'ziRCONia' + + 8 word file header size (from offset 10, not counting this + word) + 10 word version 0xyyzh (x.yy) (displayed in hex. no conversion) + z: 0 nothing + 1-0eh revision a to n (-may- be useful...) + 0fh Beta + 12 word number of blocks within file + 14 dword total length of unpacked file + 18 dword file offset where is located the "block offset table" + 22 word dummy... must currently be 0ffffH + + + The block offset table is simply N_of_Block dwords which are the + absolute position of each block in the file. Each of those blocks have + the following header: + + 0 dword unpacked size + 4 dword compressed size + 8 dword XOR check (see note below) + 12 word number of "sub-blocks" (nblk) + 14 word flags (see below) + 16 word number of translation table entry } for compression + 18 word start number of bit } don't mind them + for now... + 20 sub-block[nblk] Sub-blocks of data info. + + each sub-block has the following info: + 0 dword absolute position in uncompressed file + 4 dword size of uncompressed block + all "nblk" sub-block info are stored right after the block header. + + Those small blocks are only non-contiguous blocks of the "same type" + grouped together within one bigger block for better compression. + + - XOR check: instead of implementing a CRC, I coded a XOR check. + How it works: a dword variable is set to 0, and XORed + with every complete 4 bytes of the original data of the + "bigblock". Remaining bytes (i.e, size of bigblock is + not a multiple of 4) are simply ignored. This is only + to implement a minimal check of destination when + decompressing. + + - Flags: this is a 16 bits field: + + 15 14 13 12 11 10 9 8 + Ŀ + 0 0 0 0 0 0 Abs16 M/S + + 7 6 5 4 3 2 1 0 + Ŀ + R T y p e R 8/16DeltaComp. + + bits marked as "0" MUST be 0 (they are reserved for future + extensions...) Every "1" must be considered as invalid or + unsupported feature (compressed by a newer version of MMCMP) + bits marked as "R" are reserved (used during compression processing + and they don't mean much within the file...) No check should be + performed on those bits. + + - Comp.: 0: not compressed + 1: compressed + - Delta: 0: data is not changed + 1: data is Delta (every byte or word is the difference + between itself and the previous one. First byte or word + is compared to 0. + - 8/16: 0: 8 bits compression scheme + 1: 16 bits compression scheme + - M/S: 0: mono + 1: stereo (not implemented yet) MUST BE 0 + + - Abs16 Whithin compression algorithm, 16 bits samples are + converted to deltas and transformed a bit so there's + no negative numbers. However, some trackers already + convert data to deltas, but there's still the little + transformation to do. + 0: don't do it + 1: do it + Note: This bit IS NOT checked if Delta bit is 1, but + should be 0 in this case. May only be set if + Delta bit is 0. + + - Type: This field doesn't really serve any purpose ;) but + helping identify type of data in this block. There's + no strict identifier but the following block types are + used by MMCMP (warning: do not expect the following to + always be true... data of different types for us (e.g + instrument header and sample header) may be interpreted + as the same type of block (they are contiguous, or + similar, etc...) for better compression.) The three + bits are stored in the order you would expect (MSB at + left, LSB at right) + + 0: Module identifier: the firsts bytes of a module + (this type must NOT be used for anything else...) + 1: Module header: anything useful in the header, which + is not in block-type 0 (actually not used by MMCMP) + 2: instrument header + 3: sample header + 4: patterns + 5: sample + 6: no definition yet... + 7: remaining (every part of the module that hasn't + been thrown into the "block list" (i.e probably + don't fit under any block types...) + + Note that MMCMP sorting scheme puts block of type 0 + first and type 7 last. This is also some sort of + priority. As for now, know that block of type 0 is + UNIQUE and is the FIRST. + + +Scanning files: + + 1. Check if installed and disable MMTSR + 2. Open module + 3. Check signature. If not 'ziRCONia' jump to 11 + 4. read "block offset table" offset field (dword at offset 18) + (and any other info you would like to read) + 5. jump to this position within the file + 6. read the first entry of the table (position of block 0) + 7. jump to this position within the file + 8. read the block header. + 9. If block-type field is not 0, jump to 6 and read the next entry + instead. (the first block should be of type 0. If not, there's + probably no block of this type...) + 10.Read the uncompressed data (it should not have the compressed flag + set) + 11.reenable MMTSR if installed + 12.Do what you would do with the header info and close module if you + wish... diff --git a/it/InternalDocumentation/NETWORK.TXT b/it/InternalDocumentation/NETWORK.TXT new file mode 100644 index 0000000..5b09dc5 --- /dev/null +++ b/it/InternalDocumentation/NETWORK.TXT @@ -0,0 +1,126 @@ + + Network protocol for Impulse Tracker + +Impulse Tracker will only interface with similar versions of IT. + +Block format + +Offset Size Meaning +0 Word Block type +2 Word Block length +4 Data Basic data, depending on block type. +x+[2] Word CRC Check + +Block types + + +Block type 0 - Acknowledge receipt - targeted + + +Offset Size Meaning +0 Word Block type received +2 Word Status + +Status: Bit 0 = Off = OK, On = resend + + +Block type 1 - Ping + + +Offset Size Meaning +0 String "Impulse Tracker 2.?? Ping Packet" + + +Block type 2 - Pattern data packet - global + + +Offset Size Meaning +0 Byte Pattern number +1 Byte Row +2 Byte Column +3 Byte Data mask +4 Varies Data + +Data mask + Bit 0: Note + Bit 1: Instrument + Bit 2: Volume + Bit 3: Effect + Bit 4: Effect data + +Absence of information does NOT imply clearing. + + +Block type 3 - Pattern data block packet - global + + +Offset Size Meaning +0 Byte Pattern number +1 Byte Block width +2 Byte Block height +3 Varies Data + +Data is a block_width * block_height array as structured: + +Data mask: + Bit 0: Note + Bit 1: Instrument + Bit 2: Volume + Bit 3: Effect + Bit 4: Effect data + +Absence of information DOES imply clearing. + + +Block type 4 - "Song Segment variable" modification - global + + +Offset Size Meaning +0 Word Offset in SongSegment +2 Word Length of data +4 Varies Data + + +Block type 5 - Sample data - global + + +Offset Size Meaning +0 Word Sample number +4 DWord Offset in sample +8 Varies Data + + +Block type 6 - Chat packet - targeted/global + + +Offset Size Meaning +0 Word Length of data +2 Varies Data + + + + Functions required of the drivers + + +Initialise - basic setup code. Return error if driver unavailable in current + environment. +Connect Interface - provides connection interface, sets up a tracking + connection, returns a handle +Management Interface - provides management interface for connection, + status information etc. +Disconnect - shut down a tracking connection to a particular handle +MaximumPacketSize - returns the maximum size in bytes that the driver can + process at any time. +Send data - given handle (0 = send to all), data packet (a maximum size as + returned by MaximumPacketsize) +Receive data poll - called frequently by the main program to check for + incoming data. Approx. 2nd highest priority (after + sound driver IRQ) + + + Functions provided to the drivers + + +ProcessDataReveived - called when any data is received. +UnloadDriver - remove driver from memory (when no connections exist any longer) +Alert - when data is not being transferred. diff --git a/it/InternalDocumentation/OBJECT.TXT b/it/InternalDocumentation/OBJECT.TXT new file mode 100644 index 0000000..ea0f0ad --- /dev/null +++ b/it/InternalDocumentation/OBJECT.TXT @@ -0,0 +1,233 @@ +Object Types + + Type 0: Box + Offset 0: DW 0 + Offset 2-5: DB Left/Top/Right/Bottom coordinates + Offset 6: DB Style. + + Style Variables + 0: Thin box, dark all around + 1: Thin box, light all around + 2: Thick box, dark all around + 3: Thick box, light all around + 4: Thin box, 'Up' + 5: Thin box, 'Down' + 6: Thick box, 'Up' + 7: Thick box, 'Down' + 8: Within thin box, 'Up' + 9: Within thin box, 'Down' + 10: Within thick box, 'Up' + 11: Within thick box, 'Down' + 12: Within thin box, dark } + 13: Within thin box, light } Empty boxes. + 14: Within thick box, dark } + 15: Within thick box, light } + +16 = empty within. + + Type 1: Text + Offset 0: DW 1 + Offset 2,3: DB X/Y coordinates + Offset 4: DB Colour + Offset 5: [Text] + + Type 2: Button + Offset 0: DW 2 + Offset 2-9: DW Up/Down/Left/Right associations + Offset 10: DW ButtonUsageType + Offset 12-15: [UsageType Data] + Offset 16: DW ButtonEffectType + Offset 18-27: [ButtonEffectType Data] + Offset 28-31: DB Left/Top/Right/Bottom coordinates + Offset 32: DB Button Style (refer to box style) + Offset 33: DB Button flags + Bit 0: Up/Down flag (0=up, 1=down) + Bit 1: + Offset 34: [Button Text] + + ButtonUsageType Variable + 0: Normal press-release buttons + Data: None + 1: Toggle press/release buttons + Data: None + 2: Radio button effect (one of selection) + Data: DW Min list range, Max list range + + ButtonEffectType + 0: Return Value + Data: DW Return Value + 1: New Object List + Data: DD DWord Ptr ObjectList + 2: Call Function + Data: DD DWord Ptr Function + 3: Set Button variable + Data: DW VariableOffset + DW Value + 4: Jump to Function + Data DD DWord Ptr Function + 5: Set variable + Data DD DWord Ptr Function, returning ES:DI with mem location + DW Value to set it to/check for + DW 2 * Value to pass to function + 6: Check variable, and jump to function + Data DD DWord Ptr Function, returning ES:DI with mem location + DW Value to set it to/check for + DD Function to jump to + + Type 3: Empty + Type 4: Empty + + Type 5: Select Direct Screen + Offset 0: DW 5 + Offset 2: DB Mode (0=Buffered, 1=Direct) + + Type 6: Redefine Characters + Offset 0: DW 6 + Offset 2: DW FirstCharacterToDefine + Offset 4: DW NumberOfCharactersToDefine + Offset 6: [CharacterDefinitionTable] + + Type 7: Empty + + Type 8: Call Far Function + Offset 0: DW 8 + Offset 2: DD DWord Ptr (Pre)Function + + Type 9: Thumb bar + Offset 0: DW 9 + Offset 2: DB X/Y coordinates + Offset 4: DW MinRange, MaxRange + Offset 8: DW WriteData1, WriteData2 + Offset 12: DW Up/Down/Tab/Shift-Tab associations + DW PgUp/PgDn + + WriteData1: + 0:Panning + 1:GetPEVariables + 2:Sample Variables + 3:GetMusicVariables (Song) + 4:Channel Volume settings + 5:LoadSampleVariables + 6:InstrumentVariables + 7:Screen Variables (eg. palette) + 8:Inst (segment) variable + 9:Driver segment, WriteData2 = offset + + Type 10: Infoline + Offset 0: DW 10 + Offset 2: [Text] + + Type 11: Set help context + Offset 0: DW 11 + Offset 2: DW HelpContextNumber + + Type 12: OrderListData + Offset 0: DW 12 + Offset 2: DB X/Y coordinates + Offset 4: DW Length of list (vertical) + Offset 6-9: DW Left/Right associations + + Type 13: 3 Num Entry + Offset 0: DW 13 + Offset 2: DB X/Y coordinates + Offset 4: DW Ptr Info 1 + Offset 6: DW Ptr Info 2 + Offset 8: DD DWord Ptr CheckFunction (0=none) + Offset 12: DW Up/Down/Right/Left associations + + Ptr Info 1: + 0: Instrument header. Ptr Info 2 = offset + + + Type 14: Scalable Thumb bar + Offset 0: DW 14 + Offset 2: DB X/Y coordinates + Offset 4: DW MinRange, MaxRange + Offset 8: DW WriteData1, WriteData2 + Offset 12: DW Up/Down/Tab/Shift-Tab associations + DW PgUp/PgDn + Offset 24 DW DisplayLength + + WriteData1: + 0:Panning + 1:GetPEVariables + 2:Sample Variables + 3:GetMusicVariables (Song) + 4:Channel Volume settings + 5:LoadSampleVariables + 6:InstrumentVariables + 7:Screen Variables (eg. palette) + 8:Inst (segment) variable + 9:Driver segment, WriteData2 = offset + + Type 15: Call Far Function 2 + Offset 0: DW 15 + Offset 2: DD DWord Ptr PreFunction + Offset 6: DD DWord Ptr DrawFunction + Offset 10: DD DWord Ptr Postfunction + + Type 16: String Input + Offset 0: DW 16 + Offset 2: DB X/Y coordinates + Offset 4: DW LocationFunctionNumber1, LocationFunctionNumber2 + Offset 8: DW Size (Length, including terminating null) + Offset 10: DD DWord Ptr FunctionOnEnter (0 = no function) + Offset 14: DW Up/Down/Tab/Shift-Tab associations + + LocationFunctionNumber1 + 0: Disk segment, LFN2 = Offset + 1: SamplePtr. + 2: Instrument segment, LFN2 = Offset + 3: Load Sample Ptr. + 4: Music (song) segment, LFN2 = offset + 5: Function segment, LFN2 = offset + 6: Instrument Ptr. + + Type 17: Toggle + Offset 0: DW 17 + Offset 2: DB X/Y coordinates + Offset 4: DW Ptr Info 1 + Offset 6: DW Ptr Info 2 + Offset 8: DB Bit Toggle + Offset 9: DW Up/Down/Right/Left associations + + Ptr Info 1: + 0: Sample header. Ptr Info 2 = offset in header. + 1: Pattern segment (code). Ptr Info 2 = offset. + 2: Music (song) segment. Ptr Info 2 = offset + 3: Load sample header. Ptr info 2 = offset in header. + 4: Instrument header. Ptr Info 2 = offset in header. + + Type 18: 5NumEntry + Offset 0: DW 18 + Offset 2: DB X/Y coordinates + Offset 4: DW Ptr Info 1 + Offset 6: DW Ptr Info 2 + Offset 8: DD DWord Ptr CheckFunction (0=none) + Offset 12: DW Up/Down/Right/Left associations + + Ptr Info 1: + 0: Sample header. Ptr Info 2 = offset. + 1: Sample load header. Ptr Info 2 = offset. + 2: Inst Segment (for sample resize). + + +Main menu return values. + 0: Function not handled + 1: Redraw screen + 2: Goto prefunction + 3: Goto keyboard input + 4: Handled, return value. + 5: New list in CX:DX, SI contains new action + +;------------ + +Special string data: + ; 0 = End of string + ; 13 = Next line + ; 10 = Toggle character sets + ; 0FFh, x, n = repeat character n 'x' times + ; 0FEh, x = set colour to x + ; 0FDh, 'D' = show decimal number + ; 0FDh, 'X' = show hex number + ; 0FDh, 'S' = show signed number + ; 0FDh, 'L' = show long number diff --git a/it/Keyboard/BE.ASM b/it/Keyboard/BE.ASM new file mode 100644 index 0000000..3f5f11f --- /dev/null +++ b/it/Keyboard/BE.ASM @@ -0,0 +1,637 @@ + + .model tiny + .code + +; Copyrights +; Impulse Tracker v2.14 *BELGIAN* Keyboard Definition File +; Copyright (C) 1998, SiDEWiNDER / DiMENSiON X +; +; You can use this source code as a base for your own keyboard driver, if you +; want to. (BUT NOT FOR A BELGIAN ONE OFCOURSE!!!!!) +; +; Read BE.TXT for more details!! +; +; Contact +; My Email: sidewind@mail.dma.be +; My Homepage: http://fly.to/SiDEWiNDER +; DiMENSiON X WHQ: http://travel.to/DiMENSiON.X +; +; Assembling +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; & + DB 0 + DW '&' + DB 3 ; 1 + DW '1' + DB 7 ; | + DW '|' + DB 0FFh + + DB 3 ; + DB 0 + DW '' + DB 3 ; 2 + DW '2' + DB 7 ; @ + DW '@' + DB 0FFh + + DB 4 ; " + DB 0 + DW '"' + DB 3 ; 3 + DW '3' + DB 7 ; # + DW '#' + DB 0FFh + + DB 5 ; ' + DB 0 + DW '''' + DB 3 ; 4 + DW '4' + DB 0FFh + + DB 6 ; ( + DB 0 + DW '(' + DB 3 ; 5 + DW '5' + DB 0FFh + + DB 7 ; paragraph, translated into $, should be OK... + DB 0 + DW '$' + DB 3 ; 6 + DW '6' + DB 7 ; ^ + DW '^' + DB 0FFh + + DB 8 ; + DB 0 + DW '' + DB 3 ; 7 + DW '7' + DB 0FFh + + DB 9 ; ! + DB 0 + DW '!' + DB 3 ; 8 + DW '8' + DB 0FFh + + DB 10 ; + DB 0 + DW '' + DB 3 ; 9 + DW '9' + DB 7 ; { + DW '{' + DB 0FFh + + DB 11 ; + DB 0 + DW '' + DB 3 ; 0 + DW '0' + DB 7 ; } + DW '}' + DB 0FFh + + DB 12 ; ) + DB 0 + DW ')' + DB 3 ; + DW '' + DB 0FFh + + DB 13 ; - + DB 0 + DW '-' + DB 3 ; _ + DW '_' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 17 ; Z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1Ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; (sirconflexe)-dead-key... + DB 0 + DW '^' + DB 3 ; (trema)-dead-key... + DW '' + DB 7 ; [ + DW '[' + DB 0FFh + + DB 27 ; $ + DB 0 + DW '$' + DB 3 ; * + DW '*' + DB 7 ; ] + DW ']' + DB 0FFh + + DB 30 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; M + DB 1 + DW 'M' + DB 2 ; m + DW 'm' + DB 0FFh + + DB 40 ; + DB 0 + DW '' + DB 3 ; % + DW '%' + DB 7 ; ` + DW '`' + DB 0FFh + + DB 41 ; + DB 0 + DW '' + DB 0FFh + + DB 43 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 7 ; ' + DW '''' + DB 0FFh + + DB 44 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; , + DB 0 + DW ',' + DB 1 + DW '?' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; ; + DB 0 + DW ';' + DB 3 ; . + DW '.' + DB 0FFh + + DB 52 ; : + DB 0 + DW ':' + DB 3 ; / + DW '/' + DB 0FFh + + DB 53 ; = + DB 0 + DW '=' + DB 3 ; + + DW '+' + DB 7 ; ~ + DW '~' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 3 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 86 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 7 ; \ + DW '\' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/CA.ASM b/it/Keyboard/CA.ASM new file mode 100644 index 0000000..88a3544 --- /dev/null +++ b/it/Keyboard/CA.ASM @@ -0,0 +1,609 @@ + .model tiny + .code +; +; Canadian french keyboard layout for IT by Delta X +; En passant: Salut tous les franais dans le monde!! :) +; +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; @ + DW '"' + DB 7 + DW '@' + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; # + DW '/' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; ^ + DW '?' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; & + DW '&' + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; * + DW '*' + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ( + DW '(' + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; ) + DW ')' + DB 0FFh + + DB 12 ; - + DB 0 + DW '-' + DB 3 ; _ + DW '_' + DB 0FFh + + DB 13 ; = + DB 0 + DW '=' + DB 3 ; + + DW '+' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; [ + DB 0 + DW '[' + DB 3 ; { + DW '{' + DB 7 + DW '[' + DB 0FFh + + DB 27 ; ] + DB 0 + DW ']' + DB 3 ; } + DW '}' + DB 7 + DW ']' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; ; + DB 0 + DW ';' + DB 3 ; : + DW ':' + DB 7 + DW '~' + DB 0FFh + + DB 40 ; ' + DB 0 + DW "`" + DB 3 ; " + DW "'" + DB 7 + DW '{' + DB 0FFh + + DB 41 ; ` + DB 0 + DW '#' + DB 3 ; ~ + DW '|' + DB 7 + DW '\' + DB 0FFh + + DB 43 ; \ + DB 0 + DW '<' + DB 3 ; | + DW '>' + DB 7 + DW '}' + DB 0FFh + + DB 44 ; z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1Ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW "'" + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW '>' + DB 0FFh + + DB 53 ; / + DB 0 + DW '' + DB 3 + DW '' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 3 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/CH.ASM b/it/Keyboard/CH.ASM new file mode 100644 index 0000000..f99397a --- /dev/null +++ b/it/Keyboard/CH.ASM @@ -0,0 +1,620 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; + + DW '+' + DB 7 ;| + DW '|' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; " + DW '"' + DB 7 ;@ + DW '@' + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; * + DW '*' + DB 7 + DW '#' ;# + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; + DW '' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; & + DW '&' + DB 7 + DW '' ; + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; / + DW '/' + DB 7 ; + DW '' + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; ( + DW '(' + DB 7 ; + DW '' + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ) + DW ')' + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; = + DW '=' + DB 0FFh + + DB 12 ; ' + DB 0 + DW "'" + DB 3 ; ? + DW '?' + DB 7 ; + DW '' + DB 0FFh + + DB 13 ; ^ + DB 0 + DW '^' + DB 3 ; ` + DW '`' + DB 7 ; ~ + DW '~' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1Ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 7 ;[ + DW '[' + DB 0FFh + + DB 27 ; + DB 0 + DW '' + DB 3 ; ! + DW '!' + DB 7 ; ] + DW ']' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 40 ; + DB 0 + DW "" + DB 3 ; + DW '' + DB 7 ;{ + DW '{' + DB 0FFh + + + DB 41 ; $ + DB 0 + DW '$' + DB 3 ; + DW '' + DB 7 ;} + DW '}' + DB 0FFh + + DB 43 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 7 ; \ + DW '\' + DB 0FFh + + DB 44 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW ';' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW ':' + DB 0FFh + + DB 53 ; / + DB 0 + DW '-' + DB 3 + DW '_' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 3 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/DE.ASM b/it/Keyboard/DE.ASM new file mode 100644 index 0000000..c0f202a --- /dev/null +++ b/it/Keyboard/DE.ASM @@ -0,0 +1,616 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; " + DW '"' + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; # + DW '#' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; & + DW '&' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; & + DW '/' + DB 7 + DW '{' ; { + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; ( + DW '(' + DB 7 + DW '[' ; [ + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ) + DW ')' + DB 7 + DW ']' ; ] + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; = + DW '=' + DB 7 + DW '}' ; } + DB 0FFh + + DB 12 ; + DB 0 + DW '' + DB 3 ; ? + DW '?' + DB 7 + DW '\' ; \ + DB 0FFh + + DB 13 ; ' + DB 0 + DW "'" + DB 3 ; ` + DW "`" + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 7 ; Alt-Gr-Q (Alt-Ctrl-Q) + DW '@' + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1ah + DB 5 ; Alt-Z + DW 2c00h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 27 ; + + DB 0 + DW '+' + DB 3 ; * + DW '*' + DB 7 + DW '~' ; ~ + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 40 ; + DB 0 + DW "" + DB 3 ; + DW '' + DB 0FFh + + DB 41 + DB 0 + DW "^" + DB 3 + DW "" + DB 0FFh + + DB 43 ; # + DB 0 + DW '#' + DB 3 ; ' + DW "'" + DB 0FFh + + DB 44 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW ';' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW ':' + DB 0FFh + + DB 53 ; - + DB 0 + DW '-' + DB 3 + DW '_' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 3 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 86 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 7 + DW '|' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/DK.ASM b/it/Keyboard/DK.ASM new file mode 100644 index 0000000..c9d68bd --- /dev/null +++ b/it/Keyboard/DK.ASM @@ -0,0 +1,616 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; " + DW '"' + DB 7 + DW "@" ; @ + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; # + DW '#' + DB 7 + DW '' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '' + DB 7 + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; & + DW '&' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; & + DW '/' + DB 7 + DW '{' ; { + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; ( + DW '(' + DB 7 + DW '[' ; [ + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ) + DW ')' + DB 7 + DW ']' ; ] + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; = + DW '=' + DB 7 + DW '}' ; } + DB 0FFh + + DB 12 ; + + DB 0 + DW '+' + DB 3 ; ? + DW '?' + DB 0FFh + + DB 13 ; ' + DB 0 + DW "" + DB 3 ; ` + DW "`" + DB 7 + DW '|' ; | + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Z + DW 19h + DB 5 ; Alt-Z + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 27 ; . + DB 0 + DW '' + DB 3 ; ~ + DW '^' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 40 ; + DB 0 + DW "" + DB 3 ; + DW '' + DB 0FFh + + DB 41 + DB 0 + DW "" + DB 3 + DW "" + DB 0FFh + + DB 43 ; * + DB 0 + DW "'" + DB 3 ; ' + DW "*" + DB 0FFh + + DB 44 ; Y + DB 1 + DW 'Z' + DB 2 ; y + DW 'z' + DB 4 ; Ctrl-Y + DW 1ah + DB 5 ; Alt-Y + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW ';' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW ':' + DB 0FFh + + DB 53 ; - + DB 0 + DW '-' + DB 3 + DW '_' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 43 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 7 + DW '\' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/ES.ASM b/it/Keyboard/ES.ASM new file mode 100644 index 0000000..40d3f58 --- /dev/null +++ b/it/Keyboard/ES.ASM @@ -0,0 +1,620 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 5 ; | + DW '|' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; " + DW '"' + DB 5 ; @ + DW '@' + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; + DW '' + DB 5 ; # + DW '#' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '$' + DB 5 ; ~ + DW '~' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; & + DW '&' + DB 5 ; + DW '' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; / + DW '/' + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; ( + DW '(' + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ) + DW ')' + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; = + DW '=' + DB 0FFh + + DB 12 ; ' + DB 0 + DW "'" + DB 3 ; ? + DW '?' + DB 0FFh + + DB 13 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; ` + DB 0 + DW '`' + DB 3 ; ^ + DW '^' + DB 5 ; [ + DW '[' + DB 0FFh + + DB 27 ; + + DB 0 + DW '+' + DB 3 ; * + DW '*' + DB 5 ; ] + DW ']' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 40 ; ' + DB 0 + DW "'" + DB 3 ; + DW '' + DB 5 ; { + DW '{' + DB 0FFh + + DB 41 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 5 ; \ + DW '\' + DB 0FFh + + DB 43 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 5 ; } + DW '}' + DB 0FFh + + DB 44 ; z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1Ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 ; ; + DW ';' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 ; : + DW ':' + DB 0FFh + + DB 53 ; - + DB 0 + DW '-' + DB 3 ; _ + DW '_' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 3 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 86 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/FI.ASM b/it/Keyboard/FI.ASM new file mode 100644 index 0000000..6c630a4 --- /dev/null +++ b/it/Keyboard/FI.ASM @@ -0,0 +1,618 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; " + DW '"' + DB 7 + DW "@" ; @ + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; # + DW '#' + DB 7 + DW '' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '' + DB 7 + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; & + DW '&' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; / + DW '/' + DB 7 + DW '{' ; { + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; ( + DW '(' + DB 7 + DW '[' ; [ + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ) + DW ')' + DB 7 + DW ']' ; ] + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; = + DW '=' + DB 7 + DW '}' ; } + DB 0FFh + + DB 12 ; + + DB 0 + DW '+' + DB 3 ; ? + DW '?' + DB 7 ; \ + DW '\' + DB 0FFh + + DB 13 ; ' + DB 0 + DW "" + DB 3 ; ` + DW "`" + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 27 ; . + DB 0 + DW '' + DB 3 ; ^ + DW '^' + DB 7 ; ~ + DW '~' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 40 ; + DB 0 + DW "" + DB 3 ; + DW '' + DB 0FFh + + DB 41 + DB 0 + DW "`" + DB 3 + DW "" + DB 0FFh + + DB 43 ; ' + DB 0 + DW "'" + DB 3 ; * + DW "*" + DB 0FFh + + DB 44 ; Z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 ; m + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 ; ; + DW ';' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 ; : + DW ':' + DB 0FFh + + DB 53 ; - + DB 0 + DW '-' + DB 3 ; _ + DW '_' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 86 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 7 + DW '|' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/FR.ASM b/it/Keyboard/FR.ASM new file mode 100644 index 0000000..88b4fed --- /dev/null +++ b/it/Keyboard/FR.ASM @@ -0,0 +1,613 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '&' + DB 3 ; ! + DW '1' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '' + DB 3 ; " + DW '2' + DB 7 + DW "~" ; @ + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '"' + DB 3 ; # + DW '3' + DB 7 + DW "#" + DB 0FFh + + DB 5 ; 4 + DB 0 + DW "'" + DB 3 ; $ + DW '4' + DB 7 + DW '{' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '(' + DB 3 ; % + DW '5' + DB 7 + DW '[' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '-' + DB 3 ; & + DW '6' + DB 7 + DW '|' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '' + DB 3 ; + DW '7' + DB 7 + DW '`' ; + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '_' + DB 3 ; + DW '8' + DB 7 + DW '\' ; + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '' + DB 3 ; + DW '9' + DB 7 + DW '^' ; + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '' + DB 3 ; = + DW '0' + DB 7 + DW '@' ; } + DB 0FFh + + DB 12 ; + + DB 0 + DW ')' + DB 3 ; ? + DW '' + DB 7 + DW ']' + DB 0FFh + + DB 13 ; ' + DB 0 + DW "=" + DB 3 ; ` + DW "+" + DB 7 + DW '}' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'A' + DB 2 ; q + DW 'a' + DB 4 ; Ctrl-Q + DW 1h + DB 5 ; Alt-Q + DW 1E00h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'Z' + DB 2 ; w + DW 'z' + DB 4 ; Ctrl-W + DW 19h + DB 5 ; Alt-W + DW 1500h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Z + DW 19h + DB 5 ; Alt-Z + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; + DB 0 + DW '^' + DB 3 ; + DW '' + DB 0FFh + + DB 27 ; . + DB 0 + DW '$' + DB 3 ; ~ + DW '' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'Q' + DB 2 ; a + DW 'q' + DB 4 ; Ctrl-A + DW 11h + DB 5 ; Alt-A + DW 1000h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; + DB 1 + DW 'M' + DB 2 ; + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 40 ; + DB 0 + DW "" + DB 3 ; + DW '%' + DB 0FFh + + DB 41 ; ' + DB 0 + DW "*" + DB 3 ; * + DW "" + DB 0FFh + + DB 43 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 0FFh + + DB 44 ; Y + DB 1 + DW 'W' + DB 2 ; y + DW 'w' + DB 4 ; Ctrl-Y + DW 17h + DB 5 ; Alt-Y + DW 1100h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 0 + DW ',' + DB 3 + DW '?' + DB 0FFh + + DB 51 ; , + DB 0 + DW ';' + DB 3 + DW '.' + DB 0FFh + + DB 52 ; . + DB 0 + DW ':' + DB 3 + DW '/' + DB 0FFh + + DB 53 ; - + DB 0 + DW '!' + DB 3 + DW '!' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/IT.ASM b/it/Keyboard/IT.ASM new file mode 100644 index 0000000..2c4e3a7 --- /dev/null +++ b/it/Keyboard/IT.ASM @@ -0,0 +1,588 @@ + .model tiny + .code + +; FIXED Italian keyboard configuration file for Impulse Tracker 2 +; fixed by DjM of Digital Things (DiT) +; why: Italian keyboard has no '`' key; with this configuration file +; note off command can be entered with '\' key (like in FastTracker 2) +; or with the similar ' (apostrophe) key +; to type \ and ' in message editor, use Right Alt + key + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 86 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; " + DW '"' + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; Chr(156) + DW 9Ch + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; & + DW '&' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; / + DW '/' + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; ( + DW '(' + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ) + DW ')' + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; = + DW '=' + DB 0FFh + + DB 12 ; ' used as ` + DB 0 + DW '`' + DB 3 ; ? + DW '?' + DB 7 ; to type ' in message editor + DW 27h + DB 0FFh + + DB 13 ; Chr(141) + DB 0 + DW 8Dh + DB 3 ; ^ + DW '^' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; Chr(138) + DB 0 + DW 8Ah + DB 3 ; Chr(130) + DW 82h + DB 7 ; [ + DW '[' + DB 0FFh + + DB 27 ; + + DB 0 + DW '+' + DB 3 ; * + DW '*' + DB 7 ; ] + DW ']' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; Chr(149) + DB 0 + DW 95h + DB 3 ; Chr(135) + DW 87h + DB 7 ; @ + DW '@' + DB 0FFh + + DB 40 ; Chr(133) + DB 0 + DW 85h + DB 3 ; Chr(248) + DW 0F8h + DB 7 ; # + DW '#' + DB 0FFh + + DB 41 ; \ used as ` + DB 0 + DW "`" + DB 3 ; | + DW "|" + DB 7 ; to type \ in message editor + DW '\' + DB 0FFh + + DB 43 ; Chr(151) + DB 0 + DW 97h + DB 3 ; Chr(21) + DW 15h + DB 0FFh + + DB 44 ; z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1Ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW ';' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW ':' + DB 0FFh + + DB 53 ; - + DB 0 + DW '-' + DB 3 ; _ + DW '_' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 3 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 83 ; keypad . + DB 8 + DW '.' + DB 0FFh + + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/KEYBOARD.TXT b/it/Keyboard/KEYBOARD.TXT new file mode 100644 index 0000000..3f70cfe --- /dev/null +++ b/it/Keyboard/KEYBOARD.TXT @@ -0,0 +1,12 @@ + +This ZIP contains several different keyboard configurations for Impulse +Tracker. To use a particular configuration file, copy the appropriate file +to KEYBOARD.CFG + +eg. to use a German keyboard configuration (DE.KBD), do + COPY DE.KBD KEYBOARD.CFG + +Make sure that KEYBOARD.CFG is in the same directory as IT.EXE + +An example of how to create your own keyboard file is included in the form +of US.ASM diff --git a/it/Keyboard/NO.ASM b/it/Keyboard/NO.ASM new file mode 100644 index 0000000..26484ea --- /dev/null +++ b/it/Keyboard/NO.ASM @@ -0,0 +1,614 @@ + + .model tiny + .code + +; This keyboard configuration created by Benjamin Bruheim + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; " + DW '"' + DB 7 + DW "@" ; @ + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; # + DW '#' + DB 7 + DW '' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '' + DB 7 + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; & + DW '&' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; & + DW '/' + DB 7 + DW '{' ; { + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; ( + DW '(' + DB 7 + DW '[' ; [ + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ) + DW ')' + DB 7 + DW ']' ; ] + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; = + DW '=' + DB 7 + DW '}' ; } + DB 0FFh + + DB 12 ; + + DB 0 + DW '+' + DB 3 ; ? + DW '?' + DB 0FFh + + DB 13 ; ' + DB 0 + DW "\" + DB 3 ; ` + DW "`" + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-y + DW 19h + DB 5 ; Alt-y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 27 ; . + DB 0 + DW '' + DB 3 ; ~ + DW '^' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; + DB 0 + DW "" + DB 3 ; + DW "" + DB 0FFh + + DB 40 ; + DB 0 + DW "" + DB 3 ; + DW "" + DB 0FFh + + DB 41 + DB 0 + DW "|" + DB 3 + DW "" + DB 0FFh + + DB 43 ; ' + DB 0 + DW "'" + DB 3 ; * + DW "*" + DB 0FFh + + DB 44 ; Z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-z + DW 1ah + DB 5 ; Alt-z + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW ';' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW ':' + DB 0FFh + + DB 53 ; - + DB 0 + DW '-' + DB 3 + DW '_' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 86 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/PO.ASM b/it/Keyboard/PO.ASM new file mode 100644 index 0000000..4ac21d5 --- /dev/null +++ b/it/Keyboard/PO.ASM @@ -0,0 +1,610 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 + DB 0 + DW '1' + DB 3 + DW '!' + DB 0FFh + + DB 3 + DB 0 + DW '2' + DB 3 + DW '"' + DB 5 + DW '@' + DB 0FFh + + DB 4 + DB 0 + DW '3' + DB 3 + DW '#' + DB 0FFh + + DB 5 + DB 0 + DW '4' + DB 3 + DW '$' + DB 0FFh + + DB 6 + DB 0 + DW '5' + DB 3 + DW '%' + DB 0FFh + + DB 7 + DB 0 + DW '6' + DB 3 + DW '&' + DB 0FFh + + DB 8 + DB 0 + DW '7' + DB 3 + DW '/' + DB 5 + DW '{' + DB 0FFh + + DB 9 + DB 0 + DW '8' + DB 3 + DW '(' + DB 5 + DW '[' + DB 0FFh + + DB 10 + DB 0 + DW '9' + DB 3 + DW ')' + DB 5 + DW ']' + DB 0FFh + + DB 11 + DB 0 + DW '0' + DB 3 + DW '=' + DB 5 + DW '}' + DB 0FFh + + DB 12 + DB 0 + DW '''' + DB 3 + DW '?' + DB 0FFh + + DB 13 + DB 0 + DW '<' + DB 3 + DW '>' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 + DB 0 + DW '+' + DB 3 + DW '*' + DB 0FFh + + DB 27 + DB 0 + DW '''' + DB 3 + DW '`' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 + DB 0 + DW 'c' ; porque o nao funciona no IT + DB 3 + DW 'C' ; porque o nao funciona no IT + DB 0FFh + + DB 40 + DB 0 + DW "o" ; porque o nao funciona no IT + DB 3 + DW 'a' ; porque o nao funciona no IT + DB 0FFh + + DB 41 + DB 0 + DW '\' + DB 3 + DW '|' + DB 0FFh + + DB 43 + DB 0 + DW '~' + DB 3 + DW '^' + DB 0FFh + + DB 44 ; z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1Ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 + DB 0 + DW ',' + DB 3 + DW ';' + DB 0FFh + + DB 52 + DB 0 + DW '.' + DB 3 + DW ':' + DB 0FFh + + DB 53 + DB 0 + DW '-' + DB 3 + DW '_' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 3 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 86 ; a new key generated by me, for + DB 0 ; the Portuguese keyboard. + DW '<' ; It's located between the + DB 3 ; LShift and the Z key... + DW '>' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/SE.ASM b/it/Keyboard/SE.ASM new file mode 100644 index 0000000..8b141cd --- /dev/null +++ b/it/Keyboard/SE.ASM @@ -0,0 +1,612 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; " + DW '"' + DB 7 + DW "@" ; @ + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; # + DW '#' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '$' + DB 7 + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; & + DW '&' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; & + DW '/' + DB 7 + DW '{' ; { + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; ( + DW '(' + DB 7 + DW '[' ; [ + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ) + DW ')' + DB 7 + DW ']' ; ] + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; = + DW '=' + DB 7 + DW '}' ; } + DB 0FFh + + DB 12 ; + + DB 0 + DW '+' + DB 3 ; ? + DW '?' + DB 0FFh + + DB 13 ; ' + DB 0 + DW "'" + DB 3 ; ` + DW "`" + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Z + DW 19h + DB 5 ; Alt-Z + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 27 ; . + DB 0 + DW '.' + DB 3 ; ~ + DW '~' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; + DB 0 + DW '' + DB 3 ; + DW '' + DB 0FFh + + DB 40 ; + DB 0 + DW "" + DB 3 ; + DW '' + DB 0FFh + + DB 41 + DB 0 + DW "^" + DB 3 + DW "+" + DB 0FFh + + DB 43 ; * + DB 0 + DW '*' + DB 3 ; ' + DW "'" + DB 0FFh + + DB 44 ; Y + DB 1 + DW 'Z' + DB 2 ; y + DW 'z' + DB 4 ; Ctrl-Y + DW 1ah + DB 5 ; Alt-Y + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW ';' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW ':' + DB 0FFh + + DB 53 ; - + DB 0 + DW '-' + DB 3 + DW '_' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 43 ; < + DB 0 + DW '<' + DB 3 ; > + DW '>' + DB 7 + DW '|' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/UK.ASM b/it/Keyboard/UK.ASM new file mode 100644 index 0000000..5896ee6 --- /dev/null +++ b/it/Keyboard/UK.ASM @@ -0,0 +1,596 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; " + DW '"' + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; + DW '' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; ^ + DW '^' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; & + DW '&' + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; * + DW '*' + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ( + DW '(' + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; ) + DW ')' + DB 0FFh + + DB 12 ; - + DB 0 + DW '-' + DB 3 ; _ + DW '_' + DB 0FFh + + DB 13 ; = + DB 0 + DW '=' + DB 3 ; + + DW '+' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; [ + DB 0 + DW '[' + DB 3 ; { + DW '{' + DB 0FFh + + DB 27 ; ] + DB 0 + DW ']' + DB 3 ; } + DW '}' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; ; + DB 0 + DW ';' + DB 3 ; : + DW ':' + DB 0FFh + + DB 40 ; ' + DB 0 + DW "'" + DB 3 ; @ + DW '@' + DB 0FFh + + DB 41 + DB 0 + DW "`" + DB 0FFh + + DB 43 ; # + DB 0 + DW '#' + DB 3 ; ~ + DW '~' + DB 0FFh + + DB 44 ; z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1Ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW '<' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW '>' + DB 0FFh + + DB 53 ; / + DB 0 + DW '/' + DB 3 + DW '?' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 86 ; \ + DB 0 + DW '\' + DB 3 ; | + DW '|' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/Keyboard/US.ASM b/it/Keyboard/US.ASM new file mode 100644 index 0000000..49a22d8 --- /dev/null +++ b/it/Keyboard/US.ASM @@ -0,0 +1,598 @@ + + .model tiny + .code + +; to create the file: +; TASM +; TLINK /TDC +; REN .COM KEYBOARD.CFG +; +; Structure is: +; Keycode (1 byte) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; Condition (1 byte) +; Return value (1 word) +; . +; . +; . +; 0FFh <-- end of condition/return value list +; +; Keycode is the value in the keypress table in IT on Ctrl-F1 (remember the +; values on the keypress table are in HEX..) +; +; Condition is one of the following +; 0 = requires NO Shift/Ctrl/Alt/..., +; 1 = if Shift and key while caps lock OFF *OR* CAPS lock ON, no ctrl/alt +; 2 = if Shift and key while caps lock ON *OR* CAPS lock OFF, no ctrl/alt +; 3 = if Shift +; 4 = if Ctrl +; 5 = if left/right Alt +; 6 = if Left Alt +; 7 = if Right Alt +; 8 = if Numlock on, no ctrl/alt +; 9 = if Numlock off, no ctrl/alt +; 0FFh = end of list. +; +; Return value is the character, or a DOS character value + +ORG 100h + +FileStart: + +FileLength DW Offset EndKeyboardTable - Offset StartKeyboardTable + +StartKeyboardTable: + + DB 2 ; 1 + DB 0 + DW '1' + DB 3 ; ! + DW '!' + DB 0FFh + + DB 3 ; 2 + DB 0 + DW '2' + DB 3 ; @ + DW '@' + DB 0FFh + + DB 4 ; 3 + DB 0 + DW '3' + DB 3 ; # + DW '#' + DB 0FFh + + DB 5 ; 4 + DB 0 + DW '4' + DB 3 ; $ + DW '$' + DB 0FFh + + DB 6 ; 5 + DB 0 + DW '5' + DB 3 ; % + DW '%' + DB 0FFh + + DB 7 ; 6 + DB 0 + DW '6' + DB 3 ; ^ + DW '^' + DB 0FFh + + DB 8 ; 7 + DB 0 + DW '7' + DB 3 ; & + DW '&' + DB 0FFh + + DB 9 ; 8 + DB 0 + DW '8' + DB 3 ; * + DW '*' + DB 0FFh + + DB 10 ; 9 + DB 0 + DW '9' + DB 3 ; ( + DW '(' + DB 0FFh + + DB 11 ; 0 + DB 0 + DW '0' + DB 3 ; ) + DW ')' + DB 0FFh + + DB 12 ; - + DB 0 + DW '-' + DB 3 ; _ + DW '_' + DB 0FFh + + DB 13 ; = + DB 0 + DW '=' + DB 3 ; + + DW '+' + DB 0FFh + + DB 14 ; Backspace + DB 4 ; Ctrl-Backspace + DW 127 + DB 0FFh + + DB 15 ; Tab + DB 3 ; ShiftTab + DW 0F00h + DB 0FFh + + DB 16 ; Q + DB 1 + DW 'Q' + DB 2 ; q + DW 'q' + DB 4 ; Ctrl-Q + DW 11h + DB 5 ; Alt-Q + DW 1000h + DB 0FFh + + DB 17 ; W + DB 1 + DW 'W' + DB 2 ; w + DW 'w' + DB 4 ; Ctrl-W + DW 17h + DB 5 ; Alt-W + DW 1100h + DB 0FFh + + DB 18 ; E + DB 1 + DW 'E' + DB 2 ;e + DW 'e' + DB 4 ; Ctrl-E + DW 5 + DB 5 ; Alt-E + DW 1200h + DB 0FFh + + DB 19 ; R + DB 1 + DW 'R' + DB 2 ; r + DW 'r' + DB 4 ; Ctrl-R + DW 12h + DB 5 ; Alt-R + DW 1300h + DB 0FFh + + DB 20 ; T + DB 1 + DW 'T' + DB 2 ; t + DW 't' + DB 4 ; Ctrl-T + DW 14h + DB 5 ; Alt-T + DW 1400h + DB 0FFh + + DB 21 ; Y + DB 1 + DW 'Y' + DB 2 ; y + DW 'y' + DB 4 ; Ctrl-Y + DW 19h + DB 5 ; Alt-Y + DW 1500h + DB 0FFh + + DB 22 ; U + DB 1 + DW 'U' + DB 2 ; u + DW 'u' + DB 4 ; Ctrl-U + DW 15h + DB 5 ; Alt-U + DW 1600h + DB 0FFh + + DB 23 ; I + DB 1 + DW 'I' + DB 2 ; i + DW 'i' + DB 4 ; Ctrl-I + DW 9 + DB 5 ; Alt-I + DW 1700h + DB 0FFh + + DB 24 ; O + DB 1 + DW 'O' + DB 2 ; o + DW 'o' + DB 4 ; Ctrl-O + DW 0Fh + DB 5 ; Alt-O + DW 1800h + DB 0FFh + + DB 25 ; P + DB 1 + DW 'P' + DB 2 ; p + DW 'p' + DB 4 ; Ctrl-P + DW 10h + DB 5 ; Alt-P + DW 1900h + DB 0FFh + + DB 26 ; [ + DB 0 + DW '[' + DB 3 ; { + DW '{' + DB 0FFh + + DB 27 ; ] + DB 0 + DW ']' + DB 3 ; } + DW '}' + DB 0FFh + + DB 30 ; A + DB 1 + DW 'A' + DB 2 ; a + DW 'a' + DB 4 ; Ctrl-A + DW 1 + DB 5 ; Alt-A + DW 1E00h + DB 0FFh + + DB 31 ; S + DB 1 + DW 'S' + DB 2 ; s + DW 's' + DB 4 ; Ctrl-S + DW 13h + DB 5 ; Alt-S + DW 1F00h + DB 0FFh + + DB 32 ; D + DB 1 + DW 'D' + DB 2 ; d + DW 'd' + DB 4 ; Ctrl-D + DW 4 + DB 5 ; Alt-D + DW 2000h + DB 0FFh + + DB 33 ; F + DB 1 + DW 'F' + DB 2 ; f + DW 'f' + DB 4 ; Ctrl-F + DW 6 + DB 5 ; Alt-F + DW 2100h + DB 0FFh + + DB 34 ; G + DB 1 + DW 'G' + DB 2 ; g + DW 'g' + DB 4 ; Ctrl-G + DW 7 + DB 5 ; Alt-G + DW 2200h + DB 0FFh + + DB 35 ; H + DB 1 + DW 'H' + DB 2 ; h + DW 'h' + DB 4 ; Ctrl-H + DW 8 + DB 5 ; Alt-H + DW 2300h + DB 0FFh + + DB 36 ; J + DB 1 + DW 'J' + DB 2 ; j + DW 'j' + DB 4 ; Ctrl-J + DW 0Ah + DB 5 ; Alt-J + DW 2400h + DB 0FFh + + DB 37 ; K + DB 1 + DW 'K' + DB 2 ; k + DW 'k' + DB 4 ; Ctrl-K + DW 0Bh + DB 5 ; Alt-K + DW 2500h + DB 0FFh + + DB 38 ; L + DB 1 + DW 'L' + DB 2 ; l + DW 'l' + DB 4 ; Ctrl-L + DW 0Ch + DB 5 ; Alt-L + DW 2600h + DB 0FFh + + DB 39 ; ; + DB 0 + DW ';' + DB 3 ; : + DW ':' + DB 0FFh + + DB 40 ; ' + DB 0 + DW "'" + DB 3 ; " + DW '"' + DB 0FFh + + DB 41 ; ` + DB 0 + DW '`' + DB 3 ; ~ + DW '~' + DB 0FFh + + DB 43 ; \ + DB 0 + DW '\' + DB 3 ; | + DW '|' + DB 0FFh + + DB 44 ; z + DB 1 + DW 'Z' + DB 2 ; z + DW 'z' + DB 4 ; Ctrl-Z + DW 1Ah + DB 5 ; Alt-Z + DW 2C00h + DB 0FFh + + DB 45 ; X + DB 1 + DW 'X' + DB 2 ; x + DW 'x' + DB 4 ; Ctrl-X + DW 1Ah + DB 5 ; Alt-X + DW 2D00h + DB 0FFh + + DB 46 ; C + DB 1 + DW 'C' + DB 2 ; c + DW 'c' + DB 4 ; Ctrl-C + DW 3 + DB 5 ; Alt-C + DW 2E00h + DB 0FFh + + DB 47 ; V + DB 1 + DW 'V' + DB 2 ; v + DW 'v' + DB 4 ; Ctrl-V + DW 16h + DB 5 ; Alt-V + DW 2F00h + DB 0FFh + + DB 48 ; B + DB 1 + DW 'B' + DB 2 ; b + DW 'b' + DB 4 ; Ctrl-B + DW 2 + DB 5 ; Alt-B + DW 3000h + DB 0FFh + + DB 49 ; N + DB 1 + DW 'N' + DB 2 ; n + DW 'n' + DB 4 ; Ctrl-N + DW 0Eh + DB 5 ; Alt-N + DW 3100h + DB 0FFh + + DB 50 ; M + DB 1 + DW 'M' + DB 2 + DW 'm' + DB 4 ; Ctrl-M + DW 0Dh + DB 5 ; Alt-M + DW 3200h + DB 0FFh + + DB 51 ; , + DB 0 + DW ',' + DB 3 + DW '<' + DB 0FFh + + DB 52 ; . + DB 0 + DW '.' + DB 3 + DW '>' + DB 0FFh + + DB 53 ; / + DB 0 + DW '/' + DB 3 + DW '?' + DB 0FFh + + DB 55 ; XT/AT printscreen, Enhanced keyboard * + DB 0 + DW '*' + DB 0FFh + + DB 57 ; Spacebar + DB 0 + DW ' ' + DB 3 + DW ' ' + DB 0FFh + + DB 71 ; Keypad 7 + DB 8 + DW '7' + DB 10 + DW 7 + DB 0FFh + + DB 72 ; Keypad 8 + DB 8 + DW '8' + DB 10 + DW 8 + DB 0FFh + + DB 73 ; Keypad 9 + DB 8 + DW '9' + DB 10 + DW 9 + DB 0FFh + + DB 74 ; Grey - + DB 0 + DW '-' + DB 0FFh + + DB 75 ; Keypad 4 + DB 8 + DW '4' + DB 10 + DW 4 + DB 0FFh + + DB 76 ; Keypad 5 + DB 8 + DW '5' + DB 10 + DW 5 + DB 0FFh + + DB 77 ; Keypad 6 + DB 8 + DW '6' + DB 10 + DW 6 + DB 0FFh + + DB 78 ; Grey + + DB 0 + DW '+' + DB 0FFh + + DB 79 ; Keypad 1 + DB 8 + DW '1' + DB 10 + DW 1 + DB 0FFh + + DB 80 ; Keypad 2 + DB 8 + DW '2' + DB 10 + DW 2 + DB 0FFh + + DB 81 ; Keypad 3 + DB 8 + DW '3' + DB 10 + DW 3 + DB 0FFh + + DB 82 ; Keypad 0 + DB 8 + DW '0' + DB 10 + DW 0 + DB 0FFh + + DB 83 + DB 8 + DW '.' + DB 0FFh + + DB 128+35h ; Grey / + DB 0 + DW '/' + DB 0FFh + + DB 0FFh + +EndKeyboardTable: + +End FileStart diff --git a/it/LICENSE.TXT b/it/LICENSE.TXT new file mode 100644 index 0000000..974fc09 --- /dev/null +++ b/it/LICENSE.TXT @@ -0,0 +1,25 @@ +Copyright © 2014, Jeffrey Lim. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/it/MAKEFILE.MAK b/it/MAKEFILE.MAK new file mode 100644 index 0000000..c00a2f8 --- /dev/null +++ b/it/MAKEFILE.MAK @@ -0,0 +1,9 @@ +IT.EXE: IT.OBJ IT_DISK.OBJ IT_DISPL.OBJ IT_EMS.OBJ IT_ERR.OBJ IT_F.OBJ IT_G.OBJ IT_H.OBJ \ +IT_I.OBJ IT_K.OBJ IT_L.OBJ IT_M.OBJ IT_NET.OBJ IT_MSG.OBJ IT_MUSIC.OBJ IT_NET.OBJ IT_OBJ1.OBJ IT_PE.OBJ IT_S.OBJ \ +IT_TUTE.OBJ IT_MMTSR.OBJ IT_MOUSE.OBJ IT_MDATA.OBJ IT_FOUR.OBJ IT_VESA.OBJ + tlink /3 /s /v @source.lst + +.ASM.OBJ: +# TASM /Zi /m /uT310 /jSMART $*.asm + TASM /m /uT310 /jSMART $*.asm + diff --git a/it/NETWORK.INC b/it/NETWORK.INC new file mode 100644 index 0000000..932f279 --- /dev/null +++ b/it/NETWORK.INC @@ -0,0 +1,32 @@ +IF NETWORKENABLED + Extrn Network_GetSendQueue:Far + Extrn Network_FinishedSendQueue:Far + Extrn Network_AddWordToQueue:Far + Extrn Network_EnsureNoNetwork:Far + Extrn Network_SendSampleHeader:Far + Extrn Network_SendInstrumentHeader:Far + Extrn Network_QueueSampleData:Far + Extrn Network_SendSongDataInformation:Far + +NETWORK_PARTIALPATTERNOBJECT EQU 0 +NETWORK_ENTIREPATTERNOBJECT EQU 1 +NETWORK_REQUESTPATTERNOBJECT EQU 2 +NETWORK_SONGDATAOBJECT EQU 3 +NETWORK_INSTRUMENTHEADEROBJECT EQU 4 +NETWORK_SAMPLEHEADEROBJECT EQU 5 +NETWORK_SETPATTERNLENGTH EQU 6 +NETWORK_DELETESAMPLEOBJECT EQU 7 + +EnsureNoNetwork EQU Call Network_EnsureNoNetwork +NetworkSendSample EQU Call Network_SendSampleHeader +NetworkSendInstrument EQU Call Network_SendInstrumentHeader + +ELSE + +EnsureNoNetwork EQU ; +NetworkSendSample EQU ; +NetworkSendInstrument EQU ; + +ENDIF + + diff --git a/it/Network/DEBUG.INC b/it/Network/DEBUG.INC new file mode 100644 index 0000000..93f45f6 --- /dev/null +++ b/it/Network/DEBUG.INC @@ -0,0 +1,130 @@ +; +; Debug macro. To write to the file, use "Trace " +; + +IF TRACEENABLED + +IF CREATENEWLOGFILE +FirstTime DB 0 +ENDIF + +LogFileName DB "Logfile.Txt", 0 + +; + +Proc WriteDebugFile + + PushA + Push DS + + Push CS + Pop DS + + Mov DX, Offset LogFileName + +IF CREATENEWLOGFILE + + Cmp DS:FirstTime, 0 + JNE WriteDebugFile1 + + Mov AH, 3Ch + Xor CX, CX + Int 21h + JC WriteDebugFileEnd + + Mov DS:FirstTime, 1 + XChg AX, BX + Jmp WriteDebugFile2 + + WriteDebugFile1: + +ENDIF + Mov AX, 3D02h + Int 21h + JC WriteDebugFileEnd + + XChg AX, BX + + Mov AX, 4202h + Xor CX, CX + Xor DX, DX + Int 21h ; Move to end of file + +WriteDebugFile2: + Mov AH, 40h + Mov CX, 82 + Mov DX, SI + Int 21h + + Mov AH, 3Eh + Int 21h + +WriteDebugFileEnd: + Pop DS + PopA + Ret + +EndP WriteDebugFile + +; + +Trace Macro LogMessage + Local X, Y + + PushF + Push SI + Jmp Y + X: + DB LogMessage + DB 80-($-Offset X) Dup (0) + DB 0Dh, 0Ah + Y: + Mov SI, Offset X + Call WriteDebugFile + Pop SI + PopF + + EndM + +; + +ELSE + +; + +Trace Macro LogMessage + EndM + +; + +ENDIF + +IF SCREENTRACEENABLED + +ScreenTrace Macro Value + Mov Byte Ptr [FS:0], Value + EndM + +ScreenTraceStart Macro + Push FS + Push 0B800h + Pop FS + EndM + +ScreenTraceEnd Macro + Pop FS + EndM + +ELSE + +ScreenTrace Macro Value + EndM + +ScreenTraceStart Macro + EndM + +ScreenTraceEnd Macro + EndM + +ENDIF + diff --git a/it/Network/DRHEAD.INC b/it/Network/DRHEAD.INC new file mode 100644 index 0000000..d4b0f37 --- /dev/null +++ b/it/Network/DRHEAD.INC @@ -0,0 +1,19 @@ + +NUMREQUIREDVARIABLES EQU 16 ; Number of bytes required from IT.EXE by Driver +NUMREQUIREDFUNCTIONS EQU 32 ; Number of functions (DD Offsets) required by + ; Network driver +NUMPROVIDEDVARIABLES EQU 16 ; Number of bytes provided from driver to IT.EXE +NUMPROVIDEDFUNCTIONS EQU 16 ; Number of functions (DW Offsets) provided by + ; Network driver + +ID DB "Impulse Tracker Network Driver" + DB 26 + DB (62 - ($-Offset ID)) Dup (0) + DB 13, 10 + +DriverID DB DRIVERIDSTRING + DB (62 - ($ - Offset DriverID)) Dup (0) + +LengthOfDriver DW Offset EndDriver - Offset StartDriver + + diff --git a/it/Network/EXECOM.COM b/it/Network/EXECOM.COM new file mode 100755 index 0000000000000000000000000000000000000000..dc9924543eea3e59ec6e2b36cf473010fdefd41e GIT binary patch literal 1248 zcmdT?-%Aux6drf?qHZW;AU>3w4T)rPTeB>6-PLT%#Wd*$Nn$YWUUg`k*=Fvz`DW}( zG!Q-ZScEURJuJ+_x(`|uk<|8}5Ya=W_98<;1z8l*xwDn{&>zsi%(?e`-#zDi-<_Xx zQ$psJ`E>PACIk~T^Eb)Hz9Poz%#`;{5RK?f#+oJ=`H%h_n8~HK-Wy}RPT&k z;cTKaxq;}6{X8eM=Q~Kjr;}{S+701uJuzQdk=Ys{|Bh!p*>Zc*{5;=4W{L1+I{m~m zjUU(abk=<}+(3FS7=xYZa1#-XGZ+tJ>`8}PFdV~eJH`;kHX^XHt2~q#`^?%yB3(Am;LOnpZJ^G2+lt%Ol|whPPctZxy%<u-%Td)}NrSs z2*>_%{|qC-geXf12t)^>&KStT!88gYz7nJ3I%xE=A!(8_iYr--i%e1#q;-PM#P}s% z2}Mc@O*qN8nxLT5(Q&GVpz6qoP90F862oo~MB(`5&R~(_+zu?uR25`V8>O%} z&~>U8QmP>*0PRsH@J#c;o_Zv2N=C(rf7y}JP>bW)rsH@RRrA7)fdc?tYI0JOM#mWJ zjn_kC%aInq8&t114: 16 bytes name followed by 12 bytes address (3 sets) +; Max size = 115 bytes. + +; Note: If Destination of Intro was FF:FF:FF:FF:FF:FF (ie. broadcast) +; Then a reply intro must be made + +; Remove: +; Offset 0: DB 2 ; Block type - size = 1 +; Called when a person gains a maximum limit of 3 extra connections +; Or does not wish to be listed in the IPX screen any further. + +; Quit: +; Offset 0: DB 3 ; Block type - size = 1 +; Called when a person unloads the IPX driver for any reason. +; Causes removal from group and removal from listings + +; Talk: +; Offset 0: DB 4 ; Block type, talk +; Offset 1: 16 bytes ; Sender name +; Offset 17: 60 bytes ; Message + +; Close connection ; Remove oneself from the group. +; Offset 0: DB 5 +; Causes removal from group + +; Request connection +; Offset 0: DB 6 +; Offset 1: 16 bytes ; Sender name +; Only nodes with no connections can request connections + +; Accept/Reject connection +; Offset 0: DB 7 +; Offset 1: DB Number of connections including this one. 0 = reject +; Offset 2: Other user information (name (16), full address(12)) +; Reply from requested node. + +; Confirm connection +; Offset 0: DB 8 +; Offset 1: DB Confirm 0 = cancelled +; Offset 2: UserName (16), Full Address (12) +; Add this to the connection list +; Send out this information to anyone already connected to this group. + +; Request intro +; Offset 0: DB 9 + +; Notes: +; The IPX driver will automatically open port 'IT' (4945h) to listen +; for general/maintenance broadcasts (Socket1). Listening packets at +; socket 2 will (only) receive a maximum of 128 bytes. +; A dedicated (dynamically allocated) socket will be used for all music data. +; (Socket2). Socket2 will be able to receive the MAXDATASIZE (1024 bytes) +; Initiate/Terminate connection requests are handled through Socket1 +; Once established, the IPX driver will use 4 packets for listening. +; Each send packet will be timestamped in order to have a maximum timeout, +; after which an error message is generated, giving the user the option to +; drop the participant. +; Acknowledgement packets will be sent for everything received at Socket2 to +; Socket1 of the sender. + +; Required functions: +; GetBuffer(NumberOfBytes) - returns pointer +; SetBuffer(NumberOfBytes, Data) +; GetTimer - returns number of ticks since program startup in EAX. +; Generic Function Handler +; S_GetDestination +; S_DrawString +; SetInfoLine + +; Variables required: +; GlobalKeyList + +; Provided functions: +; DriverScreen +; Poll (Update procedure) + +; Note: IT's network handler will send data to: +; either 0 -> everyone +; or individual connections. +; + +MAXIMUMUSERS EQU 4 +TIMEOUT EQU 10 +SENDTIMEOUT EQU 182 ; 10 seconds +RETRYTIMEOUT EQU 36 ; 2 seconds +MAINTENANCETIMEOUT EQU 18 ; 1 second + +TRACEENABLED EQU 0 +SCREENTRACEENABLED EQU 0 +CREATENEWLOGFILE EQU 1 + +;Ŀ +; Externals +; + +; + + +; + +Segment IPX PARA Public 'Code' USE16 + Assume CS:IPX, DS:Nothing, ES:Nothing + +ORG 0 +StartDriver: + +include vtable.inc +include reqproc.inc + +IPXEntryAddress Label DWord + DW Offset F_Nothing ; Done so that it won't crash if there's +Seg14 DW 0 ; no IPX due to call to Poll + +IPXMaximumPacketSize DW 0 +IPXRetryCount DW 0 + +IntroBlockInformation Label ; **************************************** + DB 1 ; Block type +NumberOfConnections DB 0 + +IF FIXEDUSERNAME + include username.inc +ELSE + CONFIGURATIONOFFSET EQU $+128 + CONFIGURATIONSIZE EQU 16 + UserName DB 16 Dup (0) + IPXLocalAddress Label + IPXNetworkAddress DD 0 ; Do not change order + IPXNodeAddress DW 0, 0, 0 ; + IPXSocket DW 0 ; Dynamic socket +ENDIF + +UserName1 DB 16 Dup (0) +UserAddress1 DB 10 Dup (0) +UserSocket1 DW 0 +UserName2 DB 16 Dup (0) +UserAddress2 DB 10 Dup (0) +UserSocket2 DW 0 +UserName3 DB 16 Dup (0) +UserAddress3 DB 10 Dup (0) ; size = 26*4+2=106 +UserSocket3 DW 0 + +AcknowledgementBlockInformation Label ; ************************************ + DB 0 +PacketID DB 0 ; Size = 2 + +ByteBlockInformation Label +ByteBlock DB 0 + +OldNumberOfConnections DB 0 + +MessageReceived DB 0 +IFE FIXEDUSERNAME +DriverName DB "ITIPX.NET", 0 +ENDIF + +ALIGN 2 + +OldNumNodes DW 0 +NumNodes DW 0 +TopNode DW 0 +CurrentNode DW 0 + +NoReply DB 0 +SendingData DB 0 +SendTime DD 0 +RetryTime DD 0 +LastPacketSize DW 0 + +; ---- Interface stuff -------------------------------------------------------- + +RequestConnectionBox DW 0 + DB 27, 24, 54, 32 + DB 3 + +RequestConnectionText DW 1 + DB 29, 27 + DB 20h + DB "Connection request from:", 13 + DB " " +ConnectionRequestName DB 16 Dup (0) +ConnectionRequestAddress DB 12 Dup (0) +ConnectionRequest DB 0 ; Bit 0 = requesting a connection + ; Bit 1 = connection requested, waiting + ; for reply. + ; Bit 2 = connection accepted, waiting + ; for verification. + ; Bit 7 = leave connetion request box + +IPXHeaderText DW 1 + DB 36, 25 + DB 23h + DB "IPX Driver", 0 + +AcceptButton DW 2 + DW 0FFFFh, 0FFFFh, 4, 4 + DW 0 + DW 0, 0 + DW 0 + DW 1 ; Returns 1 + DW 0, 0, 0, 0 + DB 28, 29, 39, 31 + DB 8 + DB 0 + DB " Accept", 0 + +RejectButton DW 2 + DW 0FFFFh, 0FFFFh, 3, 3 + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 41, 29, 52, 31 + DB 8 + DB 0 + DB " Reject", 0 + +ConnectionRequestList DW 3 + DW IdleFunctionList2 + DW ESCReturn0List + DW RequestConnectionBox + DW IPXHeaderText + DW RequestConnectionText + DW AcceptButton + DW RejectButton + DW 0 + +WaitforConnectList DW 2 + DW IdleFunctionList2 ; Needs check for connection + DW ESCReturn0List ; No global keys. + DW NoIPXBox + DW WaitforConnectText + DW CancelButton + DW 0 + +ConnectionRejectedList DW 2 + DW IdleFunctionList + DW ESCReturn0List + DW NoIPXBox + DW ConnectionRejectedText + DW OKButton + DW 0 + +ConnectionCancelledList DW 2 + DW IdleFunctionList + DW ESCReturn0List + DW NoIPXBox + DW ConnectionCancelledText + DW OKButton + DW 0 + +WaitforConnectText DW 1 + DB 28, 27 + DB 20h + DB "Requesting Connection...", 0 + + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +NoIPXBox DW 0 + DB 25, 25, 54, 32 + DB 3 + +NoIPXText DW 1 + DB 28, 27 + DB 20h + DB "IPX Network not detected", 0 + +ConnectionRejectedText DW 1 + DB 31, 27 + DB 20h + DB "Connection refused", 0 + +ConnectionCancelledText DW 1 + DB 30, 27 + DB 20h + DB "Connection cancelled", 0 + +NoSocketText DW 1 + DB 27, 27 + DB 20h + DB "IPX Socket request failure", 0 + +IFE FIXEDUSERNAME +UserNameBox DW 0 + DB 31, 29, 48, 31 + DB 27 + +UserNameText DW 1 + DB 29, 27 + DB 20h + DB "Please enter your name", 0 +ENDIF + +ESCReturn0List DB 0 + DW 101h + DW Offset F_Return0 +KeyListSeg1 DW 0 + DB 0FFh + +IFE FIXEDUSERNAME +UserNameInput DW 16 + DB 32, 30 +StringSeg1 DW 0 + DW Offset UserName + DW 16 + DW Offset F_Return1 +StringSeg2 DW 0 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh +ENDIF + +FillHeader DW 8 +FillHeader2 DD 0 + +DrawHeader DW 8 +DrawHeader2 DD 0 + +OKButton DW 2 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 35, 29, 44, 31 + DB 8 + DB 0 + DB " OK", 0 + +CancelButton DW 2 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 0 + DW 0 ; Returns 0 + DW 0, 0, 0, 0 + DB 34, 29, 45, 31 + DB 8 + DB 0 + DB " Cancel", 0 + +SocketErrorList DW 2 + DW Near Ptr IdleFunctionList + DW 0 + DW Near Ptr NoIPXBox + DW Near Ptr NoSocketText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +NoIPXMessageList DW 2 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturn0List + DW Near Ptr NoIPXBox + DW Near Ptr NoIPXText + DW Near Ptr OKButton + DW Near Ptr FillHeader + DW 0 + +IFE FIXEDUSERNAME +IPXGetName Label + DW 5 + DW Near Ptr IdleFunctionList + DW Near Ptr ESCReturn0List + + DW Near Ptr DrawHeader + DW Near Ptr FillHeader + DW Near Ptr NoIPXBox + DW Near Ptr UserNameText + DW Near Ptr UserNameBox + DW Near Ptr UserNameInput + + DW 0 +ENDIF + +IPXConnectedScreen Label + DW 5 + DW Near Ptr IdleFunctionList2 + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox + DW Near Ptr DrawHeader + DW Near Ptr FillHeader + DW Near Ptr IPXHeader + + DW Near Ptr ConnectionDetailMsg + DW Near Ptr LeaveSessionButton + DW Near Ptr ShowConnectionDetails + + DW Near Ptr MessageBox + DW Near Ptr MessageEnterBox + DW Near Ptr SendMessageText + DW Near Ptr GroupMessageInput + + DW Near Ptr ShowConnectMessages + DW Near Ptr PacketsSentMessage + DW Near Ptr PacketsReceivedMessage + DW Near Ptr PacketsFailedMessage + DW Near Ptr PacketsRetryMessage + DW Near Ptr PacketsAckMessage + + DW 0 + +PacketsSentMessage DW 1 + DB 2, 33 + DB 20h + DB "Packets sent: ", 0FDh, "D", 0 +PacketsSent DW 0 + +PacketsReceivedMessage DW 1 + DB 2, 34 + DB 20h + DB "Packets rcvd: ", 0FDh, "D", 0 +PacketsReceived DW 0 + +PacketsFailedMessage DW 1 + DB 2, 35 + DB 20h + DB "Packets fail: ", 0FDh, "D", 0 +PacketsFailed DW 0 + +PacketsRetryMessage DW 1 + DB 2, 36 + DB 20h + DB "Packets rtry: ", 0FDh, "D", 0 +PacketsRetry DW 0 + +PacketsAckMessage DW 1 + DB 2, 32 + DB 20h + DB "Acks Rcvd: ", 0FDh, "D", 0 +PacketsAck DW 0 + +ConnectionDetailMsg DW 1 + DB 2, 13 + DB 23h + DB "Connection Details", 0 + +LeaveSessionButton DW 2 + DW 10, 10, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 4 + DW Offset IPX_LeaveSession +Seg19 DW 0 + DW 0, 0, 0 + DB 61, 12, 78, 14 + DB 8 + DB 0 + DB " Leave", 0 + +ShowConnectionDetails DW 8 + DW Offset IPX_ShowConnectionDetails +Seg20 DW 0 + +IPXScreen Label + DW 5 + DW Near Ptr IdleFunctionList2 + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox + DW Near Ptr DrawHeader + DW Near Ptr FillHeader + DW Near Ptr IPXHeader + + DW Near Ptr NodeBox + DW Near Ptr ConnectNetworkList + + DW Near Ptr UnloadDriverButton + + DW Near Ptr MessageBox + DW Near Ptr MessageEnterBox + DW Near Ptr SendMessageText + DW Near Ptr ConnectMessageInput + + DW Near Ptr ShowConnectMessages + + DW 0 + +IPXQueueScreen DW 0 + +IPXHeader DW 10 + DB "IPX Network Driver", 0 + +NodeBox DW 0 + DB 2, 12, 52, 36 + DB 27 + +MessageBox DW 0 + DB 2, 37, 78, 46 + DB 27 + +MessageEnterBox DW 0 + DB 15, 47, 78, 49 + DB 27 + +SendMessageText DW 1 + DB 3, 48 + DB 20h + DB "Send Message", 0 + +ConnectMessageInput DW 16 ; String input + DB 16, 48 +Seg16 DW 0 + DW Offset MessageEntryArea + DW 56 + DW Offset IPX_SendMessage +Seg17 DW 0 + DW 5, 5, 5, 6 + +GroupMessageInput DW 16 ; String input + DB 16, 48 +Seg21 DW 0 + DW Offset MessageEntryArea + DW 56 + DW Offset IPX_SendGroupMessage +Seg22 DW 0 + DW 5, 5, 5, 6 + +ShowConnectMessages DW 8 + DW Offset IPX_DisplayMessages +Seg18 DW 0 + +UnloadDriverButton DW 2 + DW 0FFFFh, 10, 5, 10 + DW 0 + DW 0, 0 + DW 4 + DW Offset IPX_Shutdown +Seg15 DW 0 + DW 0, 0, 0 + DB 61, 12, 78, 14 + DB 8 + DB 0 + DB " Disconnect", 0 + +IdleFunctionList DD 0 + DD 0 + +ConnectNetworkList DW 15 +DrawConnectNetworkList DW Offset IPX_DrawConnect +Seg11 DW 0 +PreConnectNetworkList DW Offset IPX_PreConnect +Seg12 DW 0 +PostConnectNetworkList DW Offset IPX_PostConnect +Seg13 DW 0 + +IdleFunctionList2 DD 0 + DW Offset IdleCheck +IdleSeg DW 0 + DD 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +Label ConnectKeys Byte + DB 0 + DW 1C8h ; Up arrow + DW IPX_ConnectUp + + DB 0 + DW 1D0h ; Down arrow + DW IPX_ConnectDown + + DB 0 ; PgUp + DW 1C9h + DW IPX_ConnectPgUp + + DB 0 ; PgDn + DW 1D1h + DW IPX_ConnectPgDn + + DB 0 + DW 1C7h + DW IPX_ConnectHome + + DB 0 + DW 1CFh + DW IPX_ConnectEnd + + DB 0 ; Tab + DW 10Fh + DW IPX_ConnectTab + + DB 0 + DW 11Ch + DW IPX_ConnectEnter + + DB 0FFh + +; + +MessageBlock DB 4 +MessageSenderName DB 16 Dup (0) +MessageEntryArea DB 56 Dup (0) + +MessageData DB 72*8 Dup (0) + +InfoListMessage DB 64 Dup (0) +ConnectionNumberMsg DB "Connection Number ", 0FDh, "D", 0Dh + DB " User name: ", 0 +ConnectionAddressMsg DB " User address: ", 0 +UnknownPacketMessage DB "IPX Error: Unknown Packet Type Received", 0 + +; This prompt needs to be reworded. +AutoRejectMessage DB "IPX AutoRejectConnection: " +ClosedMessage DB "IPX ClosedConnection: " +AutoDropMessage DB "IPX DropConnection: " + +; + +Macro_MaintenanceRHeader Macro Index + MaintenanceRHeader&Index& Label + DW 0 ; Checksum + DW 0 ; Length + DB 0 ; Transport Control + DB 4 ; Packet type + DB 12 Dup (0) ; Destination Address + DB 12 Dup (0) ; Source Address + MaintenanceRData&Index& Label + DB 128 Dup (0) + +EndM + + IndexCounter = 1 + Rept 4 + Macro_MaintenanceRHeader %IndexCounter + IndexCounter = IndexCounter+1 + EndM + +MaintenanceSendHeaderBroadcast Label + DW 0 ; Checksum + DW 0 ; Length + DB 0 ; Transport Control + DB 4 ; Packet type + DB 0, 0, 0, 0 ; Destination net address + DB 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh ; Node address - broadcast + DW 'IT' ; Destination socket + DB 12 Dup (0) ; Source Address + +MaintenanceSendHeaderDirected Label + DW 0 ; Checksum + DW 0 ; Length + DB 0 ; Transport Control + DB 4 ; Packet type +MaintenanceDirectedDestination Label + DB 12 Dup (0) ; Destination address + DB 12 Dup (0) ; Source Address + +MaintenanceECB1 Label + DD 0 ; Link Address - IPX controlled + DW Offset MaintenanceESR +MESeg1 DW 0 + DB 0 ; In use flag - IPX controlled + DB 0 ; Completion code - IPX controlled + DW 'IT' ; Socket Number - Required + DB 16 Dup (0) ; IPX workspace - IPX controlled + DB 6 Dup (0) ; Immediate address - IPX controlled + DW 2 ; Fragment count - Required + DW Offset MaintenanceRHeader1 +Seg1 DW 0 + DW 30 ; Fragment size 1 + DW Offset MaintenanceRData1 +Seg2 DW 0 + DW 128 ; Fragment size 2 + +MaintenanceECB2 Label + DD 0 ; Link Address - IPX controlled + DW Offset MaintenanceESR +MESeg2 DW 0 + DB 0 ; In use flag - IPX controlled + DB 0 ; Completion code - IPX controlled + DW 'IT' ; Socket Number - Required + DB 16 Dup (0) ; IPX workspace - IPX controlled + DB 6 Dup (0) ; Immediate address - IPX controlled + DW 2 ; Fragment count - Required + DW Offset MaintenanceRHeader2 +Seg3 DW 0 + DW 30 ; Fragment size 1 + DW Offset MaintenanceRData2 +Seg4 DW 0 + DW 128 ; Fragment size 2 + +MaintenanceECB3 Label + DD 0 ; Link Address - IPX controlled + DW Offset MaintenanceESR +MESeg3 DW 0 + DB 0 ; In use flag - IPX controlled + DB 0 ; Completion code - IPX controlled + DW 'IT' ; Socket Number - Required + DB 16 Dup (0) ; IPX workspace - IPX controlled + DB 6 Dup (0) ; Immediate address - IPX controlled + DW 2 ; Fragment count - Required + DW Offset MaintenanceRHeader3 +Seg5 DW 0 + DW 30 ; Fragment size 1 + DW Offset MaintenanceRData3 +Seg6 DW 0 + DW 128 ; Fragment size 2 + +MaintenanceECB4 Label + DD 0 ; Link Address - IPX controlled + DW Offset MaintenanceESR +MESeg4 DW 0 + DB 0 ; In use flag - IPX controlled + DB 0 ; Completion code - IPX controlled + DW 'IT' ; Socket Number - Required + DB 16 Dup (0) ; IPX workspace - IPX controlled + DB 6 Dup (0) ; Immediate address - IPX controlled + DW 2 ; Fragment count - Required + DW Offset MaintenanceRHeader4 +Seg7 DW 0 + DW 30 ; Fragment size 1 + DW Offset MaintenanceRData4 +Seg8 DW 0 + DW 128 ; Fragment size 2 + +MaintenanceSendECB Label + DD 0 ; Link Address - IPX controlled + DD 0 +SendECBInUse Label Byte + DB 0 ; In use flag - IPX controlled + DB 0 ; Completion Code - IPX controlled + DW 'IT' ; Socket Number - Required + DB 16 Dup (0) ; IPX workspace - IPX controlled +MSendDest DB 6 Dup (0FFh); Immediate address - broadcast + DW 2 ; Fragment count - Required +MaintenanceSendHeader DW 0 +Seg9 DW 0 + DW 30 ; Fragment size 1 +MaintenanceSendDataOffset DW 0 +Seg10 DW 0 +MaintenanceSendDataSize DW 0 + +; + +MaintenanceSData DB 128 Dup (0) + +; + + +;Data packet definitions. + +Zero DB 0 +Ten DB 10 + +NUMBEROFLISTENINGPACKETS EQU 4 +MAXDATASIZE EQU 1024 + +Macro_DataReceiveBlock Macro Index + DataReceiveHeader&Index& Label + DW 0 ; Checksum + DW 0 ; Length + DB 0 ; Transport Control + DB 4 ; Packet type + DB 12 Dup (0) ; Destination Address + DB 12 Dup (0) ; Source Address + DataReceive&Index& Label + DB MAXDATASIZE Dup (0) + + DataReceiveECB&Index& Label + DD 0 ; Link Address -IPX controlled + DW Offset DataESR + DataSegA&Index& DW 0 + DB 0 ; In use flag -IPX controlled + DB 0 ; Completion code-IPX controlled + DSocket&Index& DW 0 ; Socket Number -Required + DB 16 Dup (0) ; IPX workspace -IPX controlled + DB 6 Dup (0) ; Immediate addr -IPX controlled + DW 2 ; Fragment count -Required + DW Offset DataReceiveHeader&Index& + DataSegB&Index& DW 0 + DW 30 ; Fragment Size 1 + DW Offset DataReceive&Index& + DataSegC&Index& DW 0 + DW MAXDATASIZE ; Fragment size 2 + +EndM + +Macro_SendAckBlock Macro Index + + SendAckHeader&Index& Label + DW 0 ; Checksum + DW 0 ; Length + DB 0 ; Transport Control + DB 4 ; Packet type + DB 10 Dup (0) ; Destination Address + DW 'IT' + DB 12 Dup (0) ; Source Address + + SendAckECB&Index& Label + DD 0 ; Link Address -IPX controlled + DD 0 ; ESR Address -None + DB 0 ; In use flag -IPX controlled + DB 0 ; Completion code-IPX controlled + DW 'IT' ; Socket Number -Required + DB 16 Dup (0) ; IPX workspace -IPX controlled + DB 6 Dup (0) ; Immediate addr -IPX controlled + DW 2 ; Fragment count -Required + DW Offset SendAckHeader&Index& + SendAckA&Index& DW 0 + DW 30 ; Fragment Size 1 + DW Offset Zero ; Offset 42 = 2Ah + SendAckB&Index& DW 0 + DW 1 + +EndM + + IndexCounter = 1 + Rept NUMBEROFLISTENINGPACKETS + Macro_DataReceiveBlock %IndexCounter + IndexCounter = IndexCounter + 1 + EndM + + IndexCounter = 1 + Rept (MAXIMUMUSERS-1) + Macro_SendAckBlock %IndexCounter + IndexCounter = IndexCounter + 1 + EndM + + +Macro_DataSendBlock Macro Index + DataSendHeader&Index& Label + DW 0 ; Checksum + DW 0 ; Length + DB 0 ; Transport Control + DB 4 ; Packet type + DB 12 Dup (0) ; Destination Address + DB 12 Dup (0) ; Source Address + + DataSendECB&Index& Label + DD 0 ; Link Address -IPX controlled + DW Offset SendDataESR + SDataSegA&Index& DW 0 + DB 0 ; In use flag -IPX controlled + SResult&Index& DB 0 ; Completion code-IPX controlled + SDSocket&Index& DW 0 ; Socket Number -Required + DB 16 Dup (0) ; IPX workspace -IPX controlled + DB 6 Dup (0) ; Immediate addr -IPX controlled + DW 2 ; Fragment count -Required + DW Offset DataSendHeader&Index& + SDataSegB&Index& DW 0 + DW 30 ; Fragment Size 1 + DW Offset DataSend + SDataSegC&Index& DW 0 + DW MAXDATASIZE ; Fragment size 2 +EndM + + DataSend DB MAXDATASIZE Dup (0) + + IndexCounter = 1 + Rept 3 + Macro_DataSendBlock %IndexCounter + IndexCounter = IndexCounter + 1 + EndM + +; +; RELOCATION TABLE +; + +Macro_DataSegments Macro Index + DW Offset DataSegA&Index& + DW Offset DataSegB&Index& + DW Offset DataSegC&Index& +EndM + +Macro_AckSegments Macro Index + DW Offset SendAckA&Index& + DW Offset SendAckB&Index& +EndM + +Macro_SDataSegments Macro Index + DW Offset SDataSegA&Index& + DW Offset SDataSegB&Index& + DW Offset SDataSegC&Index& +EndM + +RelocationTable Label Word + DW Offset Seg1, Offset Seg2, Offset Seg3, Offset Seg4 + DW Offset Seg5, Offset Seg6, Offset Seg7, Offset Seg8 + DW Offset Seg9, Offset Seg10 +IFE FIXEDUSERNAME + DW Offset StringSeg1, Offset StringSeg2 +ENDIF + DW Offset MESeg1, Offset MESeg2, Offset MESeg3, Offset MESeg4 + Dw Offset KeyListSeg1, Offset IdleSeg, Offset Seg11, Offset Seg12 + DW Offset Seg13, Offset Seg14, Offset Seg15, Offset Seg16 + DW Offset Seg17, Offset Seg18, Offset Seg19, Offset Seg20 + DW Offset Seg21, Offset Seg22 + + IndexCounter = 1 + Rept NUMBEROFLISTENINGPACKETS + Macro_DataSegments %IndexCounter + IndexCounter = IndexCounter + 1 + EndM + + IndexCounter = 1 + Rept (MAXIMUMUSERS-1) + Macro_AckSegments %IndexCounter + IndexCounter = IndexCounter + 1 + EndM + + IndexCounter = 1 + Rept 3 + Macro_SDataSegments %IndexCounter + IndexCounter = IndexCounter + 1 + EndM + + DW 0 + +; + +include debug.inc + +; + +Proc F_Nothing Far + + Xor AX, AX + Ret + +EndP F_Nothing + +; + +Proc F_Return0 Far + + Xor DX, DX + Mov AX, 4 + + Ret + +EndP F_Return0 + +; + +Proc F_Return1 Far + + Cmp Byte Ptr [CS:UserName], 0 + JE F_Return0 + + Mov DX, 1 + Mov AX, 4 + Ret + +EndP F_Return1 + +; + +Proc IdleCheck Far + + Push CS + Pop DS + Assume DS:IPX + + Mov AL, ConnectionRequest + And ConnectionRequest, 0Fh + + Test AL, 1 + JZ IdleCheckConnectionRequestBit1 + +IdleCheckConnectionRequestBit0: ; OK.. connection around + Test AL, AL + JNS IdleNoRedraw + + Mov DX, 1 ; Return 1. + Jmp IdleCheckReturnValue + +IdleCheckConnectionRequestBit1: ; If connection is cancelled before + Test AL, 2 + JZ IdleCheckNoConnectionRequest + + Test AL, AL ; Acceptance or Rejection. + JNS IdleNoRedraw + + Mov DX, 2 + +IdleCheckReturnValue: + Mov AX, 5 + Mov DI, 4 + Ret + +IdleCheckNoConnectionRequest: + Mov AL, NumberOfConnections + Cmp OldNumberOfConnections, AL + Mov OldNumberOfConnections, AL + JE IdleCheck3 + +; Mov AX, 5 +; Mov DI, 1 ; Redraw +; Ret + Jmp IPX_DriverScreen + +IdleCheck3: + Mov AX, NumNodes + Cmp AX, OldNumNodes + Mov OldNumNodes, AX + JE IdleCheck1 + +IdleCheck2: + Mov AX, 1 + Ret + +IdleCheck1: + Cmp MessageReceived, 0 + Mov MessageReceived, 0 + JNE IdleCheck2 + +IdleNoRedraw: + Xor AX, AX + Ret + +EndP IdleCheck + Assume DS:Nothing + +; + +Proc TransferDestinationAddress ; SI = Header + + Push AX + Push CX + Push SI + Push DI + + Add SI, 12h + Mov DI, Offset MaintenanceDirectedDestination + Mov CX, 10/2 + Rep MovsW + Mov AX, 'IT' + StosW + + Pop DI + Pop SI + Pop CX + Pop AX + Ret + +EndP TransferDestinationAddress + +; + +Proc NodeSearch ; DS gets set to DiskDataArea + ; Given EAX:EDX = Node address + ; Returns carry if found and BX = address + Assume DS:IPX + + Mov CX, NumNodes + Mov DS, DiskDataArea + Assume DS:Nothing + +; ClC +; Ret + + Xor BX, BX + JCXZ NodeSearch2 + +NodeSearch1: + Cmp [BX+20], EAX + JNE NodeSearch3 + Cmp [BX+24], EDX + JNE NodeSearch3 + + StC + Ret + +NodeSearch3: + Add BX, 32 + Loop NodeSearch1 +; Dec CX +; JNZ NodeSearch1 + +NodeSearch2: + Ret + +EndP NodeSearch + +; + +Proc CheckFromSelf + + Push SI + Push DI + + Add SI, 12h ; Source internetwork address + Mov DI, Offset IPXLocalAddress + Mov CX, 10 + RepE CmpSB + + Pop DI + Pop SI + + Ret + +EndP CheckFromSelf + +; + +Proc ConnectionReject + + Mov DI, Offset MaintenanceSData + Mov AX, 7 + StosW + Call IPX_MaintenanceSendData + Ret + +EndP ConnectionReject + +; + +Proc FindConnection ; Returns carry set if not found, + ; BX = address, AX = connection number + ; 0 = first connect + Assume DS:IPX + + Push CX + Push SI + Push DI + + Xor AX, AX + Add SI, 18 ; Address of sender + Mov DI, Offset UserAddress1 + +FindConnection1: + Cmp AL, NumberOfConnections + JAE FindConnection2 + + Mov CX, 10 + Push SI + RepE CmpsB + Pop SI + JE FindConnection3 + + Add DI, CX + Inc AX + Add DI, 16+12-10 + Jmp FindConnection1 + +FindConnection2: + StC + +FindConnection3: + LEA BX, [DI-26] + + Pop DI + Pop SI + Pop CX + Ret + +EndP FindConnection + +; + +Proc RemoveFromGroup ; Assumes DS = CS = IPX + + Call FindConnection + JC RemoveFromGroupEnd + + PushA + Push ES + + Push DS + Pop ES + + Mov AH, 6 + Mul AH + Mov BX, AX + + Mov SI, Offset ClosedMessage + Mov DI, Offset InfoListMessage + Mov CX, 22/2 + Rep MovsW + Mov SI, [SendPacketInformation+BX] + Sub SI, 16 + Mov CX, 16/2 + Rep MovsW + Mov BX, 100 + Mov SI, Offset InfoListMessage + Call IT_SetInfoLine + + Pop ES + PopA + +Proc RemoveFromGroup2 + Assume DS:IPX + + Push AX + + Mov AH, NumberOfConnections + Sub AH, AL + + Mov DI, BX + LEA SI, [BX+28] + + Dec NumberOfConnections + Mov AL, 28/2 + Mul AH + + Mov CX, AX + Rep MovsW + +; Remove from ack list + Pop CX + + Mov AX, 0FFFEh + ShL AL, CL ; AL = mask for 'upper' bits + ShL AH, CL + Not AH ; AH = mask for 'lower' bits + Mov CL, SendingData + And AL, CL + And AH, CL + ShR AL, 1 + Or AL, AH + Mov SendingData, AL + +RemoveFromGroupEnd: + Ret + +EndP RemoveFromGroup2 +EndP RemoveFromGroup + Assume DS:Nothing + +; + +Proc SendDataOK ; Returns carry if data is still + ; pending to send. + Assume DS:IPX + + Xor AX, AX + Mov AL, NumberOfConnections + + Test AL, AL + JZ SendDataOK_Fail + + Cmp SResult1, 0 + JNE SendDataOK_Fail + Dec AX + JZ SendDataOK_End + + Cmp SResult2, 0 + JNE SendDataOK_Fail + Dec AX + JZ SendDataOK_End + + Cmp SResult3, 0 + JE SendDataOK_End + +SendDataOK_Fail: + StC + +SendDataOK_End: + Ret + +EndP SendDataOK + Assume DS:Nothing + +; + +Macro_AckOffsets Macro Index + DW Offset SendAckHeader&Index&+6 + DW Offset SendAckECB&Index& +EndM + +AckOffsets Label + IndexCounter = 1 + Rept (MAXIMUMUSERS-1) + Macro_AckOffsets %IndexCounter + IndexCounter = IndexCounter + 1 + EndM + +PacketReceived DB 0 + +Proc DataESR Far + + PushF + PushAD + Push DS + + ScreenTraceStart + + Push ES + Push SI + + Push CS + Pop DS + Assume DS:IPX ; Also ES = IPX + + ScreenTrace '0' + + ClD + + Mov PacketReceived, 1 + Inc PacketsReceived + + Trace "R: ESR" + ScreenTrace '1' + + Cmp Byte Ptr [SI+9], 0 ; Received packet successfully? + JNE DESRBadPacket + + Mov DI, [SI+2Ah] ; Offset to fragment 2 + Mov SI, [SI+24h] ; Offset to fragment 1 (ie. header) + Mov CX, [SI+2] + XChg CH, CL + Sub CX, 30 + + ScreenTrace '2' + + Call FindConnection + JC DESRRelisten + + ScreenTrace '3' + +; Send acknowledgement + PushA + Push DS + Push ES + + Mov BX, AX + Mov SI, DI + Call IT_ReceiveData + + ScreenTrace '4' + + Pop ES + Pop DS + PopA + + PushF + Mov BX, AX + ShL BX, 2 + + Mov EAX, [SI+12h] + Mov ECX, [SI+16h] + Mov DX, [SI+1Ah] + + Mov DI, [AckOffsets+BX] + StosD + Mov [DI], ECX + Mov [DI+4], DX + Mov SI, [AckOffsets+BX+2] + Mov [SI+28], ECX + Mov [SI+32], DX + + Mov Word Ptr [SI+2Ah], Offset Zero + + PopF + JNC DESRNoBadPacket + +DESRBadPacket: + ScreenTrace '5' + + Mov Word Ptr [SI+2Ah], Offset Ten + Inc PacketsFailed + +DESRNoBadPacket: + ScreenTrace '6' + + Mov BX, 3 + Call [DWord Ptr IPXEntryAddress] + + ScreenTrace '7' + Trace "R: Source recognised" + + Jmp DESRRelisten + +DESRRelisten: + ScreenTrace '8' + Pop SI + Pop ES + + Trace "R: Packet relisten to socket" + + Mov BX, 4 ; Relisten to the socket. + Call [DWord Ptr IPXEntryAddress] + + ScreenTrace '9' + + ScreenTraceEnd + + Pop DS + PopAD + PopF + Ret + +EndP DataESR + Assume DS:Nothing + +; + +Proc SendDataGivenBX ; Given BX = Offset to SendPacketInfo stuff + + Mov SI, [BX] + Mov DI, [BX+2] + Mov CX, 6 + Rep MovsW + + Sub SI, 8 + Mov DI, [BX+4] + Add DI, 28 ; Immediate address + + MovsW + MovsW + MovsW + + Inc PacketsSent + + Push AX + Push BX + Mov SI, [BX+4] + Mov BX, LastPacketSize + Mov AX, IPXSocket + Mov [SI+0Ah], AX ; Socket Number + Mov [SI+2Eh], BX + Mov BX, 3 + Call [DWord Ptr IPXEntryAddress] + + Pop BX + Pop AX + + Ret + +EndP SendDataGivenBX + +; + +SendPacketInformation DW Offset UserAddress1, Offset DataSendHeader1+6, Offset DataSendECB1 + DW Offset UserAddress2, Offset DataSendHeader2+6, Offset DataSendECB2 + DW Offset UserAddress3, Offset DataSendHeader3+6, Offset DataSendECB3 + +Proc SendITData Near + + PushAD + PushF + Push DS + Push ES + + Push CS + Push CS + Pop ES + Pop DS + Assume DS:IPX + + Cmp SendingData, 0 + JNE SendITDataCheckTime + + Mov AX, MAXDATASIZE + Mov DI, Offset DataSend + Call IT_SendData + Test CX, CX + JZ SendITDataEnd ; No Network Data to send + + Call IT_GetTime ; Returns EAX + Mov SendTime, EAX + Mov RetryTime, EAX + + Mov LastPacketSize, CX + + Mov AL, NumberOfConnections + Mov BX, Offset SendPacketInformation + + Test AL, AL + JZ SendITDataEnd + + Test DL, DL + JNZ SendITDataSingle + +; Have to send to all connections + + Mov CL, AL + Mov CH, 1 + ShL CH, CL + Dec CH + Mov SendingData, CH + +SendITData1: + Trace "Sending broadcast packet" + + Call SendDataGivenBX + + Add BX, 6 + Dec AL + + JNZ SendITData1 + + Jmp SendITDataEnd + +SendITDataSingle: + Trace "Sending single packet" + + Cmp DL, AL + JA SendITDataEnd ; Invalid destination + + Mov CL, AL + Mov CH, 1 + Dec CX + ShL CH, CL + Mov SendingData, CH + +; Have to send to single destination + Mov AL, 6 + Mul DL ; AX = Destination*6 + + Add BX, AX + Sub BX, 6 + Call SendDataGivenBX + Jmp SendITDataEnd + +SendITDataCheckTime: + Mov DL, NumberOfConnections + Test DL, DL + JZ SendITDataEnd + + Call IT_GetTime + Mov EBX, EAX + Mov ECX, EAX + Sub EBX, RetryTime + Sub ECX, SendTime + + Cmp EBX, RETRYTIMEOUT + JB SendITDataEnd + +; Check for true timeout.. drop if so. + Cmp ECX, SENDTIMEOUT + JA SendITDataTimeout + +; Else retry sending packet. + Mov RetryTime, EAX + + Mov AL, SendingData + Mov BX, Offset SendPacketInformation + +SendITDataRetry: + ShR AL, 1 + JNC SendITDataRetry2 + + Call SendDataGivenBX + Inc PacketsRetry + +SendITDataRetry2: + Add BX, 6 + Dec DL + JNZ SendITDataRetry + + Jmp SendITDataEnd + +SendITDataTimeout: + Xor AX, AX ; AX = connection number + Mov DH, SendingData + +SendITDataTimeout1: + ShR DH, 1 + JNC SendITDataTimeout2 + + Mov AH, 6 + Mul AH + Mov BX, AX + + Mov SI, Offset AutoDropMessage + Mov DI, Offset InfoListMessage + Mov CX, 20/2 + Rep MovsW + Mov SI, [SendPacketInformation+BX] + Sub SI, 16 + Mov CX, 16/2 + Rep MovsW + Mov BX, 100 + Mov SI, Offset InfoListMessage + Call IT_SetInfoLine + + Call RemoveFromGroup2 + Jmp SendITDataEnd + +SendITDataTimeout2: + Inc AX + Dec DL + JNZ SendITDataTimeout1 + +SendITDataEnd: + Pop ES + Pop DS + PopF + PopAD + + Ret + +EndP SendITData + +; + +Proc SendDataESR Far + + Push DS + PushF + + ScreenTraceStart + + Push CS + Pop DS + Assume DS:IPX ; Also ES = IPX + ClD + + Trace "S: ESR" + ScreenTrace 'A' + + Cmp Byte Ptr [SI+9], 0 ; Received packet successfully? + JNE SDESRResend + + ScreenTrace 'B' + Call SendITData + + ScreenTrace 'C' + + ScreenTraceEnd + + PopF + Pop DS + Ret + +SDESRResend: + Inc PacketsFailed + + ScreenTrace 'D' + + Mov BX, 3 + Call [DWord Ptr IPXEntryAddress] + + ScreenTrace 'E' + + ScreenTraceEnd + + PopF + Pop DS + Ret + +EndP SendDataESR + Assume DS:Nothing + +; + +MAXIMUMBLOCKTYPE = 10 + +MESRBlockOffsets Label Word + DW Offset MESRBlockType0, Offset MESRBlockType1 + DW Offset MESRBlockType2, Offset MESRBlockType3 + DW Offset MESRBlockType4, Offset MESRBlockType5 + DW Offset MESRBlockType6, Offset MESRBlockType7 + DW Offset MESRBlockType8, Offset MESRBlockType9 + DW Offset MESRBLockType10 + +; + +Proc MaintenanceESR Far ; Given ES:SI = ECB + + PushF + PushAD + + ScreenTraceStart + + Push DS + Push SI + + ClD + + Push CS + Pop DS + Assume DS:IPX ; Also ES = IPX + + ScreenTrace 'a' + + Cmp Byte Ptr [SI+9], 0 ; Received packet successfully? + JNE MESRRelisten + + ScreenTrace 'b' + + Mov DI, [SI+2Ah] ; Offset to fragment 2 + Mov SI, [SI+24h] ; Offset to fragment 1 (ie. header) + + Mov DX, [DI] ; DL = block type + Mov BX, DX + And BX, 0FFh + Cmp BL, MAXIMUMBLOCKTYPE + JA MESRBlockTypeUnknown + Add BX, BX + Jmp [MESRBlockOffsets+BX] + +MESRBlockType0: ; Acknowledgement + ScreenTrace 'c' + + Call FindConnection + JC MESRBlockType0End + + Inc PacketsAck + Mov CX, AX + Mov AL, 0FEh + + RoL AL, CL + And SendingData, AL + + ScreenTrace 'd' + + Call SendITData + +MESRBlockType0End: + ScreenTrace 'e' + + Jmp MESRBlockTypeFinished + +;****************************************************************************** + +MESRBlockType1: ; Intro + ScreenTrace 'f' +; Cmp NumberOfConnections, 3 ; Don't respond if 3 connections already! +; JE MESRBlockType1End + + ; Ignore packets from self........ + + Call CheckFromSelf + JE MESRBlockType1End + + ScreenTrace 'g' + + ; ................................. + +; Now check whether destination was broadcast... + + Cmp Byte Ptr [DI+1], 0 + JNE MESRBlockType1NoReply + + Cmp Word Ptr [SI+0Ah], 0FFFFh + JNE MESRBlockType1NoReply + Cmp DWord Ptr [SI+0Ch], 0FFFFFFFFh + JNE MESRBlockType1NoReply + + Cmp NoReply, 0 + JNE MESRBlockType1End +; Yes it was broadcast.. now reply.. + + ScreenTrace 'h' + + Mov AL, 1 + Call SendConnectionData + + ScreenTrace 'i' + +MESRBlockType1NoReply: + ScreenTrace 'j' + +; Don't log if we don't want to log (ie. only log if current mode = 24) + +; Cmp NumberOfConnections, 0 +; JNE MESRBlockType1End + Call IT_GetCurrentMode + Cmp AL, 24 + JNE MESRBlockType1End + + ScreenTrace 'k' + +; Don't log if already logged.. + + Mov EAX, [SI+20] ; Sender's ID + Mov EDX, [SI+24] + + Call NodeSearch + JC MESRBlockType1End + + ScreenTrace 'l' + +; Don't have the node -> log it! + + LEA SI, [DI+2] + Push CS + Push DS + Pop ES + Pop DS + + Mov DI, NumNodes + Xor DX, DX + + Cmp DI, 2000 + JA MESRBlockType1End + + LodsB + + ShL DI, 5 + Mov DL, AL + + Inc DX + + Xor AX, AX + Add NumNodes, DX + +MESRBlockType1Transfer: + StosW + Mov CX, 26/2 + Rep MovsW + Inc AX + Add DI, 4 + Dec DX + JNZ MESRBlockType1Transfer + +MESRBlockType1End: + ScreenTrace 'm' + + Jmp MESRBlockTypeFinished + +;****************************************************************************** + +MESRBlockType3: ; Quit ; Have to say farewell to direct connections + ; also. Should cascade to MESRBlockType2 + ScreenTrace 'n' + Call RemoveFromGroup + +;****************************************************************************** + +MESRBlockType2: ; Remove ; Only significant on connect driver screen + ScreenTrace 'o' + + Cmp NumberOfConnections, 0 + JNE MESRBlockType2End + Call IT_GetCurrentMode + Cmp AL, 24 + JNE MESRBlockType2End + + ScreenTrace 'p' + + Mov EAX, [SI+20] ; Sender's ID + Mov EDX, [SI+24] + + Call NodeSearch + JNC MESRBlockType2End ; DS = DiskData + + ScreenTrace 'q' + + Push DS + Pop ES + + Mov CX, CS:NumNodes + Mov DI, BX + ShL CX, 5 + LEA SI, [BX+32] + Xor AX, AX + + Sub CX, DI + Rep MovsB + + Mov CX, 32/2 + Rep StosW + + Mov SI, BX + +MESRBlockType2a: + Cmp [SI], AX + JE MESRBlockType2b + + Dec Word Ptr [SI] + Add SI, 32 + Jmp MESRBlockType2a + +MESRBlockType2b: + ScreenTrace 'r' + + ShR BX, 5 + + Push CS + Pop DS + + Dec NumNodes + Cmp BX, CurrentNode + JAE MESRBlockType2End + + Dec CurrentNode + +MESRBlockType2End: + ScreenTrace 's' + + Jmp MESRBlockTypeFinished + +;****************************************************************************** + +MESRBlockType4: ; Message + ScreenTrace 't' + + Call CheckFromSelf + JE MESRBlockType4End + +; If NumberOfConnections = 0 && CurrentMode = 24, then check that name is logged + Cmp NumberOfConnections, 0 + JNE MESRBlockType4_6 + + Call IT_GetCurrentMode + Cmp AL, 24 + JNE MESRBlockType4_3 + + Push DS + Push ES + + Mov EAX, [SI+20] ; Sender's ID + Mov EDX, [SI+24] + + Call NodeSearch + JC MESRBlockType4_4 + +; Couldn't find node. + Push DI + Push SI + + Push CS + Push DS + Pop ES + Pop DS + + LEA SI, [DI+1] + Mov DI, NumNodes + Cmp DI, 2000 + JA MESRBlockType4_5 + + ShL DI, 5 + Xor AX, AX + + StosW + Mov CX, 16/2 + Rep MovsW + + Pop SI + Push SI + + Add SI, 18 + Mov CX, 10/2 + Rep MovsW + + Inc NumNodes + +MESRBlockType4_5: + Pop SI + Pop DI + +MESRBlockType4_4: + Pop ES + Pop DS + + Jmp MESRBlockType4_3 + +MESRBlockType4_6: + ; Have connections.. only accept messages from group + Call FindConnection + JC MESRBlockType4End + +MESRBlockType4_3: + Mov MessageReceived, 1 + + Push DI + + Mov SI, Offset MessageData+72 + Mov DI, Offset MessageData + Mov CX, (72*7)/2 + Rep MovsW + + Pop SI + LodsB + Mov CX, 72/2 + Rep MovsW + + Call IT_GetCurrentMode + Cmp AL, 24 + JE MESRBlockType4End + + Sub SI, 72 + Mov DI, Offset InfoListMessage + + Mov CX, 61 + + Push SI + +MESRBlockType4_1: + LodsB + StosB + Test AL, AL + LoopNZ MESRBlockType4_1 + + Pop SI + Mov Word Ptr [DI-1], ':'+ ' '*100h + Inc DI + Add SI, 16 + Mov AX, 0FEh+2300h + StosW + +MESRBlockType4_2: + LodsB + StosB + Test AL, AL + LoopNZ MESRBlockType4_2 + Xor AL, AL + StosB + + Mov BX, 150 + Mov SI, Offset InfoListMessage + Call IT_SetInfoLine + +MESRBlockType4End: + Jmp MESRBlockTypeFinished + +;****************************************************************************** + +MESRBlockType5: + Call RemoveFromGroup + Jmp MESRBlockTypeFinished + +;****************************************************************************** + +MESRBlockType6: ; Request connection + ; auto reject if: + ; This node is requesting a connection + ; Someone else is requesting a connection + ; NumConnections already = 3 + Cmp NumberOfConnections, 3 + JE MESRBlockType6AutoReject + Test ConnectionRequest, 0Fh + JNE MESRBlockType6AutoReject + + Or ConnectionRequest, 2 ; Mark that someone is requesting a con + +; Else prompt user +; Save connection request address + + Push DI + + Add SI, 18 ; Save address of connection requester + Mov DI, Offset ConnectionRequestAddress + Mov CX, 12/2 + Rep MovsW + + Pop DI + + Inc DI + Mov SI, DI + Xor AL, AL + Mov CX, 16 + Push CX + RepNE ScasB ; DI = one after 0 found + Pop CX + Sub DI, SI + Mov DX, DI + Sub CX, DI + ShR CX, 1 + + Mov DI, Offset ConnectionRequestName + + Mov AL, ' ' + Rep StosB + + Mov CX, DX + Rep MovsB + + Mov IPXQueueScreen, 1 + + Jmp MESRBlockTypeFinished + +MESRBlockType6AutoReject: + Call MaintenanceWaitforSend + Call TransferDestinationAddress + + Push DI + Mov SI, Offset AutoRejectMessage + Mov DI, Offset InfoListMessage + Mov CX, 26/2 + Rep MovsW + Pop SI + Inc SI + Mov CX, 16/2 + Rep MovsW + Mov BX, 100 + Mov SI, Offset InfoListMessage + Call IT_SetInfoLine + Call ConnectionReject + +MESRBlockType6End: + Jmp MESRBlockTypeFinished + +;****************************************************************************** + +MESRBlockType7: ; Accept/Reject connection +; First verify that sender is the same as ConnectionRequestAddress and that +; connectionRequest Bit 0 is set. if not, then send negative confirmation + + Test [ConnectionRequest], 1 + JZ MESRBlockType7Reject + + Push SI + Push DI + + Mov CX, 10/2 + Add SI, 18 ; Sender's address + Mov DI, Offset ConnectionRequestAddress + RepE CmpsW + + Pop DI + Pop SI + + JNE MESRBlockType7Reject + +; OK.. +; Connection rejected if DH = 0 + + Or ConnectionRequest, 80h ; Leave wait for connection request + ; screen + ShR DX, 8 + JZ MESRBlockTypeFinished + + Call MaintenanceWaitforSend + Call TransferDestinationAddress + +; Connection accepted if DH != 0 +; Then copy DH*28 lots of bytes starting at UserName1 +; And set NumberOfConnections to DH +; Then call IT_EstablishConnection + + Mov NumberOfConnections, DL + LEA SI, [DI+2] + Mov DI, Offset UserName1 + +MESRBlockType7Accepted: + Mov CX, 28/2 + Rep MovsW + Dec DX + JNZ MESRBlockType7Accepted + +; Send positive ack + + Mov SI, Offset UserName + Mov DI, Offset MaintenanceSData + Mov AX, 108h + Mov CX, 28/2 + StosW + Rep MovsW + Call IPX_MaintenanceSendData + + Call IT_NewConnection + + Jmp MESRBlockTypeFinished + +MESRBlockType7Reject: + Test DH, DH ; If connection rejected, dont' send + ; Further response. + JZ MESRBlockType7End + + Mov DI, Offset MaintenanceSData + Mov AX, 8 + StosW + Call IPX_MaintenanceSendData + +MESRBlockType7End: + Jmp MESRBlockTypeFinished + +;****************************************************************************** + +MESRBlockType8: ; Confirm connection + + ; Check whether connection was requested and whether this cancellation + ; is from that sender. + +; If Confirm connection is from ConnectionRequestAddress and ConnectRequest & 2 +; *OR* Confirm connection is from someone in the current group +; Then add user to user list, increment NumberOfConnections + + Cmp NumberOfConnections, 3 + JE MESRBlockType8End + + Call FindConnection ; Was it from the group? + JNC MESRBlockType8AddUser ; Yes -> Add user + + Push SI + Push DI + + Add SI, 12h + Mov DI, Offset ConnectionRequestAddress + Mov CX, 12/2 + RepE CmpsW + + Pop DI + Pop SI + JNE MESRBlockType8End + + Test DH, DH ; Cancelled? + JZ MESRBlockType8ScreenRefresh + +; If received from group, then don't send +; If not received from group, then send to rest of group. + ; Establish connection + ; If NumConnections != 0 + ; then send connection establishment to all + ; other connected users. +; Send to the rest of the group! + Mov AL, NumberOfConnections + + Push AX + Inc AL + Call IT_EstablishConnection + Pop AX + + Test AL, AL + JZ MESRBlockType8AddUser + + Call MaintenanceWaitforSend + + Push DI + + Mov SI, DI + Mov DI, Offset MaintenanceSData + Mov CX, 30/2 + Rep MovsW + + Mov SI, Offset UserAddress1 + Mov [MaintenanceSendHeader], Offset MaintenanceSendHeaderDirected + Mov [MaintenanceSendDataOffset], Offset MaintenanceSData + Mov [MaintenanceSendDataSize], 30 + +MESRBlockType8Group1: + + Push AX + Push SI + + Mov DI, Offset MaintenanceDirectedDestination + Mov CX, 10/2 + Rep MovsW + Mov AX, 'IT' + StosW + + Call SendMaintenancePacket + + Pop SI + Pop AX + + Dec AL + JZ MESRBlockType8GroupEnd + + Add SI, 28 + Call MaintenanceWaitforSend + Jmp MESRBlockType8Group1 + +MESRBlockType8GroupEnd: + Pop DI + +MESRBlockType8AddUser: + LEA SI, [DI+2] + Mov AL, 28 + Mul NumberOfConnections + + Mov DI, AX + Add DI, Offset UserName1 + Mov CX, 28/2 + Rep MovsW + + Inc NumberOfConnections + +MESRBlockType8ScreenRefresh: + Or ConnectionRequest, 80h + +MESRBlockType8End: + Jmp MESRBlockTypeFinished + +;****************************************************************************** + +MESRBlockType9: ; Request intro +; Mov [MaintenanceSendHeader], Offset MaintenanceSendHeaderDirected + Mov AL, 1 + Call SendConnectionData + + Jmp MESRBlockTypeFinished + +;****************************************************************************** + +MESRBlockType10: ; Resend data + Call FindConnection + JC MESRBlockType10End + + Inc PacketsRetry + + Mov AH, 6 + Mul AH + Mov BX, AX + Add BX, Offset SendPacketInformation + Call SendDataGivenBX + +MESRBlockType10End: + Jmp MESRBlockTypeFinished + +MESRBlockTypeUnknown: + Mov BX, 72 + Mov SI, Offset UnknownPacketMessage + Call IT_SetInfoLine + +MESRBlockTypeFinished: +; Should process the info, respond if necessary and set the packet back +; for listening. + +MESRRelisten: + Push CS + Push CS + Pop ES + Pop DS + + Pop SI + + ScreenTrace 'z' + + Mov BX, 4 ; Relisten to the socket. + Call [DWord Ptr IPXEntryAddress] + + ScreenTrace 'Z' + + Pop DS + ScreenTraceEnd + + PopAD + PopF + Ret + +EndP MaintenanceESR + Assume DS:Nothing + +; + +Proc MaintenanceWaitForSend + + PushF + PushAD + Push DS + + ScreenTraceStart + + Push CS + Pop DS + Assume DS:IPX + + Call IT_GetTime ; Returns EAX + Mov EDX, EAX + +SendMaintenancePacket1: + Cmp [SendECBInUse], 0 + JE SendMaintenancePacket2 + + StI + + Mov BX, 0Ah ; IPX processing. + Call [DWord Ptr IPXEntryAddress] + + Mov EBX, EDX + Call IT_GetTime + Sub EBX, EAX + Cmp EBX, MAINTENANCETIMEOUT + JB SendMaintenancePacket1 + +; Error message! + +SendMaintenancePacket2: + ScreenTraceEnd + + Pop DS + PopAD + PopF + Ret + +EndP MaintenanceWaitForSend + Assume DS:Nothing + +; + +Proc SendMaintenancePacket + + PushAD + Push DS + Push ES + + Push CS + Push CS + Pop ES + Pop DS + Assume DS:IPX + + Call MaintenanceWaitForSend + + Mov SI, [MaintenanceSendHeader] + Mov DI, Offset MSendDest + Add SI, 10 + MovsW + MovsW + MovSW + + Mov BX, 3 + Mov SI, Offset MaintenanceSendECB + Call [DWord Ptr IPXEntryAddress] + + Pop ES + Pop DS + PopAD + Ret + +EndP SendMaintenancePacket + Assume DS:Nothing + +; + +Proc DetectIPXNetwork Far ; IPX detection. + + Push CS + Pop DS + Assume DS:IPX + +IF FIXEDUSERNAME + Mov CX, 18 + Mov SI, Offset UserName +ELSE + Xor CX, CX +ENDIF + Call IT_DecodeUserName + + Mov AX, 7A00h + Int 2Fh + + Sub AL, 0FFh + JC DetectIPXNetwork1 + + Mov [Word Ptr IPXEntryAddress], DI + Mov [Word Ptr IPXEntryAddress+2], ES + + Mov BX, 1Ah + Call [DWord Ptr IPXEntryAddress] + + Mov [IPXMaximumPacketSize], AX + Mov [IPXRetryCount], CX + + Push CS + Pop ES + + Mov BX, 9 + Mov SI, Offset IPXLocalAddress + Call [DWord Ptr IPXEntryAddress] + + ClC + +DetectIPXNetwork1: + Ret + +EndP DetectIPXNetwork + Assume DS:Nothing + +; + +Macro_SetupListenDataPackets Macro Index + Mov DSocket&Index&, DX +EndM + +Macro_ListenDataPackets Macro Index + Mov SI, Offset DataReceiveECB&Index& + Call [DWord Ptr IPXEntryAddress] +EndM + +Proc IPX_Initialise Far + + Push CS + Pop DS + Assume DS:IPX + + Trace "IPX: Initialise" + + Mov SI, Offset RelocationTable + +IPX_RelocationFixup: + LodsW + Test AX, AX + JZ IPX_RelocationEnd + Mov BX, AX + Mov [BX], DS + + Jmp IPX_RelocationFixup + +IPX_RelocationEnd: + Mov EAX, IT_DrawHeader + Mov EBX, IT_FillHeader + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + + Mov DrawHeader2, EAX + Mov FillHeader2, EBX + Mov IdleFunctionList, ECX + Mov IdleFunctionList2, ECX + Mov GlobalKeyLink2, EDX + + Call DetectIPXNetwork + JNC IPX_Initialise1 + + Push DS + Push Offset NoIPXMessageList + Jmp IPX_InitialiseReturn + +IPX_Initialise1: + Xor AL, AL + Xor BX, BX ; Open socket + Mov DX, 'IT' + Call [DWord Ptr IPXEntryAddress] + Test AL, AL + JNZ IPX_InitialiseError1 + + Xor AL, AL + Xor BX, BX + Xor DX, DX + Call [DWord Ptr IPXEntryAddress] + Test AL, AL + JNZ IPX_InitialiseError2 + + Mov IPXSocket, DX + + IndexCounter = 1 + Rept NUMBEROFLISTENINGPACKETS + Macro_SetupListenDataPackets %IndexCounter + IndexCounter = IndexCounter + 1 + EndM + +IPX_Initialise2: + +IFE FIXEDUSERNAME +; OK.. ask for user name. + Push DS + Push Offset IPXGetName + Call IT_FunctionHandler + + Push CS + Pop DS + + Test DX, DX + JNZ IPX_Initialise3 + Jmp IPX_Shutdown1 + +IPX_Initialise3: +ENDIF + +; Setup to listen for packets! + + Push CS + Pop ES + Mov BX, 4 + + Mov SI, Offset MaintenanceECB1 + Call [DWord Ptr IPXEntryAddress] + + Mov SI, Offset MaintenanceECB2 + Call [DWord Ptr IPXEntryAddress] + + Mov SI, Offset MaintenanceECB3 + Call [DWord Ptr IPXEntryAddress] + + Mov SI, Offset MaintenanceECB4 + Call [DWord Ptr IPXEntryAddress] + + IndexCounter = 1 + Rept NUMBEROFLISTENINGPACKETS + Macro_ListenDataPackets %IndexCounter + IndexCounter = IndexCounter + 1 + EndM + + Jmp IPX_DriverScreen + +IPX_InitialiseError2: ; Close socket. + Mov BX, 1 + Mov DX, 'IT' + Call [DWord Ptr IPXEntryAddress] + +IPX_InitialiseError1: + Push DS + Push Offset SocketErrorList + +IPX_InitialiseReturn: + Call IT_FunctionHandler + Jmp IT_UnloadDriver + +EndP IPX_Initialise + Assume DS:Nothing + +; + +Proc BroadcastMaintenanceByte ; Given AL + + Call MaintenanceWaitforSend + Mov [ByteBlock], AL + Mov [MaintenanceSendHeader], Offset MaintenanceSendHeaderBroadcast + Mov [MaintenanceSendDataOffset], Offset ByteBlockInformation + Mov [MaintenanceSendDataSize], 1 + Call SendMaintenancePacket + + Ret + +EndP BroadcastMaintenanceByte + +; + +Proc IPX_DriverScreen Far + + Push CS + Pop DS + Assume DS:IPX + + Mov ES, DiskDataArea + Xor DI, DI + Mov CX, 32768 + Xor AX, AX + Rep StosW + + Cmp NumberOfConnections, 0 + JE IPX_DriverScreen1 + +; Alternative screens here for post-connection. + + Mov AX, 5 + Mov SI, 1 + Mov DI, AX + Mov DX, Offset IPXConnectedScreen + Mov CX, CS + + Ret + +IPX_DriverScreen1: + Mov OldNumNodes, 0 + Mov NumNodes, 0 + Mov CurrentNode, 0 + +; Call MaintenanceWaitforSend +; Mov [MaintenanceSendHeader], Offset MaintenanceSendHeaderBroadcast + Xor AX, AX + Call SendConnectionData + + Mov AX, 5 + Mov SI, 1 + Mov DI, AX + Mov DX, Offset IPXScreen + Mov CX, CS + + Ret + +EndP IPX_DriverScreen + Assume DS:Nothing + +; + +Proc IPX_Shutdown Far ; Shutdown has to: + ; free all allocated + ; Transmit logoff message + ; release any allocated sockets + ; Unload driver +IFE FIXEDUSERNAME + Call IT_GotoHomeDirectory +ENDIF + Push CS + Pop DS + Assume DS:IPX + +IFE FIXEDUSERNAME + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SaveConfiguration2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfiguration1 + + Mov AH, 40h + Mov CX, CONFIGURATIONSIZE + Mov DX, Offset UserName + Int 21h + +SaveConfiguration1: + Mov AH, 3Eh + Int 21h + +SaveConfiguration2: +ENDIF + Mov AL, 3 ; Block type 3 = quit + Call BroadcastMaintenanceByte + +IPX_Shutdown1: +; Free both sockets + Mov BX, 1 + + Mov DX, 'IT' ; Release maintenance socket. + Call [DWord Ptr IPXEntryAddress] + + Mov DX, IPXSocket + Call [DWord Ptr IPXEntryAddress] + + Jmp IT_UnloadDriver + +EndP IPX_Shutdown + Assume DS:Nothing + +; + +Proc IPX_LeaveSession Far + + Mov AL, 5 ; Log off from group. + Call BroadcastMaintenanceByte + + Mov CS:NumberOfConnections, 0 + + Jmp IPX_DriverScreen + +EndP IPX_LeaveSession + +; + +Proc IPX_Update Far + + Push CS + Pop DS + Assume DS:IPX + + Xor AX, AX + XChg IPXQueueScreen, AX + + Test AX, 1 + JZ IPX_Update2 + + Push AX + + ; For Connection requests.. + And ConnectionRequest, 0Fh + + Call IT_S_SaveScreen + Push CS + Push Offset ConnectionRequestList + Call IT_FunctionHandler + + Push CS + Push CS + Pop DS + Pop ES + + Call IT_S_RestoreScreen + + ; Transfer destination address + Mov SI, Offset ConnectionRequestAddress + Mov DI, Offset MaintenanceDirectedDestination + Mov CX, 12/2 + Rep MovsW + + Cmp DX, 1 + JB IPX_UpdateConnectionReject + JA IPX_UpdateConnectionCancelled + +IPX_UpdateConnectionAccept: +; Have to send complete info about all connnections back +; including socket numbers + Mov AH, NumberOfConnections + Mov DI, Offset MaintenanceSData + Mov AL, 7 + Mov SI, Offset UserName + Inc AH + Mov CX, ((16+12)*3)/2 + StosW + Rep MovsW + Call IPX_MaintenanceSendData + + Jmp IPX_UpdateConnectionEnd + +IPX_UpdateConnectionReject: + Call ConnectionReject + Jmp IPX_UpdateConnectionEnd + +IPX_UpdateConnectionCancelled: + Push CS + Push Offset ConnectionCancelledList + Call IT_FunctionHandler + Call IT_S_RestoreScreen + +IPX_UpdateConnectionEnd: + And ConnectionRequest, Not 2 + Pop AX + +IPX_Update3: + Mov BX, 0Ah ; Relinquish control + Call [DWord Ptr IPXEntryAddress] + + Mov AX, 1 + Ret ; Redraw required. + +IPX_Update2: + Call SendITData + + Call IT_GetCurrentMode + Cmp AL, 24 + JE IPX_Update3 + +IPX_UpdateEnd: + Mov BX, 0Ah ; Relinquish control + Call [DWord Ptr IPXEntryAddress] + + Xor AX, AX + XChg AL, PacketReceived + Ret + +EndP IPX_Update + Assume DS:Nothing + +; + +Proc IPX_DrawHexNumber ; Given AL = Number + + LodsB + Mov DH, AL + ShR AL, 4 + Cmp AL, 10 + SBB AL, 69h + DAS + StosW + Mov AL, DH + And AL, 0Fh + Cmp AL, 10 + SBB AL, 69h + DAS + StosW + + Ret + +EndP IPX_DrawHexNumber + +; + +Proc IPX_DrawAddress + + Mov CX, 3 + +IPX_DrawAddress1: + Call IPX_DrawHexNumber + Mov AL, ':' + StosW + Loop IPX_DrawAddress1 + Call IPX_DrawHexNumber + Mov AL, ' ' + StosW + + Mov CX, 5 + +IPX_DrawAddress2: + Call IPX_DrawHexNumber + Mov AL, ':' + StosW + Loop IPX_DrawAddress2 + Call IPX_DrawHexNumber + + Ret + +EndP IPX_DrawAddress + +; + +Proc IPX_DrawConnect Far + + Push CS + Pop DS + Assume DS:IPX + + Call IT_S_GetDestination ; Gets ES + + Mov AX, 168+200h + Mov DI, (13*80+22)*2 + Mov CX, 23 + +IPX_DrawConnect2: + StosW + Add DI, 158 + Loop IPX_DrawConnect2 + + Cmp [NumNodes], 0 + JNE IPX_DrawConnect1 + + Ret + +IPX_DrawConnect1: + Mov SI, [TopNode] + Mov DX, [NumNodes] + Mov BX, [CurrentNode] + + Cmp BX, DX + JB IPX_DrawConnectClip3 + + Mov BX, DX + Dec BX + Mov [CurrentNode], BX + +IPX_DrawConnectClip3: + +; Need to make sure they're within bounds. + Cmp BX, SI + JAE IPX_DrawConnectClip1 + + Mov SI, BX + +IPX_DrawConnectClip1: + LEA DI, [SI+22] + Cmp BX, DI + JBE IPX_DrawConnectClip2 + + LEA SI, [BX-22] + +IPX_DrawConnectClip2: + Mov DI, (13*80+3)*2 + Mov [TopNode], SI + + Sub DX, SI + JZ IPX_DrawConnectEnd + + ShL SI, 5 + + Mov DS, [DiskDataArea] + Assume DS:Nothing + + Cmp DX, 23 + JB IPX_DrawConnectClip + + Mov DX, 23 + +IPX_DrawConnectClip: + Push DI + + LodsW + + Mov AH, 3 + Mov CX, 16 + + Test AL, AL + JZ IPX_DrawConnectUserName + + Add DI, 4 + +IPX_DrawConnectUserName: + LodsB + StosW + Loop IPX_DrawConnectUserName + + Pop DI + + Add DI, 40 + + Call IPX_DrawAddress + + Add SI, 4 + Add DI, 62 + + Dec DL + JNZ IPX_DrawConnectClip + + Mov CL, 0E0h + Jmp IPX_PreConnectChain + +IPX_DrawConnectEnd: + Ret + +EndP IPX_DrawConnect + +; + +Proc IPX_PreConnect Far + + Mov CL, 30h + +IPX_PreConnectChain: + Push CS + Pop DS + Assume DS:IPX + + Cmp [NumNodes], 0 + JE IPX_PreConnectEnd + + Mov AX, [CurrentNode] + Sub AX, [TopNode] + Add AX, 13 + Mov BX, 160 + Mul BX + + Call IT_S_GetDestination + + Mov DL, CL + Mov DH, CL + Or DH, 2 + + LEA DI, [EAX+6] + Mov CX, 49 + +IPX_PreConnectScreen1: + Mov AX, [ES:DI] + Mov AH, DL + Cmp CX, 49-19 + JNE IPX_PreConnectScreen2 + + Mov AH, DH + +IPX_PreConnectScreen2: + StosW + Loop IPX_PreConnectScreen1 + +IPX_PreConnectEnd: + Ret + +EndP IPX_PreConnect + Assume DS:Nothing + +; + +Proc IPX_PostConnect Far + + Push CS + Pop DS + Assume DS:IPX + + Mov SI, Offset ConnectKeys + Call IT_FunctionDivider + JC IPX_PostConnect1 + + Jmp [Word Ptr SI] + +IPX_PostConnect1: + Xor AX, AX + Ret + Xor AX, AX + Ret + +EndP IPX_PostConnect + +; + +Proc IPX_ConnectUp Far + Assume DS:IPX + + Mov AX, 1 + + Sub CurrentNode, AX + AdC CurrentNode, 0 + + Ret + +EndP IPX_ConnectUp + Assume DS:Nothing + +; + +Proc IPX_ConnectDown Far + Assume DS:IPX + + Mov AX, 1 + Add CurrentNode, AX + Ret + +EndP IPX_ConnectDown + Assume DS:Nothing + +; + +Proc IPX_ConnectPgUp Far + Assume DS:IPX + + Mov AX, CurrentNode + Sub AX, 24 + JNC IPX_ConnectPgUp1 + + Xor AX, AX + +IPX_ConnectPgUp1: + Mov CurrentNode, AX + + Mov AX, 1 + Ret + +EndP IPX_ConnectPgUp + Assume DS:Nothing + +; + +Proc IPX_ConnectPgDn Far + Assume DS:IPX + + Add CurrentNode, 24 + + Mov AX, 1 + Ret + +EndP IPX_ConnectPgDn + Assume DS:Nothing + +; + +Proc IPX_ConnectHome Far + + Mov CurrentNode, 0 + Mov AX, 1 + Ret + +EndP IPX_ConnectHome + +; + +Proc IPX_ConnectEnd Far + + Mov CurrentNode, 1000 + + Mov AX, 1 + Ret + +EndP IPX_ConnectEnd + +; + +Proc IPX_ConnectTab Far + Assume DS:IPX + + Mov AX, 6 + StosW + + Mov AX, 1 + Ret + +EndP IPX_ConnectTab + Assume DS:Nothing + +; + +Proc IPX_GetDestinationAddress + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:IPX + + Cmp NumNodes, 1 + JB IPX_GetDestinationAddress1 + + Mov SI, CurrentNode + Mov DI, Offset MaintenanceDirectedDestination + ShL SI, 5 + Mov CX, 10/2 + Add SI, 18 ; SI = offset to node address + + Push DS + Mov DS, DiskDataArea + + Rep MovsW + Mov AX, 'IT' + StosW ; Destination socket is maintenance socket. + + Pop DS + ClC + +IPX_GetDestinationAddress1: + Ret + +EndP IPX_GetDestinationAddress + Assume DS:Nothing + +; + +Proc IPX_MaintenanceSendData + + Mov [MaintenanceSendHeader], Offset MaintenanceSendHeaderDirected + +Proc IPX_MaintenanceSendDataNoHeader + Sub DI, Offset MaintenanceSData + Mov [MaintenanceSendDataOffset], Offset MaintenanceSData + Mov [MaintenanceSendDataSize], DI + + Call SendMaintenancePacket + + Ret + +EndP IPX_MaintenanceSendDataNoHeader +EndP IPX_MaintenanceSendData + +; + +Proc SendConnectionData + Assume DS:IPX + + PushA + Push DS + Pop ES + + Call MaintenanceWaitforSend + Mov [MaintenanceSendHeader], Offset MaintenanceSendHeaderBroadcast + + Test AX, AX + JZ SendConnectionData2 + + Call TransferDestinationAddress + Mov [MaintenanceSendHeader], Offset MaintenanceSendHeaderDirected + +SendConnectionData2: + Mov DI, Offset MaintenanceSData + Mov SI, Offset IntroBlockInformation + MovsB + StosB + MovSB + Mov DL, NumberOfConnections + +SendConnectionData1: + Mov CX, (16+10)/2 + Rep MovsW + LodsW + Dec DL + JNS SendConnectionData1 + + + Call IPX_MaintenanceSendDataNoHeader + PopA + Ret + +EndP SendConnectionData + Assume DS:Nothing + +; + +Proc IPX_ConnectEnter Far ; Have to request a connection + + Call IPX_GetDestinationAddress + JC IPX_ConnectEnter1 + Assume DS:IPX + + Or ConnectionRequest, 1 + + Push DS + Mov DS, DiskDataArea + Assume DS:Nothing + + Sub SI, 26 + Mov DI, Offset ConnectionRequestName + Mov CX, 26/2 + Rep MovsW + Pop DS + Assume DS:IPX + + Mov SI, Offset UserName + Mov DI, Offset MaintenanceSData + Mov AL, 6 + StosB + Mov CX, 16/2 + Rep MovsW + + Call IPX_MaintenanceSendData + + Push DS + Push Offset WaitforConnectList + Call IT_FunctionHandler + + Push CS + Push CS + Pop DS + Pop ES + + And ConnectionRequest, Not 1 + +; If DX = 0, then connection was cancelled +; If DX = 1, then either connected or cancelled. + + Test DX, DX + JNZ IPX_ConnectEnter2 + +; Connection cancelled. + Mov SI, Offset ConnectionRequestAddress + Mov DI, Offset MaintenanceDirectedDestination + Mov CX, 10/2 + Rep MovsW + Mov AX, 'IT' + StosW + + Mov DI, Offset MaintenanceSData + Mov AX, 8 + StosW + Call IPX_MaintenanceSendData + Jmp IPX_ConnectEnter1 + +IPX_ConnectEnter2: + Cmp NumberOfConnections, 0 + JNE IPX_ConnectEnter3 + +; Connection rejected + + Push DS + Push Offset ConnectionRejectedList + Call IT_FunctionHandler + Jmp IPX_ConnectEnter1 + +IPX_ConnectEnter3: +; Connection established + +IPX_ConnectEnter1: + Mov AX, 1 + Ret + +EndP IPX_ConnectEnter + +; + +Proc IPX_SendGroupMessage Far + + Push CS + Pop DS + + Cmp MessageEntryArea, 0 + JE IPX_SendMessageEnd + + Mov SI, Offset UserName + Mov DI, Offset MessageSenderName + Mov CX, 16/2 + Rep MovsW + + Mov [MaintenanceSendHeader], Offset MaintenanceSendHeaderDirected + Mov [MaintenanceSendDataOffset], Offset MessageBlock + Mov [MaintenanceSendDataSize], 73 + + Mov SI, Offset UserAddress1 + Mov DL, NumberOfConnections + +IPX_SendGroupMessage1: + Mov DI, Offset MaintenanceDirectedDestination + Mov CX, 10/2 + Rep MovsW + Mov AX, 'IT' + StosW + + Call SendMaintenancePacket + Add SI, 18 + + Dec DL + JNZ IPX_SendGroupMessage1 + + Jmp IPX_SendMessageChain + +; + +Proc IPX_SendMessage Far + + Push CS + Pop DS + + Cmp MessageEntryArea, 0 + JE IPX_SendMessageEnd + + Mov SI, Offset UserName + Mov DI, Offset MessageSenderName + Mov CX, 16/2 + Rep MovsW + + Mov [MaintenanceSendHeader], Offset MaintenanceSendHeaderBroadcast + Mov [MaintenanceSendDataOffset], Offset MessageBlock + Mov [MaintenanceSendDataSize], 73 + Call SendMaintenancePacket + +; Wait until sent, then does this.. + +IPX_SendMessageChain: + Call MaintenanceWaitForSend + + Mov SI, Offset MessageData+72 + Mov DI, Offset MessageData + Mov CX, 72*7/2 + Rep MovsW + Mov SI, Offset MessageSenderName + Mov CX, 72/2 + Rep MovsW + + Xor AX, AX + Mov DI, Offset MessageEntryArea + Mov CX, 56/2 + Rep StosW + +IPX_SendMessageEnd: + Mov AX, 1 + Ret + +EndP IPX_SendMessage +EndP IPX_SendGroupMessage + + +; + +Proc IPX_ShowConnectionDetails Far + + Push CS + Pop DS + Assume DS:IPX + + MOv DX, 1 + Mov DI, (4+15*80)*2 + Mov BX, Offset UserName1 + Call IT_S_GetDestination + +IPX_ShowConnectionDetailsLoop: + +; Want to show: +; Connection %d +; User name: %s +; User address: [hex] +; (Bytes transferred) + + Push DX + + Mov AH, 20h + Mov SI, Offset ConnectionNumberMsg + Call IT_S_DrawString + + Mov SI, BX + Mov CX, 16 + +IPX_ShowConnectionDetails1: + LodsB + StosW + Loop IPX_ShowConnectionDetails1 + + Push SI + + Add DI, 104 + Mov SI, Offset ConnectionAddressMsg + Call IT_S_DrawString + + Pop SI + + Call IPX_DrawAddress + + Mov AL, ' ' + StosW + + Call IPX_DrawHexNumber + Call IPX_DrawHexNumber + + Mov BX, SI + Add DI, 62+160 + + Pop DX + + Inc DX + + Cmp DL, NumberOfConnections + JBE IPX_ShowConnectionDetailsLoop + + Ret + +EndP IPX_ShowConnectionDetails + Assume DS:Nothing + +; + +Proc IPX_DisplayMessages Far + + Push CS + Pop DS + Assume DS:IPX + + Call IT_S_GetDestination + + Mov CX, 8 + Mov DI, (38*80+3)*2 + Mov SI, Offset MessageData + +IPX_DisplayMessages1: + Cmp Byte Ptr [SI], 0 + JE IPX_DisplayMessages4 + + Push SI + Push DI + + Push SI + Mov AH, 3 + +IPX_DisplayMessages2: + LodSB + Test AL, AL + JZ IPX_DisplayMessages5 + StosW + Jmp IPX_DisplayMessages2 + +IPX_DisplayMessages5: + Pop SI + Add SI, 16 + + Mov AL, ':' + StosW + Mov AL, ' ' + StosW + + Mov AH, 2 + +IPX_DisplayMessages3: + LodsB + StosW + Test AL, AL + JNZ IPX_DisplayMessages3 + + Pop DI + Pop SI + +IPX_DisplayMessages4: + Add SI, 72 + Add DI, 160 + Loop IPX_DisplayMessages1 + + Ret + +EndP IPX_DisplayMessages + Assume DS:Nothing + +; + +Proc IPX_ConnectionStatus Far; Returns 0 if not connected + ; Otherwise returns connection count + + Mov AL, CS:NumberOfConnections + Ret + +EndP IPX_ConnectionStatus + +; + +EndDriver: + +ProvidedVariableTableStart: + DB NUMPROVIDEDVARIABLES-($-ProvidedVariableTableStart) Dup (0) + +ProvidedProcedureTableStart: + DW Offset IPX_Initialise + DW Offset IPX_Shutdown + DW Offset IPX_DriverScreen + DW Offset IPX_Update + DW Offset IPX_ConnectionStatus + + DW NUMPROVIDEDFUNCTIONS - ($-ProvidedProcedureTableStart)/4 Dup (0) + + +; + +EndS + +End diff --git a/it/Network/MIPX.BAT b/it/Network/MIPX.BAT new file mode 100755 index 0000000..c3b9e56 --- /dev/null +++ b/it/Network/MIPX.BAT @@ -0,0 +1,5 @@ +tasm /m /la /ut310 ipx +tlink /3 ipx +execom ipx itipx.net +copy itipx.net .. + diff --git a/it/Network/NETDRIVE.ASM b/it/Network/NETDRIVE.ASM new file mode 100644 index 0000000..b394f42 --- /dev/null +++ b/it/Network/NETDRIVE.ASM @@ -0,0 +1,47 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +; + +EndDriver: + +;******** Provided Variable Table ************* + +ProvidedVariableStart: + DB NUMPROVIDEDVARIABLES-($-ProvidedVariableStart) Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + DW Offset Initialise + DW Offset Shutdown + DW Offset DriverScreen + DW Offset Update + DW Offset ConnectionStatus +ProvidedTableEnd: + DW NUMPROVIDEDFUNCTIONS-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/Network/REQPROC.INC b/it/Network/REQPROC.INC new file mode 100644 index 0000000..4f1e436 --- /dev/null +++ b/it/Network/REQPROC.INC @@ -0,0 +1,32 @@ + +ProcedureTableStart Label + +IT_UnloadDriver DD ? +IT_FunctionHandler DD ? +IT_FunctionDivider DD ? + +IT_ReceiveData DD ? +IT_SendData DD ? +IT_EstablishConnection DD ? + +IT_GotoHomeDirectory DD ? +IT_GetTime DD ? +IT_SetInfoLine DD ? + +IT_DrawHeader DD ? +IT_FillHeader DD ? + +IT_S_GetDestination DD ? +IT_S_DrawString DD ? +IT_S_SaveScreen DD ? +IT_S_RestoreScreen DD ? + +IT_GetCurrentMode DD ? + +IT_NewConnection DD ? + +IT_DecodeUserName DD ? + + DD NUMREQUIREDFUNCTIONS - ($-ProcedureTableStart)/4 Dup (0) + + diff --git a/it/Network/USERNAME.INC b/it/Network/USERNAME.INC new file mode 100644 index 0000000..56dcaf0 --- /dev/null +++ b/it/Network/USERNAME.INC @@ -0,0 +1,6 @@ +UserName DB 0FFh, 014h, 04Fh, 0F0h, 047h, 0C8h, 09Fh, 0DCh, 063h, 000h, 03Fh, 0FCh, 0AEh, 0FCh, 0AEh, 0FCh +IPXLocalAddress Label +UserKey DW 0141Eh +IPXNetworkAddress DW 0 ; Combines with previous line +IPXNodeAddress DW 0, 0, 0 +IPXSocket DW 0 diff --git a/it/Network/VTABLE.INC b/it/Network/VTABLE.INC new file mode 100644 index 0000000..9ee92e1 --- /dev/null +++ b/it/Network/VTABLE.INC @@ -0,0 +1,10 @@ + +VariableTableStart Label + +GlobalKeyList DD ? +IdleUpdateInfoLine DD ? +DiskDataArea DW ? ; Segment + + DB NUMREQUIREDVARIABLES-($-VariableTableStart) Dup (0) + + diff --git a/it/PE_TRANS.INC b/it/PE_TRANS.INC new file mode 100644 index 0000000..78a9771 --- /dev/null +++ b/it/PE_TRANS.INC @@ -0,0 +1,1703 @@ + +XMVolume DB 0 + +; + +Proc TranslateXMNote + + Cmp AL, 96 + JBE TranslateXMNote1 + + Mov AL, 0FFh-11 ; Note off + +TranslateXMNote1: + Add AL, 11 + StosB + Ret + +EndP TranslateXMNote + +; + +XMEffectG DB 193, 193+4, 193+5, 193+6, 193+6, 193+7, 193+7, 193+8 + DB 193+8, 193+9 + +; + +Proc TranslateXMInstrument + + Cmp AL, 99 + JBE TranslateXMInstrument1 + + Xor AL, AL + + Cmp Byte Ptr [ES:DI-1], 0FFh ; note off? + JE TranslateXMInstrument2 + Mov Byte Ptr [ES:DI-1], 0FDh + Jmp TranslateXMInstrument2 + +TranslateXMInstrument1: + Cmp Byte Ptr [ES:DI-1], 0FFh ; note off? + JNE TranslateXMInstrument2 + + Xor AL, AL + +TranslateXMInstrument2: + StosB + Ret + +EndP TranslateXMInstrument + +; + +Proc TranslateXMVolume + + Push AX + + Mov AH, AL + Mov DX, AX + Mov AL, 0FFh + Cmp AH, 10h ; Nothing + JB TranslateXMVolume1 + + Mov AL, AH + Sub AL, 10h + Cmp AH, 50h ; Volume + JBE TranslateXMVolume1 + + Mov AL, 0FFh + Cmp AH, 60h ; Nothing + JB TranslateXMVolume1 + + Mov AL, AH + And AX, 0F00Fh + + Cmp AL, 9 + JBE TranslateXMVolume2 + + Mov AL, 9 + +TranslateXMVolume2: + Cmp AH, 70h + JAE TranslateXMVolume3 + + Add AL, 95 ; Volume down + Jmp TranslateXMVolume1 + +TranslateXMVolume3: + Cmp AH, 80h + JAE TranslateXMVolume4 + + Add AL, 85 ; volume up + Jmp TranslateXMVolume1 + +TranslateXMVolume4: + Cmp AH, 90h + JAE TranslateXMVolume5 + + Add AL, 75 ; Fine volume down + Jmp TranslateXMVolume1 + +TranslateXMVolume5: + Cmp AH, 0A0h + JAE TranslateXMVolume6 + + Add AL, 65 ; fine volume up + Jmp TranslateXMVolume1 + +TranslateXMVolume6: + Cmp AH, 0B0h + JAE TranslateXMVolume7 + + Mov AL, 0FFh ; Vibrato speed + Jmp TranslateXMVolume1 + +TranslateXMVolume7: + Cmp AH, 0C0h + JAE TranslateXMVolume8 + + Cmp AL, 3 + JBE TranslateXMVolumeH + + Dec AX + +TranslateXMVolumeH: + Add AL, 203 ; Vibrato + Jmp TranslateXMVolume1 + +TranslateXMVolume8: + Cmp AH, 0D0h + JAE TranslateXMVolume9 + + Mov AL, DL + Sub AL, 0C0h + Mov AH, AL + ShL AL, 2 + Or AL, AH ;Panning + Add AL, 128 + Jmp TranslateXMVolume1 + +TranslateXMVolume9: + Cmp AH, 0F0h + JAE TranslateXMVolume10 + + Mov AL, 0FFh ; Pan slide left/right + Jmp TranslateXMVolume1 + +TranslateXMVolume10: ; Porta + Push BX + Mov BX, AX + And BX, 0FFh + Mov AL, [CS:XMEffectG+BX] + Pop BX + +TranslateXMVolume1: + StosB + Pop AX + Ret + +EndP TranslateXMVolume + +; + +Proc TranslateXMEffect ; Given AX = data + + Test AX, AX + JNZ TranslateXMEffect1 + +TranslateXMEffectVol: + Xor AX, AX + Cmp CS:XMVolume, 60h + JB TranslateXMEffectEnd + Mov DH, 0FFh + Jmp TranslateXMEffectVolume + +TranslateXMEffect1: + Cmp AL, 'K'-'A'+0Ah + JNE TranslateXMEffect24 + + Mov AL, [ES:DI-3] + Cmp AL, 0FDh + JNE TranslateXMEffectVol + + Mov Word Ptr [ES:DI-3], 0FFh + Jmp TranslateXMEffectVol + +TranslateXMEffect24: + Cmp AL, 0 + JNE TranslateXMEffect2 + + Mov AL, 'J'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect2: + Cmp AL, 1 + JNE TranslateXMEffect3 + + Mov AL, 'F'-'@' + Test AH, AH + JNZ TranslateXMEffectEnd + Cmp CS:XMVolume, 60h + JB TranslateXMEffectEnd + Mov DH, 105 + Jmp TranslateXMEffectVolume + +TranslateXMEffect3: + Cmp AL, 2 + JNE TranslateXMEffect4 + + Mov AL, 'E'-'@' + Test AH, AH + JNZ TranslateXMEffectEnd + Cmp CS:XMVolume, 60h + JB TranslateXMEffectEnd + Mov DH, 115 + Jmp TranslateXMEffectVolume + +TranslateXMEffect4: + Cmp AL, 3 + JNE TranslateXMEffect5 + + Mov AL, 'G'-'@' + Test AH, AH + JNZ TranslateXMEffectEnd + Cmp CS:XMVolume, 60h + JB TranslateXMEffectEnd + Mov DH, 193 + Jmp TranslateXMEffectVolume + +TranslateXMEffect5: + Cmp AL, 4 + JNE TranslateXMEffect6 + + Mov AL, AH + And AX, 0FF0h + Cmp AH, 4 + JBE TranslateXMEffectH1 + + Dec AH + +TranslateXMEffectH1: + Or AH, AL + Mov AL, 'H'-'@' + Test AH, AH + JNZ TranslateXMEffectEnd + Cmp CS:XMVolume, 60h + JB TranslateXMEffectEnd + Mov DH, 203 + Jmp TranslateXMEffectVolume + +TranslateXMEffect6: + Cmp AL, 5 + JNE TranslateXMEffect7 + + Mov AL, 'L'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect7: + Cmp AL, 6 + JNE TranslateXMEffect8 + + Mov AL, 'K'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect8: + Cmp AL, 7 + JNE TranslateXMEffect9 + + Mov AL, 'R'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect9: + Cmp AL, 8 + JNE TranslateXMEffect10 + + Mov AL, 'X'-'@' + Cmp CS:XMVolume, 60h + JB TranslateXMEffectEnd + Mov DH, AH + ShR DH, 2 + AdC DH, 128 + Jmp TranslateXMEffectVolume + +TranslateXMEffect10: + Cmp AL, 9 + JNE TranslateXMEffect11 + + Mov AL, 'O'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect11: + Cmp AL, 0Ah + JNE TranslateXMEffect12 + + Mov AL, 'D'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect12: + Cmp AL, 0Bh + JNE TranslateXMEffect13 + + Mov AL, 'B'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect13: + Cmp AL, 0Ch + JNE TranslateXMEffect14 + + Mov DH, AH + Cmp DH, 64 + JB TranslateXMEffectVolume + + Mov DH, 64 + +TranslateXMEffectVolume: + Mov AL, CS:XMVolume + Mov AH, AL + And AH, 0Fh + + Cmp AL, 60h + JAE TranslateXMEffectVolume1 + + Xor AX, AX + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume1: + Cmp AL, 70h + JAE TranslateXMEffectVolume2 + + Mov AL, 'D'-'@' + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume2: + Cmp AL, 80h + JAE TranslateXMEffectVolume3 + + Mov AL, 'D'-'@' + ShL AH, 4 + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume3: + Cmp AL, 90h + JAE TranslateXMEffectVolume4 + + Mov AL, 'D'-'@' + Test AH, AH + JZ TranslateXMEffect3Memory + Or AH, 0F0h + Cmp AH, 0FFh + JNE TranslateXMEffect3Memory + + Dec AH + +TranslateXMEffect3Memory: + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume4: + Cmp AL, 0A0h + JAE TranslateXMEffectVolume5 + + Mov AL, 'D'-'@' + Test AH, AH + JZ TranslateXMEffect4Memory + + ShL AH, 4 + Or AH, 0Fh + +TranslateXMEffect4Memory: + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume5: + Cmp AL, 0B0h + JAE TranslateXMEffectVolume6 + + Mov AL, 'H'-'@' + ShL AH, 4 + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume6: + Cmp AL, 0C0h + JAE TranslateXMEffectVolume7 + + Cmp AH, 4 + JBE TranslateXMEffectVolumeH6 + + Dec AH + +TranslateXMEffectVolumeH6: + Mov AL, 'H'-'@' + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume7: + Cmp AL, 0D0h + JAE TranslateXMEffectVolume8 + + Mov AL, 'S'-'@' + Or AH, 80h + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume8: + Cmp AL, 0E0h + JAE TranslateXMEffectVolume9 + + Mov AL, 'P'-'@' + ShL AH, 4 + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume9: + Cmp AL, 0F0h + JAE TranslateXMEffectVolume10 + + Mov AL, 'P'-'@' + Jmp TranslateXMEffectVolumeEnd + +TranslateXMEffectVolume10: + Mov AL, 'G'-'@' + ShL AH, 4 + +TranslateXMEffectVolumeEnd: + Mov [ES:DI-1], DH + StosW + Ret + +TranslateXMEffect14: + Cmp AL, 0Dh + JNE TranslateXMEffect15 + + Mov AL, AH + And AX, 0F00Fh + ShR AH, 1 + Add AL, AH + ShR AH, 2 + Add AH, AL + Mov AL, 'C'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect15: + Cmp AL, 0Eh + JNE TranslateXMEffect16 + + ; 'Multiplex' effect + Mov AL, AH + And AX, 0FF0h + Test AL, AL + JNZ TranslateXMEffectE1 + + Xor AX, AX + Jmp TranslateXMEffectEnd + +TranslateXMEffectE1: + Cmp AL, 10h + JNE TranslateXMEffectE2 + + Test AH, AH + JZ TranslateE1Memory + Or AH, 0F0h + +TranslateE1Memory: + Mov AL, 'F'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectE2: + Cmp AL, 20h + JNE TranslateXMEffectE3 + + Test AH, AH + JZ TranslateE2Memory + Or AH, 0F0h + +TranslateE2Memory: + Mov AL, 'E'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectE3: + Cmp AL, 30h + JNE TranslateXMEffectE4 + + Xor AX, AX + Jmp TranslateXMEffectEnd + +TranslateXMEffectE4: + Cmp AL, 40h + JNE TranslateXMEffectE5 + + Or AH, 30h + Mov AL, 'S'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectE5: + Cmp AL, 50h + JNE TranslateXMEffectE6 + + Xor AX, AX + Jmp TranslateXMEffectEnd + +TranslateXMEffectE6: + Cmp AL, 60h + JNE TranslateXMEffectE7 + + Or AH, 0B0h + Mov AL, 'S'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectE7: + Cmp AL, 70h + JNE TranslateXMEffectE8 + + Or AH, 040h + Mov AL, 'S'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectE8: + Cmp AL, 80h + JNE TranslateXMEffectE9 + + Or AH, 80h + Mov AL, 'S'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectE9: + Cmp AL, 90h + JNE TranslateXMEffectEA + + Mov AL, 'Q'-'@' + Test AH, AH + JNZ TranslateXMEffectEnd + Jmp TranslateXMEffectVol + +TranslateXMEffectEA: + Cmp AL, 0A0h + JNE TranslateXMEffectEB + + Test AH, AH + JZ TranslateXMEAMemory + + ShL AH, 4 + Or AH, 0Fh + +TranslateXMEAMemory: + Mov AL, 'D'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectEB: + Cmp AL, 0B0h + JNE TranslateXMEffectEC + + Test AH, AH + JZ TranslateXMEBMemory + + Or AH, 0F0h + Cmp AH, 0FFh + JNE TranslateXMEBMemory + + Dec AH + +TranslateXMEBMemory: + Mov AL, 'D'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectEC: + Cmp AL, 0C0h + JNE TranslateXMEffectED + + Or AH, 0C0h + Mov AL, 'S'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectED: + Cmp AL, 0D0h + JNE TranslateXMEffectEE + + Or AH, 0D0h + Mov AL, 'S'-'@' + + Jmp TranslateXMEffectEnd + +TranslateXMEffectEE: + Cmp AL, 0E0h + JNE TranslateXMEffectEF + + Or AH, 0E0h + Mov AL, 'S'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffectEF: + Xor AX, AX + Jmp TranslateXMEffectEnd + +TranslateXMEffect16: + Cmp AL, 0Fh + JNE TranslateXMEffect18 + + Mov AL, 'T'-'@' + Cmp AH, 20h + JAE TranslateXMTempo1 + + Mov AL, 'A'-'@' + +TranslateXMTempo1: + Jmp TranslateXMEffectEnd + +TranslateXMEffect18: + Cmp AL, 10h ; 'G'lobal volume + JNE TranslateXMEffect19 + + Mov AL, 'V'-'@' + Cmp AH, 40h + JB TranslateXMEffectV + + Mov AH, 80h + Jmp TranslateXMEffectEnd + +TranslateXMEffectV: + ShL AH, 1 + Jmp TranslateXMEffectEnd + +TranslateXMEffect19: + Cmp AL, 11h ; 'H' + JNE TranslateXMEffect20 + + Mov AL, AH + And AX, 0FF0h + ShL AH, 1 + Cmp AH, 0Fh + JBE TranslateGlobalVolSlide2 + + Mov AH, 0Fh + +TranslateGlobalVolSlide2: + ShL AL, 1 + JNC TranslateGlobalVolSlide1 + + Mov AL, 0F0h + +TranslateGlobalVolSlide1: + Or AH, AL + Mov AL, 'W'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect20: + Cmp AL, 'R'-'A'+0Ah + JNE TranslateXMEffect21 + + Mov AL, 'Q'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect21: + Cmp AL, 'T'-'A'+0Ah + JNE TranslateXMEffect22 + + Mov AL, AH + And AX, 0FF0h + Test AH, AH + JNZ Tremor1 + + Inc AH + +Tremor1: + Test AL, AL + JNZ Tremor2 + + Inc AX +Tremor2: + Or AH, AL + Mov AL, 'I'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect22: + Cmp AL, 'X'-'A'+0Ah + JNE TranslateXMEffect23 + + Mov AL, AH + And AX, 0FF0h + Or AH, 0E0h + Cmp AL, 10h + JE TranslateXMEffectX1 + Cmp AL, 20h + JE TranslateXMEffectX2 + + Xor AX, AX + Jmp TranslateXMEffectEnd + +TranslateXMEffectX1: + Mov AL, 'F'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffectX2: + Mov AL, 'E'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEffect23: + Cmp AL, 'Z'-'A'+0Ah + JNE TranslateXMEffect25 + + Mov AL, 'Z'-'@' + Jmp TranslateXMEffectEnd + +TranslateXMEFfect25: + Jmp TranslateXMEffectVol +; Xor AX, AX + +TranslateXMEffectEnd: + StosW + Ret + +EndP TranslateXMEffect + +; + +Proc PE_TranslateXMPattern Far ; DS:SI points to + ; data, AX = rows + ; CX = channels + ; DX = pattern num + + ; Has to return DS:SI + PushA + Push DS + Push ES + + Dec AX + Mov CS:TempVariableArea3, AX + Cmp AX, 31 + JAE PE_XMLimitRows + + Mov AX, 31 + +PE_XMLimitRows: + Mov CS:MaxRow, AX + Mov CS:PatternNumber, DX ; Pattern number + Mov CS:TempVariableArea2, CX ; Channels + + Call PE_ClearPatternData + + Mov ES, CS:PatternDataArea + Xor DI, DI + Xor AX, AX ; AX = row number + +PE_TranslateXMPattern1: + Push AX + Push DI + + Mov CX, CS:TempVariableArea2 ; CX = channels + +PE_TranslateXMPattern2: + Push CX + + LodsB ; AL = either note or compression + ; control. + Test AL, AL + JS PE_TranslateXMPatternCompressed + + Call TranslateXMNote + LodsB + Call TranslateXMInstrument + LodsB + Mov CS:XMVolume, AL + Call TranslateXMVolume + LodsW + Call TranslateXMEffect + Jmp PE_TranslateXMPattern3 + +PE_TranslateXMPatternCompressed: + Mov CS:XMVolume, 0 + Mov AH, AL + Test AH, 1 + JZ PE_TranslateXMPattern4 + + LodsB + Call TranslateXMNote + Dec DI + +PE_TranslateXMPattern4: + Inc DI + + Test AH, 2 + JZ PE_TranslateXMPattern5 + + LodsB + Call TranslateXMInstrument + Dec DI + +PE_TranslateXMPattern5: + Inc DI + + Test AH, 4 + JZ PE_TranslateXMPattern6 + + LodsB + Mov CS:XMVolume, AL + Call TranslateXMVolume + Dec DI + +PE_TranslateXMPattern6: + Inc DI + + Xor AL, AL + Test AH, 8 + JZ PE_TranslateXMPattern7 + + LodsB + +PE_TranslateXMPattern7: + Test AH, 10h + Mov AH, 0 + JZ PE_TranslateXMPattern8 + + Mov AH, [SI] + Inc SI + +PE_TranslateXMPattern8: + Call TranslateXMEffect + +PE_TranslateXMPattern3: + Pop CX + Dec CX + JNZ PE_TranslateXMPattern2 + + Pop DI + Pop AX + Add DI, 320 ; Next row. + Inc AX + Cmp AX, CS:TempVariableArea3 + JBE PE_TranslateXMPattern1 + + Mov CS:TempVariableArea, SI + + Mov AX, CS:TempVariableArea3 + Cmp AX, CS:MaxRow + JE PE_TranslateXMPatternNoBreak + + Mov DX, 320 + Mul DX + Mov DI, AX + Add DI, 3 + +PE_TranslateXMPatternBreak1: + Cmp Word Ptr [ES:DI], 0 + JE PE_TranslateXMPatternBreak2 + + Add DI, 5 + Jmp PE_TranslateXMPatternBreak1 + +PE_TranslateXMPatternBreak2: + Mov Word Ptr [ES:DI], 'C'-'@' ; Break. + +PE_TranslateXMPatternNoBreak: + Push CS + Pop DS + + Call Far Ptr PE_TranslateS3MPointer8 + + + Pop ES + Pop DS + PopA + + Mov SI, CS:TempVariableArea + + Ret + +EndP PE_TranslateXMPattern + +; + +Proc TranslateMODCommand ; AL = command + ; AH = command value + ; ES:DI points to + ; command destination + + Test AX, AX + JNZ TranslateMODCommand7 + + StosW + Ret + +TranslateMODCommand7: + Cmp AL, 0 + JNE TranslateMODCommand8 + + Mov AL, 'J'-'@' + StosW + Ret + +TranslateMODCommand8: + Cmp AL, 1 + JNE TranslateMODCommand9 + + Mov AL, 'F'-'@' + Jmp TranslateMODCommand36 + +TranslateMODCommand9: + Cmp AL, 2 + JNE TranslateMODCommand10 + + Mov AL, 'E'-'@' + Jmp TranslateMODCommand36 + +TranslateMODCommand10: + Cmp AL, 3 + JNE TranslateMODCommand11 + + Mov AL, 'G'-'@' + StosW + Ret + +TranslateMODCommand11: + Cmp AL, 4 + JNE TranslateMODCommand12 + + Mov AL, 'H'-'@' + + StosW + Ret + +TranslateMODCommand12: + Cmp AL, 5 + JNE TranslateMODCommand13 + + Mov AL, 'L'-'@' + Test AH, AH + JNZ TranslateMODCommand40 + + Mov AX, 'G'-'@' + +TranslateMODCommand40: + StosW + Ret + +TranslateMODCommand13: + Cmp AL, 6 + JNE TranslateMODCommand14 + + Mov AL, 'K'-'@' + Test AH, AH + JNZ TranslateMODCommand39 + + Mov AX, 'H'-'@' + +TranslateMODCommand39: + StosW + Ret + +TranslateMODCommand14: + Cmp AL, 7 + JNE TranslateMODCommand15 + + Mov AL, 'R'-'@' + StosW + Ret + +TranslateMODCommand15: + Cmp AL, 8 + JNE TranslateMODCommand16 + + Mov AL, 'X'-'@' + Cmp AH, 0A4h + JNE TranslateMODNoSurround + + Mov AX, 'S'-'@'+9100h + +TranslateMODNoSurround: + StosW + Ret + +TranslateMODCommand16: + Cmp AL, 9 + JNE TranslateMODCommand17 + + Mov AL, 'O'-'@' + StosW + Ret + +TranslateMODCommand17: + Cmp AL, 10 + JNE TranslateMODCommand18 + + Mov AL, 'D'-'@' + Test AH, 0Fh + JZ TranslateMODVolumeSlide1 + Test AH, 0F0h + JZ TranslateMODVolumeSlide1 + + And AH, 0F0h + +TranslateMODVolumeSlide1: + Jmp TranslateMODCommand36 + +TranslateMODCommand18: + Cmp AL, 11 + JNE TranslateMODCommand19 + + Mov AL, 'B'-'@' + StosW + Ret + +TranslateMODCommand19: + Cmp AL, 12 + JNE TranslateMODCommand20 + + Cmp AH, 64 + JBE TranslateMODCommand37 + + Mov AH, 64 + +TranslateMODCommand37: + Mov [ES:DI-1], AH + Add DI, 2 + Ret + +TranslateMODCommand20: + Cmp AL, 13 + JNE TranslateMODCommand21 + + Mov AL, AH + And AX, 0F00Fh + ShR AH, 1 ; AH = highnibble*8 + Add AL, AH + + ShR AH, 2 ; AH = highnibble*2 + Add AH, AL + + Mov AL, 'C'-'@' + StosW + Ret + +TranslateMODCommand21: + Cmp AL, 14 + JNE TranslateMODCommand34 + + Mov AL, AH + And AX, 0FF0h + + Cmp AL, 0 + JNE TranslateMODCommand22 + + Test AH, AH + JZ TranslateMODCommand36 + + Mov AL, 'S'-'@' + StosW + Ret + +TranslateMODCommand22: + Cmp AL, 10h + JNE TranslateMODCommand23 + + Test AH, AH + JZ TranslateMODCommand36 + + Mov AL, 'F'-'@' + Or AH, 0F0h + StosW + Ret + +TranslateMODCommand23: + Cmp AL, 20h + JNE TranslateMODCommand24 + + Test AH, AH + JZ TranslateMODCommand36 + + Mov AL, 'E'-'@' + Or AH, 0F0h + StosW + Ret + +TranslateMODCommand24: + Cmp AL, 30h + JNE TranslateMODCommand25 + + Mov AL, 'S'-'@' + Or AH, 010h + StosW + Ret + +TranslateMODCommand25: + Cmp AL, 40h + JNE TranslateMODCommand26 + + Mov AL, 'S'-'@' + Or AH, 030h + StosW + Ret + +TranslateMODCommand26: + Cmp AL, 50h + JNE TranslateMODCommand27 + + Mov AL, 'S'-'@' + Or AH, 020h + StosW + Ret + +TranslateMODCommand27: + Cmp AL, 60h + JNE TranslateMODCommand28 + + Mov AL, 'S'-'@' + Or AH, 0B0h + StosW + Ret + +TranslateMODCommand28: + Cmp AL, 70h + JNE TranslateMODCommand29 + + Mov AL, 'S'-'@' + Or AH, 40h + StosW + Ret + +TranslateMODCommand29: + Cmp AL, 80h + JNE TranslateMODCommand30 + + Or AH, AL + Mov AL, 'S'-'@' + StosW + Ret + +TranslateMODCommand30: + Cmp AL, 90h + JNE TranslateMODCommand31 + + Test AH, AH + JZ TranslateMODCommand36 + + Mov AL, 'Q'-'@' + Jmp TranslateMODCommand36 + +TranslateMODCommand31: + Cmp AL, 0A0h + JNE TranslateMODCommand32 + + And AH, 0Fh + JZ TranslateMODCommand36 + + Mov AL, 'D'-'@' + ShL AH, 4 + Or AH, 0Fh + StosW + Ret + +TranslateMODCommand32: + Cmp AL, 0B0h + JNE TranslateMODCommand33 + + And AH, 0Fh + JZ TranslateMODCommand36 + + Mov AL, 'D'-'@' + Or AH, 0F0h + StosW + Ret + + +TranslateMODCommand33: + Or AH, AL + Mov AL, 'S'-'@' + StosW + Ret + +TranslateMODCommand34: ; Set speed. + Cmp AH, 20h + JA TranslateMODCommand35 + + Mov AL, 'A'-'@' + Jmp TranslateMODCommand36 + +TranslateMODCommand35: + Mov AL, 'T'-'@' + StosW + Ret + +TranslateMODCommand36: + Test AH, AH + JNZ TranslateMODCommand38 + + Xor AX, AX + +TranslateMODCommand38: + StosW + Ret + +EndP TranslateMODCommand + +; + +Proc PE_TranslateMTMPattern Far ; DS:SI points to data + ; DX = pattern no. + PushA + Push DS + Push ES + + Mov CS:MaxRow, 63 + Mov CS:PatternNumber, DX + + Call PE_ClearPatternData + + Mov ES, CS:PatternDataArea + Xor DI, DI + + Mov CX, 32 + +PE_TranslateMTMPattern1: + Push CX + Push DI + + Mov CX, 64 + +PE_TranslateMTMPattern2: + LodsW ; Layout of AX + XChg AH, AL + ; ppppppiiiiiieeee + ; p = pitch val + ; i = ins + ; e = effect + Mov DL, AL + And DL, 0Fh ; DL = effect. + ShR AX, 2 ; AX = 00pppppp iiiiiixx + ShR AL, 2 ; AH = pitch, AL = ins. + XChg AH, AL ; AH = ins. AL =pitch + + Test AL, AL + JZ PE_TranslateMTMPattern3 + + Add AL, 36 ; Middle octave C-5 + Jmp PE_TranslateMTMPattern4 + +PE_TranslateMTMPattern3: + Mov AL, NONOTE + +PE_TranslateMTMPattern4: + StosB ; Pitch. + + Mov AL, AH ; Instrument + Mov AH, 0FFh ; volume + StosW + + LodsB ; DL = effect, AL = effectval. + Mov AH, AL ; AH = AL = effectval. DL = eff. + Mov AL, DL + + Call TranslateMODCommand + + Add DI, 315 + Loop PE_TranslateMTMPattern2 + + Pop DI + Pop CX + Add DI, 5 + Loop PE_TranslateMTMPattern1 + + Push CS + Pop DS + Call Far Ptr PE_TranslateMODPattern1 + + Pop ES + Pop DS + PopA + + Ret + +EndP PE_TranslateMTMPattern + +; + +Proc PE_TranslateMODPattern Far ; DS:SI points to data + ; DX = pattern no. + ; AX = number of channels + PushA + Push DS + Push ES + + Mov CS:MaxRow, 63 + Mov CS:PatternNumber, DX + + Call PE_ClearPatternData + + Mov ES, CS:PatternDataArea + Xor DI, DI + Mov CX, 64 + +PE_TranslateMODPattern2: + Push AX + Push CX + Push DI + + Mov CX, AX + +PE_TranslateMODPattern3: + Mov AL, [DS:SI+1] + Mov AH, [DS:SI] + And AX, 0FFFh ; AX = period of note. + Mov DX, 72 + Xor BX, BX + +PE_TranslateMODPattern4: + Cmp AX, [CS:MODPeriodTable+BX] + JAE PE_TranslateMODPattern5 + + Add BX, 2 + Dec DX + JNZ PE_TranslateMODPattern4 + + Inc DI + Jmp PE_TranslateMODPattern6 + +PE_TranslateMODPattern5: + ShR BX, 1 ; BL = note. + Mov AL, BL + Add AL, 36 ; For C5 as central note. + StosB + +PE_TranslateMODPattern6: + Mov AL, [DS:SI] + Mov AH, [DS:SI+2] + ShR AH, 4 + And AL, 0F0h + Or AL, AH + StosB ; Sample stored. + + Inc DI ; Points to effect/commandvalue + + Mov AH, [DS:SI+3] + Mov AL, [DS:SI+2] + And AL, 0Fh ; AL = effect, AH = param. + + Call TranslateMODCommand + + Add SI, 4 + Loop PE_TranslateMODPattern3 + + Pop DI + Pop CX + Pop AX + Add DI, 320 + Loop PE_TranslateMODPattern2 + + Push CS + Pop DS + Call Far Ptr PE_TranslateMODPattern1 + + Pop ES + Pop DS + PopA + + Ret + +PE_TranslateMODPattern1: + Call PEFunction_StorePattern + + RetF + +EndP PE_TranslateMODPattern + +; + +Proc PE_Translate669Pattern Far + + PushA ; DS:0 points to data + Push DS ; CL = Maxrow + Push ES ; AH = Starting tempo + ; BP = PatternNumber + Mov Byte Ptr [CS:MaxRow], CL + Mov [CS:PatternNumber], BP + + Call PE_ClearPatternData + + Mov ES, CS:PatternDataArea + Cmp CL, 31 + JAE Pattern669Rows + + Mov [CS:MaxRow], 31 + + Mov AL, 5 + Mul CL + Mov DI, AX + ShL DI, 6 + + Mov Word Ptr [ES:DI+8*5+3], 'C'-'@' + +Pattern669Rows: + Xor DI, DI + + Mov AL, 'A'-'@' + Mov [ES:DI+8*5+3], AX ; Tempo setting + Inc CL + Xor SI, SI + + Xor EAX, EAX + Mov BP, Offset EncodingInfo + Mov [CS:BP], EAX + Mov [CS:BP+4], EAX + Mov [CS:BP+8], EAX + Mov [CS:BP+12], EAX + +Translate669Pattern1: + Mov CH, 8 + +Translate669Pattern2: + LodsW + Cmp AL, 0FEh + JB Translate669Pattern4 + JE Translate669Pattern3 + + Add DI, 3 + Jmp Translate669Pattern5 + +Translate669Pattern3: + Add DI, 2 + ShR AX, 6 + And AL, 3Ch + StosB + Jmp Translate669Pattern5 + +Translate669Pattern4: + Mov DX, AX ; Note + + And AX, 0F003h + ShL AL, 4 + ShR AH, 4 + Or AH, AL + Inc AH + Mov AL, DL + ShR AL, 2 + Add AL, 36 + StosW + + Mov AL, DH ; Volume + ShL AL, 2 + And AL, 3Ch + StosB + + Mov Word Ptr [CS:BP], 0 + +Translate669Pattern5: + LodsB + + Cmp AL, 0FFh + JE Translate669NoEffect + + Mov AH, AL + And AX, 00FF0h + +Translate669EffectA: ; Portamento Up + Cmp AL, 0 + JNE Translate669EffectB + + Mov AL, 'F'-'@' + Mov [CS:BP], AX + Jmp Translate669EffectEnd + +Translate669EffectB: ; Portamento down + Cmp AL, 10h + JNE Translate669EffectC + + Mov AL, 'E'-'@' + Mov [CS:BP], AX + Jmp Translate669EffectEnd + +Translate669EffectC: ; Portamento to + Cmp AL, 20h + JNE Translate669EffectD + + Mov AL, 'G'-'@' + Mov [CS:BP], AX + Jmp Translate669EffectEnd + +Translate669EffectD: ; Frequency Adjust + Cmp AL, 30h + JNE Translate669EffectE + + Mov AX, ('E'-'@')+0F100h + Mov Word Ptr [CS:BP], 0 + Jmp Translate669EffectEnd + +Translate669EffectE: ; Vibrato + Cmp AL, 40h + JNE Translate669EffectF + + Mov AL, 'H'-'@' + Or AH, 80h + Mov [CS:BP], AX + Jmp Translate669EffectEnd + +Translate669EffectF: + Cmp AL, 50h + JNE Translate669NoEffect + + Mov AL, 'A'-'@' + Mov Word Ptr [CS:BP], 0 + Jmp Translate669EffectEnd + +Translate669NoEffect: + Mov AX, [CS:BP] + +Translate669EffectEnd: + StosW + + Add BP, 2 + + Dec CH + JNZ Translate669Pattern2 + + Add DI, 320-8*5 + Mov BP, Offset EncodingInfo + + Dec CL + JNZ Translate669Pattern1 + + Push CS + Pop DS + + Call Far Ptr PE_TranslateS3MPointer8 + + Pop ES + Pop DS + PopA + + Ret + +EndP PE_Translate669Pattern + +; + +Proc PE_TranslateS3MPattern Far ; DS:SI points to data. + ; DX = pattern no. + PushA + Push DS + Push ES + + Mov CS:MaxRow, 63 + Mov CS:PatternNumber, DX + + Call PE_ClearPatternData + + Mov ES, CS:PatternDataArea + Xor DI, DI + Mov CX, 64 + +PE_TranslateS3MPattern1: + Push DI + +PE_TranslateS3MPattern2: + LodsB + Test AL, AL + JNZ PE_TranslateS3MPattern3 + + Pop DI + Add DI, 320 + + Loop PE_TranslateS3MPattern1 + + Push CS + Pop DS + + Call Far Ptr PE_TranslateS3MPointer8 + + Pop ES + Pop DS + PopA + + Ret + +PE_TranslateS3MPointer8: + Call PEFunction_StorePattern + + RetF + +PE_TranslateS3MPattern3: + Push DI + Mov BH, AL + And AL, 31 + Mov AH, 5 + Mul AH ; DI+AX = offset. + Add DI, AX + Test BH, 32 + JZ PE_TranslateS3MPattern6 + + LodsB +; Cmp AL, 0FFH +; JE PE_TranslateS3MPattern5 + Cmp AL, 0FEh + JE PE_TranslateS3MPattern4 + Cmp AL, 07Fh + JA PE_TranslateS3MPattern5 + + Mov BL, AL + And BL, 0Fh + ShR AL, 4 + Mov AH, 12 + Mul AH + Add AL, BL + Add AL, 12 ; C5 is now central octave + Mov [ES:DI], AL ; Note + Jmp PE_TranslateS3MPattern5 + +PE_TranslateS3MPattern4: + Mov Byte Ptr [ES:DI], 0FEh + +PE_TranslateS3MPattern5: + LodsB ; Instrument + Cmp AL, 99 + JBE PE_TranslateS3MPattern13 + + Xor AL, AL + +PE_TranslateS3MPattern13: + Mov [ES:DI+1], AL + +PE_TranslateS3MPattern6: + Test BH, 64 + JZ PE_TranslateS3MPattern7 + + LodsB ; Volume + Cmp AL, 64 + JBE PE_TranslateS3MPattern12 + Cmp AL, 0FFh + JE PE_TranslateS3MPattern12 + + Mov AL, 64 + +PE_TranslateS3MPattern12: + Mov [ES:DI+2], AL + +PE_TranslateS3MPattern7: + Test BH, 128 + JZ PE_TranslateS3MPattern8 + + LodsW + Cmp AL, 'C'-'@' + JNE PE_TranslateS3MPattern9 + + Mov AL, AH + And AX, 0F00Fh + ShR AH, 1 + Add AL, AH + ShR AH, 2 + Add AH, AL + Mov AL, 'C'-'@' + Jmp PE_TranslateS3MPattern10 + +PE_TranslateS3MPattern9: + Cmp AL, 'V'-'@' + JNE PE_TranslateS3MPattern11 + + Jmp PE_TranslateS3MPattern14 + +PE_TranslateS3MPattern11: + Cmp AL, 'X'-'@' + JNE PE_TranslateS3MPattern15 + + Cmp AH, 0A4h + JNE PE_TranslateS3MPattern14 + + Mov AX, 'S'-'@'+9100h + Jmp PE_TranslateS3MPattern10 + +PE_TranslateS3MPattern14: + ShL AH, 1 + JNC PE_TranslateS3MPattern10 + + Mov AH, 0FFh + Jmp PE_TranslateS3MPattern10 + +PE_TranslateS3MPattern15: + Cmp AL, 'D'-'@' + JNE PE_TranslateS3MPattern10 + Test AL, 0Fh + JZ PE_TranslateS3MPattern10 + Test AL, 0F0h + JZ PE_TranslateS3MPattern10 + + Mov BL, AH + Mov BH, AH + And BX, 0FF0h + Cmp BH, 0Fh + JE PE_TranslateS3MPattern10 + Cmp BL, 0F0h + JE PE_TranslateS3MPattern10 + + And AH, 0Fh + +PE_TranslateS3MPattern10: + Mov [ES:DI+3], AX + +PE_TranslateS3MPattern8: + Pop DI + + Jmp PE_TranslateS3MPattern2 + +EndP PE_TranslateS3MPattern + + diff --git a/it/README.md b/it/README.md new file mode 100644 index 0000000..ba510c0 --- /dev/null +++ b/it/README.md @@ -0,0 +1,138 @@ +Impulse Tracker +=============== + +Full source code for Impulse Tracker, including sound drivers, network drivers, +and some supporting documentation + +  + +Pre-Requisite Software +---------------------- + +To build Impulse Tracker, you will need: + +- Turbo Assembler v4.1 + +- Turbo Link v3.01 + +- Borland MAKE v4.0 + +- A DOS environment + +  + +Once you have these, building IT.EXE should be just a single call to `MAKE` + + +Sound drivers are build individually via M\*.BAT files inside the SoundDrivers +subdirectory + +  + +Quick File Overview +------------------- + +- IT.ASM: + Startup routines + +- IT\_DISK.ASM: + Disk IO Routines. Uses IT\_D\_\*.INC files + +- IT\_DISPL.ASM: + Display routines for the Playback Screen (F5) + +- IT\_EMS.ASM: + EMS memory handling routines + +- IT\_F.ASM: + Collection of functions used by the object model + +- IT\_FOUR.ASM: + Fast Fourier routines. Used by the graphic equalizer (Alt-F12). + Not available on all all sound cards + +- IT\_G.ASM: + Global key handler functions + +- IT\_H.ASM: + Help Module (F1) + +- IT\_I.ASM: + Sample list (F3) and Instrument list (F4) module + +- IT\_K.ASM: + Keyboard module + +- IT\_L.ASM: + Information line code + +- IT\_M.ASM: + Main message loop/dispatcher + +- IT\_MDATA.ASM: + Global music variable data + +- IT\_MMTSR.ASM: + Sample compression/decompression routines + +- IT\_MOUSE.ASM: + Mouse handling code + +- IT\_MSG.ASM: + Message editor module (Shift-F9) + +- IT\_MUSIC.ASM: + Module playback code. Also uses IT\_M\_EFF.INC + +- IT\_NET.ASM: + Network code + +- IT\_OBJ1.ASM: + UI object definitions + +- IT\_PE.ASM: + Pattern Editor module (F2) + +- IT\_S.ASM: + Screen functions, including character generation + +- IT\_TUTE.ASM: + Interactive Tutorial module + +- IT\_VESA.ASM: + VESA code for graphic equalizer + +- SWITCH.INC: + High level switches for the program + + + +Frequently Asked Questions +-------------------------- + +Q: "What are all those funny characters in the source code?" + +A: I wrote the original source code using DOS characters, with characters drawing borders/boxes in +comments in the source code. In the interests of posterity, I have left the code intact as it was. + + +Q: "Why didn't you use STRUCs or ENUMs" in your ASM source? + +A: Simply because I didn't know about them at the time. I wish I did. There's a InternalDocumentation +folder that I've included in the repository that details what some of the magic numbers appearing +through the code might mean. + + +Q: "Flow in some functions seems to jump all over the place. Why?" + +A: The original code was compatible all the way back to an 8086 machine. 8086 would allow you to do +conditional jumps only within +/-128 bytes, so I spent too much time shuffling code around to meet +this restriction. When I shifted away from this 8086 restriction, I never went back to update the +code that was mutilated by it. +  + + +License +------- + +License for this source code is pending. diff --git a/it/ReleaseDocumentation/BUGS.TXT b/it/ReleaseDocumentation/BUGS.TXT new file mode 100644 index 0000000..d571358 --- /dev/null +++ b/it/ReleaseDocumentation/BUGS.TXT @@ -0,0 +1,39 @@ + +OK.. here's a list of the known problems - please don't write to me about them! + +1) Apparently, many problems have been encountered with QEMM... I really + don't know what's going wrong here at the moment (I haven't had any + experience with QEMM myself), but try using the following line in your + CONFIG.SYS file. If this still doesnt' work, I would recommend that you + steer clear of QEMM if possible for the meantime. + + DEVICE=\QEMM.SYS DMA=64, HANDLES=255 + +2) With the GUS, 16-bit samples > 256k will *NOT* be played correctly. This is + due to a 'quirk' of the GUS - something that I don't know how to easily fix. + This does *NOT* occur with 8-bit samples. (This is the same problem that + you'll find in FastTracker II also) + +3) The "Active Channels" indication is *NOT* always 100% accurate (it's + even affected by stuff played in muted channels.....) Also, on a GUS or + AWE32, the program requires the hardware to provide the 'end of note + indication', whereas the mixing routines are calculated internally... + hence, if the hardware provides the indication a little later than expected, + another channel is allocated - what this means is that the value as played + on wavetable cards *MAY* differ from the value played on software-mixed + cards. This difference is minor (ie. 2 channels at most, unless you *TRY* + to setup a special situation) + +4) There is no 'enforce Amiga limits' option in IT (Which was in ST3) so + pitches of notes exceeding the Amiga limit will not be suitably played. + +5) If your system behaves unexpectedly in IT, it *MAY* be necessary to + specify the complete parameter list on the command line. This should NOT + be a problem in most cases, but it has been known to occur. + +6) In Windows '95, if you shell to DOS when using SB on a high IRQ, then + playback may stop! I've got no idea as to why this happens, but it seems + to restore itself after loading another module (on a SB16) + +7) If you Shell to DOS with insufficient memory available, WEIRD things may + occur... diff --git a/it/ReleaseDocumentation/CONTRIB.TXT b/it/ReleaseDocumentation/CONTRIB.TXT new file mode 100644 index 0000000..8c60373 --- /dev/null +++ b/it/ReleaseDocumentation/CONTRIB.TXT @@ -0,0 +1,595 @@ + + To all of the following people listed, I offer my heartfelt thanks. + Impulse Tracker would not be the same without them. + + --------------------------------- + Demosongs for Impulse Tracker + --------------------------------- + + IT1.00 - "Firestorm" - Chris Jarvis + IT1.01 - "Pale Dreams" - Chris Jarvis + IT1.03 - "Firepower" - Chris Jarvis + IT1.05 - "Sidewalk" - Chris Jarvis + IT1.06 - "Creation of Gaia" - Sherman Wu (ZaStaR) + IT2.00 - "Fallen World" - Chris Jarvis + IT2.01 - "A Hidden Fate" - Chris Jarvis + IT2.04 - "Winter's Dream" - Andy Sega (Necros) + IT2.08 - "Acid Dreams" - Liam Widdowson (Legend) + IT2.14 - "Blue Flame" - Chris Jarvis + + + ----------------------------------------- + Additional Coding for Impulse Tracker + ----------------------------------------- + + Impulse Tracker Font Customiser - Sherman Wu (ZaStaR) + Impulse Tracker Text Importer - Sherman Wu (ZaStaR) + Music Module Compression - Emmanual Giasson (Zirconia) + Keyboard Configuration files - Stefan Kucharik (Eliot) + + + ---------------------- + Website Management + ---------------------- + + USA Site - Shawn Mativetsky (Shawn202) + http://www.noisemusic.org/it + UK Site - Andi Simpson (Imminent) + http://www.mixbbs.demon.co.uk + European Site - Joost Baaij (CH:ilm) + (no longer operational) + Spanish Site - Javier Gutierrez + http://www.musica.org/impulse + Music and Tracking Site - Matthias Ziegs (MAZ) + http://www.maz-sound.com + IT Resource Central - Matthew Gardner + http://www.unidev.com/~logic/music/it + + + ---------------------- + Documentation Help + ---------------------- + + ASCII Logos - Ze`ev Nissan (Cruel Creator) + FILE_ID.DIZ - Ze`ev Nissan (Cruel Creator) + MIDI Output documentation - Andre Pang (Ozone) + + +-------------------------------------------------------------------------------- + + Hardware Thanks + + (Sorted alphabetically by company name) + + --------------------------------------- + +Company: Advanced Micro Devices (AMD) +Received: Interwave Board +Website: http://www.amd.com +Notes: AMD has discontinued the production of the Interwave chips. + Nonetheless, thank-you to Christopher Cox for his excellent service. + + --------------------------------------- + +Company: Creative Laboratories +Received: Sound Blaster AWE32 +Website: http://www.creaf.com + + --------------------------------------- + +Company: Hanmesoft / Hoontech, Korea +Received: Sound Track '97 + Sound Track '97 PCI +Website: http://www.hoontech.com +Notes: The Sound Track '97 PCI is the worlds first fully SBPro and WSS + compatible PCI card and has some of the best features ever seen + on a soundcard! For bangs per buck, it's hard to beat one of these! + + Thanks go to Haejin Park and to Seungho Pak! + + --------------------------------------- + +Company: Synergy Advanced Technology (Taiwan) +Received: ViperMAX +Website: http://www.synergy.ca/pctoybox +Notes: For a fully compatible Gravis UltraSound card with perfect Sound + Blaster compatibility, check out the ViperMAX cards - providing + the best of two worlds without the troubles of PnP. + + Special thanks go to James Hsu, Synergy Advanced Technology. + + --------------------------------------- + +Company: TerraTec International +Received: AudioSystem EWS64XL + SoundSystem Maestro 32/96 + SoundSystem Maestro 16/96 + SoundSystem Gold 16/96 + SoundSystem Base1 +Website: http://www.terratec.de +Notes: Terratec produces extremely high quality soundcards to cover + everyone's needs - check out their high end EWS64XL cards! + + Thanks go to the entire Terratec Team, especially Kay Bruns, + Wim Roegels and Sascha Kamps - 3 of the team that I've had + the pleasure to come in contact with! + + +-------------------------------------------------------------------------------- + + Contributions + ----------------- + +(sorted in alphabetical order, listing is Full Name / Alias / Country + notes) + +Name Alias Country Notes +------------------------------------------------------------------------------- + + Dire Portugal + KjWise Iceland +Egor Abramov Russia +Habib Al-Assaad +Tony Allen UK MEGA HUGE contribution, thanks! +Simon Altman P'Wolverine Australia +Tal Amir Israel +Asbjoern Andersen Mystical Denmark +Steven Anderson USA Big contribution, thanks! +Mikael Andersson Sweden +Thomas Andersson Divion Sweden +Peter Andries Belgium +Jose Angel Spain +Tor Erik Arntzen Norway +Nicolas Arrouet Onix4MAN France +Patrick Arzul Sth Africa Big contribution, thanks! +Tal Asa +Peter Askelf Sweden +Hans-Joachim Backe Germany +Martin Bahner Norway +Erick Baker USA Big contribution, thanks! +Rodger Ballard Saqquara USA +Brandon Bannerman Catspaw USA +John Barger USA MEGA HUGE contribution, thanks!! +Alex Barnell England +Matthew Barnes USA +Jayson Barrons USA +Claus Bartels Germany +Jonathan Bartlett +Michael Baumann Germany +David Benjamin USA +Brian Bennetts Daedalus USA +Vaughan Bentley South Africa +John Bergman USA Big contribution, thanks! +Jeff Best Australia +Allen Bettilyon Tremlo USA +Bastiaan Bijl Thanatos Netherlands +Mike Blaine +Christian Bode Germany +Lembrecht Bodo Germany +Fabian Boes Germany +Vicente Beltran Boil Razz Spain +Zozo Bogyo Hungary Big contribution, thanks! +Nathan Bonfiglio Ash Please contact me! +Eman Borg Malta +Gianluca Bove Yello '73 Italy +Martin Boverhof Netherlands +Alexander Brandon Siren USA +Yannis Brown Yannis Australia +Remko Brugman Digistorm Netherlands +Michael Buchholtz Germany Big contribution, thanks! +Jrg Burbach Germany +Mike Burrell MikPos Canada +Clay Busker USA Big contribution, thanks! +Jeremy Butcher Netherlands +Robert Buecker III USA +Gunnar Buettner Germany +Jim Cairns Canada +Rimas Campe USA +Mike Cantelon Foolish Bird Canada +Isaac Carrasco Spain Big contribution, thanks! +Edward Cashin USA +Zach Cappelletti Shams Kitz USA +Michael Carlsson Silverstance Sweden +Christopher Castiglione USA +Nilton Catsillo Chile +Hector Chang ZoneSeek Canada Big contribution, thanks! +Eric Charlent Spher-X France +Eric Chavanon France +Andy Chen USA +Charles Cho Deadsoul USA Big contribution, thanks! +Kenny Chou USA +Rick Christy GrymmJack USA +Rogier Claessens Netherlands Big contribution, thanks! +Jeff Clement Canada +David Clipperton Canada +Mike Cody USA +Shoshi Cohen Israel +Caleb Coppock USA Big contribution, thanks! +Ben Cormier Canada +David Cornish Australia Big contribution, thanks! +Martin Cosgrave UK +Antony Cowderoy UK +David Cox-Espenlaub USA +Matt Cramer USA +Jim Crawford Pfister USA +Dan Cunningham Pentatonic USA Big contribution, thanks! +Daniel Cunningham Ireland +David Cuny USA +Nicholas Dahlin Denmark +Chad Dahlquist +Christopher Daniel USA +Tristan Daniel Jesus2099 France +Thomas Daniels III USA MEGA HUGE contribution, thanks! +Ben Dany +Tulio Guimaraes da Silva Brazil HUGE contribution, thanks! +Dave Davis USA +Tomer Dayan Israel +Fabio De Araujo Neves Brazil +Benoit De Greift Eagle Belgium +David Dean Sector4 Australia +Pierre Decourcelles France Big contribution, thanks! +Barthelemy Defossez France +Guy Detienne Belgium +John Dietzel USA +John Di Giacomo USA +Luciano Di Lucrezia Spectrum Big contribution, thanks! +Nick Dinges Germany +Robin Dittwald Satixu Germany +Siem Doodeman Netherlands +Asaf Dor +Stephen Dredge Australia +Andrew Dun Australia +Dave Dunger Australia +Andrew Durk USA +Florian Dvorski Thunk Germany +Brendan Ebel USA +Adam Ebringer Australia +Michael Edwards UK +John Ehmann Canada +Richard Eijkenbroek Netherlands +Michael Elis Isreal +Garrett Ellis USA +Irad Eshel Israel +Scott Esposto USA +Alexander Ewering Internal Germany +Gary Feinmesser England +Nick Feldman UK +Jim Fergusson USA +Robin Fernandes France +Dan Fetherstonhaugh England +Reuben Firmin Rubz Scotland Big contribution, thanks! +Kyle Fischer USA +Edward Flick USA +Brad Folkens USA +Adam Frank USA +Andrew Franks Derelict USA +Graham Freeman Australia +Calvin French Canada +Joseph Freund Australia +David Friberg USA +Matt Friedly Subliminal USA +Richard Funke Norway +James Furness UK +Robert Gage Australia +Miles Gannett USA +Peter Gaywood UK +Christopher General Canada +Giovanni Giampieri Italy Big contribution, thanks! +Slavko Glamocanin Slovenia +Owen Godwin USA +Markus Goetz Cookie Jar Germany Big contribution, thanks! +John Goforth USA +David Goodale Canada +Ferdinand Gozum DJ USA +Jeff Graham USA HUGE contribution, thanks! +Joseph Graham BrianXavier USA +Micah Greenlay USA +Lorenzo Grifi Italy +Sebastian Grillmaier Wayfinder Germany +Moritz Grimm Maxx Germany +Karsten Grombach Germany Big contribution, thanks! +Ariel Gross Stalker USA HUGE contribution, thanks! +Sylvian Guiraud France Big contribution, thanks! +Joe Hahn USA +Peter Hajba Skaven Finland +Doris Hamburger USA +Tim Hamers Netherlands +David Hamilton England +Eric Hamilton Dilvish USA Big contribution, thanks! +John Harris USA +Todd Hartley Tronster USA +Ian Haskin SiN Canada +John Hastie USA +Joshua Hastey Ith USA +Thomas Havelka USA +David Hays D-Range USA +Axel Hedfors Sweden +Brett Helgeson Australia Big contribution, thanks! +Greg Heo Canada Big contribution, thanks! +Liam Hesse Lemm England +Anthony Hicks USA +Robert Hilpert Germany MEGA HUGE contribution, thanks! +Erik Hjelmvik Tweety Sweden +Jason Hlisic isotone Australia Big contribution, thanks! +John Hobson USA +Rune Holm TitanStar Norway +Krystal Holstein USA Big contribution, thanks! +Alexandre Holzhey Brazil +Aake Honkaniemi PAH Finland Big contribution, thanks! +Raymon Hoving Finland +Troy Howard USA Big contribution, thanks! +Ben Howell Rhythm USA +Shu Hung Canada Big contribution, thanks! +Ryan Hunt Pinion USA +David Hunter USA +Steve Hunter UK Big contribution, thanks! +Samuel Hurst Australia +Kohan Ikin Australia +Sam Izzo Jestyr Australia +Shane Jackson MetaMan Canada +Keith Jagielski USA +Daniel Janiak Redrick Slovakia Big contribution, thanks! +Marko Janssen Netherlands +Simon Jarosch Vivid Germany +Chris Jarvis Australia +Dave Jeavons Realclean Australia HUGE contribution, thanks! +James Jeen Australia +Joshua Jersild USA +Jan Jirak Czechoslovakia +Robert Johnson Xenopraxis +Mischa Jonker Netherlands +Ben Just Australia Big contribution, thanks! +Jaakko Kaivosoja Finland +Steffen Kamprath Germany +Frank Kane USA +Ben Kapper Netherlands +Ilpo Karkkainen Griffin Finland +Tero Karkinen Finland +Thomas Karolczak Mindflyer XS +Cole Kelley USA +Keith Kelly Syrinx USA +Mehran Khalili Screamager Luxembourg +Leonard Khiroug USA +Richard Kidwell USA +Thomas Kim USA +David Klande Germany +Martin Kleinman Brain Netherlands +Martin Klossek Germany +Bart Knol Armadon Netherlands +Stephen Knowles USA +Odd Henry Knutsen Netherlands +Henning Koch Germany +Alexander Koenig Germany +David Kondrad USA +Zaf Korbetis Australia Big contribution, thanks! +Evan Korzon USA +Christopher Kowalski USA +Kristof Kowalski Cyntax Australia +Kevin Krebs Canada +Bert Kroes Netherlands +Peter Kunath Germany MEGA HUGE contribution, thanks! +Rich La Bonte Flatrich USA +Michael Ladanyi Canada +Brian J LaMattina USA +Perttu Lamminmki Finland +William Lamy willbe France +Adam Langdon-Thomas UK +Janet Lankester USA +Patrick Lea Australia +Jon Leahy UK HUGE contribution, thanks! +Steven LeBeau USA +Eliot Lee PrOtoCoL USA Big contribution, thanks! +Nicolas Leveille Knos France +Buzz Libre USA +Rik Ling USA +Randy Locklair USA MEGA HUGE contribution, thanks! +Michael Loftus USA MEGA HUGE contribution, thanks! +Kris Long USA +Jerome Majewski USA HUGE contribution, thanks! +Sami Mkinen Finland +Don Manton Canada +Peter Mares South Africa +Anthony Marin Verminator USA +Norman Mark Nothing More Canada +Alexander Martin Germany +Mike Ma'rton Hungary +Akos Matte Bat & Cyborg Hungary +Lucas Higa Mattsson Sweden +Nicola McAleer Ireland +Brad McKinnon EtherWizard USA Big contribution, thanks! +Ray McManus USA +Keith McNally Canada +Glen McNiece Australia +Vincent Meijer Netherlands +Mitchell Menghi Australia +David Menkes Behemoth USA +Mike Merker Canada +Jonathan Mesiano-Crookston Canada +Christopher Micali Zephyr USA +John Michael-Lloyd USA Big contribution, thanks! +Chris Michetti Canada +Pekka Mikkola Finland +Alex Milla Spain +Matthew Miller Australia HUGE contribution, thanks! +Tracey Miller Australia Big contribution, thanks! +Matthew Mitchell USA Big contribution, thanks! +Chun-Yan Miu Hong Kong +Mauro Molinari DjM Italy +Lutz Mller Germany +Jo Moore USA +Freddy Mousseau France +Marten Mons Netherlands +F. Edmund Mueller USA +Markus Mueller G42 Germany Big contribution, thanks! +Paul Munson Canada +Aaron Murray USA +Eric Nadeau Canada +Riley Nagler USA +Tirone Nel South Africa +Frank Nentwich Germany +Mikkel Nordberg Denmark HUGE contribution, thanks! +Gary Norris USA +Fumihiro Odaki Japan +Michiyasu Odaki Japan +John O'Laughlin USA +Anthony Oetzmann AiRON Germany +Xavier Orengo USA +Frido Otten Cybertron Netherlands Big contribution, thanks! +Olli Paasovaara Finland +Robert Pain UK +Jonathan Pak Maelstrom Australia +Andre Pang Ozone Australia +Adam Parker USA +Jourden Parks AllenKray USA +Kiran Patil USA Big contribution, thanks! +Stefan Pavlov +Christian Pfaff Germany Big contribution, thanks! +Jean-Luc Pedneault Canada +Nick Pelling UK +P-J Perrussel-Morin CyberNitrox France Big contribution, thanks! +Chaim Peter-Chester USA +Claus Peterson Denmark Big contribution, thanks! +Felix Petrescu Waka X Romania +Henri Pihkala Estonia +Jason Phelps USA Big contribution, thanks! +Miklavz Pirnat +Eddie Plaskur Mexican Beans Australia +Harout Pogossian HP +Eric Pomerleau O'Realitea Canada +Pascal Q. Porcupine Spikey USA Big contribution, thanks! +William Price USA +Alexander Rahm Germany HUGE contribution, thanks! +Hazhir Ranjram Balk USA +Alessandro Rascazzo Antitesi Italy +Pasi Rastas Finland +Justin Ray Zinc Canada +Tobias Reckhard Jester Germany +Jimmy Redfern Jimmy Ireland +Justin Reid Stein USA +Viktor Rez Hungary +Owyn Richen +Dan Richters USA Big contribution, thanks! +Jay Ridley Australia +Michael Riegel USA +Todd Rieger USA Big contribution, thanks! +James Rimmer USA +Brendan Robert USA +Jeff Robinson USA +Josh Rodman K8to USA MEGA HUGE contribution, thanks! +Jens Roeben Germany +Nick Rose Phantasm Canada +Ryan Ross Canada +Benjamin Rumbaugh USA +Keijo Ruonamaa Gze Finland +Geert Rutten Loonatic Netherlands +Hannu Salonen Salomon Finland +Kevin Salt Netherlands +Mark Sanders USA +Denis dos Santos Brazil +Adi Sapir Doc Israel +Janne Savolainen Finland +Ben Saylor USA Big contribution, thanks! +Konrad Schandera iCEWiND GERMANY +H.R. Scheper-Keuter Josuf Netherlands +Gerben Schmidt Netherlands +Martin Schmidt Germany +Daniel Schwab Germany +Wolfgang Schwarz Germany Big contribution, thanks! +Matthew Scott USA +Kristian Sergiejew Poland +Saurin Shah Nebula USA +Jarrod Sharp Australia +Dan Shaw USA +Ryan Shaw USA +Shaul Shentai Israel HUGE contribution, thanks! +Philip Shipley USA +Oren Shomron Isreal +Josh Silvey USA +Morten Skarstad Norway +Peter Skeide Norway MEGA HUGE contribution, thanks! +Steven Slater Canada +Martijn Sneijder Netherlands +Trond Smevik Poke Norway +Greg Smith Canada +Zachary Smith Dr. Zachary USA +Christoph Sllner AGENT S Germany +Scott Sorenson USA +Nicolas Soudee Zoner USA Big contribution, thanks! +Michael Soutar MSoutar Australia +Kasper Souren Netherlands +Patrick Stacey Australia +Nick Stanfield UK +Andrew Ryan Stinnett USA +Ian Stocker RabiteMan USA Big contribution, thanks! +Mark Straver Moonchild Netherlands +Jer Sypult USA +Charles Tabourot France +Ravon Tamar RavEon Israel +Patrice Tarabbia Mercure France +Jason Le Sueur Tatum USA Big contribution, thanks! +Thor Teague USA +Michael Teehan USA Big contribution, thanks! +Michel ten Voorde Netherlands +Franck Theuex France Big contribution, thanks! +Michael Thomas USA +Sebastian Thomas Scotland +Jaymz Thompson +Philip Thompson UK +Franz Thues Germany +Gabriele Tittarelli T.S.P. Italy +Jason Tracer Electric Keet USA +Nash Trajkowski Australia +Eric Tremblay DeltaX Canada +Brad Turcotte Canada +Michael Twarkowsky Germany +Asbjorn Ulsberg Norway +Martin Underwood UK +Jani Visnen Finland +Mathew Valente TSSF Canada +David Van Dromme Stormlord Belgium +Ryan Van Eerdewijk Canada +Marti Van Lin +Erik Van Hengstum Netherlands +Ernst Van Rossum Netherlands +Filip Van Schoor Cantaloup Belgium +Jan Van Stiphout +Maarten Van Strien Crystal Score Netherlands +Jos vd Geest Netherlands +Oscar Vela Spain +Markus Visti Finland +Ganesh Viswanathan Genosha India +Benjamin Vogt Australia +Edwin Volkmer Netherlands +Vincent Voois Vv Netherlands MEGA HUGE contribution, thanks! +Fredrik Von Braun Sweden +Arno Vryman Netherlands +Petri Vuorio Finland +Ben Waddington Australia Big contribution, thanks! +Gerd Wagner Germany +Chris Wallace CTS USA +Thomas Walter Subsonic Australia +Adrian Ward England HUGE contribution, thanks! +Timothy Weller Flukey USA +Bill Wells USA +Mike Wells USA +Inyoung Whang USA +Jemi White Australia +Brian Wickman CD USA +Liam Widdowson Legend Australia +Gene Wie Psibelius USA Big contribution, thanks! +David Wiernicki Perisoft USA Big contribution, thanks! +John Williams Jackal USA +John Wilson USA +Tobias Wilton Sweden Big contribution, thanks! +Mathias Wintzer +Marco Wotschadlo Germany +Doug Wright Netriangle USA +Fuming Wu Adi Taiwan +Takeshi Yamamoto Japan Huge contribution, thanks! +Shane Yates AlphaRISC Australia +David Zearing USA +Daniel Zegiel USA +Matthias Ziegs MAZ Germany + +... where's your name? :) + + diff --git a/it/ReleaseDocumentation/DRIVERS.TXT b/it/ReleaseDocumentation/DRIVERS.TXT new file mode 100644 index 0000000..0e8e9a9 --- /dev/null +++ b/it/ReleaseDocumentation/DRIVERS.TXT @@ -0,0 +1,577 @@ + + Notes about the sound drivers + + Be sure to check the driver screen (Shift-F5) of your soundcard! + + I often get asked what soundcard I believe is the best. + + My favourite soundcard is the SBLive! produced by Creative Labs. + + + + Driver Summary + +Driver Def/Max Quick- Stereo Bits Mixing Rate/Resolution + Channels select MIDI In/Out available? + +VSound Driver 64/256 Auto Yes 16 8kHz to 64kHz +VSound Driver MMX 128/256 Auto Yes 16 8kHz to 64kHz + For more details on the VSound drivers, check ITVSOUND.TXT + +PC Speaker 64/256 /S1 No 5-7 12->44kHz +DAC on LPT 64/256 No 8 12->44kHz +GUS, Hardware * 32/32 /S7 Yes 16 19->44kHz (A) +GUSMAX, Software * 64/256 Yes 16 8->64kHz +Interwave, Hardware * 32/32 /S8 Yes 16 44kHz, MIDI In + Out +Sound Blaster 1.0 * 64/256 /S2 No 8 12kHz->22kHz +Sound Blaster 2.0 * 64/256 /S3 No 8 12kHz->44kHz +Sound Blaster Pro * 64/256 /S4 Yes 8 6kHz->22kHz (B) + No 8 12kHz->44kHz (B) +Sound Blaster 16 * 64/256 /S5 Yes 16 12kHz->44kHz, MIDI In +Sound Blaster AWE 32* 30/30 Yes 16 44kHz, MIDI In + Out +Pro Audio Spectrum 64/256 /S9 Yes 8 12->44kHz +Pro Audio Spectrum 16 64/256 /S10 Yes 16 12->44kHz +Windows Sound System * 64/256 /S11 Yes 16 8->64kHz +ESS 1868 AudioDrive * 64/256 /S12 Yes 16 22->56.8kHz, MIDI In +ESS 1688 AudioDrive 64/256 Yes 16 8->48kHz +EWS64 Codec * 64/256 /S13 Yes 16 8->48kHz +Ensoniq SoundscapeVIVO* 64/256 /S14 Yes 16 8->48kHz +SoundTrack PCI * 64/256 Yes 16 8->48kHz + +MPU401 MIDI Driver - /S19 - - MIDI In + Out + +Disk Writer * 256/256 /S20 Yes 16 8->64kHz + +* = Driver will play in the background of Windows '95 + +Notes +A) Depends on number of channels used. The hiquality GUS driver reinitialises + the GUS continually to use as few channels as necessary. Some GUS cards + cannot cope with this and you will need to use the alternative ITGUSLO.DRV + instead. +B) The mixing rate of the SBPro depends on whether playback is stereo or mono + + + +PC Speaker (ITPCSPKR.DRV) + + Nothing much else to say here, except... GET A SOUND CARD! :) + + Note: On the info page, using the 'variables' display WILL distort + PC Speaker output. Also, it has been found that the Info Page + screens and the Pattern Editor cause a noticeably higher amount + of hiss through the speaker. + + Note: This driver *MAY NOT* work on laptop's piezo-electric speakers. + + Note: No driver screen available. + + Note: Not for use with Win95 + + + +DAC on LPT 1/2 Drivers + + These drivers are almost exactly the same as the PC speaker drivers, + with only minor modifications. + + To use these, run IT /sITLPT1.DRV or IT /sITLPT2.DRV - depending on + which LPT you have your DAC plugged into. + + Note: If you're interested in building your own parallel port DAC, + check out: http://www.dnc.net/users/collver/dac.htm + or: ftp://ftp.informatik.hu-berlin.de/pub/os/linux/hu-sound/ + + Note: No driver screen available. + + Note: On the info page, using the 'variables' display WILL distort + PC Speaker output. Also, it has been found that the Info Page + screens and the Pattern Editor cause a noticeably higher amount + of hiss through the speaker. + + + + +Gravis UltraSound, Hardware mixing (ITGUS.DRV) + + This file actually contains two drivers in one file. The first is + accessed just by using IT (with no command line parameters, or with + /s7 for Gravis UltraSound). This is equivalent to the original + internal driver that came with previous versions of Impulse Tracker. + + The second driver is selected by providing the correct IRQ for the + GF1 chip. (The second-to-last number of your ULTRASND environment + variable). This is an IRQ driven routine, which means that it'll + work in the background of Windows '95. But note that the timing for + this is NOT as accurate as the timing in the first driver. There is + also a possibility that multitasking OSs can sometimes (although + rarely) cause some settings to the GUS to be missed (which will cause + a note to play unexpectedly). This can be fixed just by restarting + playback. There is NO check for the correctness of the IRQ provided. + Note that the IRQ driven routine doesn't seem to work on all + computers either.. :( + + The Gravis UltraSound *CANNOT* cope with 16-bit samples greater than + 256k-bytes. This is equivalent to 128k-length samples. Also, 16-bit + samples cannot cross 256k boundaries on the GUS, meaning that the + amount of memory you have on the card may decrease by more than you + expect when you load a 16-bit sample. + + You cannot choose the mixing rate for the GUS - the mixing rate is + dependent on the number of channels playing. This driver continuously + reinitialises the GUS to use as few channels as possible. You can + further restrict the number of channels used with /Lxx on the command + line of Impulse Tracker. + +Gravis UltraSound 2, Hardware mixing (ITGUS2.DRV) + + If the first Gravis UltraSound driver clicks continuously when nothing + is supposed to be playing, use this driver ("IT /sITGUS2.DRV"). + + This driver file also contains two drivers - check above on how to + access the second driver. + +Gravis UltraSound Lo-freq, Hardware mixing (ITGUSLO.DRV) + + Only use this driver if notes do *NOT* finish playing off correctly + on your GUS. ("IT /sITGUSLO.DRV" or copy ITGUSLO.DRV over ITGUS.DRV) + This driver does not try to continuously reinitialise the card to use + a minimum number of channels like the above two drivers do. + + + +Gravis Ultrasound MAX - Software mixing (ITGUSMAX.DRV) + + This device has ONLY been included because it works for SOME people. + It has NEVER worked under Win95 with GUS drivers installed as far as + I know. If it doesn't work for you - I'm sorry, you'll have to use + the hardware drivers. Don't write to me and complain if they don't + work for you - you probably won't get a reply. + + To use this driver, you MUST specify your GUSMAX's Codec IRQ *AND* + DMA on the command line as: + + IT /sITGUSMAX.DRV /i /d + + If you want to specify a port (which should be auto-detected OK), + the port is of the Codec, NOT the GUS's Base Address. + (ie. 32Ch NOT 220h) + + Note: After some testing, it *seems* that you'll need an ULTRINIT + of version 2.28a or above to use this driver... + +Here's part of an EMail that I received from Jarkko Seppanen on how he got +ITGUSMAX.DRV working: + +I just found a weird way to make the GUS MAX software mixer to work (for me, +at least). I normally use DMA 6 for playback and DMA 7 for recording. I was +playing around with IT and trying to get the driver to work and changed +both DMAs to 1. And for my surprise it started to work. Next I tried it +with both DMAs 6, with the same result. But the funny thing is, when I +first play a song with both DMAs the same and then change them back to the +original (6 and 7), it still works. I'm using IT v2.11 with ultrinit v2.31. + + + +InterWave Driver - Hardware mixing (ITIW.DRV) + (This includes GUS PnP, GUS PnP Pro, WavExtreme 32 Pro + more) + + You *NEED* to have RAM onboard your soundcard to use this driver, + otherwise your Interwave card will NOT be detected. + + This file actually contains two drivers in one file. The first is + accessed just by using IT (with no command line parameters, or with + /s8 for AMD Interwave IC). This is similar to the original internal + GUS driver that came with previous versions of Impulse Tracker. + + The second driver is selected by providing the correct IRQ for the + Interwave chip. (This is the value given in Windows'95/settings/ + control panel/system/Interwave SYNTH/IRQ). This is an IRQ driven + routine, which means that it'll work in the background of Windows '95. + But note that the timing for this is NOT as accurate as the timing in + the first driver. There is also a possibility that multitasking OSs + can sometimes (although rarely) cause some settings to the GUS to be + missed (which will cause a note to play unexpectedly). This can be + fixed just by restarting playback (or reinitialising in severe cases). + + There is NO check for the correctness of the IRQ provided. + + The Interwave driver contains handlers for two different memory modes + on the Interwave - the more memory efficient mode is where the amount + of ram is directly compatible with the interwave, the second is where + the DRAM configuration is NOT directly compatible with the interwave + and the driver has to handle the RAM slightly more explicitly, which + causes the loss of memory-usage efficiency. + + Here are the modes directly compatible with the interwave: + + Bank 0 Bank 1 Bank 2 Bank 3 Total + 256Kb 0 0 0 256Kb + 256Kb 256Kb 0 0 512Kb + 256Kb 256Kb 256Kb 256Kb 1MB + 256Kb 1MB 0 0 1.25MB + 256Kb 1MB 1MB 1MB 3.25MB + 256Kb 256Kb 1MB 0 1.5MB + 256Kb 256Kb 1MB 1MB 2.5MB + 1MB 0 0 0 1MB + 1MB 1MB 0 0 2MB + 1MB 1MB 1MB 1MB 4MB + 4MB 0 0 0 4MB + * 4MB 4MB 0 0 8MB + * 4MB 4MB 4MB 4MB 16MB + + * These modes cannot be handled by the first driver, so are actually + handled in the second mode. + + The mixing rate for the Interwave driver is fixed at 44100Hz + (CD quality) + + Bug warning: If the sound does NOT play properly, you may need to + run IWINIT before running Impulse Tracker + + + +Sound Blaster 1.0 driver (ITSB.DRV) + + The Sound Blaster has a mixing range of 12000->21739 Hz. You CANNOT + hear any stereo (or surround) effects with this driver, because the + Sound Blaster does NOT support stereo. + + Hardware detection routines are used for Address (eg. 220h), + environment is checked for IRQ and DMA. + + Command line arguments for IRQ and DMA are NOT checked but assumed + correct IF this driver is explicitly selected + (IT /s2 or IT /sITSB.DRV). + +Sound Blaster 2.0 driver (ITSB2.DRV) + + The Sound Blaster 2 driver is basically the same as the Pro driver + with stereo options removed... (ie SB2 cannot do stereo). The + mixing range is from 12000 to 43478 Hz. + + Hardware detection routines are used for Address (eg. 220h), + environment is checked for IRQ and DMA. + + Command line arguments for IRQ and DMA are NOT checked but assumed + correct IF this driver is explicitly selected (IT /s3 or + IT /sITSB2.DRV). + +Sound Blaster Pro driver (ITSBPRO.DRV) + + The Sound Blaster Pro has a mixing range of 12000->43478 in mono mode, + or 6000->21739 in stereo mode. + + Hardware detection routines are used for Address (eg. 220h), + environment is checked for IRQ and DMA. + + Command line arguments for IRQ and DMA are NOT checked but assumed + correct IF this driver is explicitly selected + (IT /s4 or IT /sITSBPRO.DRV). + +Sound Blaster 16 driver (ITSB16.DRV, ITSB16B.DRV, ITSB16C.DRV) + + The Sound Blaster 16 has a mixing range of 12000->45454 in either mono + or stereo modes. + + If you specify this driver ( IT /s5 or IT /sITSB16.DRV ) AND an IRQ + or DMA, IT will try to *FORCE* the SB16 to use the IRQ/DMA. + + eg. On my system, I have my SB16 configured to IRQ 2, DMA 5, but I + can force it to use IRQ 7, DMA 0 with IT /s5 /i7 /d0 + + Hardware detection routines are used for all Address, IRQ and DMA. + + Note: If you select either of the 32-bit mixing modes, then volumes + between 0->32768 are used internally instead of 0->128. + + The second driver, ITSB16B.DRV is a cut down version of the main + driver which does NOT have the advanced mixing options - the only + benefit of this is that it requires less memory. To use this, type: + "IT /sITSB16B.DRV". If you want to have this file automatically used + just copy it over ITSB16.DRV. + + To get MIDI input, I had to do this in Win95: + + Goto "My Computer", right click -> properties -> device manager -> + sound, video and multimedia -> SB16/AWE32 DSP + + Now go to the "resources" tab, and unclick "Use automatic settings" + + Either: + 1) Change your MIDI port from 300h to 330h or + 2) Select a 'basic configuration' which doesn't include the MIDI port + + ( 3) Get an updated driver from Creative Labs, if they've fixed it ) + + Click OK, then click OK on the warning message. + + There is a good chance that it should work now. I believe this is a + bug in the older Win95 SB16 drivers. (I *know* that the SB16 driver + I have prevents MIDI in DOS boxes and is the cause of these problems + because if I remove it, MIDI works flawlessly in DOS boxes in in Win95) + +;---------- ITSB16C.DRV -------- + + I finally managed to encounter a computer which wouldn't accept IT's + old SB16 drivers - and hence I created ITSB16C.DRV. + If you run ITSB16.DRV and the playback cursor does NOT move, then + you MUST close your Win95 box (or restart your computer), *then* run: + + IT /sITSB16C.DRV + + This driver is similar to ITSB16B.DRV in that it is a cut down + version of the full SB16 driver, but this one also has the MIDI + input disabled (which seems to be causing all the problems on the + cards which just won't 'play') + + + +Sound Blaster AWE 32 drivers (ITAWE32.DRV, ITAWE32B.DRV) + + The Sound Blaster AWE 32 driver directly uses the EMU8000 synth chip. + This synth chip has several limitations which you should be aware of: + + It can only use 16-bit samples. + 8 bit samples are automatically converted by IT (so that's not a + problem), but your free memory may decrease by double of what you + expect. (eg. you will need at least 1MB of memory to load 512k + of 8 bit samples) + + It doesn't support ping pong loops or no loops. + IT will automatically expand ping pong loops and will pad non-looped + samples with silence, but this makes sample sustain loops impossible + to implement fully. It also means that ping pong looped samples + could take up to double the memory of forwards looped samples. + + Sustain loops will NOT operate on the AWE32 driver. Instead, they + will be treated as NORMAL loops. + + If you change the loop type from none->forwards or + forwards->ping pong or ping pong->none, you WILL need to reload + the samples each time (Ctrl-G). If you change the loop points on + a sample, you *will* have to reload the samples (Ctrl-G) + + Has a limited frequency range - from the programming information, + it seems that it is impossible to play a note at above 176kHz. + This equates to any notes 2 octaves above middle C (or higher) for + a sample at 44kHz. If a note is not played because of this + frequency limitation, a message will show at the top of the screen + indicating that the frequency range has been exceeded. + + Note: The Address used for the SB AWE 32 is the address of the EMU8000, + NOT the address of your SB. (for command line params, eg A660) + + Note: This driver is NOT used as a default, as many users would benefit + more from the SB16 driver. (I recommend having at least 2MB + of memory if you want to use this driver). Run "IT /s6" if you + do want to use this driver. + + Note: This driver can operate in Win95. In this mode, it uses a + different mechanism which allows the playing of music in the + background, but timing is *NOT* as accurate here (accurate to + around 100 milli seconds as opposed to 800 nano seconds per + frame) + + Note: The second driver, ITAWE32B.DRV, is for people who do *NOT* have + a floating point unit (ie. 386, 486SX computers). ITAWE32.DRV + is preferred as it requires less memory. + + To access ITAWE32B.DRV, run "IT /sITAWE32B.DRV" + + + +Pro Audio Spectrum (ITPAS.DRV) +Pro Audio Spectrum 16 (ITPAS16.DRV) + + BIG thanks to Pelusa for VITAL programming information for this!! + BIG thanks to MZ/PoP for lending me a PAS16 to stuff around with!! + + Note: These drivers will *NOT* work in the background of Win95, + although they will work fine in the foreground. + + Note: You NEED to have the MVSOUND.SYS driver installed for these + to operate or a Window's system driver. + + + +Windows Sound System (ITWSS.DRV, ITWSS2.DRV) + + Again, BIG thanks to Pelusa for VITAL programming information for this! + + ITWSS is a 16-bit driver, with output frequencies ranging from 8kHz to + 64kHz (!). Mixing speeds above 48kHz *MAY* not work on all Windows + Sound System Cards. + + ITWSS.DRV is a completely IRQ driven routine. Although this may not be + compatible with *ALL* soundcards, it permits background playback in + Windows'95 and is FAR MORE EFFICIENT than ITWSS2.DRV. ITWSS2.DRV should + be used if ITWSS doesn't operate properly. + + Note: There is *NO* autodetection on IRQ/DMA. You *will* need to set + these on the command line if they are not IRQ7/DMA1. + + If you *DO* specify IRQ and/or DMA, then it must be DMA 0, 1 or 3, + and IRQ 7, 9 10 or 11. Impulse Tracker will attempt to SET the DMA/IRQ + of your WSS card to these values, in a similar manner to how the SB16 + driver operates. + + + +ESS ES1868 AudioDrive (ITES1868.DRV) + + The drivers for the ESS ES1868 AudioDrive use the PnP registers to + detect/configure this soundcard. If you have disabled the PnP on the + card the driver may not work... + + The default mixing rate is 44kHz, although the card can handle up to 56kHz + + Thanks go out to Diablo for pointing me in the right direction to find + the programming information and Andrew Lee for lending me a card to + program with! + + + +ESS ES1688 AudioDrive (ITES1688.DRV) + + This driver was written for Synergy ViperMAX / GUS Extreme soundcards, + so that the codec may be used to write songs > 1MB large. + + Thanks go to James Hsu / Synergy for providing me with a card to work on. + + + +EWS64 XL Codec (ITEWSCOD.DRV) + + Like the ESS ES1868 Audiodrive, this card uses the PnP registers to + detect/configure the soundcard. The default mixing rate is set at 48kHz + + Big thanks go out to the entire TerraTec team for providing me with a + card to use - especially Kay "Mod4Win" Bruns. + + Notes: + The settings within the EWS64 Codec driver are saved upon exiting. + + The "Reverb Types" are: + 0: Room1 + 1: Room2 + 2: Room3 + 3: Hall1 + 4: Hall2 + 5: Plate + 6: Delay + 7: Pan Delay + + The parameter "Reverb Feedback" only has meaning for Reverb Types Delay + and Pan Delay (6 and 7) + + The "Chorus Types" are: + 0: Chorus1 + 1: Chorus2 + 2: Chorus3 + 4: Feedback Chorus + 5: Flanger + 6: Short Delay + 7: Feedback Delay + + Note: Chorus will only work with EWS64 XL rev 1.1 or greater + + + +Ensoniq SoundscapeVIVO (ITVIVO.DRV) + + The drivers for the Ensoniq SoundscapeVIVO use the PnP registers to + detect/configure this soundcard. If you have disabled the PnP on the + card the driver may not work... + + The default mixing rate is 48kHz. + + + +Sound Track PCI Codec (ITSTCODE.DRV) + + This driver uses the PCI registers to autodetect the card. Unfortunately + this does not always seem to be the correct value, hence you may have to + override the parameters on the command line. (The computer *MAY* hang if + the correct values are not available!) + + Sound Track 97 PCI and Sound Track 42 PCI cards are handled by this driver. + + The 'extra' settings of reverb, chorus, echo, equalizer and surround are + not available on the ST42 cards. SRS settings are available. + + Notes: + The settings within the ST97 PCI Codec driver are saved upon exiting. + + The "Reverb Types" are: + 0: Room1 + 1: Room2 + 2: Room3 + 3: Hall1 + 4: Hall2 + 5: Plate + 6: Delay + 7: Pan Delay + + The parameter "Reverb Feedback" only has meaning for Reverb Types Delay + and Pan Delay (6 and 7) + + The "Chorus Types" are: + 0: Chorus1 + 1: Chorus2 + 2: Chorus3 + 4: Feedback Chorus + 5: Flanger + 6: Short Delay + 7: Feedback Delay + + Huge thanks go to Hanmesoft Corporation for providing me with this awesome + card to work on! (check out http://www.hoontech.com) + + + +MPU401 MIDI Driver + + The MPU401 MIDI driver provides a MIDI Driver to support MIDI Input and + MIDI Output on general soundcards. It does NOT support sample playback + at all. Trying to play a sample will result in the note being 'terminated' + immediately. + + To use this driver, you may need to provide the MIDI port on the command + line; + + eg. "IT /s19 /a360" + + Addresses 330h and 300h are checked if a port is NOT specified. + + + +Disk Writer + + The ITWAV.DRV included with distribution IT is a mono-only + example device. To use it, run IT /sITWAV.DRV or IT /s20 + + The full ITWAV.DRV file which *IS* capable of stereo output + is NOT available for public distribution. Contact me if you + wish to obtain this - it will NOT be made available without + some sort of (monetary) agreement (US$30 for non-profit use) + + Details + 16 bit Stereo/Mono output + 22kHz to 64kHz output frequency + 16 bit quadratic spline interpolation (65536x 'oversampling') + 32 bit mixing + Logarithmic volume ramping with 32768 internal volumes levels. + Sample cut click removal techniques + Resonant filtering + + To use the disk writer, run: "IT /sITWAV.DRV" or "IT /s20". + The files will be created in the same directory as IT.EXE, + and will be of .WAV format. You can change the destination + directory on the diskwriter's driver screen (Shift-F5.) + + It is greatly suggested to use a disk cache to improve the + writing speed. + + + diff --git a/it/ReleaseDocumentation/FILES.TXT b/it/ReleaseDocumentation/FILES.TXT new file mode 100644 index 0000000..57f463f --- /dev/null +++ b/it/ReleaseDocumentation/FILES.TXT @@ -0,0 +1,33 @@ + + Impulse Tracker Version 2.14 + +In the Impulse Tracker ZIP, you should find the following files: + + IT.EXE - The whole program! + IT.TXT - User's manual to Impulse Tracker + IT.DOC - User's manual in Microsoft Word format + CONTRIB.TXT - List of contributions - where's your name?? + DRIVERS.TXT - List of sound drivers for Impulse Tracker + various notes. + If you have a question related to sound quality, sound cards + or sound card specific questions, check this DOC first. + UPDATE.TXT - History of Impulse Tracker. + HINTS.TXT - Just a little compilation of hints for new composers. + FILE_ID.DIZ - Compulsory description file :) + FILES.TXT - You should know what this is by now! + BUGS.TXT - A list of a few known things that are wrong. + SUMMARY.TXT - A convenient, small reference that I recommend ANYONE to + print out. + MIDI.TXT - MIDI Out information written by Andre Pang + (Ozone/Vault) + IMPULSE.FAQ - Frequently Asked Questions file. + ITMIDI.CFG - Basic configuration file for MIDI Output + KEYBOARD.ZIP - Alternative keyboard definition files + source to create + your own + + *.DRV - Sound driver files for Impulse Tracker + +If you do distribute this program (and please do!), then I would be most +grateful if you keep ALL of the files intact. + + - Jeffrey Lim + (Pulse) diff --git a/it/ReleaseDocumentation/FILE_ID.DIZ b/it/ReleaseDocumentation/FILE_ID.DIZ new file mode 100644 index 0000000..33fb9a7 --- /dev/null +++ b/it/ReleaseDocumentation/FILE_ID.DIZ @@ -0,0 +1,12 @@ +Ŀ + Impulse Tracker v2.14 +Ĵ + MOD, 669, S3M, MTM, XM, IT supported + 8/16 bit samples, ping pong loops + 64 Channel/256 Tracks, Full panning + Volume/Pan/Frequency envelopes + Huge variety of soundcards supported + Huge variety of sample formats supported + 10 Stage pattern editing undo buffer + Internal message editor + diff --git a/it/ReleaseDocumentation/FILTERS.TXT b/it/ReleaseDocumentation/FILTERS.TXT new file mode 100644 index 0000000..447c049 --- /dev/null +++ b/it/ReleaseDocumentation/FILTERS.TXT @@ -0,0 +1,143 @@ + + Impulse Tracker and Resonant Filters + +Wanna know how to get resonant filters working in IT? Read on. + +Implementation +-------------- +So far, resonant filters have only been coded into the MMX drivers - so any +soundcard which has an MMX driver for IT will support resonant filters. Of +course, this means that your computer has to have MMX before you can run them. +To hear resonant filtering, you'll first need to select "Filtered" mixing on +Shift-F5. + +Do NOT write to me about non MMX resonant filtering. + +Resonant filters CANNOT be included with hardware GUS / Interwave drivers. The +reason is because these chips do not support resonant filtering in their mixing +algorithms. + +The AWE 32 driver has *approximate* support to IT's software resonant +filtering. Songs written using resonant filters on the AWE32 will not sound +exactly the same with other drivers. + +The diskwriter has all resonant filtering code, of course. (No MMX required) + +Note that the only external player to have resonant filtering implemented is +MikIT. If you use any other player to play your songs that use resonant +filtering (including earlier versions of IT), they will not be played +correctly. + +First note +---------- +If you do use filtering in your songs, you probably should embed your MIDI +Output configuration into the .IT file. This makes the file slightly bigger, +but it ensures that your song will be played correctly on any filter-capable +driver on any computer. This is selected by turning the "Embed MIDI Data" +on the MIDI screen (Shift-F1) to "on". + +Simple filters +-------------- +For most users, this is all that you will need to know. + +The default configuration for IT (copy ITMIDI.CFG to your IT directory) will +recognise Z00->Z7F as set filter cutoff frequency and Z80->Z8F as set filter +resonance. + Z00 is the lowest filter cutoff, Z7F is the highest filter cutoff + Z80 is the least resonance, Z8F is the highest resonance + +If you wish to reconfigure the resonant filters or perhaps create some extra +shortcuts, then read below! + +How the drivers recognise filters +--------------------------------- +The drivers know what to filter by intercepting MIDI messages. This does NOT +mean that filters will require any sort of MIDI equipment, just that the +mechanism to instruct the driver to filter a particular note within IT itself +is made via the MIDI interface. + +The instructions that the drivers understand so far are: + F0 F0 00 - Set filter cutoff frequency to + F0 F0 01 - Set Q factor (resonance) of filter to + +In each of these cases, is between 00 and 7Fh. Values above 7Fh are +ignored. Note that if filter cutoff is set to 7F and Q is set to 0, then no +filters are applied. + +How to tell the drivers these Instructions +------------------------------------------ +OK.. so how can we tell the drivers these instructions? + +For a full explanation, check MIDI.TXT - a short explanation is provided here. + +First of all, go to the MIDI Output configuration screen in IT. Do this by +pressing Shift-F1, then clicking on the "MIDI Output Configuration" button. + +You will see several MIDI configurations, then SF0->SFF then Z80-ZFF (that +bottom window is scrollable). + +Using Z80 to ZFF +---------------- +Z80->ZFF are the easiest to explain.. so I'll explain them first. + +If you type in "F0 F0 01 3F" next to Z80 (make sure that you have the letters +in upper case), then whenever you use Z80 in a pattern, "F0 F0 01 3F" will be +sent to the driver. If you refer back to what instructions the driver +understands, you'll see that this means "Set filter resonance to 3F". + +A few more examples: + Z81 = F0 F0 00 40 - set filter cutoff frequency to 40h + Z82 = F0 F0 01 20 - set filter resonance to 20h + Z83 = F0 F0 00 10 - set filter cutoff frequency to 10h + +Using SF0->SFF +-------------- +SF0->SFF are slightly more difficult to explain.. but hopefully a few examples +will make their usage clear. + +When you use Z00 to Z7F in a pattern, they do not directly translate in the +same way as the Z80->ZFF do. Instead, they set a variable internally called +'z' that gets substituted into one of the SFx commands. + +Example 1 - If you set SF0 = F0 F0 00 z (on the MIDI Output configuration) + +Then using Z01 will cause "F0 F0 00 01" to be sent. + Z01 = F0 F0 00 01 - Set filter cutoff frequency to 1, as above. + Z10 = F0 F0 00 10 - Set filter cutoff frequency to 10h + Z30 = F0 F0 00 30 - Set filter cutoff frequency to 30h + Z50 = F0 F0 00 50 - Set filter cutoff frequency to 50h + +Example 2 - If you define: + SF0 = F0 F0 00 z + SF1 = F0 F0 01 z + +Then: + SF0 - Set Zxx to use SF0 + Z30 = F0 F0 00 30 - Set filter cutoff frequency to 30h + Z50 = F0 F0 00 50 - Set filter cutoff frequency to 50h + SF1 - Set Zxx to use SF1 + Z20 = F0 F0 01 20 - Set filter resonance to 20h + Z3F = F0 F0 01 3F - Set filter resonance to 3Fh + Z50 = F0 F0 01 50 - Set filter resonance to 50h + SF0 - Set Zxx to use SF0 + Z30 = F0 F0 00 30 - Set filter cutoff frequency to 30h + Z10 = F0 F0 00 10 - Set filter cutoff frequency to 10h + SF1 - Set Zxx to use SF1 + Z20 = F0 F0 01 20 - Set filter resonance to 20h + Z30 = F0 F0 01 30 - Set filter resonance to 30h + +Note that the default startup configuration for each channel is SF0, so the +first SF0 in example 2 is unnecessary. + +Resetting the Filters +--------------------- +Since the filters are driver related (and IT.EXE really doesn't know about +their existance), they are not reset automatically when you stop/play a song. +If a MIDI Reset (FFh), MIDI Start (FAh) or MIDI Stop (FCh) message is +received, then the driver will reset all of it's internal tables. The default +configuration will send both MIDI Reset and MIDI Stop commands. + +Final Notes +----------- +Umm.. Enjoy :) + - Jeffrey Lim diff --git a/it/ReleaseDocumentation/HINTS.TXT b/it/ReleaseDocumentation/HINTS.TXT new file mode 100644 index 0000000..8197211 --- /dev/null +++ b/it/ReleaseDocumentation/HINTS.TXT @@ -0,0 +1,572 @@ + + +Hints for Composers + -- Pulse + +Well, I'm not the best person to ask for hints, but here are a few anyway. + +1) Never release your first song. There are very few people who are gifted + enough to really make a quality song the first time - it's all practice + and experience! Once you *HAVE* finished a song, listen to it a couple + of days after... see whether you can view it from another point of view. + +2) For channel echoes, use the Mxx command in a second column - this will + save you from adjusting volume related effects (ie. you can leave all the + Dxx commands alone, and it'll sound right) + +3) Don't be afraid to create multiple instruments from the same sample! The + reason for why I created instruments the way I did was so that you could + have different *articulations* of the same sample. You can achieve this + by playing around with the envelopes, fadeout, NNA - whatever. + +4) Listen to other tracked music. Try and learn how other composers have + achieved the sound they did. Experiment yourself. + +5) Start by writing music that *YOU* really like listening to - don't try and + write am orchestral piece if you don't listen to it - it'll show. + +6) Take the time to tune all your samples as accurately as possible! To do + this, play a long, clear, looped sample, then move to another channel + (using '.') and tune ALL your other samples to this one sample (so they + all have the same reference). Many potentially excellent modules have + been spoilt because they were poorly tuned. Of course, this doesn't + count the cases where samples are intentionally slightly sharp or flat + for effect (which should be the rarity instead of a rule). + +7) Try to avoid having too many samples at central panning - if you modify + the initial panning - you should be able to 'fill' out the sound with + very little extra effort. Or perhaps if you use instruments, you may + want to play around with instrument's default panning... + Pitch pan separation also provides a very convenient way to achieve a + nice pan. + +8) To find the 'perfect' loop: + + a) If you have a GUS/IW, first turn the loop off, then reload all GUS + samples (so that their entire waveform is loaded). + b) Now, select either a forwards or ping pong loop. Only select forwards + if you have a sample which has the same amplitude at both ends. If + you have a sample which has vibrato incorporated into the sample, then + you'll probably find ping pong loops inappropriate. If the sample has + an obvious reoccuring shape to it's waveform, try to account for that + when you select your initial guess at a loop. + c) Play a note at a MUCH higher pitch than you'd normally play it at. + Then, hold down '+' (or '-') on on of the loop boundaries to find a + region of lowest clicking. Then adjust it carefully (one byte at a + time) until you find the best loop location. You will normally need + to change both beginning and end points of a ping pong loop to find + a nice loop, whereas forwards loops usually only require either loop + end or beginning to be modified. + d) Now that you have a decent loop at this pitch, decrease the pitch + (typically by an octave) + e) Repeat steps (c) and (d) until you have a nice loop at the pitch that + that sample is played at. + f) Once you've finished and if you're using a GUS, press Ctrl-G (to + reload the Gravis' samples) and do a final check that you have an + appropriate loop. + + This method works very well MOST of the time - don't forget that the '+' + and '-' keys can be used to easily modify the loop - and the changed loop + is taken into account when you change it (ie. you don't need to replay the + sample). + +9) If you want to make a song realistic, try to imagine how the instrument + would be played. Pretend you are a musician when you write a part.. + Also, if you use an instrument such as a piano, try to use more than a + single piano note - a real piano will ALWAYS have more than one note + playing at a time - use some chords, etc. + +10) For a nice fill to the sound, try to balance the usage of low and high + frequencies. Songs with too much bass and too little treble sound rough, + songs with too much treble and too little bass sound insubstantial. + + + +Hints for New Composers +-- John Hawksley (a.k.a. Greebo) + +1) Listen! + +2) Spend a day figuring out every feature of the tracker. + Yes, I'm talking about all the effects and all the keys. + ST3 is widely acknowledged to be a bitch to learn, but is (sorry, + *was*) the most powerful tracker out. Once you have all the + keys and functions sorted, you'll be ripping around IT's in + no time. You can leave the advanced instrument stuff for now. + +3) Listen to other tracks, find out how the nice-sounding bits are + done. (ie look at the effects and volume/pan column). + +4) Be different. A lot of .MODs are in the same style. Sure, if you + like this and feel comfortable with it, then go for it! But if you + want to create a new feel -- do that too. People are always ready + to try new styles. I personaly enjoy arranging (that covers + a lot of styles) but you might like composing rock tracks, for + instance. So do it! + +5) Samples. Be selective. Sort all your samples into directories. + If you have an editor, the trim thein sample; try to remove the + noise or click at the start. Remember -- samples are the building + blocks from which we craft music. If the samples are bad, + the music will be too. + +6) Tune the samples! When you rip a sample or create one yourself + try to do it at the same pitch, or tune it (using the speed value) + so that everything is uniform. This will save much hair-pulling + later as you try to figure out why half the piece seems to be + in G# major and half is in Dflat minor. + +6) Chords. Originaly, people used to sample whole chords to save + sample space. Now we've got this wonderful IT with it's gazillions + of channels. From ST3 onwards, I have been contructing chords + from notes because I had the space to do so. The sound is better + and is more of a professional approach. + However (there's always a 'but'): be very careful! If you decide + to construct a chord rather than use a single sample, some + musicianship is required. Simple major chords are easy, but + inversions really add to a piece. If you are able to do it this + way (look at some piano parts to any of my stuff, for instance), + you'll get s professional, crafted sound. But it does take + a long time before you'll get a smooth flowing part. + +7) Saving. Okay, so IT hasn't crashed on me yet, but when (if) it + does, I'm not going to loose an hours work. Save regularly. + Never use IT or ST3 under the GUI in 95 and under Windows 3.1; + I found that occaisionaly, windows would do some swapping while + ST3 was saving and the module would be corrupt; but ST3 said + it was saved ok. Lesson learnt. + +8) Releasing. FTP sites are hard to come by these days. Probably + the best method of release is to uuencode your work and + post it to alt.binaries.sounds.mods newsgroup. + + +Hope these are of some help. Remember to visit the Mod Resource Web +at http://www.armory.com/~greebo/mod.html + +I can be contacted at greebo@armory.com. + +Good luck! + +John H. + + + +Hints for Composers +-- ToalNkor / Realtech + + TIP FOR LOADING EITHER LEFT OR RIGHT CHANNEL OF A STEREO SAMPLE : + + Load the sample as usual and then follow these steps : + + If you want the LEFT channel : Just divide the length by 2 + by using Ctrl-F. This will delete one byte out of two, and therefore + only the "first" sample (the left one) will remain ! + + If you want the RIGHT channel : Cut the first and last byte of the + sample (By looping it and using Ctrl-B and Ctrl-L). If the original + sample sise was X, then the actual size should be X-2. From now on, + just follow the same indications as for the left channel and tadaa... + your Right channel sample is ready for use ! + + After all these operations, dont't forget to multiply the mixfrequency + by two to get the original samplingfrequency back ! + + + + Hints for New Composers + -- StereoMan + + 1) The easiest way to produce flanging like effect is to play same sample in + two channels (they must have exactly the same pan-position) and lower or + higher the playing frequency of one of the samples - ie: + + 1 2 2 (1 is same) + ... .. .. Xpp... .. .. Xpp ... .. .. Xpp + xxx ii xx ...xxx ii xx EE1 or xxx ii xx u11 + ... .. .. ...... .. .. ... ... .. .. u00 + u00 and so on. + has the same value in the two channels. + is your instrument number. + is the note you play the sample in. + + 2) You can use the above mentioned effect, but instead of having the channels + with the same pan position you can put them as Left and Right (full) ie: + + ... .. .. X00... .. .. XFF| + . . . + + this will give you a smooth three dimensional sound. + + Note: This effect has not been tested on SurrounD equipment - the results + are li'l unpredictable. + + + 3) Quite a good way to make reverb-like-echos is shown below: + + Let's say You have some sequence playing in one channel. Put the same into + another channel and insert one or two (or more) rows before the beginning. + Now set all volumes to zero (alt-v) and clear volumes which are not + associated with notes (alt-w). Then apply a Dx0 effect (x=1..4 or more) + for example: + + n1. i. .. ...... .. .. ... The results are very good. + n2. i. .. ...n1. i. 00 D20 Once you get used to this you can + ... .. .. ...n2. i. 00 D.. achieve !very! smooth sound. + n3. i. .. ...... .. .. D.. + ... .. .. ...n3. i. 00 D.. The samples must not be too short + n4 i. .. ...... .. .. D.. so Dx0 can take effect. + ... .. .. ...n4. i. 00 D.. + + + 4) If you make the above channels with different pan positions (x22 and xDD) + or (x80, s91) - the results are stunning :) + + + 5) Take your time to read the whole help (yes, the whole of it) - you'll + be surprised to find what hides under your keyboard :) + + + 6) Make your tunes as small as possible. People are not quite happy to find + they have a 3 or 4 Megs of crap on their already full HD drives. + Remember: the smaller = the easiest to spread. + + + 7) NEVER start tracking if you're not into the right mood to track. You'll + only loose time and perhaps make another crappy tune. + + + 8) Funny, but I've found that making your own color scheme truly inspires! + + + 9) Experiment! Play around with the effects, envelopes and NNAs. They all + make music sound more realistic! + + + + George Marinov a.k.a. StereoMan - + + + +Hints for composers +-- Ilpo Karkkainen + +- If you listen only one kind of music, it will shut your mind from others. Be + versatile. When you listen lots of different kinds of music styles, it also + makes your composing a lot more wider and colorful. + +- When listening to music generally, try to sometimes consentrate to something + specific, for example backing vocals or drums. It helps you realize the whole. + It's also good to try listen what different notes there are in a chord that + you hear. At least to me, it has been very helful in chord progression. + +- Details make the whole. Use them wisely, though. Too much details make the + song sound bad. I've noticed that in some of my songs. + + + + Onix4MAN's hints + + + 1) CLEANING A WAV FILE UNDER IT. + 2) CREATING NEW SAMPLES WITH IT. + 3) 3 (4?) METHODS TO MAKE YOUR MODS SOUND MORE SPACIAL.. + + + +1) CLEANING A BAD SAMPLE UNDER IT: +----------------------------------- + +To clean up samples that click at their start (or end) because the waveform +has an error at its start (still or end), without going under a wav-editor: + + -turn on Loop + -start the loop at 100 bytes for samples > 10000 kb + 50 bytes for samples < 10000 kb + -then do 'ALT-B': Pre-Loop Cut Sample + -then turn off the loop + -do the same at the end of the sample with 'ALT-L' if the wav clicks + at its end + + The numbers of bytes given is OK for often met clicks, if your + sample is really bad, just increase it... ;) + + + +2) CREATING NEW SAMPLES WITH IT: +-------------------------------- + + -You simply have to edit one pattern composed of several samples. + (eg. Compose a Break-Beat on that pattern) + -Put this pattern at order 000. + -Save this module. + -Restart IT in Disk-Writer mode. + -Load your module. + -Play it: it is now being written as a wav file on your disk. + -Restart IT normally. + -Load that new sample and use hint 1) if it has a blank at its end to + shorten it. + + +3) 3 (4?) METHODS TO MAKE YOUR MODS SOUND MORE SPACIAL..: +--------------------------------------------------------- + + -Let's start with the 4th method: it's the Surround.. :) + But if your card can't afford surround.. Use one of the 3 following + methods: + + These methods are in fact three times the same but with 3 different way. + I'm sure you knew at least the first (and probably the 2nd too) ;) + These 3 methods require 2 channels. + +For the 2 firsts, you have to set the panning of the Sample/Instrument +somewhere (in 'Order list and panning' or on the Sample List [F3], but +you'll have to load twice the sample, or on the Instrument List [F4], +or on the Pattern Editor itself [F2], but you busy the volume column or +the command column..) +In the following examples, I've set the Panning in the Volume column +(press the key below Escape to do this) + + a) row CHANNEL 1 CHANNEL 2 + 000 C-5 01 00 .00 ... .. .. .00 + 001 ... .. .. .00 C-5 01 64 .00 + 002 ... .. .. .00 ... .. .. .00 + + + b) row CHANNEL 1 CHANNEL 2 + 000 C-5 01 00 .00 C-5 01 64 SDx + 001 ... .. .. .00 ... .. .. .00 + + With 'x < Speed Value' This second method is more precise! + You can even write SD0 (ie. 0 as x) + + + c) The last method is the more interesting if you knew the others, + because it does waste your volume column neither the command + column! So they remain free for other effects! :) + + * This time, you have to be controlled by Instruments (F12 to select + this). + * Then you will need exactly the too same instruments: + - On F4 Screen, select a blank lign and type 'Alt-P' + - Type the lign where your instrument is... Validate!.. + * Then push the panning button: + -set the pan to 00 for your first instrument + -set the pan to 64 for your second instrument + * Then FOR ONLY ONE of those 2 instruments: + Press the Pitch Button and go to edit the envelop: + + -First node: tick 00 ;) + value 00 + + -Second node: tick 01 + value 'Whatever_you_want', (-)1 or (-)2 suggested + + -Last (3rd) node: tick 02 + value 00 + + Doing this, you've created a delay between your 2 instruments. + To end, place them on the same row on the pattern editor (F2): + + row CHANNEL 1 CHANNEL 2 + 000 C-5 01 .. .00 C-5 02 .. .00 + 001 ... .. .. .00 ... .. .. .00 + + Notes: + ====== + *) You don't have to set the pan to its maximum (00 and 64/FF). + You had better do it for one of your smp/inst. And then, for another + choose 16 and 48 (decimal), or... + + *) The third method works because we do not hear the pitch change + in most cases since it is quite quick, but I suggest you do not + use this method for a piano because it's an example where you'll + hear the pitch change and it will sound very ugly: BAAaah! ;) + But it work with Violin and many others. + It may also depend on the speed of your song (time between ticks).. + + + - Nicolas ARROUET (Onix4MAN) o4m@mail.cpod.fr + + + +Hints for new composers. +- Nacho Segura + +About quality of sound, cognitive science, a more convenient composing, sound +experiments and degrees of freedom. + +1) Some composers (trackers) recommend to work with 128 rows and half the +speed (the less the faster). It's supposed that this gives you more control over +the tracks, but that's not totally true. + + - The track doubles its length, so you see the half. You have to move + more times and jump more lines every time. Is it important? Register in a + sheet (or two) how many times do you jump through the pattern. + + - I've examined several songs that use this technique, and this is my + conclusion: THEY DON'T NEED IT!!! Even lines are empty or have + effects. + +The small amount of control gained doesn't compensate the ergonomical +problems. The easiest the best, less interferences between you and the music. +Rookies could think that it only makes you be slower. This is a problem, but +it's not THE PROBLEM. When you forget twelve times what the hell did you write +in top of the pattern and in which track you'll understand... + + +2) Work. Lots of trackers are proud to say that they are very fast. That's not a +virtue, it means less work, less variety, a shorter melody, much less chords, no +harmony, sounds not perfectly adjusted, and the most important thing: +Repetitions until the Eternity. You haved lasted two months writing this four +minutes long song? Show me what you did, I'm really interested! + + +3) Discover Scroll-Lock. Load a song, press play, see what happens with the +cursor... and press some notes. +Cool!!! Isn't it? + + +4) Never use 8-bits or low-quality samples if you can avoid it. The quality of a +song depends on the quality of sounds. "More memory than expected" is better +than "crappier than expected". + + +5) Analogic synthetised instruments can produce strange interactions. An +example: WARMPAD.PAT (a Gravis Patch) sounds really nice, but this chord +produces a strange noise that doesn't exists when we play the same notes +separately: C-3, D#-3 and F-3. Upper octaves don t provocate this phenomenon. +NOTE: There are several versions of Gravis patches. + + +6) Use a global volume as high as possible. It not only gives you a better +signal-to-noise relation. It also gives to IT more degrees of freedom for +volume fades. +Make an experiment: Plug the headphones directly to your soundcard, set the +global volume to 5-8 and make a fade out from 64 to 0 (don't use envelopes, +make it in the volume comlumn of the pattern). You should listen the volume +JUMPING (not sliding, jumping!). In Scream Tracker is even worse. + + +7) Don't be messy allocating tracks (channels, columns... you know). All the +percussion grouped in adjacent tracks, the chord grouped, an empty column (or +more) separating every group of instruments, so you can write fastly this new +idea appeared two seconds ago, without having to go to "Track 21". It also +allows you to write and remix fastly. Everything has its own place and you can +disorder and reallocate patterns without knowing if that loop has been cut, or +where do I have to put a NoteCut command (^^^) to shutdown the analogic +looped bass. It seems more complex when you begin (pattern is wider), but it's +much better, easier to use. + + +8) Print the manual and bind it. And when you have done this, RTFM (you +know, READ THE #%&@$# MANUAL!!). You'll be surprised. + + +9) Make an economic contribution. I think he has worked hardly and Impulse +Tracker is the only tracker that gives tracker songs a proffesional sound and +accoustic. Don't be apologized for sending eight dollars. Is better than zero. +Even if you don't want the ITWAV.DRV you should contribute, at least with a +simbolic quantity. He has won it. + + + +Hints for composers +-- Joakim "Acoustic" Back + +1) Dont use the same bassline, piano chords or whatever the whole song. + Remember that a real drummer wont just sit there like a drummachine, + nature will make him tap sometimes and he realy wants to make + some fills sometimes. + +2) Feel the music. You dont use hammering industrial drums in a soft, + smooth gentle song. And dont place a soft panflute in a blasting + hardcore song. + +3) Use the right volume. Keeping the volume low on an instrument and then + suddenly higher creates a feel of power and rush. Use it. + +4) There are different ways to make a solo stand out. + a) high volume. Having a high volume will instantly keep it in the + focus. Be aware that to high volume will make it stand out to much + and maybe not fit in the picture anymore. + + b) high or low pitch. If you have a lot low and middle note instruments + the solo will be clear and bright as high pitched. As said in other + hints, keeping the others too low or too high will sound terrible. + +5) If you play the piano and have a midi keyboard - use the midi support! + This will make you see that you play the piano with a lot more feeling + than when you track a song with the computer-keyboard. + +6) Accept failure. Dont get all angry just because your song went totaly + nuts. This happends all the time. Your songs will be better and better + the more you use IT. + +7) Use IT alot! Play around with IT, make crazy songs. This will make you + learn ITs features and ways to make nice effects. You wont understand IT + by reading the effects from Axx to Zxx, or reading hints like these, but + mostly by using the effects and using IT, only training will get you to + the top. IT is like a sport, people that dont use it, dont get a thing + about it, but when you get the hang of it, its going to flow. + +8) Learn IT in steps. Begin with some simple samples and a few patterns, + then learn a few simple effects like Exx and Fxx. When you have learned + them, go to a new step. Wait with the instruments (F4). + +9) Make a keychart. Write down some of the keys on a piece of paper, after + a few days you will probably know most of them. When you know almost + all you will understand that using only the keyboard is MUCH faster than + the mouse. + +Thanks for reading, I hope it will help you somehow. +/ Acoustic +n98joab@tycho.helsingborg.se + + + +Hints for Composers +- Maarten Van Stien +- Crystal Score / The Black Lotus + +He! ye like simple solutions? Here's one! + +You might have used the diskwriter for simple drumloops! You also might have +loaded the wav in programs like Soundforge (the king!) to add nice nice stuff +like reverb, eq, dynamics etc... + +As you might guess when you write one period containing a drumloop and you +add reverb, then the start of the sample doesn't have reverb at all, while the +end of the drumloop as tons of reverb. Apart from the fact that it sounds lame +in most cases, LOOPING the sample sounds like hell! So what you do is +diskwriting the same loop twice or more. Then add reverb in your sample editor +and you'll notice that the second period contains the 'reverb' of the first +period. This second period can be looped perfectly. As long as you know where +to find the looping-points! + +Now, for simple drumloops with a little bit of reverb it's dead simple. +But for complex loops with TONS of reverb/delay/crap&more it might be quit +difficult! + +Solution: +* make an extra .IT with the same BPM/frames as your drumloop .IT +* add a simple, short and immediatly-starting sample at the beginning of each + period (in most cases: on pos 000, 016, 032, 048 etc.). These are some sorta + metronome instruments I guess.. +* diskwrite +* find the first sample of the 'metronome-instruments' in a sample editor. +* add markers at that place. +* Mute/Silence the samples so that your metronome-wav ONLY contains markers +* copy your complex drumloops or whatever-loops in mem. like ctrl-c +* MIX to the metronome wav. + +Now you have markers in your complex drumloops! And if you did the above stuff +right, you have perfect loops! + +Make sure the metronome-samples start immediatly! Otherwise use the offset +command (C-4 10 63 O10) or something.. + +ok.. have a nice diskwrite! + +Crystal Score/The Black Lotus +Maarten.Vanstrien@student-kmt.hku.nl diff --git a/it/ReleaseDocumentation/IMPULSE.FAQ b/it/ReleaseDocumentation/IMPULSE.FAQ new file mode 100644 index 0000000..48f474c --- /dev/null +++ b/it/ReleaseDocumentation/IMPULSE.FAQ @@ -0,0 +1,261 @@ + + +*** PLEASE take the time to check quickly through this document BEFORE *** +*** you write to me. If the answer to your questions lies within here, *** +*** do NOT expect a reply at all. *** + +This document is currently incomplete. + +1. Getting Impulse Tracker working. + 1.1 Requirements to run IT + 1.2 Insufficient memory messages + 1.3 "Mix data not allocated" + 1.4 Video characters scrambled + 1.5 Impulse Tracker often hangs + 1.6 Files won't load/take a long time to load! + 1.7 Impulse Tracker doesn't support my soundcard! + 1.8 The sound breaks up/computer slows down when playing songs! + 1.9 Microsoft Windows and Impulse Tracker + +2. Using Impulse Tracker + 2.1 Loading external samples + +3. Miscellaneous + 3.1 What are these CACHE.ITS and CACHE.ITI files?? + 3.2 Distribution sites. + +4. Future versions of Impulse Tracker - Not written yet + +1.1 Requirements of IT + + ------------------------------ + NOTE WIN95 USERS -> READ LATER + ------------------------------ + + Impulse Tracker requires a 386+ PC and > 500k of memory. Impulse + Tracker uses EMS memory. To setup EMS memory, use the following lines + in your CONFIG.SYS file: + + DEVICE=\HIMEM.SYS + DEVICE=\EMM386.EXE RAM H=255 + + Do *NOT* have "NOEMS" or "FRAME=NONE" on the same line as EMM386.EXE + + Also shove these lines in, if they're not already there: + + DOS=HIGH,UMB <--- just to get yourself a little more memory + STACKS=0,0 <--- Some computers require this to prevent crashing + + I cannot guarantee that IT will work with QEMM, but Leszek Clapinski + wrote to me with this advice (thanks!): + In your config.sys, use: + DEVICE=\QEMM386.SYS DMA=64 HANDLES=255 FORCEEMS + Then use "IT -P2" + + I recommend that you also devicehigh and Load-high (LH) as many + possible drivers, so that you have more conventional memory to play + around with. + + ----------- + Win95 Users + ----------- + + If you are a Win95 user, you're probably best off not having HIMEM.SYS + *OR* EMM386.EXE in your CONFIG.SYS file. If you *do* have EMM386, + make sure you do NOT have "noems" as a parameter. + + Win95's internal EMS handling routines *DO* automatically provide + the optimum environment for IT, so you should be able to ignore the + settings given above. + +1.2 Insufficient memory messages + + If you get Insufficient Memory messages at the soundcard + initialisation, read section 1.3 + + If you do not have enough conventional memory, the program will + exit to DOS almost immediately. If you *JUST* have enough conventional + memory, then there may not be enough memory left over to load the + sound driver(s) ( -> No sound card detected ) + +1.3 "Mix Data not allocated" messages + + All non-wavetable cards require extra *conventional* memory to be + allocated in order for them to run appropriately. The amount requires + differs between the drivers and depends also on the mixing speed (the + higher the mix speed, the more memory required). If you get this + message, try to free up some conventional memory. + +1.4 Video character's scrambled + + Some video cards (esp Matrox cards) did not follow the VGA register + standard correctly. Impulse Tracker tries to detecting whether + you have such a card, but if this is not successful, run IT /v2 + for Matrox compatibility mode. + +1.5 Impulse Tracker often hangs + + Impulse Tracker may not operate securely in anything other than + DOS and Windows 95 (these are the two systems that IT has been + extensively tested on) - QEMM/Command shells (eg 4DOS/NDOS) have + been known to cause errors in many situations. + + Aside from these, if Impulse Tracker hangs on you, please write to + me immediately, with a full description of what happens/how you can + make it happen. (Including the version of IT that you use!) + + If you get a blank screen when you run Impulse Tracker, try using + command line parameters to specify your soundcard and port/irq/dma. + The autodetect procedures seem pretty reliable, but there's a chance + that they may be interfering/interacting with unexpected hardware. + +1.6 Files won't load/take a long time to load! + + Some music modules are actually compressed with a program called + MMCMP. Under normal conditions, these files can be decompressed + automatically, under the following situations, they _cannot_: + + 1) You do NOT have EMM386 loaded - the decompression routines + require EMS memory, so if you do not have EMS, you cannot + load these files. + 2) You are running Impulse Tracker through Windows 3.xx - + Windows 3.xx prevents programs from doing certain things... + including the setup routines that the decompressor requires + to run - so these files cannot be loaded under Windows 3.xx + + These files will take longer to load, as they are compressed and are + decompressed to disk first. + +1.7 Impulse Tracker doesn't support my soundcard! + + There may be two reasons for this: + 1) Impulse Tracker really doesn't support your soundcard. + 2) Impulse Tracker supposedly does support your soundcard but + you can't get it to work. + + 1) Solution: Convince your soundcard manufacturer to send me a sound + card to play with AS WELL AS all the programming information. + Alternatively, find a soundcard that Impulse Tracker *DOES* + support - you can pick up some decent soundcards really cheaply. + + 2) First of all, check that you have enough memory. If you have + a low amount of FreeMem once you load Impulse Tracker, it probably + means that there wasn't enough memory to load the sound driver file + which will automatically cause a detect failure. + + Unfortunately, not all 100% compatible (esp "100% SBPro compatible") + soundcards are REALLY 100% compatible. If the drivers do not detect + your soundcard, then try specifying full command line parameters. + If it still doesn't work, then I'm sorry - there's nothing I can do + about this. Hassle your sound card manufacturer to make decent + eqiupment. + + Impulse Tracker uses SB cards in a different *MODE* of playback + from most programs so that they are more efficient and also so + that they can operate in the background of Windows 95. So just + because your soundcard works in another program, it doesn't mean + that it's 100% compatible. (this is for all of you who may think + "But this card works in other programs, why doesn't it work in IT?") + + For Sound Blaster cards, make sure you have the BLASTER environment + variable set in order for IT to detect your card reliably + (SB16/AWE32 excluded, as these use hardware routines). + +1.8 The sound breaks up/computer slows down when playing songs! + + (This section only deals with software mixed cards, ie. almost + every soundcard except native GUS, Interwave and EMU8000) + + Sound output from the computer requires HEAVY computation - up to + 64 thousand calculations per second PER NOTE playing. If your computer + is unable to keep up with this, the sound will have very obvious + chunks in it and your computer will slow down noticeably. + + Solutions: + 1) If you're running Impulse Tracker under windows, you may find + that running it from a DOS bootup provides a SIGNIFICANT increase + the capabilities of your computer in this respect (3x faster + in DOS than Win95 for me) + 2) Limit the number of notes you can have simultaneously via the + command line (/Lxx) - eg. "IT /L32" will limit playback to + 32 simultaneous notes maximum. + 3) Lower the number of calculations required per second per note. + This is done by changing the "mixing speed" via the command line: + eg: "IT /m32000" will cause 32000 calculations per second per note + to be made. "IT /m22000" will cause 22000 calculations per second + per note to be made. Check drivers.txt to find the range of + mixing speed values that your soundcard can manage. + 4) Get a faster computer :) + +1.9 Microsoft Windows and Impulse Tracker + + Microsoft Windows 3.xx and Impulse Tracker is a definite no-no. + I do NOT guarantee ANYTHING under this configuration. I probably + also will not fixup any problems that occur in Impulse Tracker + that only occur under Windows 3.xx + + Microsft Windows '95 and Impulse Tracker *SHOULD* work fine. + If no sound card can be detected under Windows '95, check first that + you have no other program using your soundcard (or another DOS window + still open that used your soundcard). + + Only certain soundcards can play in the background of Windows '95 for + technical reasons. Please read the relevant section of DRIVERS.DOC + for your soundcard. + + Some people have found that Impulse Tracker will hang after a few + minutes under Windows '95. Disabling virtual memory may solve this + problem. To disable Virtual Memory, right click on My Computer, + Properties, Performance, Virtual Memory and check the "disable" box. + +2.1 Loading external samples + + To load in another sample so that you can use it in your composition, + go to the sample-list page (F3), then press "Enter". You will be + taken to the "load sample" screen, where you can test out and select + samples from a wide variety of formats. This includes: + .IFF, .WAV, .S3I, .ITS, .RAW, and TX Wave .Wxx formats. + + You can even load samples DIRECTLY OUT of other modules. In the sample + loader, navigate to a drive/directory which contains modules, and you + will see that they can opened as 'libraries.' So far, support for + external sample loading from modules is available for: + .MOD, .MTM, .S3M, .XM, .669, .PTM, .FAR and of course, .IT + + .PAT and .KRZ instruments can also be loaded as sample libraries at + the moment. + +3.1 What are these CACHE.ITS and CACHE.ITI files? + + Whenever you load a sample or instrument, Impulse Tracker has to + load all the files to find out their contents, to determine + parameters such as sample format, bit fields, etc. CACHE.ITS and + CACHE.ITI are files created by Impulse Tracker so that on subsequent + usage, this information can be loaded almost instantaneously from + a single file, rather than having to reload all the information + again. + + These may be deleted without disrupting program usage, but they will + be recreated when you attempt to load samples/instruments from the + directory. + +3.2 Distribution Sites + + To get the latest versions of IT on the web, check out: + + USA Site - Shawn Mativetsky (Shawn202) + http://www.noisemusic.org/it + UK Site - Andi Simpson (Imminent) + http://www.mixbbs.demon.co.uk + Spanish Site - Javier Gutierrez + http://www.musica.org/impulse + Music and Tracking Site - Matthias Ziegs (MAZ) + http://www.maz-sound.com + IT Resource Central - Matthew Gardner + http://www.unidev.com/~logic/music/it + + Please don't write to me to become a distribution site - the sites + above should be sufficient, and I don't think it is necessary to + have BBS distributions since the use of the internet has become + so widespread. + diff --git a/it/ReleaseDocumentation/IT.TXT b/it/ReleaseDocumentation/IT.TXT new file mode 100644 index 0000000..ff5a069 --- /dev/null +++ b/it/ReleaseDocumentation/IT.TXT @@ -0,0 +1,2199 @@ + + +. ..s..s.s.ssss. +: ::$::$:$:$$$$$ +` ``````'.$$$ .$$$ $$$$$$$$$$ .$$$ .$$ .$$$ .$$$$$$$$$$ .$$$$$$$$ + . . . .$$$$ .$$$$ .$$$$ $$$ .$$'.$$$' .$$'.$$$'.$$$$' .$$'.$$$' .$$' + . . . .$$$$'.$$$$$ .$$'.$ $$$ .$$'.$$$' .$$'.$$$'.$$$$' .$$'.$$$' .$$' + . . . .$$$$'.$$$$'$ .$$'.$$ $$$ .$$'.$$$' .$$'.$$$'.$$$$' .$$$' +. . . .$$$$'.$$$$'.$ .$$' $$$ $$$$$$'.$$$' .$$'.$$$' $$$$$$$$$$'.$$$$$' + . . .$$$$'.$$$$' $$.$$' $$$ $$$ .$$$' .$$'.$$$' .$$'.$$$' .. + . . .$$$$'.$$$$' $$$$' $$$ $$$ .$$$' .$$'.$$$' .$ .$$'.$$$' .$$' +. . .$$$$'.$$$$' $$$' $$$ $$$ .$$$' .$$'.$$$' .$$ .$$'.$$$' .$$' + . .$$$$'.$$$$' $$' $$$ $$$ $$$$$$$$$' $$$$$$$$$$$ $$$'.$$$$$$$$' .cC! + + .. .. + .s$$$$$. .sssssssssssssssssssssssssssssssssssssssssssssssssss. .$$$$$s. + `$$. `$$. .ssss. .ssss. .ssss. .sss. .s ss .sss. .ssss. .$$' .$$' + `$$ `$$ ss.`$ $. ``$ $' .$$ $. `$ $$.s' $. `$ $. ``$ $$' $$' + ds.`$ ds.`$ $$ ' $$ss' $ss$$ $$ $$S $$ $$ss' $'.sb $'.sb + $$$$.$ $$$.$ $$ $$`s. $ $$ $$..$ $$`s. $$..$ $$`s. $.$$$ $.$$$$ + Y$$$$'.$$$$'.cC! `' `' `$$$$.`$$$$Y + `' `' `' `' `' + + + User's Manual + + + + 1. Introduction + 1.1 What is Impulse Tracker? + 1.2 About Impulse Tracker + 1.3 Running Impulse Tracker + 1.4 Technical information about Impulse Tracker + + 2. Using Impulse Tracker + 2.1 Playing songs + 2.2 Pattern editor + 2.3 Order list, channel panning & volume + 2.4 Samples + 2.4.1 Information about samples + 2.4.2 Sample functions + 2.5 Instruments + 2.6 Song Variables + 2.7 Hey! This program looks like Scream Tracker 3!!! + 2.8 Gravis UltraSound / Interwave / AWE32 users. + + 3. Before you write to me (Important notes) + + 4. Closing words + + 5. How to get the latest version of Impulse Tracker + + 6. Legal stuff + + + ** Please note that this document hasn't been udpated in a long time. + ** Some information may be missing, which may be present in supplementary + ** files such as DRIVERS.TXT, FILTERS.TXT, MIDI.TXT, UPDATE.TXT, etc. + + 1. Introduction + If you are familiar with tracker programs, then you could probably + skip through most of this document. (I strongly suggest that ANYONE + print out SUMMARY.TXT though, for a list of effects and editing + commands.) For those of you who have had experience with Scream + Tracker 3, read section 2.7. This should detail most of the major + differences between Scream Tracker 3 and Impulse Tracker. For those + of you who are unfamiliar with tracker programs it would probably be + best to print out this document, and then refer to it as you work + with the program. + + Check out the file UPDATE.TXT. If this document contains conflicting + information with what's listed in UPDATE.TXT, then follow what + UPDATE.TXT contains, as I may have forgotten to update this text. + + 1.1 What is Impulse Tracker? + Impulse Tracker is a program used to create high quality music + without the requirements of specialised, expensive equipment. The + hardware requirements should be easily met: Any IBM 386+ compatible + computer (although a 486+ is recommended), and a VGA or higher video + card. If you want to hear sound, you'll need one of the following: + + Sound Blaster series (or most compatibles) + Pro Audio Spectrum + Windows Sound System + ESS ES1868 AudioDrive + Ensoniq SoundscapeVIVO + EWS64XL Soundcards + Gravis UltraSound + Interwave based board + Generic MPU401 for MIDI Input/Output + DAC on LPT1/LPT2 + PC Speaker + + Note that stereo effects (including surround sound) can only be + experienced on software mixed stereo cards. Hardware mixed soundcards + support panning, but do not support surround sound. + + You'll need about 500k of conventional memory to get the program + running - about 600k to have it load almost any song (as long as you + have an EMM driver - samples are stored in EMS when possible, otherwise + the songs that you are able to load will be limited even further!). + If you use EMM386.EXE, add "H=255" at the end of it to prevent + "Out of memory" messages when you still have EMS remaining. If + you're using some other memory manager, check it's documentation + to see how to increase the number of "memory handles". + + Impulse Tracker supports direct control over 64 channels, and can + load and play the following formats: S3M, MTM, MOD and of course, + IT. At the moment, modules can only be saved in the IT and S3M + formats. + + The number of channels playable on hardware mixed soundcards is + limited by the hardware. Check DRIVERS.TXT for specific details + on your soundcard hardware. + + The Gravis UltraSound can only play 32 channels, although this + shouldn't be too much of a limitation. Note that if you put notes + in channels 33->64 in sample mode using a Gravis, you WILL NOT hear + these notes! (There's an explanation of sample mode much later on, + just keep it in mind if you own a Gravis UltraSound - it shouldn't + cause any problems.) The same restriction applies for the Sound + Blaster AWE 32, but to 30 channels. (ie. notes in channels 31->64 + will not cause any sound) + + + 1.2 About Impulse Tracker. + Impulse Tracker began simply as an extension to Scream Tracker 3 + (which should be quite obvious to Scream Tracker 3 users, due to + the interface.) At first, I only intended a couple of extra + features (eg. proper panning and a couple of other interesting + functions), but with the release of Fast Tracker 2, it became obvious + that there were many areas in which Scream Tracker could be improved. + In spite of all the limitations of Scream Tracker 3 (in comparison + to Fast Tracker 2, which offered Volume/Panning Envelopes, 16-bit + samples, Samples > 64k, an in built sampler, proper stereo panning + on SB16, etc. etc), there were still more .S3M releases than there + were .XM releases! And the reason must have been within the way + you WRITE music with Scream Tracker 3. That's why I've used the same + simple and QUICK interface that Scream Tracker 3 offered. And I've + also incorporated all the power of Fast Tracker 2 and more! + + The Tracker was written in 100% Assembler. All the routines are of + my own coding (That's why some of them suck so much :) ). + The program was written on and off during 1995, but most of the + work was completed in the summer holidays of '96. The source code + is over 100,000 lines long and occupies over 3MB. The Tracker runs + entirely in text mode (!) with some neat remapping of characters + (that's why I haven't been able to use colours to help in some places + ie. making the volume envelope nodes a different colour would have + made it easier to use!). + + 1.3 Running Impulse Tracker. + + Win95 Users - ignore all this HIMEM and EMM386 stuff.. as long as + you don't have "noems" or "noframe" as a parameter to EMM386 in your + config.sys file, it'll work fine. If you have no idea what I'm talking + about, you can probably assume it's fine :) (unless you get "out of + memory messages") + + Impulse Tracker uses EMS. If you want to be able to load large songs, + you need the following lines in your CONFIG.SYS file (on your boot + drive) + + DEVICE=\HIMEM.SYS + DEVICE=\EMM386.EXE RAM H=255 + + eg. if the files are in your C:\DOS directory, you need this: + + DEVICE=C:\DOS\HIMEM.SYS + DEVICE=C:\DOS\EMM386.EXE RAM H=255 + + + If you use QEMM, use the following line instead: + + DEVICE=\QEMM.SYS DMA=64, HANDLES=255 + + If you want to run Impulse Tracker in Windows 95, check out WIN95.TXT + + To find out details about the driver for your soundcard, check through + DRIVERS.TXT. + + Most users should not require any command line switches, however + the following are available: + + SFilename.Drv - Sets sound driver to use. eg. IT /sITIW.DRV + this may become necessary as new sound drivers + are released. + + S# Set sound card + S0 = No sound card (silent mode) + S1 = PC Speaker + S2 = Sound Blaster + S3 = Sound Blaster 2 + S4 = Sound Blaster Pro + S5 = Sound Blaster 16 + S6 = Sound Blaster AWE 32 + S7 = Gravis UltraSound + S8 = Interwave + S9 = Pro Audio Spectrum + S10 = Pro Audio Spectrum 16 + S11 = Windows Sound System + S20 = .WAV writer device + + If this parameter is omitted, then a (hardware) detection + routine is used. Check DRIVERS.TXT for specific information + on the various drivers. + + Axxx Set Base Address of sound card (hex) + D# Set DMA of sound card (decimal) + I## Set IRQ of sound card (decimal) + + M##### Set Mixspeed. Values are accepted between 0->65535, + however, the soundcards have hardware limits which will + override the command line switch. Again, check DRIVERS.TXT + for specific information on your sound driver. + + L### Limit number of active channels + + When you limit the number of channels, you are limiting the + number of notes that you can hear on playback. In a "Sample" + controlled song (explained later), the result is that if you + play a 16 channel piece with the limit at 4 channels, then + you will lose the last 12 channels! Even if the first 4 + are not playing anything. In an instrument controlled song, + the result is that you will hear 4 notes at most, which can + be controlled from any of the 64 channels, excess notes will + be lost. (The reason for this is within the channel + allocation routines.) + + Note that the hardware mixed devices (eg. Gravis UltraSound, + AMD Interwave and Sound Blaster AWE32) cannot play more + than a certain number of channels (drivers.TXT will provide + the exact details). + + If you are new to tracking and didn't understand what I was + just talking about, hilight this section with a marker + (you've printed this out, right?), and in your dabblings, + if you notice that some notes aren't being played, reread + this section. It should make sense by then, and the reason + hopefully lies in the above paragraphs. + + V1 Override VGA detection routine.. in case you DO have a + VGA and the program doesn't recognise it. If characters + look weird, you may need to use this switch to override + the Matrox mode autodetect. + + V2 Force Matrox mode. Use this switch if you get garbled stuff + appearing on your screen + + R Reverse stereo channels. + This is only really useful on the SB16. (Swaps left/right + outputs). The Sound Blaster Pro stereo setting routines + aren't accurate, and will sometimes set the left to left + and right to right (how it's supposed to be), and + sometimes set the left to right and right to left (how + it's not supposed to be :) ). + You can also switch left/right channels in IT by pressing + Alt-R on the info page. + + C Control playback in DOS Shell. + When this option is on, the following keys will operate + within the DOS Shell: + + Right-Alt: Stop playback + Right-Ctrl: Play song (if not already playing) + Grey Plus: Increase global volume + Grey Minus: Decrease global volume + + Warning: There are problems on some computers with this + enabled! If your keboard locks up, it may be + necessary to press the left ctrl/alt to "unfreeze" + it... sometimes (other times.. I don't know!) + + F Disable file colour distinctions. + When this is on, all file colours will appear the same as + the background colour. This is just to make it easier to + redo the palette to your liking more easily. + + 1.4 Technical Information + + Formats supported + Modules: + MOD (M.K., M!K!, 4CHN, 6CHN, 8CHN, xxCH, FLT4, FLT8) + 669 (Composer 669, Unis669) + MTM (MMEdit files) + S3M (Scream Tracker 3 files) + XM (Fast Tracker 2 files, DigiTracker 3 files) + IT (Impulse Tracker 1.xx, 2.xx files) + + Samples: + S3I (Scream tracker sample, 8 bit or 16 bit) + IFF (Fast tracker 2 sample, 8 bit or 16 bit) + WAV (Microsoft WAV, 8 bit or 16 bit) + Wxx (TX Wave format samples) + ITS (Impulse tracker sample, 8 bit or 16 bit) + RAW (Raw sample information, assumed 8 bit) + PAT (Gravis UltraSound patches) + KRZ (Kurzweil Synth files) + MOD (Samples from almost all .MOD formats) + PTM (Samples from Poly Tracker modules) + 669 (Samples from 669 and 669 Enhanced modules) + FAR (Samples from Farandole composer modules) + MTM (Samples from MMEdit modules) + S3M (Samples from Scream Tracker 3 modules) + XM (Samples from Fast Tracker 2 modules) + IT (Samples from Impulse Tracker 1.xx, 2.xx modules) + + Instruments: + XI (Instruments from Fast Tracker 2) + ITI (Instruments from Impulse Tracker) + XM (Instruments from Fast Tracker 2 modules) + IT (Instruments from Impulse Tracker 1.xx, 2.xx modules) + + Modules + 99 Samples maximum + 99 Instruments maximum + 200 Patterns maximum (from 32-200 rows per pattern) + 256 Orders maximum + 64 Channels under direct control + 256 Channels maximum for virtual control (64 max default) + + Samples + 8/16 bit samples + Maximum size around 4MB + No Loop/Forwards/Ping pong loop + Default pan for samples (optional) + Vibrato parameters + + Instruments + 25-point Volume/Panning/Pitch envelopes + Default pan for instruments (optional) + Pitch pan separation + Volume / panning swing + Virtual controls (*REALLY* worth understanding) + MIDI Output controls + + Sound Devices + Generic MPU401 + Sound Blaster 1.xx, 2.xx (8 bit mono) + Sound Blaster Pro (8 bit stereo) + Sound Blaster 16 (16 bit stereo, MIDI In supported) + Sound Blaster AWE 32 (16 bit stereo, hardware mixing, MIDI In & + MIDI Out supported) + Pro Audio Spectrum (8 bit stereo) + Pro Audio Spectrum 16 (16 bit stereo) + Windows Sound System card (16 bit stereo) + ESS ES1688 AudioDrive (16 bit stereo) + ESS ES1868 AudioDrive (16 bit stereo, MIDI In supported) + ESS ES1869 AudioDrive (16 bit stereo) + Gravis UltraSound (16 bit stereo, hardware mixing) + Interwave based board (eg. GUS PnP, Dynasonix, 16 bit stereo, + hardware mixing, MIDI In & MIDI Out + supported) + EWS64XL (Codec driver, 16 bit stereo) + Sound Track '97 PCI (16 bit stereo) + DAC on LPT1/LPT2 (8 bit mono) + PC Speaker (very final option not recommended... ) + + MIDI Output + Supports 128 MIDI Macros + Supports 16 parmaeterised MIDI Macros + Internal handling of conflicting notes + Fully configurable output messages + + + 2. Using Impulse Tracker + Before any specific details of how to use the tracker, it may be + worth knowing these few "editing" keys: + + When using Thumbbars. + Pressing Left and Right arrows will shift the values left/right + Holding down Ctrl while pressing left/right will move them quicker + And Shift-Left/Right will move them even quicker.... + But just typing in a number will get you directly to the desired value! + + String (text) entry. + Nothing special here (and the routines need to be rewritten), but + pressing Ctrl-Backspace will clear the entire text.. + + Numerical entries (of the 7 digit or 3 digit variety) + Pressing '+' or '-' will increase/decrease the value by 1. This is + especially useful when modifying loop values. + + 2.1 Playing songs + If you are like most of us, you would have run the program first, + and probably figured out how to do this yourself. Songs are simply + loaded by pressing F9 at any time (to invoke the file load menu) + and then selecting a song by pressing Enter. You can also type the + first few characters of a filename, and a "search" will be made for + the first match. + + Note that on all the file menus in Impulse Tracker, you can also + delete files by pressing Delete. + + After loading a song, use F5 to play it and F8 to stop. The Info + Page should appear, and you can cycle through views using + PgUp/PgDn. Separate view windows can be created by pressing Insert + (and removed by pressing delete) and these separate windows can + each have a different view method. + + Details (ranges follow in brackets): + Frequency - the speed (pitch) at which the sample is played in + samples per second + Position - the offset in a sample (in bytes) + Smp - The sample currently being played (1->99) + FVl - The final volume of the sample, taking into account + all the scaling factors (viz global volume, sample vol, + envelope volume, channel volume and fadeout) (0->128) + CV - Channel volume (0->64) + SV - Sample volume (0->64) + VE - Envelope volume (0->64) + Fde - Fadeout component (0->512) + Pn - Panning (0->64, Su = surround) + PE - Panning envelope value (0->32) + NNA - The current NNA (Cut/Con/Off/Fde) + Tot - The total number of active virtual channels 'owned' by + the channel + + If you're looking for some songs to play, check out the following + places: + ftp.cdrom.com/pub/demos/music [huge collection!] + kosmic.wit.com/kosmic/songs + ftp.uni-muenster.de/pub/sounds + archie.au/pub/aminet/mods + + 2.2 Pattern editor (F2) + The pattern editor allows you to edit patterns. For those of you + who are familiar with music, patterns can be thought of as "bars", + and the order in which these "bars" are played is determined by + order list. For those of you who are not familiar with music, + consider patterns as a small collection of notes. Impulse Tracker + supports up to 200 different patterns - it *IS* quite a lot more + than it may initially sound! + + Each pattern can range in length between 32 and 200 rows. You can + change this value by using the "Pattern Editor Configuration" screen by + pressing F2 when alredy in the Pattern Editor. (If you want to change + the number of rows of several consecutive patterns, use Ctrl-F2) + The other options available are the base octave (explained later), + the skip value (also explained later), the row hilight major and + minor (which determines the distance between the emphasized rows) + and the command/commandvalue link/split option, which determines + whether when editing, the cursor should move downwards when entering + an effect, or across to the effect value columns. + + The pattern editor appears normally as 5 'channel' columns as such: + (You can configure the pattern editor .. press F1 in the pattern + editor, then page down to find the Track View options.) + + Ŀ + C-5 01 23 A02E-5 02 64 D01 .00 .00 .00 + .00 .00 .00 .00 .00 + .00 .00 .00 .00 .00 + .00 .00 .00 .00 .00 + .00 .00 .00 .00 .00 + .00 .00 .00 .00 .00 + ^ ^ ^ ^ + Component Columns: 1 2 3 4 + + What the component columns mean: + 1) The first column contains the note and octave of the note. + Notes are entered by using the keyboard as such: + + (Note) C# D# F# G# A# C# D# F# G# A# C# D# + + + (What you SD GHJ 23 567 90 + type) + Z X C V B N M Q W E R T Y U I O P + + (Note) C D E F G A B C D E F G A B C D E + (Octave 0) (Octave 1) (Octave 2) + + (For those of you with AZERTY keyboards, you will find that + the keys should work as positioned on the keyboard, rather + than having to figure out QWERTY equivalents) + + The octave of the note is determined by adding the BaseOctave + to the Octave of the note played. The BaseOctave can be + adjusted by pressing the Grey keys '/' or '*' or using + Ctrl-Up Arrow or Ctrl-Down Arrow. + + The range of notes is from C-0 to B-9. The 'middle' note is + considered as C-5 + + Pressing '1' on the note column will enter a notecut command. + This causes any note in the column to immediately stop. + + Pressing '`' (the note below ESC) on the note colume will enter a + noteoff command. This causes all sustain points to be released + (Explained in samples and instruments in more detail.) + + At the bottom of the channel is an 'edit mask'. This highlights + what will be affected when you type anything in. Note that + typing a note in can affect more than just a note - normally + it's set to enter an instrument and volume with it! You can easily + tell IT to enter an effect with it also by changing the + channel mask with ',' (comma) on columns 2, 3 and 4. + + Examples of interpretation: + + C-4 01 . - will play note C octave 4, instrument 1 + D-4 . - will play note D, octave 4, instrument 1 + 02 . - Will play note D, octave 4, instrument 2 + E-4 . - will play note E, octave 4, instrument 2 + G-6 12 . - will play note G, octave 6, instrument 12 + + 2) The second column contains the sample/instrument, depending on + whether the tracker is operating in sample mode, or instrument + mode. Valid ranges are from 01->99 (decimal). + + 3) The third column contains the volume or panning of the note. + To toggle between entry of volumes and panning, press '`' + + Volumes. + 0 is the softest (ie. nothing) and 64 (decimal!) is the loudest. + If no volume is specified, then the default volume for the sample + is used. (Note that effects *CANNOT* raise the volume above 64) + + The volume scale works linearly - ie. one note played at a + volume of 64 will be the same 'loudness' as 4 of the same note, + one played at a volume of 10, another at a volume of 30, + another at a volume of 20 and another at a volume of 4. + (10+30+20+4 = 64) + But if you have a choice, always go for the single note (it + will require less processing (occupy less channels), and also + sound better in quality, due to roundings that occur in processing + softer volumes). + + Panning. + Panning controls appear in a different colour to the volume + controls. For panning in this column, 0 represents far left, and + 64 represents far right. If you have an Xxx effect at the same + time, the Xxx will take precedence over this column. + + It is more efficient filesize-wise to use a panning control in + this column rather than in the effect column. + + Volume, Panning & Effect?? + OK. So you want to do something tricky. Well, it's possible to + get all 3 of these how you want with a little meddling with + the channel volume control - just place one before the row with + an appropriate value (remember that the range is 0->40 HEX) such + that the channel volume scales the default volume to the desired + value.... What I mean is that if you want to play a note at volume + 32, pan 48, with vibrato H81, then you can do the following: + + M20 - Set channel volume to HALF. + C-4 01 48 H81 - The 48 is a pan command - this assumes that + the default volume for sample/instrument 1 + is 64. + + Volume Column Effects + In IT208 and higher, some extra functions are available in the + volume column. These allow you to slide the volume up/down and + pitch up/down, just like the final column effects. If you aren't + familiar with the rest of the editor, leave this section out for + now and come back after you have become acquainted to column + (4) of the editor - the effects column. + + Volume column effects are selected by pressing A-H in the first + column of the effects. + + Ax = fine volume slide up by x + Bx = fine volume slide down by x + Cx = volume slide up by x + Dx = volume slide down by x + Ex = pitch slide down by x + Fx = pitch slide up by x + Gx = portamento to note with speed x + Hx = vibrato with depth x + + In all cases, if x is 0, then the effect memory is used (as + explained in (4) + + The memory for Ax/Bx/Cx/Dx are shared, as is the memory for + Ex/Fx. + + 4) The final column contains effect data. For those of you who are + just starting, I would advise you to leave this section until + later, when you have already dabbled with entering notes, and + want some special features. It's easy to get caught up with all + these special features and you can 'overdo' the effects. + And it will sound absolutely pathetic. + + Trust me, I know - I've done it :) + + Effects are entered by typing 'a'-'z', then a hex value + (see later for an explanation of hex numbers) as the final two + entries. The effects allow you to a wide variety of functions + that are otherwise impossible to obtain. + + Due to the repetitive nature of some effects, there is a + 'memory' so that instead of typing: + + G12 It is easier to G12 + G12 use: G00 + G12 G00 + G12 G00 + G12 G00 + G12 G00 + G12 G00 + + The following effects 'memorise' their previous values: + (D/K/L), (E/F/G), (HU), I, J, N, O, S, T, W + + Note: Bracketed commands share the same 'memory' value. So + + E12 can be written as: E12 + F12 F00 + E12 E00 + F12 F00 + C-4 01 G12 C-4 01 G00 + + Commands H and U are linked even more closely. + If you use H00 or U00, then the previous vibrato, no matter + whether it was set with Hxx or Uxx will be used. So: + + H81 Is the same as: H81 + U00 H81 + U83 U83 + U00 U83 + H00 U83 + + Hex Numbers + Note: Impulse Tracker works ENTIRELY with decimal numbers + EXCEPT for the effects column. + + Instead of using a decimal system (ie. base 10), it is more + natural for the computer to work with hexadecimal (often + abbreviated to simply 'Hex') - numbers which operate in base + 16. The first 9 numbers in hex are denoted by '1' to '9' and + the next 6 are denoted by 'A' to 'F'. So if you count in hex, + it will be as follows: (0), 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, + C, D, E, F, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A, 1B, + 1C, 1D, 1E, 1F, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 2A etc. + + To convert a hex number to decimal, multiply the 'tens' column + by 16 and add the value of the second column. ie. 32 Hex = + 3*16+2 = 50 decimal. 2A hex = 2*16+10 = 42. (because A = 10) + The maximum number that you can represent with two Hex digits + is FF = 255 decimal. + + Hope that this makes SOME sense :) + + Effects. + + Axx Set Speed. + + I prefer to think of this command as "Set Frames per Row". + Normally, the tracker operates at around 50 frames a + second. If the rows were played at this speed, then a huge + amount of space would be required to enter the pattern data. + Instead, setting the 'speed' of the song will cause the + tracker to wait on the current row for 'xx' frames. Hence, + setting the speed at 50 (decimal = 32hex) will cause each + row to last about a second - quite a long time! The default + is A06. The initial speed can be set in the variables + screen on F12. + + If two Axx commands are given in the same row, then the + command in the higher channel (by number) will take effect. + + Bxx Jump to order. + + Causes the song to jump to order xx (hex). This is often + used to create looping songs. + + If two Bxx commands are given, then the command in the + higher channel will take effect. + + Cxx Break to row. + + The Command Cxx signifies the end of the current pattern, + and also that the next pattern should be played from row + xx (hex) + + If two Cxx commands are given... you know :) + + D0x Volume slide down + + The volume slide down command causes the volume of the + note to be reduced by x for each frame after (for that + row). ie. If you have a note at volume 64, with command + D01 and speed A06, then the final volume will be 64-5=59. + A note at volume 32 with command D02 at speed A05 will + result in a volume of 24. + + For greater S3M compatibility, D0F will cause the volume + to drop by 15 EVERY frame, instead of just off-note frames. + + Here's a full frame-by-frame description which should provide + greater understanding: + + At 'speed' 4: + C-4 01 .. D04 + + What this does is: + Frame 1: Plays C-4 with instrument 1 + Frame 2: Lowers the volume by 4 + Frame 3: Lowers the volume by 4 + Frame 4: Lowers the volume by 4 + + The next frame will be controlled by the next row of + information. + + Dx0 Volume slide up. + + Operates exactly the same way as D0x, but slides the + volume up by 'x'. Volumes cannot exceed 64 (checked + and limited internally). + + For greater S3M compatibility, DF0 will cause the volume + to rise by 15 EVERY frame, instead of just off-note frames. + + DFx Fine volume slide down. + + Takes the volume down by x at the start of the row. + + DxF Fine volume slide up. + + Takes the volume up by x at the start of the row. + + Exx Pitch slide down + + The pitch will slide down with speed xx (hex). In linear + frequency mode, a pitch slide down by a particular value + will always cause the same "pitch interval" - this does + not occur in Amiga frequency mode. Valid ranges for xx + are between 0 and 0DFh (as > 0E0h will be interpreted as + fine slides) + + EFx Fine pitch slide down + + Slides the pitch down by x at the start of the row. + + EEx Extra fine pitch slide down + + Same as EFx, but 4 times finer. (ie. EE4 is equivalent to + EF1) + + Fxx Pitch Slide up + FFx Fine Pitch slide up + FEx Extra fine pitch slide up + + Operates in the same manner as the Exx commands, but + slides the pitch up. If the pitch gets 'too high', then + the channel is turned off. + + Gxx Portamento to note. + + This command requires 2 parameters: A note to slide to + and a speed. Example: + + C-4 01 .00 + G-4 01 G08 + G00 + G00 + + This will cause the note C-4 to slide to G-4 with speed 8. + + You *CAN* change the sample that the note is sliding to. + It is a good idea to make sure that the C5Speed of the + samples is similar, if you want to try this! The new sample + will play from it's beginning. + + Hxy Vibrato with speed x, depth y + + Causes the frequency to osciallte with depth 'y' at speed + 'x' which causes an interesting effect. Don't get carried + away with it though! If you specify EITHER x or y as 0, then + the previous value will be used. + + Ixy Tremor with ontime x, offtime y. + + Causes the volume of the instrument to remain normal for + x frames, then sets the volume to 0 for y frames. + + Jxy Arpeggio with halftones x, y. + + This causes the note to quickly cycle through three notes - + the note playing, a note x halftones above, and a note y + halftones above. This causes an effect similar to old + C-64 chords. + + Example: C-4 01 J47 will cause the notes C-4, E-4 and + G-4 to be cycled. + + Kxx Dual command: Vibrato + Dxx (Volume slide) + + Note: The vibrato could have been set with either Hxx or + Uxx + + Lxx Dual Command: G00 + Dxx (Portamento to and Volume slide) + + Mxx Set channel volume + + Each channel has a volume range from 0->40h. The lower + the value, the softer the notes in the channel. This + command is convenient for making 'echoes'... you won't have + to modify the echoing channel from the original, except + for placing a M20 at the top of it! + + Values greater than 40h are ignored at playtime. + + N0x, Nx0, NFx, NxF Slide channel volume commands + + These commands work in the same manner as the slide + volume commands, but operate on the channel volume, + rather than directly on the note volume. + + Oxx Set sample offset. + + This will cause a sample to be played from offset yxx00h. + This is useful to skip past the first part of a sample + which may have a loud hit, or to start a speech sample + half way through. + + If you specify a value PAST the end of a sample, then the + command is ignored. + + The "y" part of yxx00h is set with command "SAy" + + Example: + ... .. .. SA5 + C-4 01 .. O10 + + This will play note C-4, instrument 1 at offset 51000hex + + Note to programmers: Oxx for 16-bit samples will move + to the xx00h*2 position in the sample - ie. the 'xx00th' + sample. + + P0x, Px0, PFx, PxF Slide panning commands. + + These work in the same maner as the slide volume + commands, but operate on the channel panning. P0x slides + the panning right, while Px0 slides the panning left. + + Qxy Retriggers a note after y frames with volume modifier x. + + This will cause a sample to be replayed from it's + beginning after every y frames. 'x' can be any of the + following: + + Value Effect on volume each retrig. + 0 No change + 1 -1 + 2 -2 + 3 -4 + 4 -8 + 5 -16 + 6 *2/3 + 7 *1/2 + 8 No change + 9 +1 + A +2 + B +4 + C +8 + D +16 + E *3/2 + F *2 + + Rxy Tremelo with speed x, depth y + + This command acts similarly to the vibrato command, but + affects the note volume, instead of the pitch. If you specify + EITHER x or y as 0, then the previous value will be used. + + S3x Sets vibrato waveform to x + S4x Sets tremelo waveform to x + S5x Sets panbrello waveform to x + + Values for x: 0 = sine wave + 1 = square wave + 2 = Ramp down + 3 = Random! + + S70 Past note cut + S71 Past note off + S72 Past note fade + + With the loss of 1-1 correspondence of editing channels + to internal playing channels, these commands provide + control over notes that have already been played by a + channel. + + Example: + Consider the following situation, where instrument + 1, notes C-4 & D-4 map to a looped sample, and the + New Note Action is set to continue. + + C-4 01 64 . + D-4 01 64 . + E-4 01 64 . <--- Use S70 here! + + Ordinarily, control would be lost over C-4 and D-4, but + using command S70 at the point indicated, the notes C-4 + and D-4 would be stopped immediately when the note E-4 + plays. + + Similarly, note off commands and Fadeout commands can + also be issued. + + Note: You *MUST* be in instrument mode for these + to have any significance. + + S6x Pattern delay for x ticks. + + S73 Set NNA to note cut + S74 Set NNA to continue + S75 Set NNA to note off + S76 Set NNA to note fade + + These options allow you to override the default NNA for a + particular NOTE (ie. it does not affect the instrument) + See section 2.5 for an explanation of NNAs. + + Note: You *MUST* be in instrument mode for these to have + any effect. + + S77 Turn Volume envelope off. + + Stops the processing of the volume envelope. This is for the + times that you don't want to use the volume envelope that + you've created. + + S78 Turn volume envelope on. + + Sometimes, you'll decide that it's better not to use the + volume envelope for most cases, but you may just want to + use it a few times - this is the command that lets you + do that! + + Note: You *MUST* be in instrument mode for this to work. + + S8x Set panning position + + Set panning position, S80 is leftmost, S8F is rightmost. + This is an obsolete command, provided only for ST3 + compatibility. Use command Xxx instead. + + S91 Set surround sound! + + For those of you who are lucky enough to have a dolby + surround sound decoder (myself not included - so if ya + wanna send me something.....), this *should* cause the + sound to come from the surround speaker. This is a + pseudo-panning command, and issuing either Xxx or S8x + will cause the surround sound to be reset. + + If you try and play Surround Sound on a GUS, Interwave + or AWE32, it will be played as a central pan. + + SAy Set high-offset. Check Oxx for an example. + + SB0 Set loopback point + SBx Loop x times. + + This pattern space-saving feature will cause the pattern + to be looped x times back to the last SB0. Note that you + can only loop within the pattern! Also, each channel has + it's own loop-back information... so you HAVE to have the + SB0 and SBx in the same channel for it to operate. + + SCx Note cut after x frames + + This will cause a note to be immediately stopped after x + frames. It is similar to issuing a "^^^" in the note column, + just that it has a finer control over timing. + + SDx Note delay for x frames + + Actually, this command works like "interpretation" delay + for x frames. Any data - note, sample/instrument or volume + in the channel will not be interpreted until x frames into + the row. + + SEx Pattern delay for x rows + + This will cause a "pause" on the row for effectively x rows + longer. + + Note that if TWO pattern delay commands are issued, then + the only the command in the higher channel will be considered. + + Txx Set tempo to xx + + Valid ranges are between 20h and 0FFh. The higher the + value, the faster the playback. This essentially + determines the time length of each frame, by the following + formulas: + Frames per minute = 24*Tempo + equivalently: + Frames per second = 0.4*Tempo + + T0x Tempo slide down + T1x Tempo slide up + + Tempo slides up and down are used to smoothly modify the + speed of the song. The tempo is modified by x every + non-row frame. + + Uxy Fine vibrato with speed x, depth y + + Same as vibrato, but 4 times finer in depth. + + Vxx Set Global volume + + Valid ranges are between 0 and 80h. All notes playing are + affected by this change. + Values greater than 80h are ignored at playtime. + + W0x, Wx0, WFx, WxF Slide global volume + + Similar to the Dxx commands, but operate on the global + volume. Useful when fading out songs. + + Xxx Set panning position + + Sets the panning position anywhere from left to right (X00 + is left, XFF is right). + + Yxy Panbrello with speed x, depth y. + + What the hell is panbrello? Well, it's a word that I coined + late one night after a friend suggested that there should + be a random pan position command. I decided.. why not - I'll + make the vibrato/tremelo equivalent of panning! And so you + have here, 'panbrello.' What this does is instead of + oscillating frequency (pitch) or volume, it oscillates the + panning position about the 'set' panning position for a + channel. This is for you techno freaks out there who want + another function to stuff around with! :) + + The random pan position can be achieved by setting the + waveform to 3 (ie. a S53 command). In this case *ONLY*, the + speed actually is interpreted as a delay in frames before + another random value is found. so S14 will be a very QUICK + panbrello, and S44 will be a slower panbrello. With any + other waveform, the higher the value for x, the faster the + panbrello, like vibrato and tremelo. If you don't know what + I'm talking about, check out the stereo-indicators on the + info page (don't forget that you have to be in stereo mode!) + + If you specify EITHER x or y as 0, then the previous value + will be used. + + 5) Editing Functions + + For a complete list of available functions, check the help screen + for the pattern editor (on F1) + + Ctrl-Backspace IMPORTANT! This one will save you a lot of + frustration - it's a 10-stage listed Undo + function! + + Grey Plus Advance to next pattern + Grey Minus Goto previous pattern + Shift-GPlus Advance 4 patterns + Shift-GMinus Go back 4 patterns + Ctrl-GPlus Go to the next order's pattern + Ctrl-GMinus Go to the previous order's pattern + + Alt-Delete Remove an entire row from the pattern + Alt-Insert Insert an entire row into the pattern + + '.' erase data. + Space will enter the previous data for that column. + '4' play the note under the cursor. + '8' play entire row. + Ctrl-F6 play pattern from the current row. + Ctrl-F7 Set playback mark - this will be the position that + subsequent playback will occur when you press F7. + Remove the mark by pressing Ctrl-F7 on the row + that is already 'marked.' + + Alt-0 -> 9 Quick select "skip value" + The skip value is the number of rows that the + editor advances by when a note is entered - this + makes it easy to enter notes on alternate rows + (press alt-2 first!) + + If the skip value is 0, then the editor will + advance to the next channel (making it easier to + enter chords) + + If the skip value is 0, AND template mode is on, + then entering a note will cause the editor to + advance by the length of the template block. + + Alt-Enter Store current pattern in memory + Alt-Backspace Restore current pattern + + 6) Block Functions + Alt-B Mark top left of block + Alt-E Mark bottom right of block + Alt-L Mark entire column (channel) + Alt-L*2 Mark entire pattern + Alt-D Mark the minor row hilight number of rows. Pressing + this repeatedly doubles the length of the block. + eg. Pressing Alt-D once may mark out 16 rows, + pressing it twice will mark 16 rows. + + Alt-A Transpose all the notes in the block a semitone + down If no block is marked, then the current note + will be transposed a semitone down. + Alt-C Copy marked block into the clipboard + Alt-F Double the length of the selected block + Alt-G Halve the length of the selected block + Alt-I Toggle Template mode... read part 8 + Alt-J Volume Amplifier... modify the volume controls + between 0 and 200% + Alt-K Slide volume... if you want to manually control a + fadeout, or fadein, then set the volumes at the + extreme ends of the blocks, then press Alt-K ONCE! + Alt-K*2 Remove all volume controls in the selected block + Alt-M Mix clipboard with pattern data.. try it out, and + you'll understand (it's like an advanced paste + command - it'll only copy the data IF there is nothing + on the row it is copying to.) + Pressing this two times will copy the data if there's + nothing in the same FIELD (not just same row). + Alt-N Toggle Multichannel mode.. Multichannel mode allows + you to select for each channel whether it should be + part of the multichannel list. If you enter a note + while on a channel which is in the multichannel + list, then the editor will advance to the next + channel. + Alt-N*2 Multichannel menu. + Alt-O Overwrite pattern data with clipboard. Like paste, + but without the "insert" part :) + Alt-P Paste clipboard into pattern at current position + Alt-Q Transpose all the notes in the block a semitone up + If no block is marked, then the current note will + be transposed a semitone up. + Alt-S Set all the instrument (sample) values to the + current instrument (sample) within a block + Alt-U Unmark block / release clipboard from memory. + Alt-V Set all the volume controls to the current + Alt-W Remove all volumes not associated with a note/inst + Alt-X Slide command value. Similar to Alt-K (slide + volume). This command can be convenient to slide + the panning from one position to another, or to + slide global volume effects, channel volume, sample + offsets... whatever... + + Alt-X*2 Erase all effect data in the selected block! + Alt-Y Swap selected block with a samesized/shaped block + starting at the current position. Swap blocks + CANNOT overlap. + Alt-Z Cut current block. + Warning: If you don't have enough memory, the + current block WILL be erased, although there is no + record of it in the clipboard.... + + 7) Track View functions + + Sometimes you just want to know what you've put in those tracks + that are currently off the screen... these functions allow you + to do just that! + + Alt-T Cycle Track view mode. + Alt-R Remove all track views + Alt-H Remove track view divisions (allows you to view 36 + channels!) + Ctrl-0 Remove current track from track view + Ctrl-1->5 Quick select a track view for current channel. + + 8) Templates + + Templates are an invention to make entering repeated + 'sequences' easier. Often, you may want to enter a note with + the same effects following each note. eg. + + C-4 01 00 D10 } + D00 } + D00 } Enter this.... + D00 } + D02 } + D00 } + D-4 01 00 D10 } + D00 } + D00 } + D00 } + D02 } + D00 } Use the templates to enter this! + E-4 01 00 D10 } + D00 } + D00 } + D00 } + D02 } + D00 } + etc.. + + With templates, this can be done by entering the first 'block', + then marking it and copying it into the clipboard (using + Alt-C). Toggle the template mode by pressing Alt-I to Template: + Overwrite, then go to the start of the second block, and press + the key for D-4 (normally X). The whole block will be filled + in! This is easiest to understand if you print this section out + and try it in the editor. + + The templates can also include other notes, which will be + translated accordingly, and can span several channels. + + A VERY neat use of templates is to enter multiple notes: + (eg. octaves, different samples, left/right stereo sample + pairs...) + + C-4 01 32 .00 C-5 02 32 .00 } Enter this... + G-4 01 32 .00 G-5 02 32 .00 } + D#4 01 32 .00 D#5 02 32 .00 } + C-4 01 32 .00 C-5 02 32 .00 } And use Templates here! + G-4 01 32 .00 G-5 02 32 .00 } + D#4 01 32 .00 D#5 02 32 .00 } + + Templates can span more than one row and one channel - you + can template blocks of any size. + + 2.3 Order List, Channel panning & volume. (F11) + After creating patterns, the tracker has to know what order to + play them back in. The order list is the means by which this is + done. Another wording of the Order List which may make it simper + to understand is the "Pattern sequence list." ie. the sequence in + which the patterns are played back. + Simply enter the patterns into the list in the order they + should be played, and voila! - you have a new piece of music. + (as long as you have something in the patterns, of course!). The + "---" marks the end of a song, and "+++" is simply a marker which + is skipped (for ST3 support). Pressing N on a row will enter the + previous order's pattern+1. eg. Entering 000, then pressing 'n' 5 + times will enter 000 (which you typed), then 1, 2, 3, 4 and 5. + + Initial channel panning and volume is the panning and volume that + each channel is set to whenever the song is reset. It will not + affect anything currently playing. On the panning list, you can + also mute channels by pressing spacebar. Pressing S will select + the initial 'panning' as surround sound. The initial channel + volumes can be accessed by pressing F11 once you are already on + the Order list and channel panning screen. + + 2.4 Samples + + 2.4.1 Information about Samples + Samples are the raw sound information. They can be of *anything* + you like - normally a musical instrument of some sort, but you + could have voice samples or sound effects too! + + Impulse Tracker accepts 8-bit or 16-bit samples. It can import + several different formats, which are detailed in section 1.4 + + If you import a 16-bit file which isn't recognised, you have to + use the following steps: + + 1) Press Alt-A (to convert signed/unsigned) and convert the + data. + 2) Press Alt-Q (to toggle to 16-bit) and DON'T convert + the data + 3) If the sample is unsigned, you will then need to convert + it AGAIN by pressing Alt-A (and selecting yes to convert + data) + + Samples have the following information: A name, a default volume, + a global volume, vibrato information, loop information and a + frequency + + The default volume of a sample is the volume at which a sample is + played, IF no volume is specifier. + + The global volume is the modifier by which ALL occurrences of the + current sample are scaled by. + + Vibrato information - the vibrato speed is the speed at which the + vibrato oscillates. Although it is possible to enter values 0->64, + the best effects are obtained by entering values around 24-48. The + vibrato depth determines the maximum deviation from the mean + frequency. The vibrato rate determines how quickly the vibrato is + applied. Higher values cause the vibrato to be applied more + quickly, a low value like 1 can take many seconds before the + vibrato is noticed. + + Loop information. Samples can be looped to provide a continuous + sound. The loop beginning and the loop end must be specified, and + the loop method (either forwards or ping pong) must be set. + (Toggle by pressing spacebar). The loop boundaries can also be + modified using '+' or '-' (even while the sample is playing!) + + Sustain loops are the loops used as long as no note off command is + encountered. In the sample tester, releasing a key provides a note + off command to the player. Once a note off command is issued, the + normal loops apply. The idea behind sustain loops originated after + listening to some synthesizers which provided 'after note' sounds + - like fingers lifting off guitar strings. With sustain loops, you + can have a guitar sound in the sustain loop, with the end of the + sample containing the 'finger off' sound. This way, you should be + able to achieve a new degree of realism. The best way to do this + is to have a reasonably small sustain loop, and a section after it + containing the note-off sound, possibly looped. (The sustain loop + should ideally be less than 1/20th of a second, so that you have + reasonably good control over the timing of the note-off, but this + is not always possible) + + Example: If you have a sample with no sample loop, but a sustain + loop around bytes 19000-20000, then while no noteoff + command is issued, then the sample will loop between + 19000 and 20000. Once a noteoff command is received, + then the sample will be played until it's end and then + will stop. + + If you have a sample of length 64000 with a ping pong + loop around the whole sample (0->64000) and a sustain + ping pong loop around bytes 20000-30000, then the + sample will loop backwards and forwards between 20000 + and 30000 until a noteoff command is received, after + which it will loop between 0 and 64000 (backwards and + forwards). + + It is recommended that you do NOT have a ping pong sustain loop + going to a forwards loop or no loop and that if you DO have a + sustain loop AND a normal loop, that the sustain loop lies + within the normal loop (for ping pong), or that the normal loop + end is after the sustain loop end (for forward's loop) (think + about what you're asking it to do in these cases carefully... + it should make sense - the tracker can still handle the cases + when this is not adhered to, but the resulting note-off effect + can vary greatly depending on timing and pitch!) + + The frequency of a sample determines its pitch. The higher the + frequency, the higher the pitch. The frequency can be doubled or + halved by pressing Alt-Grey Plus/Minus to cause an octave + rise/decrease. For the technically inclined out there, the + frequency is the number of bytes per second that have to be played + for a C-5. You can increase the frequency by one semitone by + pressing Ctrl-Grey Plus or decrease it by a semitone with + Ctrl-Grey Minus. + + To load in a sample, go to the entry in which you want to load it + then press enter. The sample library should appear. You can test + out any sample just by "playing" notes on the keyboard while you + are on top of the sample. Load a sample into the sample list by + pressing enter. Of course, if you don't have any samples, no + samples will appear :) + + Where can I get samples from?? + + You can steal ('rip') samples from modules by going to the sample + in the sample list, then pressing Alt-O. Scream Tracker 3 samples + can be saved by pressing Alt-T (vibrato, global volume + susloop + information lost) or raw samples can be saved by pressing Alt-W + (all variables lost!) + + Warning: Be careful where you rip samples from!! Some people don't + welcome it at all! And in some cases, sample ripping may be a breach + of copyright - this mainly a concern when you use commercial samples) + + There are also many great sample 'packs' available... try a local + music BBS, or the bigger FTP sites. + + Some synthesizers have patch files (eg. Kurzweil 2000 as .KRZ) which + are available through the internet. You can download these, and + convert them with an appropriate utility (I recommend Convert 1.4 - + convrt14.zip on ftp.cdrom.com/pub/demos/programs/convert and use + it to convert the files to .S3I format - even for 16 bit samples). + I don't know what sort of copyright these samples have. *YOU* have + to read any text accompanying the files to find this out. + + Finally, you can make your OWN samples! With a sampler (eg. + Digiplay 3.0) or with some other tracker (eg. Fast Tracker 2), you + are able to record information through the microphone socket of + the computer! + + Note: The length of a sample is *NOT* necessarily the number of bytes + it occupies! The length quoted is the quantity of SAMPLE INFORMATION. + If you have an 8 bit sample, then the size in bytes IS the same as + the length. If you have a 16-bit sample, then the size in bytes + is DOUBLE the length. + + 2.4.2 Sample Functions + + Alt-A and Alt-Q provide basic sample-conversion functions. Alt-A + will convert a sample to or from unsigned to signed format. Alt-Q + will allow you to change a sample between 8 and 16 bits. + + If you want to remove the part of a sample before a loop or after the + end of a loop, you can use Pre-loop cut sample (Alt-B) or Post-Loop + cut sample (Alt-L) + + To reverse a sample, use Alt-G. This can produce interesting effects. + + If you are working to a size limit, check out the functions Alt-E + and Alt-F. These functions allow you to resize the sample to whatever + size you would like! (Note that there is a reduction in quality + associated with a reduction in size). Alt-E will resize the samples + WITH interpolation, Alt-F will resize the samples WITHOUT + interpolation. + + To decrease the volume of a sample, the best way for 8 bit samples + is to reduce the Sample's GLOBAL volume. For 16-bit samples, it's + better to just attenuate the sample (ie. use Alt-M to 75%). The + sample will retain greater quality if you follow these guidelines. + + Alt-M is used to amplify a sample to between 0 and 400%. The default + value for Alt-M which appears is the maximum the sample can be + modified without creating clipping distortions. + + To exchange two samples *in the sample list only*, use Alt-X. To + swap two samples *even in the pattern data*, use Alt-S. + + 2.5 Instruments + + For those who have never used a tracker before, I strongly suggest + that you skip this section for now - learn how to 'use' samples + first. After that, you'll should be able to understand and hopefully + fully appreciate the power that instruments can provide. + + To enable instruments, go to the song variables (F12), and press + on the "Instruments" button after then "Control" prompt. This *MUST* + be done in order to use ANY instrument function (including special + note effects, viz S7x). + + The instrument parameters are split into four screens - one for + each of general options, volume options, panning options and pitch + options. To select the appropriate screen, just whack enter on any + of the four buttons at the top of the instrument list. + + Instruments are collections of samples (or just a single sample). + The translation of samples is controlled by the column in the + centre of the screen on the general options page which shows what + note/sample pair a single instrument note will be translated to. + Example: If you're on instrument 1, and the note translation table + appears as such: + + C-5C-5 01 + C#5C-5 02 + D-5D-4 03 + D#5D#4 03 + + Then entering "C-5 01" into a pattern will cause sample 1 to be + played at pitch C-5, "C#5 01", wil cause sample 2, to be played a + pitch C-5, "D-5 01" will cause Sample 3 to play at D-4, "D#5 01" + will cause Sample 3 pitch D#4 to play... get the idea? + + Why would you want to combine several samples into one instrument? + Well, one very good reason is that it makes it easier to enter + drum parts - you no longer have to change the 'instrument' if you + want another sample. And also, combining them into one instrument + makes them easier to manage - you can specify a volume envelope, + NNA or FadeOut which will apply for ALL of the samples in the + list. + + Another reason is if you want a very high quality sounding + 'instrument.' If you wanted to go overboard, you could sample + every single note on a piano separately, and set up the note + translation table to point to each sample accordingly - you'd + get a very, very nice sound - if you don't run out of memory + first. Or patience :) + + When you save an instrument to disk, all the related samples are + stored with it. This means that you can setup a 'drum kit' instrument, + and to load it into another song, you only need to select that + instrument and all the samples will be loaded for you. + + The Fadeout value for each instrument determines how quickly the + volume of the instrument decays under any of the following + conditions: + 1) NNA "FadeOut" is selected, and another note is played. (see + later in this section for info about NNAs) + 2) The end of a volume envelope is reached. + 3) A note off command is encountered, without a volume envelope. + 4) A note off command is encountered, and the 'normal' volume + envelope loop is on. + + The larger the fadeout value, the quicker the volume decays. + + Each instrument also has an associated volume/pan/pitch envelope! + The volume envelope is editing by selecting the node (left/right + arrows) then picking it up (with enter), moving it around (using + arrows, or Alt-Arrows for quicker control), then pressing enter + again to "put down the node". Nodes can be inserted or deleted + (with the keys insert and delete!). Note that the envelope will + only be used if the envelope flag is set to "on" (just below the + envelope graph).. + + Remember that you have to be in instrument mode for this all to work! + + There are 3 pieces of information for each Envelope graph - + the node number (hopefully obvious), the time of the node (the + number of 'ticks' or 'frames' that elapse before the node point) + and the value of a node (also hopefully obvious). So the x-axis + is time, and the y-axis is volume/pan/pitch - simple, really! + + You can also specify envelope loops and sustain loops. These + operate in the same manner as the sample loops, but the numbers + refer to node numbers. + + The powerful feature of this tracker, though, is not the + envelopes by themselves - it's the New Note Actions! What these + options do is allow you to select what should happen to an + instrument when another note is played in the same column. If NNA + "Cut" is selected, then the previous note will immediately be + stopped (like in all other trackers). If NNA "Continue" is + selected, then the note will continue playing! This is especially + useful for Drum Parts, where there may be a long-ish snare sample + - you can go on ahead and put a bass drum in the very next row + after it - the snare drum will still complete playing! NNA "Note + Off" issues a note off command to a note when a new note is played + in the channel. This is particularly useful in combination with + volume envelopes and volume envelope sustain loops. NNA "Note + Fade" causes the current note to fade out with the fadeout value + when a new note is played. + + WARNING!! + New Note Actions are EXTREMELY powerful, but they CAN cause + problems if you are not careful. Selecting NNA Fade with a fade + value of 0, or note continue with a looped sample (no volume + envelope) or anything which can cause a quick build up of + allocated channels can easily hang a slow computer (or even a + quick one, for that matter!) I tried to put checks against this, + but they always triggered too late - "past the point of no return" + where the CPU becomes so bogged down with processing the + information, that it can't do or try to do anything else. (The + tracker has *MANY* calculations to do - the most time consuming + are the mixing routines, which require the processor to process as + many bytes as the mixing speed per second for EACH note ie. a + mixing speed of 44kHz means that for each note playing, 44000 + calculations have to be made EVERY second... so with 64 channels + 'active' at the maximum mixing rate for a SB16, almost 3 MILLION + calculations have to be done EVERY second to produce the sound (in + mono)!!! (My 486 can cope with this, but my 386 just dies!) + + Duplicate Check Type (DCT) / Duplicate Check Action (DCA) + DCT = Off/Note/Sample/Instrument, DCA = Cut/Off/Fade + + When the duplicate check type is enabled, then repetitions of the same + instrument¬e/sample (or just repititions of the same instrument) + pair in a particular channel will cause the previous occurence of + the instrument¬e/sample pair to be cut or faded (depending on + the DCA) + + Example: If the DCT is set to note, and DCA is set to Cut, then the + asterixed notes will cut out the tilda notes + Ŀ + C-4 01 ~ C-4 02 ~ C-4 03 } + D-4 01 C-4 02 * ~ D-4 03 } Nothing get's cut. + C-4 01 * C-4 02 * C-4 02 } + + + This option was included to help limit the number of active channels, + and is especially useful for drum tracks. + + Another nifty application of Duplicity checks is the following + example: You can have a separate sample for each string of a guitar + and setup and instrument to accomodate this. Setting the NNA to + continue, the DCT to sample and the DCA to fade (with a relatively + quick fadeout) means that whenever you play a new note, the previous + note will continue to play on. BUT! If a previous note of the same + instrument has the same sample as the new note being played, then + it will be faded out - this closely relates to what you hear when + someone plays a guitar - when they play the same string, they have + to put their fingers down on the string, which causes the last note + *on that string* to fade out. + + I sincerely hope that these options do not cause the death of brilliant + 4 channel music - that would be a great shame! There is truly an art in + making a decent sound in as few channels as possible! (If you're new to + this sorta thing, then it'll grow upon you...) + + For interest's sake... + Channels are turned off internally under any of the following + conditions: + 1) The end of a sample is reached (quite obvious) + 2) When the end of a volume envelope is reached, and the final + envelope volume is 0 + 3) When the fadeout value for a channel causes it to become silent. + 4) When a duplicate note is played when DNT is set to Note and DCA is + set to cut for the instrument. + 5) When a notecut is issued (obvious) + 6) When a channel is moved to the background (using NNAs) + AND the volume is 0. + + Out of all the functions provided for the Samples and Instruments, + perhaps the only one that requires explanation is the "Update + Pattern Data" function. This function was written for people who + have already written music in MOD/S3M/MTM formats, and want to + combine their percussion parts into a single instrument. The way + to do this is to set up the instrument->note/sample table, and + then use the "Update Pattern Data" function. What this does is + search through all the patterns for all occurrences of the + note/sample pairs that appear in the instrument->note/sample + table, and replace it with the appropriate note/INSTRUMENT pair. + Sounds quite complicated... sorry :) + + Example: + If you originally have the following setup + + Sample 1 = Bass Drum + Sample 2 = Snare Drum + Sample 3 = Closed Hihat + Sample 4 = Open Hihat + + And the following column within any pattern: + + C-5 01 . + C-5 03 . + C-5 03 . + C-5 03 . + C-5 02 . + C-5 04 . + C-5 01 . + C-5 04 . + C-5 01 . + + You can combine these four samples into one instrument by + creating the instrument->note/sample table with the + following entries: (say for instrument 10) + + C-5C-5 01 + C#5C-5 <--- just an empty slot... + D-5C-5 02 + D#5C-5 + E-5C-5 03 + F-5C-5 04 + + And using the update pattern data command will produce the + following + + C-5 10 . + E-5 10 . + E-5 10 . + E-5 10 . + D-5 10 . + F-5 10 . + C-5 10 . + F-5 10 . + C-5 10 . + + 2.6 Song Variables + + Most of the options on this screen should be quite obvious, but they + are explained here for clarity. + + Song Name - should be obvious. Shove whatever you like in here :) + + Inital tempo - The tempo that the piece starts with. The tempo + calculation is explained under the set tempo + command (Txx) + + Inital speed - The speed that the song starts with. The speed + calculation is explained under the set speed + command (Axx) + + Global volume - This scales all the volumes in the song. It may be + necessary to change this value if there is overload + occuring (in the form of crackles in the music) - + especially on the Gravis UltraSound, as it is a + non-mixing device, and not scaled by the mixing + volume. + + Mixing volume - This value affects mixing sound devices (ie. + all Sound Blaster cards + PC Speaker). + + Separation - The separation determines how far apart the left/right + panning sounds. It is suggested that for a stereo + system (where the speakers are relatively close together) + that the separation be around its maximum (ie. 128). + For a stereo system where the speakers are placed a + large distance apart, a value of 80 may suit better. + A suggested separation for headphones is around 40. + This value has no significance unless stereo playback + is selected. + + Old Effects - When Impulse Tracker was first written, some effects + were interpreted differently from other formats, most + notably vibrato. When you turn this ON, then it effects + will be interpreted how the used to be in ST3/MMEdit/... + but when it's off, it'll operate how it use to in + previous versions. + + Differences: + The Vibrato (and Tremelo) used in IT is smoother than + how it was implemented in MOD/S3M/etc. It is updated + EVERY frame and hence is independant of song speed, + whereas the standard vibrato WAS dependant upon song + speed. Vibrato is two times 'deeper' with Old Effects + on. + + Sample offset commands past the end of a sample in IT + were ignored, whereas with Old Effects on, the sample + is played from it's end point. + + Control - This is the option that lets you use Instruments! + When Control Sample is selected, then all the instrument + information is ignored. The query to initialise + instruments, if accepted, will copy all the sample + names to the instruments (if the samples exist) and set + up the Note Translation Table for each instrument to point + to a sample. + + Playback - Mono: When you select mono playback, all stereo commands + are essentially ignored. If you are using a SBPro, + selecting Mono provides a higher quality output + than selecting Stereo and using a central pan. + + Stereo: This is the option to go for! + Note that stereo mode requires more processing + power than mono (unless you are using a hardware + driver) + + Pitch Slides - Amiga: This is the mode to choose for compatibility + with S3Ms, MODs, MTMs, XMs... when you select + amiga pitch slides, you'll often have to + experiment to find the adequate slide value. + + - Linear: With the linear slides, a certain slide value + will always cause the same music "interval" + change. An example of what this means is if + you slide up a note with speed 8 (ie. F08) at + speed 5, then the result will be that the + note is raised a tone. Everytime. So a C-4 + will rise to a D-4, C-5 will rise to a D-5. + (It's not like this with amiga slides! A + C-4 *MAY* rise to a D-4, but if it does then + the C-5 will rise to a note around E-5!!) + + The benefit of linear slides is that if you + slide a pair of notes at the same speed, they + will maintain the same interval (pitch + difference) throughout. Also, if you modulate + (transpose) a pattern, you will not have to + modify any slide values. + + Directories - this shows the current song/sample/instrument + directories. If you want to save the current directories + as the default to have on bootup, then press enter + on the Save button. Note that this save function also + saves the palette, keyboard type, info page layout + and pattern editing preferences to IT.CFG + + 2.7 Scream Tracker 3 Users + This section is just for users of Scream Tracker 3 who would like to know + the differences between ST3 and IT without working through the whole + document. In a nutshell: + + 1) Differences in use. + a) The Order List, Panning and Variables used to be on F1. In IT, + F1 has been reserved for the Help Screen, F11 for the order list + and panning, F12 for the variables. + If you REALLY do find this too inconvenient, use the command line + switch -k to swap the interpretation of the keys F1 and F11... + no text will be updated tho (and it does seem sorta weird!) + b) Samples now have associated Vibrato information and a global + volume. The global volume affects all instances of the sample + throughout the song. This is useful when you replace a sample, + which is at a different volume from the original - you can just + adjust the global volumes of the samples to suit. + d) Block functions are no longer restricted to one column. This also + means that when you copy entire patterns, you will have to go to + the top left of the pattern. Also, you will have to set the number + of rows in the destination pattern to the appropriate number if + it is different from the source. + This difference may take some getting used to - you may often + find yourself doing several block functions in a single columns + when you could actually have done it across the whole block! + * To mark blocks, you can use Alt-B and Alt-E, or Shift+Movement * + e) In the pattern editor, the following commands have changed: + 1) Alt-T : Track View has been upgraded. Alt-T will cycle + through all of the possible 5 viewmethods. You can + use Ctrl-1 to Ctrl-5 to quick select a view, or + Ctrl-0 to remove a view. Press Left-Ctrl+Shift 1->4 + to select a 'different way to edit' :) + 2) Alt-X : Pressing Alt-X once will slide the effect data value + in a block (useful for controlling global volume, + panning or sample offsets in some cases). Pressing + Alt-X twice will cause all of the effect data to be + deleted as in Scream Tracker 3 + 3) Alt-K : Pressing Alt-K once will slide the volumes. Pressing + Alt-K TWICE will remove all volume controls in the + block. (Works like Alt-X, but on the volume column) + 4) Alt-I : Cycle Template control. + 5) Alt-J : Volume amplifier. Select an amplification between + 0 and 200%. + 6) Alt-H : Now toggles view divisions on/off. Makes it possible + to view/edit up to 36 channels in the pattern editor!!! + 7) Alt-Z : Originally the Zap command (if pressed twice)... now + it is effectively a "Block Cut" command. It will + copy the block into the clipboard, and then wipe the + block clean. + 8) Alt-V : Will set all the volumes in the block to the default. + 9) Alt-W : Will remove ALL volumes not attached to a + note/instrument Therefore, the old Alt-V command can + be simulated using Alt-V then Alt-W. The reason for + doing this was so that the Alt-K, Alt-W combination + would slide all the volumes with notes/instruments + associated. + f) There is no chord edit feature in IT. I considered the chord + edit feature of ST3 useless and a bad influence on new trackers :) + g) Patterns can be from 32 to 200 rows! (Under Pattern edit config + on F2, or Ctrl-F2) + h) Pressing spacebar in the pattern editor will cause the previously + entered note/instrument/volume/efffect/effectvalue to be entered. + Quite convenient. Hopefully. + i) Alt-F10 now solos a channel instead of toggling all of the + channels on/off. On the InfoPage, you can use 's' to solo + channels, and 'q' to toggle channels. I felt that this was more + usable than the original. + j) The infopage itself has become upgraded... press PgUp/PgDn to + cycle through view methods, "Insert" to add a window, "Delete" + to remove the currently highlighted window, Tab to move between + windows, Alt-Up/Down to move the base of the window up/down. + k) To increase the sample frequency by an octave in the sample + list, press Alt-Grey '+' or Alt-Grey '-' to decrease the + frequency by an octave. To change it by semi-tones, use Ctrl-Grey + '+' and Ctrl-Grey '-' + l) The Sample library is accesible from all screens in the program + by pressing Ctrl-F3. The Instrument library is accesible on + Ctrl-F4. + m) Each channel has an associated volume. Echoes can be created by + just copying one channel onto another, then setting the "channel + volume" (Command Mxx) + n) When channels are muted, all commands are still interpreted, but + the notes aren't played. What this means is that commands such + as Axx, Bxx, Cxx, SBx, Vxx, Txx, Mxx, Nxx will be processed even + if they are in a muted channel. + o) Pressing Ctrl-Grey Plus and Ctrl-Grey Minus in the pattern + editor will go to the next/previous pattern according to the + order list! + p) Samples have sustain loops + Ping Pong loops supported + q) Note off command & Note cut command implemented... Note cut is + exactly like ST3's ^^^ (and appears like it too!) Note off + appears as "" and releases sustain points. + r) You can enter panning values (between 0 and 64) in the volume + column. Do this by pressing '`' to toggle between entry of + panning/volume values. + s) You can use samples >64k and 16 bit samples!!! + t) When you use a skip value of 0, the cursor will move across to + the next channel. This is a very convenient way to enter chords, + especially when combined with the multi-channel selection (whack + Alt-N twice) + + 2) Differences in interpretation of notedata. + a) Global volume changes will affect ALL of the notes playing. In + ST3, global volume changes only affected new notes. The range + for the global volume command is from 0 to 80h + b) If you specify an instrument without a note, then in ST3, the + volume is set to the default volume. In IT, the volume will be + set to the default volume *IF* the instrument specified is the + SAME as the currently playing instrument. Otherwise, the new + sample will be played from it's beginning. + c) Command X (Set panning, not REALLY implemented in ST3) now has + range from 0 to 0FFh. + d) Command C (Break to row) now works in HEX. This is so that you + can jump to any row in the (next) pattern. + e) New commands: + M: Set channel volume + N: Slide channel volume + P: Slide panning + S5x: Set panbrello waveform and reset panbrello position + S6x: Pattern delay for x frames. + S7x: Instrument related controls (8 different controls here) + S91: Surround sound on! + SAy: Set high offset + T0x: Tempo slide down + T1x: Tempo slide up. + W: Global volume slide. + X: Set pan position. + Yxy: Panbrello + f) If you use the portamento to command (Gxx) to a different sample + in ST3, the sample offset is undetermined. In Impulse Tracker, + the sample will be played from it's start. + g) The commands Hxx and Uxx will cause a vibrato half the depth + of ST3 if "Old Effects" option is OFF and the vibrato in IT is + also smoother than the vibrato in ST3. + + 3) The greatest difference is the implementation of instruments. Read + section 2.5 for more information. + + 4) Saving S3M modules. + + The following guidelines have to be followed to compose 100% + compatible S3M modules. + + General Stuff + 1) *Pitch slide mode MUST be amiga. + 2) *All initial channel volumes MUST be 64 + 3) *No instruments functions can be used. If you ARE in + instrument mode, however, Impulse Tracker will translate + the pattern data according to the Note Translation Tables. + 4) The song message is *NOT* saved in S3M format. + + Pattern stuff + 1) *The total number of patterns MUST NOT exceed 100. + 2) *The number of rows in each pattern MUST be 64 + 3) *Data is only translated within the first 16 channels. + 4) *All notes must lie within the range of C-1 to B-8 + 5) Several commands will not be interpreted by a standard + S3M player (viz. Mxx, Nxx, Pxx, S5x, S6x, S7x, S91, SAy, Wxx, + Yxx). + Also, you should have Old Effects (on the variable list) + put to *ON* if you want to write S3M files. + 6) *Panning controls in the volume column are NOT stored. + + Sample stuff + 1) *No sustain or ping pong loops can be used + 2) *No sample vibrato can be used + 3) *The sample global volume must be 64. + + 4) The Scream Tracker 3 module format supports 16 bit samples + and samples >64k although the actual program did NOT. + Note that *MOST* players probably ignore these fields + and it is likely that the module will NOT be played correctly + by a standard S3M player if it contains samples >64k and/or + 16 bit samples. + + All conditions with an asterix preceding them are checked at save + time. + + Note that both note off () and note cut (^^^) will get translated + to a note cut (^^^) in S3M format. + + 2.8 Gravis UltraSound / Interwave / AWE32 users. + + For hardware mixed devices (eg. Gravis UltraSound, Interwave and + AWE32), there are some limitations that are outlined here. + + I've already mentioned a few things throughout the DOC about hardware + mixing, but I'll reiterate them here with a few more points. + + 1) The maximum number of notes that you CAN play with a GUS and + Interwave is 32. The maximum number of the AWE32 is *30*. + + This was incorporated by effectively limiting the number of active + channels to 32/30. So if you play a 64 channel song which is using + control:Samples, then you will LOSE the last 32/34 channels. If you + are playing a 64 channel song with control:Instruments, you + shouldn't miss out on too much. This shouldn't really be a + problem in 99.9% of the cases. + + 2) The GUS playback quality is dependent on the maximum limit of active + channels. The GUS can be initialised to play anywhere between + 14 and 32 channels. Values above 32 are reduced to 32, and values + below 14 are increased to 14. The lower the number of channels, the + higher the playback quality. (14 channels will give 44100 Hz, with + 16-bit interpolation - very, very nice quality!). The default + GUS driver dynamically chooses a particular number of channels. + This doesn't ALWAYS work with all cards, so if you don't like the + transition of sample quality as the channels increase, or your + GUS seems to stop notes unexpectedly, use the other driver(s). + + 3) The GUS/Interwave/AWE32 routines occupy less memory than the mixing + routines. You will have about 30k-100k more of memory to play + around with. + + 4) The memory allocation routines are very simple and not very + versatile. When you are working through the sample library, samples + are NOT always deallocated when you move on to the next sample! If + you get the message "Out of soundcard RAM", then it may be necessary + to press Ctrl-G (or select Reload Samples from the samples menu) to + reorganise the samples in memory. Sorry about the inconvenience. + + 5) Changing the mixing volume does NOT affect these cards. + It may be necessary to reduce the global volume to remove crackle + if the output is overloading. + + 6) The surround sound option will cause the sample to be played with + a central panning. This is because I don't know how to get hardware + surround without wasting a lot of memory and channels. + + 7) The panning positions are reduced to a scale of 0->15 in the GUS, + so fine alterations in the panning may go unnoticed. The Interwave + and AWE32 permit 256 pan positions + + + 3. Before you write to me. (Important notes) + + I would very much like to get feedback on this program, but I am already + aware of several problems (?). + + 1) If you're going to write because the program looks 'too' much like + Scream Tracker 3, then don't :) I've used Scream Tracker. I loved + using it - it was the best, easiest, most convenient program ever, + so why not adopt it's design????? + + 2) The program could easily crash if you try to load a corrupted + module. If you've got some modules that you know are corrupted, try + to resist the temptation of testing the stability of the program.... + in many cases it'll die :) + + 3) A couple of people have asked about ASCII characters > 128. I'm + sorry - I can't let you have 'em on anywhere else except the message + editor. The reason is because I've used a lot of the characters for + 'graphics' - real time character generation. (the ASCII characters > + 128 don't really exist anymore) + + 4) If you 'overload' your CPU... the subsequent playback can also + become distorted! To fix this, reinitialise your sound driver with + Ctrl-I. + + 5) The help screens have only been defined for the following screens: + a) Pattern Editor + b) Sample List + c) Instrument List + d) Info Page + e) Order list and panning + f) Order list and channel volumes + g) Message editor + + I didn't think it necessary to include help screens for the other + screens, but if you feel strongly about including help on certain + points/screens, then I suppose I could make the effort... + + 6) If you have a bug to report, please check through BUGS.TXT first to + see if it's listed, and also check through this document - the problem + may be in the understanding of how the program works! Otherwise, + contact me, AND LET ME KNOW WHAT VERSION YOU ARE USING! + + 7) Any further GUS click removal is very difficult to achieve. ST3's + GUS click removal requires double the number of channels on the GUS + to be used and I can't allocate any more! Try out the alternative + GUS drivers first + + 8) Got suggestions for IT? At the moment, I'm really sorry - I barely + have enough spare time myself. I can't promise to add any suggestions + you make, but please send them along anyway. + +You can contact me by writing to: + Jeffrey Lim + 9 Wilgena Avenue + Myrtle Bank + South Australia 5064 + +EMail account: + pulse@cyburbia.net.au + WARNING!!! + If you ask me anything which is obviously contained within this document or + the FAQ, I will reply with RTFM (Read the #$%@#$% Manual). Sorry, but I hate + idiots who can't be bothered to take their time to have a quick look through + this document and write to me with stupid messages which have recently become + a chore to answer (You'd understand if you received 4000+ EMails...) + BUT! + If there *is* something that you HAVE made an effort to understand/look for, + then don't hesistate to write to me. The worst that can happen is that I + reply with RTFM :) +********ALSO******** + If you have an incorrect reply-address, don't expect to receive anything. + If you are reporting a bug, let me know what version you are using. + + If you find any major problem with the tracker, please try to find the + circumstances which cause it to trigger - if you can't, don't worry - write + to me anyway. It's just that it's much easier if I know a likely cause of + the error. (Don't worry if it seems that the cause is very, very remote - + I had a problem in my GUS playback routines which originally caused my + palette configuration screen to hang - now that's obscure!) + + Send money! I don't demand that you send me anything, (and I don't like + spoiling a program by shoving in reminder messages), but if you *DO* use + the program and think that it's worth contributing a small amount towards, + then please do so... it would be GREATLY appreciated. Remember.... even a + few dollars will be appreciated! It's very unlikely that I'll make a huge + profit (I doubt I could get close to sufficient money from this program to + make it even worth $1 for every hour I put in!). I won't be sending out any + nice thankyou notes, or bound manuals... but I will include your names in + the future versions of the tracker and I will EMail you each new version the + minute the are released if you wish. + + I believe that software *SHOULD* be cheap - you've spent perhaps a few + thousand getting your computer, so you wouldn't want to spend TOO much + more on programs! If you think this program is worth $5, then send $5. + If you think it's worth $10, then send $10. If you think it's worth + $1,000,000,000... don't let me stop you :) + + So... get together with a couple of friends and send me $10... If you send + me a significant amount, I'll put together a "special contributor's" list.. + (Oeeerrrrr :) ) + + Methods of payment: + International Money Orders - (NOT postal orders though!) + Cash (Make sure it's securely wrapped!) - it doesn't have to be Australian + currency, although it'd be nice if it could be! + Bank Transfer - EMail me for my details + + + 4. Closing Words + + I would like to thank the following people: + + Psi: For introducing me to tracking with the brilliant Scream Tracker 3 + Purple Motion: For being my music hero.... I still think + "When the Heaven's Fall" is *THE* best S3M ever written. + Red Haze: For constantly bugging me to get the tracker done, and for + his effort in testing out the program and making suggestions. + (He's directly responsible for the inclusion of Ping Pong + loops - I originally couldn't be bothered :) ) + Also extensive testing of later versions of IT... + The WALKER: For his flow of ideas & beta testing and getting the PoP + DiskMag finished.... tomorrow. Or is that next week? + OK... so he has done it. Finally.... 6 months late. :) + Perception: For his constant support over the many years he ran his BBS + Psibelius: For being the nice friendly Epinicion founder that he is. + Dominic: For his thoroughness in beta testing the program, and providing + suggestions. (He came up with more than double the number of + suggestions than almost anyone else... even though many of + them were not finally implemented :) ) + Chris Jarvis: For his effort in beta testing the tracker and producing + Firestorm (released with v1.00 of the tracker) + Pale Dreams! (released with v1.01 of the tracker) + Firepower (released with v1.03 of the tracker) + Sidewalk (released with v1.05 of the tracker) and + Fallen World (released with v2.01 of the tracker) + These are ALL amazing pieces of work! (Yes, I'm jealous!) + Zilym Limms: For his technical help with the tracker and his love of + Fast Tracker 2. Hahaha. :) + Also for his information and source code for the PAS 16. + Benjamin Bruheim: For his super list of contributions to v1.01 + ZaStaR: For his effort in putting together ITF - the font customiser! + and ITTXT - the text file importer for IT's messages! + Also for being the willing target of a barrage of beta + versions, a great contributor of ideas, a musician with whom + I could exchange work and for being a great dude all round! + Emmanuel Giasson: For creating the utilities MMCMP/MMUNCMP/MMTSR - + the music module compressor! + Diablo: For creating the Impulse Tracker directories on ftp.cdrom.com! + Siren: For providing me a contact to obtain an Interwave card! + AMD: For providing me with an Interwave card to program for! + + To the other beta testers: + Eric Bonython Phorte + Alistair Watts Julian Ellis + Alex Bates David Rohrsheim + Delta X GD (Grave Digger) + Andy Chen ShawnM + Clef Emmanuel Giasson + KXMode + + And anybody there who uses this program!!! + + Big thanks and thumbs up to Advanced Gravis for releasing their + Software Developer's Kit (SDK) free of charge! + + Congratulations to Creative Labs for finally releasing their SDKs + free of charge! + + Especially *BIG* thanks to AMD for providing me with an Interwave + card to use and the SDK! + + Finally... I have a request..... + If *YOU* write something with this program... share it with the + rest of the world!!! + + If you have an iNet account, you can upload your songs to: + ftp.cdrom.com/pub/demos/incoming/music/songs/it + - remember to ZIP up your song, to use a *lower* case filename + and to also upload a short description of your song in a .txt + file, otherwise your file will just be deleted. + + If you know of any other places where modules can be uploaded to, + let me know and I'll include them in the above list. + + 5. How to get the latest version of Impulse Tracker + + There are several places around the internet where you can find the + latest version of Impulse Tracker: + + 1) ftp.cdrom.com/pub/demos/incoming/music/programs } Check (1) first! + 2) ftp.cdrom.com/pub/demos/music/programs/trackers } + + 3) http://www.noisemusic.org/it + - American Site + 4) http://www.maz-sound.com + - Music and Tracking Site + 5) http://www.unidev.com/~logic/music/it + - IT Resource Central + 6) http://www.musica.org/impulse + - Spanish Site + 7) http://www.mixbbs.demon.co.uk + - UK Site + + If you want to have the latest version sent to you via EMail, or at least + be notified of new releases, then you'll have to send $omething to me :) + Check section 3 on how to contact me. + + + 6. Legal stuff + + No matter what happens, no matter how bad, I'm not going to be held + responsible. + + That's basically the same as any other license agreement, except you + should be able to understand this one without an interpreter :) + + YOU MAY NOT CHARGE ANYTHING FOR THIS PROGRAM - DISTRIBUTORS WHO + ARE INTERESTED IN THIS PROGRAM MUST WRITE TO ME FIRST AND HAVE MY + APPROVAL! (yeah, even by snail mail if you don't have EMail access). + + USE OF THIS PROGRAM COMMERCIALLY IS EXPRESSLY FORBIDDEN WITHOUT WRITTEN + AND SIGNED APPROVAL FROM ME. COMMERCIAL USE INVOLVES ANY USE OF IMPULSE + TRACKER IN WHICH MONEY IS INVOLVED (SPECIFICALLY THE CREATION OF ANY + MUSIC WHERE PAYMENT IS INVOLVED). THIS PROGRAM IS ONLY FREEWARE FOR + NON-COMMERCIAL USE. diff --git a/it/ReleaseDocumentation/IT256.ICO b/it/ReleaseDocumentation/IT256.ICO new file mode 100644 index 0000000000000000000000000000000000000000..45db9b02eca16efb0f01faa10865f06864a35cce GIT binary patch literal 2998 zcmcK6F=!%77{Ku_=M|5ql2*P5z?z#UTMG-^JIXR?1u_ew)G`FlC!D zKWpPT^>uxpv-v5lk1I3mthCwJ`n74F-%ai${PK?kp_0K=Njp$d_mz}JN^FOHu4{K9 z(!3R^U5S(%BKe90GyE9e$9M1zd=+~}J;fj6kMK5rA5YxD0N=*f@g=;Cm9JF1-~}&u zsmKgJ#`p0Zd;?#_pYa_$#UJC3@HT!QAL6I@0Po{Rcn9y`yZ9!)hA-puc!gJZg;#im zSNN|S6OLPsD~<+7#rP0E#RqsFKf>$i4!VnOqHE|fI#2u=evI$qJNO2^ia*1j;*ar1 zcpJZuC+=W?Z{zFu65dY84!=P&{21TIckm5-)fRO|Hc!dsG1)vKn>N|p$A|bSKEV6< z5#GV`12F00oA?^OjL+-eIK09uyuvHIVm&;r36JZR$92WyYVf!!6_F4>#RqsFKf*is zgzY0U{21TIckm5-6`!zuh#SZN-^SPRCA^JKN>HF?_%XhZ@8HR_s&ZqS6BMWrKg9=l zA3wsAoP-1g{0$gT+tfO>M760&33_>Xk>}@Ud3=17hldBbzrUB8n;UT)N3O50rQ7Yw z<>jR`n@zd6xR6?{Cgv+?{^CT@wCHnDa86GfiPXTJF6W%{3%{qd-`#_I_5GdR*#hJZgl zUQe&*WHbwi+D}`IH@6VY?^8^yZN{5LFUPY2U$14G@vHeWIoR_4%>#($k8(&`el-7y zJ1ENkd;2FF?H|k9)5Y4O!4T74?jL=389t?VsZ2`;Hv5a!OS}oqXRmLfe$m352(y

128) All volumes are adjusted by this + MV: Mix volume (0->128) During mixing, this value controls + the magnitude of the wave being mixed. + IS: Initial Speed of song. + IT: Initial Tempo of song + Sep: Panning separation between channels (0->128, 128 is max sep.) + PWD: Pitch wheel depth for MIDI controllers + Chnl Vol: Volume for each channel. Ranges from 0->64 + Chnl Pan: Each byte contains a panning value for a channel. Ranges from + 0 (absolute left) to 64 (absolute right). 32 = central pan, + 100 = Surround sound. + +128 = disabled channel (notes will not be played, but note + that effects in muted channels are + still processed) + Orders: This is the order in which the patterns are played. + Valid values are from 0->199. + 255 = "---", End of song marker + 254 = "+++", Skip to next order + + + Old Impulse Instrument Format (cmwt < 200h) + + 0 1 2 3 4 5 6 7 8 9 A B C D E F + Ŀ +0000: 'I''M''P''I' DOS FileName (12345678.123) + Ĵ +0010: 00hFlgVLSVLESLSSLE x x FadeOutNNADNCTrkVersNoS x + Ĵ +0020: Instrument Name, max 26 bytes, includes NUL................... + Ĵ +0030: ....................................... x x x x x x + Ĵ +0040: Note-Sample/Keyboard Table, Length = 240 bytes................ + Ĵ + + Ĵ +0130: Volume envelope (200 bytes)................................... + Ĵ + + Ĵ +01F8: Node points (25x2 bytes)...... + + + Total length of old instrument header is 554 bytes. + + Flg: Bit 0. On = Use volume envelope + Bit 1. On = Use volume loop + Bit 2. On = Use sustain volume loop + VLS: Volume loop start (node number) + VLE: Volume loop end (node number) + SLS: Sustain loop start (node number) + SLE: Sustain loop end (node number) + FadeOut: Ranges between 0 and 64, but the fadeout "Count" is 512. + Fade applied when: + 1) Note fade NNA is selected and triggered (by another note) + 2) Note off NNA is selected with no volume envelope + or volume envelope loop + 3) Volume envelope end is reached + + DNC: Duplicate note check (0 = Off, 1 = On) + NNA: New note action: + 0 = Note cut + 1 = Note continue + 2 = Note off + 3 = Note fade + + TrkVers: Tracker version used to save the instrument. This is only + used in the instrument files. + NoS: Number of samples associated with instrument. This is only + used in the instrument files. + + Note-Sample/Keyboard Table. + Each note of the instrument is first converted to a sample number + and a note (C-0 -> B-9). These are stored as note/sample pairs + (note first, range 0->119 for C-0 to B-9, sample ranges from + 1-99, 0=no sample) + + Volume envelope: Values from 0->64, 0FFh indicating end of envelope. + (after which note fade applies) + + Node data: Tick THEN magnitude + + + + Impulse Instrument Format + + 0 1 2 3 4 5 6 7 8 9 A B C D E F + Ŀ +0000: 'I''M''P''I' DOS FileName (12345678.123) + Ĵ +0010: 00hNNADCTDCAFadeOutPPSPPCGbVDfPRV RP TrkVersNoS x + Ĵ +0020: Instrument Name, max 26 bytes, includes NUL................... + Ĵ +0030: .......................................IFCIFRMChMPrMIDIBnk + Ĵ +0040: Note-Sample/Keyboard Table, Length = 240 bytes................ + Ĵ + + Ĵ +0130: Envelopes..................................................... + Ĵ + + NNA = New Note Action + 0 = Cut 1 = Continue + 2 = Note off 3 = Note fade + + DCT = Duplicate Check Type + 0 = Off 1 = Note + 2 = Sample 3 = Instrument + + DCA: Duplicate Check Action + 0 = Cut + 1 = Note Off + 2 = Note fade + + FadeOut: Ranges between 0 and 128, but the fadeout "Count" is 1024 + See the Last section on how this works. + Fade applied when: + 1) Note fade NNA is selected and triggered (by another note) + 2) Note off NNA is selected with no volume envelope + or volume envelope loop + 3) Volume envelope end is reached + + PPS: Pitch-Pan separation, range -32 -> +32 + PPC: Pitch-Pan center: C-0 to B-9 represented as 0->119 inclusive + + GbV: Global Volume, 0->128 + DfP: Default Pan, 0->64, &128 => Don't use + RV: Random volume variation (percentage) + RP: Random panning variation (panning change - not implemented yet) + + MCh = MIDI Channel + MPr = MIDI Program (Instrument) + + TrkVers: Tracker version used to save the instrument. This is only + used in the instrument files. + NoS: Number of samples associated with instrument. This is only + used in the instrument files. + + Note-Sample/Keyboard Table. + Each note of the instrument is first converted to a sample number + and a note (C-0 -> B-9). These are stored as note/sample byte pairs + (note first, range 0->119 for C-0 to B-9, sample ranges from + 1-99, 0=no sample) + + Envelope layout + + Envelopes: 3 structures, first for volume (130h), second for + panning (182h), third for pitch (1D4h). + + Each is structured as such: + + 0 1 2 3 4 5 6....... + Ŀ +xxxx: FlgNumLpBLpESLBSLE Node points, 25 sets, 75 bytes.... x + Ĵ + + Flg: Bit 0: Envelope on/off, 1 = on, 0 = off + Bit 1: Loop on/off, 1 = on, 0 = off + Bit 2: SusLoop on/off, 1 = on, 0 = off + + Num = Number of node points + + LpB = Loop beginning SLB = Sustain loop beginning + LpE = Loop end SLE = Sustain loop end + + Node point = 1 byte for y-value + (0->64 for vol, -32->+32 for panning or pitch) + 1 word (2 bytes) for tick number (0->9999) + + Total length of an instrument is 547 bytes, but 554 bytes are + written, just to simplify the loading of the old format. (Hence + there are 7 'wasted' bytes per instrument) + + + + Impulse Sample Format + + 0 1 2 3 4 5 6 7 8 9 A B C D E F + Ŀ +0000: 'I''M''P''S' DOS Filename (12345678.123) + Ĵ +0010: 00hGvLFlgVol Sample Name, max 26 bytes, includes NUL....... + Ĵ +0020: .......................................................CvtDfP + Ĵ +0030: Length Loop Begin Loop End C5Speed + Ĵ +0040: SusLoop Begin SusLoop End SamplePointer ViSViDViRViT + + +The cache file has the following pieces of information added on: + + 0 1 2 3 4 5 6 7 8 9 A B C D E F + Ŀ +0050: File Size Date Time Fmt........................... + + + Fmt. 0 = unchecked. 1 = directory, 2 = it sample, 3 = st sample + + + GvL: Global volume for instrument, ranges from 0->64 + Flg: Bit 0. On = sample associated with header. + Bit 1. On = 16 bit, Off = 8 bit. + Bit 2. On = stereo, Off = mono. Stereo samples not supported yet + Bit 3. On = compressed samples. + Bit 4. On = Use loop + Bit 5. On = Use sustain loop + Bit 6. On = Ping Pong loop, Off = Forwards loop + Bit 7. On = Ping Pong Sustain loop, Off = Forwards Sustain loop + Vol: Default volume for instrument + + Length: Length of sample in no. of samples NOT no. of bytes + LoopBeg: Start of loop (no of samples in, not bytes) + Loop End: Sample no. AFTER end of loop + C5Speed: Number of bytes a second for C-5 (ranges from 0->9999999) + SusLBeg: Start of sustain loop + SusLEnd: Sample no. AFTER end of sustain loop + + SmpPoint: 'Long' Offset of sample in file. + + ViS: Vibrato Speed, ranges from 0->64 + ViD: Vibrato Depth, ranges from 0->64 + ViT: Vibrato waveform type. + 0=Sine wave + 1=Ramp down + 2=Square wave + 3=Random (speed is irrelevant) + ViR: Vibrato Rate, rate at which vibrato is applied (0->64) + + The depth of the vibrato at any point is worked out in the following + way: + Every processing cycle, the following occurs: + 1) Mov AX, [SomeVariableNameRelatingToVibrato] + 2) Add AL, Rate + 3) AdC AH, 0 + 4) AH contains the depth of the vibrato as a fine-linear slide. + 5) Mov [SomeVariableNameRelatingToVibrato], AX ; For the next + ; cycle. + + For those that don't understand assembly, then the depth is + basically the running-sum of the rate divided by 256. + + Sample vibrato uses a table 256-bytes long + + Convert - bits other than bit 0 are used internally for the loading + of alternative formats. + Bit 0: + Off: Samples are unsigned } IT 2.01 and below use unsigned samples + On: Samples are signed } IT 2.02 and above use signed samples + Bit 1: + Off: Intel lo-hi byte order for 16-bit samples } Safe to ignore + On: Motorola hi-lo byte order for 16-bit samples } these values... + Bit 2: } + Off: Samples are stored as PCM values } + On: Samples are stored as Delta values } + Bit 3: } + On: Samples are stored as byte delta values } + (for PTM loader) } + Bit 4: } + On: Samples are stored as TX-Wave 12-bit values } + Bit 5: } + On: Left/Right/All Stereo prompt } + Bit 6: Reserved + Bit 7: Reserved + + DfP - Default Pan. Bits 0->6 = Pan value, Bit 7 ON to USE (opposite of inst) + + + + Impulse Pattern Format + + 0 1 2 3 4 5 6 7 8 9 A B C D E F + Ŀ +0000: Length Rows x x x x Packed data................ + Ĵ + + Length: Length of packed pattern, not including the 8 byte header + Note that the pattern + the 8 byte header will ALWAYS + be less than 64k + Rows: Number of rows in this pattern (Ranges from 32->200) + + Patterns are unpacked by the following pseudocode... (this may look + horrible, but in practise, it's just as convenient as the S3M + pattern format for playback (but not for display)) + + GetNextChannelMarker: + Read byte into channelvariable. + if(channelvariable = 0) then end of row + Channel = (channelvariable-1) & 63 ; Channel is 0 based. + if(channelvariable & 128) then read byte into maskvariable + else maskvariable = previousmaskvariable for current channel + + if(maskvariable & 1), then read note. (byte value) + // Note ranges from 0->119 (C-0 -> B-9) + // 255 = note off, 254 = notecut + // Others = note fade (already programmed into IT's player + // but not available in the editor) + + if(maskvariable & 2), then read instrument (byte value) + // Instrument ranges from 1->99 + + if(maskvariable & 4), then read volume/panning (byte value) + // Volume ranges from 0->64 + // Panning ranges from 0->64, mapped onto 128->192 + // Prepare for the following also: + // 65->74 = Fine volume up + // 75->84 = Fine volume down + // 85->94 = Volume slide up + // 95->104 = Volume slide down + // 105->114 = Pitch Slide down + // 115->124 = Pitch Slide up + // 193->202 = Portamento to + // 203->212 = Vibrato + + Effects 65 is equivalent to D0F, 66 is equivalent to D1F -> 74 = D9F + Similarly for 75-84 (DFx), 85-94 (Dx0), 95->104 (D0x). + + (Fine) Volume up/down all share the same memory (NOT shared with Dxx + in the effect column tho). + + Pitch slide up/down affect E/F/(G)'s memory - a Pitch slide + up/down of x is equivalent to a normal slide by x*4 + + Portamento to (Gx) affects the memory for Gxx and has the equivalent + slide given by this table: + + SlideTable DB 1, 4, 8, 16, 32, 64, 96, 128, 255 + + Vibrato uses the same 'memory' as Hxx/Uxx. + + if(maskvariable & 8), then read command (byte value) and commandvalue + // Valid ranges from 0->31 (0=no effect, 1=A, 2=B, 3=C, etc.) + + if(maskvariable & 16), then note = lastnote for channel + if(maskvariable & 32), then instrument = lastinstrument for channel + if(maskvariable & 64), then volume/pan = lastvolume/pan for channel + if(maskvariable & 128), then { + command = lastcommand for channel and + commandvalue = lastcommandvalue for channel + } + Goto GetNextChannelMarker + + + + Mathematics + +Abbreviations: + FV = Final Volume (Ranges from 0 to 128). In versions 1.04+, mixed output + devices are reduced further to a range from 0 to 64 due to lack of + memory. + Vol = Volume at which note is to be played. (Ranges from 0 to 64) + SV = Sample Volume (Ranges from 0 to 64) + IV = Instrument Volume (Ranges from 0 to 128) + CV = Channel Volume (Ranges from 0 to 64) + GV = Global Volume (Ranges from 0 to 128) + VEV = Volume Envelope Value (Ranges from 0 to 64) + +In Sample mode, the following calculation is done: + FV = Vol * SV * CV * GV / 262144 ; Note that 262144 = 2^18 + ; So bit shifting can be done. + +In Instrument mode the following procedure is used: + + 1) Update volume envelope value. Check for loops / end of envelope. + 2) If end of volume envelope (ie. position >= 200 or VEV = 0FFh), then turn + on note fade. + 3) If notefade is on, then NoteFadeComponent (NFC) = NFC - FadeOut + ; NFC should be initialised to 1024 when a note is played. + 4) FV = Vol * SV * IV * CV * GV * VEV * NFC / 2^41 + +Linear slides work like this: + Final frequency = Original frequency * 2^(SlideValue/768) + +(I used a lookup table for the multipliers here) + +For command Exx, SlideValue = -4*EffectValue +For command EEx, SlideValue = -EffectValue +For command Fxx, SlideValue = 4*EffectValue +For command FEx, SlideValue = EffectValue + +Note that sample vibrato always uses Linear slides. + +Notes about effects (as compared to other module formats) + +C This is now in *HEX*. (Used to be in decimal in ST3) +E/F/G/H/U You need to check whether the song uses Amiga/Linear slides. +H/U Vibrato in Impulse Tracker is two times finer than in + any other tracker and is updated EVERY tick. + If "Old Effects" is *ON*, then the vibrato is played in the + normal manner (every non-row tick and normal depth) +E/F/G These commands ALL share the same memory. +Oxx Offsets to samples are to the 'xx00th' SAMPLE. (ie. for + 16 bit samples, the offset is xx00h*2) + Oxx past the sample end will be ignored, unless "Old Effects" + is ON, in which case the Oxx will play from the end of the + sample. +Yxy This uses a table 4 times larger (hence 4 times slower) than + vibrato or tremelo. If the waveform is set to random, then + the 'speed' part of the command is interpreted as a delay. + +If you read through this document and there are ANY points which you have +troubles with (and have to try out), then let me know - because someone +else will have the same questions - and I'd like to make this DOC as easy +to understand as possible. + +For Panning.... + Here's the rough procedure used: + + NotePan = ChannelPan + if InstrumentPan=On then NotePan = InstrumentPan + NotePan = NotePan+(InstrumentNote-PPCenter)*PPSeparation/8 + +Pitch Envelopes + Each value on the envelope equates to half a semitone. This is interpolated + 64 times for smooth pitch sliding. Positive values indicate a pitch variation + UP of x semitones, negative values indicate a pitch variation down. + + General Info + +The player in Impulse Tracker 'allocates' channels to notes whenever they +are *PLAYED*. In sample mode, the allocation is simple: + Virtual Channel (number) = 'Host' channel (number) + +In instrument mode, the following procedure is used: + + Check if channel is already playing ---Yes--> set 'background' flag on. + | 'Trigger' NNA. If NNA=cut, + No then use this virtual + | channel. + | | + |<------------------ else -----------------/ + | + v + Search and find the first non-active virtual channel. + | + Non-active channel found? ----Yes----> Use this for playback. + | + No + | + v + Search through and find the channel of lowest volume that is in the # + 'background' (ie. no longer controlled directly) # + | # + Background channel found? ----Yes----> Use this for playback. # + | # + No # + | # + v # + Return error - the note is *NOT* allocated a channel, and hence is not # + played. # + + This is actually quite a simple process... just that it's another of + those 'hassles' to have to write... + + ### Note: This is by far the simplest implementation of congestion + resolution. IT 2.03 and above have a greatly enhanced + method which more selectively removes the most insignificant + channel. Obviously, there is no best way to do this - I + encourage you to experiment and find new algorithms for + yourself. + + + + Internal Tables + +FineSineData Label Byte + DB 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23 + DB 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44 + DB 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59 + DB 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64 + DB 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60 + DB 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46 + DB 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26 + DB 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2 + DB 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23 + DB -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44 + DB -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59 + DB -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64 + DB -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60 + DB -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46 + DB -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26 + DB -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2 + +FineRampDownData Label Byte + DB 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 59, 58, 58, 57, 57, 56 + DB 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48 + DB 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40 + DB 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32 + DB 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24 + DB 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16 + DB 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8 + DB 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0 + DB 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8 + DB -8, -9, -9,-10,-10,-11,-11,-12,-12,-13,-13,-14,-14,-15,-15,-16 + DB -16,-17,-17,-18,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24 + DB -24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32 + DB -32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40 + DB -40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48 + DB -48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-56 + DB -56,-57,-57,-58,-58,-59,-59,-60,-60,-61,-61,-62,-62,-63,-63,-64 + +FineSquareWave Label Byte + DB 128 Dup (64), 128 Dup (0) + +EmptyPattern Label + DW 64, 64, 0, 0 + DB 64 Dup (0) + +; + +PitchTable Label DWord ; Values are 16.16 bit + DW 2048, 0, 2170, 0, 2299, 0, 2435, 0, 2580, 0, 2734, 0 ; C-0 + DW 2896, 0, 3069, 0, 3251, 0, 3444, 0, 3649, 0, 3866, 0 ;>B-0 + + DW 4096, 0, 4340, 0, 4598, 0, 4871, 0, 5161, 0, 5468, 0 ; C-1 + DW 5793, 0, 6137, 0, 6502, 0, 6889, 0, 7298, 0, 7732, 0 ;>B-1 + + DW 8192, 0, 8679, 0, 9195, 0, 9742, 0, 10321, 0, 10935, 0 + DW 11585, 0, 12274, 0, 13004, 0, 13777, 0, 14596, 0, 15464, 0 + + DW 16384, 0, 17358, 0, 18390, 0, 19484, 0, 20643, 0, 21870, 0 + DW 23170, 0, 24548, 0, 26008, 0, 27554, 0, 29193, 0, 30929, 0 + + DW 32768, 0, 34716, 0, 36781, 0, 38968, 0, 41285, 0, 43740, 0 + DW 46341, 0, 49097, 0, 52016, 0, 55109, 0, 58386, 0, 61858, 0 + + DW 0, 1, 3897, 1, 8026, 1, 12400, 1, 17034, 1, 21944, 1 + DW 27146, 1, 32657, 1, 38496, 1, 44682, 1, 51236, 1, 58179, 1 + + DW 0, 2, 7794, 2, 16051, 2, 24800, 2, 34068, 2, 43888, 2 + DW 54292, 2, 65314, 2, 11456, 3, 23828, 3, 36936, 3, 50823, 3 + + DW 0, 4, 15588, 4, 32103, 4, 49600, 4, 2601, 5, 22240, 5 + DW 43048, 5, 65092, 5, 22912, 6, 47656, 6, 8336, 7, 36110, 7 + + DW 0, 8, 31176, 8, 64205, 8, 33663, 9, 5201, 10, 44481, 10 + DW 20559, 11, 64648, 11, 45823, 12, 29776, 13, 16671, 14, 6684, 15 + + DW 0, 16, 62352, 16, 62875, 17, 1790, 19, 10403, 20, 23425, 21 + DW 41118, 22, 63761, 23, 26111, 25, 59552, 26, 33342, 28, 13368, 30 + +FineLinearSlideUpTable Label ; Values are 16.16 bit + DW 0, 1, 59, 1, 118, 1, 178, 1, 237, 1 ; 0->4 + DW 296, 1, 356, 1, 415, 1, 475, 1, 535, 1 ; 5->9 + DW 594, 1, 654, 1, 714, 1, 773, 1, 833, 1 ; 10->14 + DW 893, 1 ; 15 + +LinearSlideUpTable Label ; Value = 2^(Val/192), Values are 16.16 bit + DW 0, 1, 237, 1, 475, 1, 714, 1, 953, 1 ; 0->4 + DW 1194, 1, 1435, 1, 1677, 1, 1920, 1, 2164, 1 ; 5->9 + DW 2409, 1, 2655, 1, 2902, 1, 3149, 1, 3397, 1 ; 10->14 + DW 3647, 1, 3897, 1, 4148, 1, 4400, 1, 4653, 1 ; 15->19 + DW 4907, 1, 5157, 1, 5417, 1, 5674, 1, 5932, 1 ; 20->24 + DW 6190, 1, 6449, 1, 6710, 1, 6971, 1, 7233, 1 ; 25->29 + DW 7496, 1, 7761, 1, 8026, 1, 8292, 1, 8559, 1 ; 30->34 + DW 8027, 1, 9096, 1, 9366, 1, 9636, 1, 9908, 1 ; 35->39 + DW 10181, 1, 10455, 1, 10730, 1, 11006, 1, 11283,1 ; 40->44 + DW 11560, 1, 11839, 1, 12119, 1, 12400, 1, 12682,1 ; 45->49 + DW 12965, 1, 13249, 1, 13533, 1, 13819, 1, 14106,1 ; 50->54 + DW 14394, 1, 14684, 1, 14974, 1, 15265, 1, 15557,1 ; 55->59 + DW 15850, 1, 16145, 1, 16440, 1, 16737, 1, 17034,1 ; 60->64 + DW 17333, 1, 17633, 1, 17933, 1, 18235, 1, 18538,1 ; 65->69 + DW 18842, 1, 19147, 1, 19454, 1, 19761, 1, 20070,1 ; 70->74 + DW 20379, 1, 20690, 1, 21002, 1, 21315, 1, 21629,1 ; 75->79 + DW 21944, 1, 22260, 1, 22578, 1, 22897, 1, 23216,1 ; 80->84 + DW 23537, 1, 23860, 1, 24183, 1, 24507, 1, 24833,1 ; 85->89 + DW 25160, 1, 25488, 1, 25817, 1, 26148, 1, 26479,1 ; 90->94 + DW 26812, 1, 27146, 1, 27481, 1, 27818, 1, 28155,1 ; 95->99 + DW 28494, 1, 28834, 1, 29175, 1, 29518, 1, 29862,1 ; 100->104 + DW 30207, 1, 30553, 1, 30900, 1, 31248, 1, 31599,1 ; 105->109 + DW 31951, 1, 32303, 1, 32657, 1, 33012, 1, 33369,1 ; 110->114 + DW 33726, 1, 34085, 1, 34446, 1, 34807, 1, 35170,1 ; 115->119 + DW 35534, 1, 35900, 1, 36267, 1, 36635, 1, 37004,1 ; 120->124 + DW 37375, 1, 37747, 1, 38121, 1, 38496, 1, 38872,1 ; 125->129 + DW 39250, 1, 39629, 1, 40009, 1, 40391, 1, 40774,1 ; 130->134 + DW 41158, 1, 41544, 1, 41932, 1, 42320, 1, 42710,1 ; 135->139 + DW 43102, 1, 43495, 1, 43889, 1, 44285, 1, 44682,1 ; 140->144 + DW 45081, 1, 45481, 1, 45882, 1, 46285, 1, 46690,1 ; 145->149 + DW 47095, 1, 47503, 1, 47917, 1, 48322, 1, 48734,1 ; 150->154 + DW 49147, 1, 49562, 1, 49978, 1, 50396, 1, 50815,1 ; 155->159 + DW 51236, 1, 51658, 1, 52082, 1, 52507, 1, 52934,1 ; 160->164 + DW 53363, 1, 53793, 1, 54224, 1, 54658, 1, 55092,1 ; 165->169 + DW 55529, 1, 55966, 1, 56406, 1, 56847, 1, 57289,1 ; 170->174 + DW 57734, 1, 58179, 1, 58627, 1, 59076, 1, 59527,1 ; 175->179 + DW 59979, 1, 60433, 1, 60889, 1, 61346, 1, 61805,1 ; 180->184 + DW 62265, 1, 62727, 1, 63191, 1, 63657, 1, 64124,1 ; 185->189 + DW 64593, 1, 65064, 1, 0, 2, 474, 2, 950, 2 ; 190->194 + DW 1427, 2, 1906, 2, 2387, 2, 2870, 2, 3355, 2 ; 195->199 + DW 3841, 2, 4327, 2, 4818, 2, 5310, 2, 5803, 2 ; 200->204 + DW 6298, 2, 6795, 2, 7294, 2, 7794, 2, 8296, 2 ; 205->209 + DW 8800, 2, 9306, 2, 9814, 2, 10323, 2, 10835,2 ; 210->214 + DW 11348, 2, 11863, 2, 12380, 2, 12899, 2, 13419,2 ; 215->219 + DW 13942, 2, 14467, 2, 14993, 2, 15521, 2, 16051,2 ; 220->224 + DW 16583, 2, 17117, 2, 17653, 2, 18191, 2, 18731,2 ; 225->229 + DW 19273, 2, 19817, 2, 20362, 2, 20910, 2, 21460,2 ; 230->234 + DW 22011, 2, 22565, 2, 23121, 2, 23678, 2, 24238,2 ; 235->239 + DW 24800, 2, 25363, 2, 25929, 2, 25497, 2, 27067,2 ; 240->244 + DW 27639, 2, 28213, 2, 28789, 2, 29367, 2, 29947,2 ; 245->249 + DW 30530, 2, 31114, 2, 31701, 2, 32289, 2, 32880, 2 ; 250->254 + DW 33473, 2, 34068, 2 ; 255->256 + +FineLinearSlideDownTable Label ; Values are 0.16 bit + DW 65535, 65477, 65418, 65359, 65300, 65241, 65182, 65359 ; 0->7 + DW 65065, 65006, 64947, 64888, 64830, 64772, 64713, 64645 ; 8->15 + +LinearSlideDownTable Label ; Values are 0.16 bit + DW 65535, 65300, 65065, 64830, 64596, 64364, 64132, 63901 ; 0->7 + DW 63670, 63441, 63212, 62984, 62757, 62531, 62306, 62081 ; 8->15 + DW 61858, 61635, 61413, 61191, 60971, 60751, 60532, 60314 ; 16->23 + DW 60097, 59880, 59664, 59449, 59235, 59022, 58809, 58597 ; 24->31 + DW 58386, 58176, 57966, 57757, 57549, 57341, 57135, 56929 ; 32->39 + DW 56724, 56519, 56316, 56113, 55911, 55709, 55508, 55308 ; 40->47 + DW 55109, 54910, 54713, 54515, 54319, 54123, 53928, 53734 ; 48->55 + DW 53540, 53347, 53155, 52963, 52773, 52582, 52393, 52204 ; 56->63 + DW 52016, 51829, 51642, 51456, 51270, 51085, 50901, 50718 ; 64->71 + DW 50535, 50353, 50172, 49991, 49811, 49631, 49452, 49274 ; 72->79 + DW 49097, 48920, 48743, 48568, 48393, 48128, 48044, 47871 ; 80->87 + DW 47699, 47527, 47356, 47185, 47015, 46846, 46677, 46509 ; 88->95 + DW 46341, 46174, 46008, 45842, 45677, 45512, 45348, 45185 ; 96->103 + DW 45022, 44859, 44698, 44537, 44376, 44216, 44057, 43898 ;104->111 + DW 43740, 43582, 43425, 43269, 43113, 42958, 42803, 42649 ;112->119 + DW 42495, 42342, 42189, 42037, 41886, 41735, 41584, 41434 ;120->127 + DW 41285, 41136, 40988, 40840, 40639, 40566, 40400, 40253 ;128->135 + DW 40110, 39965, 39821, 39678, 39535, 39392, 39250, 39109 ;136->143 + DW 38968, 38828, 38688, 38548, 38409, 38271, 38133, 37996 ;144->151 + DW 37859, 37722, 37586, 37451, 37316, 37181, 37047, 36914 ;152->159 + DW 36781, 36648, 36516, 36385, 36254, 36123, 35993, 35863 ;160->167 + DW 35734, 35605, 35477, 35349, 35221, 35095, 34968, 34842 ;168->175 + DW 34716, 34591, 34467, 34343, 34219, 34095, 33973, 33850 ;176->183 + DW 33728, 33607, 33486, 33365, 33245, 33125, 33005, 32887 ;184->191 + DW 32768, 32650, 32532, 32415, 32298, 32182, 32066, 31950 ;192->199 + DW 31835, 31720, 31606, 31492, 31379, 31266, 31153, 31041 ;200->207 + DW 30929, 30817, 30706, 30596, 30485, 30376, 30226, 30157 ;208->215 + DW 30048, 29940, 29832, 29725, 29618, 29511, 29405, 29299 ;216->223 + DW 29193, 29088, 28983, 28879, 28774, 28671, 28567, 28464 ;224->231 + DW 28362, 28260, 28158, 28056, 27955, 27855, 27754, 27654 ;232->239 + DW 27554, 27455, 27356, 27258, 27159, 27062, 26964, 26867 ;240->247 + DW 26770, 26674, 26577, 26482, 26386, 26291, 26196, 26102 ;248->255 + DW 26008 ; 256 + +; + + Effect Info + +Here's about all the info I can think of for effects. "Process" variables are +variables used internally by effects to control the direction of playback.. +This section has not been completed yet. + +First, here is the rough flow chart for processing information, it's not fully +detailed, but all of the important steps are outlined. + + Ŀ + Set note volume to volume set for each channel + Set note frequency to frequency set for each channel + + + Ŀ + Decrease tick counter Yes + Is tick counter 0 ? Ŀ + + + No Ŀ + Ŀ Tick counter = Tick counter set + Update effects for each (the current 'speed') + channel as required. Decrease Row counter. + Is row counter 0? + + No + Yes + + Ŀ Ŀ + Call update-effects for Row counter = 1 + each channel. + Increase ProcessRow + Is ProcessRow > NumberOfRows? + + Yes No + Ŀ + ProcessRow = BreakRow + BreakRow = 0 + Increase ProcessOrder + while Order[ProcessOrder] = 0xFEh, + increase ProcessOrder + if Order[ProcessOrder] = 0xFFh, + ProcessOrder = 0 + CurrentPattern = Order[ProcessOrder] + + + + + Ŀ + CurrentRow = ProcessRow + Update Pattern Variables (includes jumping to + the appropriate row if requried and getting + the NumberOfRows for the pattern) + + + + + Ŀ Yes Ŀ + Instrument mode? Ĵ Update Envelopes as required + Update fadeout as required + Calculate final volume if req + No (Sample mode) Calculate final pan if req + Process sample vibrato if req + Ŀ + Calculate final volume if required + Calculate final pan if requried + Process sample vibrato if required + + + + + + Ŀ + Output sound!!! + + +Axx Set Tempo + + if (xx != 0) { + Maxtick = xx; + Currenttick = xx; + } + +Bxx Jump to Order + + ProcessOrder = xx - 1; + ProcessRow = 0xFFFE; // indicates new pattern internally for IT... + +Cxx Break to Row + + BreakRow = xx; + ProcessRow = 0xFFFE; + +Dxx Volume slide down + + if (xx == 0) then xx = last xx for (Dxx/Kxx/Lxx) for this channel. + + Order of testing: Dx0, D0x, DxF, DFx + +Dx0 Set effect update for channel enabled if channel is ON. + If x = F, then slide up volume by 15 straight away also (for S3M compat) + Every update, add x to the volume, check and clip values > 64 to 64 +D0x Set effect update for channel enabled if channel is ON. + If x = F, then slide down volume by 15 straight away also (for S3M) + Every update, subtract x from the volume, check and clip values < 0 to 0 +DxF Add x to volume straight away. Check and clip values > 64 to 64 +DFx Subtract x from volume straight away. Check and clip values < 0 to 0 + +Hxy Vibrato + + if (x != 0) { + speed = 4*x; + } + if (y != 0) { + depth = y * 4; + if(OldEffects) depth <<= 1; + } + Set effect update for channel enabled if channel is ON. + Goto InitVibrato (explained later) + +Ixy Tremor, ontime x, offtime y + + if (x != 0) { + ontime = x; + if (oldeffects) ontime++; + } + if (y != 0) { + offtime = y; + if (oldeffects) offtime++; + } + +Nxx Channel volume slide down + + if (xx == 0) then xx = last Nxx for this channel. + + Order of testing: Nx0, N0x, NxF, NFx + +Nx0 Set effect update for channel enabled. + Every update, add x to the volume, check and clip values > 64 to 64 +N0x Set effect update for channel enabled. + Every update, subtract x from the volume, check and clip values < 0 to 0 +NxF Add x to volume straight away. Check and clip values > 64 to 64 +NFx Subtract x from volume straight away. Check and clip values < 0 to 0 + +Uxy Fine Vibrato + + if (x != 0) { + speed = 4*x; + } + if (y != 0) { + depth = y; + if(OldEffects) depth <<= 1; + } + Set effect update for channel enabled if channel is ON. + Goto InitVibrato (explained later) + +Wxx Global volume slide down + + if (xx == 0) then xx = last Wxx for this channel. + + Order of testing: Wx0, W0x, WxF, WFx + +Wx0 Set effect update for channel enabled. + Every update, add x to the volume, check and clip values > 128 to 128 +W0x Set effect update for channel enabled. + Every update, subtract x from the volume, check and clip values < 0 to 0 +WxF Add x to volume straight away. Check and clip values > 128 to 128 +WFx Subtract x from volume straight away. Check and clip values < 0 to 0 + +.. sorry this is incomplete.. diff --git a/it/ReleaseDocumentation/ITVSOUND.TXT b/it/ReleaseDocumentation/ITVSOUND.TXT new file mode 100644 index 0000000..ac4ae57 --- /dev/null +++ b/it/ReleaseDocumentation/ITVSOUND.TXT @@ -0,0 +1,70 @@ + +What is VSound? +--------------- +VSound is a virtual sound driver for Impulse Tracker. It actually uses +Microsoft's DirectSound to provide output on ANY soundcard supported by +Windows '95 or Windows '98. It does NOT support Windows NT. + +It does take a little effort to setup and doesn't perform quite as well +as the native drivers, so if you have a SB16, ESS or some other card +directly supported by IT, don't bother messing around VSound. If you have +a SBPro compatible card, some PCI card or anything else that isn't being +used to its maximum capabilities, then give these files a try. + +How to use these files +---------------------- +You MUST have DirectX installed. It was written with the DirectX6 SDK, +although I'm pretty sure DirectSound 5 is sufficient. + +1. Copy ITVSOUND.VXD into your Windows\System directory + (normally C:\WINDOWS\SYSTEM) + + Note that the file may NOT show up in Window's Explorer since they have + a system extension (.VXD). Use DOS, or enable (unhide) system files in + your Explorer configuration. + +2. In your Windows directory (normally C:\WINDOWS), edit your SYSTEM.INI file + and include the line: + device=itvsound.vxd + anywhere in the [386Enh] section + +3. Reboot your computer + +4. Run Server.EXE + +5. Run "IT" + +Configuring the driver +---------------------- +The driver can be configured by modifying Window's Registry by running +"regedit" (which comes with Windows). The variables can be found at: + "KHEY_LOCAL_MACHINE\Software\Jeffrey Lim\Impulse Tracker VSound Server" + +The 4 variables are: + BufferSize - The size of the DirectSound buffer in kb. + Permitted ranges from 4 to 64, default 24 + BufferThreshold - The size of the buffer that IT tries to maintain in kb. + Permitted ranges from 2 to 32, default 21 + BufferType - 0 = DualBuffer (BufferSize is logically split into 2 sections) + 1 = QuadBuffer (BufferSize is logically split into 4 sections) + 2 = OctBuffer (BufferSize is logically split into 8 sections) + (recommended, default) + MixSpeed - Mixing rate to be used in Hz. + Permitted ranges from 11025 to 64000, default 44100 + +You will need to restart the server before these changes take effect. + +Known Problems +-------------- +1. This driver only works with Win95 and Win98, NOT WinNT (I'll try a WinNT + driver sometime). + +2. There is an obvious latency due to the size of the buffers and the delay + that is inherent to DirectSound. Reducing the BufferSize and BufferThreshold + values can reduce this latency, however, smaller values can also cause the + sound to break up. + + Try using the values: + 1. BufferSize=16, BufferThreshold=14, BufferType=2, MixSpeed=44100 + + diff --git a/it/ReleaseDocumentation/MIDI.TXT b/it/ReleaseDocumentation/MIDI.TXT new file mode 100644 index 0000000..77c5562 --- /dev/null +++ b/it/ReleaseDocumentation/MIDI.TXT @@ -0,0 +1,400 @@ + +------------------------------------- +## Impulse Tracker MIDI Supplement ## +------------------------------------- + +Introduction +============ + +The biggest new addition to Impulse Tracker 2.12 has been support for +sending data out through the MIDI protocol. Earlier versions of Impulse +Tracker (IT) have had support for incoming MIDI data, so it was possible to +play on a 'MIDIfied' keyboard and have IT 'track' all the notes down in the +pattern in realtime. + +MIDI out, however, is a completely different ballgame. You in fact don't +have to read this supplement at all if you wish to get MIDI working, but in +order to gain full usage of MIDI out, you will have to read this in order +to understand how IT's MIDI support fully works + + +MIDI Support & Soundcards (Modified by Pulse) +============================================= + +At present, the only sound devices IT supports for MIDI output are the AMD +InterWave and the Creative Labs Sound Blaster AWE32. Support for other +soundcards is via the generic MPU401 driver. To use this driver, you must +run "IT /S19 /A

" where
is the address of your MPU401 +compatible card (eg. "IT /S19 /A330"). Note that the generic MPU401 driver +does *NOT* support sample playback at all. + +MIDI And AWE32 Soundcards (Pulse) +--------------------------------- + +I have found that the Windows '95 drivers for the AWE32 are somewhat buggy. +On my computer, I can use MIDI In/Out in Impulse Tracker *IF* I disable the +MIDI support within Windows '95. Otherwise, it is simply not recognised. To +disable the MIDI support in Windows '95, right click on "My Computer", +"Properties", "Device Configuration", "Sound, Video & Game Controllers". +Double click on "Creative Labs SB16 or AWE32" and go to the resources. +Uncheck the "Use Automatic Settings" box if it is set and change the basic +configuration to one that does NOT include the MIDI Ports 300h or 330h. +(For example, Basic Configuration 0 has only 220h, 5, 1, 5 on my computer + and IT works fine in a DOS Box) + + +Enabling MIDI +============= + +To enable MIDI output, you must first have IT on Instrument control mode +rather than Sample control mode. To do this, press F12 to go to the Song +Variables screen and switch control to 'Instruments' if you haven't already +done so. + + +MIDI & Instruments +================== + +MIDI Channel +------------ + +New to the Pitch section of the Instrument screen (press F4 and select the +"Pitch" button) are the sliders "MIDI Channel", "MIDI Program" and "MIDI +Bank". Once the MIDI Channel value for that instrument is set to a value +other than zero, IT will send out MIDI data whenever that instrument is +encountered in a pattern, on that particular MIDI Channel. What data IT +actually sends through the MIDI port will be a note on command, although +this will be discussed in more detail later. + +MIDI Program/MIDI Bank +---------------------- + +The MIDI Program and MIDI Bank sliders work in a similar manner to each +other. If they have a value set to -1, IT will not transmit a program change +message nor a bank change message for that instrument. If you specifically +set a MIDI Program for that instrument, IT will send a 'program change' +message along with the 'note on' message. + +The MIDI Bank instrument setting is also the same; IT will not send a bank +change message if the MIDI Bank slider is set to Off (ie: has a value of +-01). If the MIDI Bank setting is active for that instrument, IT will send +it along with the note on message as well. + +Summary +------- + +IT will always send a 'note on' command for a particular MIDI channel +whenever a MIDI instrument is encountered in the pattern. (A MIDI instrument +is simply an instrument where the MIDI Channel value has been set to +something other than "Off"). IT will also send a program change command and/or +a bank change command along with the note on command if they are set active. + + +More Advanced MIDI +================== + +How MIDI Works +-------------- + +MIDI is not a file format (like IT is a module format) nor is it even a file +layout. MIDI is a computer protocol (or language) which is used to +communicate between devices . You may like to think of it as a network, +where the MIDI cables are the cables you lay between computers, and MIDI is +the network protocol (such as Novell NetWare, Windows Networking or TCP/IP) +used to communicate between the sound devices. When an instrument is said to +be 'MIDI compliant', that means that it has support for the MIDI protocol +and understands MIDI messages. + +The .MID file format is simply a way to store these messages. It is a +collection of MIDI data, and when a .MID file is run through a MIDI player, +all the MIDI player does is send the data in the .MID file out through the +computer's MIDI port. In a network analogy, if you can imagine that every +single transaction run through the network was being logged to a file on +your hard disk; that every single byte was being recorded to a logfile, this +is what a .MID file is. + +An example of MIDI Communication in IT +-------------------------------------- + +You've read above that when IT encounters a MIDI instrument in the +patterndata, it sends a 'note on' command, which is defined in the MIDI +protocol to be 'Play this note on this MIDI channel at this particular +velocity'. (Velocity is similar to volume ). If you play a MIDI instrument +which is mapped to MIDI channel 2 at C-5 with a velocity of 64, the actual +data which IT sends out to the MIDI port resembles something like this (in +hex): + + Note On with parameters; + MIDI Channel: 2 + Note: C-5 + Velocity: 64 + + Data that IT sends out (hex): 91 3C 40 + Data that IT sends out (decimal): 145 60 64 + +We'll run through each of these three bytes step by step. + +The first byte (91 in hex, or 91h) is the actual 'Note on' command. It tells +the receiving MIDI device that the data which follows is part of the 'note +on' data. An analogy which trackers may find useful is the effect column. +There, you have an effect command and effect data; for example, the effect +'G20' can be split up into two parts--'G' and '20'. The 'G' part is the +actual effect command which tells IT that you wish to perform a portamento, +and the '20' part is the effect data, or in this case the spe ed at which +the portamento should occur. In this MIDI example, the '9' is the MIDI +command and the '1 3C 40' is the rest of the data for that command. + +Now, the second digit (1 in our example) specifies the MIDI channel. MIDI +channels are 0-based; that is, if you want to send to MIDI channel 6, IT +specifies 05 for the actual data. MIDI channel 10 is 09h, MIDI channel 14 is +0Dh, etc. Here we're sending to MIDI channel 2, so the value sent out over +MIDI is 01h. + +The second byte (3Ch) is actually the note to send (C-5 here). In MIDI, all +command (parameter) data is between a scale of 00h-7Fh (or 0-127 in +decimal). Notes are transmitted the same way - via numbers. If you imagine +C-1 is sent with a value of 00h, C#1 i s 01h, D-2 is 02h, etc, then the note +we want to play, C-5, has a value of 3Ch (60 decimal). + +Now the first and second bytes are done with, the third byte should be +fairly easy to understand. This byte represents the velocity at which the +note should be played. In our case, we want a velocity of 64, which +translates to 40h, and so this is the value which is sent out. + +So to recap, we have three bytes for the note on command, "91 3C 40". + + Byte 1: 91 == Note on command (on MIDI channel #2) + Byte 2: 3C == Note on data (Note to play, C-5) + Byte 3: 40 == Note on data (Velocity of 64 decimal) + +Configuring IT's MIDI out data +------------------------------ + +Keeping the above example in mind, press Shift-F1 to get to IT's MIDI screen +and press the 'MIDI Output Configuration' button. This will take you to IT's +MIDI out engine. Now, if you examine the 'Note On' field, it reads: + + 9c n v + +This can be correlated to our above example of '91 3C 40'. Now, the 'c n v' +in the Note On field corresponds to 'channel', 'note' and 'velocity'. Think +of them as variables; IT will substitute the appropriate channel, note and +velocity values which it encounters in the MIDI instrument information +and/or patterndata. + +If you now actually defined a MIDI instrument to play on MIDI channel 2, and +you played it in a pattern at C-5 with velocity 64, all IT does is read the +'Note On' field from the MIDI configuration screen and substitute '1' for +'c', '3C' (C-5) for 'n' and '64' for 'v'. Therefore, IT will read '9c n v' +and replace it with '91 3C 40'. + +In any of the MIDI output fields, lowercase letters represent variables (or +subsitutions which IT should make) and uppercase letters or numbers are +constants which IT writes to the MIDI port directly without any change. +Therefore, these fields are case se nsitive--for the note on command, '9c n +v' is blatantly different to '9C n v'. 9c represents 'send byte 09 followed +by the MIDI channel byte', whereas 9C represents 'send the byte 9C'. + +In short, 0-9 and A-F are treated as hexadecimal constants and will be +passed through directly. Lowercase letters will be treated as variables and +substituted accordingly. Note that variables are regarded as 'full bytes' by +themselves and are never part of an actual byte sequence except for the +variable 'c', so '9n' is exactly the same as '09 n' or '9 n'; all of them +will expand to the sequence '09 '. 'c' is the only value +that takes on a nibble (4-byte) value, due to the MIDI protocol definition. +This means that 9c will actually become one byte when expanded, with the +lower digit representing the channel. + +IT MIDI Variables +----------------- + +c: MIDI channel + + This is simply the MIDI channel of which the instrument is set + to, 0-based. Note that this is the only nibble sized variable. + +m: note value (instrument) + A value from 00-7Fh representing the note to be played, where + C-5 is 60h. This is the note entered in the pattern, not the + translated value. + +n: note value (sample) + + A value from 00-7Fh representing the note to be played, where + C-5 is 60h. This is the note after instrument translations have + been applied. + +o: Offset value + + Extra parameter than can be sent via Oxx commands. + +v: velocity + + The MIDI velocity of the note. + +u: volume + + Volume is similar to velocity, except that velocity does not + take the volume envelope and fadeout values into account, whereas the + 'u' volume variable does. + +x: pan set + + Sends a MIDI panning value. This does not take into account +panning envelopes. + +y: calculated pan + + Sends a MIDI panning value which does take into account +panning envelopes. + +a: high byte of bank select +b: low byte of bank select + + These commands are only really useful in the bank change +field. + +z: macro data + + (See section on macros for full explanation). + +Configuring MIDI Output for Your Keyboard +----------------------------------------- + +In the basic IT distribution, the only fields which have any data are 'Note +on', 'Note Off' and 'Program Change'. The reason for this is that these are +the only commands which are set as standards by MIDI. MIDI commands such as +Change Pan, Bank Select , e tc all differ from synth to synth. There's not +much which can be done to solve this, you will have to look up your synth's +manual to find out the exact MIDI commands it needs to issue a panning +change, bank select, etc. + +Some values which you may wish to try, however, will be: + + Change pan: Bc 0A x + Bank select: Bc 0 a 20 b + +These may or may not work. If they do, then great, but if they don't, you +will have to actually RTFM *gasp* in order to get these other commands +working. + + +Effect Commands & Macros +======================== + +Now that IT's MIDI engine is understood and the basis of MIDI communication +has been laid down, perhaps the most powerful function of IT's MIDI engine, +macros, will be explained. + +Standard Effects +---------------- + +Firstly, at the moment there is NO support for standard IT effect commands +(such as pitch slide, portamento, vibrato etc) to work via MIDI. This may or +may not be implemented in future. Currently, however, if you perform an E01 +effect on a note, nothing w ill happen as far as the MIDI aspect of the +instrument is concerned. + +Macro Effects - SFx +------------------- + +The SFx command, previously used in the .MOD format as "FunkRepeat", has +been changed in IT to allow for the functioning of MIDI macros. The unused +Zxx command will also now play a part in MIDI functioning. + +To understand how this works, it's best to take an example into account. At +the beginning of this supplement, the MIDI sequence '91 3C 40' was used +which was a Note On, MIDI channel #2 played at C-5 with a velocity of 64. +This was represented in IT's MIDI configuration as '9c n v', so it made the +appropriate substitutions to '91 3C 40'. + +The Macro Setup section of IT's MIDI Output Configuration screen can be used +to define your own custom MIDI command/data sequences. These can be +absolutely anything you like, from a MIDI SysEx command to a Note On +command. In fact, to start off, we'll tak e a Note On sequence as an example +and we will attempt to emulate the same '91 3C 40' bytes, except that we'll +make this sequence ourselves rather than letting IT do the work for us. + +How SFx and Zxx commands relate +------------------------------- + +Firstly, remember that IT substitutes values when it encounters variables. +If you glance at the above section on IT MIDI Variables, you'll notice that +the 'z' variable represents macro data. Now that this '91 3C 40' sequence +has been driven into our he ads, try setting the SF0 macro field on IT's +MIDI Output Configuration screen to '91 3C z'. + +Remember that the third byte in the MIDI sequence (40 in our normal +example) is the velocity to send with the Note On message. The SF0 macro +field you've just defined means that IT will read any Zxx effects and +replace the 'z' variable in the SF0 macro with the 'xx' value from the Zxx +effect. To enable the macro, simply put in a SF0 along with a Note On in the +pattern data. Now, all values from Z00 to Z7F will substitute for 'z' +accordingly. So, to show that our SF0 sequence will reproduce the exact same +thing as our Note On command: + + C-5 01 SF0 (this will play the note on command as usual, and + specify that the SF0 macro sequence should be + hooked to Zxx effects). + ... .. ... + ... .. ... + ... .. ... + ... .. Z40 (this will trigger our SF0 sequence with a 'z' + value of 40h). + +The above patterndata should produce a note on event at row 0 in the +pattern, and again at row 4. Now, try replacing the Z40 effect with Z7F and +IT will substitute 'z' with '7F', or a velocity of 7Fh (127 decimal) in our +SF0 sequence. The result should be that you'll hear a Note On with velocity +64 on row 0, and a Note On with velocity 127 on row 4; ie: the second note +triggered will be twice as loud. The The sequence that IT will send will be +'91 3C 7F'. + +SFx commands summary +-------------------- + +Our example above of using a 'note on' command sequence for an SFx effect is +rather pointless, since IT does this effect itself. However, it has +hopefully served its purpose by demonstrating how effects work. + +The SFx commands, as you can see, can be redefined to absolutely any MIDI +data at all. This can be something simple like a pitch slide, a complex +SysEx 'set filter to aftertouch' command, or whatever you like. The +possibilities are endless and are only li mited by what your synth can do; +IT's SFx/Zxx combination is customisable enough to handle nearly any MIDI +data you wish to output. + +If you wish to take advantage of these commands, you will have to look up +the manual for your synth and get stuck into the MIDI/SysEx section. Please +do not come to any IT support people asking for help on this subject because +every synth is different. + +Z80 -> ZFF commands +------------------- + +The Z80 to ZFF commands are also macro sequences, but they have no 'z' +variable to substitute for. They are not 'hooked' to any SFx effects, they +are straight, direct macro sequences. For example, if you have a MIDI +controllable effects unit (such as an Alesis MidiVerb), you may wish to +assign the Z80 command to set a up a certain value for the reverb delay +length. Later in the song, you can issue a Z81 command to change the reverb +delay or turn it off altogether. + +To summarise, the Z80 to ZFF commands are similar to SFx macro sequences, +but they do not have any extra parameters (whereas the SFx macro's 'z' +variables are controlled by Z00 to Z7F). + + +Contact Information +=================== + +If there are any problems with this textfile, email ozone@post1.com or +pulse@cyburbia.net.au + + __/\___/\_/\____/\____/\ .. . Andre Pang % vault ...: + + / /__ / \_ \_ __) :.. mailto:ozone@post1.com . ....: +( : / (__: ) | | _)_ : . http://www.mindflux.com.au/ .: + \___( ______/|__;__|_____| :. irc: #trax (irc.neato.org) ..: + \/ - #ozone + diff --git a/it/ReleaseDocumentation/NETWORK.TXT b/it/ReleaseDocumentation/NETWORK.TXT new file mode 100644 index 0000000..9660d11 --- /dev/null +++ b/it/ReleaseDocumentation/NETWORK.TXT @@ -0,0 +1,71 @@ + + + Networked Impulse Tracker + + +What is Networked Impulse Tracker? +---------------------------------- + +Networked Impulse Tracker is simply that - a session of Impulse Tracker where +multiple composers can all edit the same song at the same time! It may sound +a little bizarre, but networked sessions can be both extremely fun and +productive. + + +Requirements +------------ + + 1. Impulse Tracker, 7 Apr 99 or later + + 2. Impulse Tracker Network driver file. (*.NET) + + 3. Some form of network supported by the network driver file. + +To Use +------ +To initiate a Network session, Press Shift-ESC. A list of available drivers +will be shown. Select one with Enter. + + +ITIPX.NET +--------- + +ITIPX.NET is an IPX Network driver for Impulse Tracker. It is recommended that +this is used over a LAN (ie. you will need a network card in your computer). +Although Kali will work (IPX over the internet), performance will probably be +unacceptable for most people through a modem. + +The IPX driver *will not be stable* under Win95. Upgrade to Win98. +To install IPX to run under Windows, go to Start Menu->Settings->Control Panel. +Select Network, and under the Configuration Tab, press Add, then select + Protocol->Microsoft->IPX/SPX Compatible Protocol + +The IPX driver will list the available sessions in the left hand box. Select +a session to join by pressing Enter. + +The Username that the IPX driver transmits is associated with each driver file. +The public distribution identifies itself as "Unregistered". Different +usernames are availble for US$10 each. Payment can be made via Kagi at +http://order.kagi.com/?4ZM + +Please specify a username, maximum length 15 characters, or else one will be +chosen for you. Updated versions of the driver, if made, will be provided free +of charge. However, changing your username will still cost $10. + +'Normal' usage of this driver should run quite stably. However, if you try hard +to make it crash, I'm sure you will be able to. + +Note that connections will be automatically dropped if queued packets fail to +be transmitted for more than 10 seconds. + +General Notes +------------- +Impulse Tracker supports a maximum of 4 users per session. Extra users will +be automatically discarded. + +Many functions have been disabled under network mode. You will receive warning +messages in these cases. + +Do *NOT* use hardware mixed drivers for networked sessions. This specifically +means the AWE32, GUS and Interwave drivers. Since networked sessions can +change samples 'behind your back', these drivers will not update correctly. diff --git a/it/ReleaseDocumentation/README.TXT b/it/ReleaseDocumentation/README.TXT new file mode 100644 index 0000000..2b9a5b4 --- /dev/null +++ b/it/ReleaseDocumentation/README.TXT @@ -0,0 +1,72 @@ + +This package contains 6 files + +1. IT.EXE - This can be considered IT214 Patch #4. Includes a few bugfixes + and some minor enhancements. Registered users should use their + own IT.EXE + +2. ITVSOUND.MMX - Virtual Sound Driver for Impulse Tracker. This is a MMX + driver and will not work on non MMX computers. + +3. ITVSOUND.DRV - Virtual Sound Driver for Impulse Tracker. This is a non-MMX + driver and should work on all computers. + +4. ITVSOUND.VXD - Driver to connect ITVSOUND.MMX to the server. + +5. SERVER.EXE - Windows server to connect to DirectSound + +6. README.TXT - This file. + +How to use these files +---------------------- +You MUST have DirectX installed. It was written with the DirectX6 SDK, +although I'm pretty sure DirectSound 5 is sufficient. + +1. Copy ITVSOUND.VXD into your Windows\System directory + (normally C:\WINDOWS\SYSTEM) + +2. In your Windows directory (normally C:\WINDOWS), edit your SYSTEM.INI file + and include the line: + device=itvsound.vxd + anywhere in the [386Enh] section + +3. Reboot your computer + +4. Run Server.EXE + +5. Run "IT" + +Configuring the driver +---------------------- +The driver can be configured by modifying Window's Registry by running +"regedit" (which comes with Windows). The variables can be found at: + "KHEY_LOCAL_MACHINE\Software\Jeffrey Lim\Impulse Tracker VSound Server" + +The 4 variables are: + BufferSize - The size of the DirectSound buffer in kb. + Permitted ranges from 4 to 64, default 24 + BufferThreshold - The size of the buffer that IT tries to maintain in kb. + Permitted ranges from 2 to 32, default 21 + BufferType - 0 = DualBuffer (BufferSize is logically split into 2 sections) + 1 = QuadBuffer (BufferSize is logically split into 4 sections) + 2 = OctBuffer (BufferSize is logically split into 8 sections) + (recommended, default) + MixSpeed - Mixing rate to be used in Hz. + Permitted ranges from 11025 to 64000, default 44100 + +You will need to restart the server before these changes take effect. + +Known Problems +-------------- +1. This driver only works with Win95 and Win98, NOT WinNT (I'll try a WinNT + driver sometime). + +2. There is an obvious latency due to the size of the buffers and the delay + that is inherent to DirectSound. Reducing the BufferSize and BufferThreshold + values can reduce this latency, however, smaller values can also cause the + sound to break up. + + Try using the values: + 1. BufferSize=16, BufferThreshold=14, BufferType=2, MixSpeed = 44100 + + diff --git a/it/ReleaseDocumentation/SUMMARY.TXT b/it/ReleaseDocumentation/SUMMARY.TXT new file mode 100644 index 0000000..f33749b --- /dev/null +++ b/it/ReleaseDocumentation/SUMMARY.TXT @@ -0,0 +1,296 @@ + + Summary Information - Command Line + + -SFilename.Drv - Set soundcard driver + + -Sxx Quick set sound card + 0 = No Sound + 1 = PC Speaker + 2 = Sound Blaster 1.xx + 3 = Sound Blaster 2.xx + 4 = Sound Blaster Pro + 5 = Sound Blaster 16 + 6 = Sound Blaster AWE 32 + 7 = Gravis UltraSound + 8 = Interwave IC + 9 = Pro Audio Spectrum + 10 = Pro Audio Spectrum 16 + 11 = Windows Sound System + 12 = ESS ES1868 AudioDrive + 13 = EWS64 XL Codec + 19 = Generic MPU401 driver + 20 = Disk writer device + + -Axxx Set sound card's address (hexadecimal) + -D# Set DMA channel (decimal) + -I## Set IRQ number (decimal) + + -M##### Set mixing speed (decimal) + -L### Limit number of channels + + -C Control playback in DOS Shell (with Grey +/-, Right Alt & Right Ctrl) + -F Disable file-colour distinctions + -K Exchange F1 and F11 keys + -Px Pattern memory allocation strategy. + -P0 = Try to store patterns in conventional memory first, EMS is + only used once conventional memory runs out. + Not recommended, but those of you who use IT in Windows 3.xx + should try this option if you get EMS errors. (I recommend + that you don't use IT under Windows 3.xx at all) + -P1 = Use one block of EMS for all patterndata. + This is the most memory efficient of all the pattern + storage modes - (this is also the default) + -P2 = Use EMS blocks for each pattern + This is a VERY wasteful but 'safe' memory allocation scheme. + -R Reverse channels (flip left-right), same as Alt-R on the info page. + -T1 Disable usage time indication + -T2 Enable timeslice release + -V1 Override VGA detection/Matrox detection. + -V2 Force matrox compatibility mode (use with -v1) + -V3 Wait for vertical retraces + -X1 Disable internal MMTSR + -X2 Disable mouse + -X3 Disable drive map detection + -X4 Disable cache file creation + + + Summary Information - Effects, alphabetically + + Volume Column Effects + Ax - Volume slide up + Bx - Volume slide down + Cx - Fine volume slide up + Dx - Fine volume slide down + Ex - Pitch slide down + Fx - Pitch slide up + Gx - Portament to + Hx - Vibrato with speed x + + General Effects + Axx - Set speed (set number of frames per row) + Bxx - Jump to order + Cxx - Break to row xx of (next) pattern + Dxy - Volume slide, x=0 down; y=0 up; x=F fine down; y=F fine up + Exx - Pitch slide down by xx + EFx - Fine pitch slide down by x + EEx - Extra fine pitch slide down by x + Fxx - Pitch slide up by xx + FFx - Fine pitch slide down by x + FEx - Extra fine pitch slide down by x + Gxx - Portamento to note with speed xx + Hxy - Vibrato with speed x, depth y + Ixy - Tremor with ontime x, offtime y + Jxy - Arpeggio with halftones x and y + Kxy - Dual command: H00 and Dxy + Lxy - Dual command: G00 and Dxy + Mxx - Set channel volume to xx (0->40h) + Nxy - Channel volume slide, x=0 down; y=0 up; x=F fine down; y=F fine up + Oxx - Set sample offset to xx00h + Pxy - Panning slide, x=0 right; y=0 left; x=F fine right; y=F fine left + Qxy - Retrigger note every y frames with volume modifier x + Values for x: + 0: (nothing) 4: -8 8: (nothing) C: +8 + 1: -1 5: -16 9: +1 D: +16 + 2: -2 6: *2/3 A: +2 E: *3/2 + 3: -4 7: *1/2 B: +4 F: *2 + Rxy - Tremelo with speed x, depth y + S3x - Set vibrato waveform + S4x - Set tremelo waveform + S5x - Set panbrello waveform + Waveforms for x in S3x, S4x and S5x: + 0 = Sine 2 = Square + 1 = Ramp down 3 = Random + S6x - Pattern delay for x frames + S7x - Instrument functions + Values for x in S7x: + 0: Past note cut 5: Set NNA to note off + 1: Past note off 6: Set NNA to note fade + 2: Past note fade 7: Turn off volume envelope + 3: Set NNA to note cut 8: Turn on volume envelope + 4: Set NNA to continue + S8x - Set pan position + S91 - Set surround sound + SB0 - Set loopback point + SBx - Loop x times to loopback point + SCx - Note cut after x frames + SDx - Note delay for x frames + SEx - Pattern delay for x rows + SFx - Select parameterised MIDI Macro + T0x - Tempo slide down by x + T1x - Tempo slide up by x + Txx - Set tempo (20h->0FFh) + Uxy - Fine vibrato with speed x, depth y + Vxx - Set global volume to xx (0->80h) + Wxx - Global volume slide, x=0 down; y=0 up; x=F fine down; y=F fine up + Xxx - Set panning position (0->0FFh) + Yxy - Panbrello with speed x, depth y + Zxx - MIDI Macro - check MIDI.TXT + + Summary Information - Effects, categorically + +Note: Not all effects are listed here. + +Speed Control + Axx - Set speed + T0x - Tempo slide down by x + T1x - Tempo slide up by x + Txx - Set tempo (20h->0FFh) + S6x - Pattern delay for x frames + SEx - Pattern delay for x rows + +Position Control + Bxx - Jump to order + Cxx - Break to row xx of (next) pattern + SB0 - Set pattern loopback point + SBx - Loop pattern x times + +Volume Control + Ax - Volume slide up + Bx - Volume slide down + Cx - Fine volume slide up + Dx - Fine volume slide down + Dxy - Volume slide, x=0 down; y=0 up; x=F fine down; y=F fine up + Ixy - Tremor with ontime x, offtime y + Mxx - Set channel volume to xx (0->40h) + Nxy - Channel volume slide, x=0 down; y=0 up; x=F fine down; y=F fine up + Vxx - Set global volume to xx (0->80h) + Wxx - Global volume slide, x=0 down; y=0 up; x=F fine down; y=F fine up + Rxy - Tremelo with speed x, depth y + S4x - Set tremelo waveform + +Panning Control + Xxx - Set panning position (0->0FFh) + S8x - Set pan position + S91 - Set surround sound + Pxy - Panning slide, x=0 right; y=0 left; x=F fine right; y=F fine left + Yxy - Panbrello with speed x, depth y + S5x - Set panbrello waveform + +Pitch Control + Exx - Pitch slide down by xx + EFx - Fine pitch slide down by x + EEx - Extra fine pitch slide down by x + Ex - Pitch slide down + Fxx - Pitch slide up by xx + FFx - Fine pitch slide up by x + FEx - Extra fine pitch slide up by x + Fx - Pitch slide up + Gxx - Portamento to note with speed xx + Gx - Portamento to + Hxy - Vibrato with speed x, depth y + Hx - Vibrato with speed x + Uxy - Fine vibrato with speed x, depth y + S3x - Set vibrato waveform + Jxy - Arpeggio with halftones x and y + + Summary Information - Pattern Editor 1 + +Data Entry + Alt-0 -> Alt-9 Set skipvalue to 0-9 + . (period) Clear field(s) + 1 Note cut (^^^) + ` Note off () / panning toggle (in volume column) + Spacebar Use last (default) note/instrument/volume/effect/effectvalue + + + + SD GHJ 23 567 90 + + Z X C V B N M Q W E R T Y U I O P + + +Pattern selection + +, - Next/Previous pattern (*) + Shift +, - Next/Previous 4 patterns (*) + Ctrl +, - Next/Previous order's pattern (*) + +Miscellaneous + Enter Get default note/instrument/volume/effect + '<' or Ctrl-Up Decrease instrument + '>' or Ctrl-Down Increase instrument + Grey '/' Decrease octave + Grey '*' Increase octave + ',' (comma) Toggle edit mask for current field + + Ins/Del Insert/Delete a row to/from current channel + Alt-Ins/Del Insert/Delete an entire row from pattern (*) + Alt-N Toggle Multichannel + 2*Alt-N Multichannel selection menu + Alt-Enter Store pattern data + Alt-Backspace Revert pattern data (*) + Ctrl-Backspace Undo - any function with (*) can be undone. + + Ctrl-F2 Set (multiple) pattern length + +Cursor Control + Up/Down Move up/down by the skipvalue + Ctrl-Home/End Move up/down by 1 row + Alt-Up/Down Slide pattern up/down by 1 row + Alt-Left/Right Move forwards/backwards one channel + Ctrl-Left/Right Move left/right between track columns + Tab/Shift-Tab Move forwards/backwards to note column + PgUp/PgDn Move up/down by n lines (n=Row hilight major) + Ctrl-PgUp/PgDn Move to top/bottom of pattern + Home Move to start of column/start of line/start of pattern + End Move to end of column/end of line/end of pattern + Backspace Move to previous position (accounts for Multichannel) + + Ctrl-C Toggle centralise cursor option. + +Track View Functions + Alt-T Cycle current track's view + Alt-R Remove all track views + Alt-H Toggle track-view divisions + Ctrl-0 Deselect current track + Ctrl-1 - Ctrl-5 View current track in scheme 1-5 + Ctrl-Left/Right Move left/right between track columns + + Left-Ctrl & + Left-Shift 1-4 Quick setup view scheme (and enable cursor-tracking) + + Ctrl-T Toggle view-channel cursor tracking + + Summary Information - Pattern Editor 2 + +Block functions. + Shift-Movement Mark block + Alt-B Mark beginning of block + Alt-E Mark end of block + Alt-D Quick mark n/2n/4n/... lines (n=Row Hilight Major) + Alt-L Mark entire column/pattern + + Alt-U Unmark block/release clipboard + + Alt-Q Raise notes by a semitone (*) + Alt-A Lower notes by a semitone (*) + + Alt-S Set instrument (*) + Alt-V Set volume/panning (*) + Alt-W Wipe volume/panning not associated with a note/instrument (*) + Alt-K Slide volume/panning column (*) + 2*Alt-K Wipe all volume/panning controls (*) + Alt-J Volume amplifier (*) / Fast Volume attenuate (*) + Alt-Z Cut block (*) + Alt-X Slide effect value (*) + 2*Alt-X Wipe all effect & effect value data (*) + + Alt-C Copy block into clipboard + Alt-P Paste data from clipboard (*) + Alt-O Overwrite with data from clipboard (*) + Alt-M Mix data from clipboard with pattern data (*) + + Alt-F Double block length (*) + Alt-G Halve block length (*) + + Alt-I Select template mode / Fast volume amplify (*) + Ctrl-J Toggle fast volume amplification with Alt-J/Alt-I + +Playback functions + 4 Play note under cursor + 8 Play row + + Ctrl-F6 Play pattern from current row + Ctrl-F7 Set/Clear playback mark (for use with F7) + + Alt-F9 Toggle current channel on/off + Alt-F10 Solo current channel on/off diff --git a/it/ReleaseDocumentation/UPDATE.TXT b/it/ReleaseDocumentation/UPDATE.TXT new file mode 100644 index 0000000..16dd3cb --- /dev/null +++ b/it/ReleaseDocumentation/UPDATE.TXT @@ -0,0 +1,592 @@ + +Contributors Additions + - IT215 file format saving. Note that this is an alternative compression + format and is often better, but not always. Public releases of IT214 + Patch 1 and later can read IT215 compressed files. There is also a + version of MikIT that can read IT215 compression. + - Sample sorting enabled. On the sample/instrument list screens, files will + be priority sorted alphabetically if you don't move the cursor. If you + do move the cursor, then you can force a resort once all the files have + been loaded by pressing Alt-S. + - Reordering of order list with Alt-R while on the order list screen + (easier to try it out, than to try to explain it) + - Row lock in pattern editor if holding shift - very useful for chords + (ie. use Shift+note) + - 10 configurable 'preset' envelopes slots + - Extra instrument filter controls (under pitch menu). + - Alt-W on the sample list saves as .WAV format, not .RAW + - Individual Sample/Instrument solo. + - Personalised Network username + +Contributions of US$30 or more + - Stereo Diskwriter + - MIDI .IT -> .MID converter + + +Bug fixes to Network version + - Correct data transmitted on: + 1. Pattern Undo (Ctrl-Backspace) + 2. Block Mix (Alt-M) + - EMS Error 83h during network sessions + +IT214 Network + - This includes the first version of Networked Impulse Tracker. Check + NETWORK.TXT for more information. + + - ITSB16B.MMX for SBLive! users which shouldn't require reinitialisation. + +IT214 Patch 4 - This release has been made entirely for the VSOUND drivers, + which will allow you to setup IT to run under Windows '95/'98 + with *ANY* soundcard. Check ITVSOUND.TXT for more information. + + - Addition: Included command line option /V3 to wait for vertical retrace. + - Addition: Included command line option /X4 to disable cache file creation. + + - Bug fix: Several fixes to the MIDI Out implementation + - Bug fix: S3M saver sometimes caused crash problems and pattern errors + - Bug fix: SCx and Qxx commands and will work with MIDI Out instruments + - Bug fix: 64 channel view doesn't skip channels with only volume-effects + + - Driver news: 4-band EQ in diskwriter + Minor miscellaneous upgrades + Fixes to MMX drivers that clicked on 0 volume (oops) + + Clarification (only because I saw some arguments on usenet) + - the MMX drivers use 32-bit precision mixing, not 16-bit. + +IT214 Patch 3 - Merry XMas guys! + + - If anyone who has contributed has NOT received an EMail from me, please + write to me! I've sent out EMails to every one of you.. but a few + addresses have changed.. or I could have accidentally missed you (huge + apologies if so) + + - Bug fix: IFF loader + - Bug fix: XM modules with no patterns won't crash IT. (Apologies to the + GroovyCompo Organisers - for those interested in online music + tracking competitions, check http://www.groove.org) + - Bug fix: CACHE files stored on CDROMs will now work, irrespective of + their datestamp. Thanks to Humanoid/Prophecy for the Morbid Minds + CD on which I could finally test these routines! + - Bug fix: Obscure bug on instrument list under rare circumstances causing + playing notes to do weird things. + + - Driver news: Updated driver format (incompatible with previous ITs) + Resonant filters - check FILTERS.TXT for information. + This stuff has been released basically so that contributors + can distribute their songs that use filters.. + - MMX drivers implemented. + - WAV driver - time accuracy improved + - can specify destination directory (on shift-F5) + - handles resonant filters + +IT214 Patch 2 + - Bug Fix: 16-bit samples of an exact multiple of 32768 bytes in size were + getting corrupted on saving. + - Bug fix: MIDI Macros (unparameterised) were somehow disabled somewhere + after IT212.. now reenabled + +IT214 Patch 1 + - Bug fix: EMM4.0 mode reenabled + - Bug fix: Volume envelopes were skipping some ticks (sounded too fast) + - Bug fix: Slight problems with the wav writer fixed + - Bug fix: S3M saving bug fixed (was introduced in IT214 due to a 'bug + report') + - Other miscellaneous fixups + +IT214 - Version jump to make sure samples don't get screwed up by the + prerelease (IT213) loader. This is the FINAL public release. Apart + from bugfixes/new soundcard drivers, don't expect to see anything in + the future... + + - Samples are now compressed on the fly when saved and loaded from disk. + Note that this is NOT the same as using MMCMP. + + - Several unimportant (debug) procedures removed to make slightly more + memory available. + + - Driver news: Diskwriter interpolation changed from quadratic spline + to cubic spline. (Requires a FPU) + +IT213 Update + - Modification: Sample panning reset to override instrument panning due to + demand. + + - Update: .IFF loader updated. Should deal with almost any .IFF file now. + + - Update: EMS Stability improved + + - Update: Several miscellaneous changes + + - Update: If old effects is *ON*, then a looped volume envelope will NOT + include the last node (for XM compat) + + - Update: More memory available (Help text was manually compressed) + + - Row hilight information is now stored within the .IT module.. + + - Automatic MIDI Pitch wheel handling. Vibrato, pitch slides, portamentos + all handled. + + + - MIDI Configuration can be embedded into .IT files. + (Option is on Shift-F1) + + - Driver news: Terratec EWS64 XL Codec software mixing driver + Terratec Maestro 32/96 Codec software mixing driver + Terratec Maestro 16/96 Codec software mixing driver + Ensoniq SoundscapeVIVO Codec software mixing driver + Sound Track PCI Codec software mixing driver + ES1688 Audiodrive Codec software mixing driver (for ViperMAX) + MPU401 generic driver. + Direct to Disk writer now uses logarithmic volume ramping + and quadratic spline interpolation + Read DRIVERS.TXT for information on all of these. + +IT212 Update - Special thanks go out to all those that did stability testing + of the beta versions of IT212. + + - Bug fix: "Available Samples" in the instrument loading screen will be + correct if you're loading an instrument from within a module. + + - Bug fix: Sample files will store default pan values. + + - Bug fix: Trying to show pattern data past the end of a pattern will + not crash IT anymore. This could have occurred before if the + number of rows in a pattern were reduced during playback, then + switching to the info page. + + - Bug fix: Deleting samples/instruments "within" a module has been disabled + (as it should be), so that the module itself cannot be deleted. + + - Bug fix: Default sample pan will override instrument pan whether "Old + Effects" is on or off. + + - .669 Loader, since Snowman is collecting 'em :) + This loader hasn't been extensively tested, maily because Composd.Exe + will not run on my machine (64MB is "Not enough extended memory" ?!?! ). + Most songs should play though.. Please don't bug me to update the loader + any further - you won't get a reply. + + - *Much* better memory handling for patterns. EMM386 parameter H=255 + should not be required in MOST cases now (you will only need it if + you use a large number of samples (ie. > 50) ). You should also have + more FreeMem to work with. Beta testers have noted that QEMM shows even + more stability problems in this version than previous versions - please + avoid QEMM as it DOES cause crashing for as yet unknown reasons. The old + memory allocation routines can still be found if you have EMS problems by + using /P2 on the command line. + + - Keyboard handling on instrument lists has been improved to handle + multiple keypresses/releases. (but not on sample list due to usability) + + - Default volume display in *NORMAL* (5 channel) pattern editor if you press + Ctrl-V. If you use a custom font, you will need to upgrade your font set + with FONTUPGR to see this properly. + Example: + C-4 01 .. ... <-- what volume is this?? + + Press Ctrl-V: + C-4 01 [32] ... <-- it'll show that the default volume of + sample/instrument 1 is 32. + + Alt-K has been upgraded to 'pick up' these default values. (So that you + can also slide from volume 0 to the sample's default without having to + explicitly key in the value). + + - Automatic filename extension replacement on Ctrl-S, so that if you press + Ctrl-S after loading a .MOD, .669, .MTM or .XM, the filename will be + automatically modified to have a .IT extension. + + - CDRom check for CACHE.IT? files. If you burn a CDRom of samples or + instruments, include the CACHE.ITI and CACHE.ITS files from IT211+ and + they should accelerate loading of sample and instrument names on all + future versions of IT. + < Not tested, since I can't :( > + + - 64 channel miniview on the info page. (note: doesn't show all fields) + + - Note dots added on the info page. + (You may have to update your info page settings by re-saving all prefs) + + - Changed the old Alt-C on the instrument list to Alt-W (wipe data) + New Alt-C removes the instrument name and filename, but does NOT + remove the instrument parameters (like the Alt-C on the sample list) + + - MIDI OUTPUT! + Fully configurable output + 16 parameterised macros + 128 constant macros + Check MIDI.TXT for details. (Big thanks to Ozone for writing this) + + - Soundcard Driver news + Inserted a new algorithm into the direct-to-disk writer to remove + clicks at the end of samples in cases of Note Cut commands, Note Cut NNA + and instantaneous sample changes in sample mode. For those who have + sent me money and would like to receive the upgrade, EMail me. + ESS ES1868 AudioDrive driver. This will NOT support any other ESS + chipsets than the ES1868. Do not write to me asking for support for + other ESS chips unless you are willing to buy me a card (or send me + the money to do so). This driver supports mixing rates up to 56.8kHz + (16 bit, stereo) and it also supports MIDI In. + AWE32 driver update: More accurate tempo control and less clicks under + Win95 + TB Tropez users: I received an EMail telling me that the GUSMAX drivers + were working fully with the TB Tropez cards! See how + it works... + Sound drivers for the ST97 and EWS64 coming... as soon as I get them + working.... + + Other news: It seems that some people really don't care how much work + I've put into IT - Warez versions of the full ITWAV.DRV + are being sought after. Let me make this clear: Distribution + of the full version of ITWAV.DRV is NOT appreciated and if I + ever find the full version anywhere, IT will no longer be + publically released. + + +IT211 Update - Not so much this time, as I have been working full time, so + since IT has been sitting on my HDD without changes for a + couple of weeks, I decided to release the update anyway. + + - Saving a song with Ctrl-S or from the menu will not prompt about + 'overwriting' the file. + + - Compatibility Gxx volume fadeout fixed. + + - Matrox autodetection fixed to set mouse cursor properly also. + + - You can press 'L' or 'R' on the "load stereo sample" prompt to select + left or right channels. + + - Increased file-header 'load-buffer' so that more Sound Forge .WAV files + should be recognised. + + - Bug fix to: swap samples/instruments, insert/remove sample/instrument + and update instrument *could* have caused the current + editing pattern to skip being modified. + + - Bug fix: Pressing delete on a non-note column in template mode should + work as expected. + + - Note: If you delete your old IT.CFG files and run IT afresh, you'll + get an extra 'line' on the infopage to work with. + + - .KRZ sample-library loader. Note that this does NOT support multiple + .KR* files (ie. .KR1, .KR2, .KR3). To use these files, you will have + to run MERGEKRZ.EXE (supplied) to create a single .KRZ file. + (BIG thanks to Markus Jonnson for the info!) + + - .PAT sample-library loader. + + - Creating a 'host instrument' after loading a sample will first attempt + to use an instrument of the same number as the sample before finding + the first empty instrument. + + - Holding down Caps Lock in the pattern editor will allow you to play + notes without entering them into the patterns. + + Driver modifications + - Bug fix for SB16 drivers which caused patterns not to 'play'. For those + that still have troubles with the SB16 driver, read DRIVERS.TXT + - For those of you who couldn't get the GUSMAX driver working, check out + DRIVERS.TXT also :) + - The ITWAV.DRV file now writes proper .WAV files instead of .RAW + - ITAWE32.DRV uses floating point calculations to reduce memory usage. + ITAWE32B.DRV (the old driver) still exists for people who don't have + math coprocessors + + +IT210 Update - some MAJOR fixes here. + + - Approximate song length on Ctrl-P. Note that *some* soundcards will + require reinitialisation after this (almost all won't). The time given + is the 'ideal' time for the playback of the song and should correspond + *exactly* to GUS/AWE non-IRQ playback times. + + - A few more player bug fixes for XM compatibility + + - IT won't crash if you try to load instruments from an 'empty' drive + (eg. disk not inserted or no files present) + + - In the pattern editor, Insert/Delete, Note Cut/Note Off/Note Delete + are all 'template aware' - they will span more than 1 channel if + you are editing in template mode and the template has height 1. + Also, 'picking up' data with Enter will turn off Template mode's except + for "Template-Notes Only" + + - Volume column effects Ex/Fx/Gx in combination with effect Jxx should + operate as expected now. + + - Deleting a file on the instrument list will update the instrument cache + file appropriately. + + - Sample/Instrument cache file time check fixed. + + - Slight modification to the handling of SBx commands to prevent + infinite loops. + + - Simple crash recovery mechanism should you ever encounter a problem. + (You shouldn't need it!) This is on Ctrl-Alt-Del in DOS or + Ctrl-Alt-Ins in Windows. It is not guaranteed to work, but if it works + once, then I guess that the amount of time I spent on it was worth it + (~10 minutes). + + For the technically minded lot, what it does is it tries to 'kick start' + the tracker again directly from the keyboard interrupt handler. + + - Loading a stereo WAV file will cause a pop-up menu to appear to select + loading the left or right channels. + + - GUSMAX users interested in using software mixing, check out DRIVERS.TXT + + - Memory corruption error found and fixed which produced 3-sets of invalid + values in the order list/instruments (main reason for this release!) + +IT209 Update + + ************************* FONT FILES REQUIRE UPDATING ********************* + If you have your own custom font file, you will need to change character + number 184 to 190. If you have used one of the 'standard' font sets, you + will need to run ITF and grab an updated file. Failure to do so will just + make the sample page look stuffed - You have been warned :) + *************************************************************************** + + Many Many MANY miscellaneous fixes to the XM loader and playback routines + -> XM support should be *MUCH* better now. + Volume effects have been debugged... hopefully :) + + Some major errors fixed around (ie. dumping to DOS from the Instrument + screen, Pattern's not updating in memory correctly (which went wrong in + IT208) ) + + Added default sample pan to the sample list (default instrument pan WILL + override this if present). Note that using default pan is the equivalent + of using a 'set pan' effect on that row - the channel will be set to the + default sample pan. + + You can change whether the info page displays sample names or instrument + names by pressing 'i' + +IT208 Update + + So much so quickly? Well, I had exams. And when I have exams, I code, 'cos + it's better than having to study :) + + ************************* FONT FILES REQUIRE UPDATING ********************* + If you have your own custom font file, you will need to change character + number 184 to. If you have used one of the 'standard' font sets, you will + need to run ITF and grab an updated file. Failure to do so will just make + the info page and 10-channel editor look stuffed - You have been warned :) + *************************************************************************** + + - Bug fix: Keyboard configuration files could have cause MAJOR problems... + fixed! + + - Bug fix: Some files with the .MOD ID "CH" which actually were NOT MODs + were being identified as "Fast Tracker 2" modules. + (You may have to delete your CACHE.ITS files to force IT to + refresh it's data) + + - Bug fixes: MIDI input won't corrupt input on the order list + MIDI input won't interfere with button presses + MIDI input won't insert effect SDF into patterns when recording + where inappropriate. + + - Old Left Ctrl+Shift-1 'removed', Left-Ctrl+Shift 1->4 still work - and + have been updated. + + PROPER 10-channel editing mode available (complete with half sized cursors!) + as well as some minor logic improvements. (Try Left-Ctrl+Shift 2) + + - ";" and "'" made to change the samples/instrument in the pattern editor + as '<' and '>' do - just much easier to do so on American keyboards. + + - Dragging mouse nodes past boundaries is more accurate. + + - "Channel details" display (on the infopage) *can* show the 64th channel + (oops in IT207) + + - Matrox bug autodetection (Many thanks to Csaba Pankaczy for working with + me on this!) + + - Message system hooked to a timer (ie. all those messages that appear + towards the top of the screen).. so that they will last a consistent + amount of time (independent of machine). + + - Player Improvement: NNA mechanism will eliminate channels on two extra + conditions now (no difference to playback, but should + maximise channel usage) + + - Improvement: Persistence of cache files through different sessions of IT + - ie. once the sample/instrument cache files are created, they + are NOT recreated unless necessary. + + - Root "\" directory has replaced "." directory on all loading screens. + + - Several Template input related functions improved. Also, Block-Cut in + template mode won't overwrite your clipboard if you're working with + templates. + + - Template: "Notes only" added. This is different from the other templates + in that it will NOT copy the template's instruments, volumes or effects. + Instead, it will change it's instrument/volume/effect according to the + last used instrument/volume/effect, and will insert whatever is speicfied + by the edit mask. + + - Addition: Volume Column effects, Ax, Bx, Cx, Dx, Ex, Fx, Gx and Hx!!!! + + Ax = Fine volume slide up by x + Bx = Fine volume slide down by x + Cx = Volume slide up by x + Dx = Volume slide down by x + Ex = Pitch slide down by x + Fx = Pitch slide up by x + Gx = Portamento to note with speed x + Hx = Vibrato with depth x + + Note that the pitch/portamento scale here is DIFFERENT from the standard + effect slideup/down + +* Note that if you use these in your songs, IT < 2.08 will NOT play them +* correctly... (in fact, it'll probably play it extremely painfully) + + - Alt Up/Down/Ins/Del added to the note translation table. + + - Minor modifications around the tracker + + - Windows Sound System Driver! (Operates at mixing rates up to 64kHz!) + Impulse Tracker has the greatest soundcard support of any tracker by far! + + - Old Effects will 'unlink' the memory of Gxx from Exx/Fxx + + - XM LOADING!!!!!!!!!! + + Don't write to me complaining about incompatibilities - I am aware of + lots of them and you probably won't get a reply. :) *MOST* songs should + have a near perfect conversion tho... + + - Big safety feature!! Playback dying because of overload? Bad NNA selection? + F8 *should* stop playback immediately now! (in DOS). + + In Windows '95, there may be a noticeable stall before playback stops + (ie. several seconds), or it may not function at all... + +IT207 update + + - Some bug fixes to MIDI input. + - Ctrl-PgUp/PgDn on the sample list will redraw the waveforms + - Jxx memory should work fine (The memory didn't operate if the channel + wasn't active before) + - Template limits should be correctly applied. (ie. clipped within + C-0 and B-9) + - Going to a pattern from the Info Page ('G') will also go to the + current order playing. + - MIDI input can be enabled/disabled in the pattern editor with + Alt-Scroll Lock + - MOD in-module sample library loop points fixed. + - Envelope drawing algorithm slightly more tolerant of corrupt information + - Mouse envelope routines slightly improved for more accurate handling of + nodes. + - Added Message editor to main menu. + - Added 10 channel view to the info page (you may need to reset your info- + page settings and "save your preferences") + - Squished up the info page view to get a couple of extra lines! :) + - Ctrl-F7 on the order list will set the next pattern to play (at request + of ChuckB) - for DJ use + - Due to Win95's unstable disk-EMS routines, if you load a MMTSRed sample, + instrument or module (sample library), playback *will* stop to prevent + corruption of samples currently in memory. + - Notes in templates of height 1 will be played back in the pattern editor + (very useful for "multi sample" note entry) + - Added effects T0x and T1x for Tempo slide down and tempo slide up. + - Added .IT and .XM *INSTRUMENT* library support. Note that .ITs that + aren't in instrument mode or have no instruments will NOT be shown on + the instrument loader list. + - Added Alt-Ins and Alt-Del on the sample and instrument lists to add + in samples/instruments + + **** NOTE: /Sx command line parameters have been changed around just for + neatness. CHECK SUMMARY.TXT FOR NEW /Sx VALUES OR RUN "IT /?" *** + +IT 2.06 + + - Update: Yet another update to the EMS routines.. for those of you who + couldn't be bothered to read the FAQ. + + Also new command line switch: + /Px - Set pattern memory allocation strategy. + Check SUMMARY.TXT for info on this. + + - Minor update: The 10-stage undo buffer will now use EMS memory under most + circumstances. + + - Minor update: S3M and IT loader routines slightly modified for more + efficient memory usage. + + - Minor update: "Song modified" flag logic slightly modified. + + - Minor update: .WAV loader slightly improved. (should read any 8 or 16-bit + format.) + + - Minor Addition: IT will now release time slices to multitasking OS/s + if you specify /T2 on the command line. + If you are using the MIDI input capabilities of IT, you + SHOULD NOT enable this (timing gets effected badly) + + - Minor Addition: Set pattern length command on Ctrl-F2 (can set multiple + patterns) + + - Minor Addition: Command line switch /T1 to disable "usage time" indication + + - Addition: TX Wave loader for .W?? samples (eg. from Kosmic's sample dirs) + Note: These are actually 12-bit samples, which are converted to + 16-bit at load time. + + - Addition: .MOD sample library loader. + + This "only" recognises the following MOD Identifications - + "M.K.", "M!K!", "FLT4", "FLT8", "4CHN", "6CHN", "8CHN" + And FT2's extended MOD identification, "xxCH" + + If you have an "Old Amiga-MOD format" MOD (which doesn't have an + ID), then you'll have to save it as another format if you want + to rip directly from it. + + So sample library support in total: + .MOD, .669, .FAR, .MTM, .S3M, .PTM, .XM, .IT + + - Addition: Intelligent MIDI Input for SB16 and Interwave cards! + MIDI options screen is on Shift-F1 (those of you who have IT.CFG + from older versions of IT *WILL* need to visit this screen at + least once if you want to use MIDI - "Save All Preferences" will + save these settings) + + In the pattern editor, Ctrl-Z is "Change MIDI playback trigger." + Normally, it is quite difficult to start at a row/pattern with + MIDI - this options allow you to control whether a pattern or + song should START playing when you play the first note. + + (IT will play either from the start of the current pattern or + the song starting from the current row depending on your choice) + Once this is done, the trigger is immediately unset, so you will + have to setup this trigger again if you want to use it. + + Note that this *will* turn on pattern tracing. To disable it, + use Scroll-Lock. + + ****** NOTE ****** + + SB16's MIDI input is somewhat 'iffy'. If you stop receiving + MIDI input, you need to reinit the soundcard (Ctrl-I) (possibly + several times). I don't know why it does this. Dont' write + to me about it, 'cos I have spent MANY MANY hours on this little + problem and I don't want to know about it. Also, in Win95, I + found it necessary to change my SB16's configuration to EXCLUDE + the MIDI port (and I used a Microsoft MPU401 driver instead), + otherwise MIDI input was ignored. + + Sorry, no GUS MIDI at the moment, as I couldn't get it working. + Please do NOT write to me about this, you will not get a reply. + An updated GUS driver will be released if/when I get it working. diff --git a/it/SWITCH.INC b/it/SWITCH.INC new file mode 100644 index 0000000..e984f26 --- /dev/null +++ b/it/SWITCH.INC @@ -0,0 +1,44 @@ + +TRACEENABLED EQU 0 + +TUTORIAL = 0 + + EMSUSE41 = 0 + + SHOWVERSION = 0 + SHOWREGISTERNAME = 1 + + USE32BITSCREENCOPY = 0 + + SORTENABLED = 1 + DDCOMPRESS = 1 + ORDERSORT = 1 + FILTERENVELOPES = 1 + CHORDENTRY = 1 + SPECTRUMANALYSER = 1 + SAVESAMPLEWAV = 1 + ENABLEPRESETENVELOPES = 1 + ENABLESOLO = 1 + + DEFAULTFORMAT = 3 ; 0 = IT214, 1 = S3M, 2 = IT2xx, 3 = IT215 + + USEFPUCODE = 1 ; For IT_MUSIC, this will change from LUT to FPU code + + OLDDRIVER = 0 + + MUSICDEBUG = 0 + EMSDEBUG = 0 + MEMORYDEBUG = 0 + ENABLEINT3 = 0 ; For debugging. + + TIMERSCREEN = 1 + + NETWORKENABLED = 1 + SHOWPATTERNLENGTH = 0 + +IF TUTORIAL + SORTENABLED = 1 + DDCOMPRESS = 1 +ENDIF + +TRACKERVERSION = 217h ; Still have to change text in IT.ASM, IT_F.ASM diff --git a/it/SoundDrivers/AD1816.ASM b/it/SoundDrivers/AD1816.ASM new file mode 100755 index 0000000..0f10386 --- /dev/null +++ b/it/SoundDrivers/AD1816.ASM @@ -0,0 +1,2116 @@ +; +; Analog Device's AD1816 +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +PNPSERIALID EQU 0FFFFFFFFh +PNPVENDORID EQU 80719304h + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +Debug DW 0 +Debug2 DW 0 +DMASize DW 2048 + +ESSMsg DB "SoundPort AD1816 found", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +ESSNoMemoryMsg DB "SoundPort AD1816 found", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "SoundPort AD1816 reinitialised", 0 + +DriverName DB "ITAD1816.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +ESSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldESSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +ESSScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr ESSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + DW Near Ptr PhatStereo ; 18 + + DW Near Ptr DebugText + DW Near Ptr DebugText2 + + DW 0 + +ESSHeaderLine DW 10 + DB "SoundPort AD1816 Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "SoundPort AD1816 Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB "3D Phat Stereo", 13 + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 39, 17 + DB 25 + +PhatStereo DW 14 + DB 22, 16 + DW 0, 15 + DW 9, 2 + DW 17, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 16 + +MasterVolumeLeft DW 14 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 16 + +MasterVolumeRight DW 14 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 18, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 16 + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 44100 + +MixModeButton1 DW 2 + DW 18, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +DebugText DW 1 + DB 2, 47 + DB 20h + DB "MIDI Port: ", 0FDh, "Xh", 0 +MIDIPort DW 0 + +DebugText2 DW 1 + DB 2, 48 + DB 20h + DB "MIDI IRQ: ", 0FDh, "Dh", 0 +MIDIIRQ DW 0 + +VolumeTable DB 56, 56, 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dmasirq.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc AD1816Wait + + PushA + Xor CX, CX + Mov DX, CS:BasePort + +AD1816Wait1: + In AL, DX + Test AL, 80h + LoopZ AD1816Wait1 + + PopA + Ret + +EndP AD1816Wait + +; + +Proc AD1816RegisterOut ; AL = indirect register, BX = contents + + Call AD1816Wait + + Push DX + PushF + + ClI + + Mov DX, CS:BasePort + Out DX, AL + Add DL, 2 + + Mov AL, BL + Out DX, AL + Inc DX + Mov AL, BH + Out DX, AL + + PopF + Pop DX + + Ret + +EndP AD1816RegisterOut + +; + +Proc AD1816RegisterIn ; AL = register + ; Returns BX + + Call AD1816Wait + + Push AX + Push DX + + Mov DX, CS:BasePort + Out DX, AL + Add DL, 2 + + In AL, DX + Mov BL, AL + Inc DX + In AL, DX + Mov BH, AL + + Pop DX + Pop AX + + Ret + +EndP AD1816RegisterIn + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + + Mov AX, 1 + Ret + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + Mov AX, 007h + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov CX, 107h + +MIDISearchLoop: + Mov AX, CX + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + + Test AX, 0Fh + JNZ NextMIDI + Cmp AX, 300h + JB NextMIDI + Cmp AX, 400h + JAE NextMIDI + + Mov MIDIPort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + Mov MIDIIRQ, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +NextMIDI: + Add CX, 100h + Cmp CX, 0F07h + JBE MIDISearchLoop + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Inc Debug + + Inc DX + In AL, DX + Mov AH, AL + Xor AL, AL + Out DX, AL +; Call AD1816Out + + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB ESSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +ESSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE ESSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +ESSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB ESSIRQHandler6 + JE ESSIRQHFilter + + Cmp CS:Stereo, 0 + JE ESSIRQ3QFilterMono + +ESSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +ESSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +ESSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +ESSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilter: + Cmp CS:Stereo, 0 + JE ESSIRQHFilterMono + +ESSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +ESSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +ESSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +ESSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL ESSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG ESSIRQHandlerClip2 + +ESSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ ESSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +ESSIRQHandlerClip1: + Mov AX, 8000h + Jmp ESSIRQHandler7 + +ESSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp ESSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo3 + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopAD1816 + + PushA + + Mov AL, 1 + Call AD1816RegisterIn + And BX, 07FFFh ; Disable PIE + Call AD1816RegisterOut + + Mov DX, CS:BasePort + Inc DX + In AL, DX + And AL, Not 80h + Out DX, AL + + Add DL, 7 + In AL, DX + And AL, Not 1 + Out DX, AL + + PopA + Ret + +EndP StopAD1816 + +; + +Proc StartAD1816 + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov AL, 4 + Call AD1816RegisterIn + + Mov AL, 32 + Call AD1816RegisterIn + Or BX, 08000h + Call AD1816RegisterOut + + Mov AL, 2 ; Sample rate + Mov BX, MixSpeed + Call AD1816RegisterOut + + Mov AL, 8 ; DMA Size + Mov BX, DMASize + ShR BX, 2 + Dec BX + Call AD1816RegisterOut + + Mov DX, BasePort ; Wave Format + Add DL, 8 + + Mov AL, 00010001b + Cmp Stereo, 0 + JE StartAD1816A + + Or AL, 4 + +StartAD1816A: + Out DX, AL + + Mov AL, 1 ; Enable Playback interrupt + Call AD1816RegisterIn + Or BX, 8000h + Call AD1816RegisterOut + + Pop DS + Pop ES + PopA + + Ret + +EndP StartAD1816 + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov AX, CmdLineMixSpeed + Test AX, AX + JZ ClipMixSpeed3 + + Cmp AX, 11050 + JA ClipMixSpeed1 + + Mov AX, 11050 + +ClipMixSpeed1: + Cmp AX, 55200 + JB ClipMixSpeed2 + + Mov AX, 55200 + +ClipMixSpeed2: + Mov MixSpeed, AX + +ClipMixSpeed3: + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Call UpdateSoundcardVariables + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Push AX + + Call StopAD1816 + Call ResetIRQ + + Pop ES + Mov AH, 49h ; Release MixSegment + Int 21h + + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL + +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Mov CS:Debug2, BX + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopAD1816 + Call StartAD1816 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset ESSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + Mov AL, 4 + Mov BX, 3F3Fh + Sub BX, [Word Ptr CS:VolumeTable] + Call AD1816RegisterOut + + Mov AL, 33 + Mov BX, 40h + Call AD1816RegisterOut + + Mov AL, 39 + Call AD1816RegisterIn + Mov CL, [CS:VolumeTable+2] + ShL CX, 9 + And BX, 0110000111111111b + Or BX, CX + Call AD1816RegisterOut + + Mov AL, 14 + Xor BX, BX + Call AD1816RegisterOut + + Mov AL, 44 + Xor BX, BX + Call AD1816RegisterOut + + Ret + +EndP UpdateSoundcardVariables + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + Call UpdateSoundcardVariables + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/AMD3DI.MIX b/it/SoundDrivers/AMD3DI.MIX new file mode 100755 index 0000000..dc3a759 --- /dev/null +++ b/it/SoundDrivers/AMD3DI.MIX @@ -0,0 +1,56 @@ + +; 8-bit interpolated mixing routine, 4 samples at a time. Rearranged +; MM7 contains volume as packed floating point +; MM6 contains offset as packed integer offset +; MM5 = DeltaOffset + +; MM7 = RVol|LVol +; MM6 = (1-Offset2)|Offset2|(1-Offset1)|Offset1 + + MovD MM0, [SampleBlock1] ; MM0 = x|x|x|x|S2H|S2L|S1H|S1L + MovQ MM2, MM6 + + PSRAW MM2, 1 + PUnpckLBW MM0, MM0 ; MM0 = S2H|S2L|S1H|S1L + + PAddW MM6, MM5 + PMAddWD MM0, MM2 ; MM0 = IS2|IS1 + + MovD MM1, [SampleBlock2] ; MM1 = x|x|x|x|S4H|S4L|S3H|S3L + MovQ MM2, MM6 + + PUnpckLBW MM1, MM1 ; MM1 = S4H|S4L|S3H|S3L + PSRAW MM2, 1 + + PI2FD MM0, MM0 ; MM0 = FIS2|FIS1 + PMAddWD MM1, MM2 ; MM1 = IS4|IS3 + + MovQ MM2, MM0 + PUnpckLDQ MM0, MM0 ; MM0 = FIS1|FIS1 + + PUnpckHDQ MM2, MM2 ; MM2 = FIS2|FIS2 + PI2FD MM1, MM1 ; MM1 = FIS4|FIS3 + + PFMul MM0, MM7 ; MM0 = R1|L1 + PAddW MM6, MM5 + + PFMul MM2, MM7 ; MM2 = R2|L2 + MovQ MM3, MM1 + + PFAdd MM0, [Buffer1] + PUnpckLDQ MM1, MM1 ; MM1 = FIS3|FIS3 + + PFAdd MM2, [Buffer2] + PUnpckHDQ MM3, MM3 ; MM3 = FIS4|FIS4 + + PFMul MM1, MM7 + MovQ [Buffer1], MM0 + + PFMul MM3, MM7 + PFAdd MM1, [Buffer3] + + MovQ [Buffer2], MM2 + PFAdd MM3, [Buffer4] + + MovQ [Buffer3], MM1 + MovQ [Buffer4], MM3 diff --git a/it/SoundDrivers/AMD3DNI.MIX b/it/SoundDrivers/AMD3DNI.MIX new file mode 100755 index 0000000..203d218 --- /dev/null +++ b/it/SoundDrivers/AMD3DNI.MIX @@ -0,0 +1,304 @@ + +; 8-bit non interpolated mixing routine, 8 samples at a time. Not rearranged + +; MM7 contains volume as packed floating point MM7 = RVol|LVol + + MovD MM0, [SampleBlock1] ; Low 4 bytes contain samples 1-4 + MovD MM1, [SampleBlock2] ; Low 4 bytes contain samples 5-8 + + PUnpckLBW MM0, MM0 ; MM0 = S4|S3|S2|S1 + PUnpckLBW MM1, MM1 ; MM1 = S8|S7|S6|S5 + + MovQ MM2, MM0 + MovQ MM3, MM1 + + PUnpckLWD MM0, MM0 ; MM0 = S2|S1 + PUnpckLWD MM1, MM1 ; MM1 = S6|S5 + + PUnpckHWD MM2, MM2 ; MM2 = S4|S3 + PUnpckHWD MM3, MM3 ; MM3 = S8|S7 + +; What category do PI2FD instructions fall under? Are they AMD-3D ALU (ie. +; only one resource shared between pipes?) + + PI2FD MM0, MM0 ; MM0 = FS2|FS1 + PI2FD MM1, MM1 ; MM1 = FS6|FS5 + PI2FD MM2, MM2 ; MM2 = FS4|FS3 + PI2FD MM3, MM3 ; MM3 = FS8|FS7 + + MovQ MM4, MM0 + MovQ MM5, MM2 + + PUnpckLDQ MM0, MM0 ; MM0 = FS1|FS1 + PUnpckHDQ MM4, MM4 ; MM4 = FS2|FS2 + PUnpckLDQ MM2, MM2 ; MM2 = FS3|FS3 + PUnpckHDQ MM5, MM5 ; MM5 = FS4|FS4 + + PFMul MM0, MM7 ; MM0 = R1|L1 + PFMul MM4, MM7 ; MM4 = R2|L2 + PFMul MM2, MM7 ; MM2 = R3|L3 + PFMul MM5, MM7 ; MM5 = R4|L4 + + PFAdd MM0, [Buffer1] + PFAdd MM4, [Buffer2] + PFAdd MM2, [Buffer3] + PFAdd MM5, [Buffer4] + + MovQ [Buffer1], MM0 + MovQ [Buffer2], MM4 + MovQ [Buffer3], MM2 + MovQ [Buffer4], MM5 + + MovQ MM0, MM1 + MovQ MM2, MM3 + + PUnpckLDQ MM0, MM0 ; MM0 = FS5|FS5 + PUnpckHDQ MM1, MM1 ; MM1 = FS6|FS6 + PUnpckLDQ MM2, MM2 ; MM2 = FS7|FS7 + PUnpckHDQ MM3, MM3 ; MM3 = FS8|FS8 + + PFMul MM0, MM7 + PFMul MM1, MM7 + PFMul MM2, MM7 + PFMul MM3, MM7 + + PFAdd MM0, [Buffer5] + PFAdd MM1, [Buffer6] + PFAdd MM2, [Buffer7] + PFAdd MM3, [Buffer8] + + MovQ [Buffer5], MM0 + MovQ [Buffer6], MM1 + MovQ [Buffer7], MM2 + MovQ [Buffer8], MM3 + +;----------------------------------------------------------------------------- +; Rearranged to improve pairing +; MM7 contains volume as packed floating point MM7 = RVol|LVol + + MovD MM0, [SampleBlock1] ; Low 4 bytes contain samples 1-4 + MovD MM1, [SampleBlock2] ; Low 4 bytes contain samples 5-8 + + PUnpckLBW MM0, MM0 ; MM0 = S4|S3|S2|S1 + PUnpckLBW MM1, MM1 ; MM1 = S8|S7|S6|S5 + + MovQ MM2, MM0 + PUnpckLWD MM0, MM0 ; MM0 = S2|S1 + + MovQ MM3, MM1 + PUnpckLWD MM1, MM1 ; MM1 = S6|S5 + + PUnpckHWD MM2, MM2 ; MM2 = S4|S3 + PI2FD MM0, MM0 ; MM0 = FS2|FS1 + + PUnpckHWD MM3, MM3 ; MM3 = S8|S7 + PI2FD MM1, MM1 ; MM1 = FS6|FS5 + + MovQ MM4, MM0 + PI2FD MM2, MM2 ; MM2 = FS4|FS3 + + MovQ MM5, MM2 + PI2FD MM3, MM3 ; MM3 = FS8|FS7 + + PUnpckLDQ MM0, MM0 ; MM0 = FS1|FS1 + PUnpckHDQ MM4, MM4 ; MM4 = FS2|FS2 + + PFMul MM0, MM7 ; MM0 = R1|L1 + PUnpckLDQ MM2, MM2 ; MM2 = FS3|FS3 + + PFMul MM4, MM7 ; MM4 = R2|L2 + PUnpckHDQ MM5, MM5 ; MM5 = FS4|FS4 + + PFMul MM2, MM7 ; MM2 = R3|L3 + PFAdd MM0, [Buffer1] + + PFMul MM5, MM7 ; MM5 = R4|L4 + PFAdd MM4, [Buffer2] + + PFAdd MM2, [Buffer3] + MovQ [Buffer1], MM0 + + MovQ [Buffer2], MM4 + PFAdd MM5, [Buffer4] + + MovQ [Buffer3], MM2 + MovQ MM0, MM1 + + MovQ [Buffer4], MM5 + MovQ MM2, MM3 + + PUnpckLDQ MM0, MM0 ; MM0 = FS5|FS5 + PUnpckHDQ MM1, MM1 ; MM1 = FS6|FS6 + + PFMul MM0, MM7 + PUnpckLDQ MM2, MM2 ; MM2 = FS7|FS7 + + PFMul MM1, MM7 + PUnpckHDQ MM3, MM3 ; MM3 = FS8|FS8 + + PFAdd MM0, [Buffer5] + PFMul MM2, MM7 + + PFAdd MM1, [Buffer6] + PFMul MM3, MM7 + + MovQ [Buffer5], MM0 + PFAdd MM2, [Buffer7] + + MovQ [Buffer6], MM1 + PFAdd MM3, [Buffer8] + + MovQ [Buffer7], MM2 ; These will be rearranged to match + MovQ [Buffer8], MM3 ; the next iteration. + + + +; 16-bit non interpolated mixing routine, 8 samples at a time. Not rearranged + +; MM7 contains volume as packed floating point MM7 = RVol|LVol + + MovQ MM0, [SampleBlock1] ; MM0 = S4|S3|S2|S1 + MovQ MM1, [SampleBlock2] ; MM1 = S8|S7|S6|S5 + + MovQ MM2, MM0 + MovQ MM3, MM1 + + PUnpckLWD MM0, MM0 ; MM0 = S2|S1 + PUnpckLWD MM1, MM1 ; MM1 = S6|S5 + + PUnpckHWD MM2, MM2 ; MM2 = S4|S3 + PUnpckHWD MM3, MM3 ; MM3 = S8|S7 + +; What category do PI2FD instructions fall under? Are they AMD-3D ALU (ie. +; only one resource shared between pipes?) + + PI2FD MM0, MM0 ; MM0 = FS2|FS1 + PI2FD MM1, MM1 ; MM1 = FS6|FS5 + PI2FD MM2, MM2 ; MM2 = FS4|FS3 + PI2FD MM3, MM3 ; MM3 = FS8|FS7 + + MovQ MM4, MM0 + MovQ MM5, MM2 + + PUnpckLDQ MM0, MM0 ; MM0 = FS1|FS1 + PUnpckHDQ MM4, MM4 ; MM4 = FS2|FS2 + PUnpckLDQ MM2, MM2 ; MM2 = FS3|FS3 + PUnpckHDQ MM5, MM5 ; MM5 = FS4|FS4 + + PFMul MM0, MM7 ; MM0 = R1|L1 + PFMul MM4, MM7 ; MM4 = R2|L2 + PFMul MM2, MM7 ; MM2 = R3|L3 + PFMul MM5, MM7 ; MM5 = R4|L4 + + PFAdd MM0, [Buffer1] + PFAdd MM4, [Buffer2] + PFAdd MM2, [Buffer3] + PFAdd MM5, [Buffer4] + + MovQ [Buffer1], MM0 + MovQ [Buffer2], MM4 + MovQ [Buffer3], MM2 + MovQ [Buffer4], MM5 + + MovQ MM0, MM1 + MovQ MM2, MM3 + + PUnpckLDQ MM0, MM0 ; MM0 = FS5|FS5 + PUnpckHDQ MM1, MM1 ; MM1 = FS6|FS6 + PUnpckLDQ MM2, MM2 ; MM2 = FS7|FS7 + PUnpckHDQ MM3, MM3 ; MM3 = FS8|FS8 + + PFMul MM0, MM7 + PFMul MM1, MM7 + PFMul MM2, MM7 + PFMul MM3, MM7 + + PFAdd MM0, [Buffer5] + PFAdd MM1, [Buffer6] + PFAdd MM2, [Buffer7] + PFAdd MM3, [Buffer8] + + MovQ [Buffer5], MM0 + MovQ [Buffer6], MM1 + MovQ [Buffer7], MM2 + MovQ [Buffer8], MM3 + +;----------------------------------------------------------------------------- +; Rearranged to improve pairing +; MM7 contains volume as packed floating point MM7 = RVol|LVol + + MovQ MM0, [SampleBlock1] ; MM0 = S4|S3|S2|S1 + MovQ MM1, [SampleBlock2] ; MM1 = S8|S7|S6|S5 + + MovQ MM2, MM0 + PUnpckLWD MM0, MM0 ; MM0 = S2|S1 + + MovQ MM3, MM1 + PUnpckLWD MM1, MM1 ; MM1 = S6|S5 + + PI2FD MM0, MM0 ; MM0 = FS2|FS1 + PUnpckHWD MM2, MM2 ; MM2 = S4|S3 + + PI2FD MM1, MM1 ; MM1 = FS6|FS5 + PUnpckHWD MM3, MM3 ; MM3 = S8|S7 + +; What category do PI2FD instructions fall under? Are they AMD-3D ALU (ie. +; only one resource shared between pipes?) + + MovQ MM4, MM0 + PI2FD MM2, MM2 ; MM2 = FS4|FS3 + + MovQ MM5, MM2 + PI2FD MM3, MM3 ; MM3 = FS8|FS7 + + PUnpckLDQ MM0, MM0 ; MM0 = FS1|FS1 + PUnpckHDQ MM4, MM4 ; MM4 = FS2|FS2 + + PFMul MM0, MM7 ; MM0 = R1|L1 + PUnpckLDQ MM2, MM2 ; MM2 = FS3|FS3 + + PFMul MM4, MM7 ; MM4 = R2|L2 + PUnpckHDQ MM5, MM5 ; MM5 = FS4|FS4 + + PFAdd MM0, [Buffer1] + PFMul MM2, MM7 ; MM2 = R3|L3 + + PFAdd MM4, [Buffer2] + PFMul MM5, MM7 ; MM5 = R4|L4 + + PFAdd MM2, [Buffer3] + MovQ [Buffer1], MM0 + + PFAdd MM5, [Buffer4] + MovQ [Buffer2], MM4 + + MovQ MM0, MM1 + MovQ [Buffer3], MM2 + + MovQ MM2, MM3 + MovQ [Buffer4], MM5 + + PUnpckLDQ MM0, MM0 ; MM0 = FS5|FS5 + PUnpckHDQ MM1, MM1 ; MM1 = FS6|FS6 + + PFMul MM0, MM7 + PUnpckLDQ MM2, MM2 ; MM2 = FS7|FS7 + + PFMul MM1, MM7 + PUnpckHDQ MM3, MM3 ; MM3 = FS8|FS8 + + PFAdd MM0, [Buffer5] + PFMul MM2, MM7 + + PFAdd MM1, [Buffer6] + PFMul MM3, MM7 + + MovQ [Buffer5], MM0 + PFAdd MM2, [Buffer7] + + MovQ [Buffer6], MM1 + PFAdd MM3, [Buffer8] + + MovQ [Buffer7], MM2 + MovQ [Buffer8], MM3 + diff --git a/it/SoundDrivers/AWE32B.ASM b/it/SoundDrivers/AWE32B.ASM new file mode 100755 index 0000000..d728681 --- /dev/null +++ b/it/SoundDrivers/AWE32B.ASM @@ -0,0 +1,4310 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + + Comment ~ + +Index = BasePort + 802h + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + Ŀ + .............................. Register Channel Number + + + + ~ + +OldIRQHandler DD 0 +AWEMemory DD 0 +AWEMemoryUsed DD 0 +AWEUpdateCount DW 0 + +AWEUpdateTimer DW 0 + +LoadSampleFuncF DW 0 +LoadSampleFuncB DW 0 + +AWEDataTable DD 5*100 Dup (0) ; Start, Startloop, Endloop, Size +MIDIPort DW 0 +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +SB16BasePort DW 0 +MixerPort DW 0 +Step DW 1 +AWEUpdateFlag DB 0 +Compress DB 0 + DB 0 + +SBIRQMode DB 0 +BlockLength DW 100 +BlockLength2 DW 100 + +AWE32Msg DB "Sound Blaster AWE 32 detected", 13 + DB "Address ", 0FDh, "Xh, ", 0FDh, "Dk Memory", 0 + +AWE32Msg2 DB "Sound Blaster AWE 32 detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, ", 0FDh, "Dk RAM", 0 + +AWE32Status DB "FreeAWE ", 0FDh, "Dk", 0 + +AWE32ReinitMsg DB "Sound Blaster AWE 32 reinitialised", 0 +Stereo DB 0 +Forced DB 0 +DriverName DB "ITAWE32B.DRV", 0 + +FrequencyError DB "AWE Hardware frequency limit exceeded -> Note terminated", 0 + +IRQFlag DB 0FFh + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +IMR DW 0 + + CPF EQU 0 + PTRX EQU 20h + CVCF EQU 40h + VTFT EQU 60h + PSST EQU 0C0h + CSL EQU 0E0h + + CCCA EQU 100h + HWCF4 EQU 129h + HWCF5 EQU 12Ah + HWCF6 EQU 12Dh + SMALR EQU 134h + SMARR EQU 135h + SMALW EQU 136h + SMARW EQU 137h + SMLD EQU 43Ah + SMRD EQU 23Ah + WC EQU 23Bh + HWCF1 EQU 43Dh + HWCF2 EQU 43Eh + CFG2 EQU 43Eh + HWCF3 EQU 43Fh + INIT1 EQU 440h + INIT2 EQU 240h + INIT3 EQU 460h + INIT4 EQU 260h + ENVVOL EQU 480h + DCYSUSV EQU 4A0h + ENVVAL EQU 4C0h + DCYSUS EQU 4E0h + SUSDCY EQU 4E0h + ATKHLDV EQU 280h + LFO1VAL EQU 2A0h + ATKHLD EQU 2C0h + HLDATK EQU 2C0h + LFO2VAL EQU 2E0h + IP EQU 300h + IFATN EQU 320h + PEFE EQU 340h + FMMOD EQU 360h + TREMFRQ EQU 380h + FM2FRQ2 EQU 3A0h + +ALIGN 4 + +InitTable1 Label + DW 003FFh, 0030h, 007FFh, 0130h, 00BFFh, 0230h, 00FFFh, 0330h + DW 013FFh, 0430h, 017FFh, 0530h, 01BFFh, 0630h, 01FFFh, 0730h + DW 023FFh, 0830h, 027FFh, 0930h, 02BFFh, 0A30h, 02FFFh, 0B30h + DW 033FFh, 0C30h, 037FFh, 0D30h, 03BFFh, 0E30h, 03FFFh, 0F30h + + DW 043FFh, 0030h, 047FFh, 0130h, 04BFFh, 0230h, 04FFFh, 0330h + DW 053FFh, 0430h, 057FFh, 0530h, 05BFFh, 0630h, 05FFFh, 0730h + DW 063FFh, 0830h, 067FFh, 0930h, 06BFFh, 0A30h, 06FFFh, 0B30h + DW 073FFh, 0C30h, 077FFh, 0D30h, 07BFFh, 0E30h, 07FFFh, 0F30h + + DW 083FFh, 0030h, 087FFh, 0130h, 08BFFh, 0230h, 08FFFh, 0330h + DW 093FFh, 0430h, 097FFh, 0530h, 09BFFh, 0630h, 09FFFh, 0730h + DW 0A3FFh, 0830h, 0A7FFh, 0930h, 0ABFFh, 0A30h, 0AFFFh, 0B30h + DW 0B3FFh, 0C30h, 0B7FFh, 0D30h, 0BBFFh, 0E30h, 0BFFFh, 0F30h + + DW 0C3FFh, 0030h, 0C7FFh, 0130h, 0CBFFh, 0230h, 0CFFFh, 0330h + DW 0D3FFh, 0430h, 0D7FFh, 0530h, 0DBFFh, 0630h, 0DFFFh, 0730h + DW 0E3FFh, 0830h, 0E7FFh, 0930h, 0EBFFh, 0A30h, 0EFFFh, 0B30h + DW 0F3FFh, 0C30h, 0F7FFh, 0D30h, 0FBFFh, 0E30h, 0FFFFh, 0F30h + +InitTable2 Label + DW 003FFh, 8030h, 007FFh, 8130h, 00BFFh, 8230h, 00FFFh, 8330h + DW 013FFh, 8430h, 017FFh, 8530h, 01BFFh, 8630h, 01FFFh, 8730h + DW 023FFh, 8830h, 027FFh, 8930h, 02BFFh, 8A30h, 02FFFh, 8B30h + DW 033FFh, 8C30h, 037FFh, 8D30h, 03BFFh, 8E30h, 03FFFh, 8F30h + + DW 043FFh, 8030h, 047FFh, 8130h, 04BFFh, 8230h, 04FFFh, 8330h + DW 053FFh, 8430h, 057FFh, 8530h, 05BFFh, 8630h, 05FFFh, 8730h + DW 063FFh, 8830h, 067FFh, 8930h, 06BFFh, 8A30h, 06FFFh, 8B30h + DW 073FFh, 8C30h, 077FFh, 8D30h, 07BFFh, 8E30h, 07FFFh, 8F30h + + DW 083FFh, 8030h, 087FFh, 8130h, 08BFFh, 8230h, 08FFFh, 8330h + DW 093FFh, 8430h, 097FFh, 8530h, 09BFFh, 8630h, 09FFFh, 8730h + DW 0A3FFh, 8830h, 0A7FFh, 8930h, 0ABFFh, 8A30h, 0AFFFh, 8B30h + DW 0B3FFh, 8C30h, 0B7FFh, 8D30h, 0BBFFh, 8E30h, 0BFFFh, 8F30h + + DW 0C3FFh, 8030h, 0C7FFh, 8130h, 0CBFFh, 8230h, 0CFFFh, 8330h + DW 0D3FFh, 8430h, 0D7FFh, 8530h, 0DBFFh, 8630h, 0DFFFh, 8730h + DW 0E3FFh, 8830h, 0E7FFh, 8930h, 0EBFFh, 8A30h, 0EFFFh, 8B30h + DW 0F3FFh, 8C30h, 0F7FFh, 8D30h, 0FBFFh, 8E30h, 0FFFFh, 8F30h + +InitTable3 Label + DW 0C10h, 8470h, 14FEh, 0B488h, 167Fh, 0A470h, 18E7h, 84B5h + DW 1B6Eh, 842Ah, 1F1Dh, 852Ah, 0DA3h, 8F7Ch, 167Eh, 7254h + DW 0, 842Ah, 1, 852Ah, 18E6h, 8BAAh, 1B6Dh, 7234h + DW 229Fh, 8429h, 2746h, 8529h, 1F1Ch, 86E7h, 229Eh, 7224h + + DW 0DA4h, 8429h, 2C29h, 8529h, 2745h, 87F6h, 2C28h, 7254h + DW 383Bh, 8428h, 320Fh, 8528h, 320Eh, 8F02h, 1341h, 7264h + DW 3EB6h, 8428h, 3EB9h, 8528h, 383Ah, 8FA9h, 3EB5h, 7294h + DW 3EB7h, 8474h, 3EBAh, 8575h, 3EB8h, 0C4C3h, 3EBBh, 45C3h + + DW 00000, 0A404h, 00001, 0A504h, 141Fh, 8671h, 14FDh, 8287h + DW 3EBCh, 0E610h, 3EC8h, 8C7Bh, 31Ah, 87E6h, 3EC8h, 86F7h + DW 3EC0h, 821Eh, 3EBEh, 0D208h, 3EBDh, 821Fh, 3ECAh, 8386h + DW 3EC1h, 8C03h, 3EC9h, 831Eh, 3ECAh, 8C4Ch, 3EBFh, 8C55h + + DW 3EC9h, 0C208h, 3EC4h, 0BC84h, 3EC8h, 8EADh, 3EC8h, 0D308h + DW 3EC2h, 8F7Eh, 3ECBh, 821Eh, 3ECBh, 0D208h, 3EC5h, 831Fh + DW 3EC6h, 0C308h, 3EC3h, 32FFh, 3EC9h, 8265h, 3EC9h, 831Eh + DW 1342h, 0D308h, 3EC7h, 33FFh, 0, 8365h, 1420h, 9570h + +InitTable4 Label + DW 0C10h, 8470h, 14FEh, 0B488h, 167Fh, 0A470h, 18E7h, 84B5h + DW 1B6Eh, 842Ah, 1F1Dh, 852Ah, 0DA3h, 0F7Ch, 167Eh, 7254h + DW 0, 842Ah, 1, 852Ah, 18E6h, 0BAAh, 1B6Dh, 7234h + DW 229Fh, 8429h, 2746h, 8529h, 1F1Ch, 6E7h, 229Eh, 7224h + + DW 0DA4h, 8429h, 2C29h, 8529h, 2745h, 07F6h, 2C28h, 7254h + DW 383Bh, 8428h, 320Fh, 8528h, 320Eh, 0F02h, 1341h, 7264h + DW 3EB6h, 8428h, 3EB9h, 8528h, 383Ah, 0FA9h, 3EB5h, 7294h + DW 3EB7h, 8474h, 3EBAh, 8575h, 3EB8h, 44C3h, 3EBBh, 45C3h + + DW 00000, 0A404h, 00001, 0A504h, 141Fh, 0671h, 14FDh, 287h + DW 3EBCh, 0E610h, 3EC8h, 0C7Bh, 31Ah, 7E6h, 3EC8h, 86F7h + DW 3EC0h, 821Eh, 3EBEh, 0D208h, 3EBDh, 021Fh, 3ECAh, 386h + DW 3EC1h, 0C03h, 3EC9h, 31Eh, 3ECAh, 8C4Ch, 3EBFh, 0C55h + + DW 3EC9h, 0C208h, 3EC4h, 0BC84h, 3EC8h, 0EADh, 3EC8h, 0D308h + DW 3EC2h, 8F7Eh, 3ECBh, 021Eh, 3ECBh, 0D208h, 3EC5h, 31Fh + DW 3EC6h, 0C308h, 3EC3h, 32FFh, 3EC9h, 0265h, 3EC9h, 831Eh + DW 1342h, 0D308h, 3EC7h, 33FFh, 0, 8365h, 1420h, 9570h + +AWEVolumeTable Label Byte ; Value = -log(vol/256)*(20/.375) + ; = -log(vol/256)*(160/3) + + DB 255, 128, 112, 103, 96, 91, 87, 83 ; 0->7 + DB 80, 78, 75, 73, 71, 69, 67, 66 ; 8->15 + DB 64, 63, 61, 60, 59, 58, 57, 56 ; 16->23 + DB 55, 54, 53, 52, 51, 50, 50, 49 ; 24->31 + DB 48, 47, 47, 46, 45, 45, 44, 44 ; 32->39 + DB 43, 42, 42, 41, 41, 40, 40, 39 ; 40->47 + DB 39, 38, 38, 37, 37, 36, 36, 36 ; 48->55 + DB 35, 35, 34, 34, 34, 33, 33, 32 ; 56->63 + DB 32, 32, 31, 31, 31, 30, 30, 30 ; 64->71 + DB 29, 29, 29, 28, 28, 28, 28, 27 ; 72->79 + DB 27, 27, 26, 26, 26, 26, 25, 25 ; 80->87 + DB 25, 25, 24, 24, 24, 23, 23, 23 ; 88->95 + DB 23, 22, 22, 22, 22, 22, 21, 21 ; 96->103 + DB 21, 21, 20, 20, 20, 20, 20, 19 ; 104->111 + DB 19, 19, 19, 19, 18, 18, 18, 18 ; 112->119 + DB 18, 17, 17, 17, 17, 17, 16, 16 ; 120->127 + DB 16 ; 128 + + Comment ~ ; Value = -log(vol/128)*(20/.375) + ; = -log(vol/128)*(160/3) + ; This is mathematically the correct table, but it seems too + ; loud, and it overloads on playback. + + DB 255, 112, 96, 87, 80, 75, 71, 67 ; 0->7 + DB 64, 61, 59, 57, 55, 53, 51, 50 ; 8->15 + DB 48, 47, 45, 44, 43, 42, 41, 40 ; 16->23 + DB 39, 38, 37, 36, 35, 34, 34, 33 ; 24->31 + DB 32, 31, 31, 30, 29, 29, 28, 28 ; 32->39 + DB 27, 26, 26, 25, 25, 24, 24, 23 ; 40->47 + DB 23, 22, 22, 21, 21, 20, 20, 20 ; 48->55 + DB 19, 19, 18, 18, 18, 17, 17, 16 ; 56->63 + DB 16, 16, 15, 15, 15, 14, 14, 14 ; 64->71 + DB 13, 13, 13, 13, 12, 12, 12, 11 ; 72->79 + DB 11, 11, 10, 10, 10, 9, 9, 9 ; 80->87 + DB 9, 8, 8, 8, 8, 7, 7, 7 ; 88->95 + DB 7, 6, 6, 6, 6, 5, 5, 5 ; 96->103 + DB 5, 4, 4, 4, 4, 4, 4, 3 ; 104->111 + DB 3, 3, 3, 2, 2, 2, 2, 2 ; 112->119 + DB 1, 1, 1, 1, 1, 1, 1, 1 ; 120->127 + DB 0 + + ~ + +AWEPitchTable Label DWord ; Pitchval = 88200 * 2^(Pos / 4096) + DD 88200, 88215, 88230, 88245, 88260, 88275, 88290, 88305 + DD 88320, 88335, 88350, 88365, 88380, 88395, 88410, 88425 + DD 88440, 88455, 88470, 88485, 88500, 88514, 88529, 88544 + DD 88559, 88574, 88589, 88604, 88619, 88634, 88649, 88664 + DD 88679, 88694, 88709, 88724, 88739, 88754, 88770, 88785 + DD 88800, 88815, 88830, 88845, 88860, 88875, 88890, 88905 + DD 88920, 88935, 88950, 88965, 88980, 88995, 89010, 89025 + DD 89040, 89055, 89070, 89086, 89101, 89116, 89131, 89146 + DD 89161, 89176, 89191, 89206, 89221, 89236, 89252, 89267 + DD 89282, 89297, 89312, 89327, 89342, 89357, 89372, 89388 + DD 89403, 89418, 89433, 89448, 89463, 89478, 89493, 89509 + DD 89524, 89539, 89554, 89569, 89584, 89600, 89615, 89630 + DD 89645, 89660, 89675, 89691, 89706, 89721, 89736, 89751 + DD 89767, 89782, 89797, 89812, 89827, 89842, 89858, 89873 + DD 89888, 89903, 89919, 89934, 89949, 89964, 89979, 89995 + DD 90010, 90025, 90040, 90056, 90071, 90086, 90101, 90117 + DD 90132, 90147, 90162, 90178, 90193, 90208, 90223, 90239 + DD 90254, 90269, 90284, 90300, 90315, 90330, 90346, 90361 + DD 90376, 90391, 90407, 90422, 90437, 90453, 90468, 90483 + DD 90499, 90514, 90529, 90545, 90560, 90575, 90591, 90606 + DD 90621, 90637, 90652, 90667, 90683, 90698, 90713, 90729 + DD 90744, 90759, 90775, 90790, 90805, 90821, 90836, 90852 + DD 90867, 90882, 90898, 90913, 90928, 90944, 90959, 90975 + DD 90990, 91005, 91021, 91036, 91052, 91067, 91082, 91098 + DD 91113, 91129, 91144, 91160, 91175, 91190, 91206, 91221 + DD 91237, 91252, 91268, 91283, 91299, 91314, 91329, 91345 + DD 91360, 91376, 91391, 91407, 91422, 91438, 91453, 91469 + DD 91484, 91500, 91515, 91531, 91546, 91562, 91577, 91593 + DD 91608, 91624, 91639, 91655, 91670, 91686, 91701, 91717 + DD 91732, 91748, 91763, 91779, 91794, 91810, 91825, 91841 + DD 91856, 91872, 91887, 91903, 91919, 91934, 91950, 91965 + DD 91981, 91996, 92012, 92028, 92043, 92059, 92074, 92090 + DD 92105, 92121, 92137, 92152, 92168, 92183, 92199, 92215 + DD 92230, 92246, 92261, 92277, 92293, 92308, 92324, 92340 + DD 92355, 92371, 92386, 92402, 92418, 92433, 92449, 92465 + DD 92480, 92496, 92512, 92527, 92543, 92559, 92574, 92590 + DD 92606, 92621, 92637, 92653, 92668, 92684, 92700, 92715 + DD 92731, 92747, 92762, 92778, 92794, 92810, 92825, 92841 + DD 92857, 92872, 92888, 92904, 92920, 92935, 92951, 92967 + DD 92982, 92998, 93014, 93030, 93045, 93061, 93077, 93093 + DD 93108, 93124, 93140, 93156, 93171, 93187, 93203, 93219 + DD 93235, 93250, 93266, 93282, 93298, 93313, 93329, 93345 + DD 93361, 93377, 93392, 93408, 93424, 93440, 93456, 93472 + DD 93487, 93503, 93519, 93535, 93551, 93566, 93582, 93598 + DD 93614, 93630, 93646, 93662, 93677, 93693, 93709, 93725 + DD 93741, 93757, 93773, 93788, 93804, 93820, 93836, 93852 + DD 93868, 93884, 93900, 93915, 93931, 93947, 93963, 93979 + DD 93995, 94011, 94027, 94043, 94059, 94075, 94090, 94106 + DD 94122, 94138, 94154, 94170, 94186, 94202, 94218, 94234 + DD 94250, 94266, 94282, 94298, 94314, 94330, 94346, 94362 + DD 94377, 94393, 94409, 94425, 94441, 94457, 94473, 94489 + DD 94505, 94521, 94537, 94553, 94569, 94585, 94601, 94617 + DD 94633, 94649, 94665, 94681, 94697, 94713, 94729, 94746 + DD 94762, 94778, 94794, 94810, 94826, 94842, 94858, 94874 + DD 94890, 94906, 94922, 94938, 94954, 94970, 94986, 95002 + DD 95018, 95035, 95051, 95067, 95083, 95099, 95115, 95131 + DD 95147, 95163, 95179, 95196, 95212, 95228, 95244, 95260 + DD 95276, 95292, 95308, 95324, 95341, 95357, 95373, 95389 + DD 95405, 95421, 95437, 95454, 95470, 95486, 95502, 95518 + DD 95534, 95551, 95567, 95583, 95599, 95615, 95631, 95648 + DD 95664, 95680, 95696, 95712, 95729, 95745, 95761, 95777 + DD 95793, 95810, 95826, 95842, 95858, 95875, 95891, 95907 + DD 95923, 95939, 95956, 95972, 95988, 96004, 96021, 96037 + DD 96053, 96069, 96086, 96102, 96118, 96134, 96151, 96167 + DD 96183, 96200, 96216, 96232, 96248, 96265, 96281, 96297 + DD 96314, 96330, 96346, 96362, 96379, 96395, 96411, 96428 + DD 96444, 96460, 96477, 96493, 96509, 96526, 96542, 96558 + DD 96575, 96591, 96607, 96624, 96640, 96656, 96673, 96689 + DD 96706, 96722, 96738, 96755, 96771, 96787, 96804, 96820 + DD 96837, 96853, 96869, 96886, 96902, 96919, 96935, 96951 + DD 96968, 96984, 97001, 97017, 97033, 97050, 97066, 97083 + DD 97099, 97116, 97132, 97148, 97165, 97181, 97198, 97214 + DD 97231, 97247, 97264, 97280, 97296, 97313, 97329, 97346 + DD 97362, 97379, 97395, 97412, 97428, 97445, 97461, 97478 + DD 97494, 97511, 97527, 97544, 97560, 97577, 97593, 97610 + DD 97626, 97643, 97659, 97676, 97692, 97709, 97726, 97742 + DD 97759, 97775, 97792, 97808, 97825, 97841, 97858, 97874 + DD 97891, 97908, 97924, 97941, 97957, 97974, 97990, 98007 + DD 98024, 98040, 98057, 98073, 98090, 98107, 98123, 98140 + DD 98156, 98173, 98190, 98206, 98223, 98240, 98256, 98273 + DD 98289, 98306, 98323, 98339, 98356, 98373, 98389, 98406 + DD 98423, 98439, 98456, 98473, 98489, 98506, 98523, 98539 + DD 98556, 98573, 98589, 98606, 98623, 98639, 98656, 98673 + DD 98689, 98706, 98723, 98740, 98756, 98773, 98790, 98806 + DD 98823, 98840, 98857, 98873, 98890, 98907, 98924, 98940 + DD 98957, 98974, 98990, 99007, 99024, 99041, 99058, 99074 + DD 99091, 99108, 99125, 99141, 99158, 99175, 99192, 99208 + DD 99225, 99242, 99259, 99276, 99292, 99309, 99326, 99343 + DD 99360, 99377, 99393, 99410, 99427, 99444, 99461, 99477 + DD 99494, 99511, 99528, 99545, 99562, 99579, 99595, 99612 + DD 99629, 99646, 99663, 99680, 99697, 99713, 99730, 99747 + DD 99764, 99781, 99798, 99815, 99832, 99849, 99865, 99882 + DD 99899, 99916, 99933, 99950, 99967, 99984, 100001, 100018 + DD 100035, 100051, 100068, 100085, 100102, 100119, 100136, 100153 + DD 100170, 100187, 100204, 100221, 100238, 100255, 100272, 100289 + DD 100306, 100323, 100340, 100357, 100374, 100391, 100408, 100425 + DD 100442, 100459, 100476, 100493, 100510, 100527, 100544, 100561 + DD 100578, 100595, 100612, 100629, 100646, 100663, 100680, 100697 + DD 100714, 100731, 100748, 100765, 100782, 100799, 100816, 100833 + DD 100850, 100867, 100885, 100902, 100919, 100936, 100953, 100970 + DD 100987, 101004, 101021, 101038, 101055, 101073, 101090, 101107 + DD 101124, 101141, 101158, 101175, 101192, 101209, 101227, 101244 + DD 101261, 101278, 101295, 101312, 101329, 101347, 101364, 101381 + DD 101398, 101415, 101432, 101450, 101467, 101484, 101501, 101518 + DD 101535, 101553, 101570, 101587, 101604, 101621, 101639, 101656 + DD 101673, 101690, 101707, 101725, 101742, 101759, 101776, 101793 + DD 101811, 101828, 101845, 101862, 101880, 101897, 101914, 101931 + DD 101949, 101966, 101983, 102000, 102018, 102035, 102052, 102069 + DD 102087, 102104, 102121, 102139, 102156, 102173, 102190, 102208 + DD 102225, 102242, 102260, 102277, 102294, 102312, 102329, 102346 + DD 102363, 102381, 102398, 102415, 102433, 102450, 102467, 102485 + DD 102502, 102520, 102537, 102554, 102572, 102589, 102606, 102624 + DD 102641, 102658, 102676, 102693, 102711, 102728, 102745, 102763 + DD 102780, 102797, 102815, 102832, 102850, 102867, 102884, 102902 + DD 102919, 102937, 102954, 102972, 102989, 103006, 103024, 103041 + DD 103059, 103076, 103094, 103111, 103129, 103146, 103163, 103181 + DD 103198, 103216, 103233, 103251, 103268, 103286, 103303, 103321 + DD 103338, 103356, 103373, 103391, 103408, 103426, 103443, 103461 + DD 103478, 103496, 103513, 103531, 103548, 103566, 103583, 103601 + DD 103618, 103636, 103653, 103671, 103689, 103706, 103724, 103741 + DD 103759, 103776, 103794, 103811, 103829, 103847, 103864, 103882 + DD 103899, 103917, 103934, 103952, 103970, 103987, 104005, 104022 + DD 104040, 104058, 104075, 104093, 104110, 104128, 104146, 104163 + DD 104181, 104199, 104216, 104234, 104252, 104269, 104287, 104304 + DD 104322, 104340, 104357, 104375, 104393, 104410, 104428, 104446 + DD 104463, 104481, 104499, 104516, 104534, 104552, 104570, 104587 + DD 104605, 104623, 104640, 104658, 104676, 104694, 104711, 104729 + DD 104747, 104764, 104782, 104800, 104818, 104835, 104853, 104871 + DD 104889, 104906, 104924, 104942, 104960, 104977, 104995, 105013 + DD 105031, 105048, 105066, 105084, 105102, 105120, 105137, 105155 + DD 105173, 105191, 105209, 105226, 105244, 105262, 105280, 105298 + DD 105315, 105333, 105351, 105369, 105387, 105405, 105422, 105440 + DD 105458, 105476, 105494, 105512, 105530, 105547, 105565, 105583 + DD 105601, 105619, 105637, 105655, 105672, 105690, 105708, 105726 + DD 105744, 105762, 105780, 105798, 105816, 105834, 105851, 105869 + DD 105887, 105905, 105923, 105941, 105959, 105977, 105995, 106013 + DD 106031, 106049, 106067, 106085, 106103, 106120, 106138, 106156 + DD 106174, 106192, 106210, 106228, 106246, 106264, 106282, 106300 + DD 106318, 106336, 106354, 106372, 106390, 106408, 106426, 106444 + DD 106462, 106480, 106498, 106516, 106534, 106552, 106570, 106588 + DD 106606, 106624, 106643, 106661, 106679, 106697, 106715, 106733 + DD 106751, 106769, 106787, 106805, 106823, 106841, 106859, 106877 + DD 106895, 106914, 106932, 106950, 106968, 106986, 107004, 107022 + DD 107040, 107058, 107077, 107095, 107113, 107131, 107149, 107167 + DD 107185, 107203, 107222, 107240, 107258, 107276, 107294, 107312 + DD 107331, 107349, 107367, 107385, 107403, 107421, 107440, 107458 + DD 107476, 107494, 107512, 107531, 107549, 107567, 107585, 107603 + DD 107622, 107640, 107658, 107676, 107694, 107713, 107731, 107749 + DD 107767, 107786, 107804, 107822, 107840, 107859, 107877, 107895 + DD 107913, 107932, 107950, 107968, 107986, 108005, 108023, 108041 + DD 108060, 108078, 108096, 108114, 108133, 108151, 108169, 108188 + DD 108206, 108224, 108243, 108261, 108279, 108297, 108316, 108334 + DD 108352, 108371, 108389, 108408, 108426, 108444, 108463, 108481 + DD 108499, 108518, 108536, 108554, 108573, 108591, 108609, 108628 + DD 108646, 108665, 108683, 108701, 108720, 108738, 108757, 108775 + DD 108793, 108812, 108830, 108849, 108867, 108886, 108904, 108922 + DD 108941, 108959, 108978, 108996, 109015, 109033, 109051, 109070 + DD 109088, 109107, 109125, 109144, 109162, 109181, 109199, 109218 + DD 109236, 109255, 109273, 109292, 109310, 109329, 109347, 109366 + DD 109384, 109403, 109421, 109440, 109458, 109477, 109495, 109514 + DD 109532, 109551, 109569, 109588, 109607, 109625, 109644, 109662 + DD 109681, 109699, 109718, 109736, 109755, 109774, 109792, 109811 + DD 109829, 109848, 109867, 109885, 109904, 109922, 109941, 109960 + DD 109978, 109997, 110015, 110034, 110053, 110071, 110090, 110108 + DD 110127, 110146, 110164, 110183, 110202, 110220, 110239, 110258 + DD 110276, 110295, 110314, 110332, 110351, 110370, 110388, 110407 + DD 110426, 110444, 110463, 110482, 110500, 110519, 110538, 110557 + DD 110575, 110594, 110613, 110631, 110650, 110669, 110688, 110706 + DD 110725, 110744, 110763, 110781, 110800, 110819, 110838, 110856 + DD 110875, 110894, 110913, 110931, 110950, 110969, 110988, 111007 + DD 111025, 111044, 111063, 111082, 111100, 111119, 111138, 111157 + DD 111176, 111195, 111213, 111232, 111251, 111270, 111289, 111307 + DD 111326, 111345, 111364, 111383, 111402, 111421, 111439, 111458 + DD 111477, 111496, 111515, 111534, 111553, 111571, 111590, 111609 + DD 111628, 111647, 111666, 111685, 111704, 111723, 111742, 111760 + DD 111779, 111798, 111817, 111836, 111855, 111874, 111893, 111912 + DD 111931, 111950, 111969, 111988, 112007, 112026, 112045, 112063 + DD 112082, 112101, 112120, 112139, 112158, 112177, 112196, 112215 + DD 112234, 112253, 112272, 112291, 112310, 112329, 112348, 112367 + DD 112386, 112405, 112424, 112443, 112462, 112481, 112500, 112520 + DD 112539, 112558, 112577, 112596, 112615, 112634, 112653, 112672 + DD 112691, 112710, 112729, 112748, 112767, 112786, 112806, 112825 + DD 112844, 112863, 112882, 112901, 112920, 112939, 112958, 112977 + DD 112997, 113016, 113035, 113054, 113073, 113092, 113111, 113130 + DD 113150, 113169, 113188, 113207, 113226, 113245, 113265, 113284 + DD 113303, 113322, 113341, 113360, 113380, 113399, 113418, 113437 + DD 113456, 113476, 113495, 113514, 113533, 113552, 113572, 113591 + DD 113610, 113629, 113649, 113668, 113687, 113706, 113726, 113745 + DD 113764, 113783, 113803, 113822, 113841, 113860, 113880, 113899 + DD 113918, 113937, 113957, 113976, 113995, 114015, 114034, 114053 + DD 114072, 114092, 114111, 114130, 114150, 114169, 114188, 114208 + DD 114227, 114246, 114266, 114285, 114304, 114324, 114343, 114362 + DD 114382, 114401, 114420, 114440, 114459, 114479, 114498, 114517 + DD 114537, 114556, 114575, 114595, 114614, 114634, 114653, 114672 + DD 114692, 114711, 114731, 114750, 114770, 114789, 114808, 114828 + DD 114847, 114867, 114886, 114906, 114925, 114944, 114964, 114983 + DD 115003, 115022, 115042, 115061, 115081, 115100, 115120, 115139 + DD 115159, 115178, 115198, 115217, 115237, 115256, 115276, 115295 + DD 115315, 115334, 115354, 115373, 115393, 115412, 115432, 115451 + DD 115471, 115490, 115510, 115529, 115549, 115569, 115588, 115608 + DD 115627, 115647, 115666, 115686, 115706, 115725, 115745, 115764 + DD 115784, 115804, 115823, 115843, 115862, 115882, 115902, 115921 + DD 115941, 115960, 115980, 116000, 116019, 116039, 116059, 116078 + DD 116098, 116117, 116137, 116157, 116176, 116196, 116216, 116235 + DD 116255, 116275, 116294, 116314, 116334, 116354, 116373, 116393 + DD 116413, 116432, 116452, 116472, 116491, 116511, 116531, 116551 + DD 116570, 116590, 116610, 116630, 116649, 116669, 116689, 116708 + DD 116728, 116748, 116768, 116788, 116807, 116827, 116847, 116867 + DD 116886, 116906, 116926, 116946, 116966, 116985, 117005, 117025 + DD 117045, 117065, 117084, 117104, 117124, 117144, 117164, 117183 + DD 117203, 117223, 117243, 117263, 117283, 117302, 117322, 117342 + DD 117362, 117382, 117402, 117422, 117442, 117461, 117481, 117501 + DD 117521, 117541, 117561, 117581, 117601, 117621, 117640, 117660 + DD 117680, 117700, 117720, 117740, 117760, 117780, 117800, 117820 + DD 117840, 117860, 117880, 117900, 117919, 117939, 117959, 117979 + DD 117999, 118019, 118039, 118059, 118079, 118099, 118119, 118139 + DD 118159, 118179, 118199, 118219, 118239, 118259, 118279, 118299 + DD 118319, 118339, 118359, 118379, 118399, 118419, 118439, 118459 + DD 118480, 118500, 118520, 118540, 118560, 118580, 118600, 118620 + DD 118640, 118660, 118680, 118700, 118720, 118740, 118761, 118781 + DD 118801, 118821, 118841, 118861, 118881, 118901, 118921, 118942 + DD 118962, 118982, 119002, 119022, 119042, 119062, 119083, 119103 + DD 119123, 119143, 119163, 119183, 119204, 119224, 119244, 119264 + DD 119284, 119304, 119325, 119345, 119365, 119385, 119405, 119426 + DD 119446, 119466, 119486, 119506, 119527, 119547, 119567, 119587 + DD 119608, 119628, 119648, 119668, 119689, 119709, 119729, 119749 + DD 119770, 119790, 119810, 119831, 119851, 119871, 119891, 119912 + DD 119932, 119952, 119973, 119993, 120013, 120033, 120054, 120074 + DD 120094, 120115, 120135, 120155, 120176, 120196, 120216, 120237 + DD 120257, 120277, 120298, 120318, 120339, 120359, 120379, 120400 + DD 120420, 120440, 120461, 120481, 120502, 120522, 120542, 120563 + DD 120583, 120604, 120624, 120644, 120665, 120685, 120706, 120726 + DD 120747, 120767, 120787, 120808, 120828, 120849, 120869, 120890 + DD 120910, 120931, 120951, 120971, 120992, 121012, 121033, 121053 + DD 121074, 121094, 121115, 121135, 121156, 121176, 121197, 121217 + DD 121238, 121258, 121279, 121299, 121320, 121341, 121361, 121382 + DD 121402, 121423, 121443, 121464, 121484, 121505, 121525, 121546 + DD 121567, 121587, 121608, 121628, 121649, 121670, 121690, 121711 + DD 121731, 121752, 121773, 121793, 121814, 121834, 121855, 121876 + DD 121896, 121917, 121937, 121958, 121979, 121999, 122020, 122041 + DD 122061, 122082, 122103, 122123, 122144, 122165, 122185, 122206 + DD 122227, 122247, 122268, 122289, 122309, 122330, 122351, 122372 + DD 122392, 122413, 122434, 122454, 122475, 122496, 122517, 122537 + DD 122558, 122579, 122600, 122620, 122641, 122662, 122683, 122703 + DD 122724, 122745, 122766, 122786, 122807, 122828, 122849, 122870 + DD 122890, 122911, 122932, 122953, 122974, 122994, 123015, 123036 + DD 123057, 123078, 123099, 123119, 123140, 123161, 123182, 123203 + DD 123224, 123244, 123265, 123286, 123307, 123328, 123349, 123370 + DD 123391, 123411, 123432, 123453, 123474, 123495, 123516, 123537 + DD 123558, 123579, 123599, 123620, 123641, 123662, 123683, 123704 + DD 123725, 123746, 123767, 123788, 123809, 123830, 123851, 123872 + DD 123893, 123914, 123935, 123956, 123977, 123998, 124019, 124040 + DD 124061, 124081, 124102, 124124, 124145, 124166, 124187, 124208 + DD 124229, 124250, 124271, 124292, 124313, 124334, 124355, 124376 + DD 124397, 124418, 124439, 124460, 124481, 124502, 124523, 124544 + DD 124565, 124586, 124608, 124629, 124650, 124671, 124692, 124713 + DD 124734, 124755, 124776, 124797, 124819, 124840, 124861, 124882 + DD 124903, 124924, 124945, 124967, 124988, 125009, 125030, 125051 + DD 125072, 125093, 125115, 125136, 125157, 125178, 125199, 125221 + DD 125242, 125263, 125284, 125305, 125327, 125348, 125369, 125390 + DD 125411, 125433, 125454, 125475, 125496, 125518, 125539, 125560 + DD 125581, 125603, 125624, 125645, 125666, 125688, 125709, 125730 + DD 125751, 125773, 125794, 125815, 125837, 125858, 125879, 125901 + DD 125922, 125943, 125964, 125986, 126007, 126028, 126050, 126071 + DD 126092, 126114, 126135, 126156, 126178, 126199, 126220, 126242 + DD 126263, 126285, 126306, 126327, 126349, 126370, 126391, 126413 + DD 126434, 126456, 126477, 126498, 126520, 126541, 126563, 126584 + DD 126606, 126627, 126648, 126670, 126691, 126713, 126734, 126756 + DD 126777, 126799, 126820, 126841, 126863, 126884, 126906, 126927 + DD 126949, 126970, 126992, 127013, 127035, 127056, 127078, 127099 + DD 127121, 127142, 127164, 127185, 127207, 127228, 127250, 127271 + DD 127293, 127315, 127336, 127358, 127379, 127401, 127422, 127444 + DD 127465, 127487, 127509, 127530, 127552, 127573, 127595, 127617 + DD 127638, 127660, 127681, 127703, 127725, 127746, 127768, 127789 + DD 127811, 127833, 127854, 127876, 127898, 127919, 127941, 127963 + DD 127984, 128006, 128028, 128049, 128071, 128093, 128114, 128136 + DD 128158, 128179, 128201, 128223, 128244, 128266, 128288, 128309 + DD 128331, 128353, 128375, 128396, 128418, 128440, 128462, 128483 + DD 128505, 128527, 128549, 128570, 128592, 128614, 128636, 128657 + DD 128679, 128701, 128723, 128744, 128766, 128788, 128810, 128832 + DD 128853, 128875, 128897, 128919, 128941, 128963, 128984, 129006 + DD 129028, 129050, 129072, 129094, 129115, 129137, 129159, 129181 + DD 129203, 129225, 129247, 129268, 129290, 129312, 129334, 129356 + DD 129378, 129400, 129422, 129444, 129465, 129487, 129509, 129531 + DD 129553, 129575, 129597, 129619, 129641, 129663, 129685, 129707 + DD 129729, 129751, 129773, 129794, 129816, 129838, 129860, 129882 + DD 129904, 129926, 129948, 129970, 129992, 130014, 130036, 130058 + DD 130080, 130102, 130124, 130146, 130168, 130190, 130212, 130235 + DD 130257, 130279, 130301, 130323, 130345, 130367, 130389, 130411 + DD 130433, 130455, 130477, 130499, 130521, 130543, 130566, 130588 + DD 130610, 130632, 130654, 130676, 130698, 130720, 130742, 130765 + DD 130787, 130809, 130831, 130853, 130875, 130897, 130920, 130942 + DD 130964, 130986, 131008, 131030, 131053, 131075, 131097, 131119 + DD 131141, 131163, 131186, 131208, 131230, 131252, 131274, 131297 + DD 131319, 131341, 131363, 131386, 131408, 131430, 131452, 131475 + DD 131497, 131519, 131541, 131564, 131586, 131608, 131630, 131653 + DD 131675, 131697, 131720, 131742, 131764, 131786, 131809, 131831 + DD 131853, 131876, 131898, 131920, 131943, 131965, 131987, 132010 + DD 132032, 132054, 132077, 132099, 132121, 132144, 132166, 132188 + DD 132211, 132233, 132256, 132278, 132300, 132323, 132345, 132368 + DD 132390, 132412, 132435, 132457, 132480, 132502, 132524, 132547 + DD 132569, 132592, 132614, 132637, 132659, 132682, 132704, 132726 + DD 132749, 132771, 132794, 132816, 132839, 132861, 132884, 132906 + DD 132929, 132951, 132974, 132996, 133019, 133041, 133064, 133086 + DD 133109, 133131, 133154, 133176, 133199, 133221, 133244, 133267 + DD 133289, 133312, 133334, 133357, 133379, 133402, 133425, 133447 + DD 133470, 133492, 133515, 133537, 133560, 133583, 133605, 133628 + DD 133651, 133673, 133696, 133718, 133741, 133764, 133786, 133809 + DD 133832, 133854, 133877, 133900, 133922, 133945, 133968, 133990 + DD 134013, 134036, 134058, 134081, 134104, 134126, 134149, 134172 + DD 134194, 134217, 134240, 134263, 134285, 134308, 134331, 134353 + DD 134376, 134399, 134422, 134444, 134467, 134490, 134513, 134535 + DD 134558, 134581, 134604, 134627, 134649, 134672, 134695, 134718 + DD 134741, 134763, 134786, 134809, 134832, 134855, 134877, 134900 + DD 134923, 134946, 134969, 134992, 135014, 135037, 135060, 135083 + DD 135106, 135129, 135152, 135174, 135197, 135220, 135243, 135266 + DD 135289, 135312, 135335, 135358, 135381, 135403, 135426, 135449 + DD 135472, 135495, 135518, 135541, 135564, 135587, 135610, 135633 + DD 135656, 135679, 135702, 135725, 135748, 135771, 135794, 135816 + DD 135839, 135862, 135885, 135908, 135931, 135954, 135977, 136000 + DD 136023, 136047, 136070, 136093, 136116, 136139, 136162, 136185 + DD 136208, 136231, 136254, 136277, 136300, 136323, 136346, 136369 + DD 136392, 136415, 136438, 136462, 136485, 136508, 136531, 136554 + DD 136577, 136600, 136623, 136646, 136670, 136693, 136716, 136739 + DD 136762, 136785, 136808, 136832, 136855, 136878, 136901, 136924 + DD 136947, 136971, 136994, 137017, 137040, 137063, 137086, 137110 + DD 137133, 137156, 137179, 137203, 137226, 137249, 137272, 137295 + DD 137319, 137342, 137365, 137388, 137412, 137435, 137458, 137481 + DD 137505, 137528, 137551, 137575, 137598, 137621, 137644, 137668 + DD 137691, 137714, 137738, 137761, 137784, 137808, 137831, 137854 + DD 137877, 137901, 137924, 137948, 137971, 137994, 138018, 138041 + DD 138064, 138088, 138111, 138134, 138158, 138181, 138205, 138228 + DD 138251, 138275, 138298, 138322, 138345, 138368, 138392, 138415 + DD 138439, 138462, 138485, 138509, 138532, 138556, 138579, 138603 + DD 138626, 138650, 138673, 138697, 138720, 138744, 138767, 138790 + DD 138814, 138837, 138861, 138884, 138908, 138931, 138955, 138978 + DD 139002, 139026, 139049, 139073, 139096, 139120, 139143, 139167 + DD 139190, 139214, 139237, 139261, 139285, 139308, 139332, 139355 + DD 139379, 139402, 139426, 139450, 139473, 139497, 139520, 139544 + DD 139568, 139591, 139615, 139639, 139662, 139686, 139709, 139733 + DD 139757, 139780, 139804, 139828, 139851, 139875, 139899, 139922 + DD 139946, 139970, 139993, 140017, 140041, 140065, 140088, 140112 + DD 140136, 140159, 140183, 140207, 140231, 140254, 140278, 140302 + DD 140326, 140349, 140373, 140397, 140421, 140444, 140468, 140492 + DD 140516, 140539, 140563, 140587, 140611, 140635, 140658, 140682 + DD 140706, 140730, 140754, 140777, 140801, 140825, 140849, 140873 + DD 140897, 140920, 140944, 140968, 140992, 141016, 141040, 141064 + DD 141087, 141111, 141135, 141159, 141183, 141207, 141231, 141255 + DD 141279, 141303, 141326, 141350, 141374, 141398, 141422, 141446 + DD 141470, 141494, 141518, 141542, 141566, 141590, 141614, 141638 + DD 141662, 141686, 141710, 141734, 141758, 141782, 141806, 141830 + DD 141854, 141878, 141902, 141926, 141950, 141974, 141998, 142022 + DD 142046, 142070, 142094, 142118, 142142, 142166, 142190, 142214 + DD 142238, 142262, 142286, 142310, 142334, 142359, 142383, 142407 + DD 142431, 142455, 142479, 142503, 142527, 142551, 142576, 142600 + DD 142624, 142648, 142672, 142696, 142720, 142745, 142769, 142793 + DD 142817, 142841, 142865, 142890, 142914, 142938, 142962, 142986 + DD 143011, 143035, 143059, 143083, 143107, 143132, 143156, 143180 + DD 143204, 143228, 143253, 143277, 143301, 143325, 143350, 143374 + DD 143398, 143423, 143447, 143471, 143495, 143520, 143544, 143568 + DD 143593, 143617, 143641, 143665, 143690, 143714, 143738, 143763 + DD 143787, 143811, 143836, 143860, 143884, 143909, 143933, 143957 + DD 143982, 144006, 144031, 144055, 144079, 144104, 144128, 144152 + DD 144177, 144201, 144226, 144250, 144275, 144299, 144323, 144348 + DD 144372, 144397, 144421, 144446, 144470, 144494, 144519, 144543 + DD 144568, 144592, 144617, 144641, 144666, 144690, 144715, 144739 + DD 144764, 144788, 144813, 144837, 144862, 144886, 144911, 144935 + DD 144960, 144984, 145009, 145033, 145058, 145082, 145107, 145132 + DD 145156, 145181, 145205, 145230, 145254, 145279, 145304, 145328 + DD 145353, 145377, 145402, 145427, 145451, 145476, 145500, 145525 + DD 145550, 145574, 145599, 145624, 145648, 145673, 145698, 145722 + DD 145747, 145772, 145796, 145821, 145846, 145870, 145895, 145920 + DD 145944, 145969, 145994, 146018, 146043, 146068, 146093, 146117 + DD 146142, 146167, 146191, 146216, 146241, 146266, 146290, 146315 + DD 146340, 146365, 146390, 146414, 146439, 146464, 146489, 146513 + DD 146538, 146563, 146588, 146613, 146637, 146662, 146687, 146712 + DD 146737, 146762, 146786, 146811, 146836, 146861, 146886, 146911 + DD 146936, 146960, 146985, 147010, 147035, 147060, 147085, 147110 + DD 147135, 147160, 147184, 147209, 147234, 147259, 147284, 147309 + DD 147334, 147359, 147384, 147409, 147434, 147459, 147484, 147509 + DD 147534, 147559, 147583, 147608, 147633, 147658, 147683, 147708 + DD 147733, 147758, 147783, 147808, 147833, 147858, 147883, 147909 + DD 147934, 147959, 147984, 148009, 148034, 148059, 148084, 148109 + DD 148134, 148159, 148184, 148209, 148234, 148259, 148284, 148310 + DD 148335, 148360, 148385, 148410, 148435, 148460, 148485, 148510 + DD 148536, 148561, 148586, 148611, 148636, 148661, 148686, 148712 + DD 148737, 148762, 148787, 148812, 148838, 148863, 148888, 148913 + DD 148938, 148964, 148989, 149014, 149039, 149064, 149090, 149115 + DD 149140, 149165, 149191, 149216, 149241, 149266, 149292, 149317 + DD 149342, 149367, 149393, 149418, 149443, 149469, 149494, 149519 + DD 149544, 149570, 149595, 149620, 149646, 149671, 149696, 149722 + DD 149747, 149772, 149798, 149823, 149848, 149874, 149899, 149925 + DD 149950, 149975, 150001, 150026, 150051, 150077, 150102, 150128 + DD 150153, 150178, 150204, 150229, 150255, 150280, 150306, 150331 + DD 150356, 150382, 150407, 150433, 150458, 150484, 150509, 150535 + DD 150560, 150586, 150611, 150637, 150662, 150688, 150713, 150739 + DD 150764, 150790, 150815, 150841, 150866, 150892, 150917, 150943 + DD 150968, 150994, 151019, 151045, 151071, 151096, 151122, 151147 + DD 151173, 151198, 151224, 151250, 151275, 151301, 151326, 151352 + DD 151378, 151403, 151429, 151455, 151480, 151506, 151531, 151557 + DD 151583, 151608, 151634, 151660, 151685, 151711, 151737, 151762 + DD 151788, 151814, 151839, 151865, 151891, 151917, 151942, 151968 + DD 151994, 152019, 152045, 152071, 152097, 152122, 152148, 152174 + DD 152200, 152225, 152251, 152277, 152303, 152328, 152354, 152380 + DD 152406, 152432, 152457, 152483, 152509, 152535, 152561, 152586 + DD 152612, 152638, 152664, 152690, 152716, 152741, 152767, 152793 + DD 152819, 152845, 152871, 152897, 152922, 152948, 152974, 153000 + DD 153026, 153052, 153078, 153104, 153130, 153156, 153181, 153207 + DD 153233, 153259, 153285, 153311, 153337, 153363, 153389, 153415 + DD 153441, 153467, 153493, 153519, 153545, 153571, 153597, 153623 + DD 153649, 153675, 153701, 153727, 153753, 153779, 153805, 153831 + DD 153857, 153883, 153909, 153935, 153961, 153987, 154013, 154039 + DD 154065, 154091, 154118, 154144, 154170, 154196, 154222, 154248 + DD 154274, 154300, 154326, 154352, 154379, 154405, 154431, 154457 + DD 154483, 154509, 154535, 154562, 154588, 154614, 154640, 154666 + DD 154692, 154719, 154745, 154771, 154797, 154823, 154850, 154876 + DD 154902, 154928, 154954, 154981, 155007, 155033, 155059, 155086 + DD 155112, 155138, 155164, 155191, 155217, 155243, 155269, 155296 + DD 155322, 155348, 155374, 155401, 155427, 155453, 155480, 155506 + DD 155532, 155559, 155585, 155611, 155638, 155664, 155690, 155717 + DD 155743, 155769, 155796, 155822, 155848, 155875, 155901, 155928 + DD 155954, 155980, 156007, 156033, 156060, 156086, 156112, 156139 + DD 156165, 156192, 156218, 156245, 156271, 156297, 156324, 156350 + DD 156377, 156403, 156430, 156456, 156483, 156509, 156536, 156562 + DD 156589, 156615, 156642, 156668, 156695, 156721, 156748, 156774 + DD 156801, 156827, 156854, 156880, 156907, 156934, 156960, 156987 + DD 157013, 157040, 157066, 157093, 157120, 157146, 157173, 157199 + DD 157226, 157253, 157279, 157306, 157332, 157359, 157386, 157412 + DD 157439, 157466, 157492, 157519, 157546, 157572, 157599, 157626 + DD 157652, 157679, 157706, 157732, 157759, 157786, 157812, 157839 + DD 157866, 157893, 157919, 157946, 157973, 157999, 158026, 158053 + DD 158080, 158106, 158133, 158160, 158187, 158213, 158240, 158267 + DD 158294, 158321, 158347, 158374, 158401, 158428, 158455, 158481 + DD 158508, 158535, 158562, 158589, 158616, 158642, 158669, 158696 + DD 158723, 158750, 158777, 158804, 158830, 158857, 158884, 158911 + DD 158938, 158965, 158992, 159019, 159046, 159073, 159100, 159126 + DD 159153, 159180, 159207, 159234, 159261, 159288, 159315, 159342 + DD 159369, 159396, 159423, 159450, 159477, 159504, 159531, 159558 + DD 159585, 159612, 159639, 159666, 159693, 159720, 159747, 159774 + DD 159801, 159828, 159855, 159882, 159909, 159936, 159963, 159990 + DD 160018, 160045, 160072, 160099, 160126, 160153, 160180, 160207 + DD 160234, 160261, 160289, 160316, 160343, 160370, 160397, 160424 + DD 160451, 160479, 160506, 160533, 160560, 160587, 160614, 160642 + DD 160669, 160696, 160723, 160750, 160778, 160805, 160832, 160859 + DD 160886, 160914, 160941, 160968, 160995, 161023, 161050, 161077 + DD 161104, 161132, 161159, 161186, 161213, 161241, 161268, 161295 + DD 161323, 161350, 161377, 161405, 161432, 161459, 161487, 161514 + DD 161541, 161569, 161596, 161623, 161651, 161678, 161705, 161733 + DD 161760, 161787, 161815, 161842, 161870, 161897, 161924, 161952 + DD 161979, 162007, 162034, 162061, 162089, 162116, 162144, 162171 + DD 162199, 162226, 162253, 162281, 162308, 162336, 162363, 162391 + DD 162418, 162446, 162473, 162501, 162528, 162556, 162583, 162611 + DD 162638, 162666, 162693, 162721, 162748, 162776, 162804, 162831 + DD 162859, 162886, 162914, 162941, 162969, 162997, 163024, 163052 + DD 163079, 163107, 163135, 163162, 163190, 163217, 163245, 163273 + DD 163300, 163328, 163356, 163383, 163411, 163438, 163466, 163494 + DD 163521, 163549, 163577, 163604, 163632, 163660, 163688, 163715 + DD 163743, 163771, 163798, 163826, 163854, 163882, 163909, 163937 + DD 163965, 163993, 164020, 164048, 164076, 164104, 164131, 164159 + DD 164187, 164215, 164243, 164270, 164298, 164326, 164354, 164382 + DD 164409, 164437, 164465, 164493, 164521, 164549, 164576, 164604 + DD 164632, 164660, 164688, 164716, 164744, 164771, 164799, 164827 + DD 164855, 164883, 164911, 164939, 164967, 164995, 165023, 165051 + DD 165078, 165106, 165134, 165162, 165190, 165218, 165246, 165274 + DD 165302, 165330, 165358, 165386, 165414, 165442, 165470, 165498 + DD 165526, 165554, 165582, 165610, 165638, 165666, 165694, 165722 + DD 165750, 165778, 165806, 165834, 165862, 165891, 165919, 165947 + DD 165975, 166003, 166031, 166059, 166087, 166115, 166143, 166172 + DD 166200, 166228, 166256, 166284, 166312, 166340, 166368, 166397 + DD 166425, 166453, 166481, 166509, 166538, 166566, 166594, 166622 + DD 166650, 166678, 166707, 166735, 166763, 166791, 166820, 166848 + DD 166876, 166904, 166933, 166961, 166989, 167017, 167046, 167074 + DD 167102, 167130, 167159, 167187, 167215, 167244, 167272, 167300 + DD 167328, 167357, 167385, 167413, 167442, 167470, 167498, 167527 + DD 167555, 167584, 167612, 167640, 167669, 167697, 167725, 167754 + DD 167782, 167811, 167839, 167867, 167896, 167924, 167953, 167981 + DD 168009, 168038, 168066, 168095, 168123, 168152, 168180, 168209 + DD 168237, 168266, 168294, 168322, 168351, 168379, 168408, 168436 + DD 168465, 168493, 168522, 168551, 168579, 168608, 168636, 168665 + DD 168693, 168722, 168750, 168779, 168807, 168836, 168865, 168893 + DD 168922, 168950, 168979, 169007, 169036, 169065, 169093, 169122 + DD 169151, 169179, 169208, 169236, 169265, 169294, 169322, 169351 + DD 169380, 169408, 169437, 169466, 169494, 169523, 169552, 169580 + DD 169609, 169638, 169667, 169695, 169724, 169753, 169781, 169810 + DD 169839, 169868, 169896, 169925, 169954, 169983, 170011, 170040 + DD 170069, 170098, 170127, 170155, 170184, 170213, 170242, 170271 + DD 170299, 170328, 170357, 170386, 170415, 170444, 170472, 170501 + DD 170530, 170559, 170588, 170617, 170646, 170674, 170703, 170732 + DD 170761, 170790, 170819, 170848, 170877, 170906, 170935, 170964 + DD 170992, 171021, 171050, 171079, 171108, 171137, 171166, 171195 + DD 171224, 171253, 171282, 171311, 171340, 171369, 171398, 171427 + DD 171456, 171485, 171514, 171543, 171572, 171601, 171630, 171659 + DD 171688, 171717, 171746, 171776, 171805, 171834, 171863, 171892 + DD 171921, 171950, 171979, 172008, 172037, 172066, 172096, 172125 + DD 172154, 172183, 172212, 172241, 172270, 172300, 172329, 172358 + DD 172387, 172416, 172445, 172475, 172504, 172533, 172562, 172591 + DD 172621, 172650, 172679, 172708, 172737, 172767, 172796, 172825 + DD 172854, 172884, 172913, 172942, 172972, 173001, 173030, 173059 + DD 173089, 173118, 173147, 173177, 173206, 173235, 173264, 173294 + DD 173323, 173352, 173382, 173411, 173440, 173470, 173499, 173529 + DD 173558, 173587, 173617, 173646, 173675, 173705, 173734, 173764 + DD 173793, 173822, 173852, 173881, 173911, 173940, 173970, 173999 + DD 174028, 174058, 174087, 174117, 174146, 174176, 174205, 174235 + DD 174264, 174294, 174323, 174353, 174382, 174412, 174441, 174471 + DD 174500, 174530, 174559, 174589, 174618, 174648, 174678, 174707 + DD 174737, 174766, 174796, 174825, 174855, 174885, 174914, 174944 + DD 174973, 175003, 175033, 175062, 175092, 175122, 175151, 175181 + DD 175210, 175240, 175270, 175299, 175329, 175359, 175388, 175418 + DD 175448, 175478, 175507, 175537, 175567, 175596, 175626, 175656 + DD 175686, 175715, 175745, 175775, 175804, 175834, 175864, 175894 + DD 175924, 175953, 175983, 176013, 176043, 176072, 176102, 176132 + DD 176162, 176192, 176221, 176251, 176281, 176311, 176341, 176371 + +GUSScreenList Label + DW 7 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr GravisHeaderLine + + DW Near Ptr MixerText + DW Near Ptr VolumeBox1 + DW Near Ptr VolumeBox2 + + DW Near Ptr MasterVolumeLeft ; 7 + DW Near Ptr MasterVolumeRight + DW Near Ptr TrebleVolumeLeft + DW Near Ptr TrebleVolumeRight + DW Near Ptr BassVolumeLeft + DW Near Ptr BassVolumeRight ; 12 + + DW Near Ptr SampleText + + DW Near Ptr SampleSize0Button ; 14 + DW Near Ptr SampleSize1Button + DW Near Ptr SampleSize2Button + DW Near Ptr SampleSize3Button ; 17 + + DW Near Ptr EffectText + DW Near Ptr EffectBox + + DW Near Ptr ChorusThumbBar ; 20 + DW Near Ptr ReverbThumbBar + + DW DriverText + + DW 0 + +GravisHeaderLine DW 10 + DB "Sound Blaster AWE 32 Driver", 0 + +DriverText DW 1 + DB 27, 48 + DB 21h + DB "Sound Blaster AWE 32 Driver 1.5 for Impulse Tracker", 0 + +MixerText DW 1 + DB 3, 13 + DB 20h + DB "Mixer options", 13 + DB 13 + DB " Master Volume Left", 13 + DB " Master Volume Right", 13 + DB 13 + DB 13 + DB " Treble Left", 13 + DB " Treble Right", 13 + DB " Bass Left", 13 + DB " Bass Right", 13 + DB 0 + +VolumeBox1 DW 0 + DB 24, 14, 30, 17 + DB 25 + +VolumeBox2 DW 0 + DB 17, 18, 21, 23 + DB 25 + +MasterVolumeLeft DW 9 + DB 25, 15 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 8, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 25, 16 + DW 0, 31 + DW 9, 1 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeLeft DW 9 + DB 18, 19 + DW 0, 15 + DW 9, 2 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeRight DW 9 + DB 18, 20 + DW 0, 15 + DW 9, 3 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeLeft DW 9 + DB 18, 21 + DW 0, 15 + DW 9, 4 + DW 10, 12, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeRight DW 9 + DB 18, 22 + DW 0, 15 + DW 9, 5 + DW 11, 14, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +SampleText DW 1 + DB 3, 25 + DB 20h + DB "Sample resizing options", 0 + +SampleSize0Button DW 2 + DW 12, 15, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment1 DW 0 + DW 0 + DW Offset SetCompress +DriverSegment2 DW 0 + DB 7, 27, 20, 29, 8 + DB 0 + DB " Original", 0 + +SampleSize1Button DW 2 + DW 14, 16, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment3 DW 0 + DW 1 + DW Offset SetCompress +DriverSegment4 DW 0 + DB 7, 30, 20, 32, 8 + DB 0 + DB " Half", 0 + +SampleSize2Button DW 2 + DW 15, 17, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment5 DW 0 + DW 2 + DW Offset SetCompress +DriverSegment6 DW 0 + DB 7, 33, 20, 35, 8 + DB 0 + DB " Quarter", 0 + +SampleSize3Button DW 2 + DW 16, 20, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment7 DW 0 + DW 3 + DW Offset SetCompress +DriverSegment8 DW 0 + DB 7, 36, 20, 38, 8 + DB 0 + DB " Eighth", 0 + +EffectText DW 1 + DB 3, 40 + DB 20h + DB "Effect options", 13 + DB 13 + DB " Chorus", 13 + DB " Reverb", 0 + + +EffectBox DW 0 + DB 12, 41, 30, 44 + DB 25 + +ChorusThumbBar DW 9 + DB 13, 42 + DW 0, 127 + DW 9, 6 + DW 17, 21, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +ReverbThumbBar DW 9 + DB 13, 43 + DW 0, 127 + DW 9, 7 + DW 20, 0FFFFh, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + + + +VolumeTable DB 6 Dup (0) +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 2 +Chorus DB 10, 64 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +AWEParameters DB 64 Dup (0FFh), 64 Dup (0) + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc DetectUART ; Given DX = Port + +; From SB-DevKit + + ClI + + Inc DX + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 40h ; Ready for output + LoopNZ DetectUART1 + JNZ DetectUARTError + + Mov AL, 0FFh ; Reset! + Out DX, AL + + Xor CX, CX + +DetectUART2: + In AL, DX + Test AL, 80h + JNZ DetectUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART4 + +DetectUART3: + Loop DetectUART2 + +DetectUARTError: + StI + StC + Ret + +DetectUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +DetectUART5: + In AL, DX + Test AL, 40h + LoopNZ DetectUART5 + JNZ DetectUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +DetectUART6: + Xor CX, CX + +DetectUART7: + In AL, DX + Test AL, 80h + JNZ DetectUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART9 + +DetectUART8: + Loop DetectUART7 + + Jmp DetectUARTError + +DetectUART9: + StI + ClC + Ret + +EndP DetectUART + +; + +Proc ReinitUART + + Mov DX, MIDIPort + Test DX, DX + JZ ReinitUART1 + + Call DetectUART + +ReinitUART1: + Ret + +EndP ReinitUART + +; + +Proc ResetUART + + Mov DX, MIDIPort + Test DX, DX + JZ ResetUART1 + + Inc DX + + Mov AL, 0FFh + Out DX, AL + +ResetUART1: + Ret + +EndP ResetUART + +; + +Proc SetCompress Far + + Mov CX, [SI+22] + Mov CS:Compress, CL + + Mov AX, 1 + ShL AX, CL + Mov CS:Step, AX + + Call Music_LoadAllSamples + + Mov AX, 1 + Ret + +EndP SetCompress + +; + +Proc GetCompress Far + + Push CS + Pop ES + Mov DI, Offset Compress + + Ret + +EndP GetCompress + +; + +Proc Load8BitSamplesForwards ; Given DS:SI, ECX = count + + Push BX + + Mov BX, CS:Step + Mov DX, CS:BasePort + Add DX, 400h + Xor AL, AL + +Load8BitSamplesForwards2: + Mov AH, [SI] + Add SI, BX + JC Load8BitSamplesForwards4 + +Load8BitSamplesForwards3: + Out DX, AX + + Dec ECX + JNZ Load8BitSamplesForwards2 + + Pop BX + Ret + +Load8BitSamplesForwards4: + Add ESI, 10000h + Int 3 + Jmp Load8BitSamplesForwards3 + +EndP Load8BitSamplesForwards + +; + +Proc Load16BitSamplesForwards ; Given DS:SI, ECX = count + + Push BX + + Mov BX, CS:Step + Mov DX, CS:BasePort + Add DX, 400h + Add BX, BX + +Load16BitSamplesForwards2: + Mov AX, [SI] + Add SI, BX + JC Load16BitSamplesForwards4 + +Load16BitSamplesForwards3: + Out DX, AX + + Dec ECX + JNZ Load16BitSamplesForwards2 + + Pop BX + Ret + +Load16BitSamplesForwards4: + Add ESI, 10000h + Int 3 + Jmp Load16BitSamplesForwards3 + +EndP Load16BitSamplesForwards + +; + +Proc Load8BitSamplesBackwards ; Given DS:SI, ECX = count + + Push BX + + Mov BX, CS:Step + Mov DX, CS:BasePort + Add DX, 400h + Xor AL, AL + + Sub SI, BX + JC Load8BitSamplesBackwards6 + +Load8BitSamplesBackwards2: + Sub SI, BX + JC Load8BitSamplesBackwards4 + +Load8BitSamplesBackwards3: + Mov AH, [SI] + Out DX, AX + + Dec ECX + JNZ Load8BitSamplesBackwards2 + + + Pop BX + Ret + +Load8BitSamplesBackwards4: + Sub ESI, 10000h + JC Load8BitSamplesBackwards5 + Int 3 + Jmp Load8BitSamplesBackwards3 + +Load8BitSamplesBackwards5: + Xor ESI, ESI + Jmp Load8BitSamplesBackwards3 + +Load8BitSamplesBackwards6: + Sub ESI, 10000h + Int 3 + Jmp Load8BitSamplesBackwards2 + + +EndP Load8BitSamplesBackwards + +; + +Proc Load16BitSamplesBackwards ; Given DS:SI, ECX = count + + Push BX + + Mov BX, CS:Step + Mov DX, CS:BasePort + Add DX, 400h + Add BX, BX + + Sub SI, BX + JC Load16BitSamplesBackwards6 + +Load16BitSamplesBackwards2: + Sub SI, BX + JC Load16BitSamplesBackwards4 + +Load16BitSamplesBackwards3: + Mov AX, [SI] + Out DX, AX + + Dec ECX + JNZ Load16BitSamplesBackwards2 + + Pop BX + Ret + +Load16BitSamplesBackwards4: + Sub ESI, 10000h + JC Load16BitSamplesBackwards5 + Int 3 + Jmp Load16BitSamplesBackwards3 + +Load16BitSamplesBackwards5: + Xor ESI, ESI + Jmp Load16BitSamplesBackwards3 + +Load16BitSamplesBackwards6: + Sub ESI, 10000h + Int 3 + Jmp Load16BitSamplesBackwards2 + + +EndP Load16BitSamplesBackwards + +; + +Proc WriteDataChannel + + Or AX, DX + +Proc WriteData ; Have BX/EBX = value + ; AX = xxyyh + ; ^ ^ + ; | | + ; | \-- value to send to pointer register + ; \---- 0, 1, 2 or 3, 4 + ; 0 = data reg 0 + ; 1 = data reg 1, dword + ; 2 = data reg 2 + ; 3 = data reg 3 + ; 4 = data reg 4, word + + Push DX + Push AX + + Mov DX, BasePort + Add DX, 802h + And AX, 0FFh + Out DX, AX + Pop AX + + Cmp AH, 1 + JB WriteDataReg0 + JE WriteDataReg1DWord + Cmp AH, 3 + JB WriteDataReg2 + JE WriteDataReg3 + Jmp WriteDataReg1Word + +WriteDataReg0: + Sub DX, 802h + Mov EAX, EBX + Out DX, EAX + + Pop DX + Ret + +WriteDataReg1DWord: + Sub DX, 402h + Mov EAX, EBX + Out DX, EAX + + Pop DX + Ret + +WriteDataReg1Word: + Sub DX, 402h + Mov AX, BX + Out DX, AX + + Pop DX + Ret + +WriteDataReg2: + Sub DX, 400h + Mov AX, BX + Out DX, AX + + Pop DX + Ret + +WriteDataReg3: + Sub DL, 2 + Mov AX, BX + Out DX, AX + + Pop DX + Ret + +EndP WriteData + +EndP WriteDataChannel + +; + +Proc ReadDataChannel + + Or AX, DX + +Proc ReadData ; AX = xxyyh + ; ^ ^ + ; | | + ; | \-- value to send to pointer register + ; \---- 0, 1, 2 or 3, 4 + ; 0 = data reg 0 + ; 1 = data reg 1, dword + ; 2 = data reg 2 + ; 3 = data reg 3 + ; 4 = data reg 4, word + + Push DX + Push AX + + Mov DX, BasePort + Add DX, 802h + And AX, 0FFh + Out DX, AX + Pop AX + + Cmp AH, 1 + JB ReadDataReg0 + JE ReadDataReg1DWord + Cmp AH, 3 + JB ReadDataReg2 + JE ReadDataReg3 + Jmp ReadDataReg1Word + +ReadDataReg0: + Sub DX, 802h + In EAX, DX + + Pop DX + Ret + +ReadDataReg1DWord: + Sub DX, 402h + In EAX, DX + + Pop DX + Ret + +ReadDataReg1Word: + Sub DX, 402h + In AX, DX + + Pop DX + Ret + +ReadDataReg2: + Sub DX, 400h + In AX, DX + + Pop DX + Ret + +ReadDataReg3: + Sub DL, 2 + In AX, DX + + Pop DX + Ret + +EndP ReadData + +EndP ReadDataChannel + +; + +Proc SetAWEFrequency + + Push DS + Push SI + Push CX + Push DX + + Mov EAX, [SI+10h] ; Final freq + + Mov CL, Compress + ShR EAX, CL + + Test EAX, EAX + JZ SetAWEFrequencyError + Cmp EAX, 88200*2 + JAE SetAWEFrequencyError + + Push CS + Pop DS + Assume DS:Driver + + And ESI, 0FFFFh + + Mov BX, 0F000h + Mov CX, 0FFFh ; Use binary search + Xor DX, DX ; CX = upper, DX = lower + +SetAWEFrequency1: + Cmp EAX, 88200 + JAE SetAWEFrequency2 + + Sub BX, 1000h + JC SetAWEFrequencyError + Add EAX, EAX + Jmp SetAWEFrequency1 + +SetAWEFrequency2: + Cmp CX, DX + JBE SetAWEFrequency5 + + Mov SI, CX + Add SI, DX + ShR SI, 1 + + Cmp EAX, [AWEPitchTable+ESI*4] + JE SetAWEFrequency3 + JB SetAWEFrequency4 ; In lower half + + ; In upper half + Inc SI + Mov DX, SI + Jmp SetAWEFrequency2 + +SetAWEFrequency4: ; In lower half + Dec SI + Mov CX, SI + Jmp SetAWEFrequency2 + +SetAWEFrequency5: + Mov SI, CX + +SetAWEFrequency3: + Add BX, SI + + Pop DX + Pop CX + Pop SI + Pop DS + + Mov AX, IP + Call WriteDataChannel + + Ret + Assume DS:Nothing + +SetAWEFrequencyError: + Call StopAWENote + + Mov Word Ptr [SI], 200h + Test Byte Ptr [SI+3Ah], 80h + JNZ SetAWEFrequencyError1 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + +SetAWEFrequencyError1: + Mov AX, IP + Xor EBX, EBX + Call WriteDataChannel + + Push CS + Pop DS + Mov SI, Offset FrequencyError + Mov BX, 40 + Call SetInfoLine + + Pop DX + Pop CX + Pop SI + Pop DS + + Ret + +EndP SetAWEFrequency + Assume DS:Nothing + +; + +Proc SetAWEPan + + Mov AX, PSST + Call ReadDataChannel ; Get starting offset + + Cmp CS:Stereo, 0 + JE SetPan2 + + Test CL, 128 + JNZ SetPan2 + + Mov BL, [SI+37h] ; Final pan + Cmp BL, 100 ; Surround -> central + JNE SetPan1 + +SetPan2: + Mov BL, 32 + +SetPan1: ; BL = 0->64, need to extend to 0->255 + Add BL, BL + Add BL, BL + SBB BL, 0 ; BL = 0->255 + Not BL + + ShL EAX, 8 + SHLD EBX, EAX, 24 + Mov AX, PSST + Call WriteDataChannel + + Ret + +EndP SetAWEPan + +; + +Proc SetAWEVolume + + Test CH, 8 + JZ SetAWEVolume1 + + Test CH, 1 + JNZ SetAWEVolume5 + + Cmp Byte Ptr [SI+8], 0FFh + JE SetAWEVolume4 + +SetAWEVolume5: + Mov Byte Ptr [SI+8], 0FFh + + Mov AX, IFATN + Call ReadDataChannel + Mov BX, AX + Mov AX, IFATN + Mov BL, 0FFh + Call WriteDataChannel + +SetAWEVolume4: + Ret + +SetAWEVolume1: +; First check if channel has been disowned + Xor BX, BX + Mov BL, [SI+3Ah] ; BL = host channel + + Test BL, BL + JS SetAWEVolume3 + +SetAWEVolume2: + Mov AH, [CS:AWEParameters+BX] ; AH = filter + Mov AL, [CS:AWEParameters+BX+64] ; AL = Q. + + ShR AL, 3 + Mov [SI+5Bh], AH + + Cmp AL, [SI+3Fh] + JE SetAWEVolume3 + + Mov [SI+3Fh], AL + +; Set Q + Mov BL, AL + ShL EBX, 28 + + Mov AX, CCCA + Call ReadDataChannel + And EAX, 0FFFFFFFh + Or EBX, EAX + Mov AX, CCCA + Call WriteDataChannel + +SetAWEVolume3: + Mov AL, [SI+3Eh] + Mul Byte Ptr [SI+5Bh] + ShL AX, 1 + Xor BX, BX + Add AH, 1 + Mov BL, [SI+20h] ; Final volume + Mov [SI+8], BL + Mov BL, [CS:AWEVolumeTable+BX] + Mov BH, AH + Mov AX, IFATN + Call WriteDataChannel + + Ret + +EndP SetAWEVolume + +; + +Proc StopAWENote + + Mov AX, DCYSUSV + Mov BX, 80h + Call WriteDataChannel + + Mov AX, VTFT + Mov EBX, 0FFFFh + Call WriteDataChannel + + Mov AX, CVCF + Call WriteDataChannel + + Mov BX, 80h + Mov AX, DCYSUSV + Call WriteDataChannel + + Mov AX, VTFT + Mov EBX, 0FFFFh + Call WriteDataChannel + + Mov AX, CVCF + Call WriteDataChannel + + Xor EBX, EBX + Mov AX, ENVVOL + Call WriteDataChannel + + Mov AX, ENVVAL + Call WriteDataChannel + + Mov AX, SUSDCY + Call WriteDataChannel + + Mov AX, ATKHLDV + Call WriteDataChannel + + Mov AX, LFO1VAL + Call WriteDataChannel + + Mov AX, HLDATK + Call WriteDataChannel + + Mov AX, LFO2VAL + Call WriteDataChannel + + Mov AX, IP + Call WriteDataChannel + + Mov AX, IFATN + Call WriteDataChannel + + Mov AX, PEFE + Call WriteDataChannel + + Mov AX, FMMOD + Call WriteDataChannel + + Mov AX, TREMFRQ + Call WriteDataChannel + + Mov AX, FM2FRQ2 + Call WriteDataChannel + + Mov AX, PTRX + Call WriteDataChannel + + Mov AX, VTFT + Call WriteDataChannel + +; Mov AX, PSST +; Call WriteDataChannel + + Mov BL, 8 + Mov AX, CSL + Call WriteDataChannel + + Xor BX, BX + Mov AX, CCCA + Call WriteDataChannel + + Mov AX, CPF + Call WriteDataChannel + + Ret + +EndP StopAWENote + +; + +Proc SetAWERegisters ; DS:SI = channel info table + ; CX = number of channels... + + Push CX + Push SI + + ; Stage 1. + ; Turn off any channel which has + ; a new note to play + ; If no new note to play and channel + ; is on, then get current position + + Xor DX, DX ; DX = oscillator number + +GetAWERegisters1: + Mov BX, [SI] + Test BH, 2 ; Note cut command + JZ GetAWERegisters2 + + Mov BX, 200h + Mov [SI], BX + + Call StopAWENote + Jmp GetAWERegisters4 + +GetAWERegisters2: + Test BL, 1 ; Channel on? + JZ GetAWERegisters4 + + Test BH, 1 ; New note? + JZ GetAWERegisters3 + + ; Fade out volume + Mov AX, DCYSUSV + Mov BX, 807Fh + Call WriteDataChannel + +; Call StopAWENote + + Jmp GetAWERegisters4 + +GetAWERegisters3: ; Get offset + Mov AX, CCCA + Call ReadDataChannel + + Xor BX, BX + And EAX, 00000000111111111111111111111111b + Inc EAX ; Interpolator correction + ; EAX = address in sound memory + Mov BL, [SI+36h] ; BL = sample number + LEA BX, [EBX*4+EBX] + ShL BX, 2 + Add BX, Offset AWEDataTable + + Cmp Byte Ptr [SI+0Ah], 8 + JB GetAddressNoLoop + JE GetAddressForwardsLoop + +GetAddressPingPongLoop: + Cmp EAX, [CS:BX+16] + JB SetOldAddress + + Neg EAX + Add EAX, [CS:BX+8] + Jmp SetOldAddress1 + +GetAddressNoLoop: + Cmp EAX, [CS:BX+4] ; Start loop + JB SetOldAddress + + Call StopAWENote + + ; OK.. gotta turn off channel + Mov Word Ptr [SI], 0 + Test Byte Ptr [SI+3Ah], 80h + JNZ GetAWERegisters4 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + + Jmp GetAWERegisters4 + +GetAddressForwardsLoop: +SetOldAddress: + Sub EAX, [CS:BX] ; EAX = address in sample + JNS SetOldAddress1 + + Xor EAX, EAX + +SetOldAddress1: + Push CX + Mov CL, Compress + ShL EAX, CL + Pop CX + + XChg [SI+4Ch], EAX + Mov [SI+2Ch], EAX + +GetAWERegisters4: + Add SI, 128 + + Inc DX + Dec CX + JNZ GetAWERegisters1 + + Pop SI + Pop CX + + Xor DX, DX ; DX = oscillator number + +SetAWERegisters1: + ; Stage 2. + ; If new frequency, play new frequency + ; If new volume, play new volume + ; If new pan, play new pan + ; If new note, set ENVVOL, ENVVAL, SUSDCY, ATKHLDV, LFO1VAL, HLDATK + ; LFO2VAL, IP, IFATN, PEFE, FMMOD, TREMFRQ, FM2FRQ2 + ; PSST, CSL, CCCA + ; VTFT, CVCF, DCYSUSV, PTRX, CPF + + Push CX + Mov CX, [SI] + Test CL, 1 ; Channel on? + JZ SetAWERegistersEnd + + Test CH, 1 ; New note? + JZ SetAWERegisters2 + + Xor BX, BX + Mov BL, [SI+36h] + LEA DI, [EBX*4+EBX] + ShL DI, 2 + Add DI, Offset AWEDataTable + + Mov AX, DCYSUSV + Mov BX, 80h + Call WriteDataChannel + + Mov AX, VTFT + Xor EBX, EBX + Call WriteDataChannel + + Mov AX, CVCF + Call WriteDataChannel + + Cmp DWord Ptr [CS:DI], 0FFFFFFFFh + JE SetAWERegistersError + + Mov AX, PTRX + Call WriteDataChannel + + Mov AX, CPF + Call WriteDataChannel + + + Mov AX, ENVVOL + Mov BX, 8000h + Call WriteDataChannel + + Mov AX, ENVVAL + Mov BX, 8000h + Call WriteDataChannel + + Mov AX, SUSDCY + Mov BX, 7F7Fh + Call WriteDataChannel + + Mov AX, ATKHLDV + Call WriteDataChannel + + Mov AX, LFO1VAL + Mov BX, 8000h + Call WriteDataChannel + + Mov AX, HLDATK + Mov BX, 7F7Fh + Call WriteDataChannel + + Mov AX, LFO2VAL + Mov BX, 8000h + Call WriteDataChannel + + Call SetAWEFrequency + Call SetAWEVolume + + Mov AX, PEFE + Xor BX, BX + Call WriteDataChannel + + Mov AX, FMMOD + Call WriteDataChannel + + Mov AX, TREMFRQ + Mov BX, 10h + Call WriteDataChannel + + Mov AX, FM2FRQ2 + Call WriteDataChannel + + + Mov EBX, [CS:DI+4] + Dec EBX ; Interpolator offset + Mov AX, PSST + Call WriteDataChannel + + Call SetAWEPan + + Mov AL, [CS:VolumeTable+6] ; Chorus + ShL EAX, 24 + Mov EBX, [CS:DI+8] + Dec EBX ; Interpolator offset + Or EBX, EAX + Mov AX, CSL + Call WriteDataChannel + + Mov AL, [SI+3Fh] + ShL EAX, 28 + + Push CX + Mov CL, Compress + Mov EBX, [SI+4Ch] + ShR EBX, CL + Pop CX + Add EBX, [CS:DI] + Dec EBX ; Interpolator offset + Or EBX, EAX + + Mov AX, CCCA ; Current address. + Call WriteDataChannel + + + Mov AX, VTFT + Mov EBX, 0FFFFh + Call WriteDataChannel + + Mov AX, CVCF + Call WriteDataChannel + + Mov AX, DCYSUSV + Mov BX, 7F7Fh + Call WriteDataChannel + + Mov AX, PTRX + Mov EBX, 40000000h ; 25% reverb + Or BH, [CS:VolumeTable+7] + Call WriteDataChannel + + Mov AX, CPF + Call WriteDataChannel + Jmp SetAWERegistersEnd + +SetAWERegisters2: + Test CL, 32 ; Frequency change? + JZ SetAWERegisters3 + + Call SetAWEFrequency + +SetAWERegisters3: + Test CL, 64 ; Volume change? + JZ SetAWERegisters4 + + Call SetAWEVolume + +SetAWERegisters4: + Test CH, 80h ; New pan? + JZ SetAWERegistersEnd + + Call SetAWEPan + +SetAWERegistersEnd: + Pop CX + And Word Ptr [SI], 0111100010011111b + + Add SI, 128 + + Inc DX + Dec CX + JNZ SetAWERegisters1 + + Ret + +SetAWERegistersError: + Call StopAWENote + + Mov Word Ptr [SI], 0 + Test Byte Ptr [SI+3Ah], 80h + JNZ SetAWERegistersEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + + Jmp SetAWERegistersEnd + +EndP SetAWERegisters + +; + +Proc ACKIRQ + + Mov AL, 20h + Cmp CS:IRQ, 7 + JBE ACKIRQ1 + + Out 0A0h, AL + +ACKIRQ1: + Out 20h, AL + Ret + +EndP ACKIRQ + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Mov DX, MIDIPort + + Mov BL, [MIDIBufferTail] + Test DX, DX + JZ CheckMIDIEnd + + Inc DX + +CheckMIDIAgain: + In AL, DX + + Test AL, AL + JS CheckMIDIAgain + + Dec DX + In AL, DX + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc MIDIIRQHandler + + Push AX BX DX + + Mov DX, CS:MixerPort + Mov AL, 82h + Out DX, AL + Inc DL + In AL, DX + + Test AL, 4 + JZ MIDIIRQHandlerEnd + + Call CheckMIDI + +MIDIIRQHandlerEnd: + Call AckIRQ + + Pop DX BX AX + IRet + + +EndP MIDIIRQHandler + +; + +Proc SBIRQHandler + + PushAD + Push DS + Push ES + + StI + + Push CS + Pop DS + Assume DS:Driver + +SBIRQHandlerAgain: + Mov DX, MixerPort + Mov AL, 82h + Out DX, AL + Inc DL + In AL, DX + + Test AL, 4 + JZ NoMIDIIRQ + + Push AX + Call CheckMIDI + Pop AX + +NoMIDIIRQ: +; Test AL, 2 +; JZ No16BitIRQ +; +; Push AX +; Mov DX, MixerPort +; Add DL, 0Fh-4 +; In AL, DX +; Pop AX +; +; No16BitIRQ: + Test AL, 1 + JNZ SB8BitIRQ + +SBNo8BitIRQ: + Call AckIRQ + Jmp SBEndIRQ + +SB8BitIRQ: + Mov DX, MixerPort + Add DL, 0Eh-4 + In AL, DX ; 8-bit IRQ ack. + + Add DL, 0Ch-0Eh + + Mov AL, 80h ; Output block of silence + Call SBOut + Mov AX, BlockLength2 + Call SBOut + Mov AL, AH + Call SBOut + + Mov AL, 0D3h + Call SBOut + + ClD + Call ACKIRQ + + Inc IRQFlag + JNZ SBEndIRQ + + Call SaveEMSPageFrame + Assume DS:Nothing + +SB8BitIRQAgain: + Call Update ; Returns DS:SI, CX + + Mov BX, BlockLength + Cmp BX, BlockLength2 + JE SBIRQHandler2 + Mov BlockLength2, BX + + Mov DX, SB16BasePort + Add DL, 0Ch + + Mov AL, 0D0h + Call SBOut + + Mov AL, 80h ; Output block of silence + Call SBOut + Mov AL, BL + Call SBOut + Mov AL, BH + Call SBOut + +SBIRQHandler2: + Call SetAWERegisters + Sub CS:IRQFlag, 1 + JNC SB8BitIRQAgain + + Call RestoreEMSPageFrame + +SBEndIRQ: + Pop ES + Pop DS + PopAD + + IRet + +EndP SBIRQHandler + Assume DS:Nothing + +; + +Proc AWEIRQHandler ; IRQ Handler has to + ; 1) Update AWE registers + ; 2) Update song position + Push AX + Push DS + + Mov AX, AWEUpdateTimer + Add AWEUpdateCount, AX + JC AWEIRQHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp AWEIRQHandler2 + +AWEIRQHandler1: + PushF + Call [OldIRQHandler] + +AWEIRQHandler2: + Xor AWEUpdateFlag, 1 + JZ AWEIRQHandlerEnd + + PushAD + Push ES + + ClD + + Call SaveEMSPageFrame + Call Update ; Returns DS:SI, CX + Call SetAWERegisters + Call RestoreEMSPageFrame + + Pop ES + PopAD + +AWEIRQHandlerEnd: + Pop DS + Pop AX + IRet + +EndP AWEIRQHandler + +; + +Proc EnableRAM + + Mov DX, BasePort + Mov CX, 29 + +EnableRAM1: + Mov AX, DCYSUSV + Or AX, CX + Mov BX, 80h + Call WriteData + + Mov AX, VTFT + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CVCF + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, PTRX + Or AX, CX + Mov EBX, 40000000h + Call WriteData + + Mov AX, CPF + Or AX, CX + Mov EBX, 40000000h + Call WriteData + + Mov AX, PSST + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CSL + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CCCA + Or AX, CX + Mov EBX, 6000000h ; Left write + Call WriteData + + Dec CX + JNS EnableRAM1 + + Ret + +EndP EnableRAM + +; + +Proc TestAWE ; Given DX = baseport. + + Push DX + + Add DX, 802h + In AL, DX + In AL, DX + Not AL + Mov BL, AL + Out DX, AL + In AL, DX + Cmp AL, BL + JNE TestAWE1 ; Register changed + + In AX, DX ; Is upper part of pointer + Mov BX, AX ; changing? + Mov CX, 128 + +TestAWE2: + In AX, DX + Cmp AL, BL + JNE TestAWE1 + Cmp AH, BH + JNE TestAWE3 + + Dec CX + JNZ TestAWE2 + Jmp TestAWE1 + +TestAWE3: + Pop DX + + ClC + Ret + +TestAWE1: + Pop DX + StC + Ret + +EndP TestAWE + +; + +Proc InitSetAWE + + Mov CX, 31 + +InitSetAWE1: + Mov AX, 31 + Sub AX, CX + Mov BX, [SI] + Or AX, INIT1 + Call WriteData + + Add SI, 2 + + Dec CX + JNS InitSetAWE1 + + Mov CX, 31 + +InitSetAWE2: + Mov AX, 31 + Sub AX, CX + Mov BX, [SI] + Or AX, INIT2 + Call WriteData + + Add SI, 2 + + Dec CX + JNS InitSetAWE2 + + Mov CX, 31 + +InitSetAWE3: + Mov AX, 31 + Sub AX, CX + Mov BX, [SI] + Or AX, INIT3 + Call WriteData + + Add SI, 2 + + Dec CX + JNS InitSetAWE3 + + Mov CX, 31 + +InitSetAWE4: + Mov AX, 31 + Sub AX, CX + Mov BX, [SI] + Or AX, INIT4 + Call WriteData + + Add SI, 2 + + Dec CX + JNS InitSetAWE4 + + Ret + +EndP InitSetAWE + +; + +Proc InitAWE + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + + Mov AX, HWCF1 + Mov BX, 59h + Call WriteData + + Mov AX, CFG2 + Mov BX, 20h + Call WriteData + + Mov CX, 31 + +InitAwe1: + Mov BX, 80h + Mov AX, DCYSUSV + Or AX, CX + Call WriteData + + Xor EBX, EBX + Mov AX, ENVVOL + Or AX, CX + Call WriteData + + Mov AX, ENVVAL + Or AX, CX + Call WriteData + + Mov AX, SUSDCY + Or AX, CX + Call WriteData + + Mov AX, ATKHLDV + Or AX, CX + Call WriteData + + Mov AX, LFO1VAL + Or AX, CX + Call WriteData + + Mov AX, HLDATK + Or AX, CX + Call WriteData + + Mov AX, LFO2VAL + Or AX, CX + Call WriteData + + Mov AX, IP + Or AX, CX + Call WriteData + + Mov AX, IFATN + Or AX, CX + Call WriteData + + Mov AX, PEFE + Or AX, CX + Call WriteData + + Mov AX, FMMOD + Or AX, CX + Call WriteData + + Mov AX, TREMFRQ + Or AX, CX + Call WriteData + + Mov AX, FM2FRQ2 + Or AX, CX + Call WriteData + + Mov AX, PTRX + Or AX, CX + Call WriteData + + Mov AX, VTFT + Or AX, CX + Call WriteData + + Mov AX, PSST + Or AX, CX + Call WriteData + + Mov AX, CSL + Or AX, CX + Call WriteData + + Mov AX, CCCA + Or AX, CX + Call WriteData + + Dec CX + JNS InitAWE1 + + Mov CX, 31 + +InitAWE8: + Mov AX, CPF + Or AX, CX + Call WriteData + + Mov AX, CVCF + Or AX, CX + Call WriteData + + Dec CX + JNS InitAWE8 + ; Initialise still... + Mov AX, SMALR + Call WriteData + + Mov AX, SMARR + Call WriteData + + Mov AX, SMALW + Call WriteData + + Mov AX, SMARW + Call WriteData + + Mov SI, Offset InitTable1 + Call InitSetAWE + + ; Wait for 1024 sample periods + Mov AX, WC + Call ReadData + + Mov BX, AX + Mov CX, AX + Add CX, 400h ; 1024 + Cmp BX, CX + JB InitAWE3 + +InitAWE4: + Mov AX, WC + Call ReadData + Cmp AX, CX + JA InitAWE4 + +InitAWE3: + Mov AX, WC + Call ReadData + Cmp AX, CX + JB InitAWE3 + + Mov SI, Offset InitTable2 + Call InitSetAWE + + Mov SI, Offset InitTable3 + Call InitSetAWE + + Mov AX, HWCF4 + Xor EBX, EBX + Call WriteData + + Mov AX, HWCF5 + Mov EBX, 83h + Call WriteData + + Mov AX, HWCF6 + Mov EBX, 8000h + Call WriteData + + Mov SI, Offset InitTable4 + Call InitSetAWE + + Mov AX, HWCF3 + Mov BX, 4 + Call WriteData + + Ret + +EndP InitAWE + Assume DS:Nothing + +; + +Proc InitDRAMRefresh + + Mov AX, DCYSUSV+1Eh + Mov BX, 80h + Call WriteData + + Mov AX, DCYSUSV+1Fh + Call WriteData + +; + + Mov AX, VTFT+1Eh + Xor EBX, EBX + Call WriteData + + Mov AX, CVCF+1Eh + Call WriteData + + Mov AX, VTFT+1Fh + Call WriteData + + Mov AX, CVCF+1Fh + Call WriteData + +; + + Mov AX, PTRX+1Eh + Call WriteData + + Mov AX, CPF+1Eh + Call WriteData + + Mov AX, PTRX+1Fh + Call WriteData + + Mov AX, CPF+1Fh + Call WriteData + +; + + Mov AX, PSST+1Eh + Call WriteData + Mov AX, PSST+1Fh + Call WriteData + + Mov BX, 0FFFFh + Mov AX, CSL+1Eh + Call WriteData + Mov AX, CSL+1Fh + Call WriteData + + Xor BX, BX + Mov AX, CCCA+1Eh + Call WriteData + Mov AX, CCCA+1Fh + Call WriteData + + Ret + +EndP InitDRAMRefresh + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + + ShR AL, 7 + LoopZ SBIn + +; Test AL, AL +; JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov DX, BasePort + Cmp DX, 0FFFFh + JE DetectCard1 + + Cmp DX, 620h + JB DetectCard3 + Cmp DX, 680h + JA DetectCard3 + + Call TestAWE + JNC DetectCardFound + Ret + +DetectCard1: + Mov DX, 620h + +DetectCard2: + Call TestAWE + JNC DetectCardFound + + Add DL, 20h + Cmp DL, 80h + JBE DetectCard2 + +DetectCard3: + StC + Ret + +DetectCardFound: + Mov BasePort, DX + + ; Initialise AWE 32 + Call InitAWE + Call InitDRAMRefresh + + ; Detect amount of RAM. + + Mov DX, BasePort + Mov CX, 29 + +DetectCardMemory1: + Mov AX, DCYSUSV + Or AX, CX + Mov BX, 80h + Call WriteData + + Mov AX, VTFT + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CVCF + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, PTRX + Or AX, CX + Mov EBX, 40000000h + Call WriteData + + Mov AX, CPF + Or AX, CX + Mov EBX, 40000000h + Call WriteData + + Mov AX, PSST + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CSL + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CCCA + Or AX, CX + Mov EBX, 4000000h ; Left read + + Test CL, 2 + JZ DetectCardMemory2 + + Mov EBX, 6000000h ; Left write + +DetectCardMemory2: + Call WriteData + + Dec CX + JNS DetectCardMemory1 + + Xor EDI, EDI ; Amount of memory stored in + ; EDI + + Mov AX, SMALW + Mov EBX, 200000h + Call WriteData + + Mov AX, SMLD + Mov BX, 0FFFFh + Call WriteData + + Mov AX, SMLD + Mov BX, 5555h + Call WriteData + + Mov AX, SMLD + Mov BX, 0AAAAh + Call WriteData + + Mov AX, SMALR + Mov EBX, 200000h + Call WriteData + + Mov AX, SMLD + Call ReadData + + Mov AX, SMLD + Call ReadData + Cmp AX, 0FFFFh + JNE DetectCardMemory6 + + Mov AX, SMLD + Call ReadData + Cmp AX, 5555h + JNE DetectCardMemory6 + + Mov AX, SMLD + Call ReadData + Cmp AX, 0AAAAh + JNE DetectCardMemory6 + + Mov EDI, 20000h + +DetectCardMemory3: ; Set read/write addresses.. + Mov AX, SMALW + Mov EBX, EDI + Add EBX, 200000h + Call WriteData + + Mov AX, SMLD + Mov BX, 5555h + Call WriteData + + Mov AX, SMLD + Mov BX, 0AAAAh + Call WriteData + + Mov AX, SMALR + Mov EBX, 200000h + Call WriteData + + Mov AX, SMLD + Call ReadData + + Mov AX, SMLD + Call ReadData + Cmp AX, 0FFFFh + JNE DetectCardMemory5 + + Mov AX, SMALR + Mov EBX, EDI + Add EBX, 200000h + Call WriteData + + Mov AX, SMLD + Call ReadData + + Mov AX, SMLD + Call ReadData + Cmp AX, 5555h + JNE DetectCardMemory5 + + Mov AX, SMLD + Call ReadData + Cmp AX, 0AAAAh + JNE DetectCardMemory5 + +DetectCardMemory4: + Add EDI, 20000h + Cmp EDI, 0E00000h + JB DetectCardMemory3 + +DetectCardMemory5: + Cmp EDI, 0DFFFE0h + JB DetectCardMemory7 + + Mov EDI, 0DFFFE0h + +DetectCardMemory7: + Test EDI, EDI + JZ DetectCardMemory6 + + Mov AWEMemory, EDI + + Mov MixerPort, 210h + Mov AX, BasePort + Sub AX, 400h + Call ResetDSP + JNC DetectMixer2 + +DetectMixer1: + Mov AX, MixerPort + Call ResetDSP + JNC DetectMixer2 + +DetectMixer3: + Add MixerPort, 10h + Cmp MixerPort, 280h + JBE DetectMixer1 + + Mov DX, BasePort + Sub DX, 400h + Mov MixerPort, DX + + Jmp DetectCard4 + +DetectMixer2: ; OK... DSP found. + ; Get DSP version + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + + Mov CX, 200 + +DetectMixerLoop1: + In AL, DX +; Test AL, AL +; JS DetectMixerLoop1 + ShR AL, 7 + LoopNZ DetectMixerLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AX, 40Ch ; SB DSP = 4.12+ + JB DetectMixer3 + + Sub DL, 0Eh + Mov MixerPort, DX + +DetectCard4: + Mov SB16BasePort, DX + Add MixerPort, 4 ; Mixerport + + Add DL, 4 + + Mov AL, 30h + Call SBGetRegister + ShR AL, 3 + Mov VolumeTable, AL + + Mov AL, 31h + Call SBGetRegister + ShR AL, 3 + Mov [VolumeTable+1], AL + + Mov AL, 44h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+2], AL + + Mov AL, 45h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+3], AL + + Mov AL, 46h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+4], AL + + Mov AL, 47h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+5], AL + + Mov DX, MixerPort + Mov AX, 0C034h + Out DX, AX + + Mov AL, 35h + Out DX, AX + + Mov DX, MixerPort + Mov AL, 80h ; IRQ select + Out DX, AL + Inc DL ; 2x5h = Mixer data port + + In AL, DX + + Dec DL + + Mov BX, IRQ + Cmp BX, 0FFFFh + JE DetectCardIRQ1 + Cmp Forced, 0 + JE DetectCardIRQ1 + + Mov AH, 11h + Cmp BL, 2 + JE SetCardIRQ1 + Cmp BL, 9 + JE SetCardIRQ1 + + Mov AH, 12h + Cmp BL, 5 + JE SetCardIRQ1 + + Mov AH, 14h + Cmp BL, 7 + JE SetCardIRQ1 + + Mov AH, 18h + Cmp BL, 10 + JE SetCardIRQ1 + + Jmp NoWindows + +SetCardIRQ1: + Mov AL, 80h + Out DX, AL + Inc DL + Mov AL, AH + Out DX, AL + Dec DL + Jmp DetectCard6 + +DetectCardIRQ1: + Mov BX, 2 + Test AL, 1 + JNZ DetectCardIRQ2 + + Mov BL, 5 + Test AL, 2 + JNZ DetectCardIRQ2 + + Mov BL, 7 + Test AL, 4 + JNZ DetectCardIRQ2 + + Mov BL, 10 + Test AL, 8 + JNZ DetectCardIRQ2 + + StC + Ret + +DetectCardIRQ2: + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + + Cmp BX, IRQ + JE DetectCard6 + + StC + Ret + +DetectCardIRQ3: + Mov IRQ, BX + +DetectCard6: + Mov AX, 1600h ; Windows detection. + Int 2Fh + Test AL, 7Fh + JZ NoWindows + + Mov SBIRQMode, 1 + +NoWindows: + Mov EAX, 'Jeff' + ClC + Ret + +DetectCardMemory6: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc SetSamplingRate + + PushA + + Mov AX, CS:SB16BasePort + Mov DX, AX + Call ResetDSP + Add DL, 0Ch + ; Set mixing frequency + Mov AL, 40h + Call SBOut + Mov AL, 211 + Call SBOut ; 22222 Hz. + + Mov AL, 80h + Call SBOut + Mov AX, BlockLength + Dec AX + Call SBOut + Mov AL, AH + Call SBOut + + PopA + Ret + +EndP SetSamplingRate + +; + +Proc SetMIDIIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset MIDIIRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetMIDIIRQ + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SBIRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc InitMIDI + + Mov DX, 330h + Call DetectUART + JC DetectMIDI1 + + Mov MIDIPort, 330h + Jmp DetectMIDIEnd + +DetectMIDI1: + Mov DX, 300h + Call DetectUART + JC DetectMIDIEnd + + Mov MIDIPort, 300h + +DetectMIDIEnd: + Ret + +EndP InitMIDI + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov AX, CS + Mov DriverSegment1, AX + Mov DriverSegment2, AX + Mov DriverSegment3, AX + Mov DriverSegment4, AX + Mov DriverSegment5, AX + Mov DriverSegment6, AX + Mov DriverSegment7, AX + Mov DriverSegment8, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Cmp SBIRQMode, 0 + JE InitSound1 + + Call SetIRQ + Call GetTempo + Call SetTempo + Call ResetMemory + Call SetSamplingRate + + Call InitMIDI + + Mov SI, Offset AWE32Msg2 + Mov AX, BasePort + + Mov BX, IRQ + + Mov ECX, AWEMemory + SHR ECX, 9 + + Ret + +InitSound1: + Call SetMIDIIRQ + Call GetTempo + Call SetTempo + Call ResetMemory + + Xor AX, AX + Mov ES, AX ; ES = 0 + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset AWEIRQHandler + + ClI + + XChg DWord Ptr [ES:20h], EAX ; Clock tick + Mov OldIRQHandler, EAX + + StI + +InitSound2: + Call InitMIDI + + Mov SI, Offset AWE32Msg + Mov AX, BasePort + + Mov EBX, AWEMemory + SHR EBX, 9 + + Ret + +EndP InitSound + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset AWE32ReinitMsg + Mov BX, 40 + Call SetInfoLine + + Call ResetUART + Call InitAWE + Call InitDRAMRefresh + + Cmp SBIRQMode, 0 + JE ReInitSound1 + + Call ResetIRQ + Call SetIRQ + Call SetSamplingRate + Call ReinitUART + Ret + +ReInitSound1: + Xor AX, AX + Mov ES, AX ; ES = 0 + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset AWEIRQHandler + + Mov DWord Ptr [ES:20h], EAX ; Clock tick + + Call ResetIRQ + Call SetMIDIIRQ + Call ReinitUART + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset Chorus + Int 21h + +SaveConfig1: + PushF + Mov AH, 3Eh + Int 21h + PopF + +SaveConfig2: + Call ResetIRQ + + Cmp SBIRQMode, 0 + JE UnInitSound1 + + Mov DX, SB16BasePort + Add DL, 0Ch + + Mov AL, 0D0h + Call SBOut + + Call ResetUART + +; Mov AX, SB16BasePort +; Call ResetDSP + + Call InitAWE + Ret + +UnInitSound1: + Mov AL, 34h + Out 43h, AL + + Xor AX, AX + Out 40h, AL + Out 40h, AL + + Mov ES, AX + Mov EAX, OldIRQHandler + Mov [ES:20h], EAX + + Mov AX, SB16BasePort + Call ResetDSP + Call ResetUART + Call InitAWE + Call ResetIRQ + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Cmp CS:SBIRQMode, 0 + JE SetTempo1 + ; BlockLength = 55555/BPM + + Mov AX, 55555 + Xor DX, DX + Div BX + Dec AX + Mov BlockLength, AX + +; Mov DX, SB16BasePort +; Add DL, 0Ch + + Jmp SetTempo2 + +SetTempo1: + ; Frames per second = 2 * (0.4*Tempo) + Mov AX, 0C214h + Mov DX, 16h ; Ticks = (1193181/(2*0.4))/Tempo + Div BX + + ; AX contains counter. + Mov AWEUpdateTimer, AX + + Out 40h, AL ; Timer IRQ. + Mov AL, AH + Out 40h, AL + +SetTempo2: + Pop DX + Pop BX + Pop AX + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + ; if no sample, then do nothing + ; MemoryUsed = length of sample + ; if sustain loop, then use sustain + ; loop information + ; if no sustain loop, then use loop + ; information + ; if no loop or sustain loop, + ; memoryused += 16; (16 zero samples + ; at the end) + ; + PushAD + Push DS + Push ES + Push FS + + Push AX + + ClI + + Call EnableRAM ; Enable access to DRAM. + + ; Set destination address + Mov AX, SMALW + Mov EBX, CS:AWEMemoryUsed + Add EBX, 200000h + Call WriteData + + Mov DX, CS:BasePort + Add DX, 802h ; Index + Mov AX, 32+26 + Out DX, AX + + Pop AX + + Mov FS, CS:SongDataArea + LEA DI, [EAX*4+EAX] + ShL DI, 2 + Add DI, Offset AWEDataTable-20 + + Mov ECX, -1 + + Mov DWord Ptr [CS:DI], ECX ; Start + Mov DWord Ptr [CS:DI+4], ECX ; Loop start + Mov DWord Ptr [CS:DI+8], ECX ; Loop end + Mov DWord Ptr [CS:DI+12], ECX ; Size occupied + Mov DWord Ptr [CS:DI+16], ECX ; Size occupied + + Mov BP, AX + Add BP, BP + Mov BP, [FS:64910+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length + JC LoadSampleNoError + + JZ LoadSample1 + + ; 16 bit + + Mov CS:LoadSampleFuncF, Offset Load16BitSamplesForwards + Mov CS:LoadSampleFuncB, Offset Load16BitSamplesBackwards + + Jmp LoadSample2 + +LoadSample1: ; 8 bit + Mov CS:LoadSampleFuncF, Offset Load8BitSamplesForwards + Mov CS:LoadSampleFuncB, Offset Load8BitSamplesBackwards + +LoadSample2: + Mov AL, [FS:BP+12h] + Test AL, 30h ; Loop or sustain loop? + JZ LoadSampleNoLoop + + Mov EBX, [FS:BP+34h] ; Loop begin + Mov EDX, [FS:BP+38h] ; Loop end + Test AL, 20h ; Sustain loop? + JZ LoadSample3 + + ShR AL, 1 + Mov EBX, [FS:BP+40h] + Mov EDX, [FS:BP+44h] + Jmp LoadSample3 + +LoadSampleError: + ClC + Jmp LoadSampleEnd + +LoadSampleNoError: + StC + +LoadSampleEnd: + StI + Pop FS + Pop ES + Pop DS + PopAD + + Ret + +LoadSampleNoLoop: ; ECX contains length of sample + Mov EAX, ECX + Mov EDX, AWEMemoryUsed + Mov EBX, AWEMemory + Sub EBX, EDX ; EBX = AWEMemory remaining + + Mov CL, Compress + ShR EAX, CL ; Compress sample + Add EAX, 16 ; zeroes at end of sample + + Cmp EAX, EBX + JA LoadSampleError + + Mov ECX, EAX + Add AWEMemoryUsed, EAX ; Record memory as used + Mov [CS:DI+12], EAX + + Add EDX, 200000h + + Sub ECX, 16 ; Number of samples to transfer + Mov [CS:DI], EDX + Add EDX, ECX + Mov [CS:DI+4], EDX ; Loop start + Add EDX, 14 + Mov [CS:DI+8], EDX ; Loop end + + ; Now to transfer samples to AWE32 + Call [CS:LoadSampleFuncF] + ; Now to shove a whole lot of zeroes + Xor AX, AX + Mov CX, 16 + +LoadSampleNoLoop2: + Out DX, AX + Loop LoadsampleNoLoop2 + + Jmp LoadSampleNoError + +LoadSample3: ; OK... EBX = loop start + ; EDX = loop end + ; AL&40h = ping pong + Test AL, 40h + JNZ LoadSamplePingPong + + Mov CL, Compress + + Push EBX + + ShR EDX, CL + ShR EBX, CL + Mov EAX, EDX + Add EAX, 2 ; For loop fixing + + Mov ECX, AWEMemory + Sub ECX, AWEMemoryUsed ; ECX = AWEMemoryRemaining + + Cmp EAX, ECX + Pop ECX + JA LoadSampleError ; Sufficient memory? + Push ECX + + Mov ECX, EAX + Mov EAX, AWEMemoryUsed + Add AWEMemoryUsed, ECX + Mov [CS:DI+12], ECX + + Sub ECX, 2 + + Add EAX, 200000h + Mov [CS:DI], EAX + + Add EDX, EAX + Add EAX, EBX + + Mov [CS:DI+4], EAX + Mov [CS:DI+8], EDX + + Call [CS:LoadSampleFuncF] + ; Now to fix loop.. 1 extra + ; sample. + + Pop ESI ; Loop start + Test Byte Ptr [FS:BP+12h], 2 + JZ LoadSampleForwards1 + + Add ESI, ESI + +LoadSampleForwards1: + Int 3 + + Mov ECX, 2 + Call [CS:LoadSampleFuncF] + + Jmp LoadSampleNoError + +LoadSamplePingPong: + Mov CL, Compress + ShR EDX, CL + ShR EBX, CL + + Mov EAX, EDX + Add EAX, EDX + Sub EAX, EBX + Inc EAX + + Mov ECX, AWEMemory + Sub ECX, AWEMemoryUsed + + Cmp EAX, ECX + JA LoadSampleError + + Mov [CS:DI+12], EAX + Mov ECX, AWEMemoryUsed + Add AWEMemoryUsed, EAX + + Add ECX, 200000h + Add EAX, ECX + Dec EAX + + Mov [CS:DI], ECX + Add ECX, EBX + Mov [CS:DI+4], ECX + Mov [CS:DI+8], EAX + + Mov EAX, [CS:DI] + Add EAX, EDX + Mov [CS:DI+16], EAX + + Mov ECX, EDX + Sub EDX, EBX + Push EDX + + Call [CS:LoadSampleFuncF] + + Pop ECX + Inc ECX + + Call [CS:LoadSampleFuncB] + + Jmp LoadSampleNoError + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + PushAD + + LEA DI, [EAX*4+EAX] ; DI = AX * 5 + ShL DI, 2 + Add DI, Offset AWEDataTable + + Mov EBX, [CS:DI+12] + Mov EAX, CS:AWEMemoryUsed + Sub EAX, EBX + Add EAX, 200000h + Cmp EAX, [CS:DI] + JNE ReleaseSample1 + + Sub AWEMemoryUsed, EBX +ReleaseSample1: + Mov EAX, -1 + Mov [CS:DI], EAX + Mov [CS:DI+4], EAX + Mov [CS:DI+8], EAX + Mov [CS:DI+12], EAX + + PopAD + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Push CS + Pop ES + + Xor EAX, EAX + Mov CS:AWEMemoryUsed, EAX + + Mov DI, Offset AWEDataTable + Mov CX, 1000 + Mov AX, 0FFFFh + Rep StosW + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset AWE32Status + + Mov EAX, AWEMemory + Sub EAX, AWEMemoryUsed + SHR EAX, 9 + + ClC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset GUSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, MixerPort + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +Proc UARTOut + + Ret + +EndP UARTOut + +; + + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:AWEParameters+BX], AL + + Pop BX + + Mov CS:InterpretState, 0 + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Ret + +SendUARTOut3: + Mov InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset AWEParameters + Mov CX, 32 + Or AX, -1 + Rep StosW + Mov CX, 32 + Inc AX + Rep StosW + + Pop ES + PopA + +SendUARTOutNoClear: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 30 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 30 +DriverFlags DW 1 ; MIDI Out supported + + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + + DW Offset SendUARTOut ; For MIDI Out + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/AWE32DRV.ASM b/it/SoundDrivers/AWE32DRV.ASM new file mode 100755 index 0000000..e101d68 --- /dev/null +++ b/it/SoundDrivers/AWE32DRV.ASM @@ -0,0 +1,3961 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + + Comment ~ + +Index = BasePort + 802h + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + Ŀ + .............................. Register Channel Number + + + + ~ + +OldIRQHandler DD 0 +AWEMemory DD 0 +AWEMemoryUsed DD 0 +AWEUpdateCount DW 0 + +AWEUpdateTimer DW 0 + +LoadSampleFuncF DW 0 +LoadSampleFuncB DW 0 + +AWEDataTable DD 5*100 Dup (0) ; Start, Startloop, Endloop, Size +MIDIPort DW 0 +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +DMABuffer DW 0 + +SB16BasePort DW 0 +MixerPort DW 0 +Step DW 1 +AWEUpdateFlag DB 0 +Compress DB 0 + DB 0 + +SBIRQMode DB 0 +BlockLength DW 100 +BlockLength2 DW 100 + +AWE32Msg DB "Sound Blaster AWE 32 detected", 13 + DB "Address ", 0FDh, "Xh, ", 0FDh, "Dk Memory", 0 + +AWE32Msg2 DB "Sound Blaster AWE 32 detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +AWE32Status DB "FreeAWE ", 0FDh, "Dk", 0 + +AWE32ReinitMsg DB "Sound Blaster AWE 32 reinitialised", 0 +Stereo DB 0 +Forced DB 0 +DriverName DB "ITAWE32.DRV", 0 + +FrequencyError DB "AWE Hardware frequency limit exceeded -> Note terminated", 0 + +IRQFlag DB 0FFh + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +IMR DW 0 + + CPF EQU 0 + PTRX EQU 20h + CVCF EQU 40h + VTFT EQU 60h + PSST EQU 0C0h + CSL EQU 0E0h + + CCCA EQU 100h + HWCF4 EQU 129h + HWCF5 EQU 12Ah + HWCF6 EQU 12Dh + SMALR EQU 134h + SMARR EQU 135h + SMALW EQU 136h + SMARW EQU 137h + SMLD EQU 43Ah + SMRD EQU 23Ah + WC EQU 23Bh + HWCF1 EQU 43Dh + HWCF2 EQU 43Eh + CFG2 EQU 43Eh + HWCF3 EQU 43Fh + INIT1 EQU 440h + INIT2 EQU 240h + INIT3 EQU 460h + INIT4 EQU 260h + ENVVOL EQU 480h + DCYSUSV EQU 4A0h + ENVVAL EQU 4C0h + DCYSUS EQU 4E0h + SUSDCY EQU 4E0h + ATKHLDV EQU 280h + LFO1VAL EQU 2A0h + ATKHLD EQU 2C0h + HLDATK EQU 2C0h + LFO2VAL EQU 2E0h + IP EQU 300h + IFATN EQU 320h + PEFE EQU 340h + FMMOD EQU 360h + TREMFRQ EQU 380h + FM2FRQ2 EQU 3A0h + +ALIGN 4 + +InitTable1 Label + DW 003FFh, 0030h, 007FFh, 0130h, 00BFFh, 0230h, 00FFFh, 0330h + DW 013FFh, 0430h, 017FFh, 0530h, 01BFFh, 0630h, 01FFFh, 0730h + DW 023FFh, 0830h, 027FFh, 0930h, 02BFFh, 0A30h, 02FFFh, 0B30h + DW 033FFh, 0C30h, 037FFh, 0D30h, 03BFFh, 0E30h, 03FFFh, 0F30h + + DW 043FFh, 0030h, 047FFh, 0130h, 04BFFh, 0230h, 04FFFh, 0330h + DW 053FFh, 0430h, 057FFh, 0530h, 05BFFh, 0630h, 05FFFh, 0730h + DW 063FFh, 0830h, 067FFh, 0930h, 06BFFh, 0A30h, 06FFFh, 0B30h + DW 073FFh, 0C30h, 077FFh, 0D30h, 07BFFh, 0E30h, 07FFFh, 0F30h + + DW 083FFh, 0030h, 087FFh, 0130h, 08BFFh, 0230h, 08FFFh, 0330h + DW 093FFh, 0430h, 097FFh, 0530h, 09BFFh, 0630h, 09FFFh, 0730h + DW 0A3FFh, 0830h, 0A7FFh, 0930h, 0ABFFh, 0A30h, 0AFFFh, 0B30h + DW 0B3FFh, 0C30h, 0B7FFh, 0D30h, 0BBFFh, 0E30h, 0BFFFh, 0F30h + + DW 0C3FFh, 0030h, 0C7FFh, 0130h, 0CBFFh, 0230h, 0CFFFh, 0330h + DW 0D3FFh, 0430h, 0D7FFh, 0530h, 0DBFFh, 0630h, 0DFFFh, 0730h + DW 0E3FFh, 0830h, 0E7FFh, 0930h, 0EBFFh, 0A30h, 0EFFFh, 0B30h + DW 0F3FFh, 0C30h, 0F7FFh, 0D30h, 0FBFFh, 0E30h, 0FFFFh, 0F30h + +InitTable2 Label + DW 003FFh, 8030h, 007FFh, 8130h, 00BFFh, 8230h, 00FFFh, 8330h + DW 013FFh, 8430h, 017FFh, 8530h, 01BFFh, 8630h, 01FFFh, 8730h + DW 023FFh, 8830h, 027FFh, 8930h, 02BFFh, 8A30h, 02FFFh, 8B30h + DW 033FFh, 8C30h, 037FFh, 8D30h, 03BFFh, 8E30h, 03FFFh, 8F30h + + DW 043FFh, 8030h, 047FFh, 8130h, 04BFFh, 8230h, 04FFFh, 8330h + DW 053FFh, 8430h, 057FFh, 8530h, 05BFFh, 8630h, 05FFFh, 8730h + DW 063FFh, 8830h, 067FFh, 8930h, 06BFFh, 8A30h, 06FFFh, 8B30h + DW 073FFh, 8C30h, 077FFh, 8D30h, 07BFFh, 8E30h, 07FFFh, 8F30h + + DW 083FFh, 8030h, 087FFh, 8130h, 08BFFh, 8230h, 08FFFh, 8330h + DW 093FFh, 8430h, 097FFh, 8530h, 09BFFh, 8630h, 09FFFh, 8730h + DW 0A3FFh, 8830h, 0A7FFh, 8930h, 0ABFFh, 8A30h, 0AFFFh, 8B30h + DW 0B3FFh, 8C30h, 0B7FFh, 8D30h, 0BBFFh, 8E30h, 0BFFFh, 8F30h + + DW 0C3FFh, 8030h, 0C7FFh, 8130h, 0CBFFh, 8230h, 0CFFFh, 8330h + DW 0D3FFh, 8430h, 0D7FFh, 8530h, 0DBFFh, 8630h, 0DFFFh, 8730h + DW 0E3FFh, 8830h, 0E7FFh, 8930h, 0EBFFh, 8A30h, 0EFFFh, 8B30h + DW 0F3FFh, 8C30h, 0F7FFh, 8D30h, 0FBFFh, 8E30h, 0FFFFh, 8F30h + +InitTable3 Label + DW 0C10h, 8470h, 14FEh, 0B488h, 167Fh, 0A470h, 18E7h, 84B5h + DW 1B6Eh, 842Ah, 1F1Dh, 852Ah, 0DA3h, 9F7Ch, 167Eh, 0F254h + DW 0, 842Ah, 1, 852Ah, 18E6h, 9BAAh, 1B6Dh, 0F234h + DW 229Fh, 8429h, 2746h, 8529h, 1F1Ch, 96E7h, 229Eh, 0F224h + + DW 0DA4h, 8429h, 2C29h, 8529h, 2745h, 97F6h, 2C28h, 0F254h + DW 383Bh, 8428h, 320Fh, 8528h, 320Eh, 9F02h, 1341h, 0F264h + DW 3EB6h, 8428h, 3EB9h, 8528h, 383Ah, 9FA9h, 3EB5h, 0F294h + DW 3EB7h, 8474h, 3EBAh, 8575h, 3EB8h, 0C4C3h, 3EBBh, 0C5C3h + + DW 00000, 0A404h, 00001, 0A504h, 141Fh, 8671h, 14FDh, 8287h + DW 3EBCh, 0E610h, 3EC8h, 8C7Bh, 31Ah, 87E6h, 3EC8h, 86F7h + DW 3EC0h, 821Eh, 3EBEh, 0D208h, 3EBDh, 821Fh, 3ECAh, 8386h + DW 3EC1h, 8C03h, 3EC9h, 831Eh, 3ECAh, 8C4Ch, 3EBFh, 8C55h + + DW 3EC9h, 0C208h, 3EC4h, 0BC84h, 3EC8h, 8EADh, 3EC8h, 0D308h + DW 3EC2h, 8F7Eh, 3ECBh, 821Eh, 3ECBh, 0D208h, 3EC5h, 831Fh + DW 3EC6h, 0C308h, 3EC3h, 0B2FFh, 3EC9h, 8265h, 3EC9h, 831Eh + DW 1342h, 0D308h, 3EC7h, 0B3FFh, 0, 8365h, 1420h, 9570h + +InitTable4 Label + DW 0C10h, 8470h, 14FEh, 0B488h, 167Fh, 0A470h, 18E7h, 84B5h + DW 1B6Eh, 842Ah, 1F1Dh, 852Ah, 0DA3h, 0F7Ch, 167Eh, 7254h + DW 0, 842Ah, 1, 852Ah, 18E6h, 0BAAh, 1B6Dh, 7234h + DW 229Fh, 8429h, 2746h, 8529h, 1F1Ch, 6E7h, 229Eh, 7224h + + DW 0DA4h, 8429h, 2C29h, 8529h, 2745h, 07F6h, 2C28h, 7254h + DW 383Bh, 8428h, 320Fh, 8528h, 320Eh, 0F02h, 1341h, 7264h + DW 3EB6h, 8428h, 3EB9h, 8528h, 383Ah, 0FA9h, 3EB5h, 7294h + DW 3EB7h, 8474h, 3EBAh, 8575h, 3EB8h, 44C3h, 3EBBh, 45C3h + + DW 00000, 0A404h, 00001, 0A504h, 141Fh, 0671h, 14FDh, 287h + DW 3EBCh, 0E610h, 3EC8h, 0C7Bh, 31Ah, 7E6h, 3EC8h, 86F7h + DW 3EC0h, 821Eh, 3EBEh, 0D208h, 3EBDh, 021Fh, 3ECAh, 386h + DW 3EC1h, 0C03h, 3EC9h, 31Eh, 3ECAh, 8C4Ch, 3EBFh, 0C55h + + DW 3EC9h, 0C208h, 3EC4h, 0BC84h, 3EC8h, 0EADh, 3EC8h, 0D308h + DW 3EC2h, 8F7Eh, 3ECBh, 021Eh, 3ECBh, 0D208h, 3EC5h, 31Fh + DW 3EC6h, 0C308h, 3EC3h, 32FFh, 3EC9h, 0265h, 3EC9h, 831Eh + DW 1342h, 0D308h, 3EC7h, 33FFh, 0, 8365h, 1420h, 9570h + +AWEVolumeTable Label Byte ; Value = -log(vol/256)*(20/.375) + ; = -log(vol/256)*(160/3) + + DB 255, 128, 112, 103, 96, 91, 87, 83 ; 0->7 + DB 80, 78, 75, 73, 71, 69, 67, 66 ; 8->15 + DB 64, 63, 61, 60, 59, 58, 57, 56 ; 16->23 + DB 55, 54, 53, 52, 51, 50, 50, 49 ; 24->31 + DB 48, 47, 47, 46, 45, 45, 44, 44 ; 32->39 + DB 43, 42, 42, 41, 41, 40, 40, 39 ; 40->47 + DB 39, 38, 38, 37, 37, 36, 36, 36 ; 48->55 + DB 35, 35, 34, 34, 34, 33, 33, 32 ; 56->63 + DB 32, 32, 31, 31, 31, 30, 30, 30 ; 64->71 + DB 29, 29, 29, 28, 28, 28, 28, 27 ; 72->79 + DB 27, 27, 26, 26, 26, 26, 25, 25 ; 80->87 + DB 25, 25, 24, 24, 24, 23, 23, 23 ; 88->95 + DB 23, 22, 22, 22, 22, 22, 21, 21 ; 96->103 + DB 21, 21, 20, 20, 20, 20, 20, 19 ; 104->111 + DB 19, 19, 19, 19, 18, 18, 18, 18 ; 112->119 + DB 18, 17, 17, 17, 17, 17, 16, 16 ; 120->127 + DB 16 ; 128 + + Comment ~ ; Value = -log(vol/128)*(20/.375) + ; = -log(vol/128)*(160/3) + ; This is mathematically the correct table, but it seems too + ; loud, and it overloads on playback. + + DB 255, 112, 96, 87, 80, 75, 71, 67 ; 0->7 + DB 64, 61, 59, 57, 55, 53, 51, 50 ; 8->15 + DB 48, 47, 45, 44, 43, 42, 41, 40 ; 16->23 + DB 39, 38, 37, 36, 35, 34, 34, 33 ; 24->31 + DB 32, 31, 31, 30, 29, 29, 28, 28 ; 32->39 + DB 27, 26, 26, 25, 25, 24, 24, 23 ; 40->47 + DB 23, 22, 22, 21, 21, 20, 20, 20 ; 48->55 + DB 19, 19, 18, 18, 18, 17, 17, 16 ; 56->63 + DB 16, 16, 15, 15, 15, 14, 14, 14 ; 64->71 + DB 13, 13, 13, 13, 12, 12, 12, 11 ; 72->79 + DB 11, 11, 10, 10, 10, 9, 9, 9 ; 80->87 + DB 9, 8, 8, 8, 8, 7, 7, 7 ; 88->95 + DB 7, 6, 6, 6, 6, 5, 5, 5 ; 96->103 + DB 5, 4, 4, 4, 4, 4, 4, 3 ; 104->111 + DB 3, 3, 3, 2, 2, 2, 2, 2 ; 112->119 + DB 1, 1, 1, 1, 1, 1, 1, 1 ; 120->127 + DB 0 + + ~ + +GUSScreenList Label + DW 7 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr GravisHeaderLine + + DW Near Ptr MixerText + DW Near Ptr VolumeBox1 + DW Near Ptr VolumeBox2 + + DW Near Ptr MasterVolumeLeft ; 7 + DW Near Ptr MasterVolumeRight + DW Near Ptr TrebleVolumeLeft + DW Near Ptr TrebleVolumeRight + DW Near Ptr BassVolumeLeft + DW Near Ptr BassVolumeRight ; 12 + + DW Near Ptr SampleText + + DW Near Ptr SampleSize0Button ; 14 + DW Near Ptr SampleSize1Button + DW Near Ptr SampleSize2Button + DW Near Ptr SampleSize3Button ; 17 + + DW Near Ptr EffectText + DW Near Ptr EffectBox + + DW Near Ptr ChorusThumbBar ; 20 + DW Near Ptr ReverbThumbBar + + DW DriverText + + DW 0 + +GravisHeaderLine DW 10 + DB "Sound Blaster AWE 32 Driver", 0 + +DriverText DW 1 + DB 27, 48 + DB 21h + DB "Sound Blaster AWE 32 Driver 1.5 for Impulse Tracker", 0 + +MixerText DW 1 + DB 3, 13 + DB 20h + DB "Mixer options", 13 + DB 13 + DB " Master Volume Left", 13 + DB " Master Volume Right", 13 + DB 13 + DB 13 + DB " Treble Left", 13 + DB " Treble Right", 13 + DB " Bass Left", 13 + DB " Bass Right", 13 + DB 0 + +VolumeBox1 DW 0 + DB 24, 14, 30, 17 + DB 25 + +VolumeBox2 DW 0 + DB 17, 18, 21, 23 + DB 25 + +MasterVolumeLeft DW 9 + DB 25, 15 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 8, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 25, 16 + DW 0, 31 + DW 9, 1 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeLeft DW 9 + DB 18, 19 + DW 0, 15 + DW 9, 2 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeRight DW 9 + DB 18, 20 + DW 0, 15 + DW 9, 3 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeLeft DW 9 + DB 18, 21 + DW 0, 15 + DW 9, 4 + DW 10, 12, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeRight DW 9 + DB 18, 22 + DW 0, 15 + DW 9, 5 + DW 11, 14, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +SampleText DW 1 + DB 3, 25 + DB 20h + DB "Sample resizing options", 0 + +SampleSize0Button DW 2 + DW 12, 15, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment1 DW 0 + DW 0 + DW Offset SetCompress +DriverSegment2 DW 0 + DB 7, 27, 20, 29, 8 + DB 0 + DB " Original", 0 + +SampleSize1Button DW 2 + DW 14, 16, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment3 DW 0 + DW 1 + DW Offset SetCompress +DriverSegment4 DW 0 + DB 7, 30, 20, 32, 8 + DB 0 + DB " Half", 0 + +SampleSize2Button DW 2 + DW 15, 17, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment5 DW 0 + DW 2 + DW Offset SetCompress +DriverSegment6 DW 0 + DB 7, 33, 20, 35, 8 + DB 0 + DB " Quarter", 0 + +SampleSize3Button DW 2 + DW 16, 20, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment7 DW 0 + DW 3 + DW Offset SetCompress +DriverSegment8 DW 0 + DB 7, 36, 20, 38, 8 + DB 0 + DB " Eighth", 0 + +EffectText DW 1 + DB 3, 40 + DB 20h + DB "Effect options", 13 + DB 13 + DB " Chorus", 13 + DB " Reverb", 0 + + +EffectBox DW 0 + DB 12, 41, 30, 44 + DB 25 + +ChorusThumbBar DW 9 + DB 13, 42 + DW 0, 127 + DW 9, 6 + DW 17, 21, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +ReverbThumbBar DW 9 + DB 13, 43 + DW 0, 127 + DW 9, 7 + DW 20, 0FFFFh, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + + + +VolumeTable DB 6 Dup (0) +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 2 +Chorus DB 10, 64 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +ALIGN 16 +FPSave DB 128 Dup (0) + +AWEParameters DB 64 Dup (0FFh), 64 Dup (0) + +include dma.inc + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc UARTOut + + Push CX + Push DX + Mov DX, CS:MIDIPort + Test DX, DX + JZ UARTOutEnd + + Push AX + Xor CX, CX + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + LoopNZ UARTOut1 + + Pop AX + JNZ UARTOutEnd + + Dec DX + Out DX, AL + +UARTOutEnd: + Pop DX + Pop CX + + Ret + +EndP UARTOut + +; + + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:AWEParameters+BX], AL + + Pop BX + + Mov CS:InterpretState, 0 + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Ret + +SendUARTOut3: + Mov InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset AWEParameters + Mov CX, 32 + Or AX, -1 + Rep StosW + Mov CX, 32 + Inc AX + Rep StosW + + Pop ES + PopA + +SendUARTOutNoClear: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +Proc DetectUART ; Given DX = Port + +; outportb(BasePort+1, 0xFF); +; while(InputUART() != 0xFE); +; outportb(BasePort+1, 0x3F); +; while(InputUART() != 0xFE); + + ClI + + Inc DX + Mov AL, 0FFh ; reset + Out DX, AL + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 80h + LoopNZ DetectUART1 + JNZ DetectUARTFailed + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JNE DetectUART1 + + Xor CX, CX + +DetectUART3: + In AL, DX + Test AL, 40h + LoopNZ DetectUART3 + JNZ DetectUARTFailed + + Mov AL, 03Fh + Out DX, AL + + Xor CX, CX + +DetectUART2: + In AL, DX + Test AL, 80h + LoopNZ DetectUART2 + JNZ DetectUARTFailed + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JNE DetectUART2 + Dec DX + + ClC + StI + Ret + +DetectUARTFailed: + StC + StI + Ret + +Comment ~ + +; From SB-DevKit + + ClI + + Inc DX + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 40h ; Ready for output + LoopNZ DetectUART1 + JNZ DetectUARTError + + Mov AL, 0FFh ; Reset! + Out DX, AL + + Xor CX, CX + +DetectUART2: + In AL, DX + Test AL, 80h + JNZ DetectUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART4 + +DetectUART3: + Loop DetectUART2 + +DetectUARTError: + StI + StC + Ret + +DetectUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +DetectUART5: + In AL, DX + Test AL, 40h + LoopNZ DetectUART5 + JNZ DetectUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +DetectUART6: + Xor CX, CX + +DetectUART7: + In AL, DX + Test AL, 80h + JNZ DetectUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART9 + +DetectUART8: + Loop DetectUART7 + + Jmp DetectUARTError + +DetectUART9: + StI + ClC + Ret + +~ + +EndP DetectUART + +; + +Proc ReinitUART + + Mov DX, MIDIPort + Test DX, DX + JZ ReinitUART1 + + Call DetectUART + +ReinitUART1: + Ret + +EndP ReinitUART + +; + +Proc ResetUART + + Mov DX, MIDIPort + Test DX, DX + JZ ResetUART1 + + Inc DX + + Mov AL, 0FFh + Out DX, AL + +ResetUART1: + Ret + +EndP ResetUART + +; + +Proc SetCompress Far + + Mov CX, [SI+22] + Mov CS:Compress, CL + + Mov AX, 1 + ShL AX, CL + Mov CS:Step, AX + + Call Music_LoadAllSamples + + Mov AX, 1 + Ret + +EndP SetCompress + +; + +Proc GetCompress Far + + Push CS + Pop ES + Mov DI, Offset Compress + + Ret + +EndP GetCompress + +; + +Proc Load8BitSamplesForwards ; Given DS:SI, ECX = count + + Push BX + + Mov BX, CS:Step + Mov DX, CS:BasePort + Add DX, 400h + Xor AL, AL + +Load8BitSamplesForwards2: + Mov AH, [SI] + Add SI, BX + JC Load8BitSamplesForwards4 + +Load8BitSamplesForwards3: + Out DX, AX + + Dec ECX + JNZ Load8BitSamplesForwards2 + + Pop BX + Ret + +Load8BitSamplesForwards4: + Add ESI, 10000h + Int 3 + Jmp Load8BitSamplesForwards3 + +EndP Load8BitSamplesForwards + +; + +Proc Load16BitSamplesForwards ; Given DS:SI, ECX = count + + Push BX + + Mov BX, CS:Step + Mov DX, CS:BasePort + Add DX, 400h + Add BX, BX + +Load16BitSamplesForwards2: + Mov AX, [SI] + Add SI, BX + JC Load16BitSamplesForwards4 + +Load16BitSamplesForwards3: + Out DX, AX + + Dec ECX + JNZ Load16BitSamplesForwards2 + + Pop BX + Ret + +Load16BitSamplesForwards4: + Add ESI, 10000h + Int 3 + Jmp Load16BitSamplesForwards3 + +EndP Load16BitSamplesForwards + +; + +Proc Load8BitSamplesBackwards ; Given DS:SI, ECX = count + + Push BX + + Mov BX, CS:Step + Mov DX, CS:BasePort + Add DX, 400h + Xor AL, AL + + Sub SI, BX + JC Load8BitSamplesBackwards6 + +Load8BitSamplesBackwards2: + Sub SI, BX + JC Load8BitSamplesBackwards4 + +Load8BitSamplesBackwards3: + Mov AH, [SI] + Out DX, AX + + Dec ECX + JNZ Load8BitSamplesBackwards2 + + + Pop BX + Ret + +Load8BitSamplesBackwards4: + Sub ESI, 10000h + JC Load8BitSamplesBackwards5 + Int 3 + Jmp Load8BitSamplesBackwards3 + +Load8BitSamplesBackwards5: + Xor ESI, ESI + Jmp Load8BitSamplesBackwards3 + +Load8BitSamplesBackwards6: + Sub ESI, 10000h + Int 3 + Jmp Load8BitSamplesBackwards2 + + +EndP Load8BitSamplesBackwards + +; + +Proc Load16BitSamplesBackwards ; Given DS:SI, ECX = count + + Push BX + + Mov BX, CS:Step + Mov DX, CS:BasePort + Add DX, 400h + Add BX, BX + + Sub SI, BX + JC Load16BitSamplesBackwards6 + +Load16BitSamplesBackwards2: + Sub SI, BX + JC Load16BitSamplesBackwards4 + +Load16BitSamplesBackwards3: + Mov AX, [SI] + Out DX, AX + + Dec ECX + JNZ Load16BitSamplesBackwards2 + + Pop BX + Ret + +Load16BitSamplesBackwards4: + Sub ESI, 10000h + JC Load16BitSamplesBackwards5 + Int 3 + Jmp Load16BitSamplesBackwards3 + +Load16BitSamplesBackwards5: + Xor ESI, ESI + Jmp Load16BitSamplesBackwards3 + +Load16BitSamplesBackwards6: + Sub ESI, 10000h + Int 3 + Jmp Load16BitSamplesBackwards2 + + +EndP Load16BitSamplesBackwards + +; + +Proc WriteDataChannel + + Or AX, DX + +Proc WriteData ; Have BX/EBX = value + ; AX = xxyyh + ; ^ ^ + ; | | + ; | \-- value to send to pointer register + ; \---- 0, 1, 2 or 3, 4 + ; 0 = data reg 0 + ; 1 = data reg 1, dword + ; 2 = data reg 2 + ; 3 = data reg 3 + ; 4 = data reg 4, word + + Jmp $+2 + Jmp $+2 + + Push DX + Push AX + + Mov DX, BasePort + Add DX, 802h + And AX, 0FFh + Out DX, AX + Pop AX + + Jmp $+2 + Jmp $+2 + + Cmp AH, 1 + JB WriteDataReg0 + JE WriteDataReg1DWord + Cmp AH, 3 + JB WriteDataReg2 + JE WriteDataReg3 + Jmp WriteDataReg1Word + +WriteDataReg0: + Sub DX, 802h + Mov EAX, EBX + Out DX, EAX + + Pop DX + Ret + +WriteDataReg1DWord: + Sub DX, 402h + Mov EAX, EBX + Out DX, EAX + + Pop DX + Ret + +WriteDataReg1Word: + Sub DX, 402h + Mov AX, BX + Out DX, AX + + Pop DX + Ret + +WriteDataReg2: + Sub DX, 400h + Mov AX, BX + Out DX, AX + + Pop DX + Ret + +WriteDataReg3: + Sub DL, 2 + Mov AX, BX + Out DX, AX + + Pop DX + Ret + +EndP WriteData + +EndP WriteDataChannel + +; + +Proc ReadDataChannel + + Or AX, DX + +Proc ReadData ; AX = xxyyh + ; ^ ^ + ; | | + ; | \-- value to send to pointer register + ; \---- 0, 1, 2 or 3, 4 + ; 0 = data reg 0 + ; 1 = data reg 1, dword + ; 2 = data reg 2 + ; 3 = data reg 3 + ; 4 = data reg 4, word + + Jmp $+2 + Jmp $+2 + + Push DX + Push AX + + Mov DX, BasePort + Add DX, 802h + And AX, 0FFh + Out DX, AX + Pop AX + + Jmp $+2 + Jmp $+2 + + Cmp AH, 1 + JB ReadDataReg0 + JE ReadDataReg1DWord + Cmp AH, 3 + JB ReadDataReg2 + JE ReadDataReg3 + Jmp ReadDataReg1Word + +ReadDataReg0: + Sub DX, 802h + In EAX, DX + + Pop DX + Ret + +ReadDataReg1DWord: + Sub DX, 402h + In EAX, DX + + Pop DX + Ret + +ReadDataReg1Word: + Sub DX, 402h + In AX, DX + + Pop DX + Ret + +ReadDataReg2: + Sub DX, 400h + In AX, DX + + Pop DX + Ret + +ReadDataReg3: + Sub DL, 2 + In AX, DX + + Pop DX + Ret + +EndP ReadData + +EndP ReadDataChannel + +; + +Const44100 DD 44100.0 +Const1000h DD 4096.0 +ConstE000h DD 57344.0 + +Proc SetAWEFrequency + + Mov EAX, [SI+10h] ; Final freq + + Push CX + Mov CL, Compress + ShR EAX, CL + Pop CX + +; Test EAX, EAX + JZ SetAWEFrequencyError + Cmp EAX, 88200*2 + JAE SetAWEFrequencyError + + Mov DWord Ptr [SI+4], EAX + + FLd CS:ConstE000h + FLd CS:Const1000h + FILd DWord Ptr [SI+4] + FDiv CS:Const44100 + FYL2X ; ST = ln(Pitch/44100)/ln(2) * 1000h + FAddP ST(1) + FIStP DWord Ptr [SI+4] + + Mov AX, IP + Mov BX, [SI+4] + Call WriteDataChannel + + Ret + Assume DS:Nothing + +SetAWEFrequencyError: + Call StopAWENote + + Mov Word Ptr [SI], 200h + Test Byte Ptr [SI+3Ah], 80h + JNZ SetAWEFrequencyError1 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + +SetAWEFrequencyError1: + Mov AX, IP + Xor EBX, EBX + Call WriteDataChannel + + Push DS SI + + Push CS + Pop DS + Mov SI, Offset FrequencyError + Mov BX, 40 + Call SetInfoLine + + Pop SI DS + + Ret + +EndP SetAWEFrequency + Assume DS:Nothing + +; + +Proc SetAWEPan + + Mov AX, PSST + Call ReadDataChannel ; Get starting offset + + Cmp CS:Stereo, 0 + JE SetPan2 + + Test CL, 128 + JNZ SetPan2 + + Mov BL, [SI+37h] ; Final pan + Cmp BL, 100 ; Surround -> central + JNE SetPan1 + +SetPan2: + Mov BL, 32 + +SetPan1: ; BL = 0->64, need to extend to 0->255 + Add BL, BL + Add BL, BL + SBB BL, 0 ; BL = 0->255 + Not BL + + ShL EAX, 8 + SHLD EBX, EAX, 24 + Mov AX, PSST + Call WriteDataChannel + + Ret + +EndP SetAWEPan + +; + +Proc SetAWEVolume + + Test CH, 8 + JZ SetAWEVolume1 + + Test CH, 1 + JNZ SetAWEVolume5 + + Cmp Byte Ptr [SI+8], 0FFh + JE SetAWEVolume4 + +SetAWEVolume5: + Mov Byte Ptr [SI+8], 0FFh + + Mov AX, IFATN + Call ReadDataChannel + Mov BX, AX + Mov AX, IFATN + Mov BL, 0FFh + Call WriteDataChannel + +SetAWEVolume4: + Ret + +SetAWEVolume1: +; First check if channel has been disowned + Xor BX, BX + Mov BL, [SI+3Ah] ; BL = host channel + + Test BL, BL + JS SetAWEVolume3 + +SetAWEVolume2: + Mov AH, [CS:AWEParameters+BX] ; AH = filter + Mov AL, [CS:AWEParameters+BX+64] ; AL = Q. + + ShR AL, 3 + Mov [SI+5Bh], AH + + Cmp AL, [SI+3Fh] + JE SetAWEVolume3 + + Mov [SI+3Fh], AL + +; Set Q + Mov BL, AL + ShL EBX, 28 + + Mov AX, CCCA + Call ReadDataChannel + And EAX, 0FFFFFFFh + Or EBX, EAX + Mov AX, CCCA + Call WriteDataChannel + +SetAWEVolume3: + Mov AL, [SI+3Eh] + Mul Byte Ptr [SI+5Bh] + ShL AX, 1 + Xor BX, BX + Add AH, 1 + Mov BL, [SI+20h] ; Final volume + Mov [SI+8], BL + Mov BL, [CS:AWEVolumeTable+BX] + Mov BH, AH + Mov AX, IFATN + Call WriteDataChannel + + Ret + +EndP SetAWEVolume + +; + +Proc StopAWENote + + Mov AX, DCYSUSV + Mov BX, 80h + Call WriteDataChannel + + Mov AX, VTFT + Mov EBX, 0FFFFh + Call WriteDataChannel + + Mov AX, CVCF + Call WriteDataChannel + + Mov BX, 80h + Mov AX, DCYSUSV + Call WriteDataChannel + + Mov AX, VTFT + Mov EBX, 0FFFFh + Call WriteDataChannel + + Mov AX, CVCF + Call WriteDataChannel + + Xor EBX, EBX + Mov AX, ENVVOL + Call WriteDataChannel + + Mov AX, ENVVAL + Call WriteDataChannel + + Mov AX, SUSDCY + Call WriteDataChannel + + Mov AX, ATKHLDV + Call WriteDataChannel + + Mov AX, LFO1VAL + Call WriteDataChannel + + Mov AX, HLDATK + Call WriteDataChannel + + Mov AX, LFO2VAL + Call WriteDataChannel + + Mov AX, IP + Call WriteDataChannel + + Mov AX, IFATN + Call ReadDataChannel + Mov BH, AH + Mov AX, IFATN + Call WriteDataChannel + + Xor EBX, EBX + Mov AX, PEFE + Call WriteDataChannel + + Mov AX, FMMOD + Call WriteDataChannel + + Mov AX, TREMFRQ + Call WriteDataChannel + + Mov AX, FM2FRQ2 + Call WriteDataChannel + + Mov AX, PTRX + Call WriteDataChannel + + Mov AX, VTFT + Call WriteDataChannel + +; Mov AX, PSST +; Call WriteDataChannel + + Mov BL, 8 + Mov AX, CSL + Call WriteDataChannel + + Mov AX, CCCA + Call ReadDataChannel + Mov EBX, EAX + Mov AX, CCCA + And EBX, 0F0000000h + Call WriteDataChannel + + Xor EBX, EBX + Mov AX, CPF + Call WriteDataChannel + + Ret + +EndP StopAWENote + +; + +Proc SetAWERegisters ; DS:SI = channel info table + ; CX = number of channels... + + Push CX + Push SI + + ; Stage 1. + ; Turn off any channel which has + ; a new note to play + ; If no new note to play and channel + ; is on, then get current position + + Xor DX, DX ; DX = oscillator number + +GetAWERegisters1: + Mov BX, [SI] + Test BH, 2 ; Note cut command + JZ GetAWERegisters2 + + Mov BX, 200h + Mov [SI], BX + + Call StopAWENote + Jmp GetAWERegisters4 + +GetAWERegisters2: + Test BL, 1 ; Channel on? + JZ GetAWERegisters4 + + Test BH, 1 ; New note? + JZ GetAWERegisters3 + + ; Fade out volume +; Mov AX, DCYSUSV +; Mov BX, 807Fh +; Call WriteDataChannel + + Call StopAWENote + + Jmp GetAWERegisters4 + +GetAWERegisters3: ; Get offset + Mov AX, CCCA + Call ReadDataChannel + + Xor BX, BX + And EAX, 00000000111111111111111111111111b + Inc EAX ; Interpolator correction + ; EAX = address in sound memory + Mov BL, [SI+36h] ; BL = sample number + LEA BX, [EBX*4+EBX] + ShL BX, 2 + Add BX, Offset AWEDataTable + + Cmp Byte Ptr [SI+0Ah], 8 + JB GetAddressNoLoop + JE GetAddressForwardsLoop + +GetAddressPingPongLoop: + Cmp EAX, [CS:BX+16] + JB SetOldAddress + + Neg EAX + Add EAX, [CS:BX+8] + Jmp SetOldAddress1 + +GetAddressNoLoop: + Cmp EAX, [CS:BX+4] ; Start loop + JB SetOldAddress + + Call StopAWENote + + ; OK.. gotta turn off channel + Mov Word Ptr [SI], 0 + Test Byte Ptr [SI+3Ah], 80h + JNZ GetAWERegisters4 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + + Jmp GetAWERegisters4 + +GetAddressForwardsLoop: +SetOldAddress: + Sub EAX, [CS:BX] ; EAX = address in sample + JNS SetOldAddress1 + + Xor EAX, EAX + +SetOldAddress1: + Push CX + Mov CL, Compress + ShL EAX, CL + Pop CX + + XChg [SI+4Ch], EAX + Mov [SI+2Ch], EAX + +GetAWERegisters4: + Add SI, 128 + + Inc DX + Dec CX + JNZ GetAWERegisters1 + + Pop SI + Pop CX + + Xor DX, DX ; DX = oscillator number + +SetAWERegisters1: + ; Stage 2. + ; If new frequency, play new frequency + ; If new volume, play new volume + ; If new pan, play new pan + ; If new note, set ENVVOL, ENVVAL, SUSDCY, ATKHLDV, LFO1VAL, HLDATK + ; LFO2VAL, IP, IFATN, PEFE, FMMOD, TREMFRQ, FM2FRQ2 + ; PSST, CSL, CCCA + ; VTFT, CVCF, DCYSUSV, PTRX, CPF + + Push CX + Mov CX, [SI] + Test CL, 1 ; Channel on? + JZ SetAWERegistersEnd + + Test CH, 1 ; New note? + JZ SetAWERegisters2 + + Xor BX, BX + Mov BL, [SI+36h] + LEA DI, [EBX*4+EBX] + ShL DI, 2 + Add DI, Offset AWEDataTable + + Mov AX, DCYSUSV + Mov BX, 80h + Call WriteDataChannel + + Mov AX, VTFT + Xor EBX, EBX + Call WriteDataChannel + + Mov AX, CVCF + Call WriteDataChannel + + Cmp DWord Ptr [CS:DI], 0FFFFFFFFh + JE SetAWERegistersError + + Mov AX, PTRX + Call WriteDataChannel + + Mov AX, CPF + Call WriteDataChannel + + + Mov AX, ENVVOL + Mov BX, 8000h + Call WriteDataChannel + + Mov AX, ENVVAL + Mov BX, 8000h + Call WriteDataChannel + + Mov AX, SUSDCY + Mov BX, 7F7Fh + Call WriteDataChannel + + Mov AX, ATKHLDV + Call WriteDataChannel + + Mov AX, LFO1VAL + Mov BX, 8000h + Call WriteDataChannel + + Mov AX, HLDATK + Mov BX, 7F7Fh + Call WriteDataChannel + + Mov AX, LFO2VAL + Mov BX, 8000h + Call WriteDataChannel + + Call SetAWEFrequency + Call SetAWEVolume + + Mov AX, PEFE + Xor BX, BX + Call WriteDataChannel + + Mov AX, FMMOD + Call WriteDataChannel + + Mov AX, TREMFRQ + Mov BX, 10h + Call WriteDataChannel + + Mov AX, FM2FRQ2 + Call WriteDataChannel + + + Mov EBX, [CS:DI+4] + Dec EBX ; Interpolator offset + Mov AX, PSST + Call WriteDataChannel + + Call SetAWEPan + + Mov AL, [CS:VolumeTable+6] ; Chorus + ShL EAX, 24 + Mov EBX, [CS:DI+8] + Dec EBX ; Interpolator offset + Or EBX, EAX + Mov AX, CSL + Call WriteDataChannel + + Mov AL, [SI+3Fh] + ShL EAX, 28 + + Push CX + Mov CL, Compress + Mov EBX, [SI+4Ch] + ShR EBX, CL + Pop CX + Add EBX, [CS:DI] + Dec EBX ; Interpolator offset + Or EBX, EAX + + Mov AX, CCCA ; Current address. + Call WriteDataChannel + + + Mov AX, VTFT + Mov EBX, 0FFFFh + Call WriteDataChannel + + Mov AX, CVCF + Call WriteDataChannel + + Mov AX, DCYSUSV + Mov BX, 7F7Fh + Call WriteDataChannel + + Mov AX, PTRX + Mov EBX, 40000000h ; 25% reverb + Or BH, [CS:VolumeTable+7] + Call WriteDataChannel + + Mov AX, CPF + Call WriteDataChannel + Jmp SetAWERegistersEnd + +SetAWERegisters2: + Test CL, 32 ; Frequency change? + JZ SetAWERegisters3 + + Call SetAWEFrequency + +SetAWERegisters3: + Test CL, 64 ; Volume change? + JZ SetAWERegisters4 + + Call SetAWEVolume + +SetAWERegisters4: + Test CH, 80h ; New pan? + JZ SetAWERegistersEnd + + Call SetAWEPan + +SetAWERegistersEnd: + Pop CX + And Word Ptr [SI], 0111100010011111b + + Add SI, 128 + + Inc DX + Dec CX + JNZ SetAWERegisters1 + + Ret + +SetAWERegistersError: + Call StopAWENote + + Mov Word Ptr [SI], 0 + Test Byte Ptr [SI+3Ah], 80h + JNZ SetAWERegistersEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + + Jmp SetAWERegistersEnd + +EndP SetAWERegisters + +; + +Proc ACKIRQ + + Mov AL, 20h + Cmp CS:IRQ, 7 + JBE ACKIRQ1 + + Out 0A0h, AL + +ACKIRQ1: + Out 20h, AL + Ret + +EndP ACKIRQ + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Mov DX, MIDIPort + + Mov BL, [MIDIBufferTail] + Test DX, DX + JZ CheckMIDIEnd + + Inc DX + +CheckMIDIAgain: + In AL, DX + + Test AL, AL + JS CheckMIDIAgain + + Dec DX + In AL, DX + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc MIDIIRQHandler + + Push AX BX DX + + Mov DX, CS:MixerPort + Mov AL, 82h + Out DX, AL + Inc DL + In AL, DX + + Test AL, 4 + JZ MIDIIRQHandlerEnd + + Call CheckMIDI + +MIDIIRQHandlerEnd: + Call AckIRQ + + Pop DX BX AX + IRet + + +EndP MIDIIRQHandler + +; + +Proc SBIRQHandler + + PushAD + Push DS + Push ES + + StI + + Push CS + Pop DS + Assume DS:Driver + + FNSave [FPSave] + +SBIRQHandlerAgain: + Mov DX, MixerPort + Mov AL, 82h + Out DX, AL + Inc DL + In AL, DX + + Test AL, 4 + JZ NoMIDIIRQ + + Push AX + Call CheckMIDI + Pop AX + +NoMIDIIRQ: +; Test AL, 2 +; JZ No16BitIRQ +; +; Push AX +; Mov DX, MixerPort +; Add DL, 0Fh-4 +; In AL, DX +; Pop AX +; +; No16BitIRQ: + Test AL, 1 + JNZ SB8BitIRQ + +SBNo8BitIRQ: + Call AckIRQ + Jmp SBEndIRQ + +SB8BitIRQ: + Mov DX, MixerPort + Add DL, 0Eh-4 + In AL, DX ; 8-bit IRQ ack. + + +; Add DL, 0Ch-0Eh + +; Mov AL, 80h ; Output block of silence +; Call SBOut +; Mov AX, BlockLength2 +; Call SBOut +; Mov AL, AH +; Call SBOut + + ClD + Call ACKIRQ + + Inc IRQFlag + JNZ SBEndIRQ + + Call SaveEMSPageFrame + Assume DS:Nothing + +SB8BitIRQAgain: + Call Update ; Returns DS:SI, CX + + Mov BX, BlockLength + Cmp BX, BlockLength2 + JE SBIRQHandler2 + Mov BlockLength2, BX + + Mov DX, SB16BasePort + Add DL, 0Ch + + MOv AL, 0DAh + Call SBOut + Mov AL, 0C6h + Call SBOut + Xor AL, AL + Call SBOut + Mov AL, BL + Call SBOut + Mov AL, BH + Call SBOut + +; Mov AL, 0D0h +; Call SBOut + +; Mov AL, 80h ; Output block of silence +; Call SBOut +; Mov AL, BL +; Call SBOut +; Mov AL, BH +; Call SBOut + +SBIRQHandler2: + Call SetAWERegisters + Sub CS:IRQFlag, 1 + JNC SB8BitIRQAgain + + Call RestoreEMSPageFrame + +SBEndIRQ: + FRstor [CS:FPSave] + + Pop ES + Pop DS + PopAD + + IRet + +EndP SBIRQHandler + Assume DS:Nothing + +; + +Proc AWEIRQHandler ; IRQ Handler has to + ; 1) Update AWE registers + ; 2) Update song position + Push AX + Push DS + + Mov AX, AWEUpdateTimer + Add AWEUpdateCount, AX + JC AWEIRQHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp AWEIRQHandler2 + +AWEIRQHandler1: + PushF + Call [OldIRQHandler] + +AWEIRQHandler2: + Xor AWEUpdateFlag, 1 + JZ AWEIRQHandlerEnd + + FNSave [CS:FPSave] + + PushAD + Push ES + + ClD + + Call SaveEMSPageFrame + Call Update ; Returns DS:SI, CX + Call SetAWERegisters + Call RestoreEMSPageFrame + + Pop ES + PopAD + + FRstor [CS:FPSave] + +AWEIRQHandlerEnd: + Pop DS + Pop AX + IRet + +EndP AWEIRQHandler + +; + +Proc EnableRAM + + Mov DX, BasePort + Mov CX, 29 + +EnableRAM1: + Mov AX, DCYSUSV + Or AX, CX + Mov BX, 80h + Call WriteData + + Mov AX, VTFT + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CVCF + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, PTRX + Or AX, CX + Mov EBX, 40000000h + Call WriteData + + Mov AX, CPF + Or AX, CX + Mov EBX, 40000000h + Call WriteData + + Mov AX, PSST + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CSL + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CCCA + Or AX, CX + Mov EBX, 6000000h ; Left write + Call WriteData + + Dec CX + JNS EnableRAM1 + + Ret + +EndP EnableRAM + +; + +Proc TestAWE ; Given DX = baseport. + + Push DX + + Add DX, 802h + In AL, DX + In AL, DX + Not AL + Mov BL, AL + Out DX, AL + In AL, DX + Cmp AL, BL + JNE TestAWE1 ; Register changed + + In AX, DX ; Is upper part of pointer + Mov BX, AX ; changing? + Mov CX, 128 + +TestAWE2: + In AX, DX + Cmp AL, BL + JNE TestAWE1 + Cmp AH, BH + JNE TestAWE3 + + Dec CX + JNZ TestAWE2 + Jmp TestAWE1 + +TestAWE3: + Pop DX + + ClC + Ret + +TestAWE1: + Pop DX + StC + Ret + +EndP TestAWE + +; + +Proc InitSetAWE + + Mov CX, 31 + +InitSetAWE1: + Mov AX, 31 + Sub AX, CX + Mov BX, [SI] + Or AX, INIT1 + Call WriteData + + Add SI, 2 + + Dec CX + JNS InitSetAWE1 + + Mov CX, 31 + +InitSetAWE2: + Mov AX, 31 + Sub AX, CX + Mov BX, [SI] + Or AX, INIT2 + Call WriteData + + Add SI, 2 + + Dec CX + JNS InitSetAWE2 + + Mov CX, 31 + +InitSetAWE3: + Mov AX, 31 + Sub AX, CX + Mov BX, [SI] + Or AX, INIT3 + Call WriteData + + Add SI, 2 + + Dec CX + JNS InitSetAWE3 + + Mov CX, 31 + +InitSetAWE4: + Mov AX, 31 + Sub AX, CX + Mov BX, [SI] + Or AX, INIT4 + Call WriteData + + Add SI, 2 + + Dec CX + JNS InitSetAWE4 + + Ret + +EndP InitSetAWE + +; + +Proc InitAWE + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + + Mov AX, HWCF1 + Mov BX, 59h + Call WriteData + + Mov AX, CFG2 + Mov BX, 20h + Call WriteData + + Mov CX, 31 + +InitAwe1: + Mov BX, 80h + Mov AX, DCYSUSV + Or AX, CX + Call WriteData + + Xor EBX, EBX + Mov AX, ENVVOL + Or AX, CX + Call WriteData + + Mov AX, ENVVAL + Or AX, CX + Call WriteData + + Mov AX, SUSDCY + Or AX, CX + Call WriteData + + Mov AX, ATKHLDV + Or AX, CX + Call WriteData + + Mov AX, LFO1VAL + Or AX, CX + Call WriteData + + Mov AX, HLDATK + Or AX, CX + Call WriteData + + Mov AX, LFO2VAL + Or AX, CX + Call WriteData + + Mov AX, IP + Or AX, CX + Call WriteData + + Mov AX, IFATN + Or AX, CX + Call WriteData + + Mov AX, PEFE + Or AX, CX + Call WriteData + + Mov AX, FMMOD + Or AX, CX + Call WriteData + + Mov AX, TREMFRQ + Or AX, CX + Call WriteData + + Mov AX, FM2FRQ2 + Or AX, CX + Call WriteData + + Mov AX, PTRX + Or AX, CX + Call WriteData + + Mov AX, VTFT + Or AX, CX + Call WriteData + + Mov AX, PSST + Or AX, CX + Call WriteData + + Mov AX, CSL + Or AX, CX + Call WriteData + + Mov AX, CCCA + Or AX, CX + Call WriteData + + Dec CX + JNS InitAWE1 + + Mov CX, 31 + +InitAWE8: + Mov AX, CPF + Or AX, CX + Call WriteData + + Mov AX, CVCF + Or AX, CX + Call WriteData + + Dec CX + JNS InitAWE8 + ; Initialise still... + Mov AX, SMALR + Call WriteData + + Mov AX, SMARR + Call WriteData + + Mov AX, SMALW + Call WriteData + + Mov AX, SMARW + Call WriteData + + Mov SI, Offset InitTable1 + Call InitSetAWE + + ; Wait for 1024 sample periods + Mov AX, WC + Call ReadData + + Mov BX, AX + Mov CX, AX + Add CX, 400h ; 1024 + Cmp BX, CX + JB InitAWE3 + +InitAWE4: + Mov AX, WC + Call ReadData + Cmp AX, CX + JA InitAWE4 + +InitAWE3: + Mov AX, WC + Call ReadData + Cmp AX, CX + JB InitAWE3 + + Mov SI, Offset InitTable2 + Call InitSetAWE + + Mov SI, Offset InitTable3 + Call InitSetAWE + + Mov AX, HWCF4 + Xor EBX, EBX + Call WriteData + + Mov AX, HWCF5 + Mov EBX, 83h + Call WriteData + + Mov AX, HWCF6 + Mov EBX, 8000h + Call WriteData + + Mov SI, Offset InitTable4 + Call InitSetAWE + + Mov AX, HWCF3 + Mov BX, 4 + Call WriteData + + Ret + +EndP InitAWE + Assume DS:Nothing + +; + +Proc InitDRAMRefresh + + Mov AX, DCYSUSV+1Eh + Mov BX, 80h + Call WriteData + + Mov AX, DCYSUSV+1Fh + Call WriteData + +; + + Mov AX, VTFT+1Eh + Xor EBX, EBX + Call WriteData + + Mov AX, CVCF+1Eh + Call WriteData + + Mov AX, VTFT+1Fh + Call WriteData + + Mov AX, CVCF+1Fh + Call WriteData + +; + + Mov AX, PTRX+1Eh + Call WriteData + + Mov AX, CPF+1Eh + Call WriteData + + Mov AX, PTRX+1Fh + Call WriteData + + Mov AX, CPF+1Fh + Call WriteData + +; + + Mov AX, PSST+1Eh + Call WriteData + Mov AX, PSST+1Fh + Call WriteData + + Mov BX, 0FFFFh + Mov AX, CSL+1Eh + Call WriteData + Mov AX, CSL+1Fh + Call WriteData + + Xor BX, BX + Mov AX, CCCA+1Eh + Call WriteData + Mov AX, CCCA+1Fh + Call WriteData + + Ret + +EndP InitDRAMRefresh + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + + ShR AL, 7 + LoopZ SBIn + +; Test AL, AL +; JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov DX, BasePort + Cmp DX, 0FFFFh + JE DetectCard1 + + Cmp DX, 620h + JB DetectCard3 + Cmp DX, 680h + JA DetectCard3 + + Call TestAWE + JNC DetectCardFound + Ret + +DetectCard1: + Mov DX, 620h + +DetectCard2: + Call TestAWE + JNC DetectCardFound + + Add DL, 20h + Cmp DL, 80h + JBE DetectCard2 + +DetectCard3: + StC + Ret + +DetectCardFound: + Mov BasePort, DX + + ; Initialise AWE 32 + Call InitAWE + Call InitDRAMRefresh + + ; Detect amount of RAM. + + Mov DX, BasePort + Mov CX, 29 + +DetectCardMemory1: + Mov AX, DCYSUSV + Or AX, CX + Mov BX, 80h + Call WriteData + + Mov AX, VTFT + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CVCF + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, PTRX + Or AX, CX + Mov EBX, 40000000h + Call WriteData + + Mov AX, CPF + Or AX, CX + Mov EBX, 40000000h + Call WriteData + + Mov AX, PSST + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CSL + Or AX, CX + Xor EBX, EBX + Call WriteData + + Mov AX, CCCA + Or AX, CX + Mov EBX, 4000000h ; Left read + + Test CL, 2 + JZ DetectCardMemory2 + + Mov EBX, 6000000h ; Left write + +DetectCardMemory2: + Call WriteData + + Dec CX + JNS DetectCardMemory1 + + Xor EDI, EDI ; Amount of memory stored in + ; EDI + + Mov AX, SMALW + Mov EBX, 200000h + Call WriteData + + Mov AX, SMLD + Mov BX, 0FFFFh + Call WriteData + + Mov AX, SMLD + Mov BX, 5555h + Call WriteData + + Mov AX, SMLD + Mov BX, 0AAAAh + Call WriteData + + Mov AX, SMALR + Mov EBX, 200000h + Call WriteData + + Mov AX, SMLD + Call ReadData + + Mov AX, SMLD + Call ReadData + Cmp AX, 0FFFFh + JNE DetectCardMemory6 + + Mov AX, SMLD + Call ReadData + Cmp AX, 5555h + JNE DetectCardMemory6 + + Mov AX, SMLD + Call ReadData + Cmp AX, 0AAAAh + JNE DetectCardMemory6 + + Mov EDI, 20000h + +DetectCardMemory3: ; Set read/write addresses.. + Mov AX, SMALW + Mov EBX, EDI + Add EBX, 200000h + Call WriteData + + Mov AX, SMLD + Mov BX, 5555h + Call WriteData + + Mov AX, SMLD + Mov BX, 0AAAAh + Call WriteData + + Mov AX, SMALR + Mov EBX, 200000h + Call WriteData + + Mov AX, SMLD + Call ReadData + + Mov AX, SMLD + Call ReadData + Cmp AX, 0FFFFh + JNE DetectCardMemory5 + + Mov AX, SMALR + Mov EBX, EDI + Add EBX, 200000h + Call WriteData + + Mov AX, SMLD + Call ReadData + + Mov AX, SMLD + Call ReadData + Cmp AX, 5555h + JNE DetectCardMemory5 + + Mov AX, SMLD + Call ReadData + Cmp AX, 0AAAAh + JNE DetectCardMemory5 + +DetectCardMemory4: + Add EDI, 20000h + Cmp EDI, 0E00000h + JB DetectCardMemory3 + +DetectCardMemory5: + Cmp EDI, 0DFFFE0h + JB DetectCardMemory7 + + Mov EDI, 0DFFFE0h + +DetectCardMemory7: + Test EDI, EDI + JZ DetectCardMemory6 + + Mov AWEMemory, EDI + + Mov MixerPort, 210h + Mov AX, BasePort + Sub AX, 400h + Call ResetDSP + JNC DetectMixer2 + +DetectMixer1: + Mov AX, MixerPort + Call ResetDSP + JNC DetectMixer2 + +DetectMixer3: + Add MixerPort, 10h + Cmp MixerPort, 280h + JBE DetectMixer1 + + Mov DX, BasePort + Sub DX, 400h + Mov MixerPort, DX + + Jmp DetectCard4 + +DetectMixer2: ; OK... DSP found. + ; Get DSP version + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + + Mov CX, 200 + +DetectMixerLoop1: + In AL, DX +; Test AL, AL +; JS DetectMixerLoop1 + ShR AL, 7 + LoopNZ DetectMixerLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AX, 40Ch ; SB DSP = 4.12+ + JB DetectMixer3 + + Sub DL, 0Eh + Mov MixerPort, DX + +DetectCard4: + Mov SB16BasePort, DX + Add MixerPort, 4 ; Mixerport + + Add DL, 4 + + Mov AL, 30h + Call SBGetRegister + ShR AL, 3 + Mov VolumeTable, AL + + Mov AL, 31h + Call SBGetRegister + ShR AL, 3 + Mov [VolumeTable+1], AL + + Mov AL, 44h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+2], AL + + Mov AL, 45h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+3], AL + + Mov AL, 46h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+4], AL + + Mov AL, 47h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+5], AL + + Mov DX, MixerPort + Mov AX, 0F834h + Out DX, AX + + Mov AL, 35h + Out DX, AX + + Mov DX, MixerPort + Mov AL, 80h ; IRQ select + Out DX, AL + Inc DL ; 2x5h = Mixer data port + + In AL, DX + + Dec DL + + Mov BX, IRQ + Cmp BX, 0FFFFh + JE DetectCardIRQ1 + Cmp Forced, 0 + JE DetectCardIRQ1 + + Mov AH, 11h + Cmp BL, 2 + JE SetCardIRQ1 + Cmp BL, 9 + JE SetCardIRQ1 + + Mov AH, 12h + Cmp BL, 5 + JE SetCardIRQ1 + + Mov AH, 14h + Cmp BL, 7 + JE SetCardIRQ1 + + Mov AH, 18h + Cmp BL, 10 + JE SetCardIRQ1 + + Jmp NoWindows + +SetCardIRQ1: + Mov AL, 80h + Out DX, AL + Inc DL + Mov AL, AH + Out DX, AL + Dec DL + Jmp DetectCard6 + +DetectCardIRQ1: + Mov BX, 2 + Test AL, 1 + JNZ DetectCardIRQ2 + + Mov BL, 5 + Test AL, 2 + JNZ DetectCardIRQ2 + + Mov BL, 7 + Test AL, 4 + JNZ DetectCardIRQ2 + + Mov BL, 10 + Test AL, 8 + JNZ DetectCardIRQ2 + + StC + Ret + +DetectCardIRQ2: + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + + Cmp BX, IRQ + JE DetectCard6 + + StC + Ret + +DetectCardIRQ3: + Mov IRQ, BX + +DetectCard6: + Mov AL, 81h + Out DX, AL + Inc DX + In AL, DX + Dec DX + + And AL, 11 + Xor BX, BX + Cmp AL, 1 + JE DetectCardDMA + + Inc BX + Cmp AL, 2 + JE DetectCardDMA + + Inc BX + Inc BX + Cmp AL, 8 + JNE NoWindows + +DetectCardDMA: + Mov DMA, BX + +DetectCardWindows: + Mov AX, 1600h ; Windows detection. + Int 2Fh + Test AL, 7Fh + JZ NoWindows + + Mov SBIRQMode, 1 + +NoWindows: + Mov EAX, 'Jeff' + ClC + Ret + +DetectCardMemory6: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc SetSamplingRate + Assume DS:Driver + + PushA + Push ES + + Mov AX, SB16BasePort + Call ResetDSP + +; Set dma + Mov BX, DMABuffer + Xor AX, AX + Mov DX, DMA + Mov DI, 512 + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, 256 + Rep StosW + + Mov DX, SB16BasePort + Add DL, 0Ch + +; Mov AL, 0D3h ; Turn off speaker +; Call SBOut + ; Set mixing frequency + Mov AL, 40h + Call SBOut + Mov AL, 0EAh + Call SBOut ; 45454Hz +; Mov AL, 211 +; Call SBOut ; 22222 Hz. + + Mov AL, 0C6h + Call SBOut + Xor AL, AL + Call SBOut + Mov AX, BlockLength + Dec AX + Call SBOut + Mov AL, AH + Call SBOut + + Pop ES + PopA + Ret + +EndP SetSamplingRate + Assume DS:Nothing + +; + +Proc SetMIDIIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset MIDIIRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetMIDIIRQ + +; + +Proc SetIRQ + Assume DS:Driver + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SBIRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc InitMIDI + Assume DS:Driver + + Mov DX, 330h + Call DetectUART + JC DetectMIDI1 + + Mov MIDIPort, 330h + Jmp DetectMIDIEnd + +DetectMIDI1: + Mov DX, 300h + Call DetectUART + JC DetectMIDIEnd + + Mov MIDIPort, 300h + +DetectMIDIEnd: + Ret + +EndP InitMIDI + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +FControlWord DW 0 + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + FNInit ; Initialise floating point + FNSTCW FControlWord + And FControlWord, 0F0FFh + FLDCW FControlWord + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov AX, CS + Mov DriverSegment1, AX + Mov DriverSegment2, AX + Mov DriverSegment3, AX + Mov DriverSegment4, AX + Mov DriverSegment5, AX + Mov DriverSegment6, AX + Mov DriverSegment7, AX + Mov DriverSegment8, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Cmp SBIRQMode, 0 + JE InitSound1 + + Cmp DMABuffer, 0 + JNE InitSound3 + + Mov AH, 48h + Mov BX, 1024/16 + Int 21h + JNC InitSound4 + + Mov SBIRQMode, 0 + Jmp InitSound1 + +InitSound4: + Mov DMABuffer, AX + +InitSound3: + Call SetIRQ + Call GetTempo + Call SetTempo + Call ResetMemory + Call SetSamplingRate + + Call InitMIDI + + Mov SI, Offset AWE32Msg2 + Mov AX, BasePort + + Mov BX, IRQ + Mov CX, DMA + + Ret + +InitSound1: + Call SetMIDIIRQ + Call GetTempo + Call SetTempo + Call ResetMemory + + Xor AX, AX + Mov ES, AX ; ES = 0 + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset AWEIRQHandler + + ClI + + XChg DWord Ptr [ES:20h], EAX ; Clock tick + Mov OldIRQHandler, EAX + + StI + +InitSound2: + Call InitMIDI + + Mov SI, Offset AWE32Msg + Mov AX, BasePort + + Mov EBX, AWEMemory + SHR EBX, 9 + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset AWE32ReinitMsg + Mov BX, 40 + Call SetInfoLine + + Call ResetUART + Call InitAWE + Call InitDRAMRefresh + + Cmp SBIRQMode, 0 + JE ReInitSound1 + + Call ResetIRQ + Call SetIRQ + Call SetSamplingRate + Call ReinitUART + Ret + +ReInitSound1: + Xor AX, AX + Mov ES, AX ; ES = 0 + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset AWEIRQHandler + + Mov DWord Ptr [ES:20h], EAX ; Clock tick + + Call ResetIRQ + Call SetMIDIIRQ + Call ReinitUART + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset Chorus + Int 21h + +SaveConfig1: + PushF + Mov AH, 3Eh + Int 21h + PopF + +SaveConfig2: + Call ResetIRQ + + Cmp SBIRQMode, 0 + JE UnInitSound1 + + Mov DX, SB16BasePort + Add DL, 0Ch + + Call ResetUART + + Mov AX, SB16BasePort + Call ResetDSP + + Call InitAWE + + Push ES + Mov AH, 49h + Mov ES, DMABuffer + Int 21h + Pop ES + + Ret + +UnInitSound1: + Mov AL, 34h + Out 43h, AL + + Xor AX, AX + Out 40h, AL + Out 40h, AL + + Mov ES, AX + Mov EAX, OldIRQHandler + Mov [ES:20h], EAX + + Mov AX, SB16BasePort + Call ResetDSP + Call ResetUART + Call InitAWE + Call ResetIRQ + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Cmp CS:SBIRQMode, 0 + JE SetTempo1 + ; BlockLength = 55555/BPM + ; BlockLength = 45454*5/2 + ; = 113635 + Mov AX, 48099 + Mov DX, 1 + + Div BX + Dec AX + Dec AX + Mov CS:BlockLength, AX + +; Mov DX, SB16BasePort +; Add DL, 0Ch + + Jmp SetTempo2 + +SetTempo1: + ; Frames per second = 2 * (0.4*Tempo) + Mov AX, 0C214h + Mov DX, 16h ; Ticks = (1193181/(2*0.4))/Tempo + Div BX + + ; AX contains counter. + Mov CS:AWEUpdateTimer, AX + + Out 40h, AL ; Timer IRQ. + Mov AL, AH + Out 40h, AL + +SetTempo2: + Pop DX + Pop BX + Pop AX + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + ; if no sample, then do nothing + ; MemoryUsed = length of sample + ; if sustain loop, then use sustain + ; loop information + ; if no sustain loop, then use loop + ; information + ; if no loop or sustain loop, + ; memoryused += 16; (16 zero samples + ; at the end) + ; + PushAD + Push DS + Push ES + Push FS + + Push AX + + ClI + + Call EnableRAM ; Enable access to DRAM. + + ; Set destination address + Mov AX, SMALW + Mov EBX, CS:AWEMemoryUsed + Add EBX, 200000h + Call WriteData + + Mov DX, CS:BasePort + Add DX, 802h ; Index + Mov AX, 32+26 + Out DX, AX + + Pop AX + + Mov FS, CS:SongDataArea + LEA DI, [EAX*4+EAX] + ShL DI, 2 + Add DI, Offset AWEDataTable-20 + + Mov ECX, -1 + + Mov DWord Ptr [CS:DI], ECX ; Start + Mov DWord Ptr [CS:DI+4], ECX ; Loop start + Mov DWord Ptr [CS:DI+8], ECX ; Loop end + Mov DWord Ptr [CS:DI+12], ECX ; Size occupied + Mov DWord Ptr [CS:DI+16], ECX ; Size occupied + + Mov BP, AX + Add BP, BP + Mov BP, [FS:64910+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length + JC LoadSampleNoError + + JZ LoadSample1 + + ; 16 bit + + Mov CS:LoadSampleFuncF, Offset Load16BitSamplesForwards + Mov CS:LoadSampleFuncB, Offset Load16BitSamplesBackwards + + Jmp LoadSample2 + +LoadSample1: ; 8 bit + Mov CS:LoadSampleFuncF, Offset Load8BitSamplesForwards + Mov CS:LoadSampleFuncB, Offset Load8BitSamplesBackwards + +LoadSample2: + Mov AL, [FS:BP+12h] + Test AL, 30h ; Loop or sustain loop? + JZ LoadSampleNoLoop + + Mov EBX, [FS:BP+34h] ; Loop begin + Mov EDX, [FS:BP+38h] ; Loop end + Test AL, 20h ; Sustain loop? + JZ LoadSample3 + + ShR AL, 1 + Mov EBX, [FS:BP+40h] + Mov EDX, [FS:BP+44h] + Jmp LoadSample3 + +LoadSampleError: + ClC + Jmp LoadSampleEnd + +LoadSampleNoError: + StC + +LoadSampleEnd: + StI + Pop FS + Pop ES + Pop DS + PopAD + + Ret + +LoadSampleNoLoop: ; ECX contains length of sample + Mov EAX, ECX + Mov EDX, AWEMemoryUsed + Mov EBX, AWEMemory + Sub EBX, EDX ; EBX = AWEMemory remaining + + Mov CL, Compress + ShR EAX, CL ; Compress sample + Add EAX, 16 ; zeroes at end of sample + + Cmp EAX, EBX + JA LoadSampleError + + Mov ECX, EAX + Add AWEMemoryUsed, EAX ; Record memory as used + Mov [CS:DI+12], EAX + + Add EDX, 200000h + + Sub ECX, 16 ; Number of samples to transfer + Mov [CS:DI], EDX + Add EDX, ECX + Mov [CS:DI+4], EDX ; Loop start + Add EDX, 14 + Mov [CS:DI+8], EDX ; Loop end + + ; Now to transfer samples to AWE32 + Call [CS:LoadSampleFuncF] + ; Now to shove a whole lot of zeroes + Xor AX, AX + Mov CX, 16 + +LoadSampleNoLoop2: + Out DX, AX + Loop LoadsampleNoLoop2 + + Jmp LoadSampleNoError + +LoadSample3: ; OK... EBX = loop start + ; EDX = loop end + ; AL&40h = ping pong + Test AL, 40h + JNZ LoadSamplePingPong + + Mov CL, Compress + + Push EBX + + ShR EDX, CL + ShR EBX, CL + Mov EAX, EDX + Add EAX, 2 ; For loop fixing + + Mov ECX, AWEMemory + Sub ECX, AWEMemoryUsed ; ECX = AWEMemoryRemaining + + Cmp EAX, ECX + Pop ECX + JA LoadSampleError ; Sufficient memory? + Push ECX + + Mov ECX, EAX + Mov EAX, AWEMemoryUsed + Add AWEMemoryUsed, ECX + Mov [CS:DI+12], ECX + + Sub ECX, 2 + + Add EAX, 200000h + Mov [CS:DI], EAX + + Add EDX, EAX + Add EAX, EBX + + Mov [CS:DI+4], EAX + Mov [CS:DI+8], EDX + + Call [CS:LoadSampleFuncF] + ; Now to fix loop.. 1 extra + ; sample. + + Pop ESI ; Loop start + Test Byte Ptr [FS:BP+12h], 2 + JZ LoadSampleForwards1 + + Add ESI, ESI + +LoadSampleForwards1: + Int 3 + + Mov ECX, 2 + Call [CS:LoadSampleFuncF] + + Jmp LoadSampleNoError + +LoadSamplePingPong: + Mov CL, Compress + ShR EDX, CL + ShR EBX, CL + + Mov EAX, EDX + Add EAX, EDX + Sub EAX, EBX + Inc EAX + + Mov ECX, AWEMemory + Sub ECX, AWEMemoryUsed + + Cmp EAX, ECX + JA LoadSampleError + + Mov [CS:DI+12], EAX + Mov ECX, AWEMemoryUsed + Add AWEMemoryUsed, EAX + + Add ECX, 200000h + Add EAX, ECX + Dec EAX + + Mov [CS:DI], ECX + Add ECX, EBX + Mov [CS:DI+4], ECX + Mov [CS:DI+8], EAX + + Mov EAX, [CS:DI] + Add EAX, EDX + Mov [CS:DI+16], EAX + + Mov ECX, EDX + Sub EDX, EBX + Push EDX + + Call [CS:LoadSampleFuncF] + + Pop ECX + Inc ECX + + Call [CS:LoadSampleFuncB] + + Jmp LoadSampleNoError + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + PushAD + + LEA DI, [EAX*4+EAX] ; DI = AX * 5 + ShL DI, 2 + Add DI, Offset AWEDataTable + + Mov EBX, [CS:DI+12] + Mov EAX, CS:AWEMemoryUsed + Sub EAX, EBX + Add EAX, 200000h + Cmp EAX, [CS:DI] + JNE ReleaseSample1 + + Sub AWEMemoryUsed, EBX +ReleaseSample1: + Mov EAX, -1 + Mov [CS:DI], EAX + Mov [CS:DI+4], EAX + Mov [CS:DI+8], EAX + Mov [CS:DI+12], EAX + + PopAD + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Push CS + Pop ES + + Xor EAX, EAX + Mov CS:AWEMemoryUsed, EAX + + Mov DI, Offset AWEDataTable + Mov CX, 1000 + Mov AX, 0FFFFh + Rep StosW + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset AWE32Status + + Mov EAX, AWEMemory + Sub EAX, AWEMemoryUsed + SHR EAX, 9 + + ClC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset GUSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, MixerPort + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 30 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 30 +DriverFlags DW 1 ; MIDI Out supported + + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + + DW Offset SendUARTOut ; For MIDI Out + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/BASE1.ASM b/it/SoundDrivers/BASE1.ASM new file mode 100755 index 0000000..01ff0a5 --- /dev/null +++ b/it/SoundDrivers/BASE1.ASM @@ -0,0 +1,2070 @@ +; +; Analog Device's AD1816 +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +PNPSERIALID EQU 0FFFFFFFFh +PNPVENDORID EQU 1114B250h + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +DMASize DW DMABUFFERLENGTH/2 + +ESSMsg DB "SoundSystem Base 1 found", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +ESSNoMemoryMsg DB "SoundSystem Base 1 found", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "SoundSystem Base 1 reinitialised", 0 + +DriverName DB "ITBASE1.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +ESSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldESSIRQHandler DD 0 + +MIDIIRQ DW 0 +MIDIPort DW 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +ESSScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr ESSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + DW Near Ptr PhatStereo ; 18 + + DW 0 + +ESSHeaderLine DW 10 + DB "SoundSystem Base 1 Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 29, 48 + DB 21h + DB "SoundSystem Base 1 Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB "3D Phat Stereo", 13 + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 39, 17 + DB 25 + +PhatStereo DW 14 + DB 22, 16 + DW 0, 15 + DW 9, 2 + DW 17, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 16 + +MasterVolumeLeft DW 14 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 16 + +MasterVolumeRight DW 14 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 18, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 16 + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 44100 + +MixModeButton1 DW 2 + DW 18, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 56, 56, 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dmasirq.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc AD1816Wait + + PushA + Xor CX, CX + Mov DX, CS:BasePort + +AD1816Wait1: + In AL, DX + Test AL, 80h + LoopZ AD1816Wait1 + + PopA + Ret + +EndP AD1816Wait + +; + +Proc AD1816RegisterOut ; AL = indirect register, BX = contents + + Call AD1816Wait + + Push DX + PushF + + ClI + + Mov DX, CS:BasePort + Out DX, AL + Add DL, 2 + + Mov AL, BL + Out DX, AL + Inc DX + Mov AL, BH + Out DX, AL + + PopF + Pop DX + + Ret + +EndP AD1816RegisterOut + +; + +Proc AD1816RegisterIn ; AL = register + ; Returns BX + + Call AD1816Wait + + Push AX + Push DX + + Mov DX, CS:BasePort + Out DX, AL + Add DL, 2 + + In AL, DX + Mov BL, AL + Inc DX + In AL, DX + Mov BH, AL + + Pop DX + Pop AX + + Ret + +EndP AD1816RegisterIn + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + + Mov AX, 1 + Ret + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + Mov AX, 007h + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov AX, 107h ; LDN 1 - MIDI device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Mov MIDIPort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + Mov MIDIIRQ, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + + Inc DX + In AL, DX + Mov AH, AL + Xor AL, AL + Out DX, AL + + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + + Cmp BX, DMABUFFERLENGTH/2 + JB WSSIRQHandler1 + + Mov AX, DMABUFFERLENGTH/2 + +WSSIRQHandler1: + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE ESSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +ESSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB ESSIRQHandler6 + JE ESSIRQHFilter + + Cmp CS:Stereo, 0 + JE ESSIRQ3QFilterMono + +ESSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +ESSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +ESSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +ESSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilter: + Cmp CS:Stereo, 0 + JE ESSIRQHFilterMono + +ESSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +ESSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +ESSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +ESSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL ESSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG ESSIRQHandlerClip2 + +ESSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ ESSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +ESSIRQHandlerClip1: + Mov AX, 8000h + Jmp ESSIRQHandler7 + +ESSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp ESSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo3 + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopAD1816 + + PushA + + Mov AL, 1 + Call AD1816RegisterIn + And BX, 07FFFh ; Disable PIE + Call AD1816RegisterOut + + Mov DX, CS:BasePort + Inc DX + In AL, DX + And AL, Not 80h + Out DX, AL + + Add DL, 7 + In AL, DX + And AL, Not 1 + Out DX, AL + + PopA + Ret + +EndP StopAD1816 + +; + +Proc StartAD1816 + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov AL, 4 + Call AD1816RegisterIn + + Mov AL, 32 + Call AD1816RegisterIn + Or BX, 08000h + Call AD1816RegisterOut + + Mov AL, 2 ; Sample rate + Mov BX, MixSpeed + Call AD1816RegisterOut + + Mov AL, 8 ; DMA Size + Mov BX, DMASize + ShR BX, 2 + Dec BX + Call AD1816RegisterOut + + Mov DX, BasePort ; Wave Format + Add DL, 8 + + Mov AL, 00010001b + Cmp Stereo, 0 + JE StartAD1816A + + Or AL, 4 + +StartAD1816A: + Out DX, AL + + Mov AL, 1 ; Enable Playback interrupt + Call AD1816RegisterIn + Or BX, 8000h + Call AD1816RegisterOut + + Pop DS + Pop ES + PopA + + Ret + +EndP StartAD1816 + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, CmdLineMixSpeed + Mov AX, 44100 + + Test DX, DX + JZ ClipMixSpeed2 + + Mov AX, DX + Cmp AX, 11050 + JA ClipMixSpeed1 + + Mov AX, 11050 + +ClipMixSpeed1: + Cmp AX, 55200 + JB ClipMixSpeed2 + + Mov AX, 55200 + +ClipMixSpeed2: + Mov MixSpeed, AX + Mov DX, 2643 + Mul DX + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Call UpdateSoundcardVariables + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Push AX + + Call StopAD1816 + Call ResetIRQ + + Pop ES + Mov AH, 49h ; Release MixSegment + Int 21h + + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopAD1816 + Call StartAD1816 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset ESSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + Mov AL, 4 + Mov BX, 3F3Fh + Sub BX, [Word Ptr CS:VolumeTable] + Call AD1816RegisterOut + + Mov AL, 39 + Call AD1816RegisterIn + Mov CL, [CS:VolumeTable+2] + And BX, 0110000111111111b + ShL CX, 9 + Or BX, CX + Call AD1816RegisterOut + + Mov AL, 14 + Xor BX, BX + Call AD1816RegisterOut + + Ret + +EndP UpdateSoundcardVariables + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + Call UpdateSoundcardVariables + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/DEBUG.INC b/it/SoundDrivers/DEBUG.INC new file mode 100755 index 0000000..ef745d7 --- /dev/null +++ b/it/SoundDrivers/DEBUG.INC @@ -0,0 +1,101 @@ +; +; Debug macro. To write to the file, use "Trace " +; + +IF TRACEENABLED + +IF CREATENEWLOGFILE +FirstTime DB 0 +ENDIF + +LogFileName DB "Logfile.Txt", 0 + +; + +Proc WriteDebugFile + + PushA + Push DS + + Push CS + Pop DS + + Mov DX, Offset LogFileName + +IF CREATENEWLOGFILE + + Cmp DS:FirstTime, 0 + JNE WriteDebugFile1 + + Mov AH, 3Ch + Xor CX, CX + Int 21h + JC WriteDebugFileEnd + + Mov DS:FirstTime, 1 + XChg AX, BX + Jmp WriteDebugFile2 + + WriteDebugFile1: + +ENDIF + Mov AX, 3D02h + Int 21h + JC WriteDebugFileEnd + + XChg AX, BX + + Mov AX, 4202h + Xor CX, CX + Xor DX, DX + Int 21h ; Move to end of file + +WriteDebugFile2: + Mov AH, 40h + Mov CX, 82 + Mov DX, SI + Int 21h + + Mov AH, 3Eh + Int 21h + +WriteDebugFileEnd: + Pop DS + PopA + Ret + +EndP WriteDebugFile + +; + +Trace Macro LogMessage + Local X, Y + + PushF + Push SI + Jmp Y + X: + DB LogMessage + DB 80-($-Offset X) Dup (0) + DB 0Dh, 0Ah + Y: + Mov SI, Offset X + Call WriteDebugFile + Pop SI + PopF + + EndM + +; + +ELSE + +; + +Trace Macro LogMessage + EndM + +; + +ENDIF + diff --git a/it/SoundDrivers/DMA.INC b/it/SoundDrivers/DMA.INC new file mode 100755 index 0000000..c9f1fa9 --- /dev/null +++ b/it/SoundDrivers/DMA.INC @@ -0,0 +1,113 @@ + +DMAData Label Byte +; Port/Mask, Port/Clear, Port/DMAMode, Address, Page, Count, Port/Mask + DB 0Ah, 4, 0Ch, 0, 0Bh, 58h, 87h, 0, 1, 0Ah, 0 + DB 0Ah, 5, 0Ch, 0, 0Bh, 59h, 83h, 2, 3, 0Ah, 1 + DB 0Ah, 6, 0Ch, 0, 0Bh, 5Ah, 81h, 4, 5, 0Ah, 2 + DB 0Ah, 7, 0Ch, 0, 0Bh, 5Bh, 82h, 6, 7, 0Ah, 3 + DB 0D4h, 4, 0D8h, 0, 0D6h, 58h, 8Fh, 0C0h, 0C2h, 0D4h, 0 + DB 0D4h, 5, 0D8h, 0, 0D6h, 59h, 8Bh, 0C4h, 0C6h, 0D4h, 1 + DB 0D4h, 6, 0D8h, 0, 0D6h, 5Ah, 89h, 0C8h, 0CAh, 0D4h, 2 + DB 0D4h, 7, 0D8h, 0, 0D6h, 5Bh, 8Ah, 0CCh, 0CEh, 0D4h, 3 + +ActualDMAPtr Label DWord +ActualDMAOffset DW 0 +ActualDMASegment DW 0 + +; + +Proc SetDMA ; BX:AX points to DMA buffer + ; DL = DMA Channel + ; DI = DMA Size + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov ActualDMASegment, BX + Mov ActualDMAOffset, AX + + Mov CH, BH + ShR CH, 4 + ShL BX, 4 + Add BX, AX + AdC CH, 0 + Mov SI, BX ; CH:BH:BL contains 24 bit DMA address + Neg SI + Cmp SI, DI + JA SetDMA1 + + Add ActualDMAOffset, SI + Add BX, SI + AdC CH, 0 + +SetDMA1: + Cmp DL, 3 + JBE SetDMA2 + + ShR DI, 1 + Push CX + ShR CH, 1 + Pop CX + RCR BX, 1 + +SetDMA2: + Mov AL, 11 + Mul DL + Mov SI, AX + Add SI, Offset DMAData + + Xor DX, DX + + LodsB ; Set mask + Mov DL, AL + LodsB + Out DX, AL + + LodsB ; Clear Ptrs + Mov DL, AL + LodsB + Out DX, AL + + LodsB ; Set Mode + Mov DL, AL + LodsB + Out DX, AL + + LodsB + Mov DL, AL ; DL = page port + Mov AL, CH + Out DX, AL + + LodsB + Mov DL, AL ; DL = address port + Mov AL, BL + Out DX, AL + Mov AL, BH + Out DX, AL + + LodsB + Mov DL, AL ; DL = count port + Mov AX, DI + Dec AX + Out DX, AL + Mov AL, AH + Out DX, AL + + LodsB ; Reset mask + Mov DL, AL + LodsB + Out DX, AL + + Pop DS + PopA + + Ret + +EndP SetDMA + Assume DS:Nothing + +; + diff --git a/it/SoundDrivers/DMANAI.INC b/it/SoundDrivers/DMANAI.INC new file mode 100755 index 0000000..31071d5 --- /dev/null +++ b/it/SoundDrivers/DMANAI.INC @@ -0,0 +1,113 @@ + +DMAData Label Byte +; Port/Mask, Port/Clear, Port/DMAMode, Address, Page, Count, Port/Mask + DB 0Ah, 4, 0Ch, 0, 0Bh, 08h, 87h, 0, 1, 0Ah, 0 + DB 0Ah, 5, 0Ch, 0, 0Bh, 09h, 83h, 2, 3, 0Ah, 1 + DB 0Ah, 6, 0Ch, 0, 0Bh, 0Ah, 81h, 4, 5, 0Ah, 2 + DB 0Ah, 7, 0Ch, 0, 0Bh, 0Bh, 82h, 6, 7, 0Ah, 3 + DB 0D4h, 4, 0D8h, 0, 0D6h, 08h, 8Fh, 0C0h, 0C2h, 0D4h, 0 + DB 0D4h, 5, 0D8h, 0, 0D6h, 09h, 8Bh, 0C4h, 0C6h, 0D4h, 1 + DB 0D4h, 6, 0D8h, 0, 0D6h, 0Ah, 89h, 0C8h, 0CAh, 0D4h, 2 + DB 0D4h, 7, 0D8h, 0, 0D6h, 0Bh, 8Ah, 0CCh, 0CEh, 0D4h, 3 + +ActualDMAPtr Label DWord +ActualDMAOffset DW 0 +ActualDMASegment DW 0 + +; + +Proc SetDMA ; BX:AX points to DMA buffer + ; DL = DMA Channel + ; DI = DMA Size + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov ActualDMASegment, BX + Mov ActualDMAOffset, AX + + Mov CH, BH + ShR CH, 4 + ShL BX, 4 + Add BX, AX + AdC CH, 0 + Mov SI, BX ; CH:BH:BL contains 24 bit DMA address + Neg SI + Cmp SI, DI + JA SetDMA1 + + Add ActualDMAOffset, SI + Add BX, SI + AdC CH, 0 + +SetDMA1: + Cmp DL, 3 + JBE SetDMA2 + + ShR DI, 1 + Push CX + ShR CH, 1 + Pop CX + RCR BX, 1 + +SetDMA2: + Mov AL, 11 + Mul DL + Mov SI, AX + Add SI, Offset DMAData + + Xor DX, DX + + LodsB ; Set mask + Mov DL, AL + LodsB + Out DX, AL + + LodsB ; Clear Ptrs + Mov DL, AL + LodsB + Out DX, AL + + LodsB ; Set Mode + Mov DL, AL + LodsB + Out DX, AL + + LodsB + Mov DL, AL ; DL = page port + Mov AL, CH + Out DX, AL + + LodsB + Mov DL, AL ; DL = address port + Mov AL, BL + Out DX, AL + Mov AL, BH + Out DX, AL + + LodsB + Mov DL, AL ; DL = count port + Mov AX, DI + Dec AX + Out DX, AL + Mov AL, AH + Out DX, AL + + LodsB ; Reset mask + Mov DL, AL + LodsB + Out DX, AL + + Pop DS + PopA + + Ret + +EndP SetDMA + Assume DS:Nothing + +; + diff --git a/it/SoundDrivers/DMASIRQ.INC b/it/SoundDrivers/DMASIRQ.INC new file mode 100755 index 0000000..df906c5 --- /dev/null +++ b/it/SoundDrivers/DMASIRQ.INC @@ -0,0 +1,116 @@ + +DMAData Label Byte +; Port/Mask, Port/Clear, Port/DMAMode, Address, Page, Count, Port/Mask + DB 0Ah, 4, 0Ch, 0, 0Bh, 58h, 87h, 0, 1, 0Ah, 0 + DB 0Ah, 5, 0Ch, 0, 0Bh, 59h, 83h, 2, 3, 0Ah, 1 + DB 0Ah, 6, 0Ch, 0, 0Bh, 5Ah, 81h, 4, 5, 0Ah, 2 + DB 0Ah, 7, 0Ch, 0, 0Bh, 5Bh, 82h, 6, 7, 0Ah, 3 + DB 0D4h, 4, 0D8h, 0, 0D6h, 58h, 8Fh, 0C0h, 0C2h, 0D4h, 0 + DB 0D4h, 5, 0D8h, 0, 0D6h, 59h, 8Bh, 0C4h, 0C6h, 0D4h, 1 + DB 0D4h, 6, 0D8h, 0, 0D6h, 5Ah, 89h, 0C8h, 0CAh, 0D4h, 2 + DB 0D4h, 7, 0D8h, 0, 0D6h, 5Bh, 8Ah, 0CCh, 0CEh, 0D4h, 3 + +ActualDMAPtr Label DWord +ActualDMAOffset DW 0 +ActualDMASegment DW 0 + +; + +Proc SetDMA ; BX:AX points to DMA buffer + ; DL = DMA Channel + ; DI = DMA Size + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov ActualDMASegment, BX + Mov ActualDMAOffset, AX + + Mov CH, BH + ShR CH, 4 + ShL BX, 4 + Add BX, AX + AdC CH, 0 + Mov SI, BX ; CH:BH:BL contains 24 bit DMA address + Neg SI + Cmp SI, DI + JA SetDMA1 + + Add ActualDMAOffset, SI + Add BX, SI + AdC CH, 0 + +SetDMA1: + Cmp DL, 3 + JBE SetDMA2 + + ShR DI, 1 + Push CX + ShR CH, 1 + Pop CX + RCR BX, 1 + +SetDMA2: + Mov AL, 11 + Mul DL + Mov SI, AX + Add SI, Offset DMAData + + Xor DX, DX + + LodsB ; Set mask + Mov DL, AL + LodsB + Out DX, AL + + LodsB ; Clear Ptrs + Mov DL, AL + LodsB + Out DX, AL + + LodsB ; Set Mode + Mov DL, AL + LodsB + Out DX, AL + + LodsB + Mov DL, AL ; DL = page port + Mov AL, CH + Out DX, AL + + LodsB + Mov DL, AL ; DL = address port + Mov AL, BL + Out DX, AL + Mov AL, BH + Out DX, AL + + LodsB + Mov DL, AL ; DL = count port + Mov AX, DI + Dec AX + Out DX, AL + Mov AL, AH + Out DX, AL + + Mov Byte Ptr [CS:DMAPort1], DL + Mov Byte Ptr [CS:DMAPort2], DL + + LodsB ; Reset mask + Mov DL, AL + LodsB + Out DX, AL + + Pop DS + PopA + + Ret + +EndP SetDMA + Assume DS:Nothing + +; + diff --git a/it/SoundDrivers/DRHEAD.INC b/it/SoundDrivers/DRHEAD.INC new file mode 100755 index 0000000..03186ab --- /dev/null +++ b/it/SoundDrivers/DRHEAD.INC @@ -0,0 +1,8 @@ + +ID DB "Impulse Tracker Advanced Sound Driver", 13, 10 + DB "Copyright (C) 1995-1998 Jeffrey Lim", 0 + DB 26 + + DB 126 - ($ - Offset ID) Dup (0) + +LengthOfDriver DW Offset EndDriver - Offset StartDriver diff --git a/it/SoundDrivers/ENVIVO.ASM b/it/SoundDrivers/ENVIVO.ASM new file mode 100755 index 0000000..f4198e1 --- /dev/null +++ b/it/SoundDrivers/ENVIVO.ASM @@ -0,0 +1,2300 @@ +; +; Windows Sound System Driver +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +PNPSERIALID EQU 98B03C20h +PNPVENDORID EQU 8140D315h +PNPVENDORID2 EQU 8040D315h + +DMASize DW 2048 + +WSSMsg DB "Ensoniq SoundscapeVIVO Codec", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Ensoniq SoundscapeVIVO Codec", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Ensoqiq SoundscapeVIVO Codec reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITVIVO.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITVIVO.DRV", 0 + +DriverName DB "ITVIVO.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + +IRQSetupTable DB 0, 0, 0, 0, 0, 0, 0, 8 + DB 0, 10h, 18h, 20h, 0, 0, 0, 0 + +DMASetupTable DB 1, 2, 0, 3, 0, 0, 0, 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW 0 + +WSSHeaderLine DW 10 + DB "Ensoniq SoundscapeVIVO Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 26, 48 + DB 21h + DB "Ensoniq SoundscapeVIVO Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 2 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 14 ; 14 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Add DX, 6 + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID2 + JE VendorAlsoOK + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + +VendorAlsoOK: + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 62h + Call PnP_ReadData + Mov AH, AL + Mov AL, 63h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Mov AX, 202h + Call PnP_WriteData + Ret + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + + Mov DX, BasePort + Add DX, 4 + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Mov EAX, 'Jeff' + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 6 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB WSSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +WSSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + Add DX, 4 + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Add DX, 4 + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DX, 4 + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/EQUALIZE.INC b/it/SoundDrivers/EQUALIZE.INC new file mode 100755 index 0000000..c00c665 --- /dev/null +++ b/it/SoundDrivers/EQUALIZE.INC @@ -0,0 +1,161 @@ +; Do output filtering +; First copy old contents across +; Assumes destination is MixSegment:0 +; data order is lastvalues, coefficients, volumes + + Push CS + Pop DS + Assume DS:Driver + + Xor DI, DI + Mov SI, Offset LastFilter + + Mov EAX, [SI+40h] + Mov EBX, [SI+44h] + Mov ECX, [SI+48h] + Mov EDX, [SI+4Ch] + Or EAX, EBX + Or ECX, EDX + Or EAX, ECX + JZ NoEqualize + + Mov CX, 80/4 + Mov ES, MixSegment + + Rep MovsD + +; Now do filtering. + FNInit + Mov CX, BytesToMix + + Push ES + Pop DS + Assume DS:Nothing + + Mov SI, DMABUFFERLENGTH*2+80 + +OutputFilter1: + FILD DWord Ptr [SI] ; Left sample + FILD DWord Ptr [SI+4] ; R, L + + FLd DWord Ptr [DS:20h] ; LB, R, L + FMul ST, ST(2) ; L.LB, R, L + FLd DWord Ptr [DS:20h] ; LB, L.LB, R, L + FMul ST, ST(2) ; R.LB, L.LB, R, L + FLd DWord Ptr [DS:0] ; OL, R.LB, L.LB, R, L + FMul DWord Ptr [DS:24h] ; OL.LB, R.LB, L.LB, R, L + FLd DWord Ptr [DS:4] ; OR, OL.LB, R.LB, L.LB, R, L + FMul DWord Ptr [DS:24h] ; OR.LB, OL.LB, R.LB, L.LB, R, L + + FXCh ; OL.LB, OR.LB, R.LB, L.LB, R, L + FAddP ST(3), ST + FAdd ; RLB, LLB, R, L + + FLd DWord Ptr [DS:28h] ; MB, RLB, LLB, R, L + FMul ST, ST(4) ; L.MB, RLB, LLB, R, L + FLd DWord Ptr [DS:28h] ; MB, L.MB, RLB, LLB, R, L + FMul ST, ST(4) ; R.MB, L.MB, RLB, LLB, R, L + FLd DWord Ptr [DS:8] ; OL, R.MB, L.MB, RLB, LLB, R, L + FMul DWord Ptr [DS:2Ch] ; OL.MB, R.MB, L.MB, RLB, LLB, R, L + FLd DWord Ptr [DS:0Ch] ; OR, OL.MB, R.MB, L.MB, RLB, LLB, R, L + FMul DWord Ptr [DS:2Ch] ; OR.MB, OL.MB, R.MB, L.MB, RLB, LLB, R, L + + FXCh ; OL.MB, OR.MB, R.MB, L.MB, RLB, LLB, R, L + FAddP ST(3), ST + FAdd ; RMB, LMB, RLB, LLB, R, L + FXCh ST(3) ; LLB, LMB, RLB, RMB, R, L + FStP DWord Ptr [DS:0] + FStP DWord Ptr [DS:8] + FStP DWord Ptr [DS:4] + FStP DWord Ptr [DS:0Ch] + + FLd DWord Ptr [DS:30h] + FMul ST, ST(2) + FLd DWord Ptr [DS:30h] + FMul ST, ST(2) + FLd DWord Ptr [DS:10h] + FMul DWord Ptr [DS:34h] + FLd DWord Ptr [DS:14h] + FMul DWord Ptr [DS:34h] + + FXCh + FAddP ST(3), ST + FAdd + + FLd DWord Ptr [DS:38h] + FMul ST, ST(4) + FLd DWord Ptr [DS:38h] + FMul ST, ST(4) + FLd DWord Ptr [DS:18h] + FMul DWord Ptr [DS:3Ch] + FLd DWord Ptr [DS:1Ch] + FMul DWord Ptr [DS:3Ch] + + FXCh + FAddP ST(3), ST + FAdd + FXCh ST(3) + FStP DWord Ptr [DS:10h] + FStP DWord Ptr [DS:18h] + FStP DWord Ptr [DS:14h] + FStP DWord Ptr [DS:1Ch] ; R, L + +; For each one, output value += ((band value) - (previous band value)) * Volume + + FLd DWord Ptr [DS:18h] + FSub DWord Ptr [DS:10h] ; L4, R, L + FLd DWord Ptr [DS:1Ch] + FSub DWord Ptr [DS:14h] ; R4, L4, R, L + FLd DWord Ptr [DS:10h] + FSub DWord Ptr [DS:8] + FLd DWord Ptr [DS:14h] + FSub DWord Ptr [DS:0Ch] ; R3, L3, R4, L4, R, L + FLd DWord Ptr [DS:8] + FSub DWord Ptr [DS:0] + FLd DWord Ptr [DS:0Ch] + FSub DWord Ptr [DS:4] ; R2, L2, R3, L3, R4, L4, R, L + FXCh ST(5) ; L4, L2, R3, L3, R4, R2, R, L + FMul DWord Ptr [DS:4Ch] ; L4V, L2, R3, L3, R4, R2, R, L + FXCh ST(4) ; R4, L2, R3, L3, L4V, R2, R, L + FMul DWord Ptr [DS:4Ch] ; R4V, L2, R3, L3, L4V, R2, R, L + FXCh ST(3) ; L3, L2, R3, R4V, L4V, R2, R, L + FMul DWord Ptr [DS:48h] ; L3V, L2, R3, R4V, L4V, R2, R, L + FXCh ST(2) ; R3, L2, L3V, R4V, L4V, R2, R, L + FMul DWord Ptr [DS:48h] ; R3V, L2, L3V, R4V, L4V, R2, R, L + FXCh ; L2, R3V, L3V, R4V, L4V, R2, R, L + FMul DWord Ptr [DS:44h] ; L2V, R3V, L3V, R4V, L4V, R2, R, L + FXCh ST(5) ; R2, R3V, L3V, R4V, L4V, L2V, R, L + FMul DWord Ptr [DS:44h] ; R2V, R3V, L3V, R4V, L4V, L2V, R, L + FXCh ST(4) ; L4V, R3V, L3V, R4V, R2V, L2V, R, L + FAddP ST(7), ST ; R3V, L3V, R4V, R2V, L2V, R, L + FAddP ST(5), ST ; L3V, R4V, R2V, L2V, R, L + FAddP ST(3), ST + FAdd + FLd DWord Ptr [DS:0] + FMul DWord Ptr [DS:40h] ; L1V, RV, LV, R, L + FLd DWord Ptr [DS:4] ; + FMul DWord Ptr [DS:40h] ; R1V, L1V, RV, LV, R, L + FXCh ST(2) ; RV, L1V, R1V, LV, R, L + FAddP ST(4), ST ; L1V, R1V, LV, R, L + FAddP ST(4), ST ; R1V, LV, R, L + FAddP ST(2), ST + FAddP ST(2), ST + + FIStP DWord Ptr [SI+4] + FIStP DWord Ptr [SI] + + Add SI, 8 + Dec CX + JNZ OutputFilter1 + +; Transfer contents out + Push CS + Pop ES + + Mov DI, Offset LastFilter + Xor SI, SI + Mov CX, 32/4 + + Rep MovsD +; Finished output filtering! +NoEqualize: diff --git a/it/SoundDrivers/ES1688.ASM b/it/SoundDrivers/ES1688.ASM new file mode 100755 index 0000000..01d3a48 --- /dev/null +++ b/it/SoundDrivers/ES1688.ASM @@ -0,0 +1,2265 @@ +; +; ESS Technology's ES1688 Audiodrive chip +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +;Debug DW 0 +;Debug2 DW 0 +ESSMsg DB "ES1688 AudioDrive found", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +ESSNoMemoryMsg DB "ES1688 AudioDrive found", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "ES1688 AudioDrive reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITES1688.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITES1688.DRV", 0 + +DriverName DB "ITES1688.DRV", 0 + +ALIGN 4 +FilterValue DD 0 +FilterValue2 DD 0 +ESSMixConst DB 0, 0 + +DMASize DW 4096 ; Smaller gives better MIDI timing +ConfigPort DW 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldESSIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +ESSScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr ESSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + +Comment ~ + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + +~ + + DW 0 + +ESSHeaderLine DW 10 + DB "ESS AudioDrive Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 33, 48 + DB 21h + DB "ESS AudioDrive Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +Comment ~ + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 14 + DB 22, 14 + DW 0, 15 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MasterVolumeRight DW 14 + DB 22, 15 + DW 0, 15 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +~ + +MixModeText DW 1 + DB 2, 14 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 44100 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 16, 32, 18, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 19, 32, 21, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 22, 32, 24, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 29 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 31, 29, 33, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 34, 29, 36, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 37, 29, 39, 8 + DB 0 + DB " 75% Filter", 0 + +ALIGN 4 + +VolumeTable DB 2 Dup (0) +MIDIPort DW 0 + +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dmasirq.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc ESSOut ; AL = data + ; DX = 2xCh + + Push AX + +ESSOut1: + In AL, DX + Test AL, AL + JS ESSOut1 + + Pop AX + Out DX, AL + + Ret + +EndP ESSOut + +; + +Proc ESSOut2 ; AL = data + ; DX = 2xCh + + Push AX + +ESSOut2A: + In AL, DX + Test AL, 80h + LoopNZ ESSOut2A + + Pop AX + Out DX, AL + + Ret + +EndP ESSOut2 + +; + +Proc ESSIn2 + +ESSInA1: + In AL, DX + Test AL, 40h + LoopZ ESSInA1 + JZ ESSInA2 + + Add DL, 0Ah-0Ch ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Ch-0Ah + + Ret + +ESSInA2: + Mov AL, 0FFh + Ret + +EndP ESSIn2 + +; + +Proc ESSIn ; DX = 2xCh, returns AL + +ESSIn1: + In AL, DX + Test AL, 40h + JZ ESSIn1 + + Add DL, 0Ah-0Ch ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Ch-0Ah + + Ret + +EndP ESSIn + +; + +Proc UARTOut ; AL = out + + Push DX + Push AX + + Mov DX, CS:MIDIPort + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + JNZ UARTOut1 + + Pop AX + Dec DX + Out DX, AL + + Pop DX + Ret + +EndP UARTOut + +; + +Proc UARTIn ; returns AL + + Push DX + + Mov DX, CS:MIDIPort + Inc DX + +UARTIn1: + In AL, DX + Test AL, 80h + JNZ UARTIn1 + + Dec DX + In AL, DX + + Pop DX + Ret + +EndP UARTIn + +; + +Proc ESSReadMixerRegister ; AL = register to read + ; DX = 2xCh + + Add DL, 04-0Ch + Out DX, AL + Inc DX + In AL, DX + Add DL, 0Ch-05 + + Ret + +EndP ESSReadMixerRegister + +; + +Proc ESSReadRegister ; AH = register to read. + ; DX = 2xCh + ; returns AL + + Mov AL, 0C0h + Call ESSOut + Mov AL, AH + Call ESSOut + Call ESSIn + + Ret + +EndP ESSReadRegister + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Xor CX, CX + Add DL, 0Ch ; 2xCh -> Data ready to send... + + Mov AL, 0E1h + Call ESSOut2 + + Call ESSIn2 + Mov AH, AL ; AH = Major version number + Call ESSIn2 ; AL = Minor version number + + Cmp AX, 301h + JNE DetectCardFailure + + Mov AL, 0E7h + Call ESSOut2 + Call ESSIn2 + Mov AH, AL + Call ESSIn2 + + Cmp AH, 68h + JNE DetectCardReset + Cmp AL, 88h + JB DetectCardReset + Cmp AL, 90h + JAE DetectCardReset + ; We have an ES1688 Audiodrive chip! + +Comment ~ + Mov AL, 40h + Call ESSReadMixerRegister + ShL AL, 1 + And AX, 30h + Add AX, 300h + Mov MIDIPort, AX +~ + + Mov AH, 0B1h ; IRQ determination + Call ESSReadRegister + + Mov BX, 9 + And AL, 0Ch + JZ DetectCardIRQ + + Mov BX, 5 + Cmp AL, 4 + JE DetectCardIRQ + + Mov BX, 7 + Cmp AL, 8 + JE DetectCardIRQ + + Mov BX, 10 + Cmp AL, 0Ch + JNE DetectCardFailure + + +DetectCardIRQ: + Mov IRQ, BX + + Mov AH, 0B2h + Call ESSReadRegister + + Xor BX, BX + And AL, 0Ch + JZ DetectCardFailure + + Cmp AL, 4 + JE DetectCardDMA + + Inc BX + Cmp AL, 8 + JE DetectCardDMA + + Add BL, 2 + +DetectCardDMA: + Mov DMA, BX + + Mov EAX, 'Jeff' + ClC + Ret + +DetectCardReset: + Sub DL, 0Ch + Mov AX, DX + Call ResetDSP + +DetectCardFailure: + StC + Ret + + +EndP DetectCard + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 3 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Call UARTIn + Mov BL, [MIDIBufferTail] + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + +; Inc Debug + +Comment ~ + Mov DX, [ConfigPort] + Add DL, 6 + In AL, DX + Test AL, 8 + JZ ESSNoMIDI + + Push AX + Call CheckMIDI + Pop AX + +ESSNoMIDI: + Test AL, 1 + JZ ESSIRQEnd +~ + Mov DX, [BasePort] + Add DL, 0Eh + In AL, DX + + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + + Cmp BX, DMABUFFERLENGTH/2 + JB WSSIRQHandler1 + + Mov AX, DMABUFFERLENGTH/2 + +WSSIRQHandler1: + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE ESSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +ESSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB ESSIRQHandler6 + JE ESSIRQHFilter + + Cmp CS:Stereo, 0 + JE ESSIRQ3QFilterMono + +ESSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +ESSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +ESSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +ESSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilter: + Cmp CS:Stereo, 0 + JE ESSIRQHFilterMono + +ESSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +ESSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +ESSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +ESSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL ESSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG ESSIRQHandlerClip2 + +ESSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ ESSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + +ESSIRQEnd: + Pop ES + Pop DS + PopAD + IRet + +ESSIRQHandlerClip1: + Mov AX, 8000h + Jmp ESSIRQHandler7 + +ESSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp ESSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo3 + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc GetESSMixConst + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetESSMixConst1 + + Mov CX, 22050 + Cmp AX, CX + JB GetESSMixConst1 + + Mov CX, 56821 + Cmp AX, CX + JA GetESSMixConst1 + + Mov CX, AX + +GetESSMixConst1: ; CX = mixspeed. + Mov DX, 0Ch + Mov AX, 236Ch ; DX:AX = 795.5kHz + Div CX + + Mov BX, AX + Neg AL + Mov ESSMixConst, AL + + Mov DX, 0Ch + Mov AX, 236Ch + Div BX + Mov MixSpeed, AX + + Pop DS + PopA + Ret + +EndP GetESSMixConst + +; + +Proc StartESS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov AX, BasePort + Call ResetDSP + Mov DX, AX + Add DL, 0Ch + +; Extended Functions + + Mov AL, 0C6h + Call ESSOut + +; Autoinit DMA + + Mov AL, 0B8h + Call ESSOut + Mov AL, 4 + Call ESSOut + +; Stereo/Mono select + + Mov AH, 0A8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0A8h + Call ESSOut + Mov AL, AH + And AL, Not 3 + Or AL, 2 + Cmp Stereo, 0 + JE StartESS1 + + Xor AL, 3 + +StartESS1: + Call ESSOut + +; DMA mode + + Mov AL, 0B9h + Call ESSOut + Mov AL, 2 + Call ESSOut + +; Mixspeed + + Mov AL, 0A1h + Call ESSOut + Mov AL, ESSMixConst + Call ESSOut + +; Filter clock divider + Mov AL, 0A2h + Call ESSOut + + Mov AL, 0FEh + Call ESSOut + +; DMA counter + Mov CX, DMASize + Neg CX + + Mov AL, 0A4h + Call ESSOut + Mov AL, CL + Call ESSOut + Mov AL, 0A5h + Call ESSOut + Mov AL, CH + Call ESSOut + +; Initialise DAC + Mov AL, 0B6h + Call ESSOut + Mov AL, 0 + Call ESSOut + +; Configure DACs + + Mov AL, 0B7h + Call ESSOut + Mov AL, 71h + Call ESSOut + + Mov AL, 0B7h + Call ESSOut + + Mov AL, 0BCh + Cmp Stereo, 0 + JNE StartESS2 + + Mov AL, 0F4h + +StartESS2: + Call ESSOut + +; IRQ configuration + Mov AH, 0B1h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B1h + Call ESSOut + Mov AL, AH + And AL, 0Fh + Or AL, 50h + Call ESSOut + +; DMA configuration + Mov AH, 0B2h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B2h + Call ESSOut + Mov AL, AH + And AL, 0Fh + Or AL, 50h + Call ESSOut + +; Enable voice + Mov AL, 0D1h + Call ESSOut + +; Start transfer + Mov AH, 0B8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B8h + Call ESSOut + Mov AL, AH + Or AL, 1 + Call ESSOut + +Comment ~ + +; Init UART + Mov DX, MIDIPort + Inc DX + Mov AL, 3Fh ; Intelligent mode. + Out DX, AL + +; Enable MIDI IRQ + Mov DX, BasePort + Add DL, 4 + Mov AX, 4064h + Out DX, AX + +~ + + Pop DS + Pop ES + PopA + + Ret + +EndP StartESS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + And AX, 0FF0h + ShR AH, 1 + ShR AL, 5 + Mov Word Ptr [VolumeTable], AX + + Call GetESSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Mov AX, BasePort + Call ResetDSP + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver +; +;DMAPort1 EQU $+1 +; In AL, 1 +; Mov BL, AL +;DMAPort2 EQU $+1 +; In AL, 1 +; Mov BH, AL +; +; Mov Debug2, BX + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov AX, BasePort + Call ResetDSP + Call StartESS + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset ESSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Mov AH, [VolumeTable] + ShL AH, 4 + Or AH, [VolumeTable+1] + ShL AH, 1 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/ES1688MX.ASM b/it/SoundDrivers/ES1688MX.ASM new file mode 100755 index 0000000..8996d51 --- /dev/null +++ b/it/SoundDrivers/ES1688MX.ASM @@ -0,0 +1,1751 @@ +; +; ESS Technology's ES1688 Audiodrive chip, MMX version. +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +OUTPUTFILTERENABLED EQU 0 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +;Debug DW 0 +;Debug2 DW 0 +ESSMsg DB "ES1688 AudioDrive MMX", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +ESSNoMemoryMsg DB "ES1688 AudioDrive MMX", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "ES1688 AudioDrive reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITES1688.MMX", 0 +ConfigOKMsg DB "Configuration saved to ITES1688.MMX", 0 + +DriverName DB "ITES1688.MMX", 0 + +ALIGN 4 +FPSave DB 128 Dup (0) +ESSMixConst DB 0, 0 + +DMASize DW 4096 ; Smaller gives better MIDI timing +ConfigPort DW 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 + +MixSegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldESSIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +ESSScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr ESSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + +Comment ~ + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + +~ + + DW 0 + +ESSHeaderLine DW 10 + DB "ESS1688 AudioDrive MMX Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 33, 48 + DB 21h + DB "ESS AudioDrive Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +Comment ~ + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 14 + DB 22, 14 + DW 0, 15 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MasterVolumeRight DW 14 + DB 22, 15 + DW 0, 15 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +~ + +MixModeText DW 1 + DB 2, 14 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 44100 + DW 0 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 16, 32, 18, 8 + DB 0 + DB " MMX, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 19, 32, 21, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 22, 32, 24, 8 + DB 0 + DB " MMX, Volume Ramped", 0 + +MixModeButton4 DW 2 + DW 8, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " MMX, Filtered", 0 + +ALIGN 4 + +VolumeTable DB 2 Dup (0) +MIDIPort DW 0 + +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dmasirq.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label + +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc ESSOut ; AL = data + ; DX = 2xCh + + Push AX + +ESSOut1: + In AL, DX + Test AL, AL + JS ESSOut1 + + Pop AX + Out DX, AL + + Ret + +EndP ESSOut + +; + +Proc ESSOut2 ; AL = data + ; DX = 2xCh + + Push AX + +ESSOut2A: + In AL, DX + Test AL, 80h + LoopNZ ESSOut2A + + Pop AX + Out DX, AL + + Ret + +EndP ESSOut2 + +; + +Proc DetectMMX + + PushFD + Pop EAX + Mov EBX, EAX + Xor EAX, 00200000h + Push EAX + PopFD + PushFD + Pop EAX + Cmp EAX, EBX + JZ DetectMMXFail + + Mov EAX, 1 + DB 0Fh, 0A2h ; CPUID + Test EDX, 800000h + JZ DetectMMXFail + + ClC + Ret + +DetectMMXFail: + StC + Ret + +EndP DetectMMX + +; + +Proc ESSIn2 + +ESSInA1: + In AL, DX + Test AL, 40h + LoopZ ESSInA1 + JZ ESSInA2 + + Add DL, 0Ah-0Ch ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Ch-0Ah + + Ret + +ESSInA2: + Mov AL, 0FFh + Ret + +EndP ESSIn2 + +; + +Proc ESSIn ; DX = 2xCh, returns AL + +ESSIn1: + In AL, DX + Test AL, 40h + JZ ESSIn1 + + Add DL, 0Ah-0Ch ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Ch-0Ah + + Ret + +EndP ESSIn + +; + +Proc UARTOut ; AL = out + + Push DX + Push AX + + Mov DX, CS:MIDIPort + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + JNZ UARTOut1 + + Pop AX + Dec DX + Out DX, AL + + Pop DX + Ret + +EndP UARTOut + +; + +Proc UARTIn ; returns AL + + Push DX + + Mov DX, CS:MIDIPort + Inc DX + +UARTIn1: + In AL, DX + Test AL, 80h + JNZ UARTIn1 + + Dec DX + In AL, DX + + Pop DX + Ret + +EndP UARTIn + +; + +Proc ESSReadMixerRegister ; AL = register to read + ; DX = 2xCh + + Add DL, 04-0Ch + Out DX, AL + Inc DX + In AL, DX + Add DL, 0Ch-05 + + Ret + +EndP ESSReadMixerRegister + +; + +Proc ESSReadRegister ; AH = register to read. + ; DX = 2xCh + ; returns AL + + Mov AL, 0C0h + Call ESSOut + Mov AL, AH + Call ESSOut + Call ESSIn + + Ret + +EndP ESSReadRegister + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Call DetectMMX + JC DetectCardFailure + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Xor CX, CX + Add DL, 0Ch ; 2xCh -> Data ready to send... + + Mov AL, 0E1h + Call ESSOut2 + + Call ESSIn2 + Mov AH, AL ; AH = Major version number + Call ESSIn2 ; AL = Minor version number + + Cmp AX, 301h + JNE DetectCardFailure + + Mov AL, 0E7h + Call ESSOut2 + Call ESSIn2 + Mov AH, AL + Call ESSIn2 + + Cmp AH, 68h + JNE DetectCardReset + Cmp AL, 88h + JB DetectCardReset + Cmp AL, 90h + JAE DetectCardReset + ; We have an ES1688 Audiodrive chip! + +Comment ~ + Mov AL, 40h + Call ESSReadMixerRegister + ShL AL, 1 + And AX, 30h + Add AX, 300h + Mov MIDIPort, AX +~ + + Mov AH, 0B1h ; IRQ determination + Call ESSReadRegister + + Mov BX, 9 + And AL, 0Ch + JZ DetectCardIRQ + + Mov BX, 5 + Cmp AL, 4 + JE DetectCardIRQ + + Mov BX, 7 + Cmp AL, 8 + JE DetectCardIRQ + + Mov BX, 10 + Cmp AL, 0Ch + JNE DetectCardFailure + + +DetectCardIRQ: + Mov IRQ, BX + + Mov AH, 0B2h + Call ESSReadRegister + + Xor BX, BX + And AL, 0Ch + JZ DetectCardFailure + + Cmp AL, 4 + JE DetectCardDMA + + Inc BX + Cmp AL, 8 + JE DetectCardDMA + + Add BL, 2 + +DetectCardDMA: + Mov DMA, BX + + Mov EAX, 'Jeff' + ClC + Ret + +DetectCardReset: + Sub DL, 0Ch + Mov AX, DX + Call ResetDSP + +DetectCardFailure: + StC + Ret + + +EndP DetectCard + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 3 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +include mmxmsam.inc + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Call UARTIn + Mov BL, [MIDIBufferTail] + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + +; Inc Debug + +Comment ~ + Mov DX, [ConfigPort] + Add DL, 6 + In AL, DX + Test AL, 8 + JZ ESSNoMIDI + + Push AX + Call CheckMIDI + Pop AX + +ESSNoMIDI: + Test AL, 1 + JZ ESSIRQEnd +~ + Mov DX, [BasePort] ; ESSAck + Add DL, 0Eh ; ESSAck + In AL, DX ; ESSAck + + Mov AL, 20h ; IRQAck + Cmp IRQ, 8 ; IRQAck + JB WSSAckIRQ1 ; IRQAck + ; IRQAck + Out 0A0h, AL ; IRQAck + ; IRQAck +WSSAckIRQ1: ; IRQAck + Out 20h, AL ; IRQAck + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + + Cmp BX, DMABUFFERLENGTH/2 + JB WSSIRQHandler1 + + Mov AX, DMABUFFERLENGTH/2 + +WSSIRQHandler1: + FNSave [FPSave] + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Mov BX, DMASize ; BX = bytes required + Add DI, AX + ShR BX, 1 + ; BX = samples required + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + FNRstor [CS:FPSave] + +ESSIRQEnd: + Pop ES + Pop DS + PopAD + IRet + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc GetESSMixConst + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetESSMixConst1 + + Mov CX, 22050 + Cmp AX, CX + JB GetESSMixConst1 + + Mov CX, 56821 + Cmp AX, CX + JA GetESSMixConst1 + + Mov CX, AX + +GetESSMixConst1: ; CX = mixspeed. + Mov DX, 0Ch + Mov AX, 236Ch ; DX:AX = 795.5kHz + Div CX + + Mov BX, AX + Neg AL + Mov ESSMixConst, AL + + Mov DX, 0Ch + Mov AX, 236Ch + Div BX + Mov MixSpeed, AX + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Pop DS + PopA + Ret + +EndP GetESSMixConst + +; + +Proc StartESS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov AX, BasePort + Call ResetDSP + Mov DX, AX + Add DL, 0Ch + +; Extended Functions + + Mov AL, 0C6h + Call ESSOut + +; Autoinit DMA + + Mov AL, 0B8h + Call ESSOut + Mov AL, 4 + Call ESSOut + +; Stereo/Mono select + + Mov AH, 0A8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0A8h + Call ESSOut + Mov AL, AH + And AL, Not 3 + Or AL, 2 + Cmp Stereo, 0 + JE StartESS1 + + Xor AL, 3 + +StartESS1: + Call ESSOut + +; DMA mode + + Mov AL, 0B9h + Call ESSOut + Mov AL, 2 + Call ESSOut + +; Mixspeed + + Mov AL, 0A1h + Call ESSOut + Mov AL, ESSMixConst + Call ESSOut + +; Filter clock divider + Mov AL, 0A2h + Call ESSOut + + Mov AL, 0FEh + Call ESSOut + +; DMA counter + Mov CX, DMASize + Neg CX + + Mov AL, 0A4h + Call ESSOut + Mov AL, CL + Call ESSOut + Mov AL, 0A5h + Call ESSOut + Mov AL, CH + Call ESSOut + +; Initialise DAC + Mov AL, 0B6h + Call ESSOut + Mov AL, 0 + Call ESSOut + +; Configure DACs + + Mov AL, 0B7h + Call ESSOut + Mov AL, 71h + Call ESSOut + + Mov AL, 0B7h + Call ESSOut + + Mov AL, 0BCh + Cmp Stereo, 0 + JNE StartESS2 + + Mov AL, 0F4h + +StartESS2: + Call ESSOut + +; IRQ configuration + Mov AH, 0B1h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B1h + Call ESSOut + Mov AL, AH + And AL, 0Fh + Or AL, 50h + Call ESSOut + +; DMA configuration + Mov AH, 0B2h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B2h + Call ESSOut + Mov AL, AH + And AL, 0Fh + Or AL, 50h + Call ESSOut + +; Enable voice + Mov AL, 0D1h + Call ESSOut + +; Start transfer + Mov AH, 0B8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B8h + Call ESSOut + Mov AL, AH + Or AL, 1 + Call ESSOut + +Comment ~ + +; Init UART + Mov DX, MIDIPort + Inc DX + Mov AL, 3Fh ; Intelligent mode. + Out DX, AL + +; Enable MIDI IRQ + Mov DX, BasePort + Add DL, 4 + Mov AX, 4064h + Out DX, AX + +~ + + Pop DS + Pop ES + PopA + + Ret + +EndP StartESS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + And AX, 0FF0h + ShR AH, 1 + ShR AL, 5 + Mov Word Ptr [VolumeTable], AX + + Call GetESSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, (DMABUFFERLENGTH*2)/16 + 5 + Mov BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Mov AX, BasePort + Call ResetDSP + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver +; +;DMAPort1 EQU $+1 +; In AL, 1 +; Mov BL, AL +;DMAPort2 EQU $+1 +; In AL, 1 +; Mov BH, AL +; +; Mov Debug2, BX + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov AX, BasePort + Call ResetDSP + Call StartESS + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset ESSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Mov AH, [VolumeTable] + ShL AH, 4 + Or AH, [VolumeTable+1] + ShL AH, 1 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h +; Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: +; Call UARTOut + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 + DW 3 + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/ES1868.ASM b/it/SoundDrivers/ES1868.ASM new file mode 100755 index 0000000..ab64c5f --- /dev/null +++ b/it/SoundDrivers/ES1868.ASM @@ -0,0 +1,2328 @@ +; +; ESS Technology's ES1868 AudioDrive chip. +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +PNPSERIALID EQU 0FFFFFFFFh +PNPVENDORID EQU 68187316h + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +ESSMsg DB "ESS ES1868 AudioDrive found", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +ESSNoMemoryMsg DB "ESS ES1868 AudioDrive found", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "ESS ES1868 AudioDrive reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITES1868.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITES1868.DRV", 0 + +DriverName DB "ITES1868.DRV", 0 + +ALIGN 4 +FilterValue DD 0 +FilterValue2 DD 0 +ESSMixConst DB 0, 0 + +DMASize DW 2048 ; Smaller gives better MIDI timing +ConfigPort DW 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldESSIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +ESSScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr ESSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + +Comment ~ + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + +~ + + DW 0 + +ESSHeaderLine DW 10 + DB "ESS ES1868 AudioDrive Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 26, 48 + DB 21h + DB "ESS ES1868 AudioDrive Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +Comment ~ + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 14 + DB 22, 14 + DW 0, 15 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MasterVolumeRight DW 14 + DB 22, 15 + DW 0, 15 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +~ + +MixModeText DW 1 + DB 2, 14 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 44100 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 16, 32, 18, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 19, 32, 21, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 22, 32, 24, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 29 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 31, 29, 33, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 34, 29, 36, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 37, 29, 39, 8 + DB 0 + DB " 75% Filter", 0 + +ALIGN 4 + +VolumeTable DB 2 Dup (0) +MIDIPort DW 0 + +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc ESSOut ; AL = data + ; DX = 2xCh + + Push AX + +ESSOut1: + In AL, DX + Test AL, AL + JS ESSOut1 + + Pop AX + Out DX, AL + + Ret + +EndP ESSOut + +; + +Proc ESSIn ; DX = 2xCh, returns AL + +ESSIn1: + In AL, DX + Test AL, 40h + JZ ESSIn1 + + Add DL, 0Ah-0Ch ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Ch-0Ah + + Ret + +EndP ESSIn + +; + +Proc UARTOut ; AL = out + + Push DX + Push AX + + Mov DX, CS:MIDIPort + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + JNZ UARTOut1 + + Pop AX + Dec DX + Out DX, AL + + Pop DX + Ret + +EndP UARTOut + +; + +Proc UARTIn ; returns AL + + Push DX + + Mov DX, CS:MIDIPort + Inc DX + +UARTIn1: + In AL, DX + Test AL, 80h + JNZ UARTIn1 + + Dec DX + In AL, DX + + Pop DX + Ret + +EndP UARTIn + +; + +Proc ESSReadRegister ; AH = register to read. + ; DX = 2xCh + ; returns AL + + Mov AL, 0C0h + Call ESSOut + Mov AL, AH + Call ESSOut + Call ESSIn + + Ret + +EndP ESSReadRegister + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + +; Cmp PnP_VendorID, PNPVENDORID +; JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Mov ConfigPort, AX + + Mov AX, 107h ; Audio device + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + Mov MIDIPort, AX + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, CS:MIDIPort + Inc DX + Mov AL, 0FFh + Out DX, AL + + Mov DX, CS:BasePort + Add DL, 6 + Mov AL, 3 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Call UARTIn + Mov BL, [MIDIBufferTail] + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [ConfigPort] + Add DL, 6 + In AL, DX + Test AL, 8 + JZ ESSNoMIDI + + Push AX + Call CheckMIDI + Pop AX + +ESSNoMIDI: + Test AL, 1 + JZ ESSIRQEnd + + Mov DX, [BasePort] + Add DL, 0Eh + In AL, DX + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB ESSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +ESSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE ESSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +ESSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB ESSIRQHandler6 + JE ESSIRQHFilter + + Cmp CS:Stereo, 0 + JE ESSIRQ3QFilterMono + +ESSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +ESSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +ESSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +ESSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilter: + Cmp CS:Stereo, 0 + JE ESSIRQHFilterMono + +ESSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +ESSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +ESSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +ESSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL ESSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG ESSIRQHandlerClip2 + +ESSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ ESSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + +ESSIRQEnd: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Pop ES + Pop DS + PopAD + IRet + +ESSIRQHandlerClip1: + Mov AX, 8000h + Jmp ESSIRQHandler7 + +ESSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp ESSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo3 + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc GetESSMixConst + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetESSMixConst1 + + Mov CX, 22050 + Cmp AX, CX + JB GetESSMixConst1 + + Mov CX, 56821 + Cmp AX, CX + JA GetESSMixConst1 + + Mov CX, AX + +GetESSMixConst1: ; CX = mixspeed. + Mov DX, 0Ch + Mov AX, 236Ch ; DX:AX = 795.5kHz + Div CX + + Mov BX, AX + Neg AL + Mov ESSMixConst, AL + + Mov DX, 0Ch + Mov AX, 236Ch + Div BX + Mov MixSpeed, AX + + Pop DS + PopA + Ret + +EndP GetESSMixConst + +; + +Proc StartESS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Call ResetDSP + Mov DX, BasePort + Add DL, 0Ch + +; Extended Functions + + Mov AL, 0C6h + Call ESSOut + +; Autoinit DMA + + Mov AL, 0B8h + Call ESSOut + Mov AL, 4 + Call ESSOut + +; Stereo/Mono select + + Mov AH, 0A8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0A8h + Call ESSOut + Mov AL, AH + And AL, Not 3 + Or AL, 2 + Cmp Stereo, 0 + JE StartESS1 + + Xor AL, 3 + +StartESS1: + Call ESSOut + +; DMA mode + + Mov AL, 0B9h + Call ESSOut + Mov AL, 2 + Call ESSOut + +; Mixspeed + + Mov AL, 0A1h + Call ESSOut + Mov AL, ESSMixConst + Call ESSOut + +; Filter clock divider + Mov AL, 0A2h + Call ESSOut + + Mov AL, 0FEh + Call ESSOut + +; DMA counter + Mov CX, DMASize + Neg CX + + Mov AL, 0A4h + Call ESSOut + Mov AL, CL + Call ESSOut + Mov AL, 0A5h + Call ESSOut + Mov AL, CH + Call ESSOut + +; Initialise DAC + Mov AL, 0B6h + Call ESSOut + Mov AL, 0 + Call ESSOut + +; Configure DACs + + Mov AL, 0B7h + Call ESSOut + Mov AL, 71h + Call ESSOut + + Mov AL, 0B7h + Call ESSOut + + Mov AL, 0BCh + Cmp Stereo, 0 + JNE StartESS2 + + Mov AL, 0F4h + +StartESS2: + Call ESSOut + +; IRQ configuration + Mov AL, 0B1h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; DMA configuration + Mov AL, 0B2h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; Enable voice + Mov AL, 0D1h + Call ESSOut + +; Start transfer + Mov AH, 0B8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B8h + Call ESSOut + Mov AL, AH + Or AL, 1 + Call ESSOut + +; Init UART + Mov DX, MIDIPort + Inc DX + Mov AL, 3Fh ; Intelligent mode. + Out DX, AL + +; Enable MIDI IRQ + Mov DX, BasePort + Add DL, 4 + Mov AX, 4064h + Out DX, AX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartESS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + And AX, 0FF0h + ShR AH, 1 + ShR AL, 5 + Mov Word Ptr [VolumeTable], AX + + Call GetESSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetDSP + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call ResetDSP + Call StartESS + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset ESSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Mov AH, [VolumeTable] + ShL AH, 4 + Or AH, [VolumeTable+1] + ShL AH, 1 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/ES1868MX.ASM b/it/SoundDrivers/ES1868MX.ASM new file mode 100755 index 0000000..36f4721 --- /dev/null +++ b/it/SoundDrivers/ES1868MX.ASM @@ -0,0 +1,1734 @@ +; +; ESS Technology's ES1868 AudioDrive chip. +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +PNPSERIALID EQU 0FFFFFFFFh +PNPVENDORID EQU 68187316h + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +OUTPUTFILTERENABLED EQU 0 + +FPSave DB 128 Dup (0) + +ESSMsg DB "ESS ES1868 AudioDrive MMX", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +ESSNoMemoryMsg DB "ESS ES1868 AudioDrive MMX", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "ESS ES1868 AudioDrive reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITES1868.MMX", 0 +ConfigOKMsg DB "Configuration saved to ITES1868.MMX", 0 + +DriverName DB "ITES1868.MMX", 0 + +ALIGN 4 +ESSMixConst DB 0, 0 + +DMASize DW 2048 ; Smaller gives better MIDI timing +ConfigPort DW 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 + +MixSegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 4 +MixMode DW 0 +MixModeOffset DW 0 + +IMR DW 0 +OldESSIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +ESSScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr ESSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW 0 + +ESSHeaderLine DW 10 + DB "ESS ES1868 AudioDrive MMX Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 22, 48 + DB 21h + DB "ESS ES1868 AudioDrive MMX Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MixModeText DW 1 + DB 2, 14 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 44100 + DW 0 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 16, 32, 18, 8 + DB 0 + DB " MMX, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 19, 32, 21, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 22, 32, 24, 8 + DB 0 + DB " MMX, Volume Ramped", 0 + +MixModeButton4 DW 2 + DW 8, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " MMX, Filtered", 0 + +ALIGN 4 + +VolumeTable DB 2 Dup (0) +MIDIPort DW 0 + +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label + +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc ESSOut ; AL = data + ; DX = 2xCh + + Push AX + +ESSOut1: + In AL, DX + Test AL, AL + JS ESSOut1 + + Pop AX + Out DX, AL + + Ret + +EndP ESSOut + +; + +Proc ESSIn ; DX = 2xCh, returns AL + +ESSIn1: + In AL, DX + Test AL, 40h + JZ ESSIn1 + + Add DL, 0Ah-0Ch ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Ch-0Ah + + Ret + +EndP ESSIn + +; + +Proc UARTOut ; AL = out + + Push DX + Push AX + + Mov DX, CS:MIDIPort + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + JNZ UARTOut1 + + Pop AX + Dec DX + Out DX, AL + + Pop DX + Ret + +EndP UARTOut + +; + +Proc UARTIn ; returns AL + + Push DX + + Mov DX, CS:MIDIPort + Inc DX + +UARTIn1: + In AL, DX + Test AL, 80h + JNZ UARTIn1 + + Dec DX + In AL, DX + + Pop DX + Ret + +EndP UARTIn + +; + +Proc ESSReadRegister ; AH = register to read. + ; DX = 2xCh + ; returns AL + + Mov AL, 0C0h + Call ESSOut + Mov AL, AH + Call ESSOut + Call ESSIn + + Ret + +EndP ESSReadRegister + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + +; Cmp PnP_VendorID, PNPVENDORID +; JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Mov ConfigPort, AX + + Mov AX, 107h ; Audio device + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + Mov MIDIPort, AX + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, CS:MIDIPort + Inc DX + Mov AL, 0FFh + Out DX, AL + + Mov DX, CS:BasePort + Add DL, 6 + Mov AL, 3 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +include mmxmsam.inc + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Call UARTIn + Mov BL, [MIDIBufferTail] + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [ConfigPort] + Add DL, 6 + In AL, DX + Test AL, 8 + JZ ESSNoMIDI + + Push AX + Call CheckMIDI + Pop AX + +ESSNoMIDI: + Test AL, 1 + JZ ESSIRQEnd + + Mov DX, [BasePort] + Add DL, 0Eh + In AL, DX + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB ESSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +ESSIRQHandler2: + FNSave [FPSave] + + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE ESSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +ESSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + FNRStor [CS:FPSave] + +ESSIRQEnd: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Pop ES + Pop DS + PopAD + IRet + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc GetESSMixConst + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetESSMixConst1 + + Mov CX, 22050 + Cmp AX, CX + JB GetESSMixConst1 + + Mov CX, 56821 + Cmp AX, CX + JA GetESSMixConst1 + + Mov CX, AX + +GetESSMixConst1: ; CX = mixspeed. + Mov DX, 0Ch + Mov AX, 236Ch ; DX:AX = 795.5kHz + Div CX + + Mov BX, AX + Neg AL + Mov ESSMixConst, AL + + Mov DX, 0Ch + Mov AX, 236Ch + Div BX + Mov MixSpeed, AX + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Pop DS + PopA + Ret + +EndP GetESSMixConst + +; + +Proc StartESS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Call ResetDSP + Mov DX, BasePort + Add DL, 0Ch + +; Extended Functions + + Mov AL, 0C6h + Call ESSOut + +; Autoinit DMA + + Mov AL, 0B8h + Call ESSOut + Mov AL, 4 + Call ESSOut + +; Stereo/Mono select + + Mov AH, 0A8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0A8h + Call ESSOut + Mov AL, AH + And AL, Not 3 + Or AL, 2 + Cmp Stereo, 0 + JE StartESS1 + + Xor AL, 3 + +StartESS1: + Call ESSOut + +; DMA mode + + Mov AL, 0B9h + Call ESSOut + Mov AL, 2 + Call ESSOut + +; Mixspeed + + Mov AL, 0A1h + Call ESSOut + Mov AL, ESSMixConst + Call ESSOut + +; Filter clock divider + Mov AL, 0A2h + Call ESSOut + + Mov AL, 0FEh + Call ESSOut + +; DMA counter + Mov CX, DMASize + Neg CX + + Mov AL, 0A4h + Call ESSOut + Mov AL, CL + Call ESSOut + Mov AL, 0A5h + Call ESSOut + Mov AL, CH + Call ESSOut + +; Initialise DAC + Mov AL, 0B6h + Call ESSOut + Mov AL, 0 + Call ESSOut + +; Configure DACs + + Mov AL, 0B7h + Call ESSOut + Mov AL, 71h + Call ESSOut + + Mov AL, 0B7h + Call ESSOut + + Mov AL, 0BCh + Cmp Stereo, 0 + JNE StartESS2 + + Mov AL, 0F4h + +StartESS2: + Call ESSOut + +; IRQ configuration + Mov AL, 0B1h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; DMA configuration + Mov AL, 0B2h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; Enable voice + Mov AL, 0D1h + Call ESSOut + +; Start transfer + Mov AH, 0B8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B8h + Call ESSOut + Mov AL, AH + Or AL, 1 + Call ESSOut + +; Init UART + Mov DX, MIDIPort + Inc DX + Mov AL, 3Fh ; Intelligent mode. + Out DX, AL + +; Enable MIDI IRQ + Mov DX, BasePort + Add DL, 4 + Mov AX, 4064h + Out DX, AX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartESS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + And AX, 0FF0h + ShR AH, 1 + ShR AL, 5 + Mov Word Ptr [VolumeTable], AX + + Call GetESSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, (DMABUFFERLENGTH*2)/16+5 + Mov BX, DX + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetDSP + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call ResetDSP + Call StartESS + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset ESSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Mov AH, [VolumeTable] + ShL AH, 4 + Or AH, [VolumeTable+1] + ShL AH, 1 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 + DW 3 ; MIDI, hiqual + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/ES1869.ASM b/it/SoundDrivers/ES1869.ASM new file mode 100755 index 0000000..d85d4f5 --- /dev/null +++ b/it/SoundDrivers/ES1869.ASM @@ -0,0 +1,2328 @@ +; +; ESS Technology's ES1869 AudioDrive chip. +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +PNPSERIALID EQU 0FFFFFFFFh +PNPVENDORID EQU 03007316h + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +ESSMsg DB "ESS ES1869 AudioDrive found", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +ESSNoMemoryMsg DB "ESS ES1869 AudioDrive found", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "ESS ES1869 AudioDrive reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITES1869.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITES1869.DRV", 0 + +DriverName DB "ITES1869.DRV", 0 + +ALIGN 4 +FilterValue DD 0 +FilterValue2 DD 0 +ESSMixConst DB 0, 0 + +DMASize DW 2048 ; Smaller gives better MIDI timing +ConfigPort DW 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldESSIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +ESSScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr ESSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + +Comment ~ + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + +~ + + DW 0 + +ESSHeaderLine DW 10 + DB "ESS ES1869 AudioDrive Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 26, 48 + DB 21h + DB "ESS ES1869 AudioDrive Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +Comment ~ + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 14 + DB 22, 14 + DW 0, 15 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MasterVolumeRight DW 14 + DB 22, 15 + DW 0, 15 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +~ + +MixModeText DW 1 + DB 2, 14 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 44100 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 16, 32, 18, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 19, 32, 21, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 22, 32, 24, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 29 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 31, 29, 33, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 34, 29, 36, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 37, 29, 39, 8 + DB 0 + DB " 75% Filter", 0 + +ALIGN 4 + +VolumeTable DB 2 Dup (0) +MIDIPort DW 0 + +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc ESSOut ; AL = data + ; DX = 2xCh + + Push AX + +ESSOut1: + In AL, DX + Test AL, AL + JS ESSOut1 + + Pop AX + Out DX, AL + + Ret + +EndP ESSOut + +; + +Proc ESSIn ; DX = 2xCh, returns AL + +ESSIn1: + In AL, DX + Test AL, 40h + JZ ESSIn1 + + Add DL, 0Ah-0Ch ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Ch-0Ah + + Ret + +EndP ESSIn + +; + +Proc UARTOut ; AL = out + + Push DX + Push AX + + Mov DX, CS:MIDIPort + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + JNZ UARTOut1 + + Pop AX + Dec DX + Out DX, AL + + Pop DX + Ret + +EndP UARTOut + +; + +Proc UARTIn ; returns AL + + Push DX + + Mov DX, CS:MIDIPort + Inc DX + +UARTIn1: + In AL, DX + Test AL, 80h + JNZ UARTIn1 + + Dec DX + In AL, DX + + Pop DX + Ret + +EndP UARTIn + +; + +Proc ESSReadRegister ; AH = register to read. + ; DX = 2xCh + ; returns AL + + Mov AL, 0C0h + Call ESSOut + Mov AL, AH + Call ESSOut + Call ESSIn + + Ret + +EndP ESSReadRegister + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + +; Cmp PnP_VendorID, PNPVENDORID +; JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Mov ConfigPort, AX + + Mov AX, 107h ; Audio device + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + Mov MIDIPort, AX + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, CS:MIDIPort + Inc DX + Mov AL, 0FFh + Out DX, AL + + Mov DX, CS:BasePort + Add DL, 6 + Mov AL, 3 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Call UARTIn + Mov BL, [MIDIBufferTail] + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [ConfigPort] + Add DL, 6 + In AL, DX + Test AL, 8 + JZ ESSNoMIDI + + Push AX + Call CheckMIDI + Pop AX + +ESSNoMIDI: + Test AL, 1 + JZ ESSIRQEnd + + Mov DX, [BasePort] + Add DL, 0Eh + In AL, DX + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB ESSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +ESSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE ESSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +ESSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB ESSIRQHandler6 + JE ESSIRQHFilter + + Cmp CS:Stereo, 0 + JE ESSIRQ3QFilterMono + +ESSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +ESSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +ESSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +ESSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilter: + Cmp CS:Stereo, 0 + JE ESSIRQHFilterMono + +ESSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +ESSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +ESSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +ESSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL ESSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG ESSIRQHandlerClip2 + +ESSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ ESSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + +ESSIRQEnd: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Pop ES + Pop DS + PopAD + IRet + +ESSIRQHandlerClip1: + Mov AX, 8000h + Jmp ESSIRQHandler7 + +ESSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp ESSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo3 + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc GetESSMixConst + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetESSMixConst1 + + Mov CX, 22050 + Cmp AX, CX + JB GetESSMixConst1 + + Mov CX, 56821 + Cmp AX, CX + JA GetESSMixConst1 + + Mov CX, AX + +GetESSMixConst1: ; CX = mixspeed. + Mov DX, 0Ch + Mov AX, 236Ch ; DX:AX = 795.5kHz + Div CX + + Mov BX, AX + Neg AL + Mov ESSMixConst, AL + + Mov DX, 0Ch + Mov AX, 236Ch + Div BX + Mov MixSpeed, AX + + Pop DS + PopA + Ret + +EndP GetESSMixConst + +; + +Proc StartESS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Call ResetDSP + Mov DX, BasePort + Add DL, 0Ch + +; Extended Functions + + Mov AL, 0C6h + Call ESSOut + +; Autoinit DMA + + Mov AL, 0B8h + Call ESSOut + Mov AL, 4 + Call ESSOut + +; Stereo/Mono select + + Mov AH, 0A8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0A8h + Call ESSOut + Mov AL, AH + And AL, Not 3 + Or AL, 2 + Cmp Stereo, 0 + JE StartESS1 + + Xor AL, 3 + +StartESS1: + Call ESSOut + +; DMA mode + + Mov AL, 0B9h + Call ESSOut + Mov AL, 2 + Call ESSOut + +; Mixspeed + + Mov AL, 0A1h + Call ESSOut + Mov AL, ESSMixConst + Call ESSOut + +; Filter clock divider + Mov AL, 0A2h + Call ESSOut + + Mov AL, 0FEh + Call ESSOut + +; DMA counter + Mov CX, DMASize + Neg CX + + Mov AL, 0A4h + Call ESSOut + Mov AL, CL + Call ESSOut + Mov AL, 0A5h + Call ESSOut + Mov AL, CH + Call ESSOut + +; Initialise DAC + Mov AL, 0B6h + Call ESSOut + Mov AL, 0 + Call ESSOut + +; Configure DACs + + Mov AL, 0B7h + Call ESSOut + Mov AL, 71h + Call ESSOut + + Mov AL, 0B7h + Call ESSOut + + Mov AL, 0BCh + Cmp Stereo, 0 + JNE StartESS2 + + Mov AL, 0F4h + +StartESS2: + Call ESSOut + +; IRQ configuration + Mov AL, 0B1h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; DMA configuration + Mov AL, 0B2h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; Enable voice + Mov AL, 0D1h + Call ESSOut + +; Start transfer + Mov AH, 0B8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B8h + Call ESSOut + Mov AL, AH + Or AL, 1 + Call ESSOut + +; Init UART + Mov DX, MIDIPort + Inc DX + Mov AL, 3Fh ; Intelligent mode. + Out DX, AL + +; Enable MIDI IRQ + Mov DX, BasePort + Add DL, 4 + Mov AX, 4064h + Out DX, AX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartESS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + And AX, 0FF0h + ShR AH, 1 + ShR AL, 5 + Mov Word Ptr [VolumeTable], AX + + Call GetESSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetDSP + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call ResetDSP + Call StartESS + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset ESSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Mov AH, [VolumeTable] + ShL AH, 4 + Or AH, [VolumeTable+1] + ShL AH, 1 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/ES1869MX.ASM b/it/SoundDrivers/ES1869MX.ASM new file mode 100755 index 0000000..a6c64c0 --- /dev/null +++ b/it/SoundDrivers/ES1869MX.ASM @@ -0,0 +1,1734 @@ +; +; ESS Technology's ES1869 AudioDrive chip. +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +PNPSERIALID EQU 0FFFFFFFFh +PNPVENDORID EQU 03007316h + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +OUTPUTFILTERENABLED EQU 0 + +FPSave DB 128 Dup (0) + +ESSMsg DB "ESS ES1869 AudioDrive MMX", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +ESSNoMemoryMsg DB "ESS ES1869 AudioDrive MMX", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "ESS ES1869 AudioDrive reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITES1869.MMX", 0 +ConfigOKMsg DB "Configuration saved to ITES1869.MMX", 0 + +DriverName DB "ITES1869.MMX", 0 + +ALIGN 4 +ESSMixConst DB 0, 0 + +DMASize DW 2048 ; Smaller gives better MIDI timing +ConfigPort DW 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 + +MixSegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 4 +MixMode DW 0 +MixModeOffset DW 0 + +IMR DW 0 +OldESSIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +ESSScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr ESSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW 0 + +ESSHeaderLine DW 10 + DB "ESS ES1869 AudioDrive MMX Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 22, 48 + DB 21h + DB "ESS ES1869 AudioDrive MMX Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MixModeText DW 1 + DB 2, 14 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 44100 + DW 0 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 16, 32, 18, 8 + DB 0 + DB " MMX, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 19, 32, 21, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 22, 32, 24, 8 + DB 0 + DB " MMX, Volume Ramped", 0 + +MixModeButton4 DW 2 + DW 8, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " MMX, Filtered", 0 + +ALIGN 4 + +VolumeTable DB 2 Dup (0) +MIDIPort DW 0 + +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label + +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc ESSOut ; AL = data + ; DX = 2xCh + + Push AX + +ESSOut1: + In AL, DX + Test AL, AL + JS ESSOut1 + + Pop AX + Out DX, AL + + Ret + +EndP ESSOut + +; + +Proc ESSIn ; DX = 2xCh, returns AL + +ESSIn1: + In AL, DX + Test AL, 40h + JZ ESSIn1 + + Add DL, 0Ah-0Ch ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Ch-0Ah + + Ret + +EndP ESSIn + +; + +Proc UARTOut ; AL = out + + Push DX + Push AX + + Mov DX, CS:MIDIPort + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + JNZ UARTOut1 + + Pop AX + Dec DX + Out DX, AL + + Pop DX + Ret + +EndP UARTOut + +; + +Proc UARTIn ; returns AL + + Push DX + + Mov DX, CS:MIDIPort + Inc DX + +UARTIn1: + In AL, DX + Test AL, 80h + JNZ UARTIn1 + + Dec DX + In AL, DX + + Pop DX + Ret + +EndP UARTIn + +; + +Proc ESSReadRegister ; AH = register to read. + ; DX = 2xCh + ; returns AL + + Mov AL, 0C0h + Call ESSOut + Mov AL, AH + Call ESSOut + Call ESSIn + + Ret + +EndP ESSReadRegister + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + +; Cmp PnP_VendorID, PNPVENDORID +; JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Mov ConfigPort, AX + + Mov AX, 107h ; Audio device + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + Mov MIDIPort, AX + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, CS:MIDIPort + Inc DX + Mov AL, 0FFh + Out DX, AL + + Mov DX, CS:BasePort + Add DL, 6 + Mov AL, 3 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +include mmxmsam.inc + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Call UARTIn + Mov BL, [MIDIBufferTail] + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [ConfigPort] + Add DL, 6 + In AL, DX + Test AL, 8 + JZ ESSNoMIDI + + Push AX + Call CheckMIDI + Pop AX + +ESSNoMIDI: + Test AL, 1 + JZ ESSIRQEnd + + Mov DX, [BasePort] + Add DL, 0Eh + In AL, DX + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB ESSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +ESSIRQHandler2: + FNSave [FPSave] + + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE ESSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +ESSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + FNRStor [CS:FPSave] + +ESSIRQEnd: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Pop ES + Pop DS + PopAD + IRet + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc GetESSMixConst + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetESSMixConst1 + + Mov CX, 22050 + Cmp AX, CX + JB GetESSMixConst1 + + Mov CX, 56821 + Cmp AX, CX + JA GetESSMixConst1 + + Mov CX, AX + +GetESSMixConst1: ; CX = mixspeed. + Mov DX, 0Ch + Mov AX, 236Ch ; DX:AX = 795.5kHz + Div CX + + Mov BX, AX + Neg AL + Mov ESSMixConst, AL + + Mov DX, 0Ch + Mov AX, 236Ch + Div BX + Mov MixSpeed, AX + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Pop DS + PopA + Ret + +EndP GetESSMixConst + +; + +Proc StartESS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Call ResetDSP + Mov DX, BasePort + Add DL, 0Ch + +; Extended Functions + + Mov AL, 0C6h + Call ESSOut + +; Autoinit DMA + + Mov AL, 0B8h + Call ESSOut + Mov AL, 4 + Call ESSOut + +; Stereo/Mono select + + Mov AH, 0A8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0A8h + Call ESSOut + Mov AL, AH + And AL, Not 3 + Or AL, 2 + Cmp Stereo, 0 + JE StartESS1 + + Xor AL, 3 + +StartESS1: + Call ESSOut + +; DMA mode + + Mov AL, 0B9h + Call ESSOut + Mov AL, 2 + Call ESSOut + +; Mixspeed + + Mov AL, 0A1h + Call ESSOut + Mov AL, ESSMixConst + Call ESSOut + +; Filter clock divider + Mov AL, 0A2h + Call ESSOut + + Mov AL, 0FEh + Call ESSOut + +; DMA counter + Mov CX, DMASize + Neg CX + + Mov AL, 0A4h + Call ESSOut + Mov AL, CL + Call ESSOut + Mov AL, 0A5h + Call ESSOut + Mov AL, CH + Call ESSOut + +; Initialise DAC + Mov AL, 0B6h + Call ESSOut + Mov AL, 0 + Call ESSOut + +; Configure DACs + + Mov AL, 0B7h + Call ESSOut + Mov AL, 71h + Call ESSOut + + Mov AL, 0B7h + Call ESSOut + + Mov AL, 0BCh + Cmp Stereo, 0 + JNE StartESS2 + + Mov AL, 0F4h + +StartESS2: + Call ESSOut + +; IRQ configuration + Mov AL, 0B1h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; DMA configuration + Mov AL, 0B2h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; Enable voice + Mov AL, 0D1h + Call ESSOut + +; Start transfer + Mov AH, 0B8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B8h + Call ESSOut + Mov AL, AH + Or AL, 1 + Call ESSOut + +; Init UART + Mov DX, MIDIPort + Inc DX + Mov AL, 3Fh ; Intelligent mode. + Out DX, AL + +; Enable MIDI IRQ + Mov DX, BasePort + Add DL, 4 + Mov AX, 4064h + Out DX, AX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartESS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + And AX, 0FF0h + ShR AH, 1 + ShR AL, 5 + Mov Word Ptr [VolumeTable], AX + + Call GetESSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, (DMABUFFERLENGTH*2)/16+5 + Mov BX, DX + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetDSP + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call ResetDSP + Call StartESS + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset ESSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Mov AH, [VolumeTable] + ShL AH, 4 + Or AH, [VolumeTable+1] + ShL AH, 1 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 + DW 3 ; MIDI, hiqual + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/EWS64.ASM b/it/SoundDrivers/EWS64.ASM new file mode 100755 index 0000000..abd573f --- /dev/null +++ b/it/SoundDrivers/EWS64.ASM @@ -0,0 +1,933 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;*********************************************** + +TRACEENABLED = 0 +CREATENEWLOGFILE = 1 + +include debug.inc + +PNPVENDORID EQU 36A8630Eh + +MMT_MAXENTRIES EQU 64 +MMT_MAXSIZE EQU 3*MMT_MAXENTRIES + +ST97Message DB "EWS 64 Synthesizer Detected", 13 +; DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, ", 0FDh, "Dk RAM", 0 + DB "Port ", 0FDh, "Xh, ", 0FDh, "D Voices, ", 0FDh, "Dk", 0 + +StatusLine DB "FreeEWS ", 0FDh, "Dk", 0 + +MMTData DW MMT_MAXSIZE Dup (0) + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +; EmptyFunction + +Proc EmptyFunction Far + + Xor AX, AX + StC + Ret + +EndP EmptyFunction + +; ST97InString + +Proc ST97InString ; ES:DI points to deposit point. + ; EAX = memory address + ; CX = count + + ClI + + Mov BL, 2 ; Ctrl=RD_MEM, Data=Memory Address + Call ST97OutDWord + + Mov DX, CS:BasePort ; Length + Mov AX, CX + Call ST97SendByte + + Mov AL, AH + Call ST97SendByte + +ST97InString1: + Call ST97InByte + Cmp AL, 0ABh + JE ST97InStringError + Cmp AL, 0ACh + JNE ST97InString1 + +ST97InString2: + Inc DX + Inc DX + + Rep InsW + + ClC + StI + Ret + +ST97InStringError: + StC + StI + Ret + +EndP ST97InString + +; ST97ReceiveByte + +Proc ST97ReceiveByte ; Returns AL + + Push DX + Mov DX, CS:BasePort + Inc DX + +ST97ReceiveByte1: + In AL, DX + Test AL, AL + JS ST97ReceiveByte1 + + Dec DX + In AL, DX + Pop DX + + Ret + +EndP ST97ReceiveByte + +; ST97InByte + +Proc ST97InByte ; Returns AL + + Jmp ST97ReceiveByte + +EndP ST97InByte + +; ST97InWord + +Proc ST97InWord ; Returns AX + + ClI + + Call ST97ReceiveByte + Mov AL, AH + + Call ST97ReceiveByte + XChg AL, AH + + StI + + Ret + +EndP ST97InWord + +; ST97InDWord + +Proc ST97InDWord ; Returns EAX + + ClI + + Call ST97ReceiveByte + RoR EAX, 8 + + Call ST97ReceiveByte + RoR EAX, 8 + + Call ST97ReceiveByte + RoR EAX, 8 + + Call ST97ReceiveByte + RoR EAX, 8 + + StI + Ret + +EndP ST97InDWord + +; ST97SendByte + +Proc ST97SendByte ; DX = port, AL = data + + Push AX + Push DX + Mov DX, CS:BasePort + Inc DX + +ST97SendByte1: + In AL, DX + Test AL, 40h + JNZ ST97SendByte1 + + Pop DX + Pop AX + + Out DX, AL + + Ret + +EndP ST97SendByte + +; ST97OutByte + +Proc ST97OutByte ; AL = data, AH = command, destroys AX + + ClI + Push DX + + Mov DX, CS:BasePort + Inc DX + + XChg AH, AL + Call ST97SendByte + + Dec DX + + Mov AL, AH + Call ST97SendByte + + Pop DX + StI + + Ret + +EndP ST97OutByte + +; ST97OutWord + +Proc ST97OutWord ; AX = data, BL = command, destroys AX + + ClI + Push DX + Push AX + + Mov DX, CS:BasePort + Mov AL, BL + Inc DX + Call ST97SendByte + + Pop AX + Dec DX + Call ST97SendByte + + Mov AL, AH + Call ST97SendByte + + Pop DX + StI + + Ret + +EndP ST97OutWord + +; ST97OutDWord + +Proc ST97OutDWord ; EAX = data, BL = command + + ClI + Push DX + Push AX + + Mov DX, CS:BasePort + Mov AL, BL + Inc DX + Call ST97SendByte + + Pop AX + Dec DX + Call ST97SendByte + + ShR EAX, 8 + Call ST97SendByte + + ShR EAX, 8 + Call ST97SendByte + + ShR EAX, 8 + Call ST97SendByte + + Pop DX + StI + + Ret + +EndP ST97OutDWord + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc ResetUART ; Given DX = Port + + ClI + + Inc DX + + Mov AL, 0FFh ; Reset! + Out DX, AL + Out DX, AL ; Two resets required to ensure it'll work + + Xor CX, CX + +ResetUART2: + In AL, DX + Test AL, 80h + JNZ ResetUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE ResetUART4 + +ResetUART3: + Loop ResetUART2 + +ResetUARTError: + StI + StC + Ret + +ResetUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +ResetUART5: + In AL, DX + Test AL, 40h + LoopNZ ResetUART5 + JNZ ResetUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +ResetUART6: + Xor CX, CX + +ResetUART7: + In AL, DX + Test AL, 80h + JNZ ResetUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE ResetUART9 + +ResetUART8: + Loop ResetUART7 + Jmp ResetUARTError + +ResetUART9: + StI + ClC + Ret + +EndP ResetUART + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + Mov AX, 407h ; LDN 4 + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Trace "Detecting EWS64XL" + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + Trace "EWS64XL Not found" + + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + +; Check whether the MPU can be reset + Mov DX, BasePort + Call ResetUART + JC PnP_DetectCardNotFound + +; Find memory mapping table + Mov AX, 300h ; Ctrl 3 (GET_MMT), Data 0 + Call ST97OutByte + Call ST97InDWord + + Push CS + Pop ES + Mov CX, MMT_MAXSIZE + Mov DI, Offset MMTData + Call ST97InString + + Trace "EWS64XL Found" + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Trace "EWS64XL InitSound" + + Mov SI, Offset ST97Message +Comment ~ + Mov AX, BasePort + Mov BX, IRQ + Mov ECX, DWord Ptr [MMTData+2] + ShR ECX, 9 +~ + Xor BX, BX + Mov AX, 5100h ; Cntrl = GET_VOI, Data = 0 + Call ST97OutByte + Call ST97InByte + Mov BL, AL + Mov AX, BasePort + Mov ECX, DWord Ptr [MMTData+2] + ShR ECX, 9 + + Trace "EWS64XL InitSoundEnd" + + ClC + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov DX, CS:BasePort + Inc DX + Mov AL, 0FFh + Out DX, AL + + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load (0 based) +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release (1 based) +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset MMTData+6 + Xor EAX, EAX + +GetStatus1: + Mov CX, [SI] + Add SI, 6 + + Cmp CX, -1 + JE GetStatus2 + + Cmp CX, 1 + JA GetStatus1 + JB GetStatus1 + + Add EAX, [SI+2] + Sub EAX, [SI-4] + Jmp GetStatus1 + +GetStatus2: + Mov SI, Offset StatusLine + ShR EAX, 9 + + ClC + Ret + +EndP GetStatus + Assume DS:Nothing + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Xor AX, AX + StC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 64 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 64 + + DW 5 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/EWSCODEC.ASM b/it/SoundDrivers/EWSCODEC.ASM new file mode 100755 index 0000000..604c014 --- /dev/null +++ b/it/SoundDrivers/EWSCODEC.ASM @@ -0,0 +1,3016 @@ +; +; EWS 64 Codec Driver +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +TRACEENABLED = 0 +CREATENEWLOGFILE = 1 + +include debug.inc + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 +DATAFLAG EQU 200h +ACKFLAG EQU 300h + +PNPSERIALID EQU 98B03C20h +PNPVENDORID EQU 36A8630Eh + +DMASize DW 4096 + +WSSMsg DB "Audiosystem EWS64 XL Codec", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Audiosystem EWS64 XL Codec", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Audiosystem EWS64 XL reinitialised", 0 + +DriverName DB "ITEWSCOD.DRV", 0 + +ALIGN 2 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 37 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 +VolumeTable DB 56, 56 + DB 60h, 60h, 0Ch ; Low Band + DB 40h, 40h, 1Bh ; Med Low Band + DB 40h, 40h, 72h ; Med High Band + DB 60h, 60h, 40h ; High Band + DB 0, 0, 0 ; Echo + DB 0, 2 ; Surround + DB 0, 90h, 4, 7Fh, 22h ; Reverb + DB 0, 90h, 2, 40h, 9, 3, 13h ; Chorus + +IMR DW 0 +OldWSSIRQHandler DD 0 + +; String format, Count, [Data/Port]*Count +; Port = 1 for Control port, 0 for data port. + +SAM9407Reset DW 66 + DW 1BEh, 16Fh, 7Fh, 7Fh, ACKFLAG ; Audio in on + DW 1BEh, 168h, 7Fh, 7Fh, ACKFLAG ; Echo on + DW 1BEh, 16Ch, 7Fh, 7Fh, ACKFLAG ; Reverb on + DW 1BEh, 16Dh, 7Fh, 7Fh, ACKFLAG ; Chorus on + DW 1BEh, 16Bh, 0, 0, ACKFLAG ; Equalizer type + DW 1BEh, 16Eh, 7Fh, 7Fh, ACKFLAG ; Surround on + DW 1BEh, 165h, 7Fh, 7Fh ; Post eff on Audio in + DW 1BEh, 166h, 7Fh, 7Fh ; Post eff on reverb, chorus + DW 1BEh, 133h, 0, 0 ; 2 Speaker + DW 1BEh, 120h, 7Fh, 7Fh ; Stereo input 2 + DW 1BEh, 134h, 0FFh, 0FFh ; Left gain + DW 1BEh, 135h, 0FFh, 0FFh ; Right gain + DW 1BEh, 136h, 0, 0 ; Left pan + DW 1BEh, 137h, 7Fh, 7Fh ; Right pan + DW 1BEh, 107h, 0FFh, 0FFh ; Master volume + +SAM9407EqLBL DW 4 + DW 1BEh, 110h, DATAFLAG, 60h +SAM9407EqLBR DW 4 + DW 1BEh, 114h, DATAFLAG, 60h +SAM9407EqLBF DW 4 + DW 1BEh, 118h, DATAFLAG, 0Ch +SAM9407EqMLBL DW 4 + DW 1BEh, 111h, DATAFLAG, 40h +SAM9407EqMLBR DW 4 + DW 1BEh, 115h, DATAFLAG, 40h +SAM9407EqMLBF DW 4 + DW 1BEh, 119h, DATAFLAG, 1Bh +SAM9407EqMHBL DW 4 + DW 1BEh, 112h, DATAFLAG, 40h +SAM9407EqMHBR DW 4 + DW 1BEh, 116h, DATAFLAG, 40h +SAM9407EqMHBF DW 4 + DW 1BEh, 11Ah, DATAFLAG, 72h +SAM9407EqHBL DW 4 + DW 1BEh, 113h, DATAFLAG, 60h +SAM9407EqHBR DW 4 + DW 1BEh, 117h, DATAFLAG, 60h +SAM9407EqHBF DW 4 + DW 1BEh, 11Bh, DATAFLAG, 0Ch +SAM9407EchoLevel DW 4 + DW 1BEh, 128h, DATAFLAG, 0 +SAM9407EchoTime DW 4 + DW 1BEh, 129h, DATAFLAG, 2Bh +SAM9407EchoFeed DW 4 + DW 1BEh, 12Ah, DATAFLAG, 40h +SAM9407SurroundVolume DW 4 + DW 1BEh, 130h, DATAFLAG, 0 +SAM9407SurroundDelay DW 4 + DW 1BEh, 131h, DATAFLAG, 2 +SAM9407ReverbSend DW 4 + DW 1BEh, 127h, DATAFLAG, 0 +SAM9407ReverbVolume DW 3 + DW 1BEh, 13Ah, DATAFLAG +SAM9407ReverbType DW 4 + DW 1BEh, 169h, DATAFLAG, 4 +SAM9407ReverbTime DW 3 + DW 1BEh, 178h, DATAFLAG +SAM9407ReverbFeedback DW 3 + DW 1BEh, 179h, DATAFLAG +SAM9407ChorusSend DW 4 + DW 1BEh, 124h, DATAFLAG, 0 +SAM9407ChorusVolume DW 3 + DW 1BEh, 13Bh, DATAFLAG +SAM9407ChorusType DW 4 + DW 1BEh, 16Ah, DATAFLAG, 2 +SAM9407ChorusDelay DW 3 + DW 1BEh, 174h, DATAFLAG +SAM9407ChorusFeedback DW 3 + DW 1BEh, 175h, DATAFLAG +SAM9407ChorusRate DW 3 + DW 1BEh, 176h, DATAFLAG +SAM9407ChorusDepth DW 3 + DW 1BEh, 177h, DATAFLAG +SAM9407Mono DW 4 + DW 1BEh, 132h, 7Fh, 0 +SAM9407Stereo DW 4 + DW 1BEh, 132h, 0, 0 + +SAM9407Strings DW Offset SAM9407Reset ;1 + DW Offset SAM9407EqLBL, Offset SAM9407EqLBR + DW Offset SAM9407EqLBF + DW Offset SAM9407EqMLBL, Offset SAM9407EqMLBR + DW Offset SAM9407EqMLBF + DW Offset SAM9407EqMHBL, Offset SAM9407EqMHBR + DW Offset SAM9407EqMHBF + DW Offset SAM9407EqHBL, Offset SAM9407EqHBR + DW Offset SAM9407EqHBF + DW Offset SAM9407EchoLevel ; 14 + DW Offset SAM9407EchoTime + DW Offset SAM9407EchoFeed + DW Offset SAM9407SurroundVolume ; 17 + DW Offset SAM9407SurroundDelay + DW Offset SAM9407ReverbSend ; 19 + DW Offset SAM9407ReverbVolume + DW Offset SAM9407ReverbType + DW Offset SAM9407ReverbTime + DW Offset SAM9407ReverbFeedback ; 23 + DW Offset SAM9407ChorusSend ; 24 + DW Offset SAM9407ChorusVolume + DW Offset SAM9407ChorusType + DW Offset SAM9407ChorusDelay + DW Offset SAM9407ChorusFeedback + DW Offset SAM9407ChorusRate + DW Offset SAM9407ChorusDepth ; 30 + DW Offset SAM9407Mono ; 31 + DW Offset SAM9407Stereo + + +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW Near Ptr SAM9407PortText + DW Near Ptr SAM9407ParametersText + DW Near Ptr SAM9407ParametersBox + + DW Near Ptr EqLBL ; 21 + DW Near Ptr EqLBR + DW Near Ptr EqLBF + + DW Near Ptr EqMLBL + DW Near Ptr EqMLBR + DW Near Ptr EqMLBF + + DW Near Ptr EqMHBL + DW Near Ptr EqMHBR + DW Near Ptr EqMHBF + + DW Near Ptr EqHBL + DW Near Ptr EqHBR + DW Near Ptr EqHBF + + DW Near Ptr EchoLevel + DW Near Ptr EchoTime + DW Near Ptr EchoFeedback + + DW Near Ptr SurroundVolume + DW Near Ptr SurroundDelay + + DW Near Ptr ReverbSend + DW Near Ptr ReverbVolume + DW Near Ptr ReverbType + DW Near Ptr ReverbTime + DW Near Ptr ReverbFeedback + + DW Near Ptr ChorusSend + DW Near Ptr ChorusVolume + DW Near Ptr ChorusType + DW Near Ptr ChorusDelay + DW Near Ptr ChorusFeedback + DW Near Ptr ChorusRate + DW Near Ptr ChorusDepth + + DW 0 + +WSSHeaderLine DW 10 + DB "Audiosystem EWS64 XL Codec Driver", 0 + +SAM9407ParametersText DW 1 + DB 36, 14 + DB 20h + DB "Low Band Left", 13 + DB "Low Band Right", 13 + DB "Low Band Frequency", 13 + DB "Med Low Band Left", 13 + DB "Med Low Band Right", 13 + DB "Med Low Band Frequency", 13 + DB "Med High Band Left", 13 + DB "Med High Band Right", 13 + DB "Med High Band Frequency", 13 + DB "High Band Left", 13 + DB "High Band Right", 13 + DB "High Band Frequency", 13 + DB "Echo Level", 13 + DB "Echo Time", 13 + DB "Echo Feedback", 13 + DB "Surround Volume", 13 + DB "Surround Delay", 13 + DB "Reverb Send", 13 + DB "Reverb Volume", 13 + DB "Reverb Type", 13 + DB "Reverb Time", 13 + DB "Reverb Feedback", 13 + DB "Chorus Send", 13 + DB "Chorus Volume", 13 + DB "Chorus Type", 13 + DB "Chorus Delay", 13 + DB "Chorus Feedback", 13 + DB "Chorus Rate", 13 + DB "Chorus Depth", 13 + DB 0 + +EqLBL DW 14 + DB 60, 14 + DW 0, 127 + DW 9, 2 + DW 13, 22, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBR DW 14 + DB 60, 15 + DW 0, 127 + DW 9, 3 + DW 21, 23, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBF DW 14 + DB 60, 16 + DW 0, 127 + DW 9, 4 + DW 22, 24, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBL DW 14 + DB 60, 17 + DW 0, 127 + DW 9, 5 + DW 23, 25, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBR DW 14 + DB 60, 18 + DW 0, 127 + DW 9, 6 + DW 24, 26, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBF DW 14 + DB 60, 19 + DW 0, 127 + DW 9, 7 + DW 25, 27, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBL DW 14 + DB 60, 20 + DW 0, 127 + DW 9, 8 + DW 26, 28, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBR DW 14 + DB 60, 21 + DW 0, 127 + DW 9, 9 + DW 27, 29, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBF DW 14 + DB 60, 22 + DW 0, 127 + DW 9, 10 + DW 28, 30, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBL DW 14 + DB 60, 23 + DW 0, 127 + DW 9, 11 + DW 29, 31, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBR DW 14 + DB 60, 24 + DW 0, 127 + DW 9, 12 + DW 30, 32, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBF DW 14 + DB 60, 25 + DW 0, 127 + DW 9, 13 + DW 31, 33, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoLevel DW 14 + DB 60, 26 + DW 0, 127 + DW 9, 15 + DW 32, 34, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoTime DW 14 + DB 60, 27 + DW 0, 127 + DW 9, 14 + DW 33, 35, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoFeedback DW 14 + DB 60, 28 + DW 0, 127 + DW 9, 16 + DW 34, 36, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundVolume DW 14 + DB 60, 29 + DW 0, 255 + DW 9, 17 + DW 35, 37, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundDelay DW 14 + DB 60, 30 + DW 0, 127 + DW 9, 18 + DW 36, 38, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbSend DW 14 + DB 60, 31 + DW 0, 127 + DW 9, 19 + DW 37, 39, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbVolume DW 14 + DB 60, 32 + DW 0, 255 + DW 9, 20 + DW 38, 40, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + + +ReverbType DW 14 + DB 60, 33 + DW 0, 7 + DW 9, 21 + DW 39, 41, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbTime DW 14 + DB 60, 34 + DW 0, 127 + DW 9, 22 + DW 40, 42, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbFeedback DW 14 + DB 60, 35 + DW 0, 127 + DW 9, 23 + DW 41, 43, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusSend DW 14 + DB 60, 36 + DW 0, 127 + DW 9, 24 + DW 42, 44, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusVolume DW 14 + DB 60, 37 + DW 0, 255 + DW 9, 25 + DW 43, 45, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusType DW 14 + DB 60, 38 + DW 0, 7 + DW 9, 26 + DW 44, 46, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDelay DW 14 + DB 60, 39 + DW 0, 127 + DW 9, 27 + DW 45, 47, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusFeedback DW 14 + DB 60, 40 + DW 0, 127 + DW 9, 28 + DW 46, 48, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusRate DW 14 + DB 60, 41 + DW 0, 127 + DW 9, 29 + DW 47, 49, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDepth DW 14 + DB 60, 42 + DW 0, 127 + DW 9, 30 + DW 48, 0FFFFh, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SAM9407ParametersBox DW 0 + DB 59, 13, 75, 43 + DB 25 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +SAM9407PortText DW 1 + DB 21, 47 + DB 21h + DB "Audiosystem EWS64 SAM9407 Port ", 0FDh, "Xh, Mixing Rate: ", 0FDh, "D", 0 +MixSpeed DW 48000 +SAM9407Port DW 0 + +DriverText DW 1 + DB 21, 48 + DB 21h + DB "Audiosystem EWS64 XL Codec Driver 1.2 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode", 0 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 21, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + + +; MixingRoutines + + +include dmasirq.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; SAM9407InByte + +Proc SAM9407InByte ; Returns AL + + Push DX + Mov DX, CS:SAM9407Port + Inc DX + +SAM9407InByte1: + In AL, DX + Test AL, AL + JS SAM9407InByte1 + + Dec DX + In AL, DX + Pop DX + + Ret + +EndP SAM9407InByte + +Comment ~ + +; ST97InWord + +Proc SAM9407InWord ; Returns AX + + ClI + + Call SAM9407InByte + Mov AL, AH + + Call SAM9407InByte + XChg AL, AH + + StI + + Ret + +EndP SAM9407InWord + +; SAM9407InDWord + +Proc SAM9407InDWord ; Returns EAX + + ClI + + Call SAM9407InByte + RoR EAX, 8 + + Call SAM9407InByte + RoR EAX, 8 + + Call SAM9407InByte + RoR EAX, 8 + + Call SAM9407InByte + RoR EAX, 8 + + StI + Ret + +EndP SAM9407InDWord + +~ + +; ST97SendByte + +Proc SAM9407SendByte ; DX = port, AL = data + + Push AX + Push DX + Mov DX, CS:SAM9407Port + Inc DX + +SAM9407SendByte1: + In AL, DX + Test AL, 40h + JNZ SAM9407SendByte1 + + Pop DX + Pop AX + + Out DX, AL + + Ret + +EndP SAM9407SendByte + +Comment ~ + +; ST97OutByte + +Proc SAM9407OutByte ; AL = data, AH = command, destroys AX + + ClI + Push DX + + Mov DX, CS:SAM9407Port + Inc DX + + XChg AH, AL + Call SAM9407SendByte + + Dec DX + + Mov AL, AH + Call SAM9407SendByte + + Pop DX + StI + + Ret + +EndP SAM9407OutByte + +; ST97OutWord + +Proc SAM9407OutWord ; AX = data, BL = command, destroys AX + + ClI + Push DX + Push AX + + Mov DX, CS:SAM9407Port + Mov AL, BL + Inc DX + Call SAM9407SendByte + + Pop AX + Dec DX + Call SAM9407SendByte + + Mov AL, AH + Call SAM9407SendByte + + Pop DX + StI + + Ret + +EndP SAM9407OutWord + +; ST97OutDWord + +Proc SAM9407OutDWord ; EAX = data, BL = command + + ClI + Push DX + Push AX + + Mov DX, CS:SAM9407Port + Mov AL, BL + Inc DX + Call SAM9407SendByte + + Pop AX + Dec DX + Call SAM9407SendByte + + ShR EAX, 8 + Call SAM9407SendByte + + ShR EAX, 8 + Call SAM9407SendByte + + ShR EAX, 8 + Call SAM9407SendByte + + Pop DX + StI + + Ret + +EndP SAM9407OutDWord + +~ + +; + +Proc SetSAM9407 ; DI = index. 1 = full reinit. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + LEA SI, [SAM9407Strings+EDI+EDI-2] + Mov SI, [SI] + + LodsW + Mov CX, AX + +SetSAM9407_1: +; AH = 0 = normal data, 1 = command, 2 = param, 3 = ack. + + Mov DX, SAM9407Port + LodsW + + Cmp AH, 2 + JB SetSAM9407_3 + JA SetSAM9407_4 + + Mov AL, [VolumeTable+DI] + Jmp SetSAM9407_2 + +SetSAM9407_4: + Push CX + + Mov CX, 1024 + +SetSAM9407_6: + Call SAM9407InByte + Test AL, AL + LoopNZ SetSAM9407_6 + + Pop CX + + Jmp SetSAM9407_5 + +SetSAM9407_3: + And AH, 1 + Add DL, AH + +SetSAM9407_2: + Call SAM9407SendByte + +SetSAM9407_5: + Dec CX + JNZ SetSAM9407_1 + + Pop DS + PopA + + Ret + +EndP SetSAM9407 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + + Mov AX, 1 + Ret + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 48000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 14 ; 14 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Inc DX + Inc DX + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov AX, 407h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Test AX, AX + JZ PnP_IsolateNextCard + + Mov SAM9407Port, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Trace "Detecting EWS64XL" + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + Trace "EWS64XL Not Found" + + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + Trace "EWS64XL Found" + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 2 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + + Cmp BX, DMABUFFERLENGTH/2 + JB WSSIRQHandler1 + + Mov AX, DMABUFFERLENGTH/2 + +WSSIRQHandler1: + CLD + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Trace "EWS64XL InitSound" + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Trace "EWS64XL Memory Allocated" + + + Call SetIRQ + Call GetTempo + Call SetTempo + + Trace "EWS64XL IRQ Hooked" + + Mov DX, BasePort + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Trace "EWS64XL Volume Settings Received" + + Mov DI, 1 + Call SetSAM9407 + + Trace "EWS64XL SAM9407 InitString finished" + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call StopWSS + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Push AX + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + + Pop DI + + And DI, 1 + Add DI, 31 + Call SetSAM9407 + + Mov DI, 2 +SetStereo2: + Call SetSAM9407 + Inc DI + Cmp DI, 30 + JBE SetStereo2 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + + Pop DS + PopA + + Ret + +EndP UpdateSoundcardVariables + Assume DS:Nothing + +; + +Proc SetVariable Far + + Mov [CS:VolumeTable+DI], AL + Cmp DI, 2 + JB SetVariable1 + + Call SetSAM9407 + Ret + +SetVariable1: + Call UpdateSoundcardVariables + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/EWSCODMX.ASM b/it/SoundDrivers/EWSCODMX.ASM new file mode 100755 index 0000000..12da420 --- /dev/null +++ b/it/SoundDrivers/EWSCODMX.ASM @@ -0,0 +1,2531 @@ +; +; EWS 64 Codec Driver +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +TRACEENABLED = 0 +CREATENEWLOGFILE = 1 + +include debug.inc + +OUTPUTFILTERENABLED EQU 0 +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +DATAFLAG EQU 200h +ACKFLAG EQU 300h + +PNPSERIALID EQU 98B03C20h +PNPVENDORID EQU 36A8630Eh + +DMASize DW 4096 + +WSSMsg DB "Audiosystem EWS64 XL Codec", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Audiosystem EWS64 XL Codec", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Audiosystem EWS64 XL reinitialised", 0 + +DriverName DB "ITEWSCOD.MMX", 0 + +ALIGN 2 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 35 +MixMode DW 0 +MixModeOffset DW 0 +VolumeTable DB 56, 56 + DB 60h, 60h, 0Ch ; Low Band + DB 40h, 40h, 1Bh ; Med Low Band + DB 40h, 40h, 72h ; Med High Band + DB 60h, 60h, 40h ; High Band + DB 0, 0, 0 ; Echo + DB 0, 2 ; Surround + DB 0, 90h, 4, 7Fh, 22h ; Reverb + DB 0, 90h, 2, 40h, 9, 3, 13h ; Chorus + +IMR DW 0 +OldWSSIRQHandler DD 0 + +; String format, Count, [Data/Port]*Count +; Port = 1 for Control port, 0 for data port. + +SAM9407Reset DW 66 + DW 1BEh, 16Fh, 7Fh, 7Fh, ACKFLAG ; Audio in on + DW 1BEh, 168h, 7Fh, 7Fh, ACKFLAG ; Echo on + DW 1BEh, 16Ch, 7Fh, 7Fh, ACKFLAG ; Reverb on + DW 1BEh, 16Dh, 7Fh, 7Fh, ACKFLAG ; Chorus on + DW 1BEh, 16Bh, 0, 0, ACKFLAG ; Equalizer type + DW 1BEh, 16Eh, 7Fh, 7Fh, ACKFLAG ; Surround on + DW 1BEh, 165h, 7Fh, 7Fh ; Post eff on Audio in + DW 1BEh, 166h, 7Fh, 7Fh ; Post eff on reverb, chorus + DW 1BEh, 133h, 0, 0 ; 2 Speaker + DW 1BEh, 120h, 7Fh, 7Fh ; Stereo input 2 + DW 1BEh, 134h, 0FFh, 0FFh ; Left gain + DW 1BEh, 135h, 0FFh, 0FFh ; Right gain + DW 1BEh, 136h, 0, 0 ; Left pan + DW 1BEh, 137h, 7Fh, 7Fh ; Right pan + DW 1BEh, 107h, 0FFh, 0FFh ; Master volume + +SAM9407EqLBL DW 4 + DW 1BEh, 110h, DATAFLAG, 60h +SAM9407EqLBR DW 4 + DW 1BEh, 114h, DATAFLAG, 60h +SAM9407EqLBF DW 4 + DW 1BEh, 118h, DATAFLAG, 0Ch +SAM9407EqMLBL DW 4 + DW 1BEh, 111h, DATAFLAG, 40h +SAM9407EqMLBR DW 4 + DW 1BEh, 115h, DATAFLAG, 40h +SAM9407EqMLBF DW 4 + DW 1BEh, 119h, DATAFLAG, 1Bh +SAM9407EqMHBL DW 4 + DW 1BEh, 112h, DATAFLAG, 40h +SAM9407EqMHBR DW 4 + DW 1BEh, 116h, DATAFLAG, 40h +SAM9407EqMHBF DW 4 + DW 1BEh, 11Ah, DATAFLAG, 72h +SAM9407EqHBL DW 4 + DW 1BEh, 113h, DATAFLAG, 60h +SAM9407EqHBR DW 4 + DW 1BEh, 117h, DATAFLAG, 60h +SAM9407EqHBF DW 4 + DW 1BEh, 11Bh, DATAFLAG, 0Ch +SAM9407EchoLevel DW 4 + DW 1BEh, 128h, DATAFLAG, 0 +SAM9407EchoTime DW 4 + DW 1BEh, 129h, DATAFLAG, 2Bh +SAM9407EchoFeed DW 4 + DW 1BEh, 12Ah, DATAFLAG, 40h +SAM9407SurroundVolume DW 4 + DW 1BEh, 130h, DATAFLAG, 0 +SAM9407SurroundDelay DW 4 + DW 1BEh, 131h, DATAFLAG, 2 +SAM9407ReverbSend DW 4 + DW 1BEh, 127h, DATAFLAG, 0 +SAM9407ReverbVolume DW 3 + DW 1BEh, 13Ah, DATAFLAG +SAM9407ReverbType DW 4 + DW 1BEh, 169h, DATAFLAG, 4 +SAM9407ReverbTime DW 3 + DW 1BEh, 178h, DATAFLAG +SAM9407ReverbFeedback DW 3 + DW 1BEh, 179h, DATAFLAG +SAM9407ChorusSend DW 4 + DW 1BEh, 124h, DATAFLAG, 0 +SAM9407ChorusVolume DW 3 + DW 1BEh, 13Bh, DATAFLAG +SAM9407ChorusType DW 4 + DW 1BEh, 16Ah, DATAFLAG, 2 +SAM9407ChorusDelay DW 3 + DW 1BEh, 174h, DATAFLAG +SAM9407ChorusFeedback DW 3 + DW 1BEh, 175h, DATAFLAG +SAM9407ChorusRate DW 3 + DW 1BEh, 176h, DATAFLAG +SAM9407ChorusDepth DW 3 + DW 1BEh, 177h, DATAFLAG +SAM9407Mono DW 4 + DW 1BEh, 132h, 7Fh, 0 +SAM9407Stereo DW 4 + DW 1BEh, 132h, 0, 0 + +SAM9407Strings DW Offset SAM9407Reset ;1 + DW Offset SAM9407EqLBL, Offset SAM9407EqLBR + DW Offset SAM9407EqLBF + DW Offset SAM9407EqMLBL, Offset SAM9407EqMLBR + DW Offset SAM9407EqMLBF + DW Offset SAM9407EqMHBL, Offset SAM9407EqMHBR + DW Offset SAM9407EqMHBF + DW Offset SAM9407EqHBL, Offset SAM9407EqHBR + DW Offset SAM9407EqHBF + DW Offset SAM9407EchoLevel ; 14 + DW Offset SAM9407EchoTime + DW Offset SAM9407EchoFeed + DW Offset SAM9407SurroundVolume ; 17 + DW Offset SAM9407SurroundDelay + DW Offset SAM9407ReverbSend ; 19 + DW Offset SAM9407ReverbVolume + DW Offset SAM9407ReverbType + DW Offset SAM9407ReverbTime + DW Offset SAM9407ReverbFeedback ; 23 + DW Offset SAM9407ChorusSend ; 24 + DW Offset SAM9407ChorusVolume + DW Offset SAM9407ChorusType + DW Offset SAM9407ChorusDelay + DW Offset SAM9407ChorusFeedback + DW Offset SAM9407ChorusRate + DW Offset SAM9407ChorusDepth ; 30 + DW Offset SAM9407Mono ; 31 + DW Offset SAM9407Stereo + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + +include irq.inc + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr EmptyObject + DW Near Ptr EmptyObject + DW Near Ptr EmptyObject + DW Near Ptr EmptyObject + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW Near Ptr SAM9407PortText + DW Near Ptr SAM9407ParametersText + DW Near Ptr SAM9407ParametersBox + + DW Near Ptr EqLBL ; 21 + DW Near Ptr EqLBR + DW Near Ptr EqLBF + + DW Near Ptr EqMLBL + DW Near Ptr EqMLBR + DW Near Ptr EqMLBF + + DW Near Ptr EqMHBL + DW Near Ptr EqMHBR + DW Near Ptr EqMHBF + + DW Near Ptr EqHBL + DW Near Ptr EqHBR + DW Near Ptr EqHBF + + DW Near Ptr EchoLevel + DW Near Ptr EchoTime + DW Near Ptr EchoFeedback + + DW Near Ptr SurroundVolume + DW Near Ptr SurroundDelay + + DW Near Ptr ReverbSend + DW Near Ptr ReverbVolume + DW Near Ptr ReverbType + DW Near Ptr ReverbTime + DW Near Ptr ReverbFeedback + + DW Near Ptr ChorusSend + DW Near Ptr ChorusVolume + DW Near Ptr ChorusType + DW Near Ptr ChorusDelay + DW Near Ptr ChorusFeedback + DW Near Ptr ChorusRate + DW Near Ptr ChorusDepth + + DW 0 + +WSSHeaderLine DW 10 + DB "Audiosystem EWS64 XL Codec Driver", 0 + +SAM9407ParametersText DW 1 + DB 36, 14 + DB 20h + DB "Low Band Left", 13 + DB "Low Band Right", 13 + DB "Low Band Frequency", 13 + DB "Med Low Band Left", 13 + DB "Med Low Band Right", 13 + DB "Med Low Band Frequency", 13 + DB "Med High Band Left", 13 + DB "Med High Band Right", 13 + DB "Med High Band Frequency", 13 + DB "High Band Left", 13 + DB "High Band Right", 13 + DB "High Band Frequency", 13 + DB "Echo Level", 13 + DB "Echo Time", 13 + DB "Echo Feedback", 13 + DB "Surround Volume", 13 + DB "Surround Delay", 13 + DB "Reverb Send", 13 + DB "Reverb Volume", 13 + DB "Reverb Type", 13 + DB "Reverb Time", 13 + DB "Reverb Feedback", 13 + DB "Chorus Send", 13 + DB "Chorus Volume", 13 + DB "Chorus Type", 13 + DB "Chorus Delay", 13 + DB "Chorus Feedback", 13 + DB "Chorus Rate", 13 + DB "Chorus Depth", 13 + DB 0 + +EqLBL DW 14 + DB 60, 14 + DW 0, 127 + DW 9, 2 + DW 9, 22, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBR DW 14 + DB 60, 15 + DW 0, 127 + DW 9, 3 + DW 21, 23, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBF DW 14 + DB 60, 16 + DW 0, 127 + DW 9, 4 + DW 22, 24, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBL DW 14 + DB 60, 17 + DW 0, 127 + DW 9, 5 + DW 23, 25, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBR DW 14 + DB 60, 18 + DW 0, 127 + DW 9, 6 + DW 24, 26, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBF DW 14 + DB 60, 19 + DW 0, 127 + DW 9, 7 + DW 25, 27, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBL DW 14 + DB 60, 20 + DW 0, 127 + DW 9, 8 + DW 26, 28, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBR DW 14 + DB 60, 21 + DW 0, 127 + DW 9, 9 + DW 27, 29, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBF DW 14 + DB 60, 22 + DW 0, 127 + DW 9, 10 + DW 28, 30, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBL DW 14 + DB 60, 23 + DW 0, 127 + DW 9, 11 + DW 29, 31, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBR DW 14 + DB 60, 24 + DW 0, 127 + DW 9, 12 + DW 30, 32, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBF DW 14 + DB 60, 25 + DW 0, 127 + DW 9, 13 + DW 31, 33, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoLevel DW 14 + DB 60, 26 + DW 0, 127 + DW 9, 15 + DW 32, 34, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoTime DW 14 + DB 60, 27 + DW 0, 127 + DW 9, 14 + DW 33, 35, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoFeedback DW 14 + DB 60, 28 + DW 0, 127 + DW 9, 16 + DW 34, 36, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundVolume DW 14 + DB 60, 29 + DW 0, 255 + DW 9, 17 + DW 35, 37, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundDelay DW 14 + DB 60, 30 + DW 0, 127 + DW 9, 18 + DW 36, 38, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbSend DW 14 + DB 60, 31 + DW 0, 127 + DW 9, 19 + DW 37, 39, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbVolume DW 14 + DB 60, 32 + DW 0, 255 + DW 9, 20 + DW 38, 40, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + + +ReverbType DW 14 + DB 60, 33 + DW 0, 7 + DW 9, 21 + DW 39, 41, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbTime DW 14 + DB 60, 34 + DW 0, 127 + DW 9, 22 + DW 40, 42, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbFeedback DW 14 + DB 60, 35 + DW 0, 127 + DW 9, 23 + DW 41, 43, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusSend DW 14 + DB 60, 36 + DW 0, 127 + DW 9, 24 + DW 42, 44, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusVolume DW 14 + DB 60, 37 + DW 0, 255 + DW 9, 25 + DW 43, 45, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusType DW 14 + DB 60, 38 + DW 0, 7 + DW 9, 26 + DW 44, 46, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDelay DW 14 + DB 60, 39 + DW 0, 127 + DW 9, 27 + DW 45, 47, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusFeedback DW 14 + DB 60, 40 + DW 0, 127 + DW 9, 28 + DW 46, 48, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusRate DW 14 + DB 60, 41 + DW 0, 127 + DW 9, 29 + DW 47, 49, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDepth DW 14 + DB 60, 42 + DW 0, 127 + DW 9, 30 + DW 48, 0FFFFh, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SAM9407ParametersBox DW 0 + DB 59, 13, 75, 43 + DB 25 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +SAM9407PortText DW 1 + DB 21, 47 + DB 21h + DB "Audiosystem EWS64 SAM9407 Port ", 0FDh, "Xh, Mixing Rate: ", 0FDh, "D", 0 +MixSpeed DW 48000 +SAM9407Port DW 0 + +DriverText DW 1 + DB 21, 48 + DB 21h + DB "Audiosystem EWS64 XL Codec Driver 1.2 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode", 0 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 21, 32, 23, 8 + DB 0 + DB " MMX, Non-interpolated", 0 + +MixModeButton2 DW 2 + DW 6 + DW 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 24, 32, 26, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 27, 32, 29, 8 + DB 0 + DB " MMX, Volume Ramp", 0 + +MixModeButton4 DW 2 + DW 8, 21, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 30, 32, 32, 8 + DB 0 + DB " MMX, Filtered", 0 + +LongMixSpeed DD 0 + +; MixingRoutines + +include dmasirq.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; SAM9407InByte + +Proc SAM9407InByte ; Returns AL + + Push DX + Mov DX, CS:SAM9407Port + Inc DX + +SAM9407InByte1: + In AL, DX + Test AL, AL + JS SAM9407InByte1 + + Dec DX + In AL, DX + Pop DX + + Ret + +EndP SAM9407InByte + +Comment ~ + +; ST97InWord + +Proc SAM9407InWord ; Returns AX + + ClI + + Call SAM9407InByte + Mov AL, AH + + Call SAM9407InByte + XChg AL, AH + + StI + + Ret + +EndP SAM9407InWord + +; SAM9407InDWord + +Proc SAM9407InDWord ; Returns EAX + + ClI + + Call SAM9407InByte + RoR EAX, 8 + + Call SAM9407InByte + RoR EAX, 8 + + Call SAM9407InByte + RoR EAX, 8 + + Call SAM9407InByte + RoR EAX, 8 + + StI + Ret + +EndP SAM9407InDWord + +~ + +; ST97SendByte + +Proc SAM9407SendByte ; DX = port, AL = data + + Push AX + Push DX + Mov DX, CS:SAM9407Port + Inc DX + +SAM9407SendByte1: + In AL, DX + Test AL, 40h + JNZ SAM9407SendByte1 + + Pop DX + Pop AX + + Out DX, AL + + Ret + +EndP SAM9407SendByte + +Comment ~ + +; ST97OutByte + +Proc SAM9407OutByte ; AL = data, AH = command, destroys AX + + ClI + Push DX + + Mov DX, CS:SAM9407Port + Inc DX + + XChg AH, AL + Call SAM9407SendByte + + Dec DX + + Mov AL, AH + Call SAM9407SendByte + + Pop DX + StI + + Ret + +EndP SAM9407OutByte + +; ST97OutWord + +Proc SAM9407OutWord ; AX = data, BL = command, destroys AX + + ClI + Push DX + Push AX + + Mov DX, CS:SAM9407Port + Mov AL, BL + Inc DX + Call SAM9407SendByte + + Pop AX + Dec DX + Call SAM9407SendByte + + Mov AL, AH + Call SAM9407SendByte + + Pop DX + StI + + Ret + +EndP SAM9407OutWord + +; ST97OutDWord + +Proc SAM9407OutDWord ; EAX = data, BL = command + + ClI + Push DX + Push AX + + Mov DX, CS:SAM9407Port + Mov AL, BL + Inc DX + Call SAM9407SendByte + + Pop AX + Dec DX + Call SAM9407SendByte + + ShR EAX, 8 + Call SAM9407SendByte + + ShR EAX, 8 + Call SAM9407SendByte + + ShR EAX, 8 + Call SAM9407SendByte + + Pop DX + StI + + Ret + +EndP SAM9407OutDWord + +~ + +; + +Proc SetSAM9407 ; DI = index. 1 = full reinit. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + LEA SI, [SAM9407Strings+EDI+EDI-2] + Mov SI, [SI] + + LodsW + Mov CX, AX + +SetSAM9407_1: +; AH = 0 = normal data, 1 = command, 2 = param, 3 = ack. + + Mov DX, SAM9407Port + LodsW + + Cmp AH, 2 + JB SetSAM9407_3 + JA SetSAM9407_4 + + Mov AL, [VolumeTable+DI] + Jmp SetSAM9407_2 + +SetSAM9407_4: + Push CX + + Mov CX, 1024 + +SetSAM9407_6: + Call SAM9407InByte + Test AL, AL + LoopNZ SetSAM9407_6 + + Pop CX + + Jmp SetSAM9407_5 + +SetSAM9407_3: + And AH, 1 + Add DL, AH + +SetSAM9407_2: + Call SAM9407SendByte + +SetSAM9407_5: + Dec CX + JNZ SetSAM9407_1 + + Pop DS + PopA + + Ret + +EndP SetSAM9407 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 48000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 14 ; 14 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov Word Ptr LongMixSpeed, BX + Mov WSSMixConst, DH + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Inc DX + Inc DX + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc DetectMMX + + Trace "Detecting MMX" + + PushFD + Pop EAX + Mov EBX, EAX + Xor EAX, 00200000h + Push EAX + PopFD + PushFD + Pop EAX + Cmp EAX, EBX + JZ DetectMMXFail + + Mov EAX, 1 + DB 0Fh, 0A2h ; CPUID + Test EDX, 800000h + JZ DetectMMXFail + + Trace "MMX Detected" + + ClC + Ret + +DetectMMXFail: + Trace "MMX not detected" + + StC + Ret + +EndP DetectMMX + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov AX, 407h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Test AX, AX + JZ PnP_IsolateNextCard + + Mov SAM9407Port, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Call DetectMMX + JNC DetectCard1 + + Ret + +DetectCard1: + Trace "Detecting EWS64XL" + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + Trace "EWS64XL Not Found" + + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + Trace "EWS64XL Found" + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +include mmxmsam.inc + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 2 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + + Cmp BX, DMABUFFERLENGTH/2 + JB WSSIRQHandler1 + + Mov AX, DMABUFFERLENGTH/2 + +WSSIRQHandler1: + CLD + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Trace "EWS64XL InitSound" + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 5 + (DMABUFFERLENGTH*2)/16 + Mov BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + + Trace "EWS64XL Memory Allocated" + + Call SetIRQ + Call GetTempo + Call SetTempo + + Trace "EWS64XL IRQ Hooked" + + Mov DX, BasePort + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Trace "EWS64XL Volume Settings Received" + + Mov DI, 1 + Call SetSAM9407 + + Trace "EWS64XL SAM9407 InitString finished" + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call StopWSS + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Push AX + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + + Pop DI + + And DI, 1 + Add DI, 31 + Call SetSAM9407 + + Mov DI, 2 +SetStereo2: + Call SetSAM9407 + Inc DI + Cmp DI, 30 + JBE SetStereo2 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + + Pop DS + PopA + + Ret + +EndP UpdateSoundcardVariables + Assume DS:Nothing + +; + +Proc SetVariable Far + + Mov [CS:VolumeTable+DI], AL + Cmp DI, 2 + JB SetVariable1 + + Call SetSAM9407 + Ret + +SetVariable1: + Call UpdateSoundcardVariables + Ret + +EndP SetVariable + +; + +Proc UARTOut + + Push CX + Push DX + Mov DX, CS:SAM9407Port + + Push AX + Xor CX, CX + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + LoopNZ UARTOut1 + + Pop AX + JNZ UARTOutEnd + + Dec DX + Out DX, AL + +UARTOutEnd: + Pop DX + Pop CX + + Ret + +EndP UARTOut + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 +DriverFlags DW 3 + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/EXECOM.COM b/it/SoundDrivers/EXECOM.COM new file mode 100755 index 0000000000000000000000000000000000000000..dc9924543eea3e59ec6e2b36cf473010fdefd41e GIT binary patch literal 1248 zcmdT?-%Aux6drf?qHZW;AU>3w4T)rPTeB>6-PLT%#Wd*$Nn$YWUUg`k*=Fvz`DW}( zG!Q-ZScEURJuJ+_x(`|uk<|8}5Ya=W_98<;1z8l*xwDn{&>zsi%(?e`-#zDi-<_Xx zQ$psJ`E>PACIk~T^Eb)Hz9Poz%#`;{5RK?f#+oJ=`H%h_n8~HK-Wy}RPT&k z;cTKaxq;}6{X8eM=Q~Kjr;}{S+701uJuzQdk=Ys{|Bh!p*>Zc*{5;=4W{L1+I{m~m zjUU(abk=<}+(3FS7=xYZa1#-XGZ+tJ>`8}PFdV~eJH`;kHX^XHt2~q#`^?%yB3(Am;LOnpZJ^G2+lt%Ol|whPPctZxy%<u-%Td)}NrSs z2*>_%{|qC-geXf12t)^>&KStT!88gYz7nJ3I%xE=A!(8_iYr--i%e1#q;-PM#P}s% z2}Mc@O*qN8nxLT5(Q&GVpz6qoP90F862oo~MB(`5&R~(_+zu?uR25`V8>O%} z&~>U8QmP>*0PRsH@J#c;o_Zv2N=C(rf7y}JP>bW)rsH@RRrA7)fdc?tYI0JOM#mWJ zjn_kC%aInq8&t Data read port + In AL, DX + Add DL, 0Ch-0Ah + + Ret + +EndP ESSIn + +; + +Proc UARTOut ; AL = out + + Push DX + Push AX + + Mov DX, CS:MIDIPort + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + JNZ UARTOut1 + + Pop AX + Dec DX + Out DX, AL + + Pop DX + Ret + +EndP UARTOut + +; + +Proc UARTIn ; returns AL + + Push DX + + Mov DX, CS:MIDIPort + Inc DX + +UARTIn1: + In AL, DX + Test AL, 80h + JNZ UARTIn1 + + Dec DX + In AL, DX + + Pop DX + Ret + +EndP UARTIn + +; + +Proc ESSReadRegister ; AH = register to read. + ; DX = 2xCh + ; returns AL + + Mov AL, 0C0h + Call ESSOut + Mov AL, AH + Call ESSOut + Call ESSIn + + Ret + +EndP ESSReadRegister + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Mov ConfigPort, AX + + Mov AX, 107h ; Audio device + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + Mov MIDIPort, AX + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, CS:MIDIPort + Inc DX + Mov AL, 0FFh + Out DX, AL + + Mov DX, CS:BasePort + Add DL, 6 + Mov AL, 3 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Call UARTIn + Mov BL, [MIDIBufferTail] + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [ConfigPort] + Add DL, 6 + In AL, DX + Test AL, 8 + JZ ESSNoMIDI + + Push AX + Call CheckMIDI + Pop AX + +ESSNoMIDI: + Test AL, 1 + JZ ESSIRQEnd + + Mov DX, [BasePort] + Add DL, 0Eh + In AL, DX + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB ESSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +ESSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE ESSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +ESSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB ESSIRQHandler6 + JE ESSIRQHFilter + + Cmp CS:Stereo, 0 + JE ESSIRQ3QFilterMono + +ESSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +ESSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +ESSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +ESSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilter: + Cmp CS:Stereo, 0 + JE ESSIRQHFilterMono + +ESSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +ESSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +ESSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +ESSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL ESSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG ESSIRQHandlerClip2 + +ESSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ ESSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + +ESSIRQEnd: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Pop ES + Pop DS + PopAD + IRet + +ESSIRQHandlerClip1: + Mov AX, 8000h + Jmp ESSIRQHandler7 + +ESSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp ESSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo3 + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc GetESSMixConst + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetESSMixConst1 + + Mov CX, 22050 + Cmp AX, CX + JB GetESSMixConst1 + + Mov CX, 56821 + Cmp AX, CX + JA GetESSMixConst1 + + Mov CX, AX + +GetESSMixConst1: ; CX = mixspeed. + Mov DX, 0Ch + Mov AX, 236Ch ; DX:AX = 795.5kHz + Div CX + + Mov BX, AX + Neg AL + Mov ESSMixConst, AL + + Mov DX, 0Ch + Mov AX, 236Ch + Div BX + Mov MixSpeed, AX + + Pop DS + PopA + Ret + +EndP GetESSMixConst + +; + +Proc StartESS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Call ResetDSP + Mov DX, BasePort + Add DL, 0Ch + +; Extended Functions + + Mov AL, 0C6h + Call ESSOut + +; Autoinit DMA + + Mov AL, 0B8h + Call ESSOut + Mov AL, 4 + Call ESSOut + +; Stereo/Mono select + + Mov AH, 0A8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0A8h + Call ESSOut + Mov AL, AH + And AL, Not 3 + Or AL, 2 + Cmp Stereo, 0 + JE StartESS1 + + Xor AL, 3 + +StartESS1: + Call ESSOut + +; DMA mode + + Mov AL, 0B9h + Call ESSOut + Mov AL, 2 + Call ESSOut + +; Mixspeed + + Mov AL, 0A1h + Call ESSOut + Mov AL, ESSMixConst + Call ESSOut + +; Filter clock divider + Mov AL, 0A2h + Call ESSOut + + Mov AL, 0FEh + Call ESSOut + +; DMA counter + Mov CX, DMASize + Neg CX + + Mov AL, 0A4h + Call ESSOut + Mov AL, CL + Call ESSOut + Mov AL, 0A5h + Call ESSOut + Mov AL, CH + Call ESSOut + +; Initialise DAC + Mov AL, 0B6h + Call ESSOut + Mov AL, 0 + Call ESSOut + +; Configure DACs + + Mov AL, 0B7h + Call ESSOut + Mov AL, 71h + Call ESSOut + + Mov AL, 0B7h + Call ESSOut + + Mov AL, 0BCh + Cmp Stereo, 0 + JNE StartESS2 + + Mov AL, 0F4h + +StartESS2: + Call ESSOut + +; IRQ configuration + Mov AL, 0B1h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; DMA configuration + Mov AL, 0B2h + Call ESSOut + Mov AL, 50h + Call ESSOut + +; Enable voice + Mov AL, 0D1h + Call ESSOut + +; Start transfer + Mov AH, 0B8h + Call ESSReadRegister + Mov AH, AL + Mov AL, 0B8h + Call ESSOut + Mov AL, AH + Or AL, 1 + Call ESSOut + +; Init UART + Mov DX, MIDIPort + Inc DX + Mov AL, 3Fh ; Intelligent mode. + Out DX, AL + +; Enable MIDI IRQ + Mov DX, BasePort + Add DL, 4 + Mov AX, 4064h + Out DX, AX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartESS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + And AX, 0FF0h + ShR AH, 1 + ShR AL, 5 + Mov Word Ptr [VolumeTable], AX + + Call GetESSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetDSP + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call ResetDSP + Call StartESS + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset ESSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 22h + Out DX, AL + Mov AH, [VolumeTable] + ShL AH, 4 + Or AH, [VolumeTable+1] + ShL AH, 1 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/GUS.INC b/it/SoundDrivers/GUS.INC new file mode 100755 index 0000000..4770d30 --- /dev/null +++ b/it/SoundDrivers/GUS.INC @@ -0,0 +1,2316 @@ + + .386P + Jumps + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +;************************** + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;************** Local variables **************** + +SLAVECHANNELSIZE EQU 128 + +GUSReinitMsg DB "Gravis UltraSound reinitialised", 0 + +GUSID DB "Gravis UltraSound detected", 13 + DB "Port ", 0FDh, "Xh, ", 0FDh, "Dk Memory", 0 + +GUSID2 DB "Gravis UltraSound detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, ", 0FDh, "Dk RAM", 0 + +GUSFreeMsg DB "FreeGUS ", 0FDh, "Dk", 0 + +IFDEF RIC + +GUSFreeMsg2 DB "FreeGUS ", 0FDh, "Dk", 13, 13 + DB "GUSInit ", 0FDh, "D", 0 + + IFDEF RAMP + DriverName DB "ITGUS.DRV", 0 + ELSE + DriverName DB "ITGUS2.DRV", 0 + ENDIF + +ENDIF + +ULTRASndString DB "ULTRASND" + +GUSMixTable Label Word + + DW 44100, 41160, 38588, 36318, 34300, 32495, 30870, 29400, 28064 + DW 26844, 25725, 24696, 23746, 22867, 22050, 21290, 20580, 19916 + DW 19294 + +GUSVolumeTable Label Word + DW 04000h, 07FF0h, 08FF0h, 09800h, 09FF0h, 0A400h, 0A800h, 0AC00h + DW 0AFF0h, 0B200h, 0B400h, 0B600h, 0B800h, 0BA00h, 0BC00h, 0BE00h + DW 0BFF0h, 0C100h, 0C200h, 0C300h, 0C400h, 0C500h, 0C600h, 0C700h + DW 0C800h, 0C900h, 0CA00h, 0CB00h, 0CC00h, 0CD00h, 0CE00h, 0CF00h + + DW 0CFF0h, 0D080h, 0D100h, 0D180h, 0D200h, 0D280h, 0D300h, 0D380h + DW 0D400h, 0D480h, 0D500h, 0D580h, 0D600h, 0D680h, 0D700h, 0D780h + DW 0D800h, 0D880h, 0D900h, 0D980h, 0DA00h, 0DA80h, 0DB00h, 0DB80h + DW 0DC00h, 0DC80h, 0DD00h, 0DD80h, 0DE00h, 0DE80h, 0DF00h, 0DF80h + + DW 0DFF0h, 0E040h, 0E080h, 0E0C0h, 0E100h, 0E140h, 0E180h, 0E1C0h + DW 0E200h, 0E240h, 0E280h, 0E2C0h, 0E300h, 0E340h, 0E380h, 0E3C0h + DW 0E400h, 0E440h, 0E480h, 0E4C0h, 0E500h, 0E540h, 0E580h, 0E5C0h + DW 0E600h, 0E640h, 0E680h, 0E6C0h, 0E700h, 0E740h, 0E780h, 0E7C0h + + DW 0E800h, 0E840h, 0E880h, 0E8C0h, 0E900h, 0E940h, 0E980h, 0E9C0h + DW 0EA00h, 0EA40h, 0EA80h, 0EAC0h, 0EB00h, 0EB40h, 0EB80h, 0EBC0h + DW 0EC00h, 0EC40h, 0EC80h, 0ECC0h, 0ED00h, 0ED40h, 0ED80h, 0EDC0h + DW 0EE00h, 0EE40h, 0EE80h, 0EEC0h, 0EF00h, 0EF40h, 0EF80h, 0EFC0h + + DW 0EFF0h + +ALIGN 4 + +GUSDataTable DD 100 Dup (0FFFFFFFFh) +GUSMemory DW 0 ; kb of memory on GUS +GUSRegisterSelect DW 0 +GUSVoiceSelect DW 0 +GUSUpdateTimer DW 0 +GUSUpdateCount DW 0 +GUSMemoryFree DD 0 +MixSpeed DW 0 +OldIRQHandler DD 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 8 + +Convert16To8Bit DB 0 + DB 0 +Compress DB 0 + DB 0 + +IFDEF RIC + ShowReinit DB 0 + DB 0 + UsedChannels DW ? +ENDIF + +Stereo DB 0 +GUSUpdateFlag DB 0 + +MIDIIRQ DW 0FFFFh +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 +MIDIOldIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +IMR DW 0 + +; + +GUSScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr GravisHeaderLine + + DW SampleText ; 4 + + DW ConvertSampleText + DW ConvertDisabledButton ; 6 + DW ConvertEnabledButton + + DW SampleSizeText ; 8 + DW SampleSize0Button ; 9 + DW SampleSize1Button + DW SampleSize2Button + + +IFDEF RIC + DW ReinitText ; 12 + DW ReinitButton0 + DW ReinitButton1 + DW ReinitButton2 + +ENDIF + + DW DriverText + + DW 0 + +GravisHeaderLine DW 10 + DB "Gravis UltraSound Driver", 0 + +DriverText DW 1 + DB 30, 48 + DB 21h + DB "Gravis UltraSound Driver 1.3 for Impulse Tracker", 0 + +SampleText DW 1 + DB 3, 13 + DB 20h + DB "Sample resizing options", 0 + +ConvertSampleText DW 1 + DB 5, 15 + DB 20h + DB "Reduce 16 bit samples to 8 bit", 0 + +ConvertDisabledButton DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetConvert +DriverSegment1 DW 0 + DW 0 + DW Offset SetConvert +DriverSegment2 DW 0 + DB 7, 17, 20, 19, 8 + DB 0 + DB " Disabled", 0 + +ConvertEnabledButton DW 2 + DW 6, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetConvert +DriverSegment3 DW 0 + DW 1 + DW Offset SetConvert +DriverSegment4 DW 0 + DB 7, 20, 20, 22, 8 + DB 0 + DB " Enabled", 0 + +SampleSizeText DW 1 + DB 5, 24 + DB 20h + DB "Sample size", 0 + +SampleSize0Button DW 2 + DW 7, 10, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment5 DW 0 + DW 0 + DW Offset SetCompress +DriverSegment6 DW 0 + DB 7, 26, 20, 28, 8 + DB 0 + DB " Original", 0 + +SampleSize1Button DW 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment7 DW 0 + DW 1 + DW Offset SetCompress +DriverSegment8 DW 0 + DB 7, 29, 20, 31, 8 + DB 0 + DB " Half", 0 + +IFDEF RIC + + SampleSize2Button DW 2 + DW 10, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress + DriverSegment9 DW 0 + DW 2 + DW Offset SetCompress + DriverSegment10 DW 0 + DB 7, 32, 20, 34, 8 + DB 0 + DB " Quarter", 0 + + ReinitText DW 1 + DB 3, 36 + DB 20h + DB "Show channel reinitialisation", 0 + + ReinitButton0 DW 2 + DW 11, 14, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetReinit + DriverSegment11 DW 0 + DW 0 + DW Offset SetReinit + DriverSegment12 DW 0 + DB 7, 38, 21, 40, 8 + DB 0 + DB " Disabled", 0 + + ReinitButton1 DW 2 + DW 13, 15, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetReinit + DriverSegment13 DW 0 + DW 1 + DW Offset SetReinit + DriverSegment14 DW 0 + DB 7, 41, 21, 43, 8 + DB 0 + DB " Channels", 0 + + ReinitButton2 DW 2 + DW 14, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetReinit + DriverSegment15 DW 0 + DW 2 + DW Offset SetReinit + DriverSegment16 DW 0 + DB 7, 44, 21, 46, 8 + DB 0 + DB " Frequency", 0 + +ELSE + + SampleSize2Button DW 2 + DW 10, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress + DriverSegment9 DW 0 + DW 2 + DW Offset SetCompress + DriverSegment10 DW 0 + DB 7, 32, 20, 34, 8 + DB 0 + DB " Quarter", 0 + + +ENDIF + + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +RelocationTable Label + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + +IFDEF RIC + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW Offset DriverSegment15, Offset DriverSegment16 +ENDIF + DW 0FFFFh + +;*********** Local functions ******************* +; +; GUSDelay - produces delay between GUS commands +; TestGUS - Checks for the presence of a GUS by detecting amount of memory. +; LoadGUSSample - Loads a byte to GUS, EDI = position in memory, AL = value +; LoadGUSSamples - Loads ECX bytes from DS:SI to EDI +; +;*********************************************** + +Proc GUSDelay + + Push AX + Push DX + + Mov DX, 300h + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Pop DX + Pop AX + + Ret + +EndP GUSDelay + +; + +Proc ResetGUS ; AX = baseport. + + Push AX + Push DX + + Mov DX, AX + Add DX, 103h ; Select register + + Mov AL, 4Ch ; Reset global register + Out DX, AL + + Add DL, 2 ; 8 bit data + Xor AL, AL + Out DX, AL ; Reset GUS! + + Call GUSDelay + Call GUSDelay + + Mov AL, 1 + Out DX, AL + + Call GUSDelay + Call GUSDelay + + Pop DX + Pop AX + + Ret + +EndP ResetGUS + +; + +Proc TestGUS + + Push AX + + Call ResetGUS + + Mov GUSMemory, 0 + + Mov DX, AX + Add DX, 103h ; DX = Select Register + + Mov CX, 4 ; Max amount is 1MB of memory + Xor BL, BL ; Start with first 256k pool + +TestGUS1: + Mov AL, 44h ; GUS DRAM High, 8 bit + Out DX, AL + + Add DL, 2 + Mov AL, BL + Out DX, AL + + Sub DL, 2 ; DX = Select Register + + Mov AL, 43h ; GUS DRAM Low, 16 bit + Out DX, AL + + Inc DX ; DX = Baseport+104h + Xor AX, AX + Out DX, AX ; Address 0 + + Add DL, 3 ; DX = Baseport+107h (DRAM I/O) + Mov AL, 55h + Out DX, AL ; Write value 055h + + Sub DL, 3 ; DX = Baseport+104h + Mov AX, 1 + Out DX, AX ; Address 1 + + Add DL, 3 ; DX = Baseport+107h + Mov AL, 0AAh + Out DX, AL ; Write value 0AAh + + Sub DL, 3 ; DX = Baseport+104h + Mov AX, 2 + Out DX, AX ; Address 2 + + Add DL, 3 ; DX = Baseport+107h + Mov AL, 0 + Out DX, AL ; Write value + + Sub DL, 3 ; DX = Baseport+104h + Xor AX, AX + Out DX, AX ; Address 0 + + Add DL, 3 ; DX = Baseport+107h + In AL, DX ; Read value.. should be 055h + Cmp AL, 55h + JNE TestGUS2 + + Sub DL, 3 ; DX = Baseport+104h + Mov AX, 1 + Out DX, AX ; Address 1 + + Add DL, 3 ; DX = Baseport+107h + In AL, DX ; Read value.. should be 0AAh + Cmp AL, 0AAh + JNE TestGUS2 + + Sub DL, 3 ; DX = Baseport+104h + Mov AX, 2 + Out DX, AX ; Address 2 + + Add DL, 3 ; DX = Baseport+107h + In AL, DX ; Read value.. + Cmp AL, 0 + JNE TestGUS2 + + Sub DL, 4 ; DX = Baseport+103h + + Add GUSMemory, 256 ; Another 256k! + + Add BL, 4 ; Next memory chunk + Loop TestGUS1 + + +TestGUS2: + Pop AX + + Cmp GUSMemory, 0 + JNE TestGUS3 + + StC + Ret + +TestGUS3: + ClC + Ret + +EndP TestGUS + +; + +Proc LoadGUSSample ; EDI = position, AL = value + + Push EAX + + Mov DX, CS:GUSRegisterSelect + Mov AL, 44h + Out DX, AL + + Add DL, 2 + Mov EAX, EDI + ShR EAX, 16 + Out DX, AL + Sub DL, 2 ; Select register again. + + Mov AL, 43h ; Address Low, 16 bit + Out DX, AL + Inc DX ; DX = 3x4h + + Mov AX, DI ; Memory location high + Out DX, AX ; Memory location done. + + Add DL, 3 + + Pop EAX + + Out DX, AL + Sub DL, 3 + + Inc EDI + + Ret + +EndP LoadGUSSample + +; + +Proc LoadGUSSamples ; Given DS:SI, EDI = pos, ECX = count + ; EBP = step value. + +LoadGUSSamples1: + Mov DX, CS:GUSRegisterSelect + Mov AL, 44h + Out DX, AL + + Add DL, 2 + Mov EAX, EDI + ShR EAX, 16 + Out DX, AL + Sub DL, 2 ; Select register again. + + Mov AL, 43h ; Address Low, 16 bit + Out DX, AL + Inc DX ; DX = 3x4h + +LoadGUSSamples2: + Mov AX, DI ; Memory location high + Out DX, AX ; Memory location done. + + Add DL, 3 + + Mov AL, [SI] + Add SI, BP + JC LoadGUSSamples4 + +LoadGUSSamples3: + Out DX, AL + Sub DL, 3 + + Inc DI + JZ LoadGUSSamples5 + + Dec ECX + JNZ LoadGUSSamples2 + Ret + +LoadGUSSamples4: + Add ESI, 10000h + Call UpdateSampleLocation + Jmp LoadGUSSamples3 + +LoadGUSSamples5: + Add EDI, 10000h + LoopD LoadGUSSamples1 + Ret + +EndP LoadGUSSamples + +; + +Proc Load16GUSSamples ; Given DS:SI, EDI = pos, ECX = count + ; EBP = step value. + + Add BP, BP + Dec BP + Mov BX, 1 + Xor BP, BX + Xor BX, BP + +Load16GUSSamples1: + Mov DX, CS:GUSRegisterSelect + Mov AL, 44h + Out DX, AL + + Add DL, 2 + Mov EAX, EDI + ShR EAX, 16 + Out DX, AL + Sub DL, 2 ; Select register again. + + Mov AL, 43h ; Address Low, 16 bit + Out DX, AL + Inc DX ; DX = 3x4h + +Load16GUSSamples2: + Mov AX, DI ; Memory location high + Out DX, AX ; Memory location done. + + Add DL, 3 + + Xor BX, BP + Mov AL, [SI] + Add SI, BX + JC Load16GUSSamples4 + +Load16GUSSamples3: + Out DX, AL + Sub DL, 3 + + Inc DI + JZ Load16GUSSamples5 + + LoopD Load16GUSSamples2 + Ret + +Load16GUSSamples4: + Add ESI, 10000h + Call UpdateSampleLocation + Jmp Load16GUSSamples3 + +Load16GUSSamples5: + Add EDI, 10000h + LoopD Load16GUSSamples1 + Ret + +EndP Load16GUSSamples + +;*********** Public functions ****************** + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectGUS Far + + Push CS + Pop DS + Assume DS:Driver + + Cmp BasePort, 0FFFFh + JE DetectGUS1 + + Mov AX, BasePort + + Cmp AX, 210h + JB DetectCardError + Cmp AX, 280h + JA DetectCardError + + Call TestGUS + JNC DetectGUS3 + Jmp DetectCardError + +DetectGUS1: + Mov AX, 210h + +DetectGUS2: + Call TestGUS + JNC DetectGUS3 + + Add AL, 10h + Cmp AL, 60h + JBE DetectGUS2 + +DetectCardError: + StC + Ret + +DetectGUS3: + Mov BasePort, AX + Add AX, 102h + Mov GUSVoiceSelect, AX + Inc AX + Mov GUSRegisterSelect, AX + +Comment ~ + + ; If Windows *AND* IRQ = 0FFFFh, then grab from ULTRASND variable + + Mov SI, Offset ULTRASNDString + Mov CX, 8 + Call GetEnvironment ; Returns ES:DI, Carry if error + JC DetectCardOK + + Mov CX, 3 ; Find 3 commas first. + ; Eg. skip baseport + 2 DMAs + +DetectCard1: + Mov AL, [ES:DI] + Inc DI + + Cmp AL, ',' + JNE DetectCard1 + Loop DetectCard1 + + ; GUS IRQ.. + Xor DX, DX + +DetectCardIRQ1_1: + Mov AL, [ES:DI] + Inc DI + Cmp AL, ',' + JE DetectCardIRQ1_2 + + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCardIRQ1_1 + +DetectCardIRQ1_2: ; DX = IRQ to use. + Cmp DX, 15 + JA DetectCardError + + Mov AX, 1600h + Int 2Fh ; Windows Detect. + + Test AL, 7Fh + JZ DetectCardIRQ2_1 + + Mov AX, IRQ + Cmp AX, -1 + JNE DetectCardIRQ2_2 + Mov IRQ, DX + Mov MIDIIRQ, DX + Jmp DetectCardOK + +DetectCardIRQ2_2: + Mov DX, AX + +DetectCardIRQ2_1: ; No Windows. + Mov MIDIIRQ, DX + +DetectCardOK: + +~ + + Mov EAX, 'Jeff' + ClC + Ret + +EndP DetectGUS + Assume DS:Nothing + +; + +Proc GUSIRQHandler ; IRQ Handler has to + ; 1) Update GUS registers + ; 2) Update song position + Push AX + Push DS + + Mov AX, GUSUpdateTimer + Add GUSUpdateCount, AX + JC GUSIRQHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp GUSIRQHandler2 + +GUSIRQHandler1: + PushF + Call [OldIRQHandler] + +GUSIRQHandler2: + Xor GUSUpdateFlag, 1 + JZ GUSIRQHandlerEnd + + PushAD + Push ES + + ClD + + Call SaveEMSPageFrame + Call Update ; Returns DS:SI, CX + Call SetGUSRegisters + Call RestoreEMSPageFrame + + Pop ES + PopAD + +GUSIRQHandlerEnd: + Pop DS + Pop AX + IRet + +EndP GUSIRQHandler + +; + +Comment ~ + +Proc CheckMIDI + + Push AX BX DX DS + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + Inc DH + +CheckMIDIAgain: + In AL, DX + Test AL, 1 + JZ CheckMIDI1 + + Inc DX + In AL, DX + Dec DX + + Cmp AL, 0F0h +; JAE CheckMIDIAgain + JAE CheckMIDI1 + + Mov BL, [MIDIBufferTail] + Inc BL + Cmp BL, [MIDIBufferHead] + JE CheckMIDI1 +; JE CheckMIDIAgain + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL +; Jmp CheckMIDIAgain + +CheckMIDI1: + Pop DS DX BX AX + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc GUSMIDIIRQHandler + + Push AX BX DX DS + + Push CS + Pop DS + Assume DS:Driver + + Call CheckMIDI + + Mov AL, 20h + + Cmp MIDIIRQ, 8 + JB GUSMIDIIRQHandler1 + + Out 0A0h, AL + +GUSMIDIIRQHandler1: + Out 20h, AL + + Pop DS DX BX AX + IRet + +EndP GUSMIDIIRQHandler + Assume DS:Nothing + +~ + +; + +Proc GUSIRQOnlyHandler + + PushAD + Push DS + Push ES + + Mov AL, 20h + + Cmp CS:IRQ, 8 + JB GUSIRQOnlyHandler1 + + Out 0A0h, AL + +GUSIRQOnlyHandler1: + Out 20h, AL + +GUSIRQAgain: + Mov DX, CS:BasePort + Add DL, 6 + In AL, DX + +; Test AL, 2 ; MIDI receive? +; JZ GUSIRQOnlyHandlerNoMIDI +; +; Call CheckMIDI +; +; Jmp GUSIRQAgain + +GUSIRQOnlyHandlerNoMIDI: + Test AL, 8 + JZ GUSIRQOnlyHandler3 + + Mov DX, CS:GUSRegisterSelect + Mov AL, 45h + Out DX, AL + Mov AL, 0 + Add DL, 2 + Out DX, AL + Mov AL, 8 + Out DX, AL + Sub DL, 2 + + CLD + + Call SaveEMSPageFrame + Call Update + Call SetGUSRegisters + Call RestoreEMSPageFrame + Jmp GUSIRQAgain + +GUSIRQOnlyHandler3: + Test AL, 60h + JZ GUSIRQOnlyHandler2 + + Mov DX, CS:GUSVoiceSelect + In AL, DX + Push AX + +GUSIRQOnlyHandler4: + Mov DX, CS:GUSRegisterSelect + Mov AL, 8Fh + Out DX, AL + Add DL, 2 + In AL, DX ; Bit 6 = waveramp IRQ + ; Bit 7 = wavetable IRQ... + ; Bit 0-5 = voice + + Test AL, 080h + JZ GUSIRQOnlyHandler5 + Test AL, 040h + JZ GUSIRQOnlyHandler6 + + Pop AX + Mov DX, CS:GUSVoiceSelect + Out DX, AL + +; Jmp GUSIRQAgain + Jmp GUSIRQOnlyHandler2 + +GUSIRQOnlyHandler5: ; Wavetable IRQ + Push AX + Mov DX, CS:GUSVoiceSelect + And AL, 31 + Out DX, AL + Call GUSDelay + + Inc DX + + Xor AL, AL + Out DX, AL ; AL = 0 (Mode control) + Mov AL, 2 + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + + Pop AX + Test AL, 40h + JNZ GUSIRQOnlyHandler4 + +GUSIRQOnlyHandler6: ; Volume IRQ + Mov DX, CS:GUSVoiceSelect + And AL, 31 + Out DX, AL + Call GUSDelay + + Inc DX + Mov AL, 0Dh ; Volume Ramp. + Out DX, AL + + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 6 ; Ramp rate + Out DX, AL + + Mov AL, 63 ; Ramp rate + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Jmp GUSIRQOnlyHandler4 + + +GUSIRQOnlyHandler2: + Pop ES + Pop DS + PopAD + + IRet + +EndP GUSIRQOnlyHandler + +; + +IFDEF RAMP + include gusramp.inc +ELSE + include gusnramp.inc +ENDIF + +IFDEF RIC + include gusric.inc +ELSE + include gusnric.inc +ENDIF + +; + +Proc GUSGetAddress ; Given EAX + Assume DS:Nothing + + Push CX + + Mov CL, CS:Compress + ShR EAX, CL + + Pop CX + Add EAX, [CS:GUSDataTable+BX] + ShL EAX, 9 + + Ret + +EndP GUSGetAddress + +; InitMIDIIRQ + +Comment ~ + +Proc InitMIDIIRQ + + Ret + + + PushA + Push DS + Push ES + + Mov AX, CS + Mov DS, AX + ShL EAX, 16 + Mov ES, AX + Assume DS:Driver + + Mov BX, MIDIIRQ + Cmp BX, 15 + JA InitMIDIIRQ1 + + ShL BX, 2 + Mov SI, [IRQData+BX] + + Mov AX, Offset GUSMIDIIRQHandler + XChg [ES:SI], EAX + + Mov MIDIOldIRQHandler, EAX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + + And AX, [IRQData+BX+2] ; Update mask + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov DX, BasePort + Inc DH + Mov AL, 0FFh + Out DX, AL + Mov AL, 0FCh + Out DX, AL + Jmp InitMIDIIRQEnd + +InitMIDIIRQ1: + Mov DX, BasePort + Inc DH + Mov AL, 0FFh + Out DX, AL + Mov AL, 0h + Out DX, AL + +InitMIDIIRQEnd: + Pop ES + Pop DS + PopA + + Ret + +EndP InitMIDIIRQ + Assume DS:Nothing + +; + +Proc UnInitMIDIIRQ + + Ret + + PushA + Push DS + Push ES + + Mov BX, MIDIIRQ + Cmp BX, 15 + JA UnInitMIDIIRQ1 + + ShL BX, 2 + Mov BX, [IRQData+BX] + Xor AX, AX + Mov ES, AX + + Mov EAX, MIDIOldIRQHandler + Mov [ES:BX], EAX + +UnInitMIDIIRQ1: + Mov DX, Baseport + Inc DH + Mov AL, 0FFh + Out DX, AL + + Pop ES + Pop DS + PopA + + Ret + +EndP UnInitMIDIIRQ + Assume DS:Nothing + +~ + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov SI, Offset RelocationTable + +RelocationSetup: + Mov BX, [SI] + Cmp BX, 0FFFFh + JE RelocationSetupFinished + + Mov [BX], CS + + Add SI, 2 + Jmp RelocationSetup + +RelocationSetupFinished: + ; OK... disable the GUS Line In + ; & Enable Line Out + Mov BX, AX + + Mov DX, BasePort + Mov AL, 1 + Out DX, AL + + Call ResetGUS + + Cmp BL, 14 + JAE InitSound_GUS4 + + Mov BL, 14 + +InitSound_GUS4: + +IFDEF RIC + Mov UsedChannels, BX +ENDIF + + Mov DX, GUSRegisterSelect ; Tell the GUS how many voices + Mov AL, 0Eh ; to use + Out DX, AL + + Add DL, 2 ; DX = BasePort + 105h + Mov AL, BL + Dec AL + Or AL, 0C0h + Out DX, AL ; Number of Voices set + + ; Reset each voice + Mov CX, 32 ; 32 voices to clear. + + Sub BX, 14 ; Now get mixspeed + Add BX, BX + Mov AX, [GUSMixTable+BX] + Mov MixSpeed, AX + + Sub DL, 3 ; DX = Voice select register + +GUSResetVoice: + Mov AL, CL + Dec AL + Out DX, AL + + Inc DX ; DX = BasePort + 103h + Xor AL, AL ; Voice control register, 8 bit + Out DX, AL + + + Add DL, 2 + Mov AL, 2 + Out DX, AL ; Stop voice + Sub DL, 2 + + Mov AL, 0Dh ; Volume Ramp. + Out DX, AL + + Mov AL, 3 + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Mov AL, 6 ; Ramp rate + Out DX, AL + + Mov AL, 63 ; Ramp rate + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 9 ; Volume register, 16 bit + Out DX, AL + + Inc DX + Xor AX, AX + Out DX, AX ; No volume + Call GUSDelay + Out DX, AX + + ClI + Sub DL, 2 ; DX = BasePort + 102h = Voice select. + + Loop GUSResetVoice + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + +; Call InitMIDIIRQ + + Cmp IRQ, 0FFFFh + JE InitSound_GUS1 + + Mov AX, BasePort + Call ResetGUS + + ; Set IRQ + Mov BX, IRQ + ShL BX, 2 ; BX points to offset in IRQData + + Xor DI, DI + Mov ES, DI + Mov DI, [BX+IRQData] + + In AL, 0A1h + Mov AH, AL + In AL, 21h + + And AX, [BX+IRQData+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset GUSIRQOnlyHandler + + XChg [ES:DI], EAX + Mov OldIRQHandler, EAX + + StI + + Mov DX, BasePort + Mov AL, 9 ; + 16 + Out DX, AL + + Mov DX, GUSRegisterSelect + Mov AL, 4Ch + Out DX, AL + Add DL, 2 + Mov AL, 7 + Out DX, AL + + Call GetTempo + Call SetTempo + Call ResetMemory + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, GUSMemory + + Mov SI, Offset GUSID2 + + ClC + Ret + +InitSound_GUS1: + Inc DL + Mov AL, 4Ch + Out DX, AL + Add DL, 2 + Mov AL, 3 ; 7 + Out DX, AL + + Mov DX, BasePort + Mov AL, 9 ; + 16 + Out DX, AL + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Call GetTempo + Call SetTempo + Call ResetMemory + + Xor AX, AX + Mov ES, AX ; ES = 0 + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset GUSIRQHandler + + ClI + + XChg DWord Ptr [ES:20h], EAX ; Clock tick + Mov OldIRQHandler, EAX + + StI + + Mov AX, BasePort + Mov BX, GUSMemory + Mov SI, Offset GUSID + + ClC + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc ReInitSound Far + + Push AX + + Push CS + Pop DS + Mov SI, Offset GUSReinitMsg + Mov BX, 40 + Call SetInfoLine + + Call UnInitSound + + Pop AX + Jmp InitSound + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Push CS + Pop DS + Assume DS:Driver + +IFDEF RIC + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset Convert16To8Bit + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h +SaveConfig2: + +ENDIF + Mov AX, BasePort + Call ResetGUS + + ClI + + Mov BX, CS:IRQ + Cmp BX, 0FFFFh + JE UnInitSound1 + + Mov AX, CS:IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + ShL BX, 2 + Xor DI, DI + Mov ES, DI + Mov DI, [CS:BX+IRQData] + Mov EAX, CS:OldIRQHandler + + Mov [ES:DI], EAX + +; Call UnInitMIDIIRQ + + StI + Ret + +UnInitSound1: + Mov AL, 34h + Out 43h, AL + + Xor AX, AX + Out 40h, AL + Out 40h, AL + + Mov ES, AX + Mov EAX, OldIRQHandler + Mov [ES:20h], EAX + +; Call UnInitMIDIIRQ + + StI + + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + Ret + +EndP Poll + Assume DS:Nothing + +Proc UARTOut Far + + Push DX + Push AX + + Mov DX, [CS:BasePort] + Inc DH + +UARTOut1: + In AL, DX + Test AL, 2 + JZ UARTOut1 + + Pop AX + Inc DX + + Out DX, AL + + Pop DX + + Ret + +EndP UARTOut + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far ; BX = tempo... + + Push AX + Push BX + Push DX + + Cmp CS:IRQ, 0FFFFh + JE SetTempo1 + + ShL BX, 8 + Mov DX, 1Eh + Mov AX, 8480h + Div BX + Neg AL + + Mov AH, AL + + Mov DX, CS:GUSRegisterSelect + + Mov AL, 47h + Out DX, AL + Add DL, 2 + Mov AL, AH + Out DX, AL ; Set Timer control register 2 + Sub DL, 2 + + Mov AL, 45h + Out DX, AL + Add DL, 2 + Mov AL, 8 + Out DX, AL +; Sub DL, 2 + + Mov DX, CS:BasePort + Add DL, 8 + Mov AL, 4 + Out DX, AL + + Inc DL + Mov AL, 2 + Out DX, AL + + Jmp SetTempo2 + +SetTempo1: + ; Frames per second = 2 * (0.4*Tempo) + Mov AX, 0C214h + Mov DX, 16h ; Ticks = (1193181/(2*0.4))/Tempo + Div BX + + ; AX contains counter. + Mov GUSUpdateTimer, AX + + Out 40h, AL ; Timer IRQ. + Mov AL, AH + Out 40h, AL + +SetTempo2: + Pop DX + Pop BX + Pop AX + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; + +Proc LoadSample Far + + PushAD + Push DS + Push ES + Push FS + + Mov FS, CS:SongDataArea + Mov BP, AX + Dec BP + Add BP, BP + Mov BP, [FS:64912+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length + JC Music_GUSLoadSampleEnd + + Mov BL, [FS:BP+12h] + Test BL, 16 + JZ Music_GUSLoadSample12 + + Cmp ECX, [FS:BP+38h] + JBE Music_GUSLoadSample12 + + Mov ECX, [FS:BP+38h] + Test BL, 32 + JZ Music_GUSLoadSample12 + + Cmp ECX, [FS:BP+44h] + JAE Music_GUSLoadSample12 + + Mov ECX, [FS:BP+44h] + +Music_GUSLoadSample12: + Mov EBX, ECX + Mov CL, CS:Compress + Mov EDX, 1 + ShR EBX, CL + ShL EDX, CL ; EDX = step value. + + Mov ECX, EBX + + ; Now find location to put it in + + Dec AX ; AX = sample number + Push AX ; AX = sample number (0 based) + + And EAX, 0FFh + Mov DWord Ptr [CS:GUSDataTable+4*EAX], 0FFFFFFFFh + + Add ECX, 2 + Mov EAX, GUSMemoryFree + + Test Byte Ptr [FS:BP+12h], 2 ; 16 bit?? + JZ Music_GUSLoadSamples13 + + Cmp CS:Convert16To8Bit, 0 + JNZ Music_GUSLoadSamples5 + + Sub EAX, 1 + JC Music_GUSLoadSampleWarning + And EAX, Not 1 ; For alignment + Add ECX, ECX + + Mov EBX, EAX + + Sub EBX, 1 + JC Music_GUSLoadSampleWarning + And EBX, 3FFFFh ; Get bytes remaining in 'segment' + Inc EBX + + Cmp ECX, 256*1024 + JAE Music_GUSLoadSamples13 + + Cmp ECX, EBX + JBE Music_GUSLoadSample2 + + Sub EAX, EBX + Jmp Music_GUSLoadSamples13 + +Music_GUSLoadSamples5: + Inc ESI + Add EDX, EDX ; Step value. + +Music_GUSLoadSamples13: + Cmp ECX, EAX + JBE Music_GUSLoadSample2 + + ; Warning msg here. +Music_GUSLoadSampleWarning: + Pop AX + +Music_GUSLoadSampleEndNoError: + ClC + Jmp Music_GUSLoadSampleEnd + +Music_GUSLoadSample3: + StC + +Music_GUSLoadSampleEnd: + Pop FS + Pop ES + Pop DS + PopAD + + Ret + +Music_GUSLoadSample2: ; EAX = number of bytes free. + ; DS:SI = sample. + ; ECX = number of bytes of memory + ; ES:DI = num bytes free ptr + ; BP = sample number. + + ; Location = MaxMem - DX:AX + ; = -(DX:AX - GUSBanks*4:0) + MovZX EBX, CS:GUSMemory + ShL EBX, 10 + ; BX = bytes avail. + Sub EBX, EAX + Sub EAX, ECX + Mov GUSMemoryFree, EAX + + Pop DI ; DI = sample number + + ShL DI, 2 + + Cmp CS:Convert16To8Bit, 0 + JNZ LoadGUSForced8Bit + + Test Byte Ptr [FS:BP+12h], 2 + JNZ Music_GUSLoad16BitSample + +LoadGUSForced8Bit: + Push EBX + Inc EBX + Mov [CS:GUSDataTable+DI], EBX ; Store pointer + + Mov ES, CS:SongDataArea + Pop EDI ; EDI = location in GUS mem + + Sub ECX, 2 + ; EDI = location in GUS mem + ; DS:SI = sample data + ; ECX = length. + ; EDX = step value. + ClI + + Push BP + + Mov EBP, EDX + + Mov AL, [DS:SI+BP] + Call LoadGUSSample + Call LoadGUSSamples + + Mov BH, AL + + Pop BP + + Mov AL, [FS:BP+12h] + Test AL, 16 + JZ Music_GUSLoadSample10 + + Mov ESI, [FS:BP+34h] + Test AL, 64 + JZ Music_GUSLoadSample11 + + Mov ESI, [FS:BP+38h] + Sub ESI, 2 + AdC ESI, 0 + + Mov EAX, Not 0 + Mov CL, CS:Compress + ShL EAX, CL + And ESI, EAX + +Music_GUSLoadSample11: + Test Byte Ptr [FS:BP+12h], 2 + JZ Music_GUSLoadSample6 + + Add ESI, ESI + Inc SI + +Music_GUSLoadSample6: + Call UpdateSampleLocation + + Mov BH, [SI] + +Music_GUSLoadSample10: + Mov AL, BH + Call LoadGUSSample + + StI + Jmp Music_GUSLoadSample3 ; Return.. no error. + +Music_GUSLoad16BitSample: + Push EBX + + Add EBX, 2 + Mov EAX, EBX + And EBX, 3FFFFh + And EAX, Not 3FFFFh + ShR EBX, 1 + Or EAX, EBX + Mov [CS:GUSDataTable+DI], EAX + + Mov ES, CS:SongDataArea + Pop EDI ; EDI = location in GUS mem + + Sub ECX, 4 + ClI + + Push BP + + Mov EBP, EDX + + Mov AX, [DS:ESI+EBP*2] + Call LoadGUSSample + Mov AL, AH + Call LoadGUSSample + + Call Load16GUSSamples + + Pop BP + + Xor BX, BX + + Mov AL, [FS:BP+12h] + Test AL, 16 + JZ Music_GUSLoad16BitSample11B + + Mov ESI, [FS:BP+34h] + + Test AL, 64 + JZ Music_GUSLoad16BitSample11 + + Mov ESI, [FS:BP+38h] + Sub ESI, 2 + JNC Music_GUSLoad16BitSample11 + + Xor ESI, ESI + +Music_GUSLoad16BitSample11: + Mov EAX, Not 0 + Mov CL, CS:Compress + ShL EAX, CL + And ESI, EAX + + Add ESI, ESI + Call UpdateSampleLocation + + Mov BX, [SI] + +Music_GUSLoad16BitSample11B: + Mov AX, BX + Call LoadGUSSample + Mov AL, AH + Call LoadGUSSample + + StI + Jmp Music_GUSLoadSample3 ; Return.. no error. + + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release, 0 based +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + LEA DI, [EAX*4+Offset GUSDataTable] + ; Now to release the last + ; sample from GUS memory if + ; able to. + + Cmp DWord Ptr [CS:DI], 0FFFFFFFFh + JE ReleaseSample3 + +ReleaseSample4: + MovZX EAX, CS:GUSMemory + SHL EAX, 10 + + Mov EBP, [CS:DI] ; EBP = sample pointer. + + ; If (MaxMem-(sample location in bank + sample length + 2)) = memory remaining, + ; then release memory. + + Mov ECX, [SI+30h] + Mov DL, [SI+12h] + Test DL, 16 + JZ ReleaseSample7 + + Cmp ECX, [SI+38h] + JBE ReleaseSample7 + + Mov ECX, [SI+38h] + + Test DL, 32 + JZ ReleaseSample7 + + Cmp ECX, [SI+44h] + JAE ReleaseSample7 + + Mov ECX, [SI+44h] + +ReleaseSample7: + Push EBX + Mov EBX, ECX + Mov CL, CS:Compress + ShR EBX, CL + Mov ECX, EBX + Pop EBX + + Inc ECX + Mov EDI, 1 + + Test DL, 2 + JZ ReleaseSample8Bit + + Cmp CS:Convert16To8Bit, 0 + JNZ ReleaseSample8Bit + + Add ECX, ECX + Inc DI + + ; EBP = pointer for 16 bit + ; need to convert back: + Mov EDX, EBP + Add EBP, EBP + And EBP, 3FFFFh + And EDX, Not 3FFFFh + Or EBP, EDX + +ReleaseSample8Bit: + Sub EAX, EBP + Sub EAX, ECX + + Cmp EAX, GUSMemoryFree + JNE ReleaseSample3 + + Add ECX, EDI + Add GUSMemoryFree, ECX + +ReleaseSample3: + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Push EAX + Push CX + Push ES + Push DI + + MovZX EAX, GUSMemory ; Number of kbytes + ShL EAX, 10 ; Translate to bytes + + Sub EAX, 64 ; Safety bytes. + Mov GUSMemoryFree, EAX + + Push CS + Pop ES + Mov DI, Offset GUSDataTable + Mov CX, 200 + Mov AX, 0FFFFh + Rep StosW + + Pop DI + Pop ES + Pop CX + Pop EAX + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + Push CS + Pop DS + Assume DS:Driver + + Mov EAX, GUSMemoryFree + Mov SI, Offset GUSFreeMsg + ShR EAX, 10 + +IFDEF RIC + Cmp ShowReinit, 0 + JE NoShowInit + + Mov SI, Offset GUSFreeMsg2 + Mov BX, UsedChannels + Cmp ShowReinit, 1 + JE NoShowInit + + Add BX, BX + Mov BX, [GUSMixTable+BX-28] + + NoShowInit: + +ENDIF + ClC + + Ret + +EndP GetStatus + Assume DS:Nothing + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset GUSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetConvert Far + + Mov AX, [SI+22] + Mov CS:Convert16To8Bit, AL + Call Music_LoadAllSamples + + Mov AX, 1 + Ret + +EndP SetConvert + +; + +Proc GetConvert Far + + Push CS + Pop ES + Mov DI, Offset Convert16To8Bit + Ret + +EndP GetConvert + +; + +Proc SetCompress Far + + Mov AX, [SI+22] + Mov CS:Compress, AL + Call Music_LoadAllSamples + + Mov AX, 1 + Ret + +EndP SetCompress + +; + +Proc GetCompress Far + + Push CS + Pop ES + Mov DI, Offset Compress + + Ret + +EndP GetCompress + +; + +IFDEF RIC + +Proc SetReinit Far + + Mov AX, [SI+22] + Mov CS:ShowReinit, AL + + Mov AX, 1 + Ret + +EndP SetReinit + +; + +Proc GetReinit Far + + Push CS + Pop ES + Mov DI, Offset ShowReinit + + Ret + +EndP GetReinit + +ENDIF + +; + +EndDriver: + +;******** Provided Constants Table ************* + +MaxNumberOfChannels DW 32 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 32 +DriverFlags DW 1 ; Driver supports MIDI Out + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + DW Offset DetectGUS + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + + DW Offset UARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End + + *********************** Notes ******************* + + UltraSound Output Structure + + 0 1 2 3 4 5 6 7 8 9 + +0000:(Flags)LastVol + + + diff --git a/it/SoundDrivers/GUSDRV.ASM b/it/SoundDrivers/GUSDRV.ASM new file mode 100755 index 0000000..ae60f0d --- /dev/null +++ b/it/SoundDrivers/GUSDRV.ASM @@ -0,0 +1,5 @@ + +RAMP EQU 1 + +include gus.inc + diff --git a/it/SoundDrivers/GUSDRV2.ASM b/it/SoundDrivers/GUSDRV2.ASM new file mode 100755 index 0000000..54d73a4 --- /dev/null +++ b/it/SoundDrivers/GUSDRV2.ASM @@ -0,0 +1,3 @@ + +include gus.inc + diff --git a/it/SoundDrivers/GUSHIQ2.ASM b/it/SoundDrivers/GUSHIQ2.ASM new file mode 100755 index 0000000..2afcc8d --- /dev/null +++ b/it/SoundDrivers/GUSHIQ2.ASM @@ -0,0 +1,5 @@ + +RIC EQU 1 + +include gus.inc + diff --git a/it/SoundDrivers/GUSHIQDR.ASM b/it/SoundDrivers/GUSHIQDR.ASM new file mode 100755 index 0000000..1b46dbc --- /dev/null +++ b/it/SoundDrivers/GUSHIQDR.ASM @@ -0,0 +1,4 @@ +RAMP EQU 1 +RIC EQU 1 + +include gus.inc diff --git a/it/SoundDrivers/GUSMAX.ASM b/it/SoundDrivers/GUSMAX.ASM new file mode 100755 index 0000000..fbdbfd6 --- /dev/null +++ b/it/SoundDrivers/GUSMAX.ASM @@ -0,0 +1,2091 @@ +; +; Windows Sound System Driver +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +DMASize DW 2048 + +WSSMsg DB "Using GUS CS4231 Codec", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Using GUS CS4231 Codec", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "GUS Codec reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITGUSMAX.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITGUSMAX.DRV", 0 + +DriverName DB "ITGUSMAX.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW 0 + +WSSHeaderLine DW 10 + DB "GUS CS4231 Codec Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "GUS CS4231 Codec Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 2 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 16 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Inc DX + Inc DX + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Cmp IRQ, 0FFFFh + JE DetectWSSFailure + Cmp DMA, 0FFFFh + JE DetectWSSFailure + + Mov DX, BasePort + Cmp DX, 0FFFFh + JE DetectCardFindBasePort + + Call PingWSS + JNC CheckWSSOK + +DetectWSSFailure: + StC + Ret + +DetectCardFindBasePort: + Mov DX, 31Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 32Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 33Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 34Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 35Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 36Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 530h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 604h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0F40h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0E80h + Call PingWSS + JC DetectWSSFailure + +DetectWSSOK: + Mov BasePort, DX + +CheckWSSOK: ; Check for IRQ + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Mov EAX, 'Jeff' + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 2 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB WSSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +WSSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/GUSMAXMX.ASM b/it/SoundDrivers/GUSMAXMX.ASM new file mode 100755 index 0000000..73e03bb --- /dev/null +++ b/it/SoundDrivers/GUSMAXMX.ASM @@ -0,0 +1,1589 @@ +; +; Windows Sound System Driver, with GUS PnP detection, MMX mixing. +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +OUTPUTFILTERENABLED EQU 0 + +FPSave DB 128 Dup (0) + +DMASize DW 2048 + +WSSMsg DB "GUS CS4231 Codec MMX", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "GUS CS4231 Codec MMX", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "GUS CS4231 Codec reinitialised", 0 + +DriverName DB "ITGUSMAX.MMX", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 4 +MixMode DW 0 +MixModeOffset DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 12 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 12 + DW Near Ptr MasterVolumeRight ; 13 + + DW 0 + + +WSSHeaderLine DW 10 + DB "GUS CS4231 Codec MMX Driver", 0 + +DriverText DW 1 + DB 28, 48 + DB 21h + DB "GUS CS4231 Codec MMX Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 13, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 12, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + DW 0 + +MixModeButton1 DW 2 + DW 13, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " MMX, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " MMX, Volume Ramped", 0 + +MixModeButton4 DW 2 + DW 8, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " MMX, Filtered", 0 + +VolumeTable DB 2 Dup (56) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label + +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + + +include nodebug.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Trace "GUSPnP MMX: SetMixMode" + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 14 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Inc DX + Inc DX + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectMMX + + PushFD + Pop EAX + Mov EBX, EAX + Xor EAX, 00200000h + Push EAX + PopFD + PushFD + Pop EAX + Cmp EAX, EBX + JZ DetectMMXFail + + Mov EAX, 1 + DB 0Fh, 0A2h ; CPUID + Test EDX, 800000h + JZ DetectMMXFail + + ClC + Ret + +DetectMMXFail: + StC + Ret + +EndP DetectMMX + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Call DetectMMX + JC DetectWSSFailure + + Cmp IRQ, 0FFFFh + JE DetectWSSFailure + Cmp DMA, 0FFFFh + JE DetectWSSFailure + + Mov DX, BasePort + Cmp DX, 0FFFFh + JE DetectCardFindBasePort + + Call PingWSS + JNC CheckWSSOK + +DetectWSSFailure: + StC + Ret + +DetectCardFindBasePort: + Mov DX, 31Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 32Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 33Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 34Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 35Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 36Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 530h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 604h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0F40h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0E80h + Call PingWSS + JC DetectWSSFailure + +DetectWSSOK: + Mov BasePort, DX + +CheckWSSOK: ; Check for IRQ + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Mov EAX, 'Jeff' + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +include mmxmsam.inc + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 2 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + FNSave [FPSave] + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB WSSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +WSSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Mov BX, DMASize ; BX = bytes required + Add DI, AX + + ShR BX, 1 + ; BX = samples required + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + FNRstor [CS:FPSave] + + Pop ES + Pop DS + PopAD + IRet + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Trace "GUSPnP MMX: StopSound" + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Trace "GUSPnP MMX: StartSound" + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Trace "GUSPnP MMX: InitSound" + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, (DMABUFFERLENGTH*2)/16 + 5 + Mov BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Call UpdateSoundcardVariables + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Trace "GUSPnP MMX: SetStereoCall" + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + Trace "GUSPnP MMX: Driver Screen" + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + Push AX DX + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX AX + Ret + +EndP UpdatesoundcardVariables + Assume DS:Nothing + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + Call UpdateSoundcardVariables + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h +; Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: +; Call UARTOut + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 + DW 3 + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/GUSMIXDR.ASM b/it/SoundDrivers/GUSMIXDR.ASM new file mode 100755 index 0000000..853b5f5 --- /dev/null +++ b/it/SoundDrivers/GUSMIXDR.ASM @@ -0,0 +1,2462 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 4096 + +ENDLOCATIONHIGH EQU 1Fh +ENDLOCATIONLOW EQU 0FE00h +HALFENDLOCATIONHIGH EQU 0Fh +HALFENDLOCATIONLOW EQU 0FE00h + +MIXRESOLUTION EQU 32 ; 32 bit mixing for the GUS +MIXTABLESIZE EQU 2*256*65 + +Voice0Position DD 0 +Voice1Position DD 0 + +GUSMsg DB "Gravis Ultrasound detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +GUSNoMemoryMsg DB "Gravis Ultrasound detected", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Gravis Ultrasound reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITGUSMIX.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITGUSMIX.DRV", 0 + +DriverName DB "ITGUSMIX.DRV", 0 +UltrasndString DB "ULTRASND" + +GUSMixTable Label Word + DW 44100, 41160, 38588, 36318, 34300, 32495, 30870, 29400, 28064 + DW 26844, 25725, 24696, 23746, 22867, 22050, 21290, 20580, 19916 + DW 19294 + +DSPVersion DW 0 +DSPIRQValue DB 0 +DSPDMAValue DB 0 +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +MixSpeed DW 44100 +GUSChannels DB 14 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +GUSRegisterSelect DW 0 +GUSVoiceSelect DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 8 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 +DMASize DW 4096 + +IMR DW 0 +OldIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +GUSScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr GUSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; 7 + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW 0 + +GUSHeaderLine DW 10 + DB "Gravis Ultrasound Mixed Driver", 0 + +DriverText DW 1 + DB 30, 48 + DB 21h + DB "Gravis Ultrasound Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MixModeText DW 1 + DB 2, 13 + DB 20h + DB "Mixing Mode", 0 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 15, 32, 17, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 18, 32, 20, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 21, 32, 23, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 24, 32, 26, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 28 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 30, 29, 32, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 33, 29, 35, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 36, 29, 38, 8 + DB 0 + DB " 75% Filter", 0 + +; MixingRoutines + +MixBufferPos DW 0 +MixBufferDestination DW 0 + +include dmanai.inc ; Non-auto-initialise DMA +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +;*********************************************** + +Proc GUSDelay + + Push AX + Push DX + + Mov DX, 300h + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Pop DX + Pop AX + + Ret + +EndP GUSDelay + +; + +Proc ResetGUS ; AX = baseport. + + Push AX + Push DX + + Mov DX, AX + Add DX, 103h ; Select register + + Mov AL, 4Ch ; Reset global register + Out DX, AL + + Add DL, 2 ; 8 bit data + Xor AL, AL + Out DX, AL ; Reset GUS! + + Call GUSDelay + Call GUSDelay + + Mov AL, 1 + Out DX, AL + + Call GUSDelay + Call GUSDelay + + Pop DX + Pop AX + + Ret + +EndP ResetGUS + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + + Mov BX, 200 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 44100 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + ; OK.. find number of voices to + ; achieve desired mix speed. + Mov SI, Offset GUSMixTable + Mov BL, 14 + Mov CX, 32-14 + +GetSBMixConst2: + LodsW + Cmp AX, CX + JAE GetSBMixConst3 + + Inc BL + Loop GetSBMixConst2 + +GetSBMixConst3: + Mov GUSChannels, BL + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov SI, Offset ULTRASNDString + Mov CX, 8 + Call GetEnvironment ; Returns ES:DI, Carry if error + JC DetectCardError + + Xor DX, DX ; Baseport first. + +DetectCard1: + Mov AL, [ES:DI] + Inc DI + + Cmp AL, ',' + JE DetectCard2 + + Sub AL, '0' + JC DetectCardError + Cmp AL, '9' + JA DetectCardError + + ShL DX, 4 + Add DL, AL + Jmp DetectCard1 + +DetectCard2: + Cmp DX, 210h + JB DetectCardError + Cmp DX, 280h + JA DetectCardError + + Mov BasePort, DX + Add DX, 102h + Mov GUSVoiceSelect, DX + Inc DL + Mov GUSRegisterSelect, DX + + ; Get DMA + Xor DX, DX + +DetectCard3: + Mov AL, [ES:DI] + Inc DI + Cmp AL, ',' + JE DetectCard4 + + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCard3 + +DetectCard4: + Cmp DX, 7 + JA DetectCardError + + Mov DMA, DX + + Xor DX, DX + +DetectCard5: + Mov AL, [ES:DI] + Inc DI + Cmp AL, ',' + JE DetectCard6 + + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCard5 + +DetectCard6: + Cmp DX, 7 + JA DetectCardError + ; Wasted DMA.. + + ; IRQ.. + + Xor DX, DX + +DetectCard7: + Mov AL, [ES:DI] + Inc DI + Cmp AL, ',' + JE DetectCard8 + + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCard7 + +DetectCard8: + Cmp DX, 15 + JA DetectCardError + + Mov IRQ, DX + + Mov EAX, 'Jeff' + ClC + Ret + +DetectCardError: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc GUSIRQHandler + + PushAD + Push DS + Push ES + + CLD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov AL, 20h + Cmp IRQ, 7 + JBE GUSIRQHandler1 + + Out 0A0h, AL + +GUSIRQHandler1: + Out 20h, AL + + Mov DX, BasePort + Add DL, 6 + In AL, DX + + Test AL, 20h + JZ GUSIRQHandlerEnd + + ; OK.. need to determine Cause type +GUSIRQAgain: + Mov DX, GUSRegisterSelect + Mov AL, 8Fh + Out DX, AL + Add DL, 2 + In AL, DX ; Bit 6 = waveramp IRQ + + Test AL, 80h + JZ GUSLoopIRQ + + Jmp GUSIRQHandlerEnd + +GUSLoopIRQ: ; Need to disable looping and + ; enable rollover. Set End address + ; to midpoint. + Xor MixBufferPos, 1 + JZ GUSRolloverIRQ + +; Mov MixBufferDestination, DMABUFFERLENGTH/16/2 + Mov MixBufferDestination, DMABUFFERLENGTH + + Mov DX, GUSVoiceSelect + Xor AL, AL + Out DX, AL + + Inc DX + Call GUSDelay + + Mov AL, 4 ; End address high + Out DX, AL + Mov AX, HALFENDLOCATIONHIGH + Inc DX + Out DX, AX + Dec DX + + Mov AL, 5 ; End address low + Out DX, AL + Mov AX, HALFENDLOCATIONLOW +; Cmp CS:Stereo, 0 +; JE HalfEndLocationMono +; +; Mov AX, HALFENDLOCATIONSTEREOLOW +; +; HalfEndLocationMono: + Inc DX + Out DX, AX + Dec DX + + Xor AL, AL + Out DX, AL + Mov AL, 4+32 ; 16-bit data, no loop, no IRQ. + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Mov AL, 0Dh + Out DX, AL + Mov AL, 3+4 ; Enable rollover + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Jmp GUSIRQEnd + +GUSRolloverIRQ: ; Need to disable rollover and + ; enable looping. Set End address + ; to endpoint. + Mov MixBufferDestination, 0 + + Mov DX, GUSVoiceSelect + Xor AL, AL + Out DX, AL + + Call GUSDelay + Inc DX + + Mov AL, 4 ; End address high + Out DX, AL + Mov AX, ENDLOCATIONHIGH + Inc DX + Out DX, AX + Dec DX + + Mov AL, 5 ; End location low + Out DX, AL + Mov AX, ENDLOCATIONLOW + +; Cmp Stereo, 0 +; JE EndLocationMono +; +; Mov AX, ENDLOCATIONSTEREOLOW +; +; EndLocationMono: + Inc DX + Out DX, AX + Dec DX + + Xor AL, AL + Out DX, AL + Mov AL, 4+8+32 ; 16-bit data, looping + Wavetable IRQ + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Mov AL, 0Dh + Out DX, AL + Mov AL, 3 ; Disable rollover + Add DL, 2 + Out DX, AL + Sub DL, 2 + +; Jmp GUSIRQAgain + +GUSIRQEnd: + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE GUSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +GUSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE GUSIRQHandler4 + Assume DS:Nothing + +GUSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +GUSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE GUSIRQHandler5 + + Mov DX, MixTransferRemaining + +GUSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB GUSIRQHandler6 + JE GUSIRQHFilter + + Cmp CS:Stereo, 0 + JE GUSIRQ3QFilterMono + +GUSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +GUSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL GUS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG GUS3QFilterStereoClip2 + +GUSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL GUS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG GUS3QFilterStereoClip4 + +GUSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ GUSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp GUSMixTransferEnd + +GUSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +GUSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL GUS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG GUS3QFilterMonoClip2 + +GUSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ GUSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp GUSMixTransferEnd + +GUSIRQHFilter: + Cmp CS:Stereo, 0 + JE GUSIRQHFilterMono + +GUSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +GUSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL GUSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG GUSHFilterStereoClip2 + +GUSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL GUSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG GUSHFilterStereoClip4 + +GUSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ GUSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp GUSMixTransferEnd + +GUSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +GUSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL GUSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG GUSHFilterMonoClip2 + +GUSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ GUSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp GUSMixTransferEnd + +GUSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL GUSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG GUSIRQHandlerClip2 + +GUSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ GUSIRQHandler6 + +GUSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ GUSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + ; DMA the data to MixBufferDestination + Comment ~ + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + Mov DX, GUSRegisterSelect + Mov AL, 42h ; DMA destination + Out DX, AL + Mov AX, MixBufferDestination + Inc DX + Out DX, AX + Dec DX + + Mov AL, 41h ; DMA control register + Out DX, AL + Mov AL, 1 + Cmp DMA, 4 + JB DMAType + + Or AL, 4 + +DMAType: + Add DL, 2 + Out DX, AL + + ~ + +; Comment ~ + + LDS SI, [ActualDMAPtr] + Mov DX, GUSRegisterSelect + + Mov AL, 44h + Out DX, AL ; High address + Xor AL, AL + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov DI, MixBufferDestination + Mov CX, DMASize + + Mov AL, 43h + Out DX, AL + Inc DX + +Output1: + Mov AX, DI + Out DX, AX + Add DL, 3 + + Mov AL, [SI] + Out DX, AL + + Sub DL, 3 + Inc SI + Inc DI + Dec CX + JNZ Output1 + +; ~ + + Call RestoreEMSPageFrame + +GUSIRQHandlerEnd: + Pop ES + Pop DS + PopAD + IRet + Assume DS:Nothing + +GUSIRQHandlerClip1: + Mov AX, 8000h + Jmp GUSIRQHandler7 + +GUSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp GUSIRQHandler7 + +GUSHFilterMonoClip1: + Mov AX, 8000h + Jmp GUSIRQHFilterMono2 + +GUSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp GUSIRQHFilterMono2 + +GUSHFilterStereoClip1: + Mov AX, 8000h + Jmp GUSIRQHFilterStereo2 + +GUSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp GUSIRQHFilterStereo2 + +GUSHFilterStereoClip3: + Mov AX, 8000h + Jmp GUSIRQHFilterStereo3 + +GUSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp GUSIRQHFilterStereo3 + +GUS3QFilterMonoClip1: + Mov AX, 8000h + Jmp GUSIRQ3QFilterMono2 + +GUS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp GUSIRQ3QFilterMono2 + +GUS3QFilterStereoClip1: + Mov AX, 8000h + Jmp GUSIRQ3QFilterStereo2 + +GUS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp GUSIRQ3QFilterStereo2 + +GUS3QFilterStereoClip3: + Mov AX, 8000h + Jmp GUSIRQ3QFilterStereo3 + +GUS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp GUSIRQ3QFilterStereo3 + +EndP GUSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset GUSIRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartGUS ; + + PushA + Push ES + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Mov AL, 1 + Out DX, AL + + Mov AX, DX + Call ResetGUS + + Mov DX, GUSRegisterSelect ; Tell the GUS how many voices + Mov AL, 0Eh ; to use + Out DX, AL + + Add DL, 2 ; DX = BasePort + 105h + Mov AL, GUSChannels + Dec AL + Or AL, 0C0h + Out DX, AL ; Number of Voices set + + ; Reset each voice + + Mov CX, 32 ; 32 voices to clear. + + Sub DL, 3 ; DX = Voice select register + +GUSResetVoice: + Mov AL, CL + Dec AL + Out DX, AL + + Inc DX ; DX = BasePort + 103h + Xor AL, AL ; Voice control register, 8 bit + Out DX, AL + + Add DL, 2 + Mov AL, 2 + Out DX, AL ; Stop voice + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Mov AL, 0Dh ; Volume Ramp. + Out DX, AL + + Mov AL, 3 + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + + Mov AL, 6 ; Ramp rate + Out DX, AL + + Mov AL, 63 ; Ramp rate + Add DL, 2 + Out DX, AL + Sub DL, 2 + + + Mov AL, 9 ; Volume register, 16 bit + Out DX, AL + + Inc DX + Xor AX, AX + Out DX, AX ; No volume + Call GUSDelay + Out DX, AX + + Sub DL, 2 ; DX = BasePort + 102h = Voice select. + + Loop GUSResetVoice + + ; OK.. now... gotta clear memory from + ; 0->DMABUFFERLENGTH*2 + + Mov CX, DMABUFFERLENGTH*2 + Xor DI, DI ; DI = destination + + ClI + + Inc DX ; DX = register select + Mov AL, 44h + Out DX, AL + + Xor AL, AL + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 43h + Out DX, AL + Inc DX + +ClearGUSRAM: + Mov AX, DI ; Memory location low + Out DX, AX ; Memory location done. + + Xor AL, AL + Add DL, 3 + Out DX, AL + Sub DL, 3 + + Inc DI + Dec CX + JNZ ClearGUSRAM + + StI + ; OK.. enable interrupt + Mov DX, BasePort + Mov AL, 9 + Out DX, AL ; Enables DMA/IRQ + + Mov DX, GUSRegisterSelect + Mov AL, 4Ch + Out DX, AL + Add DL, 2 + Mov AL, 7 + Out DX, AL ; Enables IRQ + + ; Setup voices + ClI + Cmp Stereo, 0 + JE StartGUSMono + +StartGUSStereo: ; Uses voices 0 and 1 + Mov DX, GUSVoiceSelect + Xor AL, AL + Out DX, AL + Call GUSDelay + Inc DX + + Mov AL, 1 ; Freq control + Out DX, AL + Inc DX + Mov AX, 0000100000000000b + Out DX, AX + Dec DX + + Mov AL, 2 ; Starting location high + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 3 ; Starting location low + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 4 ; End location high + Out DX, AL + Mov AX, HALFENDLOCATIONHIGH + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 5 ; End location low + Out DX, AL + Mov AX, HALFENDLOCATIONLOW + Inc DX + Out DX, AX + Dec DX + + Mov AL, 9 ; Current volume + Out DX, AL + Mov AX, 0EFF0h + Inc DX + Out DX, AX + Call GUSDelay + Out DX, AX + Dec DX + + Mov AL, 0Ah ; Current location high + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Bh ; Current location low + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Ch ; Pan position + Out DX, AL + Mov AL, 0 ; Full left. + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 0Dh ; Set rollover condition + Out DX, AL + Mov AL, 4+2+1 ; Rollover + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov DX, GUSVoiceSelect + Mov AL, 1 ; Voice 1 + Out DX, AL + Call GUSDelay + Inc DX + + Mov AL, 1 ; Freq control + Out DX, AL + Inc DX + Mov AX, 0000100000000000b + Out DX, AX + Dec DX + + Mov AL, 2 ; Starting location high + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 3 ; Starting location low + Out DX, AL + Mov AX, 0000001000000000b + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 4 ; End location high + Out DX, AL + Mov AX, 20h ; ENDLOCATIONHIGH + Inc DX + Out DX, AX + Dec DX + + Mov AL, 5 ; End location low + Out DX, AL + Mov AX, 0 ; ENDLOCATIONLOW + Inc DX + Out DX, AX + Dec DX + + Mov AL, 9 ; Current volume + Out DX, AL + Mov AX, 0EFF0h + Inc DX + Out DX, AX + Call GUSDelay + Out DX, AX + Dec DX + + Mov AL, 0Ah ; Current location high + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Bh ; Current location low + Out DX, AL + Mov AX, 0000001000000000b + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Ch ; Pan position + Out DX, AL + Mov AL, 0Fh ; Full right + Add DL, 2 + Out DX, AL + Sub DL, 2 + ; start voices. + + Mov AL, 0Dh + Out DX, AL + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + CLI + + Mov DX, GUSVoiceSelect ; Select voice 0 + Xor AL, AL + Out DX, AL + +; Call GUSDelay + + Inc DX + Out DX, AL + Mov AL, 4+32 ; 16-bit data, IRQ enabled + Add DL, 2 + Out DX, AL + +; Call GUSDelay +; Out DX, AL + + Sub DL, 3 + + Mov AL, 1 ; Select voice 1 + Out DX, AL + +; Call GUSDelay + + Inc DX + Xor AL, AL + Out DX, AL + Mov AL, 4+8 ; 16-bit, Loop + Add DL, 2 + Out DX, AL + +; Call GUSDelay +; Out DX, AL + + Jmp StartGUSEnd + +StartGUSMono: ; Uses voice 0 + Mov DX, GUSVoiceSelect + Xor AL, AL + Out DX, AL + Call GUSDelay + Inc DX + + Mov AL, 1 ; Freq control + Out DX, AL + Inc DX + Mov AX, 0000010000000000b + Out DX, AX + Dec DX + + Mov AL, 2 ; Starting location high + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 3 ; Starting location low + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 4 ; End location high + Out DX, AL + Mov AX, HALFENDLOCATIONHIGH + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 5 ; End location low + Out DX, AL + Mov AX, HALFENDLOCATIONLOW + Inc DX + Out DX, AX + Dec DX + + Mov AL, 9 ; Current volume + Out DX, AL + Mov AX, 0EFF0h + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Ah ; Current location high + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Bh ; Current location low + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Ch ; Pan position + Out DX, AL + Mov AL, 8 ; Central. + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 0Dh ; Set rollover condition + Out DX, AL + Mov AL, 4+2+1 ; Rollover + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Xor AL, AL + Out DX, AL + Mov AL, 4+32 ; 16-bit data, IRQ enabled + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + +StartGUSEnd: + StI + + Pop ES + PopA + + Ret + + +EndP StartGUS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + +RelocationEnd: + Mov AX, BasePort + Call ResetGUS + + ; SetupMIDI + Mov DX, BasePort + Inc DH + Mov AL, 0FFh + Out DX, AL + Mov AL, 0FCh + Out DX, AL + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + ; Allocate MixSegment first + Mov AH, 48h + Mov BX, 3859+(DMABUFFERLENGTH*2)/16 + ; 3859 = (256*2*65+8*44100/(.4*31))/16 + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset GUSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, 3859 + Mov DMASegment, AX + + Call SetIRQ + Call GetSBMixConst + Call GetTempo + Call SetTempo + + Mov SI, Offset GUSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 200 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov AX, BasePort + Call ResetGUS + + Mov DX, BasePort + Inc DH + Mov AL, 0FFh + Out DX, AL ; Stop MIDI + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Mov DX, CS:GUSVoiceSelect + Xor AL, AL + Out DX, AL + Inc DX + Mov AL, 8Ah + Out DX, AL + Inc DX + In AX, DX + ShL EAX, 16 + Dec DX + Mov AL, 8Bh + OUt DX, AL + Inc DX + In AX, DX + ShR EAX, 9 + Mov CS:Voice0Position, EAX + + Mov DX, CS:GUSVoiceSelect + Mov AL, 1 + Out DX, AL + Inc DX + Mov AL, 8Ah + Out DX, AL + Inc DX + In AX, DX + ShL EAX, 16 + Dec DX + Mov AL, 8Bh + OUt DX, AL + Inc DX + In AX, DX + ShR EAX, 9 + Mov CS:Voice1Position, EAX + + Call [CS:UARTBufferEmpty] + JNC MIDIEnd + + Mov DX, [CS:BasePort] + Inc DH + In AL, DX + Test AL, 1 + JZ MIDIEnd + + Inc DX + In AL, DX + Cmp AL, 0F0h + JAE MIDIEnd + + Call [CS:UARTSend] + +MIDIEnd: + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov CS:Stereo, AL + Call StartGUS + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset GUSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/GUSNRAMP.INC b/it/SoundDrivers/GUSNRAMP.INC new file mode 100755 index 0000000..02020e2 --- /dev/null +++ b/it/SoundDrivers/GUSNRAMP.INC @@ -0,0 +1,27 @@ +; + +Proc SetGUSVolume ; BX = new volume + + ; To do: + ; 1) Set ramp start + ; 2) Set ramp end + ; 3) Set current volume + ; 4) Start ramp + ; 5) Save new volume. + + Mov AL, 9 + Out DX, AL + + Add BX, BX + Mov AX, [CS:GUSVolumeTable+BX] + Inc DX + Out DX, AX + Call GUSDelay + Out DX, AX + Dec DX + + Ret + +EndP SetGUSVolume + + diff --git a/it/SoundDrivers/GUSNRIC.INC b/it/SoundDrivers/GUSNRIC.INC new file mode 100755 index 0000000..3863e2f --- /dev/null +++ b/it/SoundDrivers/GUSNRIC.INC @@ -0,0 +1,415 @@ +; + +Proc SetGUSRegisters ; Given DS:SI, CX + + Mov ES, CS:SongDataArea + + Push CX + Push SI + + Xor AX, AX + +GetOffsetLoop: + Push AX + Push CX + + Mov DX, GUSVoiceSelect + Out DX, AL ; OK.. now to play with this + ; voice. + Call GUSDelay + + Inc DL ; DX = select rego + + Mov BX, [SI] + Test BH, 2 + JZ GetOffsetLoop2 + + Mov BX, 200h + Mov [SI], BX + +GetOffsetLoop2: + Test BL, 1 ; Channel not on! + JZ GetOffsetLoop1 + Test BH, 1 + JZ GetOffsetLoop3 ; Prev 1. + + Xor BX, BX + Call SetGUSVolume + + Mov AL, 80h + Out DX, AL + Add DL, 2 + In AL, DX + Sub DL, 2 + Mov AH, AL + And AX, 400h + Out DX, AL ; AL = 0 (Mode control) + Mov AL, 3 + Or AL, AH + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Jmp GetOffsetLoop1 + +GetOffsetLoop3: + Mov EAX, [SI+4Ch] + Mov [SI+2Ch], EAX + + Mov AL, 8Ah + Out DX, AL + + Inc DX + In AX, DX + Dec DX + + And AH, 31 + ShL EAX, 16 ; Load high part of EAX + + Mov AL, 8Bh + Out DX, AL + Inc DX + In AX, DX + ; EAX = 000OOOOO OOOOOOOO OOOOOOOF FFFFFFFF + ; Need: 00000000 0000OOOO OOOOOOOO OOOOOOOO + + ShR EAX, 9 + ; EAX contains current loc. + ; Convert to Offset (in sample) + MovZX EBX, Byte Ptr [SI+36h] + Sub EAX, [CS:GUSDataTable+EBX*4] + Push CX + + Mov CL, CS:Compress + ShL EAX, CL + + Pop CX + Mov [SI+4Ch], EAX + +GetOffsetLoop1: + Add SI, SLAVECHANNELSIZE + + Pop CX + Pop AX + + Inc AX + Loop GetOffsetLoop + + Pop SI + Pop CX + + Xor AX, AX + +SetGUSRegisters1: + Push AX + Push CX + + Mov DX, GUSVoiceSelect + Out DX, AL ; OK.. now to play with this + ; voice. + Call GUSDelay + + Mov CX, [SI] ; CX = flags. + Inc DL ; DX = select rego + +SetGUSRegisters21: + Test CL, 32 ; Frequency change + JZ SetGUSRegisters7 + + Push DX + + Mov EAX, [SI+10h] ; EAX = freq. + + Push CX + Mov CL, CS:Compress + ShR EAX, CL + Pop CX + + Xor EDX, EDX + MovZX EBX, MixSpeed + + Div EBX ; EAX = I portion. + + Test EAX, Not 63 + JNZ SetGUSRegisters6 + + Push EAX + + Xor EAX, EAX + Div EBX + + Pop EBX ; EBX:EAX = IIII FFFF etc. + + SHRD EAX, EBX, 6 + + ; Have: IIIIIIII IIIIIIII FFFFFFFF FFFFFFFF + ; Req: IIIIIIFF FFFFFFF0 + + Pop DX + Mov AL, 1 + Out DX, AL + + ShR EAX, 16 + Add AX, 1 + SBB AX, 0 ; Just in case! + And AX, Not 1 + + Inc DX + Out DX, AX + Dec DX + + Jmp SetGUSRegisters7 + +SetGUSRegisters6: + Mov CH, 2 ; Signify to turn off channel + Pop DX + +SetGUSRegisters7: + MovZX BX, Byte Ptr [SI+36h] ; BX = sample number. + Cmp BL, 99 + JA SetGUSRegisters20 + + ShL BX, 2 ; GUSDataTable+BX = position + + Cmp DWord Ptr [CS:GUSDataTable+BX], 0FFFFFFFFh + JNE SetGUSRegisters10 + +SetGUSRegisters20: + Mov CH, 2 + Jmp SetGUSRegisters9 + +SetGUSRegisters10: + Test CH, 5 ; Loop changed?!??!? + JZ SetGUSRegisters8 + + Mov AL, 3 ; Starting location low. + Out DX, AL + + Mov EAX, [SI+40h] + Call GUSGetAddress + + ; Reqd: ...OOOOO OOOOOOOO OOOOOOOI III..... + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 2 ; Starting location high + Out DX, AL + + ShR EAX, 16 + Inc DX + Out DX, AX + Dec DX + + ; Ending location... + Mov AL, 5 ; Ending location low + Out DX, AL + + Mov EAX, [SI+44h] + Call GUSGetAddress + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 4 ; Ending location high + Out DX, AL + + SHR EAX, 16 + Inc DX + Out DX, AX + Dec DX + +SetGUSRegisters8: + Test CH, 1 ; Do Current position? + JZ SetGUSRegisters9 + + Mov AL, 0Bh ; Current location LOW + Out DX, AL + + Mov EAX, [SI+4Ch] + Mov [SI+2Ch], EAX + + ; EAX = OOOOOOOO OOOOOOOO OOOOOOOO OOOOOOOO + ; Req: xxxOOOOO OOOOOOOO OOOOOOOF FFFFFFFF + Call GUSGetAddress + + Mov DI, AX + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Ah ; Current location HIGH + Out DX, AL + + SHR EAX, 16 + Inc DX + Out DX, AX + Call GUSDelay + Out DX, AX + Dec DX + + Mov AL, 0Bh + Out DX, AL + + Mov AX, DI + Inc DX + Out DX, AX + Dec DX + +SetGUSRegisters9: + Test CL, 64 ; New volume?? + JZ SetGUSPanning + +SetGUSRegisters23: + Xor BX, BX + Test CH, 8 + JNZ SetGUSRegistersMuted + + Mov BL, Byte Ptr [SI+20h] ; BL = volume, 0->128 + +SetGUSRegistersMuted: + Call SetGUSVolume + + +SetGUSPanning: + Test CH, 128 ; New panning? + JZ SetGUSRegisters5 + + Mov AL, 0Ch ; Set panning. + Out DX, AL + + Test CS:Stereo, 1 + JZ SetGUSRegisters3 + + Mov AL, [SI+37h] + Cmp AL, 100 + JNE SetGUSRegisters4 + +SetGUSRegisters3: + Mov AL, 32 ; Surround goes to mono :( + +SetGUSRegisters4: ; AL = 0->64 + ShR AL, 1 ; AL = 0->32 + Sub AL, 1 + AdC AL, 0 ; AL = 0->31 + ShR AL, 1 + + Add DL, 2 + Out DX, AL + Sub DL, 2 + +SetGUSRegisters5: + ; Now for control register. + ; If CH | 2, then turn rego OFF + ; If CH | 5, then turn rego ON + ; If CL | 1, then check channel + Test CH, 2 + JNZ SetGUSRegisters11 + + Test CH, 5 + JNZ SetGUSRegisters12 + + Test CL, 1 + JZ SetGUSRegisters13 + + Mov AL, 80h ; Read voice control + Out DX, AL + + Add DL, 2 + In AL, DX + Sub DL, 2 + + Test AL, 1 + JZ SetGUSRegisters13 + + Xor BX, BX + Call SetGUSVolume + + Jmp SetGUSRegisters14 + +SetGUSRegisters11: + ; Turn off. + Xor AL, AL + Out DX, AL ; AL = 0 (Mode control) + Mov AL, 2 + Add DL, 2 + + Mov AH, [SI+18h] ; 16 bit? + Add AH, AH + Or AL, AH + + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Xor BX, BX + Call SetGUSVolume + +SetGUSRegisters14: + Test CL, 1 + JZ SetGUSRegisters13 + + Xor CX, CX ; Turn off channel + Test Byte Ptr [SI+3Ah], 80h + JNZ SetGUSRegisters13 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + + Jmp SetGUSRegisters13 + +SetGUSRegisters12: ; Turn on + Xor AL, AL + Out DX, AL + + Mov AL, [SI+0Ah] + + Cmp CS:Convert16To8Bit, 0 + JNZ SetGUSRegistersNo16Bit + + Mov AH, [SI+18h] ; 16 bit? + Add AH, AH + Or AL, AH + +SetGUSRegistersNo16Bit: + Test CL, 1 + JNZ SetGUSRegisters15 + + Mov AL, 2 + Xor CX, CX + +SetGUSRegisters15: + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + +SetGUSRegisters13: + And CX, 0111100010011111b ; Turns off: + ; 1) Freq, pan & vol recalc + ; 2) New note/note stop/loop cha + + Mov [SI], CX + + Add SI, SLAVECHANNELSIZE + +; Call CheckMIDI + + Pop CX + Pop AX + + Inc AX + Dec CX + JNZ SetGUSRegisters1 + + Ret + + +EndP SetGUSRegisters + diff --git a/it/SoundDrivers/GUSPNPM.ASM b/it/SoundDrivers/GUSPNPM.ASM new file mode 100755 index 0000000..a2c9d5d --- /dev/null +++ b/it/SoundDrivers/GUSPNPM.ASM @@ -0,0 +1,2270 @@ +; +; Windows Sound System Driver, with GUS PnP detection. +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +PNPVENDORID EQU 0100561Eh + +DMASize DW 2048 + +WSSMsg DB "Gravis UltraSound PnP Codec", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Gravis UltraSound PnP Codec", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Gravis UltraSound PnP Codec reinitialised", 0 + +DriverName DB "ITGUSPNP.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW 0 + +WSSHeaderLine DW 10 + DB "Gravis UltraSound PnP Codec Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 19, 48 + DB 21h + DB "Gravis UltraSound PnP Codec Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 2 Dup (56) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + + Mov AX, 1 + Ret + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 14 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Inc DX + Inc DX + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 75h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Mov AX, 202h + Call PnP_WriteData + Ret + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + + Mov EAX, 'Jeff' + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 2 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB WSSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +WSSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Call UpdateSoundcardVariables + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + Push AX DX + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX AX + Ret + +EndP UpdatesoundcardVariables + Assume DS:Nothing + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + Call UpdateSoundcardVariables + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/GUSPNPMX.ASM b/it/SoundDrivers/GUSPNPMX.ASM new file mode 100755 index 0000000..a94e740 --- /dev/null +++ b/it/SoundDrivers/GUSPNPMX.ASM @@ -0,0 +1,1769 @@ +; +; Windows Sound System Driver, with GUS PnP detection, MMX mixing. +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +OUTPUTFILTERENABLED EQU 0 + +PNPVENDORID EQU 0100561Eh + +FPSave DB 128 Dup (0) + +DMASize DW 2048 + +WSSMsg DB "Gravis UltraSound PnP MMX", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Gravis UltraSound PnP MMX", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Gravis UltraSound PnP Codec reinitialised", 0 + +DriverName DB "ITGUSPNP.MMX", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 12 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 12 + DW Near Ptr MasterVolumeRight ; 13 + + DW 0 + + +WSSHeaderLine DW 10 + DB "Gravis UltraSound PnP MMX Codec Driver", 0 + +DriverText DW 1 + DB 19, 48 + DB 21h + DB "Gravis UltraSound PnP Codec Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 13, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 12, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + DW 0 + +MixModeButton1 DW 2 + DW 13, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " MMX, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " MMX, Volume Ramped", 0 + +MixModeButton4 DW 2 + DW 8, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " MMX, Filtered", 0 + +VolumeTable DB 2 Dup (56) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label + +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + + +include nodebug.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Trace "GUSPnP MMX: SetMixMode" + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 14 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Inc DX + Inc DX + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 75h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectMMX + + PushFD + Pop EAX + Mov EBX, EAX + Xor EAX, 00200000h + Push EAX + PopFD + PushFD + Pop EAX + Cmp EAX, EBX + JZ DetectMMXFail + + Mov EAX, 1 + DB 0Fh, 0A2h ; CPUID + Test EDX, 800000h + JZ DetectMMXFail + + ClC + Ret + +DetectMMXFail: + StC + Ret + +EndP DetectMMX + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Call DetectMMX + JC DetectCard_MMXNotFound + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + Mov AX, 202h + Call PnP_WriteData + +DetectCard_MMXNotFound: + StC + Ret + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + + Mov EAX, 'Jeff' + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +include mmxmsam.inc + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 2 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + FNSave [FPSave] + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB WSSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +WSSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Mov BX, DMASize ; BX = bytes required + Add DI, AX + + ShR BX, 1 + ; BX = samples required + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + FNRstor [CS:FPSave] + + Pop ES + Pop DS + PopAD + IRet + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Trace "GUSPnP MMX: StopSound" + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Trace "GUSPnP MMX: StartSound" + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Trace "GUSPnP MMX: InitSound" + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, (DMABUFFERLENGTH*2)/16 + 5 + Mov BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Call UpdateSoundcardVariables + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Trace "GUSPnP MMX: SetStereoCall" + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + Trace "GUSPnP MMX: Driver Screen" + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + Push AX DX + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX AX + Ret + +EndP UpdatesoundcardVariables + Assume DS:Nothing + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + Call UpdateSoundcardVariables + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h +; Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: +; Call UARTOut + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 + DW 3 + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/GUSRAMP.INC b/it/SoundDrivers/GUSRAMP.INC new file mode 100755 index 0000000..15c3271 --- /dev/null +++ b/it/SoundDrivers/GUSRAMP.INC @@ -0,0 +1,114 @@ + +Proc SetGUSVolume ; BX = new volume + + ; To do: + ; 1) Set ramp start + ; 2) Set ramp end + ; 3) Set current volume + ; 4) Start ramp + ; 5) Save new volume. + + Push BX + Push CX + + Mov AL, 0Dh + Out DX, AL + + Mov AL, 3 ; Stop Ramp! + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Add BX, BX + Mov CX, [CS:GUSVolumeTable+BX] ; CX = new volume + Mov BX, [SI+2] + Add BX, BX + Mov BX, [CS:GUSVolumeTable+BX] ; BX = old volume + + Cmp BX, CX + JNE SetGUSVolume2 + + Mov AL, 89h + Out DX, AL + Inc DX + In AX, DX + Dec DX + + Mov BX, AX ; BX = old volume + +SetGUSVolume2: + + Push BX ; Old volume on stack + + Xor AH, AH ; Ramp up + Cmp CX, BX + JAE SetGUSVolume1 + + XChg BX, CX + Mov AH, 40h ; Ramp down + +SetGUSVolume1: + Mov AL, 6 ; Ramp rate + Out DX, AL + + Mov AL, Byte Ptr CS:UsedChannels + ShR AL, 1 + Add AL, 16 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 7 ; Ramp start + Out DX, AL + + Mov AL, BH + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Mov AL, 8 ; Ramp end + Out DX, AL + + Mov AL, CH + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Mov AL, 9 + Out DX, AL + + Pop BX ; BX = old volume + XChg BX, AX + + Inc DX + Out DX, AX + Call GUSDelay + Out DX, AX + Dec DX + + Mov AL, 0Dh ; Ramp control + Out DX, AL + + Mov AL, BH + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Pop CX + Pop BX + + Mov [SI+2], BX + + Ret + +EndP SetGUSVolume + + diff --git a/it/SoundDrivers/GUSRIC.INC b/it/SoundDrivers/GUSRIC.INC new file mode 100755 index 0000000..cad6258 --- /dev/null +++ b/it/SoundDrivers/GUSRIC.INC @@ -0,0 +1,651 @@ + +Proc SetGUSRegisters ; Given DS:SI, CX + + Mov ES, CS:SongDataArea + + Push CX + Push SI + + Xor AX, AX + +GetOffsetLoop: + Push AX + Push CX + + Mov DX, GUSVoiceSelect + Out DX, AL ; OK.. now to play with this + ; voice. + Call GUSDelay + + Inc DL ; DX = select rego + + Mov BX, [SI] + Test BH, 2 + JZ GetOffsetLoop2 + + Mov BX, 200h + Mov [SI], BX + +GetOffsetLoop2: + Test BL, 1 ; Channel not on! + JZ GetOffsetLoop1 + + Test BH, 1 + JZ GetOffsetLoop3 ; Prev 1. + + Xor BX, BX + Call SetGUSVolume + + Mov AL, 80h + Out DX, AL + Add DL, 2 + In AL, DX + Sub DL, 2 + Mov AH, AL + + And AX, 400h + Out DX, AL ; AL = 0 (Mode control) + Mov AL, 3 + Or AL, AH + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Jmp GetOffsetLoop1 + +GetOffsetLoop3: + Mov EAX, [SI+4Ch] + Mov [SI+2Ch], EAX + + Mov AL, 8Ah + Out DX, AL + + Inc DX + In AX, DX + Dec DX + + And AH, 31 + ShL EAX, 16 ; Load high part of EAX + + Mov AL, 8Bh + Out DX, AL + Inc DX + In AX, DX + ; EAX = 000OOOOO OOOOOOOO OOOOOOOF FFFFFFFF + ; Need: 00000000 0000OOOO OOOOOOOO OOOOOOOO + + ShR EAX, 9 + ; EAX contains current loc. + ; Convert to Offset (in sample) + MovZX EBX, Byte Ptr [SI+36h] + Sub EAX, [CS:GUSDataTable+EBX*4] + Push CX + + Mov CL, CS:Compress + ShL EAX, CL + + Pop CX + Mov [SI+4Ch], EAX + Cmp EAX, [SI+44h] + JBE GetOffsetLoop1 + + Cmp Byte Ptr [SI+0Ah], 0 + JNE GetOffsetLoop1 + + Or Word Ptr [SI], 200h + +GetOffsetLoop1: + Add SI, SLAVECHANNELSIZE + + Pop CX + Pop AX + + Inc AX + Dec CX + JNZ GetOffsetLoop + + Pop SI + Pop CX + +; + + Push CX + Push SI + + Push SI + + Mov BX, 1 + Mov DX, 1 + +ReinitChannels1: + Test Byte Ptr [SI], 1 + JZ ReinitChannels2 + + Mov BX, DX + +ReinitChannels2: + Inc DX + Add SI, 128 + Loop ReinitChannels1 + + Pop SI + + Mov CX, BX + + Cmp BX, 14 + JAE RIC3 + + Mov BX, 14 + +RIC3: + Cmp BX, 32 + JB RIC4 + + Mov BX, 32 + +RIC4: + Cmp BX, CS:UsedChannels + JE EndOfFreqChange + + JA RIC5 + Mov BX, CS:UsedChannels + Dec BX + +RIC5: + ; Now.. get new mixspeed. + ; Prepare all new frequencies + ; then write all active voices + ; + all new frequencies. + ; BX = num channels... + Push BX + Push BX + Push BX + + Add BX, BX ; BX = pointer into mixtable. + MovZX EBX, [CS:GUSMixTable+BX-28] + Mov CS:MixSpeed, BX + + Push CX + Push SI + +PrepareNewFreq2: + Test Byte Ptr [SI], 1 + JZ PrepareNewFreq3 + + Test Word Ptr [SI], 100h + JNZ PrepareNewFreq3 + + Mov EAX, [SI+10h] ; EAX = freq. + Push CX + Mov CL, CS:Compress + ShR EAX, CL + Pop CX + Xor EDX, EDX + + Div EBX ; EAX = I portion. + + Push EAX + Xor EAX, EAX + Div EBX + + Pop EDX ; EDX:EAX = IIII FFFF etc. + + SHRD EAX, EDX, 22 + Add AX, 1 + SBB AX, 0 ; Just in case! + And AX, Not 1 + Mov [SI+4], AX + +PrepareNewFreq3: + Add SI, 128 + Loop PrepareNewFreq2 + + Pop SI + Pop CX + + Pop BX + + Mov DI, CS:UsedChannels + Cmp DI, BX + JB KillExtraChannels1 + + Mov DI, BX + Mov BX, 32 +; XChg DI, BX + +KillExtraChannels1: + Cmp DI, BX + JAE KillExtraChannels2 + + Mov DX, GUSVoiceSelect + Mov AX, DI + Out DX, AL + + Inc DX ; Select rego + + Mov AL, 0Dh ; Volume Ramp. + Out DX, AL + + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Xor AL, AL + Out DX, AL ; AL = 0 (Mode control) + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 9 + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Ch ; Set panning. + Out DX, AL + Mov AL, 8 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Comment ~ + + Call GUSDelay + + Mov AL, 0Dh ; Volume Ramp. + Out DX, AL + + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Xor AL, AL + Out DX, AL ; AL = 0 (Mode control) + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 9 + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Ch ; Set panning. + Out DX, AL + Mov AL, 8 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + ~ + + Inc DI + Jmp KillExtraChannels1 + +KillExtraChannels2: + Xor BX, BX ; BX = channel number + +PrepareNewFreq4: + Mov DX, GUSVoiceSelect + Mov AL, BL + Out DX, AL + Inc DX ; Select rego + + Test Byte Ptr [SI], 1 + JZ PrepareNewFreq5 + + Test Word Ptr [SI], 120h ; New note or new freq? + JNZ PrepareNewFreq5 + + Or Byte Ptr [SI], 2h + + Mov AL, 1 + Out DX, AL + Inc DX + Mov AX, [SI+4] + Out DX, AX + +PrepareNewFreq5: + Inc BX + Add SI, 128 + Loop PrepareNewFreq4 + + Mov DX, GUSRegisterSelect + Mov AL, 0Eh + Out DX, AL + Add DL, 2 + Pop AX + Dec AL + Or AL, 0C0h + Out DX, AL + + Pop CS:UsedChannels + +EndOfFreqChange: + + Pop SI + Pop CX + +; + Xor AX, AX + +SetGUSRegisters1: + Push AX + Push CX + + Mov DX, GUSVoiceSelect + Out DX, AL ; OK.. now to play with this + ; voice. + Call GUSDelay + + Mov CX, [SI] ; CX = flags. + Inc DL ; DX = select rego + +SetGUSRegisters21: + Test CL, 32 ; Frequency change + JZ SetGUSRegisters7 + + Push DX + + Mov EAX, [SI+10h] ; EAX = freq. + + Push CX + Mov CL, CS:Compress + ShR EAX, CL + Pop CX + + Xor EDX, EDX + MovZX EBX, MixSpeed + + Div EBX ; EAX = I portion. + + Test EAX, Not 63 + JNZ SetGUSRegisters6 + + Push EAX + + Xor EAX, EAX + Div EBX + + Pop EBX ; EBX:EAX = IIII FFFF etc. + + SHRD EAX, EBX, 6 + + ; Have: IIIIIIII IIIIIIII FFFFFFFF FFFFFFFF + ; Req: IIIIIIFF FFFFFFF0 + + Pop DX + Mov AL, 1 + Out DX, AL + + ShR EAX, 16 + Add AX, 1 + SBB AX, 0 ; Just in case! + And AX, Not 1 + + Inc DX + Out DX, AX + Dec DX + + Jmp SetGUSRegisters7 + +SetGUSRegisters6: + Mov CH, 2 ; Signify to turn off channel + Pop DX + +SetGUSRegisters7: + MovZX BX, Byte Ptr [SI+36h] ; BX = sample number. + Cmp BL, 99 + JA SetGUSRegisters20 + + ShL BX, 2 ; GUSDataTable+BX = position + + Cmp DWord Ptr [CS:GUSDataTable+BX], 0FFFFFFFFh + JNE SetGUSRegisters10 + +SetGUSRegisters20: + Mov CH, 2 + Jmp SetGUSRegisters9 + +SetGUSRegisters10: + Test CX, 502h ; Loop changed?!??!? + JZ SetGUSRegisters8 + + Mov AL, 3 ; Starting location low. + Out DX, AL + + Mov EAX, [SI+40h] + Call GUSGetAddress + + ; Reqd: ...OOOOO OOOOOOOO OOOOOOOI III..... + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 2 ; Starting location high + Out DX, AL + + ShR EAX, 16 + Inc DX + Out DX, AX + Dec DX + + ; Ending location... + Mov AL, 5 ; Ending location low + Out DX, AL + + Mov EAX, [SI+44h] + Call GUSGetAddress + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 4 ; Ending location high + Out DX, AL + + SHR EAX, 16 + Inc DX + Out DX, AX + Dec DX + +SetGUSRegisters8: + Test CH, 1 ; Do Current position? + JZ SetGUSRegisters9 + + Mov AL, 0Bh ; Current location LOW + Out DX, AL + + Mov EAX, [SI+4Ch] + Mov [SI+2Ch], EAX + + ; EAX = OOOOOOOO OOOOOOOO OOOOOOOO OOOOOOOO + ; Req: xxxOOOOO OOOOOOOO OOOOOOOF FFFFFFFF + Call GUSGetAddress + + Mov DI, AX + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Ah ; Current location HIGH + Out DX, AL + + SHR EAX, 16 + Inc DX + Out DX, AX + Call GUSDelay + Out DX, AX + Dec DX + + Mov AL, 0Bh + Out DX, AL + + Mov AX, DI + Inc DX + Out DX, AX + Dec DX + +SetGUSRegisters9: + Test CL, 64 ; New volume?? + JZ SetGUSPanning + +SetGUSRegisters23: + Xor BX, BX + Test CH, 8 + JNZ SetGUSRegistersMuted + + Mov BL, Byte Ptr [SI+20h] ; BL = volume, 0->128 + +SetGUSRegistersMuted: + Call SetGUSVolume + + +SetGUSPanning: + Test CH, 128 ; New panning? + JZ SetGUSRegisters5 + + Mov AL, 0Ch ; Set panning. + Out DX, AL + + Test CS:Stereo, 1 + JZ SetGUSRegisters3 + + Mov AL, [SI+37h] + Cmp AL, 100 + JNE SetGUSRegisters4 + +SetGUSRegisters3: + Mov AL, 32 ; Surround goes to mono :( + +SetGUSRegisters4: ; AL = 0->64 + ShR AL, 1 ; AL = 0->32 + Sub AL, 1 + AdC AL, 0 ; AL = 0->31 + ShR AL, 1 + + Add DL, 2 + Out DX, AL + Sub DL, 2 + +SetGUSRegisters5: + ; Now for control register. + ; If CH | 2, then turn rego OFF + ; If CH | 5, then turn rego ON + ; If CL | 1, then check channel + Test CH, 2 + JNZ SetGUSRegisters11 + + Test CH, 5 + JNZ SetGUSRegisters12 + + Test CL, 1 + JZ SetGUSRegisters13 + + Mov AL, 80h ; Read voice control + Out DX, AL + + Add DL, 2 + In AL, DX + Sub DL, 2 + + Test AL, 1 + JZ SetGUSRegisters13 + + Xor BX, BX + Call SetGUSVolume + + Jmp SetGUSRegisters14 + +SetGUSRegisters11: + ; Turn off. + Xor AL, AL + Out DX, AL ; AL = 0 (Mode control) + Mov AL, 2 + Add DL, 2 + + Mov AH, [SI+18h] ; 16 bit? + Add AH, AH + Or AL, AH + + Out DX, AL + Call GUSDelay + Out DX, AL + Sub DL, 2 + + Xor BX, BX + Call SetGUSVolume + +SetGUSRegisters14: + Test CL, 1 + JZ SetGUSRegisters13 + + Xor CX, CX ; Turn off channel + Test Byte Ptr [SI+3Ah], 80h + JNZ SetGUSRegisters13 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + + Jmp SetGUSRegisters13 + +SetGUSRegisters12: ; Turn on + Xor AL, AL + Out DX, AL + + Mov AL, [SI+0Ah] + + Cmp CS:Convert16To8Bit, 0 + JNZ SetGUSRegistersNo16Bit + + Mov AH, [SI+18h] ; 16 bit? + Add AH, AH + Or AL, AH + +SetGUSRegistersNo16Bit: + Test CL, 1 + JNZ SetGUSRegisters15 + + Mov AL, 2 + Xor CX, CX + +SetGUSRegisters15: + Add DL, 2 + Out DX, AL + Call GUSDelay + Out DX, AL + +SetGUSRegisters13: + And CX, 0111100010011111b ; Turns off: + ; 1) Freq, pan & vol recalc + ; 2) New note/note stop/loop cha + + Mov [SI], CX + + Add SI, SLAVECHANNELSIZE + + Pop CX + Pop AX + + Inc AX + Dec CX + JNZ SetGUSRegisters1 + + Ret + + +EndP SetGUSRegisters + + diff --git a/it/SoundDrivers/IRQ.INC b/it/SoundDrivers/IRQ.INC new file mode 100755 index 0000000..464402b --- /dev/null +++ b/it/SoundDrivers/IRQ.INC @@ -0,0 +1,20 @@ + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + diff --git a/it/SoundDrivers/IWCODEC.ASM b/it/SoundDrivers/IWCODEC.ASM new file mode 100755 index 0000000..7598505 --- /dev/null +++ b/it/SoundDrivers/IWCODEC.ASM @@ -0,0 +1,2302 @@ +; +; Windows Sound System Driver, for GUS PnP +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +DMASize DW 2048 + +WSSMsg DB "Using GUS CS4231 Codec", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Using GUS CS4231 Codec", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "GUS Codec reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITGUSMAX.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITGUSMAX.DRV", 0 + +DriverName DB "ITGUSMAX.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW 0 + +WSSHeaderLine DW 10 + DB "GUS CS4231 Codec Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "GUS CS4231 Codec Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 2 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 16 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Inc DX + Inc DX + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov AX, 407h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Test AX, AX + JZ PnP_IsolateNextCard + + Mov SAM9407Port, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + Mov DX, + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Mov EAX, 'Jeff' + ClC + +DetectCardEnd: + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 2 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB WSSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +WSSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/IWDRV.ASM b/it/SoundDrivers/IWDRV.ASM new file mode 100755 index 0000000..d29ee51 --- /dev/null +++ b/it/SoundDrivers/IWDRV.ASM @@ -0,0 +1,2713 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +;************************** + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;************** Local variables **************** + +SLAVECHANNELSIZE EQU 128 +MixSpeed = 44100 + +IWReinitMsg DB "Interwave reinitialised", 0 + +IWID DB "AMD Interwave, Revision " +RevisionLetter DB " ", 13 + DB "Port ", 0FDh, "Xh, ", 0FDh, "Dk Memory", 0 + +IWID2 DB "AMD Interwave, Revision " +RevisionLetter2 DB " ", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, ", 0FDh, "Dk RAM", 0 + +IWFreeMsg DB "FreeIW ", 0FDh, "Dk", 0 + +IWVolumeTable Label Word + DW 00000h, 0A0C0h, 0ABE0h, 0B250h, 0B6F0h, 0BA80h, 0BD70h, 0BFE0h + DW 0C200h, 0C3F0h, 0C5A0h, 0C720h, 0C880h, 0C9D0h, 0CB00h, 0CC10h + DW 0CD20h, 0CE10h, 0CF00h, 0CFE0h, 0D0B0h, 0D180h, 0D230h, 0D2F0h + DW 0D3A0h, 0D440h, 0D4E0h, 0D580h, 0D610h, 0D6A0h, 0D730h, 0D7B0h + DW 0D830h, 0D8B0h, 0D930h, 0D9A0h, 0DA20h, 0DA90h, 0DAF0h, 0DB60h + DW 0DBC0h, 0DC30h, 0DC90h, 0DCF0h, 0DD50h, 0DDB0h, 0DE00h, 0DE60h + DW 0DEB0h, 0DF00h, 0DF60h, 0DFB0h, 0E000h, 0E050h, 0E090h, 0E0E0h + DW 0E130h, 0E170h, 0E1C0h, 0E200h, 0E240h, 0E290h, 0E2D0h, 0E310h + DW 0E350h, 0E390h, 0E3D0h, 0E410h, 0E440h, 0E480h, 0E4C0h, 0E4F0h + DW 0E530h, 0E560h, 0E5A0h, 0E5D0h, 0E610h, 0E640h, 0E670h, 0E6B0h + DW 0E6E0h, 0E710h, 0E740h, 0E770h, 0E7A0h, 0E7D0h, 0E800h, 0E830h + DW 0E860h, 0E890h, 0E8C0h, 0E8F0h, 0E920h, 0E940h, 0E970h, 0E9A0h + DW 0E9D0h, 0E9F0h, 0EA20h, 0EA40h, 0EA70h, 0EAA0h, 0EAC0h, 0EAF0h + DW 0EB10h, 0EB40h, 0EB60h, 0EB80h, 0EBB0h, 0EBD0h, 0EBF0h, 0EC20h + DW 0EC40h, 0EC60h, 0EC90h, 0ECB0h, 0ECD0h, 0ECF0h, 0ED10h, 0ED40h + DW 0ED60h, 0ED80h, 0EDA0h, 0EDC0h, 0EDE0h, 0EE00h, 0EE20h, 0EE40h + DW 0EE60h + +OffsetTable Label Word + DW 0FFF0h, 03000h, 02800h, 02350h, 02000h, 01D60h, 01B50h, 01980h + DW 01800h, 016A0h, 01560h, 01450h, 01350h, 01260h, 01180h, 010B0h + DW 01000h, 00F40h, 00EA0h, 00E00h, 00D60h, 00CD0h, 00C50h, 00BC0h + DW 00B50h, 00AD0h, 00A60h, 009F0h, 00980h, 00920h, 008B0h, 00850h + DW 00800h, 007A0h, 00740h, 006F0h, 006A0h, 00650h, 00600h, 005B0h + DW 00560h, 00520h, 004D0h, 00490h, 00450h, 00410h, 003C0h, 00390h + DW 00350h, 00310h, 002D0h, 00290h, 00260h, 00220h, 001F0h, 001B0h + DW 00180h, 00150h, 00120h, 000F0h, 000B0h, 00080h, 00050h, 00020h + DW 00000h + + +IWMemory DW 0 ; kb of memory on IW +IWRegisterSelect DW 0 +IWVoiceSelect DW 0 +IWUpdateTimer DW 0 +IWUpdateCount DW 0 +IWMemoryFree DD 0 +IWOutputPort DW 0 +IWUpdateFlag DB 0 +IWMemorySegmented DB 0 + +IWLMCFI DW 0 +IWBankTable DB 0, 0, 0, 0 + +IWBank1 DD 0 +IWBank2 DD 0 +IWBank3 DD 0 +IWBank4 DD 0 + +OldIRQHandler DD 0 + +Convert16To8Bit DB 0 + DB 0 +Compress DB 0 + DB 0 +Stereo DB 0 + +NewIWLMCFI DW 0 + +IWDataTable DD 100 Dup (0FFFFFFFFh) +Revision DB 0 + +BankConfigs Label ; 12 configs.. +; DB 64, 64, 64, 64 ; 12 +; DB 64, 64, 0, 0 ; 11 + DB 64, 0, 0, 0 ; 10 + DB 16, 16, 16, 16 ; 9 + DB 16, 16, 0, 0 ; 8 + DB 16, 0, 0, 0 ; 7 + DB 4, 4, 16, 16 ; 6 + DB 4, 4, 16, 0 ; 5 + DB 4, 16, 16, 16 ; 4 + DB 4, 16, 0, 0 ; 3 + DB 4, 4, 4, 4 ; 2 + DB 4, 4, 0, 0 ; 1 + DB 4, 0, 0, 0 ; 0 + + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +IMR DW 0 + +; + +IWScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr GravisHeaderLine + + DW SampleText ; 4 + + DW ConvertSampleText + DW ConvertDisabledButton ; 6 + DW ConvertEnabledButton + + DW SampleSizeText ; 8 + DW SampleSize0Button ; 9 + DW SampleSize1Button + DW SampleSize2Button + + DW DriverText + + DW 0 + +GravisHeaderLine DW 10 + DB "Interwave Driver", 0 + +DriverText DW 1 + DB 38, 48 + DB 21h + DB "Interwave Driver 1.1 for Impulse Tracker", 0 + +SampleText DW 1 + DB 3, 13 + DB 20h + DB "Sample resizing options", 0 + +ConvertSampleText DW 1 + DB 5, 15 + DB 20h + DB "Reduce 16 bit samples to 8 bit", 0 + +ConvertDisabledButton DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetConvert +DriverSegment1 DW 0 + DW 0 + DW Offset SetConvert +DriverSegment2 DW 0 + DB 7, 17, 20, 19, 8 + DB 0 + DB " Disabled", 0 + +ConvertEnabledButton DW 2 + DW 6, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetConvert +DriverSegment3 DW 0 + DW 1 + DW Offset SetConvert +DriverSegment4 DW 0 + DB 7, 20, 20, 22, 8 + DB 0 + DB " Enabled", 0 + +SampleSizeText DW 1 + DB 5, 24 + DB 20h + DB "Sample size", 0 + +SampleSize0Button DW 2 + DW 7, 10, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment5 DW 0 + DW 0 + DW Offset SetCompress +DriverSegment6 DW 0 + DB 7, 26, 20, 28, 8 + DB 0 + DB " Original", 0 + +SampleSize1Button DW 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment7 DW 0 + DW 1 + DW Offset SetCompress +DriverSegment8 DW 0 + DB 7, 29, 20, 31, 8 + DB 0 + DB " Half", 0 + +SampleSize2Button DW 2 + DW 10, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetCompress +DriverSegment9 DW 0 + DW 2 + DW Offset SetCompress +DriverSegment10 DW 0 + DB 7, 32, 20, 34, 8 + DB 0 + DB " Quarter", 0 + + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + + +RelocationTable Label + DW Offset DriverSegment1 + DW Offset DriverSegment2 + DW Offset DriverSegment3 + DW Offset DriverSegment4 + DW Offset DriverSegment5 + DW Offset DriverSegment6 + DW Offset DriverSegment7 + DW Offset DriverSegment8 + DW Offset DriverSegment9 + DW Offset DriverSegment10 + DW 0FFFFh + +;*********** Local functions ******************* +; +; TestIW - Checks for the presence of a IW by detecting amount of memory. +; LoadIWSample - Loads a byte to IW memory, AL = value +; LoadIWSamples - Loads ECX bytes from DS:SI to IW memory +; +;*********************************************** + +; + +Proc DetectMemory + + Push DS + Assume DS:Driver + + Push CS + Pop DS + + Mov IWMemory, 0 + + Mov DX, IWRegisterSelect + Mov AL, 52h + Out DX, AL + Inc DX + In AX, DX + Mov IWLMCFI, AX + And AX, 0FFF0h + Or AX, 0Ch ; Allow full 16MB addressing + + Mov NewIWLMCFI, AX + + Out DX, AX + + Mov CX, 256 + Xor EDI, EDI + +DetectMemory1: ; DX = BasePort+103h + Call IWSetPosition + + Xor AL, AL + Call LoadIWSample ; Write a 0 + + Add EDI, 10000h + Loop DetectMemory1 + + Mov EBX, 3 ; 4 banks, 3, 2, 1 and 0 + +DetectMemory2: + Mov EDI, EBX + ShL EDI, 22 ; DI = Bank * 4MB + Call IWSetPosition + + Mov AL, 0AAh + Mov DX, IWOutputPort + Out DX, AL + Mov AL, 055h + Out DX, AL + Call IWSetPosition + + Mov DX, IWOutputPort + + In AL, DX ; Bank doesn't exist? + Cmp AL, 0AAh + JNE DetectMemory3 + + In AL, DX + Cmp AL, 055h + JNE DetectMemory3 + + Mov CX, 64 ; Max of 4MB in 1 bank... + +DetectMemoryInnerLoop1: + Inc [IWBankTable+BX] + Inc IWMemory + + Add EDI, 10000h + Call IWSetPosition + + Mov DX, IWOutputPort + In AL, DX + Cmp AL, 0AAh + JE DetectMemory3 + + Loop DetectMemoryInnerLoop1 + +DetectMemory3: + Dec BX + JNS DetectMemory2 + + ; OK.. have checked each bank.. now to init. + Mov BL, 10 + Mov SI, Offset BankConfigs + Mov EAX, DWord Ptr IWBankTable + +DetectMemory4: + Cmp EAX, [SI] + JE DetectMemory5 + + Add SI, 4 + Dec BL + JNS DetectMemory4 + + Mov IWMemorySegmented, 1 + Jmp DetectMemory6 + +DetectMemory5: ; Set LMCI + Mov DX, IWRegisterSelect + Mov AL, 52h + Out DX, AL + Mov AX, IWLMCFI + + And AX, 0FFF0h + Or AL, BL + + Mov NewIWLMCFI, AX + + Inc DX + Out DX, AX + +DetectMemory6: + ShL IWMemory, 6 + JZ DetectMemory7 + + Pop DS + Ret + +DetectMemory7: + Pop DS + Pop AX ; Add SP, 2 + + StC + RetF + +EndP DetectMemory + Assume DS:Nothing + +; + +Proc ResetIW ; AX = baseport. + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DX, 103h ; DX = IGIDXR + + Comment ~ + + Mov AL, 4Ch + Out DX, AL + Add DL, 2 + Xor AL, AL + Out DX, AL + + Push DX + Mov DX, 300h + Mov CX, 20 +ResetIW4: + In AL, DX + Loop ResetIW4 + Pop DX + + Mov AL, 1 + Out DX, AL + + Push DX + Mov DX, 300h + Mov CX, 20 +ResetIW3: + In AL, DX + Loop ResetIW3 + Pop DX + + Sub DL, 2 + + ~ + + Mov AL, 19h ; Write SGMI + Out DX, AL + + Add DL, 2 + + Mov AL, 1 + Out DX, AL ; Enhanced mode enabled. + Sub DL, 2 + + Mov AL, 99h ; Read SGMI + Out DX, AL + Add DL, 2 + In AL, DX + Sub DL, 2 + + Cmp AL, 1 + JNE ResetIW1 + + Mov AL, 53h ; LMCI + Out DX, AL + + Add DL, 2 + Mov AL, 1 + Out DX, AL ; Auto increment, DRAM, 8-bit, NoInvert + Sub DL, 2 + + ClC + Jmp ResetIW2 + +ResetIW1: + StC + +ResetIW2: + Pop DX + Pop CX + Pop AX + + Ret + +EndP ResetIW + +; + +Proc TestIW + + + Call ResetIW + JC TestIW3 + + Push AX + + Mov IWMemory, 0 + + Mov DX, AX + Add DX, 103h ; DX = Select Register + + Mov CX, 256 ; Max amount is 16MB of memory + Xor BX, BX ; BX = no of 64k chunks. + +TestIW1: + ClI + + Mov AL, 44h ; IW DRAM High, 8 bit + Out DX, AL + + Add DL, 2 + Mov AX, BX ; BX = IW DRAM High + Out DX, AL + Sub DL, 2 ; DX = Select Register + + Mov AL, 43h ; IW DRAM Low, 16 bit + Out DX, AL + + Inc DX ; DX = Baseport+104h + Xor AX, AX + Out DX, AX ; Address 0 + + StI + + Add DL, 3 ; DX = Baseport+107h (DRAM I/O) + + Mov AL, 55h + Out DX, AL ; Write value 55h + Mov AL, 0AAh + Out DX, AL ; Write value 0AAh + Mov AL, CL + Out DX, AL ; Write value + + Sub DL, 3 ; DX = Baseport+104h + Xor AX, AX + Out DX, AX ; Address 0 + + Add DL, 3 ; DX = Baseport+107h + In AL, DX ; Read value.. + Cmp AL, 55h + JNE TestIW2 + + In AL, DX ; Read value.. + Cmp AL, 0AAh + JNE TestIW2 + + In AL, DX ; Read value.. + Cmp AL, CL + JNE TestIW2 + + Inc BX + Sub DL, 4 ; DX = Baseport+103h + Loop TestIW1 + +TestIW2: + Pop AX + + And BX, BX + JZ TestIW3 + + ShL BX, 6 + Mov IWMemory, BX + ClC + Ret + +TestIW3: + StC + Ret + +EndP TestIW + +; + +Proc IWSetPosition ; EDI = position + + ClI + Mov DX, CS:IWRegisterSelect + Mov AL, 44h + Out DX, AL + + Add DL, 2 + SHLD EAX, EDI, 16 +; Mov EAX, EDI +; ShR EAX, 16 + Out DX, AL + Sub DL, 2 ; Select register again. + + Mov AL, 43h ; Address Low, 16 bit + Out DX, AL + Inc DX ; DX = 3x4h + + Mov AX, DI ; Memory location high + Out DX, AX ; Memory location done. + + StI + Ret + +EndP IWSetPosition + +; + +Proc LoadIWSample ; AL = value + + Mov DX, CS:IWOutputPort + Out DX, AL + + Ret + +EndP LoadIWSample + +; + +Proc LoadIWSamples ; Given DS:SI, ECX = count + ; EBP = step value. + + Mov DX, CS:IWOutputPort + +LoadIWSamples2: + Mov AL, [SI] + Add SI, BP + JC LoadIWSamples4 + +LoadIWSamples3: + Out DX, AL + + LoopD LoadIWSamples2 + Ret + +LoadIWSamples4: + Add ESI, 10000h + Int 3 + Jmp LoadIWSamples3 + +EndP LoadIWSamples + +; + +Proc Load16IWSamples ; Given DS:SI, ECX = count + ; EBP = step value. + + Add BP, BP + Dec BP + Mov BX, 1 + Xor BP, BX + Xor BX, BP + + Mov DX, CS:IWOutputPort + +Load16IWSamples1: + Xor BX, BP + Mov AL, [SI] + Add SI, BX + JC Load16IWSamples4 + +Load16IWSamples3: + Out DX, AL + + Dec ECX + JNZ Load16IWSamples1 + Ret + +Load16IWSamples4: + Add ESI, 10000h + Int 3 + Jmp Load16IWSamples3 + +EndP Load16IWSamples + +;*********** Public functions ****************** + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectIW Far + + Cmp BasePort, 0FFFFh + JE DetectIW1 + + Mov AX, BasePort + Call TestIW + JNC DetectIW3 + + Ret + +DetectIW1: + Mov AX, 210h + +DetectIW2: + Call TestIW + JNC DetectIW3 + + Add AL, 10h + Cmp AL, 60h + JBE DetectIW2 + + StC + Ret + +DetectIW3: + Mov BasePort, AX + Add AX, 102h + Mov IWVoiceSelect, AX + Inc AX + Mov IWRegisterSelect, AX + Add AL, 4 + Mov IWOutputPort, AX + + Call DetectMemory + + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectIW + +; + +Proc IWIRQOnlyHandler + + PushAD + Push DS + Push ES + + Mov AL, 20h + + Cmp CS:IRQ, 8 + JB IWIRQOnlyHandler1 + + Out 0A0h, AL + +IWIRQOnlyHandler1: + Out 20h, AL + + Mov DX, CS:BasePort + Add DL, 6 + In AL, DX + And AL, 8 + JZ IWIRQOnlyHandler2 + + Mov DX, CS:IWRegisterSelect + Mov AL, 45h + Out DX, AL + Mov AL, 0 + Add DL, 2 + Out DX, AL + Mov AL, 8 + Out DX, AL + Sub DL, 2 + + ClD + + Call SaveEMSPageFrame + Call Update + Call SetIWRegisters + Call RestoreEMSPageFrame + +IWIRQOnlyHandler2: + Pop ES + Pop DS + PopAD + + IRet + +EndP IWIRQOnlyHandler + +; + +Proc IWIRQHandler ; IRQ Handler has to + ; 1) Update IW registers + ; 2) Update song position + Push AX + Push DS + + Mov AX, IWUpdateTimer + Add IWUpdateCount, AX + JC IWIRQHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp IWIRQHandler2 + +IWIRQHandler1: + PushF + Call [OldIRQHandler] + +IWIRQHandler2: + Xor IWUpdateFlag, 1 + JZ IWIRQHandlerEnd + + PushAD + Push ES + + ClD + + Call SaveEMSPageFrame + Call Update ; Returns DS:SI, CX + Call SetIWRegisters + Call RestoreEMSPageFrame + + Pop ES + PopAD + +IWIRQHandlerEnd: + Pop DS + Pop AX + IRet + +EndP IWIRQHandler + +; + +Proc SetIWVolume ; BX = new volume + + ; To do: + ; 1) Set ramp start + ; 2) Set ramp end + ; 3) Set current volume + ; 4) Start ramp + ; 5) Save new volume. + + Push BX + Push CX + + Mov AL, 0Dh + Out DX, AL + + Mov AL, 3 ; Stop Ramp! + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Add BX, BX + Mov CX, [CS:IWVolumeTable+BX] ; CX = new volume + Mov BX, [SI+2] + Add BX, BX + Mov BX, [CS:IWVolumeTable+BX] ; BX = old volume + + Cmp BX, CX + JNE SetIWVolume2 + + Mov AL, 89h + Out DX, AL + Inc DX + In AX, DX + Dec DX + + Mov BX, AX ; BX = old volume + +SetIWVolume2: + + Push BX ; Old volume on stack + + Xor AH, AH ; Ramp up + Cmp CX, BX + JE SetIWVolume4 + JA SetIWVolume1 + + XChg BX, CX + Mov AH, 40h ; Ramp down + +SetIWVolume1: + Mov AL, 6 ; Ramp rate + Out DX, AL + + Mov AL, 32 ; Ramp rate + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 7 ; Ramp start + Out DX, AL + + Mov AL, BH + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 8 ; Ramp end + Out DX, AL + + Mov AL, CH + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 9 + Out DX, AL + + Pop BX ; BX = old volume + XChg BX, AX + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Dh ; Ramp control + Out DX, AL + + Mov AL, BH + Add DL, 2 + Out DX, AL + Sub DL, 2 + +SetIWVolume5: + Pop CX + Pop BX + + Mov [SI+2], BX + + Ret + +SetIWVolume4: +; Mov AL, 0Dh ; Volume Ramp. +; Out DX, AL +; +; Mov AL, 3 +; Add DL, 2 +; Out DX, AL +; Sub DL, 2 + + Mov AL, 9 + Out DX, AL + + Pop AX ; AX = old volume + + Inc DX + Out DX, AX + Dec DX + + Jmp SetIWVolume5 + +EndP SetIWVolume + +; + +Proc IWGetAddress ; Given EAX + + Push CX + + Mov CL, CS:Compress + ShR EAX, CL + + Pop CX + Add EAX, [CS:IWDataTable+BX] + ShL EAX, 9 + And EAX, 7FFFFFFFh + + Ret + +EndP IWGetAddress + +; + +Proc SetIWRegisters ; Given DS:SI, CX + + Mov ES, CS:SongDataArea + + Push CX + Push SI + + Xor AX, AX + +GetOffsetLoop: + Push AX + Push CX + + Mov DX, IWVoiceSelect + Out DX, AL ; OK.. now to play with this + ; voice. + Inc DL ; DX = select rego + + Mov BX, [SI] + Test BH, 2 + JZ GetOffsetLoop2 + + Mov BX, 200h + Mov [SI], BX + +GetOffsetLoop2: + Test BL, 1 ; Channel not on! + JZ GetOffsetLoop1 + Test BH, 1 + JZ GetOffsetLoop3 ; Prev 1. + + Xor BX, BX + Call SetIWVolume + + Jmp GetOffsetLoop1 + +GetOffsetLoop3: + Mov EAX, [SI+4Ch] + Mov [SI+2Ch], EAX + + Mov AL, 8Ah + Out DX, AL + + Inc DX + In AX, DX + Dec DX + + And AH, 7Fh + ShL EAX, 16 ; Load high part of EAX + + Mov AL, 8Bh + Out DX, AL + Inc DX + In AX, DX + ; EAX = 000OOOOO OOOOOOOO OOOOOOOF FFFFFFFF + ; Need: 00000000 0000OOOO OOOOOOOO OOOOOOOO + + ShR EAX, 9 + + MovZX EBX, Byte Ptr [SI+36h] + Mov EBX, [CS:IWDataTable+EBX*4] + And EBX, 03FFFFFh + Sub EAX, EBX + Push CX + + Mov CL, CS:Compress + ShL EAX, CL + + Pop CX + Mov [SI+4Ch], EAX + +GetOffsetLoop1: + Add SI, SLAVECHANNELSIZE + + Pop CX + Pop AX + + Inc AX + Dec CX + JNZ GetOffsetLoop + + Pop SI + Pop CX + + Xor AX, AX + +SetIWRegisters1: + Push AX + Push CX + + Mov DX, IWVoiceSelect + Out DX, AL ; OK.. now to play with this + ; voice. + Mov CX, [SI] ; CX = flags. + Inc DL ; DX = select rego + + Test CH, 1 + JZ SetIWRegisters21 + + Mov AL, [SI+36] + Cmp AL, [SI+4] + JE SetIWRegisters21 + + Xor AL, AL + Out DX, AL + + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + +SetIWRegisters21: + Test CL, 32 ; Frequency change + JZ SetIWRegisters7 + + Push DX + + Mov EAX, [SI+10h] ; EAX = freq. + + Push CX + Mov CL, CS:Compress + ShR EAX, CL + Pop CX + + Xor EDX, EDX + Mov EBX, MixSpeed + + Div EBX ; EAX = I portion. + + Test EAX, Not 63 + JNZ SetIWRegisters6 + + Push EAX + + Xor EAX, EAX + Div EBX + + Pop EBX ; EBX:EAX = IIII FFFF etc. + + SHRD EAX, EBX, 6 + + ; Have: IIIIIIII IIIIIIII FFFFFFFF FFFFFFFF + ; Req: IIIIIIFF FFFFFFF0 + + Pop DX + Mov AL, 1 + Out DX, AL + + ShR EAX, 16 + AdC AX, 0 + SBB AX, 0 ; Just in case! + + Inc DX + Out DX, AX + Dec DX + + Jmp SetIWRegisters7 + +SetIWRegisters6: + Mov CH, 2 ; Signify to turn off channel + Pop DX + +SetIWRegisters7: + MovZX BX, Byte Ptr [SI+36h] ; BX = sample number. + Cmp BL, 99 + JA SetIWRegisters20 + + ShL BX, 2 ; IWDataTable+BX = position + + Cmp DWord Ptr [CS:IWDataTable+BX], 0FFFFFFFFh + JNE SetIWRegisters10 + +SetIWRegisters20: + Mov CH, 2 + Jmp SetIWRegisters9 + +SetIWRegisters10: + Test CH, 5 ; Loop changed?!??!? + JZ SetIWRegisters8 + + Mov AL, 3 ; Starting location low. + Out DX, AL + + Mov EAX, [SI+40h] + Call IWGetAddress + + ; Reqd: .OOOOOOO OOOOOOOO OOOOOOOI III..... + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 2 ; Starting location high + Out DX, AL + + ShR EAX, 16 + Inc DX + Out DX, AX + Dec DX + + ; Ending location... + Mov AL, 5 ; Ending location low + Out DX, AL + + Mov EAX, [SI+44h] + Call IWGetAddress + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 4 ; Ending location high + Out DX, AL + + SHR EAX, 16 + Inc DX + Out DX, AX + Dec DX + +SetIWRegisters8: + Test CH, 1 ; Do Current position? + JZ SetIWRegisters9 + + Xor AL, AL + Out DX, AL + + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 9 + Out DX, AL + Xor AX, AX + Inc DX + Out DX, AX + Dec DX + + Mov AL, 10h + Out DX, AL + Add DL, 2 + Mov AL, Byte Ptr [CS:IWDataTable+BX+2] + ShR AL, 6 + Out DX, AL + Sub DL, 2 + + Mov AL, 0Bh ; Current location LOW + Out DX, AL + + Mov EAX, [SI+4Ch] + Mov [SI+2Ch], EAX + + ; EAX = OOOOOOOO OOOOOOOO OOOOOOOO OOOOOOOO + ; Req: xOOOOOOO OOOOOOOO OOOOOOOF FFFFFFFF + Call IWGetAddress + + Mov DI, AX + + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Ah ; Current location HIGH + Out DX, AL + + SHR EAX, 16 + Inc DX + Out DX, AX + Dec DX + + Mov AL, 0Bh + Out DX, AL + + Mov AX, DI + Inc DX + Out DX, AX + Dec DX + +SetIWRegisters9: + Test CL, 64 ; New volume?? + JZ SetIWPan + +SetIWRegisters23: + Xor BX, BX + Test CH, 8 + JNZ SetIWRegistersMuted + + Mov BL, Byte Ptr [SI+20h] ; BL = volume, 0->128 + +SetIWRegistersMuted: + Call SetIWVolume + +SetIWPan: + Test CH, 128 ; New pan?? + JZ SetIWRegisters5 + + Xor BH, BH + + Test CS:Stereo, 1 + JZ SetIWRegisters3 + + Mov BL, [SI+37h] + Cmp BL, 100 + JNE SetIWRegisters4 + +SetIWRegisters3: + Mov BL, 32 ; Surround goes to mono :( + +SetIWRegisters4: + Add BX, BX ; BX = offset into IWTable + + Test CH, 1 + JZ IWSetPan1 + + Mov AL, 0Ch ; Right offset + Out DX, AL + Inc DX + Mov AX, [CS:OffsetTable+BX] + Out DX, AX + Dec DX + + Neg BX + + Mov AL, 13h ; Left offset final + Out DX, AL + Inc DX + Mov AX, [CS:OffsetTable+128+BX] + Out DX, AX + Dec DX + + Neg BX + +IWSetPan1: + Mov AL, 1Bh ; Right offset final + Out DX, AL + Inc DX + Mov AX, [CS:OffsetTable+BX] + Out DX, AX + Dec DX + + Neg BX + + Mov AL, 1Ch ; Left offset final + Out DX, AL + Inc DX + Mov AX, [CS:OffsetTable+128+BX] + Out DX, AX + Dec DX + +SetIWRegisters5: + ; Now for control register. + ; If CH | 2, then turn rego OFF + ; If CH | 5, then turn rego ON + ; If CL | 1, then check channel + Test CH, 2 + JNZ SetIWRegisters11 + + Test CH, 5 + JNZ SetIWRegisters12 + + Test CL, 1 + JZ SetIWRegisters13 + + Mov AL, 80h ; Read voice control + Out DX, AL + + Add DL, 2 + In AL, DX + Sub DL, 2 + + Test AL, 1 + JZ SetIWRegisters13 + + Xor BX, BX + Call SetIWVolume + + Jmp SetIWRegisters14 + +SetIWRegisters11: ; Turn off. + Mov Byte Ptr [SI+4], 0FFh + + Xor BX, BX + Call SetIWVolume + + Xor AL, AL + Out DX, AL + Mov AL, 2 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 15h + Out DX, AL + + Add DL, 2 ; Synthesizer Mode select + Mov AL, 34 ; Offset enable, enable voice + Out DX, AL + Sub DL, 2 + + +SetIWRegisters14: + Test CL, 1 + JZ SetIWRegisters13 + + Xor CX, CX ; Turn off channel + Test Byte Ptr [SI+3Ah], 80h + JNZ SetIWRegisters13 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + + Jmp SetIWRegisters13 + +SetIWRegisters12: ; Turn on + Mov AL, [SI+36] + Mov [SI+4], AL + + Mov AL, 15h + Out DX, AL + + Add DL, 2 ; Synthesizer Mode select + Mov AL, 32 ; Offset enable, enable voice + Out DX, AL + Sub DL, 2 + + Xor AL, AL + Out DX, AL + + Mov AL, [SI+0Ah] + + Cmp CS:Convert16To8Bit, 0 + JNZ SetIWRegistersNo16Bit + + Mov AH, [SI+18h] ; 16 bit? + Add AH, AH + Or AL, AH + +SetIWRegistersNo16Bit: + Test CL, 1 + JNZ SetIWRegisters15 + + Mov AL, 2 + Xor CX, CX + +SetIWRegisters15: + Add DL, 2 + Out DX, AL + +SetIWRegisters13: + And CX, 0111100010011111b ; Turns off: + ; 1) Freq & vol recalc + ; 2) New note/note stop/loop cha + + Mov [SI], CX + + Add SI, SLAVECHANNELSIZE + + Pop CX + Pop AX + + Inc AX + Dec CX + JNZ SetIWRegisters1 + + Ret + + +EndP SetIWRegisters + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov SI, Offset RelocationTable + +Relocation1: + LodsW + Cmp AX, 0FFFFh + JE RelocationEnd + + Mov BX, AX + Mov [BX], CS + Jmp Relocation1 + +RelocationEnd: ; OK... disable the IW Line In + ; & Enable Line Out + ; SetupMIDI + Mov DX, BasePort + Inc DH + Mov AL, 0FFh + Out DX, AL + Mov AL, 0FCh + Out DX, AL + + ; Setup the rest of it. + Mov DX, BasePort + Mov AL, 1 + Out DX, AL + + Mov DX, IWRegisterSelect + Mov AL, 0Eh + Out DX, AL ; DX = BasePort+103h + + Add DL, 2 ; DX = BasePort+105h + Mov AL, 0CDh + Out DX, AL ; Full mixing rate + + Mov CX, 32 + Sub DL, 3 + +IWResetVoice1: + Mov AL, CL + Dec AL + Out DX, AL + + Inc DX ; DX = BasePort + 103h + Xor AL, AL ; Voice control register, 8 bit + Out DX, AL + + Add DL, 2 + Mov AL, 3 + Out DX, AL ; Stop voice + Sub DL, 2 + + Mov AL, 0Dh ; Volume Ramp. + Out DX, AL + + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 6 ; Ramp rate + Out DX, AL + + Mov AL, 32 ; Ramp rate + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 9 ; Volume register, 16 bit + Out DX, AL + + Inc DX + Xor AX, AX + Out DX, AX ; No volume + Dec DX + + Mov AL, 15h + Out DX, AL + + Add DL, 2 ; Synthesizer Mode select + Mov AL, 32 ; Offset enable, enable voice + Out DX, AL + + ClI + Sub DL, 3 ; DX = BasePort + 102h = Voice select. + + Loop IWResetVoice1 + + Inc DL + Mov AL, 5Bh + Out DX, AL + Add DL, 2 + In AL, DX + Sub DL, 2 + Shr AL, 4 ; AL = revision number + + Add AL, 'A' + Mov Revision, AL +; Cmp AL, 'C' +; JE InitSound_IW2 + +; Mov OffsetTable, Offset IWOffsetTable2 + +InitSound_IW2: + Cmp CS:IRQ, 0FFFFh + JE InitSound_IW1 + + Mov AX, BasePort + Call ResetIW + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + ; Set IRQ + Mov BX, IRQ + ShL BX, 2 ; BX points to offset in IRQData + + Xor DI, DI + Mov ES, DI + Mov DI, [BX+IRQData] + + And AX, [BX+IRQData+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset IWIRQOnlyHandler + + XChg [ES:DI], EAX + Mov OldIRQHandler, EAX + + StI + + Mov DX, BasePort + Mov AL, 9 + Out DX, AL + + Call GetTempo + Call SetTempo + Call ResetMemory + + Mov AL, Revision + Mov RevisionLetter2, AL + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, IWMemory + + Mov SI, Offset IWID2 + + ClC + Ret + +InitSound_IW1: + Mov AL, 4Ch + Out DX, AL + Add DL, 2 + Mov AL, 3 + Out DX, AL + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Call GetTempo + Call SetTempo + Call ResetMemory + + Mov DX, BasePort + Mov AL, 1 + Out DX, AL + + Xor AX, AX + Mov ES, AX ; ES = 0 + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset IWIRQHandler + + ClI + + XChg DWord Ptr [ES:20h], EAX ; Clock tick + Mov OldIRQHandler, EAX + + StI + + Mov AL, Revision + Mov RevisionLetter, AL + + Mov AX, BasePort + Mov BX, IWMemory + Mov SI, Offset IWID + + ClC + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc ReInitSound Far + + Push CS + Pop DS + Mov SI, Offset IWReinitMsg + Mov BX, 40 + Call SetInfoLine + + Mov BX, CS:IRQ + Cmp BX, 0FFFFh + JE ReInitSound1 + + Mov AX, CS:IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + ShL BX, 2 + Xor DI, DI + Mov ES, DI + Mov DI, [CS:BX+IRQData] + Mov EAX, CS:OldIRQHandler + + Mov [ES:DI], EAX + + Jmp ReInitSound2 + +ReInitSound1: + Mov AL, 34h + Out 43h, AL + + Xor AX, AX + Out 40h, AL + Out 40h, AL + + Mov ES, AX + Mov EAX, OldIRQHandler + Mov [ES:20h], EAX + +ReInitSound2: + Mov DX, IWRegisterSelect + Mov AL, 52h + Out DX, AL + Inc DX + Mov AX, NewIWLMCFI + Out DX, AX + + Jmp RelocationEnd + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov AX, BasePort + Call ResetIW + + Mov DX, BasePort + Inc DH + Mov AL, 0FFh + Out DX, AL ; Stop MIDI + + Mov CX, 32 + Mov DX, CS:IWVoiceSelect + +IWResetVoice2: + Mov AL, CL + Dec AL + Out DX, AL + + Inc DX ; DX = BasePort + 103h + Xor AL, AL ; Voice control register, 8 bit + Out DX, AL + + Add DL, 2 + Mov AL, 3 + Out DX, AL ; Stop voice + Sub DL, 2 + + Mov AL, 0Dh ; Volume Ramp. + Out DX, AL + + Mov AL, 3 + Add DL, 2 + Out DX, AL + Sub DL, 2 + + Mov AL, 9 ; Volume register, 16 bit + Out DX, AL + + Inc DX + Xor AX, AX + Out DX, AX ; No volume + Dec DX + + Mov AL, 15h + Out DX, AL + + Add DL, 2 + Mov AL, 2 + Out DX, AL ; Deactivate voice + + ClI + Sub DL, 3 ; DX = BasePort + 102h = Voice select. + + Loop IWResetVoice2 + +; Inc DL +; Mov AL, 4Ch +; Out DX, AL +; Xor AL, AL +; Add DL, 2 +; Out DX, AL + + Mov BX, CS:IRQ + Cmp BX, 0FFFFh + JE UnInitSound1 + + Mov AX, CS:IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + ShL BX, 2 + Xor DI, DI + Mov ES, DI + Mov DI, [CS:BX+IRQData] + Mov EAX, CS:OldIRQHandler + + Mov [ES:DI], EAX + + Jmp UnInitSound2 + +UnInitSound1: + Mov AL, 34h + Out 43h, AL + + Xor AX, AX + Out 40h, AL + Out 40h, AL + + Mov ES, AX + Mov EAX, OldIRQHandler + Mov [ES:20h], EAX + +UnInitSound2: + Mov DX, IWRegisterSelect + Mov AL, 52h + Out DX, AL + Mov AX, IWLMCFI + Inc DX + Out DX, AX + + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; +; + +Proc Poll Far + + ClI + +Poll1: + Call [CS:UARTBufferEmpty] + JNC MIDIEnd + + Mov DX, [CS:BasePort] + Inc DH + In AL, DX + Test AL, 1 + JZ MIDIEnd + + Inc DX + In AL, DX + Cmp AL, 0F0h + JAE MIDIEnd + + Call [CS:UARTSend] + Jmp Poll1 + +MIDIEnd: + StI + + Ret + +EndP Poll + +; + +Proc UARTOut + + Push DX + Push AX + + Mov DX, [CS:BasePort] + Inc DH + +UARTOut1: + In AL, DX + Test AL, 2 + JZ UARTOut1 + + Pop AX + Inc DX + + Out DX, AL + + Pop DX + + Ret + +EndP UARTOut + +; + +InterpretState DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Mov CS:InterpretState, 0 + +SendUARTOut4: + Ret + +SendUARTOut3: + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Call UARTOut + Ret + +EndP SendUARTOut + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far ; BX = tempo... + + Push AX + Push BX + Push DX + + Cmp CS:IRQ, 0FFFFh + JE SetTempo1 + + ShL BX, 8 + Mov DX, 1Eh + Mov AX, 8480h + Div BX + Neg AL + + Mov AH, AL + + Mov DX, CS:IWRegisterSelect + + Mov AL, 47h + Out DX, AL + Add DL, 2 + Mov AL, AH + Out DX, AL ; Set Timer control register 2 + Sub DL, 2 + + Mov AL, 45h + Out DX, AL + Add DL, 2 + Mov AL, 8 + Out DX, AL +; Sub DL, 2 + + Mov DX, CS:BasePort + Add DL, 8 + Mov AL, 4 + Out DX, AL + + Inc DL + Mov AL, 2 + Out DX, AL + + Jmp SetTempo2 + +SetTempo1: + ; Frames per second = 2 * (0.4*Tempo) + Mov AX, 0C214h + Mov DX, 16h ; Ticks = (1193181/(2*0.4))/Tempo + Div BX + + ; AX contains counter. + Mov IWUpdateTimer, AX + + Out 40h, AL ; Timer IRQ. + Mov AL, AH + Out 40h, AL + +SetTempo2: + Pop DX + Pop BX + Pop AX + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; + +Proc LoadSample Far + + PushAD + Push DS + Push ES + Push FS + + Mov FS, CS:SongDataArea + Mov BP, AX + Dec BP + Add BP, BP + Mov BP, [FS:64912+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length + JC Music_IWLoadSampleEnd + + Mov BL, [FS:BP+12h] + Test BL, 16 + JZ Music_IWLoadSample12 + + Cmp ECX, [FS:BP+38h] + JBE Music_IWLoadSample12 + + Mov ECX, [FS:BP+38h] + Test BL, 32 + JZ Music_IWLoadSample12 + + Cmp ECX, [FS:BP+44h] + JAE Music_IWLoadSample12 + + Mov ECX, [FS:BP+44h] + +Music_IWLoadSample12: + Mov EBX, ECX + Mov CL, CS:Compress + Mov EDX, 1 + ShR EBX, CL + ShL EDX, CL ; EDX = step value. + + Mov ECX, EBX + + ; Now find location to put it in + + Dec AX ; AX = sample number + Push AX ; AX = sample number (0 based) + + And EAX, 0FFh + Mov DWord Ptr [CS:IWDataTable+4*EAX], 0FFFFFFFFh + + Add ECX, 2 + + Cmp IWMemorySegmented, 0 + JNE Music_IWLoadSegmented1 + + Mov EAX, IWMemoryFree + + Test Byte Ptr [FS:BP+12h], 2 ; 16 bit?? + JZ Music_IWLoadSamples13 + + Cmp CS:Convert16To8Bit, 0 + JNZ Music_IWLoadSamples5 + + Sub EAX, 1 + JC Music_IWLoadSampleWarning + And EAX, Not 1 ; For alignment + Add ECX, ECX + Jmp Music_IWLoadSamples13 + +Music_IWLoadSamples5: + Inc ESI + Add EDX, EDX ; Step value. + +Music_IWLoadSamples13: + Cmp ECX, EAX + JBE Music_IWLoadSample2 + + ; Warning msg here. +Music_IWLoadSampleWarning: + Pop AX + ClC + Jmp Music_IWLoadSampleEnd + +Music_IWLoadSample3: + StC + +Music_IWLoadSampleEnd: + Pop FS + Pop ES + Pop DS + PopAD + + Ret + +Music_IWLoadSegmented1: + Test Byte Ptr [FS:BP+12h], 2 ; 16 bit?? + JZ Music_IWLoadSegmented3 + + Cmp CS:Convert16To8Bit, 0 + JNZ Music_IWLoadSegmented2 + + Add ECX, ECX + + ; Check each of 4 banks... + Xor BX, BX + +Music_Load16BitSegment1: + Mov EAX, [IWBank1+BX] + And EAX, Not 1 ; For alignment + Cmp ECX, EAX + JBE Music_LoadSegment2 + +Music_Load16BitSegment2: + Add BX, 4 + Cmp BX, 16 + JB Music_Load16BitSegment1 + Jmp Music_IWLoadSampleWarning + +Music_LoadSegment2: + Sub EAX, ECX + Mov [IWBank1+BX], EAX + ShL EBX, 20 + Add EBX, EAX + Jmp LoadIWSampleChain + +Music_IWLoadSegmented2: + Inc ESI + Add EDX, EDX ; Step value. + +Music_IWLoadSegmented3: + Xor BX, BX + +Music_Load8BitSegment1: + Mov EAX, [IWBank1+BX] + Cmp ECX, EAX + JBE Music_LoadSegment2 + + Add BX, 4 + Cmp BX, 16 + JB Music_Load8BitSegment1 + Jmp Music_IWLoadSampleWarning + +Music_IWLoadSample2: ; EAX = number of bytes free. + ; DS:SI = sample. + ; ECX = number of bytes of memory + ; ES:DI = num bytes free ptr + ; BP = sample number. + + ; Location = MaxMem - DX:AX + ; = -(DX:AX - IWBanks*4:0) + MovZX EBX, CS:IWMemory + ShL EBX, 10 + ; BX = bytes avail. + Sub EBX, EAX + Sub EAX, ECX + Mov IWMemoryFree, EAX + +LoadIWSampleChain: + Pop DI ; DI = sample number + + ShL DI, 2 + + Cmp CS:Convert16To8Bit, 0 + JNZ LoadIWForced8Bit + + Test Byte Ptr [FS:BP+12h], 2 + JNZ Music_IWLoad16BitSample + +LoadIWForced8Bit: + Push EBX + Inc EBX + Mov [CS:IWDataTable+DI], EBX ; Store pointer + + Mov ES, CS:SongDataArea + Pop EDI ; EDI = location in IW mem + + Sub ECX, 2 + ; EDI = location in IW mem + ; DS:SI = sample data + ; ECX = length. + ; EDX = step value. + ClI + + Push BP + + Mov EBP, EDX + + Call IWSetPosition + + Mov AL, [DS:SI+BP] + Call LoadIWSample + Call LoadIWSamples + + Mov BH, AL + + Pop BP + + Mov AL, [FS:BP+12h] + Test AL, 16 + JZ Music_IWLoadSample10 + + Mov ESI, [FS:BP+34h] + Test AL, 64 + JZ Music_IWLoadSample11 + + Mov ESI, [FS:BP+38h] + Sub ESI, 2 + AdC ESI, 0 + + Mov EAX, Not 0 + Mov CL, CS:Compress + ShL EAX, CL + And ESI, EAX + +Music_IWLoadSample11: + Test Byte Ptr [FS:BP+12h], 2 + JZ Music_IWLoadSample6 + + Add ESI, ESI + Inc SI + +Music_IWLoadSample6: + Int 3 + + Mov BH, [SI] + +Music_IWLoadSample10: + Mov AL, BH + Call LoadIWSample + + StI + Jmp Music_IWLoadSample3 ; Return.. no error. + +Music_IWLoad16BitSample: + Push EBX + + ShR EBX, 1 + Inc BX + Mov [CS:IWDataTable+DI], EBX + + Mov ES, CS:SongDataArea + Pop EDI ; EDI = location in IW mem + + Sub ECX, 4 + ClI + + Push BP + + Mov EBP, EDX + + Call IWSetPosition + + Mov AX, [DS:ESI+EBP*2] + Call LoadIWSample + Mov AL, AH + Call LoadIWSample + + Call Load16IWSamples + + Pop BP + + Xor BX, BX + + Mov AL, [FS:BP+12h] + Test AL, 16 + JZ Music_IWLoad16BitSample11B + + Mov ESI, [FS:BP+34h] + + Test AL, 64 + JZ Music_IWLoad16BitSample11 + + Mov ESI, [FS:BP+38h] + Sub ESI, 2 + JNC Music_IWLoad16BitSample11 + + Xor ESI, ESI + +Music_IWLoad16BitSample11: + Mov EAX, Not 0 + Mov CL, CS:Compress + ShL EAX, CL + And ESI, EAX + + Add ESI, ESI + Int 3 + + Mov BX, [SI] + +Music_IWLoad16BitSample11B: + Mov AX, BX + Call LoadIWSample + Mov AL, AH + Call LoadIWSample + + StI + Jmp Music_IWLoadSample3 ; Return.. no error. + + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release, 0 based +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + LEA DI, [EAX*4+Offset IWDataTable] + ; Now to release the last + ; sample from IW memory if + ; able to. + + Mov EBP, [CS:DI] ; EBP = sample pointer. + Cmp EBP, 0FFFFFFFFh + JE ReleaseSample3 + +ReleaseSample4: + MovZX EAX, CS:IWMemory + SHL EAX, 10 + + ; If (MaxMem-(sample location in bank + sample length + 2)) = memory remaining, + ; then release memory. + + Mov ECX, [SI+30h] + Mov DL, [SI+12h] + Test DL, 16 + JZ ReleaseSample7 + + Cmp ECX, [SI+38h] + JBE ReleaseSample7 + + Mov ECX, [SI+38h] + + Test DL, 32 + JZ ReleaseSample7 + + Cmp ECX, [SI+44h] + JAE ReleaseSample7 + + Mov ECX, [SI+44h] + +ReleaseSample7: + Push EBX + Mov EBX, ECX + Mov CL, CS:Compress + ShR EBX, CL + Mov ECX, EBX + Pop EBX + + Inc ECX + Mov EDI, 1 + + Test DL, 2 + JZ ReleaseSample8Bit + + Cmp CS:Convert16To8Bit, 0 + JNZ ReleaseSample8Bit + + Add ECX, ECX + Inc DI + + ; EBP = pointer for 16 bit + ; need to convert back: + Add EBP, EBP + +ReleaseSample8Bit: + Cmp IWMemorySegmented, 0 + JNE ReleaseSampleSegmented1 + + Sub EAX, EBP + Sub EAX, ECX + + Cmp EAX, IWMemoryFree + JNE ReleaseSample3 + + Add ECX, EDI + Add IWMemoryFree, ECX + + Ret + +ReleaseSampleSegmented1: ; EBP = sample pointer + ; if EBP-EDI = mem remaining in + ; segment, then add ECX+EDI... + Xor AX, AX + Sub EBP, EDI + Add ECX, EDI + Mov EDI, EBP + + And EBP, 3FFFFFh + + ShR EDI, 22 + And DI, 3 + Mov EAX, [IWBank1+EDI*4] + Cmp EAX, EBP + JNE ReleaseSample3 + + Add [IWBank1+EDI*4], ECX + +ReleaseSample3: + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Push EAX + Push CX + Push ES + Push DI + + MovZX EAX, IWMemory ; Number of kbytes + ShL EAX, 10 ; Translate to bytes + + Cmp IWMemorySegmented, 0 + JE ResetMemory1 + + Xor AH, AH + Mov AL, [IWBankTable] + ShL EAX, 16 + Mov IWBank1, EAX + + Xor AH, AH + Mov AL, [IWBankTable+1] + ShL EAX, 16 + Mov IWBank2, EAX + + Xor AH, AH + Mov AL, [IWBankTable+2] + ShL EAX, 16 + Mov IWBank3, EAX + + Xor AH, AH + Mov AL, [IWBankTable+3] + ShL EAX, 16 + Mov IWBank4, EAX + + Jmp ResetMemory2 + +ResetMemory1: + Sub EAX, 64 ; Safety bytes. + Mov IWMemoryFree, EAX + +ResetMemory2: + Push CS + Pop ES + Mov DI, Offset IWDataTable + Mov CX, 200 + Mov AX, 0FFFFh + Rep StosW + + Pop DI + Pop ES + Pop CX + Pop EAX + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + Push CS + Pop DS + Assume DS:Driver + + Mov EAX, IWMemoryFree + Cmp IWMemorySegmented, 0 + JE GetStatus1 + + Mov EAX, IWBank1 + Add EAX, IWBank2 + Add EAX, IWBank3 + Add EAX, IWBank4 + +GetStatus1: + Mov SI, Offset IWFreeMsg + ShR EAX, 10 + + ClC + + Ret + +EndP GetStatus + Assume DS:Nothing + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset IWScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetConvert Far + + Mov AX, [SI+22] + Mov CS:Convert16To8Bit, AL + Call Music_LoadAllSamples + + Mov AX, 1 + Ret + +EndP SetConvert + +; + +Proc GetConvert Far + + Push CS + Pop ES + Mov DI, Offset Convert16To8Bit + Ret + +EndP GetConvert + +; + +Proc SetCompress Far + + Mov AX, [SI+22] + Mov CS:Compress, AL + Call Music_LoadAllSamples + + Mov AX, 1 + Ret + +EndP SetCompress + +; + +Proc GetCompress Far + + Push CS + Pop ES + Mov DI, Offset Compress + + Ret + +EndP GetCompress + +; + +EndDriver: + +;******** Provided Constants Table ************* + +MaxNumberOfChannels DW 32 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 32 + +DriverFlags DW 1 ; MIDI Out suported + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + DW Offset DetectIW + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + + DW Offset SendUARTOut ; MIDI output! + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End + + *********************** Notes ******************* + + UltraSound Output Structure + + 0 1 2 3 4 5 6 7 8 9 + +0000:(Flags)LastVol + + + diff --git a/it/SoundDrivers/IWDRV.MAP b/it/SoundDrivers/IWDRV.MAP new file mode 100644 index 0000000..cb4e8c1 --- /dev/null +++ b/it/SoundDrivers/IWDRV.MAP @@ -0,0 +1,9 @@ + + Start Stop Length Name Class + + 00000H 0007FH 00080H DRIVERHEADER CODE + 00080H 01416H 01397H DRIVER CODE + +Program entry point at 0000:0000 +Warning: No stack + diff --git a/it/SoundDrivers/K6MSAM.INC b/it/SoundDrivers/K6MSAM.INC new file mode 100755 index 0000000..445a223 --- /dev/null +++ b/it/SoundDrivers/K6MSAM.INC @@ -0,0 +1,388 @@ +; + +Align 4 +include q.inc +FilterParameters DB 64 Dup (07Fh), 64 Dup (0) +Const2048 DD 16384.0 +FreqMultiplier DD 3A9F7867h ; = 1/(2*PI*110.0*2^0.25) +FreqParameterMultiplier DD 0B92AAAAAh ; = -1/(24*256) + +NUMBEROFFILTERBANDS = 4 + +IF OUTPUTFILTERENABLED +LastFilter DD NUMBEROFFILTERBANDS*2 Dup (0) ; 4 stereo values +FilterCoefficients DD NUMBEROFFILTERBANDS*2 Dup (0) +FilterVolumes DD NUMBEROFFILTERBANDS Dup (0) +ENDIF + +FilterFreqValue DW 0 +NewControlWord DW 7Fh + +; + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + Assume DS:Nothing + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, CS:MixSegment + Mov DI, DMABUFFERLENGTH*2+80 + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov CS:MixTransferOffset, DI + + Cmp CS:Stereo, 0 + JE CS:MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD + Mov CS:MixTransferRemaining, DX + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamplesNoStop + + And Byte Ptr [SI], Not 1 + + Cmp MixMode, 2 + JB MixSamplesEnd + + Mov DWord Ptr [SI+0Ch], 0 + Jmp MixModeCommon + +MixSamplesNoStop: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Xor EAX, EAX + Mov [SI+3Ch], AX ; For filter. + Mov [SI+6Eh], AX + + Mov DWord Ptr [SI+1Ch], EAX ; Current Volume = 0 + ; for volume sliding. + Mov [SI+06h], DX + Mov [SI+5Eh], AX + Mov [SI+7Eh], AX + +MixSamples5: + Test CX, 8540h ; New volume or panning? + JZ MixSamplesMix + + Mov AX, 4*60 + + Test CH, 8 ; Muted? + JZ MixMMXNoMute + + Xor EDX, EDX + Mov [SI+06h], DX + Mov [SI+0Ch], EDX + Mov [SI+5Eh], DX + Mov [SI+1Ch], EDX + Mov [SI+6Eh], DX + Mov [SI+3Ch], DX + Mov [SI+7Eh], DX + + Xor BX, BX + Mov BL, [SI+3Ah] + + Test BL, BL + JS MixModeCommon1 + + Mov DL, [CS:FilterParameters+BX] + Mov BL, [CS:FilterParameters+BX+64] + + Mov [SI+5Bh], DL + Mov [SI+3Fh], BL + + Jmp MixModeCommon1 + +MixMMXNoMute: + Xor BX, BX + Mov BL, [SI+3Ah] + + Test BL, BL ; Disowned? Then use channel filters. + JNS MixGetChannelFilters + + Mov BL, [SI+3Fh] + Jmp MixChannelFilters + +MixGetChannelFilters: + ; Filter = [FilterParameters+BX] + ; Q = [FilterParameters+BX+64] + + Mov AL, [CS:FilterParameters+BX] ; AX = Filter + Mov BL, [CS:FilterParameters+BX+64] ; BX = Q + +; If the values are different, then force recalculate volume. (and hence mixmode) + + Cmp [SI+5Bh], AL + JE MixChannelFiltersSame + Cmp [SI+3Fh], BL + JE MixChannelFiltersSame + + Mov DWord Ptr [SI+0Ch], 0 + +MixChannelFiltersSame: + Mov [SI+5Bh], AL + Mov [SI+3Fh], BL + +MixChannelFilters: + Cmp MixMode, 3 + JNE MixMMXNoFilters + + Mov AL, [SI+3Eh] + Mul Byte Ptr [SI+5Bh] + + Mov CS:FilterFreqValue, AX + + Cmp AX, 127*255 + JNE MixChannelFiltersOK + Test BL, BL + JZ MixMMXNoFilters + +MixChannelFiltersOK: + ShL BX, 2 + + FNInit + FLdCW [CS:NewControlWord] + + FILD [CS:FilterFreqValue] ; 0->127*256 + FMul [CS:FreqParameterMultiplier] ; -i/(24*256) + FLd ST + FRndInt + FSub ST(1), ST + FXCh + F2XM1 + FLd1 + FAdd + FScale ; = 2^(i/24*256) + FMul [CS:FreqMultiplier] ; = r + FLd ST ; r, r + FMul ST(1), ST ; r, r^2 + + FLd [CS:QualityFactorTable+BX] ; 2d, r, r^2 + FMul ST(1), ST ; 2d, 2dr, r^2 + FAdd + + FLd1 ; 1, d+1, e + FXCh ; d+1, 1, e + FSubR ST(1), ST + FAdd ST, ST(2) ; 1+d+e, d, e + FDivR Const2048 ; 1/(1+d+e), d, e + FISt Word Ptr [SI+5Eh] ; + FLd ST(2) ; e, 1/(1+d+e), d, e + FAdd ST, ST + FAddP ST(2), ST ; 1/(1+d+e), d+2e, e + FMul ST(2), ST ; 1/(1+d+e), d+2e, e/(1+d+e) + FMul + FIStP Word Ptr [SI+6Eh] + FChs + FIStP Word Ptr [SI+7Eh] + FStP ST + Mov DWord Ptr [SI+0Ch], 0 + +MixMMXNoFilters: + Mov EBX, [SI+0Ch] + + Cmp Stereo, 0 + JNE MixMMXStereo + +MixMMXMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + + Jmp MixModeVolumeCheck + +MixMMXStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE MixMMXSurround + + Mul Byte Ptr MixVolume ; 0->128 + Mul Word Ptr [SI+4Ah] ; 0->32768 + ShRD AX, DX, 15 ; Maxvol = 8192 + Mov [SI+0Eh], AX ; Store into right volume + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 15 + Mov [SI+0Ch], AX + + Jmp MixModeVolumeCheck + +MixMMXSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 10 + Mov [SI+0Ch], AX + Neg AX + Mov [SI+0Eh], AX + +MixModeVolumeCheck: + Test CH, 3+4 + JNZ MixModeCommon + + Cmp EBX, [SI+0Ch] ; Same as last volume? + JE MixSamplesMix + +MixModeCommon: ; Requires AX = 30 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov AX, MixModeOffset + + Cmp DWord Ptr [SI+0Ch], 0 + JNE MixModeActualMix + + Cmp MixMode, 2 + JB MixMMXGeneralNoRamp + + Cmp DWord Ptr [SI+1Ch], 0 + JNE MixModeActualMix + +MixMMXGeneralNoRamp: + Mov AX, 4*60 + Jmp MixModeCommon1 + +MixModeActualMix: + Cmp MixMode, 3 + JNE MixModeFilter + + Cmp Word Ptr [SI+6Eh], 0 + JNE MixModeFilter + Cmp Word Ptr [SI+7Eh], 0 + JNE MixModeFilter + + Sub AX, 60 + +MixModeFilter: + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 30 + +MixModeCommon1: + Cmp Byte Ptr [SI+0Ah], 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, DMABUFFERLENGTH*2+80 + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Push Word Ptr [SI+8] + Call Word Ptr [CS:BX] + Pop BX + + And Word Ptr [SI], 0111100010001101b + + Cmp BX, Offset MixFunctionTables+60*2 + JB MixSamplesEnd + Cmp BX, Offset MixFunctionTables+60*4 + JAE MixSamplesEnd + + MovDR AX, MM6 + Mov [SI+0Ch], EAX + Mov [SI+1Ch], EAX + + Cmp BX, Offset MixfunctionTables+60*3 + JB MixSamplesEnd + + Mov ES, CS:MixSegment + Mov DX, [ES:10h] + Mov BX, [ES:14h] + Mov [SI+3Ch], DX + Mov [SI+6h], BX + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + +IF OUTPUTFILTERENABLED + include equalize.inc +ENDIF + Ret + +EndP MixSamples + Assume DS:Nothing + +; + +; + diff --git a/it/SoundDrivers/K6TRANS.INC b/it/SoundDrivers/K6TRANS.INC new file mode 100755 index 0000000..3bfb278 --- /dev/null +++ b/it/SoundDrivers/K6TRANS.INC @@ -0,0 +1,119 @@ + +; To be embedded within the IRQ handler. + + Push DX + + Cmp CS:Stereo, 0 + JNE TransferStereoBufferMMX + +TransferMonoBufferMMX: ; DX = number of 32 bit numbers -> 16 bit. + + Push DX + ShR DX, 3 + JZ TransferMonoBufferMMX2 + +TransferMonoBufferMMX1: + MovD MM0, [SI] + MovD MM1, [SI+8] + MovD MM2, [SI+10h] + MovD MM3, [SI+18h] + MovD MM4, [SI+20h] + MovD MM5, [SI+28h] + MovD MM6, [SI+30h] + MovD MM7, [SI+38h] + + PUnpckLDQ MM0, MM1 ; MM0 = S2|S1 + PUnpckLDQ MM2, MM3 ; MM2 = S4|S3 + PUnpckLDQ MM4, MM5 ; MM4 = S6|S5 + PUnpckLDQ MM6, MM7 ; MM6 = S8|S7 + + PF2ID MM0, MM0 + PF2ID MM2, MM2 + PF2ID MM4, MM4 + PF2ID MM6, MM6 + + + PackSSDW MM0, MM2 + PackSSDW MM4, MM6 + + MovQ [DI], MM0 + MovQ [DI+8], MM4 + + Add SI, 40h + Add DI, 10h + + Dec DX + JNZ TransferMonoBufferMMX1 + +TransferMonoBufferMMX2: + Pop CX + Mov DX, CX + + And CX, 7 + JZ TransferMonoBufferMMX4 + +TransferMonoBufferMMX3: + MovD MM0, [SI] + PF2ID MM0, MM0 + MovD EAX, MM0 + StosW + Add SI, 8 + + Loop TransferMonoBufferMMX3 + +TransferMonoBufferMMX4: + Jmp MMXMixTransferEnd + +TransferStereoBufferMMX: ; DX is always an even number for stereo + Push DX + + ShR DX, 3 + JZ TransferStereoBufferMMX2 + +TransferStereoBufferMMX1: ; DX = number of 32 bit numbers -> 16 bit + MovQ MM0, [SI] + MovQ MM1, [SI+8] + MovQ MM2, [SI+10h] + MovQ MM3, [SI+18h] + + PF2ID MM0, MM0 + PF2ID MM1, MM1 + PF2ID MM2, MM2 + PF2ID MM3, MM3 + + PackSSDW MM0, MM1 + PackSSDW MM2, MM3 + + MovQ [DI], MM0 + MovQ [DI+8], MM2 + + Add SI, 20h + Add DI, 10h + + Dec DX + JNZ TransferStereoBufferMMX1 + +TransferStereoBufferMMX2: + Pop CX + Mov DX, CX + + And CX, 7 + ShR CX, 1 ; Always an even number! + JZ TransferStereoBufferMMX4 + +TransferStereoBufferMMX3: + MovQ MM0, [SI] + PF2ID MM0, MM0 + PackSSDW MM0, MM0 + MovD [DI], MM0 + + Add SI, 8 + Add DI, 4 + + Loop TransferStereoBufferMMX3 + +TransferStereoBufferMMX4: + +MMXMixTransferEnd: + Pop DX + diff --git a/it/SoundDrivers/LOADSAM.INC b/it/SoundDrivers/LOADSAM.INC new file mode 100755 index 0000000..6eb0a12 --- /dev/null +++ b/it/SoundDrivers/LOADSAM.INC @@ -0,0 +1,71 @@ +Proc LoadSample Far ; Fix up end of sample bytes + + PushAD + Push DS + Push ES + Push FS + + Mov FS, CS:SongDataArea + Mov BP, AX + Add BP, BP + Mov BP, [FS:64910+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length + JC LoadSampleEnd ; Zero flag ON if 16 bit.. + + Xor EAX, EAX + Mov BL, [FS:BP+12h] + + Test BL, 10h ; Loop + JZ LoadSample2 + + Mov ESI, [FS:BP+34h] ; Start of loop + Test BL, 40h ; Pingpong? + JZ LoadSample1 + + Mov ESI, [FS:BP+38h] + Sub ESI, 2 + JNC LoadSample1 + + Xor ESI, ESI + +LoadSample1: + Test BL, 2 + JZ LoadSample4 + + Add ESI, ESI + +LoadSample4: + Int 3 + Mov AL, [SI] + Inc ESI + Int 3 + Mov AH, [SI] + +LoadSample2: + Mov ESI, [FS:BP+30h] + Test BL, 2 + JZ LoadSample3 + + Add ESI, ESI + +LoadSample3: + Int 3 + Mov [SI], AL + Inc ESI + Int 3 + Mov [SI], AH + +LoadSampleEnd: + Pop FS + Pop ES + Pop DS + PopAD + + StC + Ret + +EndP LoadSample + + diff --git a/it/SoundDrivers/LPT1DRV.ASM b/it/SoundDrivers/LPT1DRV.ASM new file mode 100755 index 0000000..c52b0fd --- /dev/null +++ b/it/SoundDrivers/LPT1DRV.ASM @@ -0,0 +1,904 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 0 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 16 ; 16 bit mixing for the SB Pro +MIXTABLESIZE EQU 2*256*65 + +SBProMsg DB "Using DAC on LPT1, Port ", 0FDh, "Xh", 0 + +SBProNoMemoryMsg DB " Using DAC on LPT1", 13 + DB " Error: Insufficient memory", 0 + +ReinitMsg DB "DAC on LPT1 reinitialised", 0 + +DSPVersion DW 0 +Forced DB 0 +InInterrupt DB 0 + +BytesToMix DW 1000 +MixSpeed DW 22000 +MixConst DW 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +DMASize DW 2048 + +OldIRQHandler DD 0 +TimerAccumulator DW 0 + +; MixingRoutines + +MixBufferPos DW 0 +OutputBufferPos DW 0 +OutputBlockEnd DW 1024 + +include mix.inc +include mono12b.mix + +MixFunctionTables Label + +include mono12b.inc ; contains the tables + +; + +Proc GetMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + + Cmp AX, 12000 + JB GetMixConst1 + + Cmp AX, 44100 + JA GetMixConst1 + + Mov CX, AX + +GetMixConst1: + Mov DX, 0012h + Mov AX, 34DDh + + Div CX + ; AX = mix const + Mov MixConst, AX + + Mov DX, 12h + Mov AX, 34DDh + Div MixConst + + Mov MixSpeed, AX + + Pop ES + Pop DS + PopA + Ret + +EndP GetMixConst + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push ES + + Xor AX, AX + Mov ES, AX + Mov AX, [ES:408h] ; LPT1 port + + Pop ES + And AX, AX + JZ DetectCard1 + + Mov Word Ptr CS:LPTPortNumber, AX + + Mov EAX, 'Jeff' + ClC + Ret + +DetectCard1: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Mov AX, 2020h + + Mov BX, CX ; BX = bytes to mix + Mov DX, CX + + Mov MixTransferOffset, DI ; } Memory write + Rep StosW ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + Jmp MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + +Mix0Mode: ; 16-bit mixing, no interpolation, no ramping +Mix0ModeMono: + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AX, 30 ; Use left only-mixing for mono + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 60 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Mov [SI+8], AX ; Offset... + + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, MixTransferRemaining + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc PCSpeakerIRQHandler + + Push AX + Push BX + Push DX + Push DS + + Mov DS, CS:DMASegment + Mov BX, CS:OutputBufferPos + +LPTPortNumber EQU $+1 + Mov DX, 1234h + + Mov AL, [BX] + Out DX, AL + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Inc BX + ; OK.. which IRQ handler? + Mov AX, MixConst + Add TimerAccumulator, AX + JC PCSpeakerIRQHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp PCSpeakerIRQHandler2 + +PCSpeakerIRQHandler1: + PushF + Call OldIRQHandler + +PCSpeakerIRQHandler2: + Mov OutputBufferPos, BX + Cmp BX, OutputBlockEnd + JAE PCSpeakerIRQHandler3 + +PCSpeakerIRQHandlerEnd: + Pop DS + Pop DX + Pop BX + Pop AX + + IRet + +PCSpeakerIRQHandler3: + Mov BX, DMASize + Mov AX, OutputBlockEnd + Add AX, BX + Cmp AX, DMABUFFERLENGTH + JBE PCSpeakerIRQHandler4 + + Mov AX, BX + Mov OutputBufferPos, 0 + +PCSpeakerIRQHandler4: + Mov OutputBlockEnd, AX + + Cmp InInterrupt, 0 + JA PCSpeakerIRQHandlerEnd + + Inc InInterrupt + + ClD + + PushAD + Push ES + + Mov ES, CS:DMASegment + Mov DI, OutputBufferPos + + Call SaveEMSPageFrame + + StI + ; BX = bytes required + + Cmp MixTransferRemaining, 0 + JNE SBProIRQHandler4 + Assume DS:Nothing + +SBProIRQHandler3: + Push BX + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BX + +SBProIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SBProIRQHandler5 + + Mov DX, MixTransferRemaining + +SBProIRQHandler5: + Push BX + Push DX + +SBProIRQHandler6: + Mov AX, [SI] + SAR AX, 6 + + Test AH, AH + JNZ SBProIRQHandlerClip1 + +SBProIRQHandler7: + StosB ; } Memory write + + Add SI, 2 + Dec DX + JNZ SBProIRQHandler6 + + Pop DX + Pop BX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SBProIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Dec InInterrupt + +PCSpkEnd2: + Pop ES + PopAD + Pop DS + Pop DX + Pop BX + Pop AX + IRet + +SBProIRQHandlerClip1: + Mov AL, 0 + JS SBProIRQHandler7 + Mov AL, 0FFh + Jmp SBProIRQHandler7 + +EndP PCSpeakerIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov OutputBufferPos, 0 + Mov OutputBlockEnd, 1024 + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Mov AX, MixConst + Out 40h, AL + Mov AL, AH + Out 40h, AL + + Xor AX, AX + Mov ES, AX + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset PCSpeakerIRQHandler + + ClI + + XChg [ES:20h], EAX + Mov OldIRQHandler, EAX + + StI + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AL, 34h ; Reset IRQ calling rate. + Out 43h, AL + Xor AL, AL + Out 40h, AL + Out 40h, AL + + Xor AX, AX + Mov ES, AX + + Mov EAX, OldIRQHandler + Mov [ES:20h], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + Call GetMixConst + + Mov AX, 661 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, DMABUFFERLENGTH/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SBProNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call GetTempo + Call SetTempo + Call SetIRQ + + Mov SI, Offset SBProMsg + Mov AX, Word Ptr LPTPortNumber + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + StC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/LPT2DRV.ASM b/it/SoundDrivers/LPT2DRV.ASM new file mode 100755 index 0000000..d30e254 --- /dev/null +++ b/it/SoundDrivers/LPT2DRV.ASM @@ -0,0 +1,904 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 0 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 16 ; 16 bit mixing for the SB Pro +MIXTABLESIZE EQU 2*256*65 + +SBProMsg DB "Using DAC on LPT2, Port ", 0FDh, "Xh", 0 + +SBProNoMemoryMsg DB " Using DAC on LPT2", 13 + DB " Error: Insufficient memory", 0 + +ReinitMsg DB "DAC on LPT2 reinitialised", 0 + +DSPVersion DW 0 +Forced DB 0 +InInterrupt DB 0 + +BytesToMix DW 1000 +MixSpeed DW 22000 +MixConst DW 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +DMASize DW 2048 + +OldIRQHandler DD 0 +TimerAccumulator DW 0 + +; MixingRoutines + +MixBufferPos DW 0 +OutputBufferPos DW 0 +OutputBlockEnd DW 1024 + +include mix.inc +include mono12b.mix + +MixFunctionTables Label + +include mono12b.inc ; contains the tables + +; + +Proc GetMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + + Cmp AX, 12000 + JB GetMixConst1 + + Cmp AX, 44100 + JA GetMixConst1 + + Mov CX, AX + +GetMixConst1: + Mov DX, 0012h + Mov AX, 34DDh + + Div CX + ; AX = mix const + Mov MixConst, AX + + Mov DX, 12h + Mov AX, 34DDh + Div MixConst + + Mov MixSpeed, AX + + Pop ES + Pop DS + PopA + Ret + +EndP GetMixConst + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push ES + + Xor AX, AX + Mov ES, AX + Mov AX, [ES:40Ah] ; LPT2 port + + Pop ES + And AX, AX + JZ DetectCard1 + + Mov Word Ptr CS:LPTPortNumber, AX + + Mov EAX, 'Jeff' + ClC + Ret + +DetectCard1: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Mov AX, 2020h + + Mov BX, CX ; BX = bytes to mix + Mov DX, CX + + Mov MixTransferOffset, DI ; } Memory write + Rep StosW ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + Jmp MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + +Mix0Mode: ; 16-bit mixing, no interpolation, no ramping +Mix0ModeMono: + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AX, 30 ; Use left only-mixing for mono + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 60 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Mov [SI+8], AX ; Offset... + + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, MixTransferRemaining + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc PCSpeakerIRQHandler + + Push AX + Push BX + Push DX + Push DS + + Mov DS, CS:DMASegment + Mov BX, CS:OutputBufferPos + +LPTPortNumber EQU $+1 + Mov DX, 1234h + + Mov AL, [BX] + Out DX, AL + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Inc BX + ; OK.. which IRQ handler? + Mov AX, MixConst + Add TimerAccumulator, AX + JC PCSpeakerIRQHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp PCSpeakerIRQHandler2 + +PCSpeakerIRQHandler1: + PushF + Call OldIRQHandler + +PCSpeakerIRQHandler2: + Mov OutputBufferPos, BX + Cmp BX, OutputBlockEnd + JAE PCSpeakerIRQHandler3 + +PCSpeakerIRQHandlerEnd: + Pop DS + Pop DX + Pop BX + Pop AX + + IRet + +PCSpeakerIRQHandler3: + Mov BX, DMASize + Mov AX, OutputBlockEnd + Add AX, BX + Cmp AX, DMABUFFERLENGTH + JBE PCSpeakerIRQHandler4 + + Mov AX, BX + Mov OutputBufferPos, 0 + +PCSpeakerIRQHandler4: + Mov OutputBlockEnd, AX + + Cmp InInterrupt, 0 + JA PCSpeakerIRQHandlerEnd + + Inc InInterrupt + + ClD + + PushAD + Push ES + + Mov ES, CS:DMASegment + Mov DI, OutputBufferPos + + Call SaveEMSPageFrame + + StI + ; BX = bytes required + + Cmp MixTransferRemaining, 0 + JNE SBProIRQHandler4 + Assume DS:Nothing + +SBProIRQHandler3: + Push BX + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BX + +SBProIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SBProIRQHandler5 + + Mov DX, MixTransferRemaining + +SBProIRQHandler5: + Push BX + Push DX + +SBProIRQHandler6: + Mov AX, [SI] + SAR AX, 6 + + Test AH, AH + JNZ SBProIRQHandlerClip1 + +SBProIRQHandler7: + StosB ; } Memory write + + Add SI, 2 + Dec DX + JNZ SBProIRQHandler6 + + Pop DX + Pop BX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SBProIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Dec InInterrupt + +PCSpkEnd2: + Pop ES + PopAD + Pop DS + Pop DX + Pop BX + Pop AX + IRet + +SBProIRQHandlerClip1: + Mov AL, 0 + JS SBProIRQHandler7 + Mov AL, 0FFh + Jmp SBProIRQHandler7 + +EndP PCSpeakerIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov OutputBufferPos, 0 + Mov OutputBlockEnd, 1024 + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Mov AX, MixConst + Out 40h, AL + Mov AL, AH + Out 40h, AL + + Xor AX, AX + Mov ES, AX + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset PCSpeakerIRQHandler + + ClI + + XChg [ES:20h], EAX + Mov OldIRQHandler, EAX + + StI + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AL, 34h ; Reset IRQ calling rate. + Out 43h, AL + Xor AL, AL + Out 40h, AL + Out 40h, AL + + Xor AX, AX + Mov ES, AX + + Mov EAX, OldIRQHandler + Mov [ES:20h], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + Call GetMixConst + + Mov AX, 661 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, DMABUFFERLENGTH/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SBProNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call GetTempo + Call SetTempo + Call SetIRQ + + Mov SI, Offset SBProMsg + Mov AX, Word Ptr LPTPortNumber + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + StC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/M12BIT.INC b/it/SoundDrivers/M12BIT.INC new file mode 100755 index 0000000..cc25545 --- /dev/null +++ b/it/SoundDrivers/M12BIT.INC @@ -0,0 +1,49 @@ + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix12Left8Bit, MFS8Bit, MBS8Bit, Mix12Single8Bit + DW Offset MixForwardsLoop, PreMix12Left8Bit, MFS8Bit, MBS8Bit, Mix12Single8Bit + DW Offset MixPingPongLoop, PreMix12Left8Bit, MFS8Bit, MBS8Bit, Mix12Single8Bit + ; Right only + DW Offset MixNoLoop, PreMix12Right8Bit, MFS8Bit, MBS8Bit, Mix12Single8Bit + DW Offset MixForwardsLoop, PreMix12Right8Bit, MFS8Bit, MBS8Bit, Mix12Single8Bit + DW Offset MixPingPongLoop, PreMix12Right8Bit, MFS8Bit, MBS8Bit, Mix12Single8Bit + ; Central + DW Offset MixNoLoop, PreMix12Central8Bit, MFS8Bit, MBS8Bit, Mix12Central8Bit + DW Offset MixForwardsLoop, PreMix12Central8Bit, MFS8Bit, MBS8Bit, Mix12Central8Bit + DW Offset MixPingPongLoop, PreMix12Central8Bit, MFS8Bit, MBS8Bit, Mix12Central8Bit + ; Stereo + DW Offset MixNoLoop, PreMix12Panned8Bit, MFS8Bit, MBS8Bit, Mix12Panned8Bit + DW Offset MixForwardsLoop, PreMix12Panned8Bit, MFS8Bit, MBS8Bit, Mix12Panned8Bit + DW Offset MixPingPongLoop, PreMix12Panned8Bit, MFS8Bit, MBS8Bit, Mix12Panned8Bit + ; Surround + DW Offset MixNoLoop, PreMix12Surround8Bit, MFS8Bit, MBS8Bit, Mix12Surround8Bit + DW Offset MixForwardsLoop, PreMix12Surround8Bit, MFS8Bit, MBS8Bit, Mix12Surround8Bit + DW Offset MixPingPongLoop, PreMix12Surround8Bit, MFS8Bit, MBS8Bit, Mix12Surround8Bit + + ; 16 bit tables + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix12Left16Bit, MFS16Bit, MBS16Bit, Mix12Single16Bit + DW Offset MixForwardsLoop, PreMix12Left16Bit, MFS16Bit, MBS16Bit, Mix12Single16Bit + DW Offset MixPingPongLoop, PreMix12Left16Bit, MFS16Bit, MBS16Bit, Mix12Single16Bit + ; Right only + DW Offset MixNoLoop, PreMix12Right16Bit, MFS16Bit, MBS16Bit, Mix12Single16Bit + DW Offset MixForwardsLoop, PreMix12Right16Bit, MFS16Bit, MBS16Bit, Mix12Single16Bit + DW Offset MixPingPongLoop, PreMix12Right16Bit, MFS16Bit, MBS16Bit, Mix12Single16Bit + ; Central + DW Offset MixNoLoop, PreMix12Central16Bit, MFS16Bit, MBS16Bit, Mix12Central16Bit + DW Offset MixForwardsLoop, PreMix12Central16Bit, MFS16Bit, MBS16Bit, Mix12Central16Bit + DW Offset MixPingPongLoop, PreMix12Central16Bit, MFS16Bit, MBS16Bit, Mix12Central16Bit + ; Stereo + DW Offset MixNoLoop, PreMix12Panned16Bit, MFS16Bit, MBS16Bit, Mix12Panned16Bit + DW Offset MixForwardsLoop, PreMix12Panned16Bit, MFS16Bit, MBS16Bit, Mix12Panned16Bit + DW Offset MixPingPongLoop, PreMix12Panned16Bit, MFS16Bit, MBS16Bit, Mix12Panned16Bit + ; Surround + DW Offset MixNoLoop, PreMix12Surround16Bit, MFS16Bit, MBS16Bit, Mix12Surround16Bit + DW Offset MixForwardsLoop, PreMix12Surround16Bit, MFS16Bit, MBS16Bit, Mix12Surround16Bit + DW Offset MixPingPongLoop, PreMix12Surround16Bit, MFS16Bit, MBS16Bit, Mix12Surround16Bit diff --git a/it/SoundDrivers/M12BIT.MIX b/it/SoundDrivers/M12BIT.MIX new file mode 100755 index 0000000..6c37825 --- /dev/null +++ b/it/SoundDrivers/M12BIT.MIX @@ -0,0 +1,813 @@ + + ; Different mixing routines required: + ; Left } shared + ; Right } + ; Central + ; Surround + ; Panned ; Each requires 8 bit and 16 bit + ; Single output - for Mono, pure left/pure right + +M12Mix8Single Macro Index + +M12Mix8Single&Index&: + Mov BL, [ES:DI] ;; 2 + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8Central Macro Index + +M12Mix8Central&Index&: + Mov BL, [ES:DI] ;; 2 + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8Surround Macro Index + +M12Mix8Surround&Index&: + Mov BL, [ES:DI] ;; 2 + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + Add [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX ;; 3 + +EndM + + ; Panned output +M12Mix8PannedNext Macro Index + +M12Mix8PannedVolume&Index& EQU $+1 + Mov BH, 12h + Mov BL, [ES:DI] + +EndM + +M12Mix8Panned Macro Index + +M12Mix8Panned&Index&: + Add BX, BX + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [BX] + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +M12Mix8PannedRightVolumeOffset&Index& EQU $+3 + Mov AX, [BX+1200h] + + M12Mix8PannedNext %(Index+1) + + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +M12Mix16Single Macro Index + +M12Mix16Single&Index&: + Mov BL, [ES:EDI+EDI+1] + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +EndM + +M12Mix16Central Macro Index + +M12Mix16Central&Index&: + Mov BL, [ES:EDI+EDI+1] + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +M12Mix16Surround Macro Index + +M12Mix16Surround&Index&: + Mov BL, [ES:EDI+EDI+1] + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + Add [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + + ; Panned output +M12Mix16PannedNext Macro Index + +M12Mix16PannedVolume&Index& EQU $+1 + Mov BH, 12h + Mov BL, [ES:EDI+EDI+1] + +EndM + +M12Mix16Panned Macro Index + +M12Mix16Panned&Index&: + Add BX, BX + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [BX] + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +M12Mix16PannedRightVolumeOffset&Index& EQU $+3 + Mov AX, [BX+1200h] + + M12Mix16PannedNext %(Index+1) + + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +; + +Mix12Single8BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8SingleOffset Macro Index + DW Offset M12Mix8Single&Index& + EndM + + REPT 16 + M12Mix8SingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Single8Bit + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Single8BitOffsetTable+BX] + +M12Single8BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + RetN + + M12Mix8Single 0 + M12Mix8Single 1 + M12Mix8Single 2 + M12Mix8Single 3 + M12Mix8Single 4 + M12Mix8Single 5 + M12Mix8Single 6 + M12Mix8Single 7 + M12Mix8Single 8 + M12Mix8Single 9 + M12Mix8Single 10 + M12Mix8Single 11 + M12Mix8Single 12 + M12Mix8Single 13 + M12Mix8Single 14 + M12Mix8Single 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8Single0 + + Ret + +EndP Mix12Single8Bit + +; + +Proc PreMix12Left8Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Single8BitVolume], AL + Ret + +EndP PreMix12Left8Bit + +; + +Proc PreMix12Right8Bit + + Add MixBufferOffset, MixResolution/8 + Mov AL, [SI+0Ch] + Mov Byte Ptr [CS:M12Single8BitVolume], AL + + Ret + +EndP PreMix12Right8Bit + +; + +Mix12Central8BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8CentralOffset Macro Index + DW Offset M12Mix8Central&Index& + EndM + + REPT 16 + M12Mix8CentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Central8BitOffsetTable+BX] + +M12Central8BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + RetN + + M12Mix8Central 0 + M12Mix8Central 1 + M12Mix8Central 2 + M12Mix8Central 3 + M12Mix8Central 4 + M12Mix8Central 5 + M12Mix8Central 6 + M12Mix8Central 7 + M12Mix8Central 8 + M12Mix8Central 9 + M12Mix8Central 10 + M12Mix8Central 11 + M12Mix8Central 12 + M12Mix8Central 13 + M12Mix8Central 14 + M12Mix8Central 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8Central0 + + Ret + +EndP Mix12Central8Bit + +; + +Proc PreMix12Central8Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Central8BitVolume], AL + + Ret + +EndP PreMix12Central8Bit + +; + +Mix12Surround8BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8SurroundOffset Macro Index + DW Offset M12Mix8Surround&Index& + EndM + + REPT 16 + M12Mix8SurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Surround8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Surround8BitOffsetTable+BX] + +M12Surround8BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + + RetN + + M12Mix8Surround 0 + M12Mix8Surround 1 + M12Mix8Surround 2 + M12Mix8Surround 3 + M12Mix8Surround 4 + M12Mix8Surround 5 + M12Mix8Surround 6 + M12Mix8Surround 7 + M12Mix8Surround 8 + M12Mix8Surround 9 + M12Mix8Surround 10 + M12Mix8Surround 11 + M12Mix8Surround 12 + M12Mix8Surround 13 + M12Mix8Surround 14 + M12Mix8Surround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8Surround0 + + Ret + +EndP Mix12Surround8Bit + +; + +Proc PreMix12Surround8Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Surround8BitVolume], AL + + Ret + +EndP PreMix12Surround8Bit + +; + +Mix12Panned8BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8PannedOffset Macro Index + DW Offset M12Mix8Panned&Index& + EndM + + REPT 16 + M12Mix8PannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Panned8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Panned8BitOffsetTable+BX] + + M12Mix8PannedNext 0 + + RetN + + M12Mix8Panned 0 + M12Mix8Panned 1 + M12Mix8Panned 2 + M12Mix8Panned 3 + M12Mix8Panned 4 + M12Mix8Panned 5 + M12Mix8Panned 6 + M12Mix8Panned 7 + M12Mix8Panned 8 + M12Mix8Panned 9 + M12Mix8Panned 10 + M12Mix8Panned 11 + M12Mix8Panned 12 + M12Mix8Panned 13 + M12Mix8Panned 14 + M12Mix8Panned 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8Panned0 + + Ret + +EndP Mix12Panned8Bit + +; + +Proc PreMix12Panned8Bit + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12PannedMacro Macro Index + Mov Byte Ptr [CS:M12Mix8PannedVolume&Index&], AL + EndM + + REPT 17 + PreMix12PannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Mov AL, [SI+0Ch] + Sub AL, [SI+0Eh] + Add AL, AL + + IndexCounter = 0 + + PreMix12PannedMacro2 Macro Index + Mov Byte Ptr [CS:M12Mix8PannedRightVolumeOffset&Index&], AL + EndM + + REPT 16 + PreMix12PannedMacro2 %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Panned8Bit + +; + +Mix12Single16BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16SingleOffset Macro Index + DW Offset M12Mix16Single&Index& + EndM + + REPT 16 + M12Mix16SingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Single16Bit + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Single16BitOffsetTable+BX] + +M12Single16BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + RetN + + M12Mix16Single 0 + M12Mix16Single 1 + M12Mix16Single 2 + M12Mix16Single 3 + M12Mix16Single 4 + M12Mix16Single 5 + M12Mix16Single 6 + M12Mix16Single 7 + M12Mix16Single 8 + M12Mix16Single 9 + M12Mix16Single 10 + M12Mix16Single 11 + M12Mix16Single 12 + M12Mix16Single 13 + M12Mix16Single 14 + M12Mix16Single 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16Single0 + + Ret + +EndP Mix12Single16Bit + +; + +Proc PreMix12Left16Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Single16BitVolume], AL + Ret + +EndP PreMix12Left16Bit + +; + +Proc PreMix12Right16Bit + + Add MixBufferOffset, MixResolution/8 + Mov AL, [SI+0Ch] + Mov Byte Ptr [CS:M12Single16BitVolume], AL + + Ret + +EndP PreMix12Right16Bit + +; + +Mix12Central16BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16CentralOffset Macro Index + DW Offset M12Mix16Central&Index& + EndM + + REPT 16 + M12Mix16CentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Central16BitOffsetTable+BX] + +M12Central16BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + + RetN + + M12Mix16Central 0 + M12Mix16Central 1 + M12Mix16Central 2 + M12Mix16Central 3 + M12Mix16Central 4 + M12Mix16Central 5 + M12Mix16Central 6 + M12Mix16Central 7 + M12Mix16Central 8 + M12Mix16Central 9 + M12Mix16Central 10 + M12Mix16Central 11 + M12Mix16Central 12 + M12Mix16Central 13 + M12Mix16Central 14 + M12Mix16Central 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16Central0 + + Ret + +EndP Mix12Central16Bit + +; + +Proc PreMix12Central16Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Central16BitVolume], AL + + Ret + +EndP PreMix12Central16Bit + +; + +Mix12Surround16BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16SurroundOffset Macro Index + DW Offset M12Mix16Surround&Index& + EndM + + REPT 16 + M12Mix16SurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Surround16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Surround16BitOffsetTable+BX] + +M12Surround16BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + + RetN + + M12Mix16Surround 0 + M12Mix16Surround 1 + M12Mix16Surround 2 + M12Mix16Surround 3 + M12Mix16Surround 4 + M12Mix16Surround 5 + M12Mix16Surround 6 + M12Mix16Surround 7 + M12Mix16Surround 8 + M12Mix16Surround 9 + M12Mix16Surround 10 + M12Mix16Surround 11 + M12Mix16Surround 12 + M12Mix16Surround 13 + M12Mix16Surround 14 + M12Mix16Surround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16Surround0 + + Ret + +EndP Mix12Surround16Bit + +; + +Proc PreMix12Surround16Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Surround16BitVolume], AL + + Ret + +EndP PreMix12Surround16Bit + +; + +Mix12Panned16BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16PannedOffset Macro Index + DW Offset M12Mix16Panned&Index& + EndM + + REPT 16 + M12Mix16PannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Panned16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Panned16BitOffsetTable+BX] + + M12Mix16PannedNext 0 + + RetN + +Pan12Bit16Loop: + M12Mix16PannedNext 16 + + M12Mix16Panned 0 + M12Mix16Panned 1 + M12Mix16Panned 2 + M12Mix16Panned 3 + M12Mix16Panned 4 + M12Mix16Panned 5 + M12Mix16Panned 6 + M12Mix16Panned 7 + M12Mix16Panned 8 + M12Mix16Panned 9 + M12Mix16Panned 10 + M12Mix16Panned 11 + M12Mix16Panned 12 + M12Mix16Panned 13 + M12Mix16Panned 14 + + M12Mix16Panned15: + Add BX, BX + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [BX] + Sub [SI+EXTRAOFFSET], AX + M12Mix16PannedRightVolumeOffset15 EQU $+3 + Mov AX, [BX+1200h] + Sub [SI+MixResolution/8+EXTRAOFFSET], AX + + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ Pan12Bit16Loop + + Ret + +EndP Mix12Panned16Bit + +; + +Proc PreMix12Panned16Bit + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12PannedMacro Macro Index + Mov Byte Ptr [CS:M12Mix16PannedVolume&Index&], AL + EndM + + REPT 17 + PreMix12PannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Mov AL, [SI+0Ch] + Sub AL, [SI+0Eh] + Add AL, AL + + IndexCounter = 0 + + PreMix12PannedMacro2 Macro Index + Mov Byte Ptr [CS:M12Mix16PannedRightVolumeOffset&Index&], AL + EndM + + REPT 16 + PreMix12PannedMacro2 %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Panned16Bit + + +; +; + diff --git a/it/SoundDrivers/M12BITF.INC b/it/SoundDrivers/M12BITF.INC new file mode 100755 index 0000000..dec5297 --- /dev/null +++ b/it/SoundDrivers/M12BITF.INC @@ -0,0 +1,49 @@ + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix12Left8BitF, MFS8Bit, MBS8Bit, Mix12Single8BitF + DW Offset MixForwardsLoop, PreMix12Left8BitF, MFS8Bit, MBS8Bit, Mix12Single8BitF + DW Offset MixPingPongLoop, PreMix12Left8BitF, MFS8Bit, MBS8Bit, Mix12Single8BitF + ; Right only + DW Offset MixNoLoop, PreMix12Right8BitF, MFS8Bit, MBS8Bit, Mix12Single8BitF + DW Offset MixForwardsLoop, PreMix12Right8BitF, MFS8Bit, MBS8Bit, Mix12Single8BitF + DW Offset MixPingPongLoop, PreMix12Right8BitF, MFS8Bit, MBS8Bit, Mix12Single8BitF + ; Central + DW Offset MixNoLoop, PreMix12Central8BitF, MFS8Bit, MBS8Bit, Mix12Central8BitF + DW Offset MixForwardsLoop, PreMix12Central8BitF, MFS8Bit, MBS8Bit, Mix12Central8BitF + DW Offset MixPingPongLoop, PreMix12Central8BitF, MFS8Bit, MBS8Bit, Mix12Central8BitF + ; Stereo + DW Offset MixNoLoop, PreMix12Panned8BitF, MFS8Bit, MBS8Bit, Mix12Panned8BitF + DW Offset MixForwardsLoop, PreMix12Panned8BitF, MFS8Bit, MBS8Bit, Mix12Panned8BitF + DW Offset MixPingPongLoop, PreMix12Panned8BitF, MFS8Bit, MBS8Bit, Mix12Panned8BitF + ; Surround + DW Offset MixNoLoop, PreMix12Surround8BitF, MFS8Bit, MBS8Bit, Mix12Surround8BitF + DW Offset MixForwardsLoop, PreMix12Surround8BitF, MFS8Bit, MBS8Bit, Mix12Surround8BitF + DW Offset MixPingPongLoop, PreMix12Surround8BitF, MFS8Bit, MBS8Bit, Mix12Surround8BitF + + ; 16 bit tables + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix12Left16BitF, MFS16Bit, MBS16Bit, Mix12Single16BitF + DW Offset MixForwardsLoop, PreMix12Left16BitF, MFS16Bit, MBS16Bit, Mix12Single16BitF + DW Offset MixPingPongLoop, PreMix12Left16BitF, MFS16Bit, MBS16Bit, Mix12Single16BitF + ; Right only + DW Offset MixNoLoop, PreMix12Right16BitF, MFS16Bit, MBS16Bit, Mix12Single16BitF + DW Offset MixForwardsLoop, PreMix12Right16BitF, MFS16Bit, MBS16Bit, Mix12Single16BitF + DW Offset MixPingPongLoop, PreMix12Right16BitF, MFS16Bit, MBS16Bit, Mix12Single16BitF + ; Central + DW Offset MixNoLoop, PreMix12Central16BitF, MFS16Bit, MBS16Bit, Mix12Central16BitF + DW Offset MixForwardsLoop, PreMix12Central16BitF, MFS16Bit, MBS16Bit, Mix12Central16BitF + DW Offset MixPingPongLoop, PreMix12Central16BitF, MFS16Bit, MBS16Bit, Mix12Central16BitF + ; Stereo + DW Offset MixNoLoop, PreMix12Panned16BitF, MFS16Bit, MBS16Bit, Mix12Panned16BitF + DW Offset MixForwardsLoop, PreMix12Panned16BitF, MFS16Bit, MBS16Bit, Mix12Panned16BitF + DW Offset MixPingPongLoop, PreMix12Panned16BitF, MFS16Bit, MBS16Bit, Mix12Panned16BitF + ; Surround + DW Offset MixNoLoop, PreMix12Surround16BitF, MFS16Bit, MBS16Bit, Mix12Surround16BitF + DW Offset MixForwardsLoop, PreMix12Surround16BitF, MFS16Bit, MBS16Bit, Mix12Surround16BitF + DW Offset MixPingPongLoop, PreMix12Surround16BitF, MFS16Bit, MBS16Bit, Mix12Surround16BitF diff --git a/it/SoundDrivers/M12BITF.MIX b/it/SoundDrivers/M12BITF.MIX new file mode 100755 index 0000000..75bd69b --- /dev/null +++ b/it/SoundDrivers/M12BITF.MIX @@ -0,0 +1,807 @@ + + ; Different mixing routines required: + ; Left } shared + ; Right } + ; Central + ; Surround + ; Panned ; Each requires 8 bit and 16 bit + ; Single output - for Mono, pure left/pure right + +Get8BitFWaveform Macro + Mov AL, [ES:DI] + Add BL, 80h + Add AL, 80h + Add BL, AL + RCR BL, 1 + Sub BL, 80h +EndM + +Get16BitFWaveform Macro + Mov AL, [ES:EDI+EDI+1] + Add BL, 80h + Add AL, 80h + Add BL, AL + RCR BL, 1 + Sub BL, 80h + +EndM + +M12Mix8FSingle Macro Index + +M12Mix8FSingle&Index&: + Get8BitFWaveForm + + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8FCentral Macro Index + +M12Mix8FCentral&Index&: + Get8BitFWaveform + + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8FSurround Macro Index + +M12Mix8FSurround&Index&: + Get8BitFWaveform + + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + Add [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8FPanned Macro Index + +M12Mix8FPanned&Index&: + Get8BitFWaveform + + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [EBX+EBX] + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +M12Mix8FPannedRightVolumeOffset&Index& EQU $+4 + Mov AX, [EBX+EBX+1200h] + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +M12Mix16FSingle Macro Index + +M12Mix16FSingle&Index&: + Get16BitFWaveForm + + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +EndM + +M12Mix16FCentral Macro Index + +M12Mix16FCentral&Index&: + Get16BitFWaveform + + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +M12Mix16FSurround Macro Index + +M12Mix16FSurround&Index&: + Get16BitFWaveform + + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + Add [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + + ; Panned output +M12Mix16FPanned Macro Index + +M12Mix16FPanned&Index&: + Get16BitFWaveform + + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [EBX+EBX] + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +M12Mix16FPannedRightVolumeOffset&Index& EQU $+4 + Mov AX, [EBX+EBX+1200h] + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +; + +Mix12Single8BitFOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8FSingleOffset Macro Index + DW Offset M12Mix8FSingle&Index& + EndM + + REPT 16 + M12Mix8FSingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Single8BitF + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Single8BitFOffsetTable+BX] + +Mix12Single8BitFVolume EQU $+3 + Mov EBX, 0 + + Mov BL, [ES:DI] + + RetN + + M12Mix8FSingle 0 + M12Mix8FSingle 1 + M12Mix8FSingle 2 + M12Mix8FSingle 3 + M12Mix8FSingle 4 + M12Mix8FSingle 5 + M12Mix8FSingle 6 + M12Mix8FSingle 7 + M12Mix8FSingle 8 + M12Mix8FSingle 9 + M12Mix8FSingle 10 + M12Mix8FSingle 11 + M12Mix8FSingle 12 + M12Mix8FSingle 13 + M12Mix8FSingle 14 + M12Mix8FSingle 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8FSingle0 + + Ret + +EndP Mix12Single8BitF + +; + +Proc PreMix12Left8BitF + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:Mix12Single8BitFVolume], AL + + Ret + +EndP PreMix12Left8BitF + +; + +Proc PreMix12Right8BitF + + Add MixBufferOffset, MixResolution/8 + Mov AL, [SI+0Ch] + Mov Byte Ptr [CS:Mix12Single8BitFVolume], AL + + Ret + +EndP PreMix12Right8BitF + +; + +Mix12Central8BitFOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8FCentralOffset Macro Index + DW Offset M12Mix8FCentral&Index& + EndM + + REPT 16 + M12Mix8FCentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central8BitF + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Central8BitFOffsetTable+BX] + +Mix12Central8BitFVolume EQU $+3 + Mov EBX, 0 + + Mov BL, [ES:DI] + + RetN + + M12Mix8FCentral 0 + M12Mix8FCentral 1 + M12Mix8FCentral 2 + M12Mix8FCentral 3 + M12Mix8FCentral 4 + M12Mix8FCentral 5 + M12Mix8FCentral 6 + M12Mix8FCentral 7 + M12Mix8FCentral 8 + M12Mix8FCentral 9 + M12Mix8FCentral 10 + M12Mix8FCentral 11 + M12Mix8FCentral 12 + M12Mix8FCentral 13 + M12Mix8FCentral 14 + M12Mix8FCentral 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8FCentral0 + + Ret + +EndP Mix12Central8BitF + +; + +Proc PreMix12Central8BitF + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:Mix12Central8BitFVolume], AL + + Ret + +EndP PreMix12Central8BitF + +; + +Mix12Surround8BitFOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8FSurroundOffset Macro Index + DW Offset M12Mix8FSurround&Index& + EndM + + REPT 16 + M12Mix8FSurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Surround8BitF + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Surround8BitFOffsetTable+BX] + +Mix12Surround8BitFVolume EQU $+3 + Mov EBX, 0 + + Mov BL, [ES:DI] + + RetN + + M12Mix8FSurround 0 + M12Mix8FSurround 1 + M12Mix8FSurround 2 + M12Mix8FSurround 3 + M12Mix8FSurround 4 + M12Mix8FSurround 5 + M12Mix8FSurround 6 + M12Mix8FSurround 7 + M12Mix8FSurround 8 + M12Mix8FSurround 9 + M12Mix8FSurround 10 + M12Mix8FSurround 11 + M12Mix8FSurround 12 + M12Mix8FSurround 13 + M12Mix8FSurround 14 + M12Mix8FSurround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8FSurround0 + + Ret + +EndP Mix12Surround8BitF + +; + +Proc PreMix12Surround8BitF + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:Mix12Surround8BitFVolume], AL + + Ret + +EndP PreMix12Surround8BitF + +; + +Mix12Panned8BitFOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8FPannedOffset Macro Index + DW Offset M12Mix8FPanned&Index& + EndM + + REPT 16 + M12Mix8FPannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Panned8BitF + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Panned8BitFOffsetTable+BX] + +Mix12Panned8BitFVolume EQU $+3 + Mov EBX, 0 + + Mov BL, [ES:DI] + + RetN + + M12Mix8FPanned 0 + M12Mix8FPanned 1 + M12Mix8FPanned 2 + M12Mix8FPanned 3 + M12Mix8FPanned 4 + M12Mix8FPanned 5 + M12Mix8FPanned 6 + M12Mix8FPanned 7 + M12Mix8FPanned 8 + M12Mix8FPanned 9 + M12Mix8FPanned 10 + M12Mix8FPanned 11 + M12Mix8FPanned 12 + M12Mix8FPanned 13 + M12Mix8FPanned 14 + M12Mix8FPanned 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8FPanned0 + + Ret + +EndP Mix12Panned8BitF + +; + +Proc PreMix12Panned8BitF + + Mov AL, [SI+0Eh] + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:Mix12Panned8BitFVolume], AL + + Xor AL, AL + Mov AH, [SI+0Ch] + Sub AH, [SI+0Eh] + Add AH, AH + MovSX EAX, AX + + IndexCounter = 0 + + PreMix12Panned8BitFMacro2 Macro Index + Mov DWord Ptr [CS:M12Mix8FPannedRightVolumeOffset&Index&], EAX + EndM + + REPT 16 + PreMix12Panned8BitFMacro2 %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Panned8BitF + +; + +Mix12Single16BitFOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16FSingleOffset Macro Index + DW Offset M12Mix16FSingle&Index& + EndM + + REPT 16 + M12Mix16FSingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Single16BitF + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Single16BitFOffsetTable+BX] + +Mix12Single16BitFVolume EQU $+3 + Mov EBX, 0 + + Mov BL, [ES:EDI+EDI+1] + + RetN + + M12Mix16FSingle 0 + M12Mix16FSingle 1 + M12Mix16FSingle 2 + M12Mix16FSingle 3 + M12Mix16FSingle 4 + M12Mix16FSingle 5 + M12Mix16FSingle 6 + M12Mix16FSingle 7 + M12Mix16FSingle 8 + M12Mix16FSingle 9 + M12Mix16FSingle 10 + M12Mix16FSingle 11 + M12Mix16FSingle 12 + M12Mix16FSingle 13 + M12Mix16FSingle 14 + M12Mix16FSingle 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16FSingle0 + + Ret + +EndP Mix12Single16BitF + +; + +Proc PreMix12Left16BitF + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:Mix12Single16BitFVolume], AL + + Ret + +EndP PreMix12Left16BitF + +; + +Proc PreMix12Right16BitF + + Add MixBufferOffset, MixResolution/8 + Mov AL, [SI+0Ch] + Mov Byte Ptr [CS:Mix12Single16BitFVolume], AL + + Ret + +EndP PreMix12Right16BitF + +; + +Mix12Central16BitFOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16FCentralOffset Macro Index + DW Offset M12Mix16FCentral&Index& + EndM + + REPT 16 + M12Mix16FCentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central16BitF + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Central16BitFOffsetTable+BX] + +Mix12Central16BitFVolume EQU $+3 + Mov EBX, 0 + + Mov BL, [ES:EDI+EDI+1] + + RetN + + M12Mix16FCentral 0 + M12Mix16FCentral 1 + M12Mix16FCentral 2 + M12Mix16FCentral 3 + M12Mix16FCentral 4 + M12Mix16FCentral 5 + M12Mix16FCentral 6 + M12Mix16FCentral 7 + M12Mix16FCentral 8 + M12Mix16FCentral 9 + M12Mix16FCentral 10 + M12Mix16FCentral 11 + M12Mix16FCentral 12 + M12Mix16FCentral 13 + M12Mix16FCentral 14 + M12Mix16FCentral 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16FCentral0 + + Ret + +EndP Mix12Central16BitF + +; + +Proc PreMix12Central16BitF + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:Mix12Central16BitFVolume], AL + + Ret + +EndP PreMix12Central16BitF + +; + +Mix12Surround16BitFOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16FSurroundOffset Macro Index + DW Offset M12Mix16FSurround&Index& + EndM + + REPT 16 + M12Mix16FSurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Surround16BitF + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Surround16BitFOffsetTable+BX] + +Mix12Surround16BitFVolume EQU $+3 + Mov EBX, 0 + + Mov BL, [ES:EDI+EDI+1] + + RetN + + M12Mix16FSurround 0 + M12Mix16FSurround 1 + M12Mix16FSurround 2 + M12Mix16FSurround 3 + M12Mix16FSurround 4 + M12Mix16FSurround 5 + M12Mix16FSurround 6 + M12Mix16FSurround 7 + M12Mix16FSurround 8 + M12Mix16FSurround 9 + M12Mix16FSurround 10 + M12Mix16FSurround 11 + M12Mix16FSurround 12 + M12Mix16FSurround 13 + M12Mix16FSurround 14 + M12Mix16FSurround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16FSurround0 + + Ret + +EndP Mix12Surround16BitF + +; + +Proc PreMix12Surround16BitF + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:Mix12Surround16BitFVolume], AL + + Ret + +EndP PreMix12Surround16BitF + +; + +Mix12Panned16BitFOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16FPannedOffset Macro Index + DW Offset M12Mix16FPanned&Index& + EndM + + REPT 16 + M12Mix16FPannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Panned16BitF + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Panned16BitFOffsetTable+BX] + +Mix12Panned16BitFVolume EQU $+3 + Mov EBX, 0 + + Mov BL, [ES:EDI+EDI+1] + + RetN + +Pan12BitF16Loop: + M12Mix16FPanned 0 + M12Mix16FPanned 1 + M12Mix16FPanned 2 + M12Mix16FPanned 3 + M12Mix16FPanned 4 + M12Mix16FPanned 5 + M12Mix16FPanned 6 + M12Mix16FPanned 7 + M12Mix16FPanned 8 + M12Mix16FPanned 9 + M12Mix16FPanned 10 + M12Mix16FPanned 11 + M12Mix16FPanned 12 + M12Mix16FPanned 13 + M12Mix16FPanned 14 + M12Mix16FPanned 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ Pan12BitF16Loop + + Ret + +EndP Mix12Panned16BitF + +; + +Proc PreMix12Panned16BitF + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:Mix12Panned16BitFVolume], AL + + Xor AL, AL + Mov AH, [SI+0Ch] + Sub AH, [SI+0Eh] + Add AH, AH + MovSX EAX, AX + + IndexCounter = 0 + + PreMix12PannedMacro2 Macro Index + Mov DWord Ptr [CS:M12Mix16FPannedRightVolumeOffset&Index&], EAX + EndM + + REPT 16 + PreMix12PannedMacro2 %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Panned16BitF + + +; +; + diff --git a/it/SoundDrivers/M12BITI.INC b/it/SoundDrivers/M12BITI.INC new file mode 100755 index 0000000..b9cd987 --- /dev/null +++ b/it/SoundDrivers/M12BITI.INC @@ -0,0 +1,49 @@ + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix12Left8BitI, MFS8Bit, MBS8Bit, Mix12Single8BitI + DW Offset MixForwardsLoop, PreMix12Left8BitI, MFS8Bit, MBS8Bit, Mix12Single8BitI + DW Offset MixPingPongLoop, PreMix12Left8BitI, MFS8Bit, MBS8Bit, Mix12Single8BitI + ; Right only + DW Offset MixNoLoop, PreMix12Right8BitI, MFS8Bit, MBS8Bit, Mix12Single8BitI + DW Offset MixForwardsLoop, PreMix12Right8BitI, MFS8Bit, MBS8Bit, Mix12Single8BitI + DW Offset MixPingPongLoop, PreMix12Right8BitI, MFS8Bit, MBS8Bit, Mix12Single8BitI + ; Central + DW Offset MixNoLoop, PreMix12Central8BitI, MFS8Bit, MBS8Bit, Mix12Central8BitI + DW Offset MixForwardsLoop, PreMix12Central8BitI, MFS8Bit, MBS8Bit, Mix12Central8BitI + DW Offset MixPingPongLoop, PreMix12Central8BitI, MFS8Bit, MBS8Bit, Mix12Central8BitI + ; Stereo + DW Offset MixNoLoop, PreMix12Panned8BitI, MFS8Bit, MBS8Bit, Mix12Panned8BitI + DW Offset MixForwardsLoop, PreMix12Panned8BitI, MFS8Bit, MBS8Bit, Mix12Panned8BitI + DW Offset MixPingPongLoop, PreMix12Panned8BitI, MFS8Bit, MBS8Bit, Mix12Panned8BitI + ; Surround + DW Offset MixNoLoop, PreMix12Surround8BitI, MFS8Bit, MBS8Bit, Mix12Surround8BitI + DW Offset MixForwardsLoop, PreMix12Surround8BitI, MFS8Bit, MBS8Bit, Mix12Surround8BitI + DW Offset MixPingPongLoop, PreMix12Surround8BitI, MFS8Bit, MBS8Bit, Mix12Surround8BitI + + ; 16 bit tables + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix12Left16BitI, MFS16Bit, MBS16Bit, Mix12Single16BitI + DW Offset MixForwardsLoop, PreMix12Left16BitI, MFS16Bit, MBS16Bit, Mix12Single16BitI + DW Offset MixPingPongLoop, PreMix12Left16BitI, MFS16Bit, MBS16Bit, Mix12Single16BitI + ; Right only + DW Offset MixNoLoop, PreMix12Right16BitI, MFS16Bit, MBS16Bit, Mix12Single16BitI + DW Offset MixForwardsLoop, PreMix12Right16BitI, MFS16Bit, MBS16Bit, Mix12Single16BitI + DW Offset MixPingPongLoop, PreMix12Right16BitI, MFS16Bit, MBS16Bit, Mix12Single16BitI + ; Central + DW Offset MixNoLoop, PreMix12Central16BitI, MFS16Bit, MBS16Bit, Mix12Central16BitI + DW Offset MixForwardsLoop, PreMix12Central16BitI, MFS16Bit, MBS16Bit, Mix12Central16BitI + DW Offset MixPingPongLoop, PreMix12Central16BitI, MFS16Bit, MBS16Bit, Mix12Central16BitI + ; Stereo + DW Offset MixNoLoop, PreMix12Panned16BitI, MFS16Bit, MBS16Bit, Mix12Panned16BitI + DW Offset MixForwardsLoop, PreMix12Panned16BitI, MFS16Bit, MBS16Bit, Mix12Panned16BitI + DW Offset MixPingPongLoop, PreMix12Panned16BitI, MFS16Bit, MBS16Bit, Mix12Panned16BitI + ; Surround + DW Offset MixNoLoop, PreMix12Surround16BitI, MFS16Bit, MBS16Bit, Mix12Surround16BitI + DW Offset MixForwardsLoop, PreMix12Surround16BitI, MFS16Bit, MBS16Bit, Mix12Surround16BitI + DW Offset MixPingPongLoop, PreMix12Surround16BitI, MFS16Bit, MBS16Bit, Mix12Surround16BitI diff --git a/it/SoundDrivers/M12BITI.MIX b/it/SoundDrivers/M12BITI.MIX new file mode 100755 index 0000000..5bc839b --- /dev/null +++ b/it/SoundDrivers/M12BITI.MIX @@ -0,0 +1,866 @@ + + ; Different mixing routines required: + ; Left } shared + ; Right } + ; Central + ; Surround + ; Panned ; Each requires 8 bit and 16 bit + ; Single output - for Mono, pure left/pure right + + ; Interpolation = [DI+1]*Error + [DI]*(1-Error) + ; = [DI+1]*Error + [DI] - [DI]*Error + ; = Error*([DI+1]-[DI]) + [DI] + + +Get8BitIWaveform Macro + MovSX EBX, Byte Ptr [ES:DI] ; 5 + MovSX EAX, Byte Ptr [ES:DI+1] ; 5 + Sub EAX, EBX ; 2 + IMul EAX, ECX + SAR EAX, 16 ; 3 + Add BL, AL ; 1 + +EndM + +Get16BitIWaveform Macro + MovSX EBX, Byte Ptr [ES:EDI+EDI+1] ; 5 + MovSX EAX, Byte Ptr [ES:EDI+EDI+3] ; 5 + Sub EAX, EBX ; 2 + IMul EAX, ECX + SAR EAX, 16 ; 3 + Add BL, AL ; 1 + +EndM + +M12Mix8ISingle Macro Index + +M12Mix8ISingle&Index&: + Get8BitIWaveform + +M12Mix8ISingleVolume&Index& EQU $+1 + Mov BH, 12h + Add BX, BX + + Add ERROR, DELTAERROR + Mov AX, [BX] + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8ICentral Macro Index + +M12Mix8ICentral&Index&: + Get8BitIWaveform + +M12Mix8ICentralVolume&Index& EQU $+1 + Mov BH, 12h + Add BX, BX + + Add ERROR, DELTAERROR ;; 1 + Mov AX, [BX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8ISurround Macro Index + +M12Mix8ISurround&Index&: + Get8BitIWaveform + +M12Mix8ISurroundVolume&Index& EQU $+1 + Mov BH, 12h + Add BX, BX + + Add ERROR, DELTAERROR ;; 1 + Mov AX, [BX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + Add [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8IPanned Macro Index + +M12Mix8IPanned&Index&: + Get8BitIWaveform + +M12Mix8IPannedVolume&Index& EQU $+1 + Mov BH, 12h + Add BX, BX + + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [BX] + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +M12Mix8IPannedRightVolumeOffset&Index& EQU $+3 + Mov AX, [BX+1200h] + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +M12Mix16ISingle Macro Index + +M12Mix16ISingle&Index&: + Get16BitIWaveForm + +M12Mix16ISingleVolume&Index& EQU $+1 + Mov BH, 12h + Add BX, BX + + Add ERROR, DELTAERROR + Mov AX, [BX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +EndM + +M12Mix16ICentral Macro Index + +M12Mix16ICentral&Index&: + Get16BitIWaveform + +M12Mix16ICentralVolume&Index& EQU $+1 + Mov BH, 12h + Add BX, BX + + Add ERROR, DELTAERROR + Mov AX, [BX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +M12Mix16ISurround Macro Index + +M12Mix16ISurround&Index&: + Get16BitIWaveform + +M12Mix16ISurroundVolume&Index& EQU $+1 + Mov BH, 12h + Add BX, BX + + Add ERROR, DELTAERROR + Mov AX, [BX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + Add [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + + ; Panned output +M12Mix16IPanned Macro Index + +M12Mix16IPanned&Index&: + Get16BitIWaveform + +M12Mix16IPannedVolume&Index& EQU $+1 + Mov BH, 12h + Add BX, BX + + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [BX] + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +M12Mix16IPannedRightVolumeOffset&Index& EQU $+3 + Mov AX, [BX+1200h] + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +; + +Mix12Single8BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8ISingleOffset Macro Index + DW Offset M12Mix8ISingle&Index& + EndM + + REPT 16 + M12Mix8ISingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Single8BitI + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix12Single8BitIOffsetTable+BX] + + M12Mix8ISingle 0 + M12Mix8ISingle 1 + M12Mix8ISingle 2 + M12Mix8ISingle 3 + M12Mix8ISingle 4 + M12Mix8ISingle 5 + M12Mix8ISingle 6 + M12Mix8ISingle 7 + M12Mix8ISingle 8 + M12Mix8ISingle 9 + M12Mix8ISingle 10 + M12Mix8ISingle 11 + M12Mix8ISingle 12 + M12Mix8ISingle 13 + M12Mix8ISingle 14 + M12Mix8ISingle 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8ISingle0 + + Ret + +EndP Mix12Single8BitI + +; + +Proc PreMix12Left8BitI + + Mov AL, [SI+0Eh] + +PreMix12Left8BitI1: + + IndexCounter = 0 + + PreMix12Single8BitIMacro Macro Index + Mov Byte Ptr [CS:M12Mix8ISingleVolume&Index&], AL + EndM + + REPT 16 + PreMix12Single8BitIMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Left8BitI + +; + +Proc PreMix12Right8BitI + + Add MixBufferOffset, MixResolution/8 + Mov AL, [SI+0Ch] + Jmp PreMix12Left8BitI1 + + Ret + +EndP PreMix12Right8BitI + +; + +Mix12Central8BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8ICentralOffset Macro Index + DW Offset M12Mix8ICentral&Index& + EndM + + REPT 16 + M12Mix8ICentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central8BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix12Central8BitIOffsetTable+BX] + + M12Mix8ICentral 0 + M12Mix8ICentral 1 + M12Mix8ICentral 2 + M12Mix8ICentral 3 + M12Mix8ICentral 4 + M12Mix8ICentral 5 + M12Mix8ICentral 6 + M12Mix8ICentral 7 + M12Mix8ICentral 8 + M12Mix8ICentral 9 + M12Mix8ICentral 10 + M12Mix8ICentral 11 + M12Mix8ICentral 12 + M12Mix8ICentral 13 + M12Mix8ICentral 14 + M12Mix8ICentral 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8ICentral0 + + Ret + +EndP Mix12Central8BitI + +; + +Proc PreMix12Central8BitI + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12Central8BitIMacro Macro Index + Mov Byte Ptr [CS:M12Mix8ICentralVolume&Index&], AL + EndM + + REPT 16 + PreMix12Central8BitIMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Central8BitI + +; + +Mix12Surround8BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8ISurroundOffset Macro Index + DW Offset M12Mix8ISurround&Index& + EndM + + REPT 16 + M12Mix8ISurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Surround8BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix12Surround8BitIOffsetTable+BX] + + M12Mix8ISurround 0 + M12Mix8ISurround 1 + M12Mix8ISurround 2 + M12Mix8ISurround 3 + M12Mix8ISurround 4 + M12Mix8ISurround 5 + M12Mix8ISurround 6 + M12Mix8ISurround 7 + M12Mix8ISurround 8 + M12Mix8ISurround 9 + M12Mix8ISurround 10 + M12Mix8ISurround 11 + M12Mix8ISurround 12 + M12Mix8ISurround 13 + M12Mix8ISurround 14 + M12Mix8ISurround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8ISurround0 + + Ret + +EndP Mix12Surround8BitI + +; + +Proc PreMix12Surround8BitI + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12Surround8BitIMacro Macro Index + Mov Byte Ptr [CS:M12Mix8ISurroundVolume&Index&], AL + EndM + + REPT 16 + PreMix12Surround8BitIMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Surround8BitI + +; + +Mix12Panned8BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8IPannedOffset Macro Index + DW Offset M12Mix8IPanned&Index& + EndM + + REPT 16 + M12Mix8IPannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Panned8BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix12Panned8BitIOffsetTable+BX] + + M12Mix8IPanned 0 + M12Mix8IPanned 1 + M12Mix8IPanned 2 + M12Mix8IPanned 3 + M12Mix8IPanned 4 + M12Mix8IPanned 5 + M12Mix8IPanned 6 + M12Mix8IPanned 7 + M12Mix8IPanned 8 + M12Mix8IPanned 9 + M12Mix8IPanned 10 + M12Mix8IPanned 11 + M12Mix8IPanned 12 + M12Mix8IPanned 13 + M12Mix8IPanned 14 + M12Mix8IPanned 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8IPanned0 + + Ret + +EndP Mix12Panned8BitI + +; + +Proc PreMix12Panned8BitI + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12Panned8BitIMacro Macro Index + Mov Byte Ptr [CS:M12Mix8IPannedVolume&Index&], AL + EndM + + REPT 16 + PreMix12Panned8BitIMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Mov AL, [SI+0Ch] + Sub AL, [SI+0Eh] + Add AL, AL + + IndexCounter = 0 + + PreMix12Panned8BitIMacro2 Macro Index + Mov Byte Ptr [CS:M12Mix8IPannedRightVolumeOffset&Index&], AL + EndM + + REPT 16 + PreMix12Panned8BitIMacro2 %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Panned8BitI + +; + +Mix12Single16BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16ISingleOffset Macro Index + DW Offset M12Mix16ISingle&Index& + EndM + + REPT 16 + M12Mix16ISingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Single16BitI + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix12Single16BitIOffsetTable+BX] + + M12Mix16ISingle 0 + M12Mix16ISingle 1 + M12Mix16ISingle 2 + M12Mix16ISingle 3 + M12Mix16ISingle 4 + M12Mix16ISingle 5 + M12Mix16ISingle 6 + M12Mix16ISingle 7 + M12Mix16ISingle 8 + M12Mix16ISingle 9 + M12Mix16ISingle 10 + M12Mix16ISingle 11 + M12Mix16ISingle 12 + M12Mix16ISingle 13 + M12Mix16ISingle 14 + M12Mix16ISingle 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16ISingle0 + + Ret + +EndP Mix12Single16BitI + +; + +Proc PreMix12Left16BitI + + Mov AL, [SI+0Eh] + +PreMix12Left16BitI1: + + IndexCounter = 0 + + PreMix12Single16BitIMacro Macro Index + Mov Byte Ptr [CS:M12Mix16ISingleVolume&Index&], AL + EndM + + REPT 16 + PreMix12Single16BitIMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Left16BitI + +; + +Proc PreMix12Right16BitI + + Add MixBufferOffset, MixResolution/8 + Mov AL, [SI+0Ch] + + Jmp PreMix12Left16BitI1 + +EndP PreMix12Right16BitI + +; + +Mix12Central16BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16ICentralOffset Macro Index + DW Offset M12Mix16ICentral&Index& + EndM + + REPT 16 + M12Mix16ICentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central16BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix12Central16BitIOffsetTable+BX] + + M12Mix16ICentral 0 + M12Mix16ICentral 1 + M12Mix16ICentral 2 + M12Mix16ICentral 3 + M12Mix16ICentral 4 + M12Mix16ICentral 5 + M12Mix16ICentral 6 + M12Mix16ICentral 7 + M12Mix16ICentral 8 + M12Mix16ICentral 9 + M12Mix16ICentral 10 + M12Mix16ICentral 11 + M12Mix16ICentral 12 + M12Mix16ICentral 13 + M12Mix16ICentral 14 + M12Mix16ICentral 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16ICentral0 + + Ret + +EndP Mix12Central16BitI + +; + +Proc PreMix12Central16BitI + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12Central16BitIMacro Macro Index + Mov Byte Ptr [CS:M12Mix16ICentralVolume&Index&], AL + EndM + + REPT 16 + PreMix12Central16BitIMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + Ret + +EndP PreMix12Central16BitI + +; + +Mix12Surround16BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16ISurroundOffset Macro Index + DW Offset M12Mix16ISurround&Index& + EndM + + REPT 16 + M12Mix16ISurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Surround16BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix12Surround16BitIOffsetTable+BX] + + M12Mix16ISurround 0 + M12Mix16ISurround 1 + M12Mix16ISurround 2 + M12Mix16ISurround 3 + M12Mix16ISurround 4 + M12Mix16ISurround 5 + M12Mix16ISurround 6 + M12Mix16ISurround 7 + M12Mix16ISurround 8 + M12Mix16ISurround 9 + M12Mix16ISurround 10 + M12Mix16ISurround 11 + M12Mix16ISurround 12 + M12Mix16ISurround 13 + M12Mix16ISurround 14 + M12Mix16ISurround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16ISurround0 + + Ret + +EndP Mix12Surround16BitI + +; + +Proc PreMix12Surround16BitI + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12Surround16BitIMacro Macro Index + Mov Byte Ptr [CS:M12Mix16ISurroundVolume&Index&], AL + EndM + + REPT 16 + PreMix12Surround16BitIMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Surround16BitI + +; + +Mix12Panned16BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16IPannedOffset Macro Index + DW Offset M12Mix16IPanned&Index& + EndM + + REPT 16 + M12Mix16IPannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Panned16BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix12Panned16BitIOffsetTable+BX] + +Pan12BitI16Loop: + M12Mix16IPanned 0 + M12Mix16IPanned 1 + M12Mix16IPanned 2 + M12Mix16IPanned 3 + M12Mix16IPanned 4 + M12Mix16IPanned 5 + M12Mix16IPanned 6 + M12Mix16IPanned 7 + M12Mix16IPanned 8 + M12Mix16IPanned 9 + M12Mix16IPanned 10 + M12Mix16IPanned 11 + M12Mix16IPanned 12 + M12Mix16IPanned 13 + M12Mix16IPanned 14 + M12Mix16IPanned 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ Pan12BitI16Loop + + Ret + +EndP Mix12Panned16BitI + +; + +Proc PreMix12Panned16BitI + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12PannedMacro Macro Index + Mov Byte Ptr [CS:M12Mix16IPannedVolume&Index&], AL + EndM + + REPT 16 + PreMix12PannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Mov AL, [SI+0Ch] + Sub AL, [SI+0Eh] + Add AL, AL + + IndexCounter = 0 + + PreMix12PannedMacro2 Macro Index + Mov Byte Ptr [CS:M12Mix16IPannedRightVolumeOffset&Index&], AL + EndM + + REPT 16 + PreMix12PannedMacro2 %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Panned16BitI + + +; +; + diff --git a/it/SoundDrivers/M12BITST.MIX b/it/SoundDrivers/M12BITST.MIX new file mode 100755 index 0000000..6d87910 --- /dev/null +++ b/it/SoundDrivers/M12BITST.MIX @@ -0,0 +1,832 @@ + +; 12 bit mixing routines, using Stack Segment. + + ; Different mixing routines required: + ; Left } shared + ; Right } + ; Central + ; Surround + ; Panned ; Each requires 8 bit and 16 bit + ; Single output - for Mono, pure left/pure right + +M12Mix8Single Macro Index + +M12Mix8Single&Index&: + Add ERROR, DELTAERROR ;; 1 + Mov BL, [SP] ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Mov AX, [EBX+EBX] ;; 2 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8Central Macro Index + +M12Mix8Central&Index&: + Mov BL, [SP] ;; 2 + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX ;; 3 + +EndM + +M12Mix8Surround Macro Index + +M12Mix8Surround&Index&: + Mov BL, [SP] ;; 2 + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX ;; 3 + Add [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX ;; 3 + +EndM + + ; Panned output +M12Mix8PannedNext Macro Index + +M12Mix8PannedVolume&Index& EQU $+1 + Mov BH, 12h + Mov BL, [SP] + +EndM + +M12Mix8Panned Macro Index + +M12Mix8Panned&Index&: + Add BX, BX + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [BX] + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +M12Mix8PannedRightVolumeOffset&Index& EQU $+3 + Mov AX, [BX+1200h] + + M12Mix8PannedNext %(Index+1) + + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +M12Mix16Single Macro Index + +M12Mix16Single&Index&: + Mov BL, [ES:EDI+EDI+1] + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +EndM + +M12Mix16Central Macro Index + +M12Mix16Central&Index&: + Mov BL, [ES:EDI+EDI+1] + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +M12Mix16Surround Macro Index + +M12Mix16Surround&Index&: + Mov BL, [ES:EDI+EDI+1] + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + Add [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + + ; Panned output +M12Mix16PannedNext Macro Index + +M12Mix16PannedVolume&Index& EQU $+1 + Mov BH, 12h + Mov BL, [ES:EDI+EDI+1] + +EndM + +M12Mix16Panned Macro Index + +M12Mix16Panned&Index&: + Add BX, BX + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [BX] + Sub [SI+(Index-15)*MixResolution/4+EXTRAOFFSET], AX + +M12Mix16PannedRightVolumeOffset&Index& EQU $+3 + Mov AX, [BX+1200h] + + M12Mix16PannedNext %(Index+1) + + Sub [SI+(Index-15)*MixResolution/4+MixResolution/8+EXTRAOFFSET], AX + +EndM + +; + +Mix12Single8BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8SingleOffset Macro Index + DW Offset M12Mix8Single&Index& + EndM + + REPT 16 + M12Mix8SingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +ALIGN 2 +OldStackSegment DW 0 +OldStackPointer DW 0 +MixingOffset DW 0 + +Proc Mix12Single8Bit + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Mov AX, [CS:Mix12BitSingle8BitOffsetTable+BX] + Mov [CS:OldStackSegment], SS + Mov [CS:OldStackPointer], SP + Mov [CS:MixingOffset], AX + +M12Single8BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + Mov ESP, EDI + Jmp [CS:MixingOffset] + + M12Mix8Single 0 + M12Mix8Single 1 + M12Mix8Single 2 + M12Mix8Single 3 + M12Mix8Single 4 + M12Mix8Single 5 + M12Mix8Single 6 + M12Mix8Single 7 + M12Mix8Single 8 + M12Mix8Single 9 + M12Mix8Single 10 + M12Mix8Single 11 + M12Mix8Single 12 + M12Mix8Single 13 + M12Mix8Single 14 + M12Mix8Single 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8Single0 + + Mov SS, [CS:StackSegment] + Mov SP, [CS:StackPointer] + + Ret + +EndP Mix12Single8Bit + +; + +Proc PreMix12Left8Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Single8BitVolume], AL + Ret + +EndP PreMix12Left8Bit + +; + +Proc PreMix12Right8Bit + + Add MixBufferOffset, MixResolution/8 + Mov AL, [SI+0Ch] + Mov Byte Ptr [CS:M12Single8BitVolume], AL + + Ret + +EndP PreMix12Right8Bit + +; + +Mix12Central8BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8CentralOffset Macro Index + DW Offset M12Mix8Central&Index& + EndM + + REPT 16 + M12Mix8CentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Mov AX, [CS:Mix12BitSingle8BitOffsetTable+BX] + Mov [CS:OldStackSegment], SS + Mov [CS:OldStackPointer], SP + Mov [CS:MixingOffset], AX + +M12Central8BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + Mov ESP, EDI + Jmp [CS:MixingOffset] + + M12Mix8Central 0 + M12Mix8Central 1 + M12Mix8Central 2 + M12Mix8Central 3 + M12Mix8Central 4 + M12Mix8Central 5 + M12Mix8Central 6 + M12Mix8Central 7 + M12Mix8Central 8 + M12Mix8Central 9 + M12Mix8Central 10 + M12Mix8Central 11 + M12Mix8Central 12 + M12Mix8Central 13 + M12Mix8Central 14 + M12Mix8Central 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8Central0 + + Mov SS, [CS:StackSegment] + Mov SP, [CS:StackPointer] + + Ret + +EndP Mix12Central8Bit + +; + +Proc PreMix12Central8Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Central8BitVolume], AL + + Ret + +EndP PreMix12Central8Bit + +; + +Mix12Surround8BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8SurroundOffset Macro Index + DW Offset M12Mix8Surround&Index& + EndM + + REPT 16 + M12Mix8SurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Surround8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Surround8BitOffsetTable+BX] + +M12Surround8BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + + RetN + + M12Mix8Surround 0 + M12Mix8Surround 1 + M12Mix8Surround 2 + M12Mix8Surround 3 + M12Mix8Surround 4 + M12Mix8Surround 5 + M12Mix8Surround 6 + M12Mix8Surround 7 + M12Mix8Surround 8 + M12Mix8Surround 9 + M12Mix8Surround 10 + M12Mix8Surround 11 + M12Mix8Surround 12 + M12Mix8Surround 13 + M12Mix8Surround 14 + M12Mix8Surround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8Surround0 + + Ret + +EndP Mix12Surround8Bit + +; + +Proc PreMix12Surround8Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Surround8BitVolume], AL + + Ret + +EndP PreMix12Surround8Bit + +; + +Mix12Panned8BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8PannedOffset Macro Index + DW Offset M12Mix8Panned&Index& + EndM + + REPT 16 + M12Mix8PannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Panned8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Panned8BitOffsetTable+BX] + + M12Mix8PannedNext 0 + + RetN + + M12Mix8Panned 0 + M12Mix8Panned 1 + M12Mix8Panned 2 + M12Mix8Panned 3 + M12Mix8Panned 4 + M12Mix8Panned 5 + M12Mix8Panned 6 + M12Mix8Panned 7 + M12Mix8Panned 8 + M12Mix8Panned 9 + M12Mix8Panned 10 + M12Mix8Panned 11 + M12Mix8Panned 12 + M12Mix8Panned 13 + M12Mix8Panned 14 + M12Mix8Panned 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix8Panned0 + + Ret + +EndP Mix12Panned8Bit + +; + +Proc PreMix12Panned8Bit + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12PannedMacro Macro Index + Mov Byte Ptr [CS:M12Mix8PannedVolume&Index&], AL + EndM + + REPT 17 + PreMix12PannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Mov AL, [SI+0Ch] + Sub AL, [SI+0Eh] + Add AL, AL + + IndexCounter = 0 + + PreMix12PannedMacro2 Macro Index + Mov Byte Ptr [CS:M12Mix8PannedRightVolumeOffset&Index&], AL + EndM + + REPT 16 + PreMix12PannedMacro2 %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Panned8Bit + +; + +Mix12Single16BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16SingleOffset Macro Index + DW Offset M12Mix16Single&Index& + EndM + + REPT 16 + M12Mix16SingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Single16Bit + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Single16BitOffsetTable+BX] + +M12Single16BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + RetN + + M12Mix16Single 0 + M12Mix16Single 1 + M12Mix16Single 2 + M12Mix16Single 3 + M12Mix16Single 4 + M12Mix16Single 5 + M12Mix16Single 6 + M12Mix16Single 7 + M12Mix16Single 8 + M12Mix16Single 9 + M12Mix16Single 10 + M12Mix16Single 11 + M12Mix16Single 12 + M12Mix16Single 13 + M12Mix16Single 14 + M12Mix16Single 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16Single0 + + Ret + +EndP Mix12Single16Bit + +; + +Proc PreMix12Left16Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Single16BitVolume], AL + Ret + +EndP PreMix12Left16Bit + +; + +Proc PreMix12Right16Bit + + Add MixBufferOffset, MixResolution/8 + Mov AL, [SI+0Ch] + Mov Byte Ptr [CS:M12Single16BitVolume], AL + + Ret + +EndP PreMix12Right16Bit + +; + +Mix12Central16BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16CentralOffset Macro Index + DW Offset M12Mix16Central&Index& + EndM + + REPT 16 + M12Mix16CentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Central16BitOffsetTable+BX] + +M12Central16BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + + RetN + + M12Mix16Central 0 + M12Mix16Central 1 + M12Mix16Central 2 + M12Mix16Central 3 + M12Mix16Central 4 + M12Mix16Central 5 + M12Mix16Central 6 + M12Mix16Central 7 + M12Mix16Central 8 + M12Mix16Central 9 + M12Mix16Central 10 + M12Mix16Central 11 + M12Mix16Central 12 + M12Mix16Central 13 + M12Mix16Central 14 + M12Mix16Central 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16Central0 + + Ret + +EndP Mix12Central16Bit + +; + +Proc PreMix12Central16Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Central16BitVolume], AL + + Ret + +EndP PreMix12Central16Bit + +; + +Mix12Surround16BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16SurroundOffset Macro Index + DW Offset M12Mix16Surround&Index& + EndM + + REPT 16 + M12Mix16SurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Surround16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Surround16BitOffsetTable+BX] + +M12Surround16BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + + RetN + + M12Mix16Surround 0 + M12Mix16Surround 1 + M12Mix16Surround 2 + M12Mix16Surround 3 + M12Mix16Surround 4 + M12Mix16Surround 5 + M12Mix16Surround 6 + M12Mix16Surround 7 + M12Mix16Surround 8 + M12Mix16Surround 9 + M12Mix16Surround 10 + M12Mix16Surround 11 + M12Mix16Surround 12 + M12Mix16Surround 13 + M12Mix16Surround 14 + M12Mix16Surround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M12Mix16Surround0 + + Ret + +EndP Mix12Surround16Bit + +; + +Proc PreMix12Surround16Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Surround16BitVolume], AL + + Ret + +EndP PreMix12Surround16Bit + +; + +Mix12Panned16BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16PannedOffset Macro Index + DW Offset M12Mix16Panned&Index& + EndM + + REPT 16 + M12Mix16PannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Panned16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Panned16BitOffsetTable+BX] + + M12Mix16PannedNext 0 + + RetN + +Pan12Bit16Loop: + M12Mix16PannedNext 16 + + M12Mix16Panned 0 + M12Mix16Panned 1 + M12Mix16Panned 2 + M12Mix16Panned 3 + M12Mix16Panned 4 + M12Mix16Panned 5 + M12Mix16Panned 6 + M12Mix16Panned 7 + M12Mix16Panned 8 + M12Mix16Panned 9 + M12Mix16Panned 10 + M12Mix16Panned 11 + M12Mix16Panned 12 + M12Mix16Panned 13 + M12Mix16Panned 14 + + M12Mix16Panned15: + Add BX, BX + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov AX, [BX] + Sub [SI+EXTRAOFFSET], AX + M12Mix16PannedRightVolumeOffset15 EQU $+3 + Mov AX, [BX+1200h] + Sub [SI+MixResolution/8+EXTRAOFFSET], AX + + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ Pan12Bit16Loop + + Ret + +EndP Mix12Panned16Bit + +; + +Proc PreMix12Panned16Bit + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12PannedMacro Macro Index + Mov Byte Ptr [CS:M12Mix16PannedVolume&Index&], AL + EndM + + REPT 17 + PreMix12PannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Mov AL, [SI+0Ch] + Sub AL, [SI+0Eh] + Add AL, AL + + IndexCounter = 0 + + PreMix12PannedMacro2 Macro Index + Mov Byte Ptr [CS:M12Mix16PannedRightVolumeOffset&Index&], AL + EndM + + REPT 16 + PreMix12PannedMacro2 %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Panned16Bit + + +; +; + diff --git a/it/SoundDrivers/M16.ASM b/it/SoundDrivers/M16.ASM new file mode 100755 index 0000000..5b88419 --- /dev/null +++ b/it/SoundDrivers/M16.ASM @@ -0,0 +1,2275 @@ +; +; Terratec Maestro 16/96 +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +PNPVENDORID EQU 2409143Eh + +DMASize DW DMABUFFERLENGTH/2 + +WSSMsg DB "SoundSystem Maestro 16/96", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "SoundSystem Maestro 16/96", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "SoundSystem Maestro 16/96 Codec reinitialised", 0 + +DriverName DB "ITMAES16.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW 0 + +WSSHeaderLine DW 10 + DB "SoundSystem Maestro 16/96 Codec Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 15, 48 + DB 21h + DB "SoundSystem Maestro 16/96 Codec Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 2 Dup (56) + +; MixingRoutines + +MixBufferPos DW 0 + +include dmasirq.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + + Mov AX, 1 + Ret + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 16 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Add DX, 6 + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 62h + Call PnP_ReadData + Mov AH, AL + Mov AL, 63h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Mov AX, 202h + Call PnP_WriteData + Ret + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + + Mov EAX, 'Jeff' + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 6 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + + Cmp BX, DMABUFFERLENGTH/2 + JB WSSIRQHandler1 + + Mov AX, DMABUFFERLENGTH/2 + +WSSIRQHandler1: + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + Add DX, 4 + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + Add DX, 4 + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Call UpdateSoundcardVariables + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + Push AX DX + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + Add DX, 4 + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX AX + Ret + +EndP UpdatesoundcardVariables + Assume DS:Nothing + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + Call UpdateSoundcardVariables + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/M16.BAT b/it/SoundDrivers/M16.BAT new file mode 100755 index 0000000..f5023d7 --- /dev/null +++ b/it/SoundDrivers/M16.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 m16 +tlink /3 m16 +execom m16 itmaes16.drv +copy itmaes16.drv .. + diff --git a/it/SoundDrivers/M32.ASM b/it/SoundDrivers/M32.ASM new file mode 100755 index 0000000..1736ea8 --- /dev/null +++ b/it/SoundDrivers/M32.ASM @@ -0,0 +1,2271 @@ +; +; Windows Sound System Driver +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +PNPVENDORID EQU 321A630Eh + +DMASize DW DMABUFFERLENGTH/2 + +WSSMsg DB "SoundSystem Maestro 32/96", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "SoundSystem Maestro 32/96", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "SoundSystem Maestro 32/96 Codec reinitialised", 0 + +DriverName DB "ITMAES32.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW 0 + +WSSHeaderLine DW 10 + DB "SoundSystem Maestro 32/96 Codec Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 15, 48 + DB 21h + DB "SoundSystem Maestro 32/96 Codec Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 2 Dup (56) + +; MixingRoutines + +MixBufferPos DW 0 + +include dmasirq.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + + Mov AX, 1 + Ret + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 48000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 14 ; 14 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Inc DX + Inc DX + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 07h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Mov AX, 202h + Call PnP_WriteData + Ret + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + + Mov EAX, 'Jeff' + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 2 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + + Cmp BX, DMABUFFERLENGTH/2 + JB WSSIRQHandler1 + + Mov AX, DMABUFFERLENGTH/2 + +WSSIRQHandler1: + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Call UpdateSoundcardVariables + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + Push AX DX + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX AX + Ret + +EndP UpdatesoundcardVariables + Assume DS:Nothing + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + Call UpdateSoundcardVariables + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/M32.BAT b/it/SoundDrivers/M32.BAT new file mode 100755 index 0000000..328ebb1 --- /dev/null +++ b/it/SoundDrivers/M32.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 m32 +tlink /3 m32 +execom m32 itmaes32.drv +copy itmaes32.drv .. + diff --git a/it/SoundDrivers/M32BIT.INC b/it/SoundDrivers/M32BIT.INC new file mode 100755 index 0000000..47bebd5 --- /dev/null +++ b/it/SoundDrivers/M32BIT.INC @@ -0,0 +1,49 @@ + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix32Left8Bit, MFS8Bit, MBS8Bit, Mix32Single8Bit + DW Offset MixForwardsLoop, PreMix32Left8Bit, MFS8Bit, MBS8Bit, Mix32Single8Bit + DW Offset MixPingPongLoop, PreMix32Left8Bit, MFS8Bit, MBS8Bit, Mix32Single8Bit + ; Right only + DW Offset MixNoLoop, PreMix32Right8Bit, MFS8Bit, MBS8Bit, Mix32Single8Bit + DW Offset MixForwardsLoop, PreMix32Right8Bit, MFS8Bit, MBS8Bit, Mix32Single8Bit + DW Offset MixPingPongLoop, PreMix32Right8Bit, MFS8Bit, MBS8Bit, Mix32Single8Bit + ; Central + DW Offset MixNoLoop, PreMix32Central8Bit, MFS8Bit, MBS8Bit, Mix32Central8Bit + DW Offset MixForwardsLoop, PreMix32Central8Bit, MFS8Bit, MBS8Bit, Mix32Central8Bit + DW Offset MixPingPongLoop, PreMix32Central8Bit, MFS8Bit, MBS8Bit, Mix32Central8Bit + ; Stereo + DW Offset MixNoLoop, PreMix32Panned8Bit, MFS8Bit, MBS8Bit, Mix32Panned8Bit + DW Offset MixForwardsLoop, PreMix32Panned8Bit, MFS8Bit, MBS8Bit, Mix32Panned8Bit + DW Offset MixPingPongLoop, PreMix32Panned8Bit, MFS8Bit, MBS8Bit, Mix32Panned8Bit + ; Surround + DW Offset MixNoLoop, PreMix32Surround8Bit, MFS8Bit, MBS8Bit, Mix32Surround8Bit + DW Offset MixForwardsLoop, PreMix32Surround8Bit, MFS8Bit, MBS8Bit, Mix32Surround8Bit + DW Offset MixPingPongLoop, PreMix32Surround8Bit, MFS8Bit, MBS8Bit, Mix32Surround8Bit + + ; 16 bit tables + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix32Left16Bit, MFS16Bit, MBS16Bit, Mix32Single16Bit + DW Offset MixForwardsLoop, PreMix32Left16Bit, MFS16Bit, MBS16Bit, Mix32Single16Bit + DW Offset MixPingPongLoop, PreMix32Left16Bit, MFS16Bit, MBS16Bit, Mix32Single16Bit + ; Right only + DW Offset MixNoLoop, PreMix32Right16Bit, MFS16Bit, MBS16Bit, Mix32Single16Bit + DW Offset MixForwardsLoop, PreMix32Right16Bit, MFS16Bit, MBS16Bit, Mix32Single16Bit + DW Offset MixPingPongLoop, PreMix32Right16Bit, MFS16Bit, MBS16Bit, Mix32Single16Bit + ; Central + DW Offset MixNoLoop, PreMix32Central16Bit, MFS16Bit, MBS16Bit, Mix32Central16Bit + DW Offset MixForwardsLoop, PreMix32Central16Bit, MFS16Bit, MBS16Bit, Mix32Central16Bit + DW Offset MixPingPongLoop, PreMix32Central16Bit, MFS16Bit, MBS16Bit, Mix32Central16Bit + ; Stereo + DW Offset MixNoLoop, PreMix32Panned16Bit, MFS16Bit, MBS16Bit, Mix32Panned16Bit + DW Offset MixForwardsLoop, PreMix32Panned16Bit, MFS16Bit, MBS16Bit, Mix32Panned16Bit + DW Offset MixPingPongLoop, PreMix32Panned16Bit, MFS16Bit, MBS16Bit, Mix32Panned16Bit + ; Surround + DW Offset MixNoLoop, PreMix32Surround16Bit, MFS16Bit, MBS16Bit, Mix32Surround16Bit + DW Offset MixForwardsLoop, PreMix32Surround16Bit, MFS16Bit, MBS16Bit, Mix32Surround16Bit + DW Offset MixPingPongLoop, PreMix32Surround16Bit, MFS16Bit, MBS16Bit, Mix32Surround16Bit diff --git a/it/SoundDrivers/M32BIT.MIX b/it/SoundDrivers/M32BIT.MIX new file mode 100755 index 0000000..4a06c34 --- /dev/null +++ b/it/SoundDrivers/M32BIT.MIX @@ -0,0 +1,803 @@ + + ; Different mixing routines required: + ; Left } shared + ; Right } + ; Central + ; Surround + ; Panned ; Each requires 8 bit and 16 bit + ; Single output - for Mono, pure left/pure right + +M32Mix8Single Macro Index + +M32Mix8Single&Index&: + MovSX EBX, Byte Ptr [ES:DI] + +M32Mix8SingleVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + ShL EAX, 8 + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 3 +EndM + +M32Mix8Central Macro Index + +M32Mix8Central&Index&: + MovSX EBX, Byte Ptr [ES:DI] ;; 4 + +M32Mix8CentralVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + ShL EAX, 8 ;; 4 + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 4 + Sub [SI+(Index-15)*8+4], EAX ;; 4 + +EndM + +M32Mix8Surround Macro Index + +M32Mix8Surround&Index&: + MovSX EBX, Byte Ptr [ES:DI] ;; 4 + +M32Mix8SurroundVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + ShL EAX, 8 ;; 4 + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 4 + Add [SI+(Index-15)*8+4], EAX ;; 4 + +EndM + + ; Panned output +M32Mix8Panned Macro Index + +M32Mix8Panned&Index&: + MovSX EBX, Byte Ptr [ES:DI] ;; 4 + +M32Mix8LeftVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h +M32Mix8RightVolume&Index& EQU $+3 + IMul EBX, EBX, 8000h + + ShL EAX, 8 ;; 4 + ShL EBX, 8 ;; 4 + + Sub [SI+(Index-15)*8], EAX ;; 4 + Sub [SI+(Index-15)*8+4], EBX ;; 4 + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + +EndM + +M32Mix16Single Macro Index + +M32Mix16Single&Index&: + MovSX EBX, Word Ptr [ES:EDI+EDI] + +M32Mix16SingleVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 3 + +EndM + +M32Mix16Central Macro Index + +M32Mix16Central&Index&: + MovSX EBX, Word Ptr [ES:EDI+EDI] + +M32Mix16CentralVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 3 + Sub [SI+(Index-15)*8+4], EAX ;; 3 + +EndM + +M32Mix16Surround Macro Index + +M32Mix16Surround&Index&: + MovSX EBX, Word Ptr [ES:EDI+EDI] + +M32Mix16SurroundVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 3 + Add [SI+(Index-15)*8+4], EAX ;; 3 + +EndM + + ; Panned output +M32Mix16Panned Macro Index + +M32Mix16Panned&Index&: + MovSX EBX, Word Ptr [ES:EDI+EDI] + +M32Mix16LeftVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h +M32Mix16RightVolume&Index& EQU $+3 + IMul EBX, EBX, 8000h + + Sub [SI+(Index-15)*8], EAX + Sub [SI+(Index-15)*8+4], EBX + + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + +EndM + +; + +Mix32Single8BitOffsetTable Label Word + + IndexCounter = 15 + + M32Mix8SingleOffset Macro Index + DW Offset M32Mix8Single&Index& + EndM + + REPT 16 + M32Mix8SingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Single8Bit + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Single8BitOffsetTable+BX] + + M32Mix8Single 0 + M32Mix8Single 1 + M32Mix8Single 2 + M32Mix8Single 3 + M32Mix8Single 4 + M32Mix8Single 5 + M32Mix8Single 6 + M32Mix8Single 7 + M32Mix8Single 8 + M32Mix8Single 9 + M32Mix8Single 10 + M32Mix8Single 11 + M32Mix8Single 12 + M32Mix8Single 13 + M32Mix8Single 14 + M32Mix8Single 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix8Single0 + + Ret + +EndP Mix32Single8Bit + +; + +Proc PreMix32Left8Bit + + Mov AX, [SI+0Eh] + +PreMix32Left8Bit1: + IndexCounter = 0 + + PreMix32SingleMacro Macro Index + Mov Word Ptr [CS:M32Mix8SingleVolume&Index&], AX + EndM + + REPT 16 + PreMix32SingleMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + Ret + +EndP PreMix32Left8Bit + +; + +Proc PreMix32Right8Bit + + Add MixBufferOffset, MixResolution/8 + Mov AX, [SI+0Ch] + Jmp PreMix32Left8Bit1 + +EndP PreMix32Right8Bit + +; + +Mix32Central8BitOffsetTable Label Word + + IndexCounter = 15 + + M32Mix8CentralOffset Macro Index + DW Offset M32Mix8Central&Index& + EndM + + REPT 16 + M32Mix8CentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Central8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Central8BitOffsetTable+BX] + + M32Mix8Central 0 + M32Mix8Central 1 + M32Mix8Central 2 + M32Mix8Central 3 + M32Mix8Central 4 + M32Mix8Central 5 + M32Mix8Central 6 + M32Mix8Central 7 + M32Mix8Central 8 + M32Mix8Central 9 + M32Mix8Central 10 + M32Mix8Central 11 + M32Mix8Central 12 + M32Mix8Central 13 + M32Mix8Central 14 + M32Mix8Central 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix8Central0 + + Ret + +EndP Mix32Central8Bit + +; + +Proc PreMix32Central8Bit + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMix32CentralMacro Macro Index + Mov Word Ptr [CS:M32Mix8CentralVolume&Index&], AX + EndM + + REPT 16 + PreMix32CentralMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Central8Bit + +; + +Mix32Surround8BitOffsetTable Label Word + + IndexCounter = 15 + + M32Mix8SurroundOffset Macro Index + DW Offset M32Mix8Surround&Index& + EndM + + REPT 16 + M32Mix8SurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Surround8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Surround8BitOffsetTable+BX] + + M32Mix8Surround 0 + M32Mix8Surround 1 + M32Mix8Surround 2 + M32Mix8Surround 3 + M32Mix8Surround 4 + M32Mix8Surround 5 + M32Mix8Surround 6 + M32Mix8Surround 7 + M32Mix8Surround 8 + M32Mix8Surround 9 + M32Mix8Surround 10 + M32Mix8Surround 11 + M32Mix8Surround 12 + M32Mix8Surround 13 + M32Mix8Surround 14 + M32Mix8Surround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix8Surround0 + + Ret + +EndP Mix32Surround8Bit + +; + +Proc PreMix32Surround8Bit + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMix32SurroundMacro Macro Index + Mov Word Ptr [CS:M32Mix8SurroundVolume&Index&], AX + EndM + + REPT 16 + PreMix32SurroundMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Surround8Bit + +; + +Mix32Panned8BitOffsetTable Label Word + + IndexCounter = 15 + + M32Mix8PannedOffset Macro Index + DW Offset M32Mix8Panned&Index& + EndM + + REPT 16 + M32Mix8PannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Panned8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Panned8BitOffsetTable+BX] + + M32Mix8Panned 0 + M32Mix8Panned 1 + M32Mix8Panned 2 + M32Mix8Panned 3 + M32Mix8Panned 4 + M32Mix8Panned 5 + M32Mix8Panned 6 + M32Mix8Panned 7 + M32Mix8Panned 8 + M32Mix8Panned 9 + M32Mix8Panned 10 + M32Mix8Panned 11 + M32Mix8Panned 12 + M32Mix8Panned 13 + M32Mix8Panned 14 + M32Mix8Panned 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix8Panned0 + + Ret + +EndP Mix32Panned8Bit + +; + +Proc PreMix32Panned8Bit + + Mov AX, [SI+0Eh] ; Left + Mov BX, [SI+0Ch] ; Right + + IndexCounter = 0 + + PreMix32PannedMacro Macro Index + Mov Word Ptr [CS:M32Mix8LeftVolume&Index&], AX + Mov Word Ptr [CS:M32Mix8RightVolume&Index&], BX + EndM + + REPT 16 + PreMix32PannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Panned8Bit + +; + +Mix32Single16BitOffsetTable Label Word + + IndexCounter = 15 + + M32Mix16SingleOffset Macro Index + DW Offset M32Mix16Single&Index& + EndM + + REPT 16 + M32Mix16SingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Single16Bit + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Single16BitOffsetTable+BX] + + M32Mix16Single 0 + M32Mix16Single 1 + M32Mix16Single 2 + M32Mix16Single 3 + M32Mix16Single 4 + M32Mix16Single 5 + M32Mix16Single 6 + M32Mix16Single 7 + M32Mix16Single 8 + M32Mix16Single 9 + M32Mix16Single 10 + M32Mix16Single 11 + M32Mix16Single 12 + M32Mix16Single 13 + M32Mix16Single 14 + M32Mix16Single 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix16Single0 + + Ret + +EndP Mix32Single16Bit + +; + +Proc PreMix32Left16Bit + + Mov AX, [SI+0Eh] ; Left + +PreMix32Left16Bit1: + IndexCounter = 0 + + PreMix32SingleMacro Macro Index + Mov Word Ptr [CS:M32Mix16SingleVolume&Index&], AX + EndM + + REPT 16 + PreMix32SingleMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Left16Bit + +; + +Proc PreMix32Right16Bit + + Add MixBufferOffset, MixResolution/8 + Mov AX, [SI+0Ch] + Jmp PreMix32Left16Bit1 + + Ret + +EndP PreMix32Right16Bit + +; + +Mix32Central16BitOffsetTable Label Word + + IndexCounter = 15 + + M32Mix16CentralOffset Macro Index + DW Offset M32Mix16Central&Index& + EndM + + REPT 16 + M32Mix16CentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Central16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Central16BitOffsetTable+BX] + + M32Mix16Central 0 + M32Mix16Central 1 + M32Mix16Central 2 + M32Mix16Central 3 + M32Mix16Central 4 + M32Mix16Central 5 + M32Mix16Central 6 + M32Mix16Central 7 + M32Mix16Central 8 + M32Mix16Central 9 + M32Mix16Central 10 + M32Mix16Central 11 + M32Mix16Central 12 + M32Mix16Central 13 + M32Mix16Central 14 + M32Mix16Central 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix16Central0 + + Ret + +EndP Mix32Central16Bit + +; + +Proc PreMix32Central16Bit + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMix32CentralMacro Macro Index + Mov Word Ptr [CS:M32Mix16CentralVolume&Index&], AX + EndM + + REPT 16 + PreMix32CentralMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Central16Bit + +; + +Mix32Surround16BitOffsetTable Label Word + + IndexCounter = 15 + + M32Mix16SurroundOffset Macro Index + DW Offset M32Mix16Surround&Index& + EndM + + REPT 16 + M32Mix16SurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Surround16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Surround16BitOffsetTable+BX] + + M32Mix16Surround 0 + M32Mix16Surround 1 + M32Mix16Surround 2 + M32Mix16Surround 3 + M32Mix16Surround 4 + M32Mix16Surround 5 + M32Mix16Surround 6 + M32Mix16Surround 7 + M32Mix16Surround 8 + M32Mix16Surround 9 + M32Mix16Surround 10 + M32Mix16Surround 11 + M32Mix16Surround 12 + M32Mix16Surround 13 + M32Mix16Surround 14 + M32Mix16Surround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix16Surround0 + + Ret + +EndP Mix32Surround16Bit + +; + +Proc PreMix32Surround16Bit + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMix32SurroundMacro Macro Index + Mov Word Ptr [CS:M32Mix16SurroundVolume&Index&], AX + EndM + + REPT 16 + PreMix32SurroundMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Surround16Bit + +; + +Mix32Panned16BitOffsetTable Label Word + + IndexCounter = 15 + + M32Mix16PannedOffset Macro Index + DW Offset M32Mix16Panned&Index& + EndM + + REPT 16 + M32Mix16PannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Panned16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Panned16BitOffsetTable+BX] + +Pan32Bit16Loop: + M32Mix16Panned 0 + M32Mix16Panned 1 + M32Mix16Panned 2 + M32Mix16Panned 3 + M32Mix16Panned 4 + M32Mix16Panned 5 + M32Mix16Panned 6 + M32Mix16Panned 7 + M32Mix16Panned 8 + M32Mix16Panned 9 + M32Mix16Panned 10 + M32Mix16Panned 11 + M32Mix16Panned 12 + M32Mix16Panned 13 + M32Mix16Panned 14 + M32Mix16Panned 15 + + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ Pan32Bit16Loop + + Ret + +EndP Mix32Panned16Bit + +; + +Proc PreMix32Panned16Bit + + Mov AX, [SI+0Eh] ; Left + Mov BX, [SI+0Ch] ; Right + + IndexCounter = 0 + + PreMix32PannedMacro Macro Index + Mov Word Ptr [CS:M32Mix16LeftVolume&Index&], AX + Mov Word Ptr [CS:M32Mix16RightVolume&Index&], BX + EndM + + REPT 16 + PreMix32PannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Panned16Bit + + +; +; + diff --git a/it/SoundDrivers/M32BITFF.MIX b/it/SoundDrivers/M32BITFF.MIX new file mode 100755 index 0000000..6a6abcd --- /dev/null +++ b/it/SoundDrivers/M32BITFF.MIX @@ -0,0 +1,6 @@ +; +; Floating point mixing routines +; DS:0 = a, DS:4 = b, DS:8 = c +; DS:10h = os1, DS:18h = OS2 +; + diff --git a/it/SoundDrivers/M32BITI.INC b/it/SoundDrivers/M32BITI.INC new file mode 100755 index 0000000..4a229ab --- /dev/null +++ b/it/SoundDrivers/M32BITI.INC @@ -0,0 +1,49 @@ + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix32Left8BitI, MFS8Bit, MBS8Bit, Mix32Single8BitI + DW Offset MixForwardsLoop, PreMix32Left8BitI, MFS8Bit, MBS8Bit, Mix32Single8BitI + DW Offset MixPingPongLoop, PreMix32Left8BitI, MFS8Bit, MBS8Bit, Mix32Single8BitI + ; Right only + DW Offset MixNoLoop, PreMix32Right8BitI, MFS8Bit, MBS8Bit, Mix32Single8BitI + DW Offset MixForwardsLoop, PreMix32Right8BitI, MFS8Bit, MBS8Bit, Mix32Single8BitI + DW Offset MixPingPongLoop, PreMix32Right8BitI, MFS8Bit, MBS8Bit, Mix32Single8BitI + ; Central + DW Offset MixNoLoop, PreMix32Central8BitI, MFS8Bit, MBS8Bit, Mix32Central8BitI + DW Offset MixForwardsLoop, PreMix32Central8BitI, MFS8Bit, MBS8Bit, Mix32Central8BitI + DW Offset MixPingPongLoop, PreMix32Central8BitI, MFS8Bit, MBS8Bit, Mix32Central8BitI + ; Stereo + DW Offset MixNoLoop, PreMix32Panned8BitI, MFS8Bit, MBS8Bit, Mix32Panned8BitI + DW Offset MixForwardsLoop, PreMix32Panned8BitI, MFS8Bit, MBS8Bit, Mix32Panned8BitI + DW Offset MixPingPongLoop, PreMix32Panned8BitI, MFS8Bit, MBS8Bit, Mix32Panned8BitI + ; Surround + DW Offset MixNoLoop, PreMix32Surround8BitI, MFS8Bit, MBS8Bit, Mix32Surround8BitI + DW Offset MixForwardsLoop, PreMix32Surround8BitI, MFS8Bit, MBS8Bit, Mix32Surround8BitI + DW Offset MixPingPongLoop, PreMix32Surround8BitI, MFS8Bit, MBS8Bit, Mix32Surround8BitI + + ; 16 bit tables + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMix32Left16BitI, MFS16Bit, MBS16Bit, Mix32Single16BitI + DW Offset MixForwardsLoop, PreMix32Left16BitI, MFS16Bit, MBS16Bit, Mix32Single16BitI + DW Offset MixPingPongLoop, PreMix32Left16BitI, MFS16Bit, MBS16Bit, Mix32Single16BitI + ; Right only + DW Offset MixNoLoop, PreMix32Right16BitI, MFS16Bit, MBS16Bit, Mix32Single16BitI + DW Offset MixForwardsLoop, PreMix32Right16BitI, MFS16Bit, MBS16Bit, Mix32Single16BitI + DW Offset MixPingPongLoop, PreMix32Right16BitI, MFS16Bit, MBS16Bit, Mix32Single16BitI + ; Central + DW Offset MixNoLoop, PreMix32Central16BitI, MFS16Bit, MBS16Bit, Mix32Central16BitI + DW Offset MixForwardsLoop, PreMix32Central16BitI, MFS16Bit, MBS16Bit, Mix32Central16BitI + DW Offset MixPingPongLoop, PreMix32Central16BitI, MFS16Bit, MBS16Bit, Mix32Central16BitI + ; Stereo + DW Offset MixNoLoop, PreMix32Panned16BitI, MFS16Bit, MBS16Bit, Mix32Panned16BitI + DW Offset MixForwardsLoop, PreMix32Panned16BitI, MFS16Bit, MBS16Bit, Mix32Panned16BitI + DW Offset MixPingPongLoop, PreMix32Panned16BitI, MFS16Bit, MBS16Bit, Mix32Panned16BitI + ; Surround + DW Offset MixNoLoop, PreMix32Surround16BitI, MFS16Bit, MBS16Bit, Mix32Surround16BitI + DW Offset MixForwardsLoop, PreMix32Surround16BitI, MFS16Bit, MBS16Bit, Mix32Surround16BitI + DW Offset MixPingPongLoop, PreMix32Surround16BitI, MFS16Bit, MBS16Bit, Mix32Surround16BitI diff --git a/it/SoundDrivers/M32BITI.MIX b/it/SoundDrivers/M32BITI.MIX new file mode 100755 index 0000000..6d645dd --- /dev/null +++ b/it/SoundDrivers/M32BITI.MIX @@ -0,0 +1,818 @@ + + ; Different mixing routines required: + ; Left } shared + ; Right } + ; Central + ; Surround + ; Panned ; Each requires 8 bit and 16 bit + ; Single output - for Mono, pure left/pure right + +Get32Bit8Waveform Macro + MovSX EBX, Byte Ptr [ES:DI+1] + MovSX EAX, Byte Ptr [ES:DI] + Sub EBX, EAX + IMul EBX, ECX + SAR EBX, 8 + ShL EAX, 8 + Add EBX, EAX + +EndM + +Get32Bit16Waveform Macro + MovSX EBX, Word Ptr [ES:EDI+EDI+2] + MovSX EAX, Word Ptr [ES:EDI+EDI] + Sub EBX, EAX + SAR EBX, 1 + IMul EBX, ECX + SAR EBX, 15 + Add EBX, EAX +EndM + +M32Mix8ISingle Macro Index + +M32Mix8ISingle&Index&: + Get32Bit8WaveForm + +M32Mix8ISingleVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 3 +EndM + +M32Mix8ICentral Macro Index + +M32Mix8ICentral&Index&: + Get32Bit8WaveForm + +M32Mix8ICentralVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 4 + Sub [SI+(Index-15)*8+4], EAX ;; 4 + +EndM + +M32Mix8ISurround Macro Index + +M32Mix8ISurround&Index&: + Get32Bit8WaveForm + +M32Mix8ISurroundVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 4 + Add [SI+(Index-15)*8+4], EAX ;; 4 + +EndM + + ; Panned output +M32Mix8IPanned Macro Index + +M32Mix8IPanned&Index&: + Get32Bit8WaveForm + +M32Mix8ILeftVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h +M32Mix8IRightVolume&Index& EQU $+3 + IMul EBX, EBX, 8000h + + Sub [SI+(Index-15)*8], EAX ;; 4 + Sub [SI+(Index-15)*8+4], EBX ;; 4 + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + +EndM + +M32Mix16ISingle Macro Index + +M32Mix16ISingle&Index&: + Get32Bit16WaveForm + +M32Mix16ISingleVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 3 + +EndM + +M32Mix16ICentral Macro Index + +M32Mix16ICentral&Index&: + Get32Bit16WaveForm + +M32Mix16ICentralVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 3 + Sub [SI+(Index-15)*8+4], EAX ;; 3 + +EndM + +M32Mix16ISurround Macro Index + +M32Mix16ISurround&Index&: + Get32Bit16WaveForm + +M32Mix16ISurroundVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*8], EAX ;; 3 + Add [SI+(Index-15)*8+4], EAX ;; 3 + +EndM + + ; Panned output +M32Mix16IPanned Macro Index + +M32Mix16IPanned&Index&: + Get32Bit16WaveForm + +M32Mix16ILeftVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h +M32Mix16IRightVolume&Index& EQU $+3 + IMul EBX, EBX, 8000h + + Sub [SI+(Index-15)*8], EAX + Sub [SI+(Index-15)*8+4], EBX + + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + +EndM + +; + +Mix32Single8BitIOffsetTable Label Word + + IndexCounter = 15 + + M32Mix8ISingleOffset Macro Index + DW Offset M32Mix8ISingle&Index& + EndM + + REPT 16 + M32Mix8ISingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Single8BitI + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Single8BitIOffsetTable+BX] + + M32Mix8ISingle 0 + M32Mix8ISingle 1 + M32Mix8ISingle 2 + M32Mix8ISingle 3 + M32Mix8ISingle 4 + M32Mix8ISingle 5 + M32Mix8ISingle 6 + M32Mix8ISingle 7 + M32Mix8ISingle 8 + M32Mix8ISingle 9 + M32Mix8ISingle 10 + M32Mix8ISingle 11 + M32Mix8ISingle 12 + M32Mix8ISingle 13 + M32Mix8ISingle 14 + M32Mix8ISingle 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix8ISingle0 + + Ret + +EndP Mix32Single8BitI + +; + +Proc PreMix32Left8BitI + + Mov AX, [SI+0Eh] + +PreMix32Left8BitI1: + IndexCounter = 0 + + PreMix32SingleMacro Macro Index + Mov Word Ptr [CS:M32Mix8ISingleVolume&Index&], AX + EndM + + REPT 16 + PreMix32SingleMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + Ret + +EndP PreMix32Left8BitI + +; + +Proc PreMix32Right8BitI + + Add MixBufferOffset, MixResolution/8 + Mov AX, [SI+0Ch] + Jmp PreMix32Left8BitI1 + +EndP PreMix32Right8BitI + +; + +Mix32Central8BitIOffsetTable Label Word + + IndexCounter = 15 + + M32Mix8ICentralOffset Macro Index + DW Offset M32Mix8ICentral&Index& + EndM + + REPT 16 + M32Mix8ICentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Central8BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Central8BitIOffsetTable+BX] + + M32Mix8ICentral 0 + M32Mix8ICentral 1 + M32Mix8ICentral 2 + M32Mix8ICentral 3 + M32Mix8ICentral 4 + M32Mix8ICentral 5 + M32Mix8ICentral 6 + M32Mix8ICentral 7 + M32Mix8ICentral 8 + M32Mix8ICentral 9 + M32Mix8ICentral 10 + M32Mix8ICentral 11 + M32Mix8ICentral 12 + M32Mix8ICentral 13 + M32Mix8ICentral 14 + M32Mix8ICentral 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix8ICentral0 + + Ret + +EndP Mix32Central8BitI + +; + +Proc PreMix32Central8BitI + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMix32CentralMacro Macro Index + Mov Word Ptr [CS:M32Mix8ICentralVolume&Index&], AX + EndM + + REPT 16 + PreMix32CentralMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Central8BitI + +; + +Mix32Surround8BitIOffsetTable Label Word + + IndexCounter = 15 + + M32Mix8ISurroundOffset Macro Index + DW Offset M32Mix8ISurround&Index& + EndM + + REPT 16 + M32Mix8ISurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Surround8BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Surround8BitIOffsetTable+BX] + + M32Mix8ISurround 0 + M32Mix8ISurround 1 + M32Mix8ISurround 2 + M32Mix8ISurround 3 + M32Mix8ISurround 4 + M32Mix8ISurround 5 + M32Mix8ISurround 6 + M32Mix8ISurround 7 + M32Mix8ISurround 8 + M32Mix8ISurround 9 + M32Mix8ISurround 10 + M32Mix8ISurround 11 + M32Mix8ISurround 12 + M32Mix8ISurround 13 + M32Mix8ISurround 14 + M32Mix8ISurround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix8ISurround0 + + Ret + +EndP Mix32Surround8BitI + +; + +Proc PreMix32Surround8BitI + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMix32SurroundMacro Macro Index + Mov Word Ptr [CS:M32Mix8ISurroundVolume&Index&], AX + EndM + + REPT 16 + PreMix32SurroundMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Surround8BitI + +; + +Mix32Panned8BitIOffsetTable Label Word + + IndexCounter = 15 + + M32Mix8IPannedOffset Macro Index + DW Offset M32Mix8IPanned&Index& + EndM + + REPT 16 + M32Mix8IPannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Panned8BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Panned8BitIOffsetTable+BX] + + M32Mix8IPanned 0 + M32Mix8IPanned 1 + M32Mix8IPanned 2 + M32Mix8IPanned 3 + M32Mix8IPanned 4 + M32Mix8IPanned 5 + M32Mix8IPanned 6 + M32Mix8IPanned 7 + M32Mix8IPanned 8 + M32Mix8IPanned 9 + M32Mix8IPanned 10 + M32Mix8IPanned 11 + M32Mix8IPanned 12 + M32Mix8IPanned 13 + M32Mix8IPanned 14 + M32Mix8IPanned 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix8IPanned0 + + Ret + +EndP Mix32Panned8BitI + +; + +Proc PreMix32Panned8BitI + + Mov AX, [SI+0Eh] ; Left + Mov BX, [SI+0Ch] ; Right + + IndexCounter = 0 + + PreMix32PannedMacro Macro Index + Mov Word Ptr [CS:M32Mix8ILeftVolume&Index&], AX + Mov Word Ptr [CS:M32Mix8IRightVolume&Index&], BX + EndM + + REPT 16 + PreMix32PannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Panned8BitI + +; + +Mix32Single16BitIOffsetTable Label Word + + IndexCounter = 15 + + M32Mix16ISingleOffset Macro Index + DW Offset M32Mix16ISingle&Index& + EndM + + REPT 16 + M32Mix16ISingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Single16BitI + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Single16BitIOffsetTable+BX] + + M32Mix16ISingle 0 + M32Mix16ISingle 1 + M32Mix16ISingle 2 + M32Mix16ISingle 3 + M32Mix16ISingle 4 + M32Mix16ISingle 5 + M32Mix16ISingle 6 + M32Mix16ISingle 7 + M32Mix16ISingle 8 + M32Mix16ISingle 9 + M32Mix16ISingle 10 + M32Mix16ISingle 11 + M32Mix16ISingle 12 + M32Mix16ISingle 13 + M32Mix16ISingle 14 + M32Mix16ISingle 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix16ISingle0 + + Ret + +EndP Mix32Single16BitI + +; + +Proc PreMix32Left16BitI + + Mov AX, [SI+0Eh] ; Left + +PreMix32Left16BitI1: + IndexCounter = 0 + + PreMix32SingleMacro Macro Index + Mov Word Ptr [CS:M32Mix16ISingleVolume&Index&], AX + EndM + + REPT 16 + PreMix32SingleMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Left16BitI + +; + +Proc PreMix32Right16BitI + + Add MixBufferOffset, MixResolution/8 + Mov AX, [SI+0Ch] + Jmp PreMix32Left16BitI1 + + Ret + +EndP PreMix32Right16BitI + +; + +Mix32Central16BitIOffsetTable Label Word + + IndexCounter = 15 + + M32Mix16ICentralOffset Macro Index + DW Offset M32Mix16ICentral&Index& + EndM + + REPT 16 + M32Mix16ICentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Central16BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Central16BitIOffsetTable+BX] + + M32Mix16ICentral 0 + M32Mix16ICentral 1 + M32Mix16ICentral 2 + M32Mix16ICentral 3 + M32Mix16ICentral 4 + M32Mix16ICentral 5 + M32Mix16ICentral 6 + M32Mix16ICentral 7 + M32Mix16ICentral 8 + M32Mix16ICentral 9 + M32Mix16ICentral 10 + M32Mix16ICentral 11 + M32Mix16ICentral 12 + M32Mix16ICentral 13 + M32Mix16ICentral 14 + M32Mix16ICentral 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix16ICentral0 + + Ret + +EndP Mix32Central16BitI + +; + +Proc PreMix32Central16BitI + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMix32CentralMacro Macro Index + Mov Word Ptr [CS:M32Mix16ICentralVolume&Index&], AX + EndM + + REPT 16 + PreMix32CentralMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Central16BitI + +; + +Mix32Surround16BitIOffsetTable Label Word + + IndexCounter = 15 + + M32Mix16ISurroundOffset Macro Index + DW Offset M32Mix16ISurround&Index& + EndM + + REPT 16 + M32Mix16ISurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Surround16BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Surround16BitIOffsetTable+BX] + + M32Mix16ISurround 0 + M32Mix16ISurround 1 + M32Mix16ISurround 2 + M32Mix16ISurround 3 + M32Mix16ISurround 4 + M32Mix16ISurround 5 + M32Mix16ISurround 6 + M32Mix16ISurround 7 + M32Mix16ISurround 8 + M32Mix16ISurround 9 + M32Mix16ISurround 10 + M32Mix16ISurround 11 + M32Mix16ISurround 12 + M32Mix16ISurround 13 + M32Mix16ISurround 14 + M32Mix16ISurround 15 + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ M32Mix16ISurround0 + + Ret + +EndP Mix32Surround16BitI + +; + +Proc PreMix32Surround16BitI + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMix32SurroundMacro Macro Index + Mov Word Ptr [CS:M32Mix16ISurroundVolume&Index&], AX + EndM + + REPT 16 + PreMix32SurroundMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Surround16BitI + +; + +Mix32Panned16BitIOffsetTable Label Word + + IndexCounter = 15 + + M32Mix16IPannedOffset Macro Index + DW Offset M32Mix16IPanned&Index& + EndM + + REPT 16 + M32Mix16IPannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix32Panned16BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:Mix32Panned16BitIOffsetTable+BX] + +Pan32Bit16ILoop: + M32Mix16IPanned 0 + M32Mix16IPanned 1 + M32Mix16IPanned 2 + M32Mix16IPanned 3 + M32Mix16IPanned 4 + M32Mix16IPanned 5 + M32Mix16IPanned 6 + M32Mix16IPanned 7 + M32Mix16IPanned 8 + M32Mix16IPanned 9 + M32Mix16IPanned 10 + M32Mix16IPanned 11 + M32Mix16IPanned 12 + M32Mix16IPanned 13 + M32Mix16IPanned 14 + M32Mix16IPanned 15 + + + Add SI, 16*MIXRESOLUTION/4 + Dec LoopCounter + JNZ Pan32Bit16ILoop + + Ret + +EndP Mix32Panned16BitI + +; + +Proc PreMix32Panned16BitI + + Mov AX, [SI+0Eh] ; Left + Mov BX, [SI+0Ch] ; Right + + IndexCounter = 0 + + PreMix32PannedMacro Macro Index + Mov Word Ptr [CS:M32Mix16ILeftVolume&Index&], AX + Mov Word Ptr [CS:M32Mix16IRightVolume&Index&], BX + EndM + + REPT 16 + PreMix32PannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix32Panned16BitI + + +; +; + diff --git a/it/SoundDrivers/M32BITM.INC b/it/SoundDrivers/M32BITM.INC new file mode 100755 index 0000000..8a12847 --- /dev/null +++ b/it/SoundDrivers/M32BITM.INC @@ -0,0 +1,11 @@ +; 8 bit tables + + DW Offset MixNoLoop, PreM32BitMPanned, MFS8Bit, MBS8Bit, M32Bit8MPanned + DW Offset MixForwardsLoop, PreM32BitMPanned, MFS8Bit, MBS8Bit, M32Bit8MPanned + DW Offset MixPingPongLoop, PreM32BitMPanned, MFS8Bit, MBS8Bit, M32Bit8MPanned + +; 16 bit + + DW Offset MixNoLoop, PreM32BitMPanned, MFS16Bit, MBS16Bit, M32Bit16MPanned + DW Offset MixForwardsLoop, PreM32BitMPanned, MFS16Bit, MBS16Bit, M32Bit16MPanned + DW Offset MixPingPongLoop, PreM32BitMPanned, MFS16Bit, MBS16Bit, M32Bit16MPanned diff --git a/it/SoundDrivers/M32BITM.MIX b/it/SoundDrivers/M32BITM.MIX new file mode 100755 index 0000000..33f837a --- /dev/null +++ b/it/SoundDrivers/M32BITM.MIX @@ -0,0 +1,502 @@ + +; + +MONITORPERFORMANCE = 0 + +ALIGN 16 + +M32BitMVolumeData DW 0, 0, 0, 0 + +IF MONITORPERFORMANCE +M32BitMCounter8BitTicksLow DD 0 +M32BitMCounter8BitTicksHigh DD 0 +M32BitMCounter16BitTicksLow DD 0 +M32BitMCounter16BitTicksHigh DD 0 +M32BitMCounter8BitLow DW 0 +M32BitMCounter8BitHigh DW 0 +M32BitMCounter16BitLow DW 0 +M32BitMCounter16BitHigh DW 0 +ENDIF + + +; + +Proc M32Bit16MPanned + +; AX = number to mix +; CX = error +; DX = deltaoffset +; BP = deltaerror +; DS:SI = 32-bit output buffer +; ES:EDI+EDI = sample location +; MM6 = L/R volumes +; MM7 = PXor mask + +IF MONITORPERFORMANCE + Push EAX + Push EDX + + Add CS:M32BitMCounter16BitLow, AX + AdC CS:M32BitMCounter16BitHigh, 0 + + RdTSC + Sub CS:M32BitMCounter16BitTicksLow, EAX + SBB CS:M32BitMCounter16BitTicksHigh, EDX + + Pop EDX + Pop EAX +ENDIF + + Mov BX, DI + Add BX, BX + +M32Bit16MPanned1: ; Mix 1 sample + Test AL, 1 + JZ M32Bit16MPanned2 + + Push AX + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:0], AX + Mov BX, DI + + MovQ MM0, [DS:0] + Add BX, BX + + PUnpckLWD MM0, MM0 + MovQ MM2, MM6 + PMulLW MM2, MM0 + PMulHW MM0, MM6 + PUnpckLWD MM2, MM0 + PAddD MM2, [SI] + MovQM [SI], MM2 + + Add SI, 8 + Pop AX + +M32Bit16MPanned2: ; Mix 2 samples + Test AL, 2 + JZ M32Bit16MPanned3 + + Push AX + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:0], AX + Mov BX, DI + Add BX, BX + Add CX, BP + AdC DI, DX + Mov AX, [ES:BX] + Mov BX, DI + Mov [DS:2], AX + Add BX, BX + + MovQ MM0, [DS:0] + PUnpckLWD MM0, MM0 + MovQ MM2, MM6 + PMulLW MM2, MM0 + PMulHW MM0, MM6 + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + PUnpckHWD MM4, MM0 + PAddD MM2, [SI] + PAddD MM4, [SI+8] + MovQM [SI], MM2 + MovQM [SI+8], MM4 + + Add SI, 10h + Pop AX + +M32Bit16MPanned3: + ShR AX, 2 + JZ M32Bit16MPannedEnd + + Mov Word Ptr [DS:20h], AX + + Mov AX, [ES:BX] + Add CX, BP + AdC DI, DX + Mov [DS:0], AX + Mov BX, DI + Add BX, BX + + Mov AX, [ES:BX] + Add CX, BP + AdC DI, DX + Mov [DS:2], AX + Mov BX, DI + Add BX, BX + + Mov AX, [ES:BX] + Add CX, BP + AdC DI, DX + Mov [DS:0Ch], AX + Mov BX, DI + Add BX, BX + + Mov AX, [ES:BX] + Add CX, BP + AdC DI, DX + Mov [DS:0Eh], AX + Mov BX, DI + Add BX, BX + + Dec Word Ptr [DS:20h] + JZ M32Bit16MPanned5 + +M32Bit16MPanned4: + MovQ MM0, [DS:0] + MovQ MM2, MM6 + MovQ MM1, [DS:8] + PUnpckLWD MM0, MM0 + + PMulLW MM2, MM0 + PUnpckHWD MM1, MM1 + + PMulHW MM0, MM6 + MovQ MM3, MM6 + + Mov AX, [ES:BX] + Add CX, BP + AdC DI, DX + Mov [DS:0], AX + Mov BX, DI + Add BX, BX + + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + + PAddD MM2, [SI] + PUnpckHWD MM4, MM0 + + PAddD MM4, [SI+8] + PMulLW MM3, MM1 + + MovQM [SI], MM2 + PMulHW MM1, MM6 + + Mov AX, [ES:BX] + Add CX, BP + AdC DI, DX + Mov [DS:2], AX + Mov BX, DI + Add BX, BX + + MovQM [SI+8], MM4 + MovQ MM5, MM3 + + MovQ MM0, [SI+18h] + PUnpckLWD MM3, MM1 + PAddD MM3, [SI+10h] + PUnpckHWD MM5, MM1 + MovQM [SI+10h], MM3 + PAddD MM5, MM0 + + Mov AX, [ES:BX] + Add CX, BP + AdC DI, DX + Mov [DS:0Ch], AX + Mov BX, DI + Add BX, BX + + MovQM [SI+18h], MM5 + + Mov AX, [ES:BX] + Add CX, BP + AdC DI, DX + Mov [DS:0Eh], AX + Mov BX, DI + Add BX, BX + + Add SI, 20h + + Dec Word Ptr [DS:20h] + JNZ M32Bit16MPanned4 + +M32Bit16MPanned5: + MovQ MM0, [DS:0] + MovQ MM2, MM6 + + MovQ MM1, [DS:8] + PUnpckLWD MM0, MM0 + + PMulLW MM2, MM0 + MovQ MM3, MM6 + + PMulHW MM0, MM6 + PUnpckHWD MM1, MM1 + + MovQ MM4, MM2 + PMulLW MM3, MM1 + + PUnpckLWD MM2, MM0 + PMulHW MM1, MM6 + + PAddD MM2, [SI] + PUnpckHWD MM4, MM0 + + PAddD MM4, [SI+8] + MovQ MM5, MM3 + + MovQM [SI], MM2 + PUnpckLWD MM3, MM1 + + MovQM [SI+8], MM4 + PUnpckHWD MM5, MM1 + + PAddD MM3, [SI+10h] + PAddD MM5, [SI+18h] + + MovQM [SI+10h], MM3 + MovQM [SI+18h], MM5 + +M32Bit16MPannedEnd: +IF MONITORPERFORMANCE + RdTSC + Add CS:M32BitMCounter16BitTicksLow, EAX + AdC CS:M32BitMCounter16BitTicksHigh, EDX +ENDIF + Ret + +EndP M32Bit16MPanned + +; + +Proc M32Bit8MPanned + +; AX = number to mix +; CX = error +; DX = deltaoffset +; BP = deltaerror +; DS:SI = 32-bit output buffer +; ES:DI = sample location +; MM6 = L/R volumes +; MM7 = PXor mask + +IF MONITORPERFORMANCE + Push EAX + Push EDX + + Add CS:M32BitMCounter8BitLow, AX + AdC CS:M32BitMCounter8BitHigh, 0 + + RdTSC + Sub CS:M32BitMCounter8BitTicksLow, EAX + SBB CS:M32BitMCounter8BitTicksHigh, EDX + + Pop EDX + Pop EAX +ENDIF + + Mov BX, AX + And AX, 3 + JZ M32Bit8MPanned3 + +M32Bit8MPanned1: ; Mix 1 sample + Test AL, 1 + JZ M32Bit8MPanned2 + + Xor AX, AX + Add ERROR, DELTAERROR + Mov AH, [ES:DI] + AdC DI, DELTAOFFSET + Mov [DS:0], AX + + MovQ MM0, [DS:0] + PUnpckLWD MM0, MM0 + MovQ MM2, MM6 + PMulLW MM2, MM0 + PMulHW MM0, MM6 + PUnpckLWD MM2, MM0 + PAddD MM2, [SI] + MovQM [SI], MM2 + + Add SI, 8 + +M32Bit8MPanned2: ; Mix 2 samples + Test BL, 2 + JZ M32Bit8MPanned3 + + Xor AX, AX + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0], AX + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:2], AX + + MovQ MM0, [DS:0] + PUnpckLWD MM0, MM0 + MovQ MM2, MM6 + PMulLW MM2, MM0 + PMulHW MM0, MM6 + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + PUnpckHWD MM4, MM0 + PAddD MM2, [SI] + PAddD MM4, [SI+8] + MovQM [SI], MM2 + MovQM [SI+8], MM4 + + Add SI, 10h + +M32Bit8MPanned3: + Xor AX, AX + ShR BX, 2 + JZ M32Bit8MPannedEnd + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0], AX + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:2], AX + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0Ch], AX + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0Eh], AX + + Dec BX + JZ M32Bit8MPanned5 + +M32Bit8MPanned4: + MovQ MM0, [DS:0] + MovQ MM2, MM6 + MovQ MM1, [DS:8] + PUnpckLWD MM0, MM0 + + PMulLW MM2, MM0 + PUnpckHWD MM1, MM1 + + PMulHW MM0, MM6 + MovQ MM3, MM6 + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0], AX + + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + + PAddD MM2, [SI] + PUnpckHWD MM4, MM0 + + PAddD MM4, [SI+8] + PMulLW MM3, MM1 + + MovQM [SI], MM2 + PMulHW MM1, MM6 + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:2], AX + + MovQM [SI+8], MM4 + MovQ MM5, MM3 + + MovQ MM0, [SI+18h] + PUnpckLWD MM3, MM1 + PAddD MM3, [SI+10h] + PUnpckHWD MM5, MM1 + MovQM [SI+10h], MM3 + PAddD MM5, MM0 + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0Ch], AX + + MovQM [SI+18h], MM5 + + Mov AH, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0Eh], AX + + Add SI, 20h + + Dec BX + JNZ M32Bit8MPanned4 + +M32Bit8MPanned5: + MovQ MM0, [DS:0] + MovQ MM2, MM6 + + MovQ MM1, [DS:8] + PUnpckLWD MM0, MM0 + + PMulLW MM2, MM0 + MovQ MM3, MM6 + + PMulHW MM0, MM6 + PUnpckHWD MM1, MM1 + + MovQ MM4, MM2 + PMulLW MM3, MM1 + + PUnpckLWD MM2, MM0 + PMulHW MM1, MM6 + + PAddD MM2, [SI] + PUnpckHWD MM4, MM0 + + PAddD MM4, [SI+8] + MovQ MM5, MM3 + + MovQM [SI], MM2 + PUnpckLWD MM3, MM1 + + MovQM [SI+8], MM4 + PUnpckHWD MM5, MM1 + + PAddD MM3, [SI+10h] + PAddD MM5, [SI+18h] + + MovQM [SI+10h], MM3 + MovQM [SI+18h], MM5 + +M32Bit8MPannedEnd: +IF MONITORPERFORMANCE + RdTSC + Add CS:M32BitMCounter8BitTicksLow, EAX + AdC CS:M32BitMCounter8BitTicksHigh, EDX +ENDIF + Ret + +EndP M32Bit8MPanned + +; + +Proc PreM32BitMPanned + Assume DS:Driver + + Mov EAX, [SI+0Ch] ; LEAX = left vol, HEAX = right vol + Mov [DWord Ptr CS:M32BitMVolumeData], EAX + Mov [DWord Ptr CS:M32BitMVolumeData+4], EAX + + SegCS MovQ MM6, M32BitMVolumeData + + Ret + +EndP PreM32BitMPanned + Assume DS:Nothing + +; + diff --git a/it/SoundDrivers/M32BITMF.INC b/it/SoundDrivers/M32BITMF.INC new file mode 100755 index 0000000..3f83cf2 --- /dev/null +++ b/it/SoundDrivers/M32BITMF.INC @@ -0,0 +1,12 @@ +; 8 bit tables + + DW Offset MixNoLoop, PreM32BitMFPanned, MFS8Bit, MBS8Bit, M32Bit8MFPanned + DW Offset MixForwardsLoop, PreM32BitMFPanned, MFS8Bit, MBS8Bit, M32Bit8MFPanned + DW Offset MixPingPongLoop, PreM32BitMFPanned, MFS8Bit, MBS8Bit, M32Bit8MFPanned + +; 16 bit tables + + DW Offset MixNoLoop, PreM32BitMFPanned, MFS16Bit, MBS16Bit, M32Bit16MFPanned + DW Offset MixForwardsLoop, PreM32BitMFPanned, MFS16Bit, MBS16Bit, M32Bit16MFPanned + DW Offset MixPingPongLoop, PreM32BitMFPanned, MFS16Bit, MBS16Bit, M32Bit16MFPanned + diff --git a/it/SoundDrivers/M32BITMF.MIX b/it/SoundDrivers/M32BITMF.MIX new file mode 100755 index 0000000..e3bb9c3 --- /dev/null +++ b/it/SoundDrivers/M32BITMF.MIX @@ -0,0 +1,708 @@ + +; +; Resonant filter mixing routines +; + +; + +MONITORPERFORMANCE = 0 +RAMPSPEED = 7 +RAMPCOMPENSATE = 63 + +IF MONITORPERFORMANCE +ALIGN 16 +M32BitMICounter8BitTicksLow DD 0 +M32BitMICounter8BitTicksHigh DD 0 +M32BitMICounter16BitTicksLow DD 0 +M32BitMICounter16BitTicksHigh DD 0 +M32BitMICounter8BitLow DW 0 +M32BitMICounter8BitHigh DW 0 +M32BitMICounter16BitLow DW 0 +M32BitMICounter16BitHigh DW 0 +ENDIF + + +; + +Proc M32Bit16MFPanned + +; AX = number to mix +; CX = error +; DX = deltaoffset +; BP = deltaerror +; DS:SI = 32-bit output buffer +; ES:EDI+EDI = sample location +; MM6 = L/R volumes +; MM7 = PXor mask + +IF MONITORPERFORMANCE + Push EAX + Push EDX + + Add CS:M32BitMICounter16BitLow, AX + AdC CS:M32BitMICounter16BitHigh, 0 + + RdTSC + Sub CS:M32BitMICounter16BitTicksLow, EAX + SBB CS:M32BitMICounter16BitTicksHigh, EDX + + Pop EDX + Pop EAX +ENDIF + +; 16 bit code here + Assume DS:Driver + SegCS MovQ MM2, M32BitMIPNotMask ; = FFFF0000FFFF0000h + Assume DS:Nothing + + Test AX, 1 + JZ M32Bit16MFPanned1 + + Push AX + MovD MM1, CX + + Mov EBX, [ES:EDI+EDI] + Add CX, BP + AdC DI, DX + PUnpckLWD MM1, MM1 + + MovD MM0, BX + PXor MM1, MM2 + + MovQ MM3, [DS:10h] + PSRLWI MM1, 1 + + PMAddWD MM0, MM1 + PMAddWD MM3, [DS:8] + + PSRADI MM0, 16 + MovQ MM1, MM3 + + PMAddWD MM0, [DS:0] + PSRLQI MM3, 32 + + PAddD MM3, MM1 + PAddD MM0, MM3 + PSRADI MM0, 14 + PUnpckLDQ MM0, MM0 + PackSSDW MM0, MM0 + + MovDR AX, MM0 + MovQ MM1, MM6 + PMulLW MM1, MM0 + PMulHW MM0, MM6 + + Mov BX, [DS:10h] + Mov [DS:10h], AX + Mov [DS:14h], BX + + MovQ MM3, [DS:18h] ; VR + PUnpckLWD MM1, MM0 + PSubW MM3, MM6 ; VR + PAddD MM1, [SI] + PSRAWI MM3, RAMPSPEED ; VR + MovQM [SI], MM1 + PAddW MM6, MM3 ; VR + + Add SI, 8 + Pop AX + +M32Bit16MFPanned1: + ShR AX, 1 + JZ M32Bit16MFPannedEnd + + Mov [DS:38h], CX + Mov EBX, [ES:EDI+EDI] + Mov [DS:3Ah], CX + Add CX, BP + AdC DI, DX + Mov [DS:30h], EBX + + Mov [DS:3Ch], CX + Mov EBX, [ES:EDI+EDI] + Mov [DS:3Eh], CX + Add CX, BP + AdC DI, DX + Mov [DS:34h], EBX + + MovQ MM5, [DS:38h] + + Mov [DS:38h], BP + Mov [DS:3Ch], BP + Mov [DS:3Ah], BP + Mov [DS:3Eh], BP + + MovQ MM7, [DS:38h] + PXor MM5, MM2 ; MM5 = offsets. + PAddW MM7, MM7 + PXor MM7, MM2 + PSubW MM7, MM2 ; MM7 = offset step + + Dec AX + JZ M32Bit16MFPanned3 + + Mov [DS:20h], AX + +M32Bit16MFPanned2: + MovQ MM2, [DS:10h] + MovQ MM0, MM5 + + PMAddWD MM2, [DS:8] + PSRLWI MM0, 1 + + PMAddWD MM0, [DS:30h] + PAddW MM5, MM7 + + PSRADI MM0, 16 + MovQ MM1, MM2 + + PMAddWD MM0, [DS:0] + PSRLQI MM2, 32 + + Mov EBX, [ES:EDI+EDI] + Add CX, BP + AdC DI, DX + Mov [DS:30h], EBX + + PAddD MM2, MM1 + MovQ MM3, MM0 + + PAddD MM0, MM2 + + PSRADI MM0, 14 + + MovQ MM1, MM0 + PackSSDW MM0, MM0 + + MovDR AX, MM0 + + Mov BX, [DS:10h] + Mov [DS:14h], BX + Mov [DS:10h], AX + + MovQ MM2, [DS:8] + PUnpckLDQ MM1, MM1 + + PMAddWD MM2, [DS:10h] + + Mov EBX, [ES:EDI+EDI] + Add CX, BP + AdC DI, DX + Mov [DS:34h], EBX + + PAddD MM3, MM2 + PSLLQI MM2, 32 + + PAddD MM3, MM2 ; MM3 = FS2, x + + PSRADI MM3, 14 + + PUnpckHDQ MM3, MM3 + MovQ MM0, MM6 + + PackSSDW MM3, MM1 ; MM3 = FS1, FS1, FS2, FS2 + + PMulLW MM0, MM3 + + MovDR AX, MM3 + PMulHW MM3, MM6 + + MovQ MM1, MM0 + + MovQ MM2, [DS:18h] ; VR + PUnpckHWD MM0, MM3 + + PAddD MM0, [SI] + PUnpckLWD MM1, MM3 + + PAddD MM1, [SI+8] + PSubW MM2, MM6 ; VR + + MovQM [SI], MM0 + PSRAWI MM2, RAMPSPEED-1 ; VR + + MovQM [SI+8], MM1 + PAddW MM6, MM2 ; VR + + Mov BX, [DS:10h] + Add SI, 10h + Mov [DS:10h], AX + Mov [DS:14h], BX + + Dec Word Ptr [DS:20h] + JNZ M32Bit16MFPanned2 + +M32Bit16MFPanned3: + MovQ MM0, [DS:30h] + PSRLWI MM5, 1 + + MovQ MM2, [DS:10h] + + PMAddWD MM0, MM5 + PMAddWD MM2, [DS:8] + + PSRADI MM0, 16 + MovQ MM1, MM2 + + PMAddWD MM0, [DS:0] + PSRLQI MM2, 32 + + PAddD MM2, MM1 + MovQ MM3, MM0 + + PAddD MM0, MM2 + + PSRADI MM0, 14 + + MovQ MM1, MM0 + PackSSDW MM0, MM0 + MovDR AX, MM0 + + Mov BX, [DS:10h] + Mov [DS:10h], AX + Mov [DS:14h], BX + + MovQ MM2, [DS:8] + PUnpckLDQ MM1, MM1 + + PMAddWD MM2, [DS:10h] + + PAddD MM3, MM2 + PSLLQI MM2, 32 + + PAddD MM3, MM2 ; MM3 = FS2, x + + PSRADI MM3, 14 + + PUnpckHDQ MM3, MM3 + MovQ MM0, MM6 + + PackSSDW MM3, MM1 ; MM3 = FS1, FS1, FS2, FS2 + + PMulLW MM0, MM3 + + MovDR AX, MM3 + PMulHW MM3, MM6 + + MovQ MM1, MM0 + + MovQ MM2, [DS:18h] ; VR + PUnpckHWD MM0, MM3 + + PAddD MM0, [SI] + PUnpckLWD MM1, MM3 + + PAddD MM1, [SI+8] + PSubW MM2, MM6 ; VR + + MovQM [SI], MM0 + PSRAWI MM2, RAMPSPEED-1 ; VR + + MovQM [SI+8], MM1 + PAddW MM6, MM2 ; VR + + Mov BX, [DS:10h] + Add SI, 10h + Mov [DS:10h], AX + Mov [DS:14h], BX + +M32Bit16MFPannedEnd: +IF MONITORPERFORMANCE + RdTSC + Add CS:M32BitMICounter16BitTicksLow, EAX + AdC CS:M32BitMICounter16BitTicksHigh, EDX +ENDIF + Ret + +EndP M32Bit16MFPanned + +; + +Proc M32Bit8MFPanned + +; Layout of data in data segment +; DS:0 = destination volume +; DS:10h->1Fh = samples +; DS:20h = SS, SP storage + +; AX = number to mix +; CX = error +; DX = deltaoffset +; BP = deltaerror +; DS:SI = 32-bit output buffer +; ES:DI = sample location +; MM6 = L/R volumes +; MM7 = PXor mask + +IF MONITORPERFORMANCE + Push EAX + Push EDX + + Add CS:M32BitMICounter8BitLow, AX + AdC CS:M32BitMICounter8BitHigh, 0 + + RdTSC + Sub CS:M32BitMICounter8BitTicksLow, EAX + SBB CS:M32BitMICounter8BitTicksHigh, EDX + + Pop EDX + Pop EAX +ENDIF + +; AX = number of samples to mix. +; MM6 = current volume. +; DS:0 = filtera +; DS:8 = filterb, filterc +; DS:10h = oldsamples. +; DS:18h = destination volume. +; DS:20h = Count +; DS:24h = ... +; DS:30h = sample area, 38h = offset area + + Assume DS:Driver + SegCS MovQ MM2, M32BitMIPNotMask ; = FFFF0000FFFF0000h + Assume DS:Nothing + + Test AX, 1 + JZ M32Bit8MFPanned1 + + MovD MM1, CX + Push AX + + Mov BX, [ES:DI] + Add CX, BP + AdC DI, DX + + MovD MM0, BX + PUnpckLWD MM1, MM1 + + PUnpckLBW MM0, MM0 + PXor MM1, MM2 + + MovQ MM3, [DS:10h] + PSRLWI MM1, 1 + + PMAddWD MM0, MM1 + PMAddWD MM3, [DS:8] + + PSRADI MM0, 16 + MovQ MM1, MM3 + + PMAddWD MM0, [DS:0] + PSRLQI MM3, 32 + + PAddD MM3, MM1 + PAddD MM0, MM3 + PSRADI MM0, 14 + PUnpckLDQ MM0, MM0 + PackSSDW MM0, MM0 + + MovDR AX, MM0 + MovQ MM1, MM6 + PMulLW MM1, MM0 + PMulHW MM0, MM6 + + Mov BX, [DS:10h] + Mov [DS:14h], BX + Mov [DS:10h], AX + + MovQ MM3, [DS:18h] ; VR + PUnpckLWD MM1, MM0 + PSubW MM3, MM6 ; VR + PAddD MM1, [SI] + PSRAWI MM3, RAMPSPEED ; VR + MovQM [SI], MM1 + PAddW MM6, MM3 ; VR + + Pop AX + Add SI, 8 + +M32Bit8MFPanned1: + ShR AX, 1 + JZ M32Bit8MFPannedEnd + + Mov [DS:38h], CX + Mov BX, [ES:DI] + Mov [DS:3Ah], CX + Add CX, BP + AdC DI, DX + Mov [DS:30h], BX + + Mov [DS:3Ch], CX + Mov BX, [ES:DI] + Mov [DS:3Eh], CX + Add CX, BP + AdC DI, DX + Mov [DS:32h], BX + + MovD MM7, BP + MovQ MM5, [DS:38h] + PUnpckLWD MM7, MM7 + PXor MM5, MM2 ; MM5 = offsets. + PUnpckLDQ MM7, MM7 + PAddW MM7, MM7 + PXor MM7, MM2 + PSubW MM7, MM2 ; MM7 = offset step + + Dec AX + JZ M32Bit8MFPanned3 + + Mov [DS:20h], AX + +M32Bit8MFPanned2: + MovD MM0, [DS:30h] + MovQ MM1, MM5 + + PUnpckLBW MM0, MM0 + PSRLWI MM1, 1 + + MovQ MM2, [DS:10h] + PMAddWD MM0, MM1 + + PMAddWD MM2, [DS:8] + PAddW MM5, MM7 + + MovQ MM1, MM2 + PSRADI MM0, 16 + + PMAddWD MM0, [DS:0] + PSRLQI MM2, 32 + + Mov BX, [ES:DI] + Add CX, BP + AdC DI, DX + Mov [DS:30h], BX + + PAddD MM2, MM1 + MovQ MM3, MM0 + + PAddD MM0, MM2 + + PSRADI MM0, 14 + + MovQ MM1, MM0 + PackSSDW MM0, MM0 + + MovDR AX, MM0 + + Mov BX, [DS:10h] + Mov [DS:10h], AX + Mov [DS:14h], BX + + MovQ MM2, [DS:8] + PUnpckLDQ MM1, MM1 + + PMAddWD MM2, [DS:10h] + + Mov BX, [ES:DI] + Add CX, BP + AdC DI, DX + Mov [DS:32h], BX + + PAddD MM3, MM2 + PSLLQI MM2, 32 + + PAddD MM3, MM2 ; MM3 = FS2, x + + PSRADI MM3, 14 + + PUnpckHDQ MM3, MM3 + MovQ MM0, MM6 + + PackSSDW MM3, MM1 ; MM3 = FS1, FS1, FS2, FS2 + + PMulLW MM0, MM3 + + MovDR AX, MM3 + PMulHW MM3, MM6 + + MovQ MM1, MM0 + + MovQ MM2, [DS:18h] ; VR + PUnpckHWD MM0, MM3 + + PAddD MM0, [SI] + PUnpckLWD MM1, MM3 + + PAddD MM1, [SI+8] + PSubW MM2, MM6 ; VR + + MovQM [SI], MM0 + PSRAWI MM2, RAMPSPEED-1 ; VR + + MovQM [SI+8], MM1 + PAddW MM6, MM2 ; VR + + Mov BX, [DS:10h] + Add SI, 10h + Mov [DS:10h], AX + Mov [DS:14h], BX + + Dec Word Ptr [DS:20h] + JNZ M32Bit8MFPanned2 + +M32Bit8MFPanned3: + MovD MM0, [DS:30h] + PSRLWI MM5, 1 + + MovQ MM2, [DS:10h] + PUnpckLBW MM0, MM0 + + PMAddWD MM0, MM5 + PMAddWD MM2, [DS:8] + + PSRADI MM0, 16 + MovQ MM1, MM2 + + PMAddWD MM0, [DS:0] + PSRLQI MM2, 32 + + PAddD MM2, MM1 + MovQ MM3, MM0 + + PAddD MM0, MM2 + + PSRADI MM0, 14 + + MovQ MM1, MM0 + PackSSDW MM0, MM0 + MovDR AX, MM0 + + Mov BX, [DS:10h] + Mov [DS:14h], BX + Mov [DS:10h], AX + + MovQ MM2, [DS:8] + PUnpckLDQ MM1, MM1 + + PMAddWD MM2, [DS:10h] + + PAddD MM3, MM2 + PSLLQI MM2, 32 + + PAddD MM3, MM2 ; MM3 = FS2, x + + PSRADI MM3, 14 + + PUnpckHDQ MM3, MM3 + MovQ MM0, MM6 + + PackSSDW MM3, MM1 ; MM3 = FS1, FS1, FS2, FS2 + + PMulLW MM0, MM3 + + MovDR AX, MM3 + PMulHW MM3, MM6 + + MovQ MM1, MM0 + + MovQ MM2, [DS:18h] ; VR + PUnpckHWD MM0, MM3 + + PAddD MM0, [SI] + PUnpckLWD MM1, MM3 + + PAddD MM1, [SI+8] + PSubW MM2, MM6 ; VR + + MovQM [SI], MM0 + PSRAWI MM2, RAMPSPEED-1 ; VR + + MovQM [SI+8], MM1 + PAddW MM6, MM2 ; VR + + Mov BX, [DS:10h] + Add SI, 10h + Mov [DS:10h], AX + Mov [DS:14h], BX + +M32Bit8MFPannedEnd: +IF MONITORPERFORMANCE + RdTSC + Add CS:M32BitMICounter8BitTicksLow, EAX + AdC CS:M32BitMICounter8BitTicksHigh, EDX +ENDIF + Ret + +EndP M32Bit8MFPanned + +; + +Proc PreM32BitMFPanned + Assume DS:Driver + + Mov ES, CS:MixSegment + + Mov AX, [SI+0Ch] ; AX = destination left + Mov BX, [SI+1Ch] ; BX = current left + Mov CX, [SI+0Eh] ; CX = destination right + Mov DX, [SI+1Eh] ; DX = current right. + + Test Word Ptr [SI], 8540h + JZ PreM32BitMFPannedV4 + + Add CX, CX + Add AX, AX + +PreM32BitMFPannedV4: + Test AX, AX + JNZ PreM32BitMFPannedV3 + Test CX, CX + JNZ PreM32BitMFPannedV3 + + Add Word Ptr [SI+8], 60 + +PreM32BitMFPannedV3: + Cmp AX, BX + JL PreM32BitMFPannedV1 + + Add AX, RAMPCOMPENSATE + +PreM32BitMFPannedV1: + Cmp CX, DX + JL PreM32BitMFPannedV2 + + Add CX, RAMPCOMPENSATE + +PreM32BitMFPannedV2: + Mov [ES:18h], AX + Mov [ES:1Ch], AX + Mov [ES:1Ah], CX + Mov [ES:1Eh], CX ; MixSegment:18h = destination volume + + Mov [CS:M32BitMIVolumeData], BX + Mov [CS:M32BitMIVolumeData+2], DX + Sub AX, BX + Sub CX, DX + SAR AX, RAMPSPEED + SAR CX, RAMPSPEED + Add BX, AX + Add DX, CX + Mov [CS:M32BitMIVolumeData+4], BX + Mov [CS:M32BitMIVolumeData+6], DX + SegCS MovQ MM6, M32BitMIVolumeData ; MM6 = current volume + + Xor EAX, EAX + Mov AX, [SI+5Eh] + Sub AX, 1 + AdC AX, 1 + Mov [ES:0], EAX + Mov [ES:4], EAX ; MixSegment:0 = filtera + + Mov AX, [SI+6Eh] + Mov [ES:8], EAX + Mov AX, [SI+7Eh] + Mov [ES:0Ch], EAX ; MixSegment:8 = filterb, filterc + + Mov AX, [SI+3Ch] + Mov [ES:10h], EAX + Mov AX, [SI+6] + Mov [ES:14h], EAX ; MixSegment:10h = old samples. + + Ret + +EndP PreM32BitMFPanned + Assume DS:Nothing + +; + diff --git a/it/SoundDrivers/M32BITMI.INC b/it/SoundDrivers/M32BITMI.INC new file mode 100755 index 0000000..799880e --- /dev/null +++ b/it/SoundDrivers/M32BITMI.INC @@ -0,0 +1,11 @@ +; 8 bit tables + + DW Offset MixNoLoop, PreM32BitMIPanned, MFS8Bit, MBS8Bit, M32Bit8MIPanned + DW Offset MixForwardsLoop, PreM32BitMIPanned, MFS8Bit, MBS8Bit, M32Bit8MIPanned + DW Offset MixPingPongLoop, PreM32BitMIPanned, MFS8Bit, MBS8Bit, M32Bit8MIPanned + +; 16 bit tables + DW Offset MixNoLoop, PreM32BitMIPanned, MFS16Bit, MBS16Bit, M32Bit16MIPanned + DW Offset MixForwardsLoop, PreM32BitMIPanned, MFS16Bit, MBS16Bit, M32Bit16MIPanned + DW Offset MixPingPongLoop, PreM32BitMIPanned, MFS16Bit, MBS16Bit, M32Bit16MIPanned + diff --git a/it/SoundDrivers/M32BITMI.MIX b/it/SoundDrivers/M32BITMI.MIX new file mode 100755 index 0000000..3bf0fde --- /dev/null +++ b/it/SoundDrivers/M32BITMI.MIX @@ -0,0 +1,686 @@ + +; + +MONITORPERFORMANCE = 0 + +ALIGN 16 + +M32BitMIVolumeData DW 0, 0, 0, 0 +M32BitMIPXorMask DW 07FFFh, 0, 07FFFh, 0 +M32BitMIPNotMask DW 0FFFFh, 0, 0FFFFh, 0 + +IF MONITORPERFORMANCE +M32BitMICounter8BitTicksLow DD 0 +M32BitMICounter8BitTicksHigh DD 0 +M32BitMICounter16BitTicksLow DD 0 +M32BitMICounter16BitTicksHigh DD 0 +M32BitMICounter8BitLow DW 0 +M32BitMICounter8BitHigh DW 0 +M32BitMICounter16BitLow DW 0 +M32BitMICounter16BitHigh DW 0 +ENDIF + + +; + +Proc M32Bit16MIPanned + +; AX = number to mix +; CX = error +; DX = deltaoffset +; BP = deltaerror +; DS:SI = 32-bit output buffer +; ES:EDI+EDI = sample location +; MM6 = L/R volumes +; MM7 = PXor mask + +IF MONITORPERFORMANCE + Push EAX + Push EDX + + Add CS:M32BitMICounter16BitLow, AX + AdC CS:M32BitMICounter16BitHigh, 0 + + RdTSC + Sub CS:M32BitMICounter16BitTicksLow, EAX + SBB CS:M32BitMICounter16BitTicksHigh, EDX + + Pop EDX + Pop EAX +ENDIF + + Mov BX, DI + Add BX, BX + + Assume DS:Driver + SegCS MovQ MM3, M32BitMIPXorMask + Assume DS:Nothing + +M32Bit16MIPanned1: + Test AL, 1 + JZ M32Bit16MIPanned2 + + Push AX + Mov [DS:10h], CX + Mov AX, [ES:BX] + Mov [DS:12h], CX + Add CX, BP + AdC DI, DX + Mov [DS:0], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:2], AX + Add BX, BX + + MovQ MM4, [DS:10h] + MovQ MM2, MM6 + MovQ MM0, [DS:0] + PSRLWI MM4, 1 + PXor MM4, MM3 + PMAddWD MM0, MM4 + PSRADI MM0, 15 + PUnpckLWD MM0, MM0 + PMulLW MM2, MM0 + PMulHW MM0, MM6 + PUnpckLWD MM2, MM0 + PAddD MM2, [SI] + MovQM [SI], MM2 + + Add SI, 8 + Pop AX + +M32Bit16MIPanned2: + Test AL, 2 + JZ M32Bit16MIPanned3 + + Push AX + Mov [DS:10h], CX + Mov AX, [ES:BX] + Mov [DS:12h], CX + Add CX, BP + AdC DI, DX + Mov [DS:0], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:2], AX + Add BX, BX + + Mov [DS:14h], CX + Mov AX, [ES:BX] + Mov [DS:16h], CX + Add CX, BP + AdC DI, DX + Mov [DS:4], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:6], AX + Add BX, BX + + MovQ MM4, [DS:10h] + MovQ MM2, MM6 + MovQ MM0, [DS:0] + PSRLWI MM4, 1 + + PXor MM4, MM3 + + PMAddWD MM0, MM4 + PSRADI MM0, 15 + PackSSDW MM0, MM0 + PUnpckLWD MM0, MM0 + PMulLW MM2, MM0 + PMulHW MM0, MM6 + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + PAddD MM2, [SI] + PUnpckHWD MM4, MM0 + PAddD MM4, [SI+8] + MovQM [SI], MM2 + MovQM [SI+8], MM4 + + Add SI, 10h + Pop AX + +M32Bit16MIPanned3: + ShR AX, 2 + JZ M32Bit16MIPannedEnd + + Mov [DS:20h], AX + + Mov [DS:10h], CX ; AGIs everywhere! + Mov AX, [ES:BX] + Mov [DS:12h], CX + Add CX, BP + AdC DI, DX + Mov [DS:0], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:2], AX + Add BX, BX + + Mov [DS:14h], CX + Mov AX, [ES:BX] + Mov [DS:16h], CX + Add CX, BP + AdC DI, DX + Mov [DS:4], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:6], AX + Add BX, BX + + MovQ MM5, [DS:10h] + + Mov [DS:10h], BP + Mov [DS:14h], BP + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:8], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:0Ah], AX + Add BX, BX + + Mov [DS:12h], BP + Mov [DS:16h], BP + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:0Ch], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:0Eh], AX + Add BX, BX + + Assume DS:Driver + SegCS MovQ MM4, M32BitMIPNotMask + Assume DS:Nothing + + MovQ MM7, [DS:10h] + PXor MM5, MM4 + + PAddW MM7, MM7 + MovQ MM2, MM5 + + PXor MM7, MM4 + PSRLWI MM2, 1 + + PSubW MM7, MM4 + PAddW MM5, MM7 + MovQ MM3, MM5 + + Dec Word Ptr [DS:20h] + JZ M32Bit16MIPanned5 + +M32Bit16MIPanned4: ; MM7 = delta offsets. + PMAddWD MM2, [DS:0] + PSRLWI MM3, 1 + +; Stall (2) + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:0], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:2], AX + Add BX, BX + + PMAddWD MM3, [DS:8] + PSRADI MM2, 15 + + PackSSDW MM2, MM2 + PAddW MM5, MM7 + + PUnpckLWD MM2, MM2 + MovQ MM0, MM6 + + PMulHW MM0, MM2 + PSRADI MM3, 15 + + PMulLW MM2, MM6 + PackSSDW MM3, MM3 + + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:4], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:6], AX + Add BX, BX + +; Stall (1) + MovQ MM4, MM2 + PUnpckLWD MM3, MM3 + + PUnpckLWD MM2, MM0 + MovQ MM1, MM6 + + PMulHW MM1, MM3 + PUnpckHWD MM4, MM0 + + PAddD MM2, [SI] + PMulLW MM3, MM6 + + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:8], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:0Ah], AX + Add BX, BX + +; Stall (1) + PAddD MM4, [SI+8] + MovQ MM0, MM3 ; + + MovQM [SI], MM2 + PUnpckLWD MM3, MM1 + + MovQM [SI+8], MM4 + PUnpckHWD MM0, MM1 + + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:0Ch], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:0Eh], AX + Add BX, BX + + PAddD MM3, [SI+10h] + MovQ MM2, MM5 + + PAddD MM0, [SI+18h] + PAddW MM5, MM7 + + MovQM [SI+10h], MM3 + MovQ MM3, MM5 + + MovQM [SI+18h], MM0 + PSRLWI MM2, 1 + + Add SI, 20h + Dec Word Ptr [DS:20h] + JNZ M32Bit16MIPanned4 + +M32Bit16MIPanned5: + PMAddWD MM2, [DS:0] + PSRLWI MM3, 1 + + PMAddWD MM3, [DS:8] + PSRADI MM2, 15 + + PackSSDW MM2, MM2 + PAddW MM5, MM7 + + PUnpckLWD MM2, MM2 + MovQ MM0, MM6 + + PMulHW MM0, MM2 + PSRADI MM3, 15 + + PMulLW MM2, MM6 + PackSSDW MM3, MM3 + + MovQ MM4, MM2 + PUnpckLWD MM3, MM3 + + PUnpckLWD MM2, MM0 + MovQ MM1, MM6 + + PMulHW MM1, MM3 + PUnpckHWD MM4, MM0 + + PAddD MM2, [SI] + PMulLW MM3, MM6 + + PAddD MM4, [SI+8] + MovQ MM0, MM3 + + MovQM [SI], MM2 + PUnpckLWD MM3, MM1 + + MovQM [SI+8], MM4 + PUnpckHWD MM0, MM1 + + PAddD MM3, [SI+10h] + PAddD MM0, [SI+18h] + MovQM [SI+10h], MM3 + MovQM [SI+18h], MM0 + +M32Bit16MIPannedEnd: +IF MONITORPERFORMANCE + RdTSC + Add CS:M32BitMICounter16BitTicksLow, EAX + AdC CS:M32BitMICounter16BitTicksHigh, EDX +ENDIF + Ret + +EndP M32Bit16MIPanned + +; + +Proc M32Bit8MIPanned + +; AX = number to mix +; CX = error +; DX = deltaoffset +; BP = deltaerror +; DS:SI = 32-bit output buffer +; ES:DI = sample location +; MM6 = L/R volumes +; MM7 = PXor mask + +IF MONITORPERFORMANCE + Push EAX + Push EDX + + Add CS:M32BitMICounter8BitLow, AX + AdC CS:M32BitMICounter8BitHigh, 0 + + RdTSC + Sub CS:M32BitMICounter8BitTicksLow, EAX + SBB CS:M32BitMICounter8BitTicksHigh, EDX + + Pop EDX + Pop EAX +ENDIF + + Mov BX, AX + + And AX, 3 + JZ M32Bit8MIPanned3 + + Assume DS:Driver + SegCS MovQ MM3, M32BitMIPXorMask + Assume DS:Nothing + +M32Bit8MIPanned1: + Test AL, 1 + JZ M32Bit8MIPanned2 + + Mov AX, [ES:DI] + Mov [DS:10h], CX + Mov [DS:12h], CX + Add CX, BP + AdC DI, DX + + MovQ MM4, [DS:10h] + MovQ MM2, MM6 + MovD MM0, AX + PSRLWI MM4, 1 + PXor MM4, MM3 + PUnpckLBW MM0, MM0 + PMAddWD MM0, MM4 + PSRADI MM0, 15 + PUnpckLWD MM0, MM0 + PMulLW MM2, MM0 + PMulHW MM0, MM6 + PUnpckLWD MM2, MM0 + PAddD MM2, [SI] + MovQM [SI], MM2 + + Add SI, 8 + +M32Bit8MIPanned2: ; Mix 2 samples + Test BL, 2 + JZ M32Bit8MIPanned3 + + Mov AX, [ES:DI] + Mov [DS:10h], CX + Mov [DS:12h], CX + Add CX, BP + AdC DI, DX + Mov [DS:0], AX + + Mov AX, [ES:DI] + Mov [DS:14h], CX + Mov [DS:16h], CX + Add CX, BP + AdC DI, DX + Mov [DS:2], AX + + MovQ MM4, [DS:10h] + MovQ MM2, MM6 + MovQ MM0, [DS:0] + PSRLWI MM4, 1 + + PUnpckLBW MM0, MM0 + PXor MM4, MM3 + + PMAddWD MM0, MM4 + PSRADI MM0, 15 + PackSSDW MM0, MM0 + PUnpckLWD MM0, MM0 + PMulLW MM2, MM0 + PMulHW MM0, MM6 + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + PAddD MM2, [SI] + PUnpckHWD MM4, MM0 + PAddD MM4, [SI+8] + MovQM [SI], MM2 + MovQM [SI+8], MM4 + + Add SI, 10h + +M32Bit8MIPanned3: + ShR BX, 2 + JZ M32Bit8MIPannedEnd + +; Have to setup offset register and delta-offset register. + + Mov AX, [ES:DI] + Mov [DS:10h], ERROR + Mov [DS:12h], ERROR + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0], AX + + Mov AX, [ES:DI] + Mov [DS:14h], ERROR + Mov [DS:16h], ERROR + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:2], AX + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:18h], DELTAERROR + Mov [DS:8h], AX + Mov [DS:1Ah], DELTAERROR + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:1Ch], DELTAERROR + Mov [DS:0Ah], AX + Mov [DS:1Eh], DELTAERROR + + Assume DS:Driver + SegCS MovQ MM4, M32BitMIPNotMask + Assume DS:Nothing + + MovQ MM7, [DS:18h] + MovQ MM5, [DS:10h] + + PAddW MM7, MM7 + + PXor MM7, MM4 + PXor MM5, MM4 + + PSubW MM7, MM4 + + Dec BX + JZ M32Bit8MIPanned5 + +M32Bit8MIPanned4: + MovQ MM0, [DS:0] + MovQ MM2, MM5 + + MovQ MM1, [DS:8] + PUnpckLBW MM0, MM0 + + PAddW MM5, MM7 + PSRLWI MM2, 1 + + PMAddWD MM0, MM2 + PUnpckLBW MM1, MM1 + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0], AX + + PSRADI MM0, 15 + MovQ MM3, MM5 + + PAddW MM5, MM7 + PSRLWI MM3, 1 + + PMAddWD MM1, MM3 + PackSSDW MM0, MM0 + + MovQ MM2, MM6 + PUnpckLWD MM0, MM0 + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:2], AX + + PMulLW MM2, MM0 + PSRADI MM1, 15 + + PMulHW MM0, MM6 + PackSSDW MM1, MM1 + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + + MovQ MM4, MM2 + PUnpckLWD MM1, MM1 + + AdC DI, DELTAOFFSET + Mov [DS:8], AX + + MovQ MM3, MM6 + PUnpckLWD MM2, MM0 + + PAddD MM2, [SI] + PMulLW MM3, MM1 + + PMulHW MM1, MM6 + PUnpckHWD MM4, MM0 + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:0Ah], AX + + PAddD MM4, [SI+8] + MovQ MM0, MM3 + + MovQM [SI], MM2 + PUnpckLWD MM3, MM1 + + MovQM [SI+8], MM4 + PUnpckHWD MM0, MM1 + + PAddD MM3, [SI+10h] + PAddD MM0, [SI+18h] + + MovQM [SI+10h], MM3 + MovQM [SI+18h], MM0 + + Add SI, 20h + + Dec BX + JNZ M32Bit8MIPanned4 + +M32Bit8MIPanned5: + MovQ MM0, [DS:0] + MovQ MM2, MM5 + MovQ MM1, [DS:8] + PUnpckLBW MM0, MM0 + PAddW MM5, MM7 + PSRLWI MM2, 1 + + PMAddWD MM0, MM2 + PUnpckLBW MM1, MM1 + + PSRLWI MM5, 1 + + PMAddWD MM1, MM5 + PSRADI MM0, 15 + + MovQ MM2, MM6 + PackSSDW MM0, MM0 + + MovQ MM3, MM6 + PUnpckLWD MM0, MM0 + + PMulLW MM2, MM0 + PSRADI MM1, 15 + + PMulHW MM0, MM6 + PackSSDW MM1, MM1 + + PUnpckLWD MM1, MM1 + MovQ MM4, MM2 + + PMulLW MM3, MM1 + PUnpckLWD MM2, MM0 + + PMulHW MM1, MM6 + PUnpckHWD MM4, MM0 + + PAddD MM2, [SI] + MovQ MM5, MM3 + + PAddD MM4, [SI+8] + PUnpckLWD MM3, MM1 + + MovQM [SI], MM2 + PUnpckHWD MM5, MM1 + + PAddD MM3, [SI+10h] + PAddD MM5, [SI+18h] + + MovQM [SI+8], MM4 + MovQM [SI+10h], MM3 + MovQM [SI+18h], MM5 + +M32Bit8MIPannedEnd: +IF MONITORPERFORMANCE + RdTSC + Add CS:M32BitMICounter8BitTicksLow, EAX + AdC CS:M32BitMICounter8BitTicksHigh, EDX +ENDIF + Ret + +EndP M32Bit8MIPanned + +; + +Proc PreM32BitMIPanned + Assume DS:Driver + + Mov EAX, [SI+0Ch] ; LEAX = left vol, HEAX = right vol + Mov [DWord Ptr CS:M32BitMIVolumeData], EAX + Mov [DWord Ptr CS:M32BitMIVolumeData+4], EAX + + SegCS MovQ MM6, M32BitMIVolumeData + + Ret + +EndP PreM32BitMIPanned + Assume DS:Nothing + +; + diff --git a/it/SoundDrivers/M32BITMV.INC b/it/SoundDrivers/M32BITMV.INC new file mode 100755 index 0000000..2ae7a0f --- /dev/null +++ b/it/SoundDrivers/M32BITMV.INC @@ -0,0 +1,12 @@ +; 8 bit tables + + DW Offset MixNoLoop, PreM32BitMVPanned, MFS8Bit, MBS8Bit, M32Bit8MVPanned + DW Offset MixForwardsLoop, PreM32BitMVPanned, MFS8Bit, MBS8Bit, M32Bit8MVPanned + DW Offset MixPingPongLoop, PreM32BitMVPanned, MFS8Bit, MBS8Bit, M32Bit8MVPanned + +; 16 bit tables + + DW Offset MixNoLoop, PreM32BitMVPanned, MFS16Bit, MBS16Bit, M32Bit16MVPanned + DW Offset MixForwardsLoop, PreM32BitMVPanned, MFS16Bit, MBS16Bit, M32Bit16MVPanned + DW Offset MixPingPongLoop, PreM32BitMVPanned, MFS16Bit, MBS16Bit, M32Bit16MVPanned + diff --git a/it/SoundDrivers/M32BITMV.MIX b/it/SoundDrivers/M32BITMV.MIX new file mode 100755 index 0000000..2334538 --- /dev/null +++ b/it/SoundDrivers/M32BITMV.MIX @@ -0,0 +1,798 @@ + +; + +MONITORPERFORMANCE = 0 +RAMPSPEED = 7 +RAMPCOMPENSATE = 63 + +IF MONITORPERFORMANCE +ALIGN 16 +M32BitMICounter8BitTicksLow DD 0 +M32BitMICounter8BitTicksHigh DD 0 +M32BitMICounter16BitTicksLow DD 0 +M32BitMICounter16BitTicksHigh DD 0 +M32BitMICounter8BitLow DW 0 +M32BitMICounter8BitHigh DW 0 +M32BitMICounter16BitLow DW 0 +M32BitMICounter16BitHigh DW 0 +ENDIF + + +; + +Proc M32Bit16MVPanned + +; AX = number to mix +; CX = error +; DX = deltaoffset +; BP = deltaerror +; DS:SI = 32-bit output buffer +; ES:EDI+EDI = sample location +; MM6 = L/R volumes +; MM7 = PXor mask + +IF MONITORPERFORMANCE + Push EAX + Push EDX + + Add CS:M32BitMICounter16BitLow, AX + AdC CS:M32BitMICounter16BitHigh, 0 + + RdTSC + Sub CS:M32BitMICounter16BitTicksLow, EAX + SBB CS:M32BitMICounter16BitTicksHigh, EDX + + Pop EDX + Pop EAX +ENDIF + +; 16 bit code here + + Mov BX, DI + + Assume DS:Driver + SegCS MovQ MM1, M32BitMIPNotMask ; = FFFF0000FFFF0000h + Assume DS:Nothing + + Add BX, BX + + Test AL, 1 + JZ M32Bit16MVPanned2 + + Push AX + Mov [DS:8h], CX ; AGIs everywhere! + Mov AX, [ES:BX] + Mov [DS:0Ah], CX + Add CX, BP + AdC DI, DX + Mov [DS:10h], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:12h], AX + Add BX, BX + + MovQ MM0, [DS:8h] + MovQ MM2, MM6 + PXor MM0, MM1 + PSRLWI MM0, 1 + PMAddWD MM0, [DS:10h] + PSRADI MM0, 15 + PUnpckLWD MM0, MM0 + PMulLW MM2, MM0 + MovQ MM4, [DS:0] ; VR + PMulHW MM0, MM6 + PSubW MM4, MM6 ; VR + PUnpckLWD MM2, MM0 + PAddD MM2, [SI] + PSRAWI MM4, RAMPSPEED ; VR + MovQM [SI], MM2 + PAddW MM6, MM4 ; VR + + Add SI, 8 + Pop AX + +M32Bit16MVPanned2: + Test AX, 2 + JZ M32Bit16MVPanned3 + + Push AX + Mov [DS:8h], CX ; AGIs everywhere! + Mov AX, [ES:BX] + Mov [DS:0Ah], CX + Add CX, BP + AdC DI, DX + Mov [DS:10h], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:12h], AX + Add BX, BX + + Mov [DS:0Ch], CX + Mov AX, [ES:BX] + Mov [DS:0Eh], CX + Add CX, BP + AdC DI, DX + Mov [DS:14h], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:16h], AX + Add BX, BX + + MovQ MM2, [DS:8] + PXor MM2, MM1 + PSRLWI MM2, 1 + PMAddWD MM2, [DS:10h] + PSRADI MM2, 15 + PackSSDW MM2, MM2 + PUnpckLWD MM2, MM2 + MovQ MM0, MM6 + PMulHW MM0, MM2 + PMulLW MM2, MM6 + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + MovQ MM5, [DS:0] ; VR + PUnpckHWD MM4, MM0 + PAddD MM2, [SI] + PSubW MM5, MM6 ; VR + PAddD MM4, [SI+8] + MovQM [SI], MM2 + PSRAWI MM5, RAMPSPEED-1 ; VR + MovQM [SI+8], MM4 + PAddW MM6, MM5 ; VR + + Pop AX + Add SI, 10h + +M32Bit16MVPanned3: + ShR AX, 2 + JZ M32Bit16MVPannedEnd + + Mov Word Ptr [DS:20h], AX + + Mov [DS:8h], CX ; AGIs everywhere! + Mov AX, [ES:BX] + Mov [DS:0Ah], CX + Add CX, BP + AdC DI, DX + Mov [DS:10h], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:12h], AX + Add BX, BX + + Mov [DS:0Ch], CX + Mov AX, [ES:BX] + Mov [DS:0Eh], CX + Add CX, BP + AdC DI, DX + Mov [DS:14h], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:16h], AX + Add BX, BX + + Mov [DS:28h], BP + Mov [DS:2Ch], BP + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:18h], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:1Ah], AX + Add BX, BX + + Mov [DS:2Ah], BP + Mov [DS:2Eh], BP + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:1Ch], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:1Eh], AX + Add BX, BX + + MovQ MM7, [DS:28h] + + MovQ MM5, [DS:8] + PAddW MM7, MM7 + + PXor MM7, MM1 + PXor MM5, MM1 + + PSubW MM7, MM1 + + Dec Word Ptr [DS:20h] + JZ M32Bit16MVPanned5 + +M32Bit16MVPanned4: +; DS:0 = destination volume +; DS:10h = samples +; DS:18h = samples +; MM5 = offsets +; MM6 = current volume +; MM7 = delta offsets + MovQ MM2, MM5 + PAddW MM5, MM7 + + PSRLWI MM2, 1 + MovQ MM3, MM5 + + PMAddWD MM2, [DS:10h] + PSRLWI MM3, 1 + + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:10h], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:12h], AX + Add BX, BX + + PSRADI MM2, 15 + PAddW MM5, MM7 + + PMAddWD MM3, [DS:18h] + PackSSDW MM2, MM2 + + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:14h], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:16h], AX + Add BX, BX + + PUnpckLWD MM2, MM2 + MovQ MM0, MM6 + + PMulHW MM0, MM2 + PSRADI MM3, 15 + + PMulLW MM2, MM6 + PackSSDW MM3, MM3 + + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:18h], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:1Ah], AX + Add BX, BX + + MovQ MM1, [DS:0] ; Destination volume + PUnpckLWD MM3, MM3 + + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + + PSubW MM1, MM6 + PUnpckHWD MM4, MM0 + + PAddD MM2, [SI] + PSRAWI MM1, RAMPSPEED-1 + + PAddD MM4, [SI+8] + PAddW MM6, MM1 ; MM6 = new volume (ramped) + + MovQM [SI], MM2 + MovQ MM1, MM6 + + MovQ MM2, [DS:0] + PMulHW MM1, MM3 + + MovQM [SI+8], MM4 + PMulLW MM3, MM6 + + Add CX, BP + Mov AX, [ES:BX] + AdC DI, DX + Mov [DS:1Ch], AX + Mov AX, [ES:BX+2] + Mov BX, DI + Mov [DS:1Eh], AX + Add BX, BX + + MovQ MM0, MM3 + PUnpckLWD MM3, MM1 + + PAddD MM3, [SI+10h] + PUnpckHWD MM0, MM1 + + MovQM [SI+10h], MM3 + PSubW MM2, MM6 + + PAddD MM0, [SI+18h] + PSRAWI MM2, RAMPSPEED-1 + + MovQM [SI+18h], MM0 + PAddW MM6, MM2 + + Add SI, 20h + + Dec Word Ptr [DS:20h] + JNZ M32Bit16MVPanned4 + +M32Bit16MVPanned5: + MovQ MM2, MM5 + PAddW MM5, MM7 + + PSRLWI MM2, 1 + MovQ MM3, MM5 + + PMAddWD MM2, [DS:10h] + PSRLWI MM3, 1 + + PSRADI MM2, 15 + PAddW MM5, MM7 + + PMAddWD MM3, [DS:18h] + PackSSDW MM2, MM2 + + PUnpckLWD MM2, MM2 + MovQ MM0, MM6 + + PMulHW MM0, MM2 + PSRADI MM3, 15 + + PMulLW MM2, MM6 + PackSSDW MM3, MM3 + + MovQ MM1, [DS:0] ; Destination volume + PUnpckLWD MM3, MM3 + + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + + PSubW MM1, MM6 + PUnpckHWD MM4, MM0 + + PAddD MM2, [SI] + PSRAWI MM1, RAMPSPEED-1 + + PAddD MM4, [SI+8] + PAddW MM6, MM1 ; MM6 = new volume (ramped) + + MovQM [SI], MM2 + MovQ MM1, MM6 + + MovQ MM2, [DS:0] + PMulHW MM1, MM3 + + MovQM [SI+8], MM4 + PMulLW MM3, MM6 + + MovQ MM0, MM3 + PUnpckLWD MM3, MM1 + + PAddD MM3, [SI+10h] + PUnpckHWD MM0, MM1 + + MovQM [SI+10h], MM3 + PSubW MM2, MM6 + + PAddD MM0, [SI+18h] + PSRAWI MM2, RAMPSPEED-1 + + MovQM [SI+18h], MM0 + PAddW MM6, MM2 + +M32Bit16MVPannedEnd: + +IF MONITORPERFORMANCE + RdTSC + Add CS:M32BitMICounter16BitTicksLow, EAX + AdC CS:M32BitMICounter16BitTicksHigh, EDX +ENDIF + Ret + +EndP M32Bit16MVPanned + +; + +Proc M32Bit8MVPanned + +; Layout of data in data segment +; DS:0 = destination volume +; DS:10h->1Fh = samples + +; AX = number to mix +; CX = error +; DX = deltaoffset +; BP = deltaerror +; DS:SI = 32-bit output buffer +; ES:DI = sample location +; MM6 = L/R volumes +; MM7 = PXor mask + +IF MONITORPERFORMANCE + Push EAX + Push EDX + + Add CS:M32BitMICounter8BitLow, AX + AdC CS:M32BitMICounter8BitHigh, 0 + + RdTSC + Sub CS:M32BitMICounter8BitTicksLow, EAX + SBB CS:M32BitMICounter8BitTicksHigh, EDX + + Pop EDX + Pop EAX +ENDIF + +; AX = number of samples to mix. +; DS:0 = destination volume +; DS:8 = SS +; DS:0Ch = SP +; DS:10h = sample setup +; MM6 = current volume. + + Mov BX, AX + + Assume DS:Driver + SegCS MovQ MM1, M32BitMIPNotMask ; = FFFF0000FFFF0000h + Assume DS:Nothing + + And AX, 3 + JZ M32Bit8MVPanned3 + +M32Bit8MVPanned1: + Test AL, 1 + JZ M32Bit8MVPanned2 + + Mov AX, [ES:DI] + Mov [DS:8h], CX + Mov [DS:0Ah], CX + Add CX, BP + AdC DI, DX + + MovQ MM4, [DS:8h] + MovQ MM2, MM6 + MovD MM0, AX + PXor MM4, MM1 + PSRLWI MM4, 1 + PUnpckLBW MM0, MM0 + PMAddWD MM0, MM4 + PSRADI MM0, 15 + PUnpckLWD MM0, MM0 + PMulLW MM2, MM0 + MovQ MM4, [DS:0] ; VR + PMulHW MM0, MM6 + PSubW MM4, MM6 ; VR + PUnpckLWD MM2, MM0 + PAddD MM2, [SI] + PSRAWI MM4, RAMPSPEED ; VR + MovQM [SI], MM2 + PAddW MM6, MM4 ; VR + + Add SI, 8 + +M32Bit8MVPanned2: + Test BL, 2 + JZ M32Bit8MVPanned3 + + Mov AX, [ES:DI] + Mov [DS:8h], CX + Mov [DS:0Ah], CX + Add CX, BP + AdC DI, DX + Mov [DS:10h], AX + + Mov AX, [ES:DI] + Mov [DS:0Ch], CX + Mov [DS:0Eh], CX + Add CX, BP + AdC DI, DX + Mov [DS:12h], AX + + MovQ MM0, [DS:10h] + MovQ MM2, [DS:8] + PXor MM2, MM1 + PUnpckLBW MM0, MM0 + PSRLWI MM2, 1 + PMAddWD MM2, MM0 + PSRADI MM2, 15 + PackSSDW MM2, MM2 + PUnpckLWD MM2, MM2 + MovQ MM0, MM6 + PMulHW MM0, MM2 + PMulLW MM2, MM6 + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + MovQ MM5, [DS:0] ; VR + PUnpckHWD MM4, MM0 + PAddD MM2, [SI] + PSubW MM5, MM6 ; VR + PAddD MM4, [SI+8] + MovQM [SI], MM2 + PSRAWI MM5, RAMPSPEED-1 ; VR + MovQM [SI+8], MM4 + PAddW MM6, MM5 ; VR + + Add SI, 10h + +M32Bit8MVPanned3: + ShR BX, 2 + JZ M32Bit8MVPannedEnd + + Mov AX, [ES:DI] + Mov [DS:8h], ERROR + Mov [DS:0Ah], ERROR + Add ERROR, BP + AdC DI, DELTAOFFSET + Mov [DS:10h], AX + + Mov AX, [ES:DI] + Mov [DS:0Ch], ERROR + Mov [DS:0Eh], ERROR + Add ERROR, BP + AdC DI, DELTAOFFSET + Mov [DS:12h], AX + + Mov AX, [ES:DI] + Add ERROR, BP + AdC DI, DELTAOFFSET + Mov [DS:28h], BP + Mov [DS:18h], AX + Mov [DS:2Ah], BP + + Mov AX, [ES:DI] + Add ERROR, BP + AdC DI, DELTAOFFSET + Mov [DS:2Ch], BP + Mov [DS:1Ah], AX + Mov [DS:2Eh], BP + + MovQ MM7, [DS:28h] + + MovQ MM5, [DS:8] + PAddW MM7, MM7 + + PXor MM7, MM1 + PXor MM5, MM1 + + PSubW MM7, MM1 + + Dec BX + JZ M32Bit8MVPanned5 + +M32Bit8MVPanned4: +; DS:0 = destination volume +; DS:10h = samples +; DS:18h = samples +; MM5 = offsets +; MM6 = current volume +; MM7 = delta offsets + MovQ MM0, [DS:10h] + MovQ MM2, MM5 + + MovQ MM1, [DS:18h] + PUnpckLBW MM0, MM0 + + PSRLWI MM2, 1 + PAddW MM5, MM7 + + PMAddWD MM2, MM0 + PUnpckLBW MM1, MM1 + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:10h], AX + + PSRADI MM2, 15 + MovQ MM3, MM5 + + PAddW MM5, MM7 + PSRLWI MM3, 1 + + PMAddWD MM3, MM1 + PackSSDW MM2, MM2 + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:12h], AX + + PUnpckLWD MM2, MM2 + MovQ MM0, MM6 + + PMulHW MM0, MM2 + PSRADI MM3, 15 + + PMulLW MM2, MM6 + PackSSDW MM3, MM3 + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:18h], AX + + MovQ MM1, [DS:0] ; Destination volume + PUnpckLWD MM3, MM3 + + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + + PSubW MM1, MM6 + PUnpckHWD MM4, MM0 + + PAddD MM2, [SI] + PSRAWI MM1, RAMPSPEED-1 + + PAddD MM4, [SI+8] + PAddW MM6, MM1 ; MM6 = new volume (ramped) + + MovQM [SI], MM2 + MovQ MM1, MM6 + + MovQ MM2, [DS:0] + PMulHW MM1, MM3 + + MovQM [SI+8], MM4 + PMulLW MM3, MM6 + + Mov AX, [ES:DI] + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + Mov [DS:1Ah], AX + + MovQ MM0, MM3 + PUnpckLWD MM3, MM1 + + PAddD MM3, [SI+10h] + PUnpckHWD MM0, MM1 + + MovQM [SI+10h], MM3 + PSubW MM2, MM6 + + PAddD MM0, [SI+18h] + PSRAWI MM2, RAMPSPEED-1 + + MovQM [SI+18h], MM0 + PAddW MM6, MM2 + + Add SI, 20h + + Dec BX + JNZ M32Bit8MVPanned4 + +M32Bit8MVPanned5: + MovQ MM0, [DS:10h] + MovQ MM2, MM5 + + MovQ MM1, [DS:18h] + PUnpckLBW MM0, MM0 + + PSRLWI MM2, 1 + PAddW MM5, MM7 + + PMAddWD MM2, MM0 + PUnpckLBW MM1, MM1 + + PSRADI MM2, 15 + MovQ MM3, MM5 + + PAddW MM5, MM7 + PSRLWI MM3, 1 + + PMAddWD MM3, MM1 + PackSSDW MM2, MM2 + + PUnpckLWD MM2, MM2 + MovQ MM0, MM6 + + PMulHW MM0, MM2 + PSRADI MM3, 15 + + PMulLW MM2, MM6 + PackSSDW MM3, MM3 + + MovQ MM1, [DS:0] ; Destination volume + PUnpckLWD MM3, MM3 + + MovQ MM4, MM2 + PUnpckLWD MM2, MM0 + + PSubW MM1, MM6 + PUnpckHWD MM4, MM0 + + PAddD MM2, [SI] + PSRAWI MM1, RAMPSPEED-1 + + PAddD MM4, [SI+8] + PAddW MM6, MM1 ; MM6 = new volume (ramped) + + MovQM [SI], MM2 + MovQ MM1, MM6 + + MovQ MM2, [DS:0] + PMulHW MM1, MM3 + + MovQM [SI+8], MM4 + PMulLW MM3, MM6 + + MovQ MM0, MM3 + PUnpckLWD MM3, MM1 + + PAddD MM3, [SI+10h] + PUnpckHWD MM0, MM1 + + MovQM [SI+10h], MM3 + PSubW MM2, MM6 + + PAddD MM0, [SI+18h] + PSRAWI MM2, RAMPSPEED-1 + + MovQM [SI+18h], MM0 + PAddW MM6, MM2 + +M32Bit8MVPannedEnd: +IF MONITORPERFORMANCE + RdTSC + Add CS:M32BitMICounter8BitTicksLow, EAX + AdC CS:M32BitMICounter8BitTicksHigh, EDX +ENDIF + Ret + +EndP M32Bit8MVPanned + +; + +Proc PreM32BitMVPanned + Assume DS:Driver + + Mov ES, CS:MixSegment + + Mov AX, [SI+0Ch] ; AX = destination left + Mov BX, [SI+1Ch] ; BX = current left + Mov CX, [SI+0Eh] ; CX = destination right + Mov DX, [SI+1Eh] ; DX = current right. + + Cmp AX, BX + JL PreM32BitMVPannedV1 + + Add AX, RAMPCOMPENSATE + +PreM32BitMVPannedV1: + Cmp CX, DX + JL PreM32BitMVPannedV2 + + Add CX, RAMPCOMPENSATE + +PreM32BitMVPannedV2: + Sub Word Ptr [SI+8], 60 + + Mov [Word Ptr ES:0], AX + Mov [Word Ptr ES:4], AX + Mov [Word Ptr ES:2], CX + Mov [Word Ptr ES:6], CX + + Mov [CS:M32BitMIVolumeData], BX + Mov [CS:M32BitMIVolumeData+2], DX + + Sub AX, BX + Sub CX, DX + + SAR AX, RAMPSPEED + SAR CX, RAMPSPEED + + Add BX, AX + Add DX, CX + + Mov [CS:M32BitMIVolumeData+4], BX + Mov [CS:M32BitMIVolumeData+6], DX + + SegCS MovQ MM6, M32BitMIVolumeData + + Ret + +EndP PreM32BitMVPanned + Assume DS:Nothing + +; + diff --git a/it/SoundDrivers/M32ULTRA.INC b/it/SoundDrivers/M32ULTRA.INC new file mode 100755 index 0000000..50b693f --- /dev/null +++ b/it/SoundDrivers/M32ULTRA.INC @@ -0,0 +1,49 @@ + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMixUltraLeft8BitI, MFS8Bit, MBS8Bit, MixUltraSingle8BitI + DW Offset MixForwardsLoop, PreMixUltraLeft8BitI, MFS8Bit, MBS8Bit, MixUltraSingle8BitI + DW Offset MixPingPongLoop, PreMixUltraLeft8BitI, MFS8Bit, MBS8Bit, MixUltraSingle8BitI + ; Right only + DW Offset MixNoLoop, PreMixUltraRight8BitI, MFS8Bit, MBS8Bit, MixUltraSingle8BitI + DW Offset MixForwardsLoop, PreMixUltraRight8BitI, MFS8Bit, MBS8Bit, MixUltraSingle8BitI + DW Offset MixPingPongLoop, PreMixUltraRight8BitI, MFS8Bit, MBS8Bit, MixUltraSingle8BitI + ; Central + DW Offset MixNoLoop, PreMixUltraCentral8BitI, MFS8Bit, MBS8Bit, MixUltraCentral8BitI + DW Offset MixForwardsLoop, PreMixUltraCentral8BitI, MFS8Bit, MBS8Bit, MixUltraCentral8BitI + DW Offset MixPingPongLoop, PreMixUltraCentral8BitI, MFS8Bit, MBS8Bit, MixUltraCentral8BitI + ; Stereo + DW Offset MixNoLoop, PreMixUltraPanned8BitI, MFS8Bit, MBS8Bit, MixUltraPanned8BitI + DW Offset MixForwardsLoop, PreMixUltraPanned8BitI, MFS8Bit, MBS8Bit, MixUltraPanned8BitI + DW Offset MixPingPongLoop, PreMixUltraPanned8BitI, MFS8Bit, MBS8Bit, MixUltraPanned8BitI + ; Surround + DW Offset MixNoLoop, PreMixUltraSurround8BitI, MFS8Bit, MBS8Bit, MixUltraSurround8BitI + DW Offset MixForwardsLoop, PreMixUltraSurround8BitI, MFS8Bit, MBS8Bit, MixUltraSurround8BitI + DW Offset MixPingPongLoop, PreMixUltraSurround8BitI, MFS8Bit, MBS8Bit, MixUltraSurround8BitI + + ; 16 bit tables + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Left only + DW Offset MixNoLoop, PreMixUltraLeft16BitI, MFS16Bit, MBS16Bit, MixUltraSingle16BitI + DW Offset MixForwardsLoop, PreMixUltraLeft16BitI, MFS16Bit, MBS16Bit, MixUltraSingle16BitI + DW Offset MixPingPongLoop, PreMixUltraLeft16BitI, MFS16Bit, MBS16Bit, MixUltraSingle16BitI + ; Right only + DW Offset MixNoLoop, PreMixUltraRight16BitI, MFS16Bit, MBS16Bit, MixUltraSingle16BitI + DW Offset MixForwardsLoop, PreMixUltraRight16BitI, MFS16Bit, MBS16Bit, MixUltraSingle16BitI + DW Offset MixPingPongLoop, PreMixUltraRight16BitI, MFS16Bit, MBS16Bit, MixUltraSingle16BitI + ; Central + DW Offset MixNoLoop, PreMixUltraCentral16BitI, MFS16Bit, MBS16Bit, MixUltraCentral16BitI + DW Offset MixForwardsLoop, PreMixUltraCentral16BitI, MFS16Bit, MBS16Bit, MixUltraCentral16BitI + DW Offset MixPingPongLoop, PreMixUltraCentral16BitI, MFS16Bit, MBS16Bit, MixUltraCentral16BitI + ; Stereo + DW Offset MixNoLoop, PreMixUltraPanned16BitI, MFS16Bit, MBS16Bit, MixUltraPanned16BitI + DW Offset MixForwardsLoop, PreMixUltraPanned16BitI, MFS16Bit, MBS16Bit, MixUltraPanned16BitI + DW Offset MixPingPongLoop, PreMixUltraPanned16BitI, MFS16Bit, MBS16Bit, MixUltraPanned16BitI + ; Surround + DW Offset MixNoLoop, PreMixUltraSurround16BitI, MFS16Bit, MBS16Bit, MixUltraSurround16BitI + DW Offset MixForwardsLoop, PreMixUltraSurround16BitI, MFS16Bit, MBS16Bit, MixUltraSurround16BitI + DW Offset MixPingPongLoop, PreMixUltraSurround16BitI, MFS16Bit, MBS16Bit, MixUltraSurround16BitI diff --git a/it/SoundDrivers/M32ULTRA.MIX b/it/SoundDrivers/M32ULTRA.MIX new file mode 100755 index 0000000..f9d89ad --- /dev/null +++ b/it/SoundDrivers/M32ULTRA.MIX @@ -0,0 +1,770 @@ + + ; Different mixing routines required: + ; Left } shared + ; Right } + ; Central + ; Surround + ; Panned ; Each requires 8 bit and 16 bit + ; Single output - for Mono, pure left/pure right + +; + +GetUltra8BitWaveform Macro ; Puts waveform value in EBX, range -32k->+32k + + Push EDX + Push EBP + + MovSX EDX, Byte Ptr [ES:DI+2] ; v + MovSX EBX, Byte Ptr [ES:DI] ; t + MovSX EAX, Byte Ptr [ES:DI+1] ; u + + LEA EBP, [EBX+EDX] ; v+t + SAR EBP, 1 + Sub EBP, EAX ; (v+t)/2 - u + IMul EBP, ECX ; ax in 8.16 format + SAR EBP, 10 ; ax in 8.6 format + + ShL EAX, 7 ; EBX = 2u<<6 + Add EDX, EBX ; EDX = v+t + Add EBX, EBX ; EAX = 2t + Add EBP, EAX ; EBP = ax+2u + Add EDX, EBX ; 3t+v + ShL EDX, 5 ; (3t+v)/2 << 6 + Sub EBP, EDX ; ax+b + + ShL EBX, 7 + + IMul EBP, ECX ; ax^2+bx in 8.22 form + SAR EBP, 14 ; ax^2+bx in 8.8 form + + Add EBX, EBP ; ax^2+bx+c + + Pop EBP + Pop EDX + +EndM + +GetUltra16BitWaveform Macro ; Puts waveform value in EBX, range -32k->+32k + + Push ECX + Push EDX + Push EBP + + MovSX EDX, Word Ptr [ES:EDI+EDI+4] ; v + MovSX EBX, Word Ptr [ES:EDI+EDI] ; t + MovSX EAX, Word Ptr [ES:EDI+EDI+2] ; u + + ShR ECX, 3 ; 0.13 + LEA EBP, [EBX+EDX] + SAR EBP, 1 + Sub EBP, EAX ; (v+t)/2 - u + IMul EBP, ECX ; 16.13 + SAR EBP, 14 ; 15.0 + + Add EDX, EBX ; EDX = v+t + Add EBP, EAX ; EBP = ax+2u + LEA EDX, [EDX+EBX*2] + SAR EDX, 2 ; EDX = (3t+v)/2 + Sub EBP, EDX ; ax + b, 15 form + + IMul EBP, ECX ; ax^2+bx in 15.13 form + SAR EBP, 12 ; ax^2+bx in 16.0 form + + Add EBX, EBP + + Pop EBP + Pop EDX + Pop ECX + +EndM + +; + +MUltraMix8ISingle Macro Index + +MUltraMix8ISingle&Index&: + GetUltra8BitWaveForm + +MUltraMix8ISingleVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-3)*8], EAX ;; 3 +EndM + +MUltraMix8ICentral Macro Index + +MUltraMix8ICentral&Index&: + GetUltra8BitWaveForm + +MUltraMix8ICentralVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-3)*8], EAX ;; 4 + Sub [SI+(Index-3)*8+4], EAX ;; 4 + +EndM + +MUltraMix8ISurround Macro Index + +MUltraMix8ISurround&Index&: + GetUltra8BitWaveForm + +MUltraMix8ISurroundVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-3)*8], EAX ;; 4 + Add [SI+(Index-3)*8+4], EAX ;; 4 + +EndM + + ; Panned output +MUltraMix8IPanned Macro Index + +MUltraMix8IPanned&Index&: + Get32Bit8WaveForm + +MUltraMix8ILeftVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h +MUltraMix8IRightVolume&Index& EQU $+3 + IMul EBX, EBX, 8000h + + Sub [SI+(Index-3)*8], EAX ;; 4 + Sub [SI+(Index-3)*8+4], EBX ;; 4 + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + +EndM + +MUltraMix16ISingle Macro Index + +MUltraMix16ISingle&Index&: + GetUltra16BitWaveForm + +MUltraMix16ISingleVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-3)*8], EAX ;; 3 + +EndM + +MUltraMix16ICentral Macro Index + +MUltraMix16ICentral&Index&: + GetUltra16BitWaveForm + +MUltraMix16ICentralVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-3)*8], EAX ;; 3 + Sub [SI+(Index-3)*8+4], EAX ;; 3 + +EndM + +MUltraMix16ISurround Macro Index + +MUltraMix16ISurround&Index&: + GetUltra16BitWaveForm + +MUltraMix16ISurroundVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h + + Add ERROR, DELTAERROR ;; 1 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-3)*8], EAX ;; 3 + Add [SI+(Index-3)*8+4], EAX ;; 3 + +EndM + + ; Panned output +MUltraMix16IPanned Macro Index + +MUltraMix16IPanned&Index&: + GetUltra16BitWaveForm + +MUltraMix16ILeftVolume&Index& EQU $+3 + IMul EAX, EBX, 8000h +MUltraMix16IRightVolume&Index& EQU $+3 + IMul EBX, EBX, 8000h + + Sub [SI+(Index-3)*8], EAX + Sub [SI+(Index-3)*8+4], EBX + + Add ERROR, DELTAERROR + AdC DI, DELTAOFFSET + +EndM + +; + +MixUltraSingle8BitIOffsetTable Label Word + + IndexCounter = 3 + + MUltraMix8ISingleOffset Macro Index + DW Offset MUltraMix8ISingle&Index& + EndM + + REPT 4 + MUltraMix8ISingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc MixUltraSingle8BitI + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 3 + ShR BX, 2 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:MixUltraSingle8BitIOffsetTable+BX] + + MUltraMix8ISingle 0 + MUltraMix8ISingle 1 + MUltraMix8ISingle 2 + MUltraMix8ISingle 3 + + Add SI, 4*MIXRESOLUTION/4 + Dec LoopCounter + JNZ MUltraMix8ISingle0 + + Ret + +EndP MixUltraSingle8BitI + +; + +Proc PreMixUltraLeft8BitI + + Mov AX, [SI+0Eh] + +PreMixUltraLeft8BitI1: + IndexCounter = 0 + + PreMixUltraSingleMacro Macro Index + Mov Word Ptr [CS:MUltraMix8ISingleVolume&Index&], AX + EndM + + REPT 4 + PreMixUltraSingleMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + Ret + +EndP PreMixUltraLeft8BitI + +; + +Proc PreMixUltraRight8BitI + + Add MixBufferOffset, MixResolution/8 + Mov AX, [SI+0Ch] + Jmp PreMixUltraLeft8BitI1 + +EndP PreMixUltraRight8BitI + +; + +MixUltraCentral8BitIOffsetTable Label Word + + IndexCounter = 3 + + MUltraMix8ICentralOffset Macro Index + DW Offset MUltraMix8ICentral&Index& + EndM + + REPT 4 + MUltraMix8ICentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc MixUltraCentral8BitI + + Dec AX + Mov BX, AX + And AX, 3 + ShR BX, 2 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:MixUltraCentral8BitIOffsetTable+BX] + + MUltraMix8ICentral 0 + MUltraMix8ICentral 1 + MUltraMix8ICentral 2 + MUltraMix8ICentral 3 + + Add SI, 4*MIXRESOLUTION/4 + Dec LoopCounter + JNZ MUltraMix8ICentral0 + + Ret + +EndP MixUltraCentral8BitI + +; + +Proc PreMixUltraCentral8BitI + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMixUltraCentralMacro Macro Index + Mov Word Ptr [CS:MUltraMix8ICentralVolume&Index&], AX + EndM + + REPT 4 + PreMixUltraCentralMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMixUltraCentral8BitI + +; + +MixUltraSurround8BitIOffsetTable Label Word + + IndexCounter = 3 + + MUltraMix8ISurroundOffset Macro Index + DW Offset MUltraMix8ISurround&Index& + EndM + + REPT 4 + MUltraMix8ISurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc MixUltraSurround8BitI + + Dec AX + Mov BX, AX + And AX, 3 + ShR BX, 2 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:MixUltraSurround8BitIOffsetTable+BX] + + MUltraMix8ISurround 0 + MUltraMix8ISurround 1 + MUltraMix8ISurround 2 + MUltraMix8ISurround 3 + + Add SI, 4*MIXRESOLUTION/4 + Dec LoopCounter + JNZ MUltraMix8ISurround0 + + Ret + +EndP MixUltraSurround8BitI + +; + +Proc PreMixUltraSurround8BitI + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMixUltraSurroundMacro Macro Index + Mov Word Ptr [CS:MUltraMix8ISurroundVolume&Index&], AX + EndM + + REPT 4 + PreMixUltraSurroundMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMixUltraSurround8BitI + +; + +MixUltraPanned8BitIOffsetTable Label Word + + IndexCounter = 3 + + MUltraMix8IPannedOffset Macro Index + DW Offset MUltraMix8IPanned&Index& + EndM + + REPT 4 + MUltraMix8IPannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc MixUltraPanned8BitI + + Dec AX + Mov BX, AX + And AX, 3 + ShR BX, 2 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:MixUltraPanned8BitIOffsetTable+BX] + + MUltraMix8IPanned 0 + MUltraMix8IPanned 1 + MUltraMix8IPanned 2 + MUltraMix8IPanned 3 + + Add SI, 4*MIXRESOLUTION/4 + Dec LoopCounter + JNZ MUltraMix8IPanned0 + + Ret + +EndP MixUltraPanned8BitI + +; + +Proc PreMixUltraPanned8BitI + + Mov AX, [SI+0Eh] ; Left + Mov BX, [SI+0Ch] ; Right + + IndexCounter = 0 + + PreMixUltraPannedMacro Macro Index + Mov Word Ptr [CS:MUltraMix8ILeftVolume&Index&], AX + Mov Word Ptr [CS:MUltraMix8IRightVolume&Index&], BX + EndM + + REPT 4 + PreMixUltraPannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMixUltraPanned8BitI + +; + +MixUltraSingle16BitIOffsetTable Label Word + + IndexCounter = 3 + + MUltraMix16ISingleOffset Macro Index + DW Offset MUltraMix16ISingle&Index& + EndM + + REPT 4 + MUltraMix16ISingleOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc MixUltraSingle16BitI + ; AX = count... + + ; Number of times to loop = (Count-1) / 16 + + Dec AX + Mov BX, AX + And AX, 3 + ShR BX, 2 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:MixUltraSingle16BitIOffsetTable+BX] + + MUltraMix16ISingle 0 + MUltraMix16ISingle 1 + MUltraMix16ISingle 2 + MUltraMix16ISingle 3 + + Add SI, 4*MIXRESOLUTION/4 + Dec LoopCounter + JNZ MUltraMix16ISingle0 + + Ret + +EndP MixUltraSingle16BitI + +; + +Proc PreMixUltraLeft16BitI + + Mov AX, [SI+0Eh] ; Left + +PreMixUltraLeft16BitI1: + IndexCounter = 0 + + PreMixUltraSingleMacro Macro Index + Mov Word Ptr [CS:MUltraMix16ISingleVolume&Index&], AX + EndM + + REPT 4 + PreMixUltraSingleMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMixUltraLeft16BitI + +; + +Proc PreMixUltraRight16BitI + + Add MixBufferOffset, MixResolution/8 + Mov AX, [SI+0Ch] + Jmp PreMixUltraLeft16BitI1 + + Ret + +EndP PreMixUltraRight16BitI + +; + +MixUltraCentral16BitIOffsetTable Label Word + + IndexCounter = 3 + + MUltraMix16ICentralOffset Macro Index + DW Offset MUltraMix16ICentral&Index& + EndM + + REPT 4 + MUltraMix16ICentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc MixUltraCentral16BitI + + Dec AX + Mov BX, AX + And AX, 3 + ShR BX, 2 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:MixUltraCentral16BitIOffsetTable+BX] + + MUltraMix16ICentral 0 + MUltraMix16ICentral 1 + MUltraMix16ICentral 2 + MUltraMix16ICentral 3 + + Add SI, 4*MIXRESOLUTION/4 + Dec LoopCounter + JNZ MUltraMix16ICentral0 + + Ret + +EndP MixUltraCentral16BitI + +; + +Proc PreMixUltraCentral16BitI + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMixUltraCentralMacro Macro Index + Mov Word Ptr [CS:MUltraMix16ICentralVolume&Index&], AX + EndM + + REPT 4 + PreMixUltraCentralMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMixUltraCentral16BitI + +; + +MixUltraSurround16BitIOffsetTable Label Word + + IndexCounter = 3 + + MUltraMix16ISurroundOffset Macro Index + DW Offset MUltraMix16ISurround&Index& + EndM + + REPT 4 + MUltraMix16ISurroundOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc MixUltraSurround16BitI + + Dec AX + Mov BX, AX + And AX, 3 + ShR BX, 2 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:MixUltraSurround16BitIOffsetTable+BX] + + MUltraMix16ISurround 0 + MUltraMix16ISurround 1 + MUltraMix16ISurround 2 + MUltraMix16ISurround 3 + + Add SI, 4*MIXRESOLUTION/4 + Dec LoopCounter + JNZ MUltraMix16ISurround0 + + Ret + +EndP MixUltraSurround16BitI + +; + +Proc PreMixUltraSurround16BitI + + Mov AX, [SI+0Eh] + + IndexCounter = 0 + + PreMixUltraSurroundMacro Macro Index + Mov Word Ptr [CS:MUltraMix16ISurroundVolume&Index&], AX + EndM + + REPT 4 + PreMixUltraSurroundMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMixUltraSurround16BitI + +; + +MixUltraPanned16BitIOffsetTable Label Word + + IndexCounter = 3 + + MUltraMix16IPannedOffset Macro Index + DW Offset MUltraMix16IPanned&Index& + EndM + + REPT 4 + MUltraMix16IPannedOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc MixUltraPanned16BitI + + Dec AX + Mov BX, AX + And AX, 3 + ShR BX, 2 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Jmp [CS:MixUltraPanned16BitIOffsetTable+BX] + +PanMUltraBit16ILoop: + MUltraMix16IPanned 0 + MUltraMix16IPanned 1 + MUltraMix16IPanned 2 + MUltraMix16IPanned 3 + + Add SI, 4*MIXRESOLUTION/4 + Dec LoopCounter + JNZ PanMUltraBit16ILoop + + Ret + +EndP MixUltraPanned16BitI + +; + +Proc PreMixUltraPanned16BitI + + Mov AX, [SI+0Eh] ; Left + Mov BX, [SI+0Ch] ; Right + + IndexCounter = 0 + + PreMixUltraPannedMacro Macro Index + Mov Word Ptr [CS:MUltraMix16ILeftVolume&Index&], AX + Mov Word Ptr [CS:MUltraMix16IRightVolume&Index&], BX + EndM + + REPT 4 + PreMixUltraPannedMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMixUltraPanned16BitI + + diff --git a/it/SoundDrivers/MAD.BAT b/it/SoundDrivers/MAD.BAT new file mode 100755 index 0000000..ec622a2 --- /dev/null +++ b/it/SoundDrivers/MAD.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 ad1816 +tlink /3 ad1816 +execom ad1816 itad1816.drv +copy itad1816.drv .. + diff --git a/it/SoundDrivers/MAWE.BAT b/it/SoundDrivers/MAWE.BAT new file mode 100755 index 0000000..57cafac --- /dev/null +++ b/it/SoundDrivers/MAWE.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 awe32drv +tlink /3 awe32drv +execom awe32drv itawe32.drv +copy itawe32.drv .. diff --git a/it/SoundDrivers/MAWEB.BAT b/it/SoundDrivers/MAWEB.BAT new file mode 100755 index 0000000..20145cd --- /dev/null +++ b/it/SoundDrivers/MAWEB.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 awe32b +tlink /3 awe32b +execom awe32b itawe32b.drv +copy itawe32b.drv .. diff --git a/it/SoundDrivers/MB.BAT b/it/SoundDrivers/MB.BAT new file mode 100755 index 0000000..de7ae06 --- /dev/null +++ b/it/SoundDrivers/MB.BAT @@ -0,0 +1,6 @@ +@rem Base1 Driver +tasm /m /ut310 base1 +tlink /3 base1 +execom base1 itbase1.drv +copy itbase1.drv .. + diff --git a/it/SoundDrivers/MES.BAT b/it/SoundDrivers/MES.BAT new file mode 100755 index 0000000..c3e86fa --- /dev/null +++ b/it/SoundDrivers/MES.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 es1868 +tlink /3 es1868 +execom es1868 ites1868.drv +copy ites1868.drv .. + diff --git a/it/SoundDrivers/MES1688.BAT b/it/SoundDrivers/MES1688.BAT new file mode 100755 index 0000000..890cbb1 --- /dev/null +++ b/it/SoundDrivers/MES1688.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 es1688 +tlink /3 es1688 +execom es1688 ites1688.drv +copy ites1688.drv .. + diff --git a/it/SoundDrivers/MES1688M.BAT b/it/SoundDrivers/MES1688M.BAT new file mode 100755 index 0000000..0f25644 --- /dev/null +++ b/it/SoundDrivers/MES1688M.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 es1688mx +tlink /3 es1688mx +execom es1688mx ites1688.mmx +copy ites1688.mmx .. + diff --git a/it/SoundDrivers/MES1788.BAT b/it/SoundDrivers/MES1788.BAT new file mode 100755 index 0000000..01230e5 --- /dev/null +++ b/it/SoundDrivers/MES1788.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 es1788 +tlink /3 es1788 +execom es1788 ites1788.drv +copy ites1788.drv .. + diff --git a/it/SoundDrivers/MES1869.BAT b/it/SoundDrivers/MES1869.BAT new file mode 100755 index 0000000..4e98784 --- /dev/null +++ b/it/SoundDrivers/MES1869.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 es1869 +tlink /3 es1869 +execom es1869 ites1869.drv +copy ites1869.drv .. + diff --git a/it/SoundDrivers/MES1869M.BAT b/it/SoundDrivers/MES1869M.BAT new file mode 100755 index 0000000..ac92bef --- /dev/null +++ b/it/SoundDrivers/MES1869M.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 es1869mx +tlink /3 es1869mx +execom es1869mx ites1869.mmx +copy ites1869.mmx .. + diff --git a/it/SoundDrivers/MESM.BAT b/it/SoundDrivers/MESM.BAT new file mode 100755 index 0000000..9c3ba08 --- /dev/null +++ b/it/SoundDrivers/MESM.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 es1868mx +tlink /3 es1868mx +execom es1868mx ites1868.mmx +copy ites1868.mmx .. + diff --git a/it/SoundDrivers/MEWS.BAT b/it/SoundDrivers/MEWS.BAT new file mode 100755 index 0000000..a69f9b3 --- /dev/null +++ b/it/SoundDrivers/MEWS.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 ews64 +tlink /3 ews64 +execom ews64 itews64.drv +copy itews64.drv .. diff --git a/it/SoundDrivers/MEWSC.BAT b/it/SoundDrivers/MEWSC.BAT new file mode 100755 index 0000000..582f17e --- /dev/null +++ b/it/SoundDrivers/MEWSC.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 ewscodec +tlink /3 ewscodec +execom ewscodec itewscod.drv +copy itewscod.drv .. + diff --git a/it/SoundDrivers/MEWSCM.BAT b/it/SoundDrivers/MEWSCM.BAT new file mode 100755 index 0000000..d74f03f --- /dev/null +++ b/it/SoundDrivers/MEWSCM.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 ewscodmx +tlink /3 ewscodmx +execom ewscodmx itewscod.mmx +copy itewscod.mmx .. + diff --git a/it/SoundDrivers/MG16.BAT b/it/SoundDrivers/MG16.BAT new file mode 100755 index 0000000..b0db2a1 --- /dev/null +++ b/it/SoundDrivers/MG16.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 gold16 +tlink /3 gold16 +execom m16 itgold16.drv +copy itgold16.drv .. + diff --git a/it/SoundDrivers/MGP.BAT b/it/SoundDrivers/MGP.BAT new file mode 100755 index 0000000..b7626ff --- /dev/null +++ b/it/SoundDrivers/MGP.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 guspnpm +tlink /3 guspnpm +execom guspnpm itguspnp.drv +copy itguspnp.drv .. diff --git a/it/SoundDrivers/MGPM.BAT b/it/SoundDrivers/MGPM.BAT new file mode 100755 index 0000000..c5a95e6 --- /dev/null +++ b/it/SoundDrivers/MGPM.BAT @@ -0,0 +1,4 @@ +tasm32 /m /ut310 guspnpmx +tlink /3 guspnpmx +execom guspnpmx itguspnp.mmx +copy itguspnp.mmx .. diff --git a/it/SoundDrivers/MGUS.BAT b/it/SoundDrivers/MGUS.BAT new file mode 100755 index 0000000..30120d1 --- /dev/null +++ b/it/SoundDrivers/MGUS.BAT @@ -0,0 +1,4 @@ +tasm /m /uT310 /l gushiqdr +tlink /3 gushiqdr +execom gushiqdr itgus.drv +copy itgus.drv .. diff --git a/it/SoundDrivers/MGUS2.BAT b/it/SoundDrivers/MGUS2.BAT new file mode 100755 index 0000000..328066a --- /dev/null +++ b/it/SoundDrivers/MGUS2.BAT @@ -0,0 +1,4 @@ +tasm /m /uT310 gushiq2 +tlink /3 gushiq2 +execom gushiq2 itgus2.drv +copy itgus2.drv .. diff --git a/it/SoundDrivers/MGUSLO.BAT b/it/SoundDrivers/MGUSLO.BAT new file mode 100755 index 0000000..7141a75 --- /dev/null +++ b/it/SoundDrivers/MGUSLO.BAT @@ -0,0 +1,4 @@ +tasm /m /uT310 gusdrv2 +tlink /3 gusdrv2 +execom gusdrv2 itguslo.drv +copy itguslo.drv .. diff --git a/it/SoundDrivers/MGUSMAX.BAT b/it/SoundDrivers/MGUSMAX.BAT new file mode 100755 index 0000000..46b43d4 --- /dev/null +++ b/it/SoundDrivers/MGUSMAX.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 gusmax +tlink /3 gusmax +execom gusmax itgusmax.drv +copy itgusmax.drv .. + diff --git a/it/SoundDrivers/MGUSMAXM.BAT b/it/SoundDrivers/MGUSMAXM.BAT new file mode 100755 index 0000000..b88175b --- /dev/null +++ b/it/SoundDrivers/MGUSMAXM.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 gusmaxmx +tlink /3 gusmaxmx +execom gusmaxmx itgusmax.mmx +copy itgusmax.mmx .. + diff --git a/it/SoundDrivers/MGUSMIX.BAT b/it/SoundDrivers/MGUSMIX.BAT new file mode 100755 index 0000000..3b27517 --- /dev/null +++ b/it/SoundDrivers/MGUSMIX.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 gusmixdr +tlink /3 gusmixdr +execom gusmixdr itgusmix.drv +copy itgusmix.drv .. diff --git a/it/SoundDrivers/MIDDRV.ASM b/it/SoundDrivers/MIDDRV.ASM new file mode 100755 index 0000000..d9adff2 --- /dev/null +++ b/it/SoundDrivers/MIDDRV.ASM @@ -0,0 +1,865 @@ + +; +; MID File generator +; + +REPEATSTATUSBYTE EQU 0 + + .486P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +; + +include ..\wavswitc.inc + +FileHandle DW 0 + +MIDOutputMsg DB "MIDI File Generator", 13 + DB "Writing to disk", 0 +MIDOutputError DB "Unable to create output file!", 0FFh, 29, " ", 0 +WriteErrorMsg DB "Error writing to output file. Output file closed", 0FFh, 11, " ", 0 +ClosedMsg DB "Closed output file", 0FFh, 42, " ", 0 +CreateMsg DB "Creating file " +Filename DB " ", 0 +OUTPUT DB "OUTPUT" +DriverName DB "ITMID.DRV", 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 80 +MIDDirectory DB ".", 79 Dup (0) + + +AccumulatedTime DD 0 + +MIDIHEADERSIZE = 22+32+7 +MIDIHeader DB "MThd", 0, 0, 0, 6, 0, 0, 0, 1 + DB 0, 018h ; 24 ppqn + DB "MTrk" +MIDIFileSize DD 0 + DB 0, 0FFh, 01, 28 + DB "Created with Impulse Tracker" + DB 0, 0FFh, 51h, 3 +InitialTempo DD 0 + +MTrkEnd DB 0, 0FFh, 2Fh, 0 + +MIDIBuffer DB 256 Dup (0) +MIDIBufferOffset DW Offset MIDIBuffer + +MIDScreenList DW 6 + DW IdleFunctionList + DW GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr MIDHeader + + DW Near Ptr DirectoryInputText + DW Near Ptr DirectoryInputBox + DW Near Ptr DirectoryInput ; 6 + + DW 0 + +IdleFunctionList DD 0 + DD 0 +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MIDHeader DW 10 + DB "MIDI File Export Driver", 0 + +DirectoryInputText DW 1 + DB 2, 14 + DB 20h + DB "Output Directory", 0 + +DirectoryInputBox DW 0 + DB 18, 13, 78, 15 + DB 25 + +DirectoryInput DW 16 + DB 19, 14 +Segment1 DW 0 + DW Offset MIDDirectory + DW 59 + DD 0 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +TRACEENABLED EQU 0 +CREATENEWLOGFILE EQU 1 +include debug.inc + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectCard + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + + Mov Segment1, DS + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GotoHomeDirectory + Mov SI, Offset MIDDirectory + Call SetDirectory + + Mov SI, Offset MIDOutputMsg + ClC + Ret + +EndP InitSound + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc CheckFileClosed + + Push CS + Pop DS + Assume DS:Driver + + Mov BX, FileHandle + Test BX, BX + JZ CheckFileClosedEnd + + Mov AH, 40h + Mov CX, 4 + Mov DX, Offset MTrkEnd + Int 21h + + Mov FileHandle, 0 + + Mov AX, 4200h ; Move to start of file + Xor CX, CX + Xor DX, DX + Int 21h ; Start of file + + Mov AX, Word Ptr [MIDIFileSize] + Mov DX, Word Ptr [MIDIFileSize+2] + XChg AL, DH + XChg AH, DL + Mov Word Ptr [MIDIFileSize], AX + Mov Word Ptr [MIDIFileSize+2], DX + + Mov AH, 40h + Mov CX, MIDIHEADERSIZE + Mov DX, Offset MIDIHeader + Int 21h + + Mov AH, 3Eh + Int 21h + + Mov SI, Offset ClosedMsg + Mov BX, 40 + Call SetInfoLine + +CheckFileClosedEnd: + Ret + +EndP CheckFileClosed + Assume DS:Nothing + +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MIDDirectory + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Call CheckFileClosed + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc WriteMIDIBlock + Assume DS:Driver + + Xor ECX, ECX + + Mov CX, MIDIBufferOffset + Mov DX, Offset MIDIBuffer + Mov AH, 40h + Mov BX, FileHandle + Sub CX, DX + JZ NoDataToWrite + + Add MIDIFileSize, ECX + + Trace "Writing MIDI block" + + Int 21h + +NoDataToWrite: + Mov MIDIBufferOffset, Offset MIDIBuffer + + Ret + +EndP WriteMIDIBlock + Assume DS:Nothing + +; + +Proc Poll Far + Assume DS:Nothing + + Mov CS:Countdown, 0 + Mov CS:MIDIBufferOffset, Offset MIDIBuffer + + Call Update ; Got DS:SI, CX + +; Scan through channels and if any channels are samples, turn them off. + +TurnOffSamples1: + Test Byte Ptr [SI], 1 ; Channel on? + JZ TurnOffSamples2 + + Mov Word Ptr [SI], 0 + + Test Byte Ptr [SI+3Ah], 80h + JNZ TurnOffSamples2 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + +TurnOffSamples2: + Add SI, 128 + Loop TurnOffSamples1 + +; OK.. check whether any MIDI data requires dumping... also whether file +; needs to be created. + + Test AX, AX ; Currently not playing + JNZ Poll1 + + Call CheckFileClosed + Ret + +Poll1: + Push CS + Pop DS + Assume DS:Driver + + Cmp FileHandle, 0 + JNE Poll2 + + Trace "New file to create" + + Mov SI, Offset MIDDirectory + Call SetDirectory + + Xor EAX, EAX + Mov AccumulatedTime, EAX + Mov AL, 4+32+7 + Mov MIDIFileSize, EAX + +; Have to create a file + Call GetFileName + Assume DS:Nothing ; Returns DS:SI + Push CS + Pop ES + Mov DI, Offset FileName + + Push DI + + Mov CX, 12 + Mov AL, ' ' + Rep StosB + + Pop DI + + Cmp Byte Ptr [DS:SI], 0 + JE PollFileNameNone + Cmp Byte Ptr [DS:SI], '.' + JE PollFileNameNone + + Mov CX, 8 +PollFileName1: + LodsB + Cmp AL, 0 + JE PollFileNameExt + Cmp AL, '.' + JE PollFileNameExt + StosB + Loop PollFileName1 + Jmp PollFileNameExt + +PollFileNameNone: + Push CS + Pop DS + Mov SI, Offset Output + Mov CX, 6 + Rep MovsB + +PollFileNameExt: + Mov EAX, 'DIM.' + StosD + Xor AL, AL + StosB + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset CreateMsg + Mov BX, 40 + Call SetInfoLine + + Mov AH, 3Ch + Xor CX, CX + Mov DX, Offset Filename + Int 21h + JC WriteError + + Mov BX, AX + Mov FileHandle, BX + Trace "File opened" + +; Write header once + Push BX + Call GetTempo + Mov EAX, 60000000 + And EBX, 0FFFFh + Xor EDX, EDX + Div EBX ; EAX = microseconds per quarter note + + ShL EAX, 8 + BSwap EAX + Mov InitialTempo, EAX + Pop BX + + Mov AH, 40h + Mov CX, MIDIHEADERSIZE + Mov DX, Offset MIDIHeader + Int 21h + JC WriteError + + Trace "Header written" + +Poll2: + Call WriteMIDIBlock + JC WriteError + +; Update time counters + Inc AccumulatedTime + + Ret + +WriteError: + Call CheckFileClosed + Mov SI, Offset WriteErrorMsg + Mov BX, 40 + Call SetInfoLine + Call StopPlayback + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far ; Frames per second = 0.4*BX + ; -> Milliseconds per frame = 1000/(0.4/BX) + ; = 2500/BX + PushAD + Push DS + +; SetTempo: FF 51 03 tt tt tt + + Push CS + Pop DS + Assume DS:Driver + + Push BX + + Mov SI, MIDIBufferOffset + Call WriteDeltaTime + + Pop BX + + Mov DWord Ptr [SI], 351FFh + Add SI, 3 + + Mov EAX, 60000000 + And EBX, 0FFFFh + Xor EDX, EDX + Div EBX ; EAX = microseconds per quarter note + + ShL EAX, 8 + BSwap EAX + Mov DWord Ptr [SI], EAX + Add SI, 3 + + Mov MIDIBufferOffset, SI + + Pop DS + PopAD + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load (0 based) +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release (1 based) +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset MIDScreenList + + ClC + Ret + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +StatusByte DB 0 +CountDown DB 0 + +StatusByteLUT DB 2, 2, 2, 2, 1, 1, 2 +InSysex DW 0 + +; + +Proc WriteDeltaTime ; Given DS:SI = buffer + + Xor EDX, EDX + Mov EBX, AccumulatedTime + Mov CX, 4 + Mov AccumulatedTime, EDX + +WriteDeltaTime1: + ShL EDX, 8 + Mov DL, BL + Or DL, 80h + ShR EBX, 7 + LoopNZ WriteDeltaTime1 + ; EDX = output bytes, DL = most signif + +WriteDeltaTime2: + Mov [SI], DL + Inc SI + ShR EDX, 8 + JNZ WriteDeltaTime2 + + And Byte Ptr [SI-1], 7Fh + + Ret + +EndP WriteDeltaTime + +; + +Proc BufferMIDIOutput ; AL = value. + + PushAD + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov BX, InSysex + Mov SI, MIDIBufferOffset + + Test BX, BX + JZ BufferMIDINoSysex + + Cmp AL, 0F7h + JNE BufferMIDIOutput1 + + Mov DX, SI + Sub DX, BX ; DX = count of sysex bytes + Mov [BX], DL + Mov InSysex, 0 + + Jmp BufferMIDIOutput1 + +BufferMIDINoSysex: + Cmp Countdown, 0 + JNE BufferMIDIOutput1 + + Cmp AL, 0F0h + JA BufferMIDIOutput2 + +; Delta time required + Call WriteDeltaTime + + Xor BX, BX + Xor DL, DL + Test AL, AL + JNS BufferMIDINoStatus + Cmp AL, 0F0h + JE BufferMIDISysex + + Mov StatusByte, AL + Inc DX + Jmp BufferMIDINoStatus + +BufferMIDISysex: + Mov [SI], AL + Inc SI + Mov InSysex, SI + Jmp BufferMIDIOutput1 + +BufferMIDINoStatus: + Mov BL, StatusByte + ShR BX, 4 + Sub BL, 8 + JC BufferMIDIOutput1 + + Add DL, [StatusByteLUT+BX] + Mov Countdown, DL + +BufferMIDIOutput1: + Mov [SI], AL + Inc SI + Dec Countdown + + Mov MIDIBufferOffset, SI + + Cmp SI, Offset MIDIBuffer+200 + JB BufferMIDIOutput2 + Cmp InSysex, 0 + JNE BufferMIDIOutput2 + + Call WriteMIDIBlock + +BufferMIDIOutput2: + Pop DS + PopAD + + Ret + +EndP BufferMIDIOutput + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call BufferMIDIOutput + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Call BufferMIDIOutput + + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 32 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 1 +DefaultChannels DW 32 +DriverFlags DW 1 ; Supports MIDI Out. + + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/MIDDRV2.ASM b/it/SoundDrivers/MIDDRV2.ASM new file mode 100755 index 0000000..74a2561 --- /dev/null +++ b/it/SoundDrivers/MIDDRV2.ASM @@ -0,0 +1,828 @@ + +; +; MID File generator +; + +REPEATSTATUSBYTE EQU 0 + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +; + +include wavswitc.inc + +FileHandle DW 0 + +MIDOutputMsg DB "MIDI File Generator", 13 + DB "Writing to disk", 0 +MIDOutputError DB "Unable to create output file!", 0FFh, 29, " ", 0 +WriteErrorMsg DB "Error writing to output file. Output file closed", 0FFh, 11, " ", 0 +ClosedMsg DB "Closed output file", 0FFh, 42, " ", 0 +CreateMsg DB "Creating file " +Filename DB " ", 0 +OUTPUT DB "OUTPUT" +DriverName DB "ITMID.DRV", 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 80 +MIDDirectory DB ".", 79 Dup (0) + + +AccumulatedTime DD 0 +AccumulatedTimeError DD 0 + +FrameTime DD 0 +FrameTimeError DD 0 + + +MIDIHeader DB "MThd", 0, 0, 0, 6, 0, 0, 0, 1, 0E7h, 28h + DB "MTrk" +MIDIFileSize DD 0 + DB 0, 0FFh, 01, 28 + DB "Created with Impulse Tracker" + +MTrkEnd DB 0, 0FFh, 2Fh, 0 + +MIDIBuffer DB 256 Dup (0) +MIDIBufferOffset DW Offset MIDIBuffer + +MIDScreenList DW 6 + DW IdleFunctionList + DW GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr MIDHeader + + DW Near Ptr DirectoryInputText + DW Near Ptr DirectoryInputBox + DW Near Ptr DirectoryInput ; 6 + + DW 0 + +IdleFunctionList DD 0 + DD 0 +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MIDHeader DW 10 + DB "MIDI File Export Driver", 0 + +DirectoryInputText DW 1 + DB 2, 14 + DB 20h + DB "Output Directory", 0 + +DirectoryInputBox DW 0 + DB 18, 13, 78, 15 + DB 25 + +DirectoryInput DW 16 + DB 19, 14 +Segment1 DW 0 + DW Offset MIDDirectory + DW 59 + DD 0 + DW 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh + +TRACEENABLED EQU 0 +CREATENEWLOGFILE EQU 1 +include debug.inc + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectCard + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + + Mov Segment1, DS + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GotoHomeDirectory + Mov SI, Offset MIDDirectory + Call SetDirectory + + Mov SI, Offset MIDOutputMsg + ClC + Ret + +EndP InitSound + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc CheckFileClosed + + Push CS + Pop DS + Assume DS:Driver + + Mov BX, FileHandle + Test BX, BX + JZ CheckFileClosedEnd + + Mov AH, 40h + Mov CX, 4 + Mov DX, Offset MTrkEnd + Int 21h + + Mov FileHandle, 0 + + Mov AX, 4200h ; Move to start of file + Xor CX, CX + Xor DX, DX + Int 21h ; Start of file + + Mov AX, Word Ptr [MIDIFileSize] + Mov DX, Word Ptr [MIDIFileSize+2] + XChg AL, DH + XChg AH, DL + Mov Word Ptr [MIDIFileSize], AX + Mov Word Ptr [MIDIFileSize+2], DX + + Mov AH, 40h + Mov CX, 22+32 + Mov DX, Offset MIDIHeader + Int 21h + + Mov AH, 3Eh + Int 21h + + Mov SI, Offset ClosedMsg + Mov BX, 40 + Call SetInfoLine + +CheckFileClosedEnd: + Ret + +EndP CheckFileClosed + Assume DS:Nothing + +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MIDDirectory + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Call CheckFileClosed + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc WriteMIDIBlock + Assume DS:Driver + + Xor ECX, ECX + + Mov CX, MIDIBufferOffset + Mov DX, Offset MIDIBuffer + Mov AH, 40h + Mov BX, FileHandle + Sub CX, DX + JZ NoDataToWrite + + Add MIDIFileSize, ECX + + Trace "Writing MIDI block" + + Int 21h + +NoDataToWrite: + Mov MIDIBufferOffset, Offset MIDIBuffer + + Ret + +EndP WriteMIDIBlock + Assume DS:Nothing + +; + +Proc Poll Far + Assume DS:Nothing + + Mov CS:Countdown, 0 + Mov CS:MIDIBufferOffset, Offset MIDIBuffer + + Call Update ; Got DS:SI, CX + +; Scan through channels and if any channels are samples, turn them off. + +TurnOffSamples1: + Test Byte Ptr [SI], 1 ; Channel on? + JZ TurnOffSamples2 + + Mov Word Ptr [SI], 0 + + Test Byte Ptr [SI+3Ah], 80h + JNZ TurnOffSamples2 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + +TurnOffSamples2: + Add SI, 128 + Loop TurnOffSamples1 + +; OK.. check whether any MIDI data requires dumping... also whether file +; needs to be created. + + Test AX, AX ; Currently not playing + JNZ Poll1 + + Call CheckFileClosed + Ret + +Poll1: + Push CS + Pop DS + Assume DS:Driver + + Cmp FileHandle, 0 + JNE Poll2 + + Trace "New file to create" + + Mov SI, Offset MIDDirectory + Call SetDirectory + + Xor EAX, EAX + Mov AccumulatedTime, EAX + Mov AccumulatedTimeError, EAX + Mov AL, 4+32 + Mov MIDIFileSize, EAX + +; Have to create a file + Call GetFileName + Assume DS:Nothing ; Returns DS:SI + Push CS + Pop ES + Mov DI, Offset FileName + + Push DI + + Mov CX, 12 + Mov AL, ' ' + Rep StosB + + Pop DI + + Cmp Byte Ptr [DS:SI], 0 + JE PollFileNameNone + Cmp Byte Ptr [DS:SI], '.' + JE PollFileNameNone + + Mov CX, 8 +PollFileName1: + LodsB + Cmp AL, 0 + JE PollFileNameExt + Cmp AL, '.' + JE PollFileNameExt + StosB + Loop PollFileName1 + Jmp PollFileNameExt + +PollFileNameNone: + Push CS + Pop DS + Mov SI, Offset Output + Mov CX, 6 + Rep MovsB + +PollFileNameExt: + Mov EAX, 'DIM.' + StosD + Xor AL, AL + StosB + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset CreateMsg + Mov BX, 40 + Call SetInfoLine + + Mov AH, 3Ch + Xor CX, CX + Mov DX, Offset Filename + Int 21h + JC WriteError + + Mov BX, AX + Mov FileHandle, BX + Trace "File opened" + +; Write header once + Mov AH, 40h + Mov CX, 22+32 + Mov DX, Offset MIDIHeader + Int 21h + JC WriteError + + Trace "Header written" + +Poll2: + Call WriteMIDIBlock + JC WriteError + +; Update time counters + Mov EAX, FrameTimeError + Mov EBX, FrameTime + Add AccumulatedTimeError, EAX + AdC AccumulatedTime, EBX + + Ret + +WriteError: + Call CheckFileClosed + Mov SI, Offset WriteErrorMsg + Mov BX, 40 + Call SetInfoLine + Call StopPlayback + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far ; Frames per second = 0.4*BX + ; -> Milliseconds per frame = 1000/(0.4/BX) + ; = 2500/BX + PushAD + + Mov EAX, 2500 + And EBX, 0FFFFh + Xor EDX, EDX + Div EBX ; EAX = milliseconds + + Mov CS:FrameTime, EAX + Mov CS:FrameTimeError, EDX + + + PopAD + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load (0 based) +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release (1 based) +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset MIDScreenList + + ClC + Ret + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +StatusByte DB 0 +CountDown DB 0 + +StatusByteLUT DB 2, 2, 2, 2, 1, 1, 2 +InSysex DW 0 + +; + +Proc BufferMIDIOutput + + PushAD + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov BX, InSysex + Mov SI, MIDIBufferOffset + + Test BX, BX + JZ BufferMIDINoSysex + + Cmp AL, 0F7h + JNE BufferMIDIOutput1 + + Mov DX, SI + Sub DX, BX ; DX = count of sysex bytes + Mov [BX], DL + Mov InSysex, 0 + + Jmp BufferMIDIOutput1 + +BufferMIDINoSysex: + Cmp Countdown, 0 + JNE BufferMIDIOutput1 + + Cmp AL, 0F0h + JA BufferMIDIOutput2 + +; Delta time required + + Xor EDX, EDX + Mov EBX, AccumulatedTime + Mov CX, 4 + Mov AccumulatedTime, EDX + +DeltaTimeOutput1: + ShL EDX, 8 + Mov DL, BL + Or DL, 80h + ShR EBX, 7 + LoopNZ DeltaTimeOutput1 + ; EDX = output bytes, DL = most signif + +DeltaTimeOutput2: + Mov [SI], DL + Inc SI + ShR EDX, 8 + JNZ DeltaTimeOutput2 + + And Byte Ptr [SI-1], 7Fh + + Xor BX, BX + Xor DL, DL + Test AL, AL + JNS BufferMIDINoStatus + Cmp AL, 0F0h + JE BufferMIDISysex + + Mov StatusByte, AL + Inc DX + Jmp BufferMIDINoStatus + +BufferMIDISysex: + Mov [SI], AL + Inc SI + Mov InSysex, SI + Jmp BufferMIDIOutput1 + +BufferMIDINoStatus: + Mov BL, StatusByte + ShR BX, 4 + Sub BL, 8 + JC BufferMIDIOutput1 + + Add DL, [StatusByteLUT+BX] + Mov Countdown, DL + +BufferMIDIOutput1: + Mov [SI], AL + Inc SI + Dec Countdown + + Mov MIDIBufferOffset, SI + + Cmp SI, Offset MIDIBuffer+200 + JB BufferMIDIOutput2 + Cmp InSysex, 0 + JNE BufferMIDIOutput2 + + Call WriteMIDIBlock + +BufferMIDIOutput2: + Pop DS + PopAD + + Ret + +EndP BufferMIDIOutput + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call BufferMIDIOutput + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Call BufferMIDIOutput + + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 32 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 1 +DefaultChannels DW 32 +DriverFlags DW 1 ; Supports MIDI Out. + + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/MIDIDRV.ASM b/it/SoundDrivers/MIDIDRV.ASM new file mode 100755 index 0000000..bcc2a53 --- /dev/null +++ b/it/SoundDrivers/MIDIDRV.ASM @@ -0,0 +1,525 @@ +; +; MIDI MPU401 Driver for Impulse Tracker. +; Accepts MIDI Input, does MIDI output, but does NOT handle samples at all. +; + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +OldIRQHandler DD 0 +MIDIUpdateTimer DW 0 +MIDIUpdateCount DW 0 +MIDIUpdateFlag DB 0 +MIDIDriverMsg DB "MPU401 or compatible detected", 13 + DB "Address ", 0FDh, "Xh", 0 +MIDIReinitMsg DB "MPU401 reinitialised", 0 + +; + +Proc ResetUART ; Given DX = port. + + ClI + + Inc DX + + Xor CX, CX + +ResetUART1: + In AL, DX + Test AL, 40h + LoopNZ ResetUART1 + JNZ ResetUARTFailed + + Mov AL, 0FFh + Out DX, AL + + Xor CX, CX + +ResetUART2: + In AL, DX + Test AL, 80h + LoopNZ ResetUART2 + JNZ ResetUARTFailed + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JNE ResetUART2 + + Dec DX + + DB 85h + +ResetUARTFailed: + StC + Ret + +EndP ResetUART + +; + +Proc SetUARTMode + + Mov DX, CS:BasePort + Inc DX + + Xor CX, CX + +SetUARTMode1: + In AL, DX + Test AL, 40h + LoopNZ SetUARTMode1 + JNZ SetUARTModeFailed + + Mov AL, 3Fh + Out DX, AL + + Xor CX, CX + +SetUARTMode2: + In AL, DX + Test AL, 80h + LoopNZ SetUARTMode2 + JNZ SetUARTModeFailed + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JNE SetUARTMode2 + Dec DX + + DB 85h + +SetUARTModeFailed: + StC + StI + Ret + +EndP SetUARTMode + +; + +Proc UARTOut ; AL = byte out + + Push CX + Push DX + Mov DX, CS:Baseport + + Push AX + Xor CX, CX + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + LoopNZ UARTOut1 + + Pop AX + JNZ UARTOutEnd + + Dec DX + Out DX, AL + +UARTOutEnd: + Pop DX + Pop CX + + Ret + +EndP UARTOut + +; + +InterpretState DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + JE SendUARTOutStateInc + + Mov CS:InterpretState, 0 + +SendUARTOut4: + Ret + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +Proc MIDIIRQHandler + + PushAD + + Mov AX, MIDIUpdateTimer + Add MIDIUpdateCount, AX + JC MIDIIRQHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp MIDIIRQHandler2 + +MIDIIRQHandler1: + PushF + Call [OldIRQHandler] + +MIDIIRQHandler2: + Xor MIDIUpdateFlag, 1 + JZ MIDIIRQHandlerEnd + + Push DS + Push ES + + ClD + + Call SaveEMSPageFrame + Call Update ; Returns DS:SI, CX + +; Have to clear any sample channels playing. +; Kill any active channel + +MIDIIRQHandler3: + Test Byte Ptr [SI], 1 ; Channel on? + JZ MIDIIRQHandler4 + + Mov Word Ptr [SI], 0 + + Test Byte Ptr [SI+3Ah], 80h + JNZ MIDIIRQHandler4 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + +MIDIIRQHandler4: + Add SI, 128 + Dec CX + JNZ MIDIIRQHandler3 + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + +MIDIIRQHandlerEnd: + PopAD + IRet + +EndP MIDIIRQHandler + +; + +Proc SetIRQ + + Mov AL, 34h + Out 43h, AL + + Xor AX, AX + Mov ES, AX + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset MIDIIRQHandler + Mov [ES:20h], EAX + + Ret + +EndP SetIRQ + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Mov DX, CS:BasePort + Cmp DX, 0FFFFh + JNE DetectCard1 + + Mov DX, 330h + Call ResetUART + JNC DetectCard2 + + Mov DX, 300h + +DetectCard1: + Call ResetUART + +DetectCard2: + Mov CS:BasePort, DX + Mov EAX, 'Jeff' + Ret + +EndP DetectCard + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + Mov EAX, [ES:20h] + Mov OldIRQHandler, EAX + Call SetIRQ + + Call SetUARTMode + + Mov SI, Offset MIDIDriverMsg + Mov AX, BasePort + + ClC + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset MIDIReinitMsg + Mov BX, 40 + Call SetInfoLine + + Mov DX, BasePort + Call ResetUART + + Call SetIRQ + Call SetUARTMode + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov DX, CS:BasePort + Call ResetUART + + Xor AX, AX + Mov ES, AX + Mov EAX, CS:OldIRQHandler + Mov [ES:20h], EAX + + Xor AL, AL + Out 40h, AL ; Timer IRQ. + Out 40h, AL + + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + ClI + + Call [UARTBufferEmpty] + JC Poll1 + +PollEnd: + StI + Ret + +Poll1: + Mov DX, BasePort + Inc DX + + In AL, DX + Test AL, AL + JS PollEnd + + Dec DX + In AL, DX + + Call [CS:UARTSend] + Jmp Poll + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + ; Frames per second = 2 * (0.4*Tempo) + Mov AX, 0C214h + Mov DX, 16h ; Ticks = (1193181/(2*0.4))/Tempo + Div BX + + ; AX contains counter. + Mov CS:MIDIUpdateTimer, AX + + Out 40h, AL ; Timer IRQ. + Mov AL, AH + Out 40h, AL + +SetTempo2: + Pop DX + Pop BX + Pop AX + Ret + +EndP SetTempo + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Xor AX, AX + StC + Ret + +EndP SoundCardScreen + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 64 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 64 +DriverFlags DW 1 ; Handles MIDI Output + + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SoundCardScreen ; SetMixVolume + DW Offset SoundCardScreen ; SetStereo + + DW Offset SoundCardScreen ; LoadSample + DW Offset SoundCardScreen ; ReleaseSample + DW Offset SoundCardScreen ; ResetMemory + + DW Offset SoundCardScreen ; GetStatus + DW Offset SoundCardScreen ; SoundCardScreen + DW Offset SoundCardScreen ; GetVariable + DW Offset SoundCardScreen ; SetVariable + + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/MIW.BAT b/it/SoundDrivers/MIW.BAT new file mode 100755 index 0000000..61058f7 --- /dev/null +++ b/it/SoundDrivers/MIW.BAT @@ -0,0 +1,4 @@ +tasm /m /uT310 iwdrv +tlink /3 iwdrv +execom iwdrv itiw.drv +copy itiw.drv .. diff --git a/it/SoundDrivers/MIX.INC b/it/SoundDrivers/MIX.INC new file mode 100755 index 0000000..d11f1a9 --- /dev/null +++ b/it/SoundDrivers/MIX.INC @@ -0,0 +1,1014 @@ + + +ERROR EQU CX +DELTAERROR EQU BP +DELTAOFFSET EQU DX +OLDPOSITION EQU [SI+2Ch] +CURRENTPOSITION EQU [SI+4Ch] +CURRENTPOSITIONERROR EQU Word Ptr [SI+48h] +LOOPSTART EQU [SI+40h] +LOOPEND EQU [SI+44h] +STEPVALUE EQU [SI+02h] +; STEPVALUEHIGH EQU Word Ptr [SI+04h] +DIRECTIONFLAG EQU Byte Ptr [SI+0Bh] + +EXTRAOFFSET = MixResolution/8-2 + +IF MIXRESOLUTION GT 16 + RESOLUTIONSHIFT = 2 +ELSE + RESOLUTIONSHIFT = 1 +ENDIF + +IF STEREOENABLED + RESOLUTIONSHIFT = RESOLUTIONSHIFT+1 +ENDIF + +MixBufferOffset DW 0 + +MixBlockSize DW 0 ; Number of bytes to mix + DW 0 ; High order 0 + +PreMixFunction DW 0 +MixFunctionSeparate DW 0 ; Function to separate blocks into 64k + ; chunks. +MixFunctionSeparateBackwards DW 0 ; function to separate blocks into 64k + ; in backwards steps. +MixFunction DW 0 ; Function to mix samples + +LastPage DW 0 + +MemoryType DB 0 +NumPages DB 0 +SampleLocation DW 0 ; Either EMS Handle or Conventional + ; base segment +EMSPageFrame DW 0 + +LoopCounter DW 0 + +; + +Proc MixNoLoop + + Call [PreMixFunction] + Call PrepareSampleSegment + + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + + Xor CX, CX + Mov EBX, LOOPEND + Sub CX, CURRENTPOSITIONERROR + SBB EBX, CURRENTPOSITION ; EBX.CX = (End-CurrentPosition) + JC MixNoLoop3 + + Cmp EDX, EBX + JL MixNoLoop1 + JG MixNoLoop2 + Cmp AX, CX + JB MixNoLoop1 + +MixNoLoop2: + ; Turn off + Mov EDX, EBX + Mov AX, CX + + Mov Word Ptr [SI], 200h + Test Byte Ptr [SI+3Ah], 80h + JNZ MixNoLoop1 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + +MixNoLoop1: + Jmp [MixFunctionSeparate] + +MixNoLoop3: + Mov Word Ptr [SI], 200h + Test Byte Ptr [SI+3Ah], 80h + JNZ MixNoLoop4 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + +MixNoLoop4: + Ret + +EndP MixNoLoop + +; + +Proc MixForwardsLoop + + Call [PreMixFunction] + Call PrepareSampleSegment + +MixForwardsLoopAgain: + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + + Xor CX, CX + Mov EBX, LOOPEND + Sub CX, CURRENTPOSITIONERROR + SBB EBX, CURRENTPOSITION ; EBX.CX = (End-CurrentPosition) + JC UpdateMixForwardsLoop + + Cmp EDX, EBX + JL MixForwardsLoop1 + JG MixForwardsLoop2 + Cmp AX, CX + JB MixForwardsLoop1 + +MixForwardsLoop2: + Mov EDX, EBX + Mov AX, CX + + Call [MixFunctionSeparate] + +UpdateMixForwardsLoop: + Mov EAX, CURRENTPOSITION + Xor EDX, EDX + + Mov EBX, LOOPEND + SUB EAX, EBX + SUB EBX, LOOPSTART + JBE MixForwardsLoop3 + + Div EBX + Add EDX, LOOPSTART + Mov CURRENTPOSITION, EDX + +; Cmp EBX, 10000h +; JAE MixForwardsLoop4 + +; Mov AX, STEPVALUEHIGH +; Cmp AX, BX +; JAE MixForwardsLoop5 + +; MixForwardsLoop4: + Cmp MixBlockSize, 0 + JG MixForwardsLoopAgain + +MixForwardsLoop3: + Ret + +; MixForwardsLoop5: +; Xor DX, DX +; Div BX +; Mov STEPVALUEHIGH, DX + +; Cmp MixBlockSize, 0 +; JG MixForwardsLoopAgain + +; Ret + +MixForwardsLoop1: + Jmp [MixFunctionSeparate] + +EndP MixForwardsLoop + +; + +Proc MixPingPongLoop + + Call [PreMixFunction] + Call PrepareSampleSegment + +MixPingPongLoopAgain: + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + + Cmp DIRECTIONFLAG, 0 + JNE MixPingPongLoopBackwards1 + +MixPingPongLoopForwards1: + Xor CX, CX + Mov EBX, LOOPEND + Sub CX, CURRENTPOSITIONERROR + SBB EBX, CURRENTPOSITION ; EBX.CX = (End-CurrentPosition) + JC UpdateMixPingPongLoopForwards1 + + Cmp EDX, EBX + JG MixPingPongLoopForwards3 + JL MixPingPongLoopForwards2 + + Cmp AX, CX + JAE MixPingPongLoopForwards3 + +MixPingPongLoopForwards2: + Jmp [MixFunctionSeparate] + +MixPingPongLoopForwards3: + Mov EDX, EBX + Mov AX, CX + Call [MixFunctionSeparate] + +UpdateMixPingPongLoopForwards1: + Mov EAX, CURRENTPOSITION + Mov EBX, LOOPEND + Xor EDX, EDX + Sub EAX, EBX + Sub EBX, LOOPSTART + JBE MixPingPongError + + Add EBX, EBX + Div EBX + + ShR EBX, 1 + + Cmp EDX, EBX + JAE MixPingPongLoopForwards4 + + Mov DIRECTIONFLAG, 1 + Mov EAX, LOOPEND + Sub EAX, EDX + Dec EAX + Mov CURRENTPOSITION, EAX + Neg Word Ptr CURRENTPOSITIONERROR + Jmp MixPingPongLoopNext + +MixPingPongLoopForwards4: + Sub EDX, EBX + Add EDX, LOOPSTART + Mov CURRENTPOSITION, EDX + Jmp MixPingPongLoopNext + +MixPingPongLoopBackwards1: + Mov EBX, CURRENTPOSITION + Mov CX, CURRENTPOSITIONERROR + + Sub CX, 0FFFFh + SBB EBX, LOOPSTART + JC UpdateMixPingPongLoopBackwards1 + + Cmp EDX, EBX + JG MixPingPongLoopBackwards3 + JL MixPingPongLoopBackwards2 + + Cmp AX, CX + JAE MixPingPongLoopBackwards3 + +MixPingPongLoopBackwards2: + Call [MixFunctionSeparateBackwards] + +MixPingPongError: + Ret + +MixPingPongLoopBackwards3: + Mov EDX, EBX + Mov AX, CX + Call [MixFunctionSeparateBackwards] + +UpdateMixPingPongLoopBackwards1: + Mov EBX, LOOPEND + Mov EAX, LOOPSTART + Sub EBX, EAX + JBE MixPingPongError + + Sub EAX, CURRENTPOSITION + Xor EDX, EDX + Add EBX, EBX + Div EBX + + ShR EBX, 1 + + Cmp EDX, EBX + JAE MixPingPongLoopBackwards4 + + Mov DIRECTIONFLAG, 0 + Add EDX, LOOPSTART + Mov CURRENTPOSITION, EDX + Neg Word Ptr CURRENTPOSITIONERROR + Jmp MixPingPongLoopNext + +MixPingPongLoopBackwards4: + Sub EBX, EDX + Add EBX, LOOPEND + Dec EBX + Mov CURRENTPOSITION, EBX + +MixPingPongLoopNext: + Cmp MixBlockSize, 0 + JG MixPingPongLoopAgain + + Ret + +EndP MixPingPongLoop + +; + +Proc UpdateNoLoop + + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + Add CURRENTPOSITIONERROR, AX + AdC EDX, CURRENTPOSITION + + Cmp EDX, LOOPEND + JL UpdateNoLoop1 + +UpdateNoLoop2: ; Turn off + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ UpdateNoLoop1 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + Ret + +UpdateNoLoop1: + Mov CURRENTPOSITION, EDX + + Ret + +EndP UpdateNoLoop + +; + +Proc UpdateForwardsLoop + + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + Add CURRENTPOSITIONERROR, AX + AdC EDX, CURRENTPOSITION + + Cmp EDX, LOOPEND + JL UpdateForwardsLoop1 + +UpdateForwardsLoop2: ; Reset position... + Mov EBX, LOOPEND + Mov EAX, EDX + Xor EDX, EDX + Sub EAX, EBX + Sub EBX, LOOPSTART + JZ UpdateForwardsLoop1 + Div EBX + + Add EDX, LOOPSTART + +UpdateForwardsLoop1: + Mov CURRENTPOSITION, EDX + Ret + +EndP UpdateForwardsLoop + +; + +Proc UpdatePingPongLoop + + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + + Cmp DIRECTIONFLAG, 0 + JNE UpdatePingPongLoopBackwards1 + +UpdatePingPongLoopForwards1: + Add CURRENTPOSITIONERROR, AX + AdC EDX, CURRENTPOSITION + + Cmp EDX, LOOPEND + JA UpdatePingPongLoopForwards2 + + Mov CURRENTPOSITION, EDX + Ret + +UpdatePingPongLoopForwards2: + Mov EAX, EDX + Mov EBX, LOOPEND + Xor EDX, EDX + Sub EAX, EBX + Sub EBX, LOOPSTART + Add EBX, EBX + Div EBX + + ShR EBX, 1 + + Cmp EDX, EBX + JAE UpdatePingPongLoopForwards3 + + Mov DIRECTIONFLAG, 1 + Mov EAX, LOOPEND + Sub EAX, EDX + Dec EAX + NEG CURRENTPOSITIONERROR + Mov CURRENTPOSITION, EAX + Ret + +UpdatePingPongLoopForwards3: + Sub EDX, EBX + Add EDX, LOOPSTART + Mov CURRENTPOSITION, EDX + Ret + +UpdatePingPongLoopBackwards1: + Sub CURRENTPOSITIONERROR, AX + Mov ECX, CURRENTPOSITION + SBB ECX, EDX + + Cmp ECX, LOOPSTART + JLE UpdatePingPongLoopBackwards2 + + Mov CURRENTPOSITION, ECX + Ret + +UpdatePingPongLoopBackwards2: + Mov EAX, LOOPSTART + Mov EBX, LOOPEND + Xor EDX, EDX + Sub EBX, EAX + Sub EAX, ECX + Add EBX, EBX + Div EBX + + ShR EBX, 1 + + Cmp EDX, EBX + JAE UpdatePingPongLoopBackwards3 + + Mov DIRECTIONFLAG, 0 + Add EDX, LOOPSTART + NEG CURRENTPOSITIONERROR + Mov CURRENTPOSITION, EDX + Ret + +UpdatePingPongLoopBackwards3: + Sub EBX, EDX + Add EBX, LOOPEND + Dec EBX + Mov CURRENTPOSITION, EBX + + Ret + +EndP UpdatePingPongLoop + +; + +Proc PrepareSampleSegment ; Sets up sample mixing segment + + Mov ES, SongDataArea + + Mov BX, [SI+34h] + Mov EAX, [ES:BX+48h] + + Mov DWord Ptr MemoryType, EAX ; Writes numpages & Sample + ; location also. + Mov LastPage, 0FFFFh + + Ret + +EndP PrepareSampleSegment + +; + +Proc SetSampleSegment ; Given EDI, Returns ES + + Mov CX, Word Ptr CS:MemoryType + + Cmp CL, 2 + JNE SetSampleSegment1 + + Push EAX + Push EDX + + Mov EBX, EDI + ShR EBX, 14 + And EDI, 16383 + + Cmp BX, LastPage + JE SetSampleEMS2 + + Mov LastPage, BX + Mov DX, SampleLocation ; EMS handle + ; BX = starting page required + Mov AL, 3 + Add BX, 3 + + Cmp BL, CH + JBE SetSampleEMS1 + + Sub CH, BL + Add BL, CH + Add AL, CH + JNC SetSampleEMS2 + +SetSampleEMS1: + Mov AH, 44h + Int 67h + + Dec BX + Dec AL + JNS SetSampleEMS1 + +SetSampleEMS2: + Mov ES, EMSPageFrame + + Pop EDX + Pop EAX + + Ret + +SetSampleSegment1: ; Conventional memory + Mov ECX, EDI + And EDI, 15 + ShR ECX, 4 + Add CX, SampleLocation + Mov ES, CX + + Ret + +EndP SetSampleSegment + +; + +Proc SetBackSampleSegment ; Given BX = frame, Returns ES + + Mov CX, Word Ptr CS:MemoryType + + Cmp CL, 2 + JNE SetBackSampleSegment1 + + Push EAX + Push EDX + + Cmp BX, LastPage + JE SetBackSampleEMS2 + + Mov LastPage, BX + Mov DX, SampleLocation ; EMS handle + ; BX = starting page required + Mov AL, 3 + Add BX, 3 + + Cmp BL, CH + JBE SetBackSampleEMS1 + + Sub CH, BL + Add BL, CH + Add AL, CH + JNC SetBackSampleEMS2 + +SetBackSampleEMS1: + Mov AH, 44h + Int 67h + + Dec BX + Dec AL + JNS SetBackSampleEMS1 + +SetBackSampleEMS2: + Mov ES, EMSPageFrame + + Pop EDX + Pop EAX + + Ret + +SetBackSampleSegment1: ; Conventional memory + ShL BX, 10 + Add BX, SampleLocation + Mov ES, BX + + Ret + +EndP SetBackSampleSegment + +; + +Proc MFS8Bit ; EDX:AX = 32.16 bytes offset. + ; to mix + + + Push AX + Push EDX + + Mov EDI, CURRENTPOSITION + Call SetSampleSegment + + Xor CX, CX ; EDI = CurrentPosition & (2^14-1) + + Mov EBX, 0FFFEh + + Sub CX, CURRENTPOSITIONERROR + SBB EBX, EDI + ; EBX:CX = 64k-(CurrentPosition & (2^14-1)) + ; EDX:AX = blocksize + Cmp EDX, EBX + JBE MFS8Bit1 + + Mov EDX, EBX + Mov AX, CX + +MFS8Bit1: + ; Now to calculate bytes to mix... + ShL EAX, 16 + SHRD EAX, EDX, 16 + ShR EDX, 16 ; EDX:EAX = (16)32.16 offset + + Mov EBX, STEPVALUE + Cmp EDX, EBX + JAE MFS8Bit2 + + Div EBX + Add EDX, 0FFFFFFFFh + AdC EAX, 0 ; EAX = no of bytes to mix + JZ MFS8Bit2 + + Push EAX + + Xor ECX, ECX + Mov DELTAOFFSET, [SI+4] ; Stepvalue + Mov DELTAERROR, [SI+2] ; Stepvalue + Mov CX, CURRENTPOSITIONERROR + + Push DS + Push SI + + Mov SI, MixBufferOffset + Mov DS, MixSegment + Call [MixFunction] + + Pop SI + Pop DS + Pop ECX + Jmp MFS8Bit3 + +MFS8Bit2: +; Xor ECX, ECX + Pop EDX + Pop AX + + Ret + +MFS8Bit3: + ; Update pointers... + Mov EAX, STEPVALUE + Mul ECX + + Sub MixBlockSize, CX + ShL CX, RESOLUTIONSHIFT + Add MixBufferOffset, CX + + ; EDX:EAX = offset mixed (32.16) + ShLD EDX, EAX, 16 + Mov BX, AX + Mov ECX, EDX ; ECX:BX = offset mixed + + Add CURRENTPOSITIONERROR, BX + AdC CURRENTPOSITION, ECX + + Pop EDX + Pop AX + + Sub AX, BX + SBB EDX, ECX + + JG MFS8Bit + + Ret + +EndP MFS8Bit + +; + +Proc MFS16Bit + + Push AX + Push EDX + + Mov EDI, CURRENTPOSITION + Add EDI, EDI + Call SetSampleSegment + + ShR EDI, 1 ; EDI = number of samples. + + Xor CX, CX + + Mov EBX, 7FFEh + + Sub CX, CURRENTPOSITIONERROR + SBB EBX, EDI + + Cmp EDX, EBX + JBE MFS16Bit1 + + Mov EDX, EBX + Mov AX, CX + +MFS16Bit1: + ; Now to calculate bytes to mix... + ShL EAX, 16 + SHRD EAX, EDX, 16 + ShR EDX, 16 ; EDX:EAX = (16)32.16 offset + + Mov EBX, STEPVALUE + Cmp EDX, EBX + JAE MFS16Bit2 + + Div EBX + Add EDX, 0FFFFFFFFh + AdC EAX, 0 ; EAX = no of bytes to mix + JZ MFS16Bit2 + + Push EAX + + Xor ECX, ECX + Mov DELTAOFFSET, [SI+4] ; Stepvalue + Mov DELTAERROR, [SI+2] ; Stepvalue + Mov CX, CURRENTPOSITIONERROR + + Push DS + Push SI + + Mov SI, MixBufferOffset + Mov DS, MixSegment + Call [MixFunction] + + Pop SI + Pop DS + Pop ECX + Jmp MFS16Bit3 + +MFS16Bit2: +; Xor ECX, ECX + Pop EDX + Pop AX + Ret + +MFS16Bit3: + ; Update pointers... + Mov EAX, STEPVALUE + Mul ECX + + Sub MixBlockSize, CX + ShL CX, RESOLUTIONSHIFT + Add MixBufferOffset, CX + + ; EDX:EAX = offset mixed (32.16) + ShLD EDX, EAX, 16 + Mov BX, AX + Mov ECX, EDX ; ECX:BX = offset mixed + + Add CURRENTPOSITIONERROR, BX + AdC CURRENTPOSITION, ECX + + Pop EDX + Pop AX + + Sub AX, BX + SBB EDX, ECX + + JG MFS16Bit + + Ret + +EndP MFS16Bit + +; + +Proc MBS8Bit + + Push AX + Push EDX ; EDX:AX = 32.16 blocksize + + Mov EDI, CURRENTPOSITION + Mov EBX, EDI + Add EBX, 2 + ShR EBX, 14 ; BX = frame + + Sub BX, 3 + JNC MBS8Bit4 + + Xor BX, BX + +MBS8Bit4: + Mov ECX, EBX + ShL ECX, 14 + Sub EDI, ECX + + Call SetBackSampleSegment + + Mov ECX, CURRENTPOSITION + Mov BX, CURRENTPOSITIONERROR + And ECX, 16383 + Add ECX, 0BFFEh + Cmp ECX, EDX + JG MBS8Bit1 + JL MBS8Bit5 + Cmp BX, AX + JG MBS8Bit1 + +MBS8Bit5: + Mov EDX, ECX + Mov AX, BX + +MBS8Bit1: + + ; Now to calculate bytes to mix... + ShL EAX, 16 + SHRD EAX, EDX, 16 + ShR EDX, 16 ; EDX:EAX = (16)32.16 offset + + Mov EBX, STEPVALUE + Cmp EDX, EBX + JAE MBS8Bit2 + + Div EBX + Add EDX, 0FFFFFFFFh + AdC EAX, 0 ; EAX = no of bytes to mix + JZ MBS8Bit2 + + Push EAX + + Xor ECX, ECX + Mov EBP, [SI+2] ; Stepvalue + Neg EBP + ShLD EDX, EBP, 16 + + Mov CX, CURRENTPOSITIONERROR + + Push DS + Push SI + + Mov SI, MixBufferOffset + Mov DS, MixSegment + Call [MixFunction] + + Pop SI + Pop DS + Pop ECX + Jmp MBS8Bit3 + +MBS8Bit2: +; Xor ECX, ECX + Pop EDX + Pop AX + Ret + +MBS8Bit3: + ; Update pointers... + Mov EAX, STEPVALUE + Mul ECX + + Sub MixBlockSize, CX + ShL CX, RESOLUTIONSHIFT + Add MixBufferOffset, CX + + ; EDX:EAX = offset mixed (32.16) + ShLD EDX, EAX, 16 + Mov BX, AX + Mov ECX, EDX ; ECX:BX = offset mixed + + Sub CURRENTPOSITIONERROR, BX + SBB CURRENTPOSITION, ECX + + Pop EDX + Pop AX + + Sub AX, BX + SBB EDX, ECX + + JG MBS8Bit + + Ret + +EndP MBS8Bit + +; + +Proc MBS16Bit + + Push AX + Push EDX ; EDX:AX = 32.16 blocksize + + Mov EDI, CURRENTPOSITION + Mov EBX, EDI + Add EBX, 4 + ShR EBX, 13 ; BX = frame + + Sub BX, 3 + JNC MBS16Bit4 + + Xor BX, BX + +MBS16Bit4: + Mov ECX, EBX + ShL ECX, 13 + Sub EDI, ECX + + Call SetBackSampleSegment + + Mov ECX, CURRENTPOSITION + Mov BX, CURRENTPOSITIONERROR + And ECX, 8191 + Add ECX, 05FFEh + Cmp ECX, EDX + JG MBS16Bit1 + JL MBS16Bit5 + Cmp BX, AX + JG MBS16Bit1 + +MBS16Bit5: + Mov EDX, ECX + Mov AX, BX + +MBS16Bit1: + + ; Now to calculate bytes to mix... + ShL EAX, 16 + SHRD EAX, EDX, 16 + ShR EDX, 16 ; EDX:EAX = (16)32.16 offset + + Mov EBX, STEPVALUE + Cmp EDX, EBX + JAE MBS16Bit2 + + Div EBX + Add EDX, 0FFFFFFFFh + AdC EAX, 0 ; EAX = no of bytes to mix + JZ MBS16Bit2 + + Push EAX + + Xor ECX, ECX + Mov EBP, [SI+2] ; Stepvalue + Neg EBP + ShLD EDX, EBP, 16 + + Mov CX, CURRENTPOSITIONERROR + + Push DS + Push SI + + Mov SI, MixBufferOffset + Mov DS, MixSegment + Call [MixFunction] + + Pop SI + Pop DS + Pop ECX + Jmp MBS16Bit3 + +MBS16Bit2: +; Xor ECX, ECX + Pop EDX + Pop AX + Ret + +MBS16Bit3: + ; Update pointers... + Mov EAX, STEPVALUE + Mul ECX + + Sub MixBlockSize, CX + ShL CX, RESOLUTIONSHIFT + Add MixBufferOffset, CX + + ; EDX:EAX = offset mixed (32.16) + ShLD EDX, EAX, 16 + Mov BX, AX + Mov ECX, EDX ; ECX:BX = offset mixed + + Sub CURRENTPOSITIONERROR, BX + SBB CURRENTPOSITION, ECX + + Pop EDX + Pop AX + + Sub AX, BX + SBB EDX, ECX + + JG MBS16Bit + + Ret + +EndP MBS16Bit + +; + +Proc ReportError + + Ret + +EndP ReportError + +; + diff --git a/it/SoundDrivers/MIXWAV.INC b/it/SoundDrivers/MIXWAV.INC new file mode 100755 index 0000000..cb2045e --- /dev/null +++ b/it/SoundDrivers/MIXWAV.INC @@ -0,0 +1,1065 @@ + + +ERROR EQU CX +DELTAERROR EQU BP +DELTAOFFSET EQU DX +OLDPOSITION EQU [SI+2Ch] +CURRENTPOSITION EQU [SI+4Ch] +CURRENTPOSITIONERROR EQU Word Ptr [SI+48h] +LOOPSTART EQU [SI+40h] +LOOPEND EQU [SI+44h] +STEPVALUE EQU [SI+02h] +; STEPVALUEHIGH EQU Word Ptr [SI+04h] +DIRECTIONFLAG EQU Byte Ptr [SI+0Bh] + +EXTRAOFFSET = MixResolution/8-2 + +IF MIXRESOLUTION GT 16 + RESOLUTIONSHIFT = 2 +ELSE + RESOLUTIONSHIFT = 1 +ENDIF + +IF STEREOENABLED + RESOLUTIONSHIFT = RESOLUTIONSHIFT+1 +ENDIF + +MixBufferOffset DW 0 + +MixBlockSize DW 0 ; Number of bytes to mix + DW 0 ; High order 0 + +PreMixFunction DW 0 +MixFunctionSeparate DW 0 ; Function to separate blocks into 64k + ; chunks. +MixFunctionSeparateBackwards DW 0 ; function to separate blocks into 64k + ; in backwards steps. +MixFunction DW 0 ; Function to mix samples + +LastPage DW 0 + +MemoryType DB 0 +NumPages DB 0 +SampleLocation DW 0 ; Either EMS Handle or Conventional + ; base segment +EMSPageFrame DW 0 + +LoopCounter DW 0 + +; + +Proc MixNoLoop + + Call [PreMixFunction] + Call PrepareSampleSegment + + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + + Xor CX, CX + Mov EBX, LOOPEND + Sub CX, CURRENTPOSITIONERROR + SBB EBX, CURRENTPOSITION ; EBX.CX = (End-CurrentPosition) + JC MixNoLoopEnd + + Cmp EDX, EBX + JL MixNoLoop1 + JG MixNoLoop2 + Cmp AX, CX + JAE MixNoLoop2 + +MixNoLoop1: + Jmp [MixFunctionSeparate] + +MixNoLoop2: ; Turn off + Mov EDX, EBX + Mov AX, CX + + Call [MixFunctionSeparate] + +MixNoLoop3: + Mov Word Ptr [SI], 200h + Test Byte Ptr [SI+3Ah], 80h + JNZ MixNoLoop4 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + +MixNoLoop4: + PushAD + Push DS + + Mov EDX, CS:LastLeftValue + Mov EDI, CS:LastRightValue + +IF USECLICKFADETHRESHHOLD + Cmp EDX, CLICKFADETHRESHHOLD + JBE NoClickRemovalLeft + + Xor EDX, EDX + +NoClickRemovalLeft: + Cmp EDI, CLICKFADETHRESHHOLD + JBE NoClickRemovalRight + + Xor EDI, EDI + +NoClickRemovalRight: +ENDIF + Neg EDX + Neg EDI + + Mov CX, CS:MixBlockSize + Mov SI, CS:MixBufferOffset + Mov DS, CS:MixSegment + JCXZ MixNoLoopClickRemovalEnd + +MixNoLoopClickRemoval1: + Mov EAX, EDX + Mov EBX, EDI + + Add [SI], EDX + Add [SI+4], EDI + + SAR EAX, 12 + SAR EBX, 12 + + Sub EAX, 1 + AdC EAX, 1 + Sub EBX, 1 + AdC EBX, 1 + + Sub EDX, EAX + Sub EDI, EBX + + Add SI, 8 + Loop MixNoLoopClickRemoval1 + +MixNoLoopClickRemovalEnd: + Add CS:LastClickRemovalLeft, EDX + Add CS:LastClickRemovalRight, EDI + + Pop DS + PopAD + +MixNoLoopEnd: + Ret + +EndP MixNoLoop + +; + +Proc MixForwardsLoop + + Call [PreMixFunction] + Call PrepareSampleSegment + +MixForwardsLoopAgain: + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + + Xor CX, CX + Mov EBX, LOOPEND + Sub CX, CURRENTPOSITIONERROR + SBB EBX, CURRENTPOSITION ; EBX.CX = (End-CurrentPosition) + JC UpdateMixForwardsLoop + + Cmp EDX, EBX + JL MixForwardsLoop1 + JG MixForwardsLoop2 + Cmp AX, CX + JB MixForwardsLoop1 + +MixForwardsLoop2: + Mov EDX, EBX + Mov AX, CX + + Call [MixFunctionSeparate] + +UpdateMixForwardsLoop: + Mov EAX, CURRENTPOSITION + Xor EDX, EDX + + Mov EBX, LOOPEND + SUB EAX, EBX + SUB EBX, LOOPSTART + JBE MixForwardsLoop3 + + Div EBX + Add EDX, LOOPSTART + Mov CURRENTPOSITION, EDX + +; Cmp EBX, 10000h +; JAE MixForwardsLoop4 + +; Mov AX, STEPVALUEHIGH +; Cmp AX, BX +; JAE MixForwardsLoop5 + +; MixForwardsLoop4: + Cmp MixBlockSize, 0 + JG MixForwardsLoopAgain + +MixForwardsLoop3: + Ret + +; MixForwardsLoop5: +; Xor DX, DX +; Div BX +; Mov STEPVALUEHIGH, DX + +; Cmp MixBlockSize, 0 +; JG MixForwardsLoopAgain + +; Ret + +MixForwardsLoop1: + Jmp [MixFunctionSeparate] + +EndP MixForwardsLoop + +; + +Proc MixPingPongLoop + + Call [PreMixFunction] + Call PrepareSampleSegment + +MixPingPongLoopAgain: + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + + Cmp DIRECTIONFLAG, 0 + JNE MixPingPongLoopBackwards1 + +MixPingPongLoopForwards1: + Xor CX, CX + Mov EBX, LOOPEND + Sub CX, CURRENTPOSITIONERROR + SBB EBX, CURRENTPOSITION ; EBX.CX = (End-CurrentPosition) + JC UpdateMixPingPongLoopForwards1 + + Cmp EDX, EBX + JG MixPingPongLoopForwards3 + JL MixPingPongLoopForwards2 + + Cmp AX, CX + JAE MixPingPongLoopForwards3 + +MixPingPongLoopForwards2: + Jmp [MixFunctionSeparate] + +MixPingPongLoopForwards3: + Mov EDX, EBX + Mov AX, CX + Call [MixFunctionSeparate] + +UpdateMixPingPongLoopForwards1: + Mov EAX, CURRENTPOSITION + Mov EBX, LOOPEND + Xor EDX, EDX + Sub EAX, EBX + Sub EBX, LOOPSTART + JBE MixPingPongError + + Add EBX, EBX + Div EBX + + ShR EBX, 1 + + Cmp EDX, EBX + JAE MixPingPongLoopForwards4 + + Mov DIRECTIONFLAG, 1 + Mov EAX, LOOPEND + Sub EAX, EDX + Dec EAX + Mov CURRENTPOSITION, EAX + Neg Word Ptr CURRENTPOSITIONERROR + Jmp MixPingPongLoopNext + +MixPingPongLoopForwards4: + Sub EDX, EBX + Add EDX, LOOPSTART + Mov CURRENTPOSITION, EDX + Jmp MixPingPongLoopNext + +MixPingPongLoopBackwards1: + Mov EBX, CURRENTPOSITION + Mov CX, CURRENTPOSITIONERROR + + Sub CX, 0FFFFh + SBB EBX, LOOPSTART + JC UpdateMixPingPongLoopBackwards1 + + Cmp EDX, EBX + JG MixPingPongLoopBackwards3 + JL MixPingPongLoopBackwards2 + + Cmp AX, CX + JAE MixPingPongLoopBackwards3 + +MixPingPongLoopBackwards2: + Call [MixFunctionSeparateBackwards] + +MixPingPongError: + Ret + +MixPingPongLoopBackwards3: + Mov EDX, EBX + Mov AX, CX + Call [MixFunctionSeparateBackwards] + +UpdateMixPingPongLoopBackwards1: + Mov EBX, LOOPEND + Mov EAX, LOOPSTART + Sub EBX, EAX + JBE MixPingPongError + + Sub EAX, CURRENTPOSITION + Xor EDX, EDX + Add EBX, EBX + Div EBX + + ShR EBX, 1 + + Cmp EDX, EBX + JAE MixPingPongLoopBackwards4 + + Mov DIRECTIONFLAG, 0 + Add EDX, LOOPSTART + Mov CURRENTPOSITION, EDX + Neg Word Ptr CURRENTPOSITIONERROR + Jmp MixPingPongLoopNext + +MixPingPongLoopBackwards4: + Sub EBX, EDX + Add EBX, LOOPEND + Dec EBX + Mov CURRENTPOSITION, EBX + +MixPingPongLoopNext: + Cmp MixBlockSize, 0 + JG MixPingPongLoopAgain + + Ret + +EndP MixPingPongLoop + +; + +Proc UpdateNoLoop + + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + Add CURRENTPOSITIONERROR, AX + AdC EDX, CURRENTPOSITION + + Cmp EDX, LOOPEND + JL UpdateNoLoop1 + +UpdateNoLoop2: ; Turn off + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ UpdateNoLoop1 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + Ret + +UpdateNoLoop1: + Mov CURRENTPOSITION, EDX + + Ret + +EndP UpdateNoLoop + +; + +Proc UpdateForwardsLoop + + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + Add CURRENTPOSITIONERROR, AX + AdC EDX, CURRENTPOSITION + + Cmp EDX, LOOPEND + JL UpdateForwardsLoop1 + +UpdateForwardsLoop2: ; Reset position... + Mov EBX, LOOPEND + Mov EAX, EDX + Xor EDX, EDX + Sub EAX, EBX + Sub EBX, LOOPSTART + JZ UpdateForwardsLoop1 + Div EBX + + Add EDX, LOOPSTART + +UpdateForwardsLoop1: + Mov CURRENTPOSITION, EDX + Ret + +EndP UpdateForwardsLoop + +; + +Proc UpdatePingPongLoop + + Mov EAX, STEPVALUE ; 16.16 value + Mul DWord Ptr [MixBlockSize] ; 16.0 value + ; EDX:EAX = 32.16 value + ShLD EDX, EAX, 16 ; EDX.AX = 32.16 value. + ; EDX.AX = BytesToMix*StepValue + + Cmp DIRECTIONFLAG, 0 + JNE UpdatePingPongLoopBackwards1 + +UpdatePingPongLoopForwards1: + Add CURRENTPOSITIONERROR, AX + AdC EDX, CURRENTPOSITION + + Cmp EDX, LOOPEND + JA UpdatePingPongLoopForwards2 + + Mov CURRENTPOSITION, EDX + Ret + +UpdatePingPongLoopForwards2: + Mov EAX, EDX + Mov EBX, LOOPEND + Xor EDX, EDX + Sub EAX, EBX + Sub EBX, LOOPSTART + Add EBX, EBX + Div EBX + + ShR EBX, 1 + + Cmp EDX, EBX + JAE UpdatePingPongLoopForwards3 + + Mov DIRECTIONFLAG, 1 + Mov EAX, LOOPEND + Sub EAX, EDX + Dec EAX + NEG CURRENTPOSITIONERROR + Mov CURRENTPOSITION, EAX + Ret + +UpdatePingPongLoopForwards3: + Sub EDX, EBX + Add EDX, LOOPSTART + Mov CURRENTPOSITION, EDX + Ret + +UpdatePingPongLoopBackwards1: + Sub CURRENTPOSITIONERROR, AX + Mov ECX, CURRENTPOSITION + SBB ECX, EDX + + Cmp ECX, LOOPSTART + JLE UpdatePingPongLoopBackwards2 + + Mov CURRENTPOSITION, ECX + Ret + +UpdatePingPongLoopBackwards2: + Mov EAX, LOOPSTART + Mov EBX, LOOPEND + Xor EDX, EDX + Sub EBX, EAX + Sub EAX, ECX + Add EBX, EBX + Div EBX + + ShR EBX, 1 + + Cmp EDX, EBX + JAE UpdatePingPongLoopBackwards3 + + Mov DIRECTIONFLAG, 0 + Add EDX, LOOPSTART + NEG CURRENTPOSITIONERROR + Mov CURRENTPOSITION, EDX + Ret + +UpdatePingPongLoopBackwards3: + Sub EBX, EDX + Add EBX, LOOPEND + Dec EBX + Mov CURRENTPOSITION, EBX + + Ret + +EndP UpdatePingPongLoop + +; + +Proc PrepareSampleSegment ; Sets up sample mixing segment + + Mov ES, SongDataArea + + Mov BX, [SI+34h] + Mov EAX, [ES:BX+48h] + + Mov DWord Ptr MemoryType, EAX ; Writes numpages & Sample + ; location also. + Mov LastPage, 0FFFFh + + Ret + +EndP PrepareSampleSegment + +; + +Proc SetSampleSegment ; Given EDI, Returns ES + + Mov CX, Word Ptr CS:MemoryType + + Cmp CL, 2 + JNE SetSampleSegment1 + + Push EAX + Push EDX + + Mov EBX, EDI + ShR EBX, 14 + And EDI, 16383 + + Cmp BX, LastPage + JE SetSampleEMS2 + + Mov LastPage, BX + Mov DX, SampleLocation ; EMS handle + ; BX = starting page required + Mov AL, 3 + Add BX, 3 + + Cmp BL, CH + JBE SetSampleEMS1 + + Sub CH, BL + Add BL, CH + Add AL, CH + JNC SetSampleEMS2 + +SetSampleEMS1: + Mov AH, 44h + Int 67h + + Dec BX + Dec AL + JNS SetSampleEMS1 + +SetSampleEMS2: + Mov ES, EMSPageFrame + + Pop EDX + Pop EAX + + Ret + +SetSampleSegment1: ; Conventional memory + Mov ECX, EDI + And EDI, 15 + ShR ECX, 4 + Add CX, SampleLocation + Mov ES, CX + + Ret + +EndP SetSampleSegment + +; + +Proc SetBackSampleSegment ; Given BX = frame, Returns ES + + Mov CX, Word Ptr CS:MemoryType + + Cmp CL, 2 + JNE SetBackSampleSegment1 + + Push EAX + Push EDX + + Cmp BX, LastPage + JE SetBackSampleEMS2 + + Mov LastPage, BX + Mov DX, SampleLocation ; EMS handle + ; BX = starting page required + Mov AL, 3 + Add BX, 3 + + Cmp BL, CH + JBE SetBackSampleEMS1 + + Sub CH, BL + Add BL, CH + Add AL, CH + JNC SetBackSampleEMS2 + +SetBackSampleEMS1: + Mov AH, 44h + Int 67h + + Dec BX + Dec AL + JNS SetBackSampleEMS1 + +SetBackSampleEMS2: + Mov ES, EMSPageFrame + + Pop EDX + Pop EAX + + Ret + +SetBackSampleSegment1: ; Conventional memory + ShL BX, 10 + Add BX, SampleLocation + Mov ES, BX + + Ret + +EndP SetBackSampleSegment + +; + +Proc MFS8Bit ; EDX:AX = 32.16 bytes offset. + ; to mix + + + Push AX + Push EDX + + Mov EDI, CURRENTPOSITION + Call SetSampleSegment + + Xor CX, CX ; EDI = CurrentPosition & (2^14-1) + + Mov EBX, 0FFFEh + + Sub CX, CURRENTPOSITIONERROR + SBB EBX, EDI + ; EBX:CX = 64k-(CurrentPosition & (2^14-1)) + ; EDX:AX = blocksize + Cmp EDX, EBX + JBE MFS8Bit1 + + Mov EDX, EBX + Mov AX, CX + +MFS8Bit1: + ; Now to calculate bytes to mix... + ShL EAX, 16 + SHRD EAX, EDX, 16 + ShR EDX, 16 ; EDX:EAX = (16)32.16 offset + + Mov EBX, STEPVALUE + Cmp EDX, EBX + JAE MFS8Bit2 + + Div EBX + Add EDX, 0FFFFFFFFh + AdC EAX, 0 ; EAX = no of bytes to mix + JZ MFS8Bit2 + + Push EAX + + Xor ECX, ECX + Mov DELTAOFFSET, [SI+4] ; Stepvalue + Mov DELTAERROR, [SI+2] ; Stepvalue + Mov CX, CURRENTPOSITIONERROR + + Push DS + Push SI + + Mov SI, MixBufferOffset + Mov DS, MixSegment + Call [MixFunction] + + Pop SI + Pop DS + Pop ECX + Jmp MFS8Bit3 + +MFS8Bit2: +; Xor ECX, ECX + Pop EDX + Pop AX + + Ret + +MFS8Bit3: + ; Update pointers... + Mov EAX, STEPVALUE + Mul ECX + + Sub MixBlockSize, CX + ShL CX, RESOLUTIONSHIFT + Add MixBufferOffset, CX + + ; EDX:EAX = offset mixed (32.16) + ShLD EDX, EAX, 16 + Mov BX, AX + Mov ECX, EDX ; ECX:BX = offset mixed + + Add CURRENTPOSITIONERROR, BX + AdC CURRENTPOSITION, ECX + + Pop EDX + Pop AX + + Sub AX, BX + SBB EDX, ECX + + JG MFS8Bit + + Ret + +EndP MFS8Bit + +; + +Proc MFS16Bit + + Push AX + Push EDX + + Mov EDI, CURRENTPOSITION + Add EDI, EDI + Call SetSampleSegment + + ShR EDI, 1 ; EDI = number of samples. + + Xor CX, CX + + Mov EBX, 7FFEh + + Sub CX, CURRENTPOSITIONERROR + SBB EBX, EDI + + Cmp EDX, EBX + JBE MFS16Bit1 + + Mov EDX, EBX + Mov AX, CX + +MFS16Bit1: + ; Now to calculate bytes to mix... + ShL EAX, 16 + SHRD EAX, EDX, 16 + ShR EDX, 16 ; EDX:EAX = (16)32.16 offset + + Mov EBX, STEPVALUE + Cmp EDX, EBX + JAE MFS16Bit2 + + Div EBX + Add EDX, 0FFFFFFFFh + AdC EAX, 0 ; EAX = no of bytes to mix + JZ MFS16Bit2 + + Push EAX + + Xor ECX, ECX + Mov DELTAOFFSET, [SI+4] ; Stepvalue + Mov DELTAERROR, [SI+2] ; Stepvalue + Mov CX, CURRENTPOSITIONERROR + + Push DS + Push SI + + Mov SI, MixBufferOffset + Mov DS, MixSegment + Call [MixFunction] + + Pop SI + Pop DS + Pop ECX + Jmp MFS16Bit3 + +MFS16Bit2: +; Xor ECX, ECX + Pop EDX + Pop AX + Ret + +MFS16Bit3: + ; Update pointers... + Mov EAX, STEPVALUE + Mul ECX + + Sub MixBlockSize, CX + ShL CX, RESOLUTIONSHIFT + Add MixBufferOffset, CX + + ; EDX:EAX = offset mixed (32.16) + ShLD EDX, EAX, 16 + Mov BX, AX + Mov ECX, EDX ; ECX:BX = offset mixed + + Add CURRENTPOSITIONERROR, BX + AdC CURRENTPOSITION, ECX + + Pop EDX + Pop AX + + Sub AX, BX + SBB EDX, ECX + + JG MFS16Bit + + Ret + +EndP MFS16Bit + +; + +Proc MBS8Bit + + Push AX + Push EDX ; EDX:AX = 32.16 blocksize + + Mov EDI, CURRENTPOSITION + Mov EBX, EDI + Add EBX, 2 + ShR EBX, 14 ; BX = frame + + Sub BX, 3 + JNC MBS8Bit4 + + Xor BX, BX + +MBS8Bit4: + Mov ECX, EBX + ShL ECX, 14 + Sub EDI, ECX + + Call SetBackSampleSegment + + Mov ECX, CURRENTPOSITION + Mov BX, CURRENTPOSITIONERROR + And ECX, 16383 + Add ECX, 0BFFEh + Cmp ECX, EDX + JG MBS8Bit1 + JL MBS8Bit5 + Cmp BX, AX + JG MBS8Bit1 + +MBS8Bit5: + Mov EDX, ECX + Mov AX, BX + +MBS8Bit1: + + ; Now to calculate bytes to mix... + ShL EAX, 16 + SHRD EAX, EDX, 16 + ShR EDX, 16 ; EDX:EAX = (16)32.16 offset + + Mov EBX, STEPVALUE + Cmp EDX, EBX + JAE MBS8Bit2 + + Div EBX + Add EDX, 0FFFFFFFFh + AdC EAX, 0 ; EAX = no of bytes to mix + JZ MBS8Bit2 + + Push EAX + + Xor ECX, ECX + Mov EBP, [SI+2] ; Stepvalue + Neg EBP + ShLD EDX, EBP, 16 + + Mov CX, CURRENTPOSITIONERROR + + Push DS + Push SI + + Mov SI, MixBufferOffset + Mov DS, MixSegment + Call [MixFunction] + + Pop SI + Pop DS + Pop ECX + Jmp MBS8Bit3 + +MBS8Bit2: +; Xor ECX, ECX + Pop EDX + Pop AX + Ret + +MBS8Bit3: + ; Update pointers... + Mov EAX, STEPVALUE + Mul ECX + + Sub MixBlockSize, CX + ShL CX, RESOLUTIONSHIFT + Add MixBufferOffset, CX + + ; EDX:EAX = offset mixed (32.16) + ShLD EDX, EAX, 16 + Mov BX, AX + Mov ECX, EDX ; ECX:BX = offset mixed + + Sub CURRENTPOSITIONERROR, BX + SBB CURRENTPOSITION, ECX + + Pop EDX + Pop AX + + Sub AX, BX + SBB EDX, ECX + + JG MBS8Bit + + Ret + +EndP MBS8Bit + +; + +Proc MBS16Bit + + Push AX + Push EDX ; EDX:AX = 32.16 blocksize + + Mov EDI, CURRENTPOSITION + Mov EBX, EDI + Add EBX, 4 + ShR EBX, 13 ; BX = frame + + Sub BX, 3 + JNC MBS16Bit4 + + Xor BX, BX + +MBS16Bit4: + Mov ECX, EBX + ShL ECX, 13 + Sub EDI, ECX + + Call SetBackSampleSegment + + Mov ECX, CURRENTPOSITION + Mov BX, CURRENTPOSITIONERROR + And ECX, 8191 + Add ECX, 05FFEh + Cmp ECX, EDX + JG MBS16Bit1 + JL MBS16Bit5 + Cmp BX, AX + JG MBS16Bit1 + +MBS16Bit5: + Mov EDX, ECX + Mov AX, BX + +MBS16Bit1: + + ; Now to calculate bytes to mix... + ShL EAX, 16 + SHRD EAX, EDX, 16 + ShR EDX, 16 ; EDX:EAX = (16)32.16 offset + + Mov EBX, STEPVALUE + Cmp EDX, EBX + JAE MBS16Bit2 + + Div EBX + Add EDX, 0FFFFFFFFh + AdC EAX, 0 ; EAX = no of bytes to mix + JZ MBS16Bit2 + + Push EAX + + Xor ECX, ECX + Mov EBP, [SI+2] ; Stepvalue + Neg EBP + ShLD EDX, EBP, 16 + + Mov CX, CURRENTPOSITIONERROR + + Push DS + Push SI + + Mov SI, MixBufferOffset + Mov DS, MixSegment + Call [MixFunction] + + Pop SI + Pop DS + Pop ECX + Jmp MBS16Bit3 + +MBS16Bit2: +; Xor ECX, ECX + Pop EDX + Pop AX + Ret + +MBS16Bit3: + ; Update pointers... + Mov EAX, STEPVALUE + Mul ECX + + Sub MixBlockSize, CX + ShL CX, RESOLUTIONSHIFT + Add MixBufferOffset, CX + + ; EDX:EAX = offset mixed (32.16) + ShLD EDX, EAX, 16 + Mov BX, AX + Mov ECX, EDX ; ECX:BX = offset mixed + + Sub CURRENTPOSITIONERROR, BX + SBB CURRENTPOSITION, ECX + + Pop EDX + Pop AX + + Sub AX, BX + SBB EDX, ECX + + JG MBS16Bit + + Ret + +EndP MBS16Bit + +; + +Proc ReportError + + Ret + +EndP ReportError + +; + diff --git a/it/SoundDrivers/MLPT1.BAT b/it/SoundDrivers/MLPT1.BAT new file mode 100755 index 0000000..f7b9a13 --- /dev/null +++ b/it/SoundDrivers/MLPT1.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 lpt1drv +tlink /3 lpt1drv +execom lpt1drv itlpt1.drv +copy itlpt1.drv .. diff --git a/it/SoundDrivers/MLPT2.BAT b/it/SoundDrivers/MLPT2.BAT new file mode 100755 index 0000000..9f3b39b --- /dev/null +++ b/it/SoundDrivers/MLPT2.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 lpt2drv +tlink /3 lpt2drv +execom lpt2drv itlpt2.drv +copy itlpt2.drv .. diff --git a/it/SoundDrivers/MMID.BAT b/it/SoundDrivers/MMID.BAT new file mode 100755 index 0000000..9d1760f --- /dev/null +++ b/it/SoundDrivers/MMID.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 middrv +tlink /3 middrv +execom middrv itmid.drv +copy itmid.drv .. diff --git a/it/SoundDrivers/MMIDI.BAT b/it/SoundDrivers/MMIDI.BAT new file mode 100755 index 0000000..d9f2c56 --- /dev/null +++ b/it/SoundDrivers/MMIDI.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 mididrv +tlink /3 mididrv +execom mididrv itmpu401.drv +copy itmpu401.drv .. diff --git a/it/SoundDrivers/MMX.INC b/it/SoundDrivers/MMX.INC new file mode 100755 index 0000000..680eed8 --- /dev/null +++ b/it/SoundDrivers/MMX.INC @@ -0,0 +1,306 @@ + +; Stuff from Intel's MMX Macro set. + +; This stuff has been written for real mode use - change the EQU below to EAX +; for protected mode use. + +opc_rdTSC = 031h +opc_Rdpmc = 033H +opc_Emms = 077H +opc_Movd_ld = 06EH +opc_Movd_st = 07EH +opc_Movq_ld = 06FH +opc_Movq_st = 07FH +opc_Packssdw = 06BH +opc_Packsswb = 063H +opc_Packuswb = 067H +opc_Paddb = 0FCH +opc_Paddd = 0FEH +opc_Paddsb = 0ECH +opc_Paddsw = 0EDH +opc_Paddusb = 0DCH +opc_Paddusw = 0DDH +opc_Paddw = 0FDH +opc_Pand = 0DBH +opc_Pandn = 0DFH +opc_Pcmpeqb = 074H +opc_Pcmpeqd = 076H +opc_Pcmpeqw = 075H +opc_Pcmpgtb = 064H +opc_Pcmpgtd = 066H +opc_Pcmpgtw = 065H +opc_Pmaddwd = 0F5H +opc_Pmulhw = 0E5H +opc_Pmullw = 0D5H +opc_Por = 0EBH +opc_PSHimd = 072H +opc_PSHimq = 073H +opc_PSHimw = 071H +opc_Pslld = 0F2H +opc_Psllq = 0F3H +opc_Psllw = 0F1H +opc_Psrad = 0E2H +opc_Psraw = 0E1H +opc_Psrld = 0D2H +opc_Psrlq = 0D3H +opc_Psrlw = 0D1H +opc_Psubb = 0F8H +opc_Psubd = 0FAH +opc_Psubsb = 0E8H +opc_Psubsw = 0E9H +opc_Psubusb = 0D8H +opc_Psubusw = 0D9H +opc_Psubw = 0F9H +opc_Punpcklbw = 060H +opc_Punpckldq = 062H +opc_Punpcklwd = 061H +opc_Punpckhbw = 068H +opc_Punpckhdq = 06AH +opc_Punpckhwd = 069H +opc_Pxor = 0EFH + +.486P + +MM0 EQU AX +MM1 EQU CX +MM2 EQU DX +MM3 EQU BX +MM4 EQU SP +MM5 EQU BP +MM6 EQU SI +MM7 EQU DI + +MMXMacro Macro Dst, Src, Opcode + Local X, Y + X: CmpXChg Src, Dst + Y: Org X+1 + DB Opcode + Org Y + EndM + +MMXIMacro Macro Dst, Src, Opcode + Local X, Y + X: BT Dst, Src + Y: Org X+1 + DB Opcode + Org Y + EndM + +MMXSRMacro Macro Dst, Src, Opcode + Local X, Y + X: CmpXChg Dst, MM2 + DB Src + Y: Org X+1 + DB Opcode + Org Y + EndM + +MMXSLMacro Macro Dst, Src, Opcode + Local X, Y + X: BTR Dst, Src + Y: Org X+1 + DB Opcode + Org Y + EndM + + +EMMS Macro + DB 0Fh, opc_Emms + EndM + + +MovQ Macro Dst, Src + MMXMacro Dst, Src, opc_MovQ_LD + EndM + +MovQM Macro Dst, Src + MMXMacro Src, Dst, opc_MovQ_ST + EndM + +MovD Macro Dst, Src + MMXMacro Dst, Src, opc_MovD_LD + EndM + +MovDM Macro Dst, Src + MMXMacro Src, Dst, opc_MovD_ST + EndM + +MovDR Macro Dst, Src + MMXMacro Src, Dst, opc_MovD_ST + EndM + + +PackSSDW Macro Dst, Src + MMXMacro Dst, Src, opc_PackSSDW + EndM + +PackSSWB Macro Dst, Src + MMXMacro Dst, Src, opc_PackSSWB + EndM + + +PAnd Macro Dst, Src + MMXMacro Dst, Src, opc_PAnd + EndM + +PAndN Macro Dst, Src + MMXMacro Dst, Src, opc_PAndN + EndM + + +PAddD Macro Dst, Src + MMXMacro Dst, Src, opc_PAddD + EndM + +PAddSW Macro Dst, Src + MMXMacro Dst, Src, opc_PAddSW + EndM + +PAddW Macro Dst, Src + MMXMacro Dst, Src, opc_PAddW + EndM + + +PMAddWD Macro Dst, Src + MMXMacro Dst, Src, opc_PMAddWD + EndM + +PMulHW Macro Dst, Src + MMXMacro Dst, Src, opc_PMulHW + EndM + +PMulLW Macro Dst, Src + MMXMacro Dst, Src, opc_PMulLW + EndM + + +POr Macro Dst, Src + MMXMacro Dst, Src, opc_POr + EndM + + +PSLLD Macro Dst, Src + MMXMacro Dst, Src, opc_PSLLD + EndM + +PSLLDI Macro Dst, Src + MMXSLMacro Dst, Src, opc_PSHImd + EndM + +PSLLQ Macro Dst, Src + MMXMacro Dst, Src, opc_PSLLQ + EndM + +PSLLQI Macro Dst, Src + MMXSLMacro Dst, Src, opc_PSHImq + EndM + + +PSRAD Macro Dst, Src + MMXMacro Dst, Src, opc_PSRAD + EndM + +PSRADI Macro Dst, Src + MMXIMacro Dst, Src, opc_PSHImd + EndM + +PSRLD Macro Dst, Src + MMXMacro Dst, Src, opc_PSRLD + EndM + +PSRLDI Macro Dst, Src + MMXSRMacro Dst, Src, opc_PSHImd + EndM + +PSRLQ Macro Dst, Src + MMXMacro Dst, Src, opc_PSRLQ + EndM + +PSRLQI Macro Dst, Src + MMXSRMacro Dst, Src, opc_PSHImq + EndM + +PSRAW Macro Dst, Src + MMXMacro Dst, Src, opc_PSRAW + EndM + +PSRAWI Macro Dst, Src + MMXIMacro Dst, Src, opc_PSHImw + EndM + +PSRLW Macro Dst, Src + MMXMacro Dst, Src, opc_PSRLW + EndM + +PSRLWI Macro Dst, Src + MMXSRMacro Dst, Src, opc_PSHImw + EndM + + +PSubB Macro Dst, Src + MMXMacro Dst, Src, opc_PSubB + EndM + +PSubSB Macro Dst, Src + MMXMacro Dst, Src, opc_PSubSB + EndM + +PSubUSB Macro Dst, Src + MMXMacro Dst, Src, opc_PSubUSB + EndM + +PSubD Macro Dst, Src + MMXMacro Dst, Src, opc_PSubD + EndM + +PSubW Macro Dst, Src + MMXMacro Dst, Src, opc_PSubW + EndM + +PSubSW Macro Dst, Src + MMXMacro Dst, Src, opc_PSubSW + EndM + +PSubUSW Macro Dst, Src + MMXMacro Dst, Src, opc_PSubUSW + EndM + + +PUnpckHBW Macro Dst, Src + MMXMacro Dst, Src, opc_PUnpckHBW + EndM + +PUnpckHDQ Macro Dst, Src + MMXMacro Dst, Src, opc_PUnpckHDQ + EndM + +PUnpckHWD Macro Dst, Src + MMXMacro Dst, Src, opc_PUnpckHWD + EndM + +PUnpckLBW Macro Dst, Src + MMXMacro Dst, Src, opc_PUnpckLBW + EndM + +PUnpckLDQ Macro Dst, Src + MMXMacro Dst, Src, opc_PUnpckLDQ + EndM + +PUnpckLWD Macro Dst, Src + MMXMacro Dst, Src, opc_PUnpckLWD + EndM + + +PXor Macro Dst, Src + MMXMacro Dst, Src, opc_PXor + EndM + + +RdPMC Macro + DB 0Fh, opc_Rdpmc + EndM + +RdTSC Macro + DB 0Fh, opc_RdTSC + EndM + diff --git a/it/SoundDrivers/MMXMSAM.INC b/it/SoundDrivers/MMXMSAM.INC new file mode 100755 index 0000000..72233ee --- /dev/null +++ b/it/SoundDrivers/MMXMSAM.INC @@ -0,0 +1,388 @@ +; + +Align 4 +include q.inc +FilterParameters DB 64 Dup (07Fh), 64 Dup (0) +Const2048 DD 16384.0 +FreqMultiplier DD 3A9F7867h ; = 1/(2*PI*110.0*2^0.25) +FreqParameterMultiplier DD 0B92AAAAAh ; = -1/(24*256) + +NUMBEROFFILTERBANDS = 4 + +IF OUTPUTFILTERENABLED +LastFilter DD NUMBEROFFILTERBANDS*2 Dup (0) ; 4 stereo values +FilterCoefficients DD NUMBEROFFILTERBANDS*2 Dup (0) +FilterVolumes DD NUMBEROFFILTERBANDS Dup (0) +ENDIF + +FilterFreqValue DW 0 +NewControlWord DW 7Fh + +; + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + Assume DS:Nothing + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, CS:MixSegment + Mov DI, DMABUFFERLENGTH*2+80 + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov CS:MixTransferOffset, DI + + Cmp CS:Stereo, 0 + JE CS:MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD + Mov CS:MixTransferRemaining, DX + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamplesNoStop + + And Byte Ptr [SI], Not 1 + + Cmp MixMode, 2 + JB MixSamplesEnd + + Mov DWord Ptr [SI+0Ch], 0 + Jmp MixModeCommon + +MixSamplesNoStop: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Xor EAX, EAX + Mov [SI+3Ch], AX ; For filter. + Mov [SI+6Eh], AX + + Mov DWord Ptr [SI+1Ch], EAX ; Current Volume = 0 + ; for volume sliding. + Mov [SI+06h], DX + Mov [SI+5Eh], AX + Mov [SI+7Eh], AX + +MixSamples5: + Test CX, 8540h ; New volume or panning? + JZ MixSamplesMix + + Mov AX, 4*60 + + Test CH, 8 ; Muted? + JZ MixMMXNoMute + + Xor EDX, EDX + Mov [SI+06h], DX + Mov [SI+0Ch], EDX + Mov [SI+5Eh], DX + Mov [SI+1Ch], EDX + Mov [SI+6Eh], DX + Mov [SI+3Ch], DX + Mov [SI+7Eh], DX + + Xor BX, BX + Mov BL, [SI+3Ah] + + Test BL, BL + JS MixModeCommon1 + + Mov DL, [CS:FilterParameters+BX] + Mov BL, [CS:FilterParameters+BX+64] + + Mov [SI+5Bh], DL + Mov [SI+3Fh], BL + + Jmp MixModeCommon1 + +MixMMXNoMute: + Xor BX, BX + Mov BL, [SI+3Ah] + + Test BL, BL ; Disowned? Then use channel filters. + JNS MixGetChannelFilters + + Mov BL, [SI+3Fh] + Jmp MixChannelFilters + +MixGetChannelFilters: + ; Filter = [FilterParameters+BX] + ; Q = [FilterParameters+BX+64] + + Mov AL, [CS:FilterParameters+BX] ; AX = Filter + Mov BL, [CS:FilterParameters+BX+64] ; BX = Q + +; If the values are different, then force recalculate volume. (and hence mixmode) + + Cmp [SI+5Bh], AL + JE MixChannelFiltersSame + Cmp [SI+3Fh], BL + JE MixChannelFiltersSame + + Mov DWord Ptr [SI+0Ch], 0 + +MixChannelFiltersSame: + Mov [SI+5Bh], AL + Mov [SI+3Fh], BL + +MixChannelFilters: + Cmp MixMode, 3 + JNE MixMMXNoFilters + + Mov AL, [SI+3Eh] + Mul Byte Ptr [SI+5Bh] + + Mov CS:FilterFreqValue, AX + + Cmp AX, 127*255 + JNE MixChannelFiltersOK + Test BL, BL + JZ MixMMXNoFilters + +MixChannelFiltersOK: + ShL BX, 2 + + FNInit + FLdCW [CS:NewControlWord] + + FILD [CS:FilterFreqValue] ; 0->127*256 + FMul [CS:FreqParameterMultiplier] ; -i/(24*256) + FLd ST + FRndInt + FSub ST(1), ST + FXCh + F2XM1 + FLd1 + FAdd + FScale ; = 2^(i/24*256) + FMul [CS:FreqMultiplier] ; = r + FLd ST ; r, r + FMul ST(1), ST ; r, r^2 + + FLd [CS:QualityFactorTable+BX] ; 2d, r, r^2 + FMul ST(1), ST ; 2d, 2dr, r^2 + FAdd + + FLd1 ; 1, d+1, e + FXCh ; d+1, 1, e + FSubR ST(1), ST + FAdd ST, ST(2) ; 1+d+e, d, e + FDivR Const2048 ; 1/(1+d+e), d, e + FISt Word Ptr [SI+5Eh] ; + FLd ST(2) ; e, 1/(1+d+e), d, e + FAdd ST, ST + FAddP ST(2), ST ; 1/(1+d+e), d+2e, e + FMul ST(2), ST ; 1/(1+d+e), d+2e, e/(1+d+e) + FMul + FIStP Word Ptr [SI+6Eh] + FChs + FIStP Word Ptr [SI+7Eh] + FStP ST + Mov DWord Ptr [SI+0Ch], 0 + +MixMMXNoFilters: + Mov EBX, [SI+0Ch] + + Cmp Stereo, 0 + JNE MixMMXStereo + +MixMMXMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + + Jmp MixModeVolumeCheck + +MixMMXStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE MixMMXSurround + + Mul Byte Ptr MixVolume ; 0->128 + Mul Word Ptr [SI+4Ah] ; 0->32768 + ShRD AX, DX, 15 ; Maxvol = 8192 + Mov [SI+0Eh], AX ; Store into right volume + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 15 + Mov [SI+0Ch], AX + + Jmp MixModeVolumeCheck + +MixMMXSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 10 + Mov [SI+0Ch], AX + Neg AX + Mov [SI+0Eh], AX + +MixModeVolumeCheck: + Test CH, 3+4 + JNZ MixModeCommon + + Cmp EBX, [SI+0Ch] ; Same as last volume? + JE MixSamplesMix + +MixModeCommon: ; Requires AX = 30 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov AX, MixModeOffset + + Cmp DWord Ptr [SI+0Ch], 0 + JNE MixModeActualMix + + Cmp MixMode, 2 + JB MixMMXGeneralNoRamp + + Cmp DWord Ptr [SI+1Ch], 0 + JNE MixModeActualMix + +MixMMXGeneralNoRamp: + Mov AX, 4*60 + Jmp MixModeCommon1 + +MixModeActualMix: + Cmp MixMode, 3 + JNE MixModeFilter + + Cmp Word Ptr [SI+6Eh], 0 + JNE MixModeFilter + Cmp Word Ptr [SI+7Eh], 0 + JNE MixModeFilter + + Sub AX, 60 + +MixModeFilter: + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 30 + +MixModeCommon1: + Cmp Byte Ptr [SI+0Ah], 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, DMABUFFERLENGTH*2+80 + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Push Word Ptr [SI+8] + Call Word Ptr [CS:BX] + Pop BX + + And Word Ptr [SI], 0111100010001101b + + Cmp BX, Offset MixFunctionTables+60*2 + JB MixSamplesEnd + Cmp BX, Offset MixFunctionTables+60*4 + JAE MixSamplesEnd + + MovDR AX, MM6 + Mov [SI+0Ch], EAX + Mov [SI+1Ch], EAX + + Cmp BX, Offset MixfunctionTables+60*3 + JB MixSamplesEnd + + Mov ES, CS:MixSegment + Mov DX, [ES:10h] + Mov BX, [ES:14h] + Mov [SI+3Ch], DX + Mov [SI+6h], BX + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + +IF OUTPUTFILTERENABLED + include equalize.inc +ENDIF + Ret + +EndP MixSamples + Assume DS:Nothing + +; + +; + diff --git a/it/SoundDrivers/MMXTRANS.INC b/it/SoundDrivers/MMXTRANS.INC new file mode 100755 index 0000000..25dd6a0 --- /dev/null +++ b/it/SoundDrivers/MMXTRANS.INC @@ -0,0 +1,116 @@ + +; To be embedded within the IRQ handler. + + Push DX + + Cmp CS:Stereo, 0 + JNE TransferStereoBufferMMX + +TransferMonoBufferMMX: ; DX = number of 32 bit numbers -> 16 bit. + + Push DX + ShR DX, 3 + JZ TransferMonoBufferMMX2 + +TransferMonoBufferMMX1: + MovD MM0, [SI] + MovD MM4, [SI+8] + MovD MM1, [SI+10h] + PUnpckLDQ MM0, MM4 + MovD MM5, [SI+18h] + PSRADI MM0, 13 + MovD MM2, [SI+20h] + PUnpckLDQ MM1, MM5 + MovD MM6, [SI+28h] + PSRADI MM1, 13 + MovD MM3, [SI+30h] + PUnpckLDQ MM2, MM6 + MovD MM7, [SI+38h] + PSRADI MM2, 13 + + PUnpckLDQ MM3, MM7 + PackSSDW MM0, MM1 + + PSRADI MM3, 13 + + MovQM [DI], MM0 + PackSSDW MM2, MM3 + + MovQM [DI+8], MM2 + + Add SI, 40h + Add DI, 10h + + Dec DX + JNZ TransferMonoBufferMMX1 + +TransferMonoBufferMMX2: + Pop CX + Mov DX, CX + + And CX, 7 + JZ TransferMonoBufferMMX4 + +TransferMonoBufferMMX3: + MovD MM0, [SI] + PSRADI MM0, 13 + PackSSDW MM0, MM1 + MovDR AX, MM0 + StosW + Add SI, 8 + + Loop TransferMonoBufferMMX3 + +TransferMonoBufferMMX4: + Jmp MMXMixTransferEnd + +TransferStereoBufferMMX: ; DX is always an even number for stereo + Push DX + + ShR DX, 3 + JZ TransferStereoBufferMMX2 + +TransferStereoBufferMMX1: ; DX = number of 32 bit numbers -> 16 bit + MovQ MM0, [SI] + MovQ MM1, [SI+10h] + PSRADI MM0, 12 + MovQ MM2, [SI+8] + PSRADI MM1, 12 + MovQ MM3, [SI+18h] + PSRADI MM2, 12 + PackSSDW MM0, MM2 + PSRADI MM3, 12 + MovQM [DI], MM0 + PackSSDW MM1, MM3 + MovQM [DI+8], MM1 ; 8 values done. + + Add SI, 20h + Add DI, 10h + + Dec DX + JNZ TransferStereoBufferMMX1 + +TransferStereoBufferMMX2: + Pop CX + Mov DX, CX + + And CX, 7 + ShR CX, 1 ; Always an even number! + JZ TransferStereoBufferMMX4 + +TransferStereoBufferMMX3: + MovQ MM0, [SI] + PSRADI MM0, 12 + PackSSDW MM0, MM1 ; Dummy register + MovDM [DI], MM0 + Add SI, 8 + Add DI, 4 + + Dec CX + JNZ TransferStereoBufferMMX3 + +TransferStereoBufferMMX4: + +MMXMixTransferEnd: + Pop DX + diff --git a/it/SoundDrivers/MNOMIX.INC b/it/SoundDrivers/MNOMIX.INC new file mode 100755 index 0000000..5843cd7 --- /dev/null +++ b/it/SoundDrivers/MNOMIX.INC @@ -0,0 +1,9 @@ + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + diff --git a/it/SoundDrivers/MONO12B.INC b/it/SoundDrivers/MONO12B.INC new file mode 100755 index 0000000..59998e9 --- /dev/null +++ b/it/SoundDrivers/MONO12B.INC @@ -0,0 +1,17 @@ + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Central + DW Offset MixNoLoop, PreMix12Central8Bit, MFS8Bit, MBS8Bit, Mix12Central8Bit + DW Offset MixForwardsLoop, PreMix12Central8Bit, MFS8Bit, MBS8Bit, Mix12Central8Bit + DW Offset MixPingPongLoop, PreMix12Central8Bit, MFS8Bit, MBS8Bit, Mix12Central8Bit + + ; 16 bit tables + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Central + DW Offset MixNoLoop, PreMix12Central16Bit, MFS16Bit, MBS16Bit, Mix12Central16Bit + DW Offset MixForwardsLoop, PreMix12Central16Bit, MFS16Bit, MBS16Bit, Mix12Central16Bit + DW Offset MixPingPongLoop, PreMix12Central16Bit, MFS16Bit, MBS16Bit, Mix12Central16Bit diff --git a/it/SoundDrivers/MONO12B.MIX b/it/SoundDrivers/MONO12B.MIX new file mode 100755 index 0000000..9de6da1 --- /dev/null +++ b/it/SoundDrivers/MONO12B.MIX @@ -0,0 +1,188 @@ + +ERROR EQU CX +DELTAERROR EQU BP +DELTAOFFSET EQU DX + + ; Different mixing routines required: + ; Left } shared + ; Right } + ; Central + ; Surround + ; Panned ; Each requires 8 bit and 16 bit + ; Single output - for Mono, pure left/pure right + +M12Mix8Central Macro Index + +M12Mix8Central&Index&: + Mov BL, [ES:DI] ;; 2 + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] ;; 2 + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*2], AX + +EndM + +M12Mix16Central Macro Index + +M12Mix16Central&Index&: + Mov BL, [ES:EDI+EDI+1] + Add ERROR, DELTAERROR + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET + Sub [SI+(Index-15)*2], AX + +EndM + +; + +; + +Mix12Central8BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8CentralOffset Macro Index + DW Offset M12Mix8Central&Index& + EndM + + REPT 16 + M12Mix8CentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central8Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Central8BitOffsetTable+BX] + +M12Central8BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + RetN + + M12Mix8Central 0 + M12Mix8Central 1 + M12Mix8Central 2 + M12Mix8Central 3 + M12Mix8Central 4 + M12Mix8Central 5 + M12Mix8Central 6 + M12Mix8Central 7 + M12Mix8Central 8 + M12Mix8Central 9 + M12Mix8Central 10 + M12Mix8Central 11 + M12Mix8Central 12 + M12Mix8Central 13 + M12Mix8Central 14 + M12Mix8Central 15 + + Add SI, 32 + Dec LoopCounter + JNZ M12Mix8Central0 + + Ret + +EndP Mix12Central8Bit + +; + +Proc PreMix12Central8Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Central8BitVolume], AL + + Ret + +EndP PreMix12Central8Bit + +; + +Mix12Central16BitOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16CentralOffset Macro Index + DW Offset M12Mix16Central&Index& + EndM + + REPT 16 + M12Mix16CentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central16Bit + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Central16BitOffsetTable+BX] + +M12Central16BitVolume EQU $+3 + Mov EBX, 0 ; Set BH = volume + + + RetN + + M12Mix16Central 0 + M12Mix16Central 1 + M12Mix16Central 2 + M12Mix16Central 3 + M12Mix16Central 4 + M12Mix16Central 5 + M12Mix16Central 6 + M12Mix16Central 7 + M12Mix16Central 8 + M12Mix16Central 9 + M12Mix16Central 10 + M12Mix16Central 11 + M12Mix16Central 12 + M12Mix16Central 13 + M12Mix16Central 14 + M12Mix16Central 15 + + Add SI, 32 + Dec LoopCounter + JNZ M12Mix16Central0 + + Ret + +EndP Mix12Central16Bit + +; + +Proc PreMix12Central16Bit + + Mov AL, [SI+0Eh] + Mov Byte Ptr [CS:M12Central16BitVolume], AL + + Ret + +EndP PreMix12Central16Bit + + +; +; + diff --git a/it/SoundDrivers/MONO12BI.INC b/it/SoundDrivers/MONO12BI.INC new file mode 100755 index 0000000..4ad266f --- /dev/null +++ b/it/SoundDrivers/MONO12BI.INC @@ -0,0 +1,17 @@ + + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Central + DW Offset MixNoLoop, PreMix12Central8BitI, MFS8Bit, MBS8Bit, Mix12Central8BitI + DW Offset MixForwardsLoop, PreMix12Central8BitI, MFS8Bit, MBS8Bit, Mix12Central8BitI + DW Offset MixPingPongLoop, PreMix12Central8BitI, MFS8Bit, MBS8Bit, Mix12Central8BitI + + ; 16 bit tables + DW Offset UpdateNoLoop, 0, 0, 0, 0 ; Update only + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + ; Central + DW Offset MixNoLoop, PreMix12Central16BitI, MFS16Bit, MBS16Bit, Mix12Central16BitI + DW Offset MixForwardsLoop, PreMix12Central16BitI, MFS16Bit, MBS16Bit, Mix12Central16BitI + DW Offset MixPingPongLoop, PreMix12Central16BitI, MFS16Bit, MBS16Bit, Mix12Central16BitI diff --git a/it/SoundDrivers/MONO12BI.MIX b/it/SoundDrivers/MONO12BI.MIX new file mode 100755 index 0000000..eb01312 --- /dev/null +++ b/it/SoundDrivers/MONO12BI.MIX @@ -0,0 +1,242 @@ + +ERROR EQU CX +DELTAERROR EQU BP +DELTAOFFSET EQU DX +HIGHERROR EQU CH + + ; Different mixing routines required: + ; Left } shared + ; Right } + ; Central + ; Surround + ; Panned ; Each requires 8 bit and 16 bit + ; Single output - for Mono, pure left/pure right + + ; Interpolation = [DI+1]*Error + [DI]*(1-Error) + ; = [DI+1]*Error + [DI] - [DI]*Error + ; = Error*([DI+1]-[DI]) + [DI] + + +M12Mix8ICentral Macro Index + +M12Mix8ICentral&Index&: + Mov AX, [ES:DI] + Mov BL, AL + SAR AL, 1 + SAR AH, 1 + Sub AH, AL + Mov AL, CH + ShR AL, 1 + IMul AH + SHL AX, 2 + Add BL, AH + +M12Mix8ICentralVolume&Index& EQU $+1 + Mov BH, 12h + + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*2], AX + +EndM + +M12Mix16ICentral Macro Index + +M12Mix16ICentral&Index&: + Mov BX, [ES:EDI+EDI] + Mov AH, [ES:EDI+EDI+3] + Mov BL, BH + SAR AH, 1 + SAR BH, 1 + Sub AH, BH + Mov AL, CH + ShR AL, 1 + IMul AH + SHL AX, 2 + Add BL, AH + +M12Mix16ICentralVolume&Index& EQU $+1 + Mov BH, 12h + + Add ERROR, DELTAERROR ;; 1 + Mov AX, [EBX+EBX] + AdC DI, DELTAOFFSET ;; 1 + Sub [SI+(Index-15)*2], AX + +EndM + +; + +; + +Mix12Central8BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix8ICentralOffset Macro Index + DW Offset M12Mix8ICentral&Index& + EndM + + REPT 16 + M12Mix8ICentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central8BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Central8BitIOffsetTable+BX] + + Xor EBX, EBX + + RetN + + M12Mix8ICentral 0 + M12Mix8ICentral 1 + M12Mix8ICentral 2 + M12Mix8ICentral 3 + M12Mix8ICentral 4 + M12Mix8ICentral 5 + M12Mix8ICentral 6 + M12Mix8ICentral 7 + M12Mix8ICentral 8 + M12Mix8ICentral 9 + M12Mix8ICentral 10 + M12Mix8ICentral 11 + M12Mix8ICentral 12 + M12Mix8ICentral 13 + M12Mix8ICentral 14 + M12Mix8ICentral 15 + + Add SI, 32 + Dec LoopCounter + JNZ M12Mix8ICentral0 + + Ret + +EndP Mix12Central8BitI + +; + +Proc PreMix12Central8BitI + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12Central8BitIMacro Macro Index + Mov Byte Ptr [CS:M12Mix8ICentralVolume&Index&], AL + EndM + + REPT 16 + PreMix12Central8BitIMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + +EndP PreMix12Central8BitI + +; + +Mix12Central16BitIOffsetTable Label Word + + IndexCounter = 15 + + M12Mix16ICentralOffset Macro Index + DW Offset M12Mix16ICentral&Index& + EndM + + REPT 16 + M12Mix16ICentralOffset %IndexCounter + IndexCounter = IndexCounter-1 + EndM + +Proc Mix12Central16BitI + + Dec AX + Mov BX, AX + And AX, 0Fh + ShR BX, 4 + Add AX, AX + Inc BX + Mov LoopCounter, BX + Mov BX, AX + + ShL AX, RESOLUTIONSHIFT-1 + + Add SI, AX + + Push [CS:Mix12Central16BitIOffsetTable+BX] + + Xor EBX, EBX + + + RetN + + M12Mix16ICentral 0 + M12Mix16ICentral 1 + M12Mix16ICentral 2 + M12Mix16ICentral 3 + M12Mix16ICentral 4 + M12Mix16ICentral 5 + M12Mix16ICentral 6 + M12Mix16ICentral 7 + M12Mix16ICentral 8 + M12Mix16ICentral 9 + M12Mix16ICentral 10 + M12Mix16ICentral 11 + M12Mix16ICentral 12 + M12Mix16ICentral 13 + M12Mix16ICentral 14 + M12Mix16ICentral 15 + + Add SI, 32 + Dec LoopCounter + JNZ M12Mix16ICentral0 + + Ret + +EndP Mix12Central16BitI + +; + +Proc PreMix12Central16BitI + + Mov AL, [SI+0Eh] + + IndexCounter = 0 + + PreMix12Central16BitIMacro Macro Index + Mov Byte Ptr [CS:M12Mix16ICentralVolume&Index&], AL + EndM + + REPT 16 + PreMix12Central16BitIMacro %IndexCounter + IndexCounter = IndexCounter+1 + EndM + + Ret + + + Ret + +EndP PreMix12Central16BitI + + +; +; + diff --git a/it/SoundDrivers/MPAS.BAT b/it/SoundDrivers/MPAS.BAT new file mode 100755 index 0000000..042d7cc --- /dev/null +++ b/it/SoundDrivers/MPAS.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 pasdrv +tlink /3 pasdrv +execom pasdrv itpas.drv +copy itpas.drv .. diff --git a/it/SoundDrivers/MPAS16.BAT b/it/SoundDrivers/MPAS16.BAT new file mode 100755 index 0000000..5ca635d --- /dev/null +++ b/it/SoundDrivers/MPAS16.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 pas16drv +tlink /3 pas16drv +execom pas16drv itpas16.drv +copy itpas16.drv .. diff --git a/it/SoundDrivers/MPC.BAT b/it/SoundDrivers/MPC.BAT new file mode 100755 index 0000000..20b3a4a --- /dev/null +++ b/it/SoundDrivers/MPC.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 pcspkdrv +tlink /3 pcspkdrv +execom pcspkdrv itpcspkr.drv +copy itpcspkr.drv .. diff --git a/it/SoundDrivers/MSAM.BAT b/it/SoundDrivers/MSAM.BAT new file mode 100755 index 0000000..cf35dec --- /dev/null +++ b/it/SoundDrivers/MSAM.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 sam9407 +tlink /3 sam9407 +execom sam9407 it9407.drv +copy it9407.drv .. + diff --git a/it/SoundDrivers/MSB.BAT b/it/SoundDrivers/MSB.BAT new file mode 100755 index 0000000..85d9c8b --- /dev/null +++ b/it/SoundDrivers/MSB.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 sbdrv +tlink /3 sbdrv +execom sbdrv itsb.drv +copy itsb.drv .. diff --git a/it/SoundDrivers/MSB16.BAT b/it/SoundDrivers/MSB16.BAT new file mode 100755 index 0000000..f99b353 --- /dev/null +++ b/it/SoundDrivers/MSB16.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 sb16drv +tlink /3 sb16drv +execom sb16drv itsb16.drv +copy itsb16.drv .. + diff --git a/it/SoundDrivers/MSB16A.BAT b/it/SoundDrivers/MSB16A.BAT new file mode 100755 index 0000000..e503e5d --- /dev/null +++ b/it/SoundDrivers/MSB16A.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 sb16k6 +tlink /3 sb16k6 +execom sb16k6 itsb16.3dn +copy itsb16.3dn .. + diff --git a/it/SoundDrivers/MSB16B.BAT b/it/SoundDrivers/MSB16B.BAT new file mode 100755 index 0000000..fc14dda --- /dev/null +++ b/it/SoundDrivers/MSB16B.BAT @@ -0,0 +1,4 @@ +tasm /m /uT310 sb16b +tlink /3 sb16b +execom sb16b itsb16b.drv +copy itsb16b.drv .. diff --git a/it/SoundDrivers/MSB16C.BAT b/it/SoundDrivers/MSB16C.BAT new file mode 100755 index 0000000..9285cb4 --- /dev/null +++ b/it/SoundDrivers/MSB16C.BAT @@ -0,0 +1,4 @@ +tasm /m /uT310 sb16c +tlink /3 sb16c +execom sb16c itsb16c.drv +copy itsb16c.drv .. diff --git a/it/SoundDrivers/MSB16D.BAT b/it/SoundDrivers/MSB16D.BAT new file mode 100755 index 0000000..4f3ad2e --- /dev/null +++ b/it/SoundDrivers/MSB16D.BAT @@ -0,0 +1,4 @@ +tasm /m /uT310 sb16d +tlink /3 sb16d +execom sb16d itsb16d.drv +copy itsb16d.drv .. diff --git a/it/SoundDrivers/MSB16M.BAT b/it/SoundDrivers/MSB16M.BAT new file mode 100755 index 0000000..e2923f3 --- /dev/null +++ b/it/SoundDrivers/MSB16M.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 sb16mmx +tlink /3 sb16mmx +execom sb16mmx itsb16.mmx +copy itsb16.mmx .. + diff --git a/it/SoundDrivers/MSB16MB.BAT b/it/SoundDrivers/MSB16MB.BAT new file mode 100755 index 0000000..0839be9 --- /dev/null +++ b/it/SoundDrivers/MSB16MB.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 sb16mmxb +tlink /3 sb16mmxb +execom sb16mmxb itsb16b.mmx +copy itsb16b.mmx .. + diff --git a/it/SoundDrivers/MSB2.BAT b/it/SoundDrivers/MSB2.BAT new file mode 100755 index 0000000..65f8c0f --- /dev/null +++ b/it/SoundDrivers/MSB2.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 sb2drv +tlink /3 sb2drv +execom sb2drv itsb2.drv +copy itsb2.drv .. diff --git a/it/SoundDrivers/MSBPRO.BAT b/it/SoundDrivers/MSBPRO.BAT new file mode 100755 index 0000000..88bd0d6 --- /dev/null +++ b/it/SoundDrivers/MSBPRO.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 sbprodrv +tlink /3 sbprodrv +execom sbprodrv itsbpro.drv +copy itsbpro.drv .. diff --git a/it/SoundDrivers/MST97.BAT b/it/SoundDrivers/MST97.BAT new file mode 100755 index 0000000..b2fd60a --- /dev/null +++ b/it/SoundDrivers/MST97.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 st97 +tlink /3 st97 +execom st97 itst97.drv +copy itst97.drv .. diff --git a/it/SoundDrivers/MSTC.BAT b/it/SoundDrivers/MSTC.BAT new file mode 100755 index 0000000..fe8212e --- /dev/null +++ b/it/SoundDrivers/MSTC.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 st97code +tlink /3 st97code +execom st97code itstcode.drv +copy itstcode.drv .. + diff --git a/it/SoundDrivers/MSTCM.BAT b/it/SoundDrivers/MSTCM.BAT new file mode 100755 index 0000000..62f7644 --- /dev/null +++ b/it/SoundDrivers/MSTCM.BAT @@ -0,0 +1,4 @@ +tasm32 /m /la /ut310 st97cmmx +tlink /3 st97cmmx +execom st97cmmx itstcode.mmx +copy itstcode.mmx .. diff --git a/it/SoundDrivers/MSTP.BAT b/it/SoundDrivers/MSTP.BAT new file mode 100755 index 0000000..23bbdca --- /dev/null +++ b/it/SoundDrivers/MSTP.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 st97pnp +tlink /3 st97pnp +execom st97pnp itstpnp.drv +copy itstpnp.drv .. + diff --git a/it/SoundDrivers/MT.BAT b/it/SoundDrivers/MT.BAT new file mode 100755 index 0000000..e4c4fd6 --- /dev/null +++ b/it/SoundDrivers/MT.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 test +tlink /3 test +execom test ittest.drv +copy ittest.drv .. + diff --git a/it/SoundDrivers/MV.BAT b/it/SoundDrivers/MV.BAT new file mode 100755 index 0000000..38807c4 --- /dev/null +++ b/it/SoundDrivers/MV.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 /la vsnd +tlink /3 vsnd +execom vsnd itvsound.drv +copy itvsound.drv .. + diff --git a/it/SoundDrivers/MVIVO.BAT b/it/SoundDrivers/MVIVO.BAT new file mode 100755 index 0000000..9394270 --- /dev/null +++ b/it/SoundDrivers/MVIVO.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 envivo +tlink /3 envivo +execom envivo itvivo.drv +copy itvivo.drv .. + diff --git a/it/SoundDrivers/MVM.BAT b/it/SoundDrivers/MVM.BAT new file mode 100755 index 0000000..dd16587 --- /dev/null +++ b/it/SoundDrivers/MVM.BAT @@ -0,0 +1,5 @@ +tasm32 /m /ut310 /la vsndmmx +tlink /3 /m vsndmmx +execom vsndmmx itvsound.mmx +copy itvsound.mmx .. + diff --git a/it/SoundDrivers/MWAV.BAT b/it/SoundDrivers/MWAV.BAT new file mode 100755 index 0000000..d0210dc --- /dev/null +++ b/it/SoundDrivers/MWAV.BAT @@ -0,0 +1,4 @@ +tasm /m /ut310 wavdrv +tlink /3 wavdrv +execom wavdrv itwav.drv +call mmid diff --git a/it/SoundDrivers/MWSS.BAT b/it/SoundDrivers/MWSS.BAT new file mode 100755 index 0000000..11d267d --- /dev/null +++ b/it/SoundDrivers/MWSS.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 wssdrv +tlink /3 wssdrv +execom wssdrv itwss.drv +copy itwss.drv .. + diff --git a/it/SoundDrivers/MWSS2.BAT b/it/SoundDrivers/MWSS2.BAT new file mode 100755 index 0000000..fef0fa1 --- /dev/null +++ b/it/SoundDrivers/MWSS2.BAT @@ -0,0 +1,5 @@ +tasm /m /ut310 wssdrv2 +tlink /3 wssdrv2 +execom wssdrv2 itwss2.drv +copy itwss2.drv .. + diff --git a/it/SoundDrivers/NODEBUG.INC b/it/SoundDrivers/NODEBUG.INC new file mode 100755 index 0000000..f7ad96f --- /dev/null +++ b/it/SoundDrivers/NODEBUG.INC @@ -0,0 +1,7 @@ +; +; Dummy trace commands +; + + +Trace Macro LogMessage + EndM diff --git a/it/SoundDrivers/NOISE.ASM b/it/SoundDrivers/NOISE.ASM new file mode 100755 index 0000000..ed80341 --- /dev/null +++ b/it/SoundDrivers/NOISE.ASM @@ -0,0 +1,2091 @@ +; +; Windows Sound System Driver +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +DMASize DW 2048 + +WSSMsg DB "Using Noise Source Codec", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Using Noise Source Codec", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Noise Source reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITNOISE.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITNOISE.DRV", 0 + +DriverName DB "ITNOISE.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW 0 + +WSSHeaderLine DW 10 + DB "Noise Source Codec Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 29, 48 + DB 21h + DB "Noise Source Codec Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 2 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 16 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Inc DX + Inc DX + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Cmp IRQ, 0FFFFh + JE DetectWSSFailure + Cmp DMA, 0FFFFh + JE DetectWSSFailure + + Mov DX, BasePort + Cmp DX, 0FFFFh + JE DetectCardFindBasePort + + Call PingWSS + JNC CheckWSSOK + +DetectWSSFailure: + StC + Ret + +DetectCardFindBasePort: + Mov DX, 31Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 32Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 33Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 34Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 35Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 36Ch + Call PingWSS + JNC DetectWSSOK + + Mov DX, 530h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 604h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0F40h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0E80h + Call PingWSS + JC DetectWSSFailure + +DetectWSSOK: + Mov BasePort, DX + +CheckWSSOK: ; Check for IRQ + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Mov EAX, 'Jeff' + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 2 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB WSSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +WSSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/PAS16DRV.ASM b/it/SoundDrivers/PAS16DRV.ASM new file mode 100755 index 0000000..8a72ec4 --- /dev/null +++ b/it/SoundDrivers/PAS16DRV.ASM @@ -0,0 +1,1986 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for the PAS16 +MIXTABLESIZE EQU 2*256*65 +TIMERCONST EQU 11932 + +Debug1 DB 0 +Debug2 DW 0 + +PAS16Msg DB "Pro Audio 16 Spectrum found", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +PAS16NoMemoryMsg DB "Pro Audio 16 Spectrum found", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Pro Audio 16 Spectrum reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITPAS16.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITPAS16.DRV", 0 + +DriverName DB "ITPAS16.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +MixSpeed DW 44100 +PASMixConst DW 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 +TimerAccumulator DW 0 + +DMALengthTable Label Byte + DB 1, 3, 5, 7, 0C2h, 0C6h, 0CAh, 0CEh + +;********************************** + +PAS16ScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr PAS16HeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW 0 + +PAS16HeaderLine DW 10 + DB "Pro Audio Spectrum 16 Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 26, 48 + DB 21h + DB "Pro Audio Spectrum 16 Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MixModeText DW 1 + DB 2, 13 + DB 20h + DB "Mixing Mode", 0 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 15, 32, 17, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 18, 32, 20, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 21, 32, 23, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 24, 32, 26, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 28 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 30, 29, 32, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 33, 29, 35, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 36, 29, 38, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 6 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetMixSpeed + Assume DS:Driver + + Push AX + Push CX + Push DX + + Mov DX, 12h + Mov AX, 34DCh + Mov CX, PASMixConst + Cmp CS:Stereo, 0 + JE GetMixSpeed1 + + And CX, Not 1 + +GetMixSpeed1: + Div CX + +GetMixSpeed2: + Mov MixSpeed, AX + + Pop DX + Pop CX + Pop AX + Ret + +EndP GetMixSpeed + Assume DS:Nothing + +; + +Proc GetPASMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetPASMixConst1 + + Mov CX, 44100 + Cmp AX, CX + JA GetPASMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetPASMixConst1 + + Mov CX, AX + +GetPASMixConst1: + Mov MixSpeed, CX + + Mov DX, 012h + Mov AX, 34DCh + Div CX + + Mov PASMixConst, AX + Mov BX, AX + + Pop DS + PopA + Ret + +EndP GetPASMixConst + Assume DS:Nothing + +; + +Proc TestPAS ; AX = port + + Push AX + + Mov DX, 803h ; Default is 0B8Bh + Xor DX, AX ; DX = Interrupt Control port + In AL, DX + + Cmp AL, 0FFh + JE TestPAS1 + + Mov AH, AL + Xor AL, 11100000b + Out DX, AL + + Jmp $+2 + Jmp $+2 + In AL, DX + + Cmp AL, AH + XChg AH, AL + Out DX, AL + JNE TestPAS1 + + Pop AX + Push AX + + Mov DX, AX ; PAS 16? + Xor DX, 0EF8Bh xor 388h + In AL, DX + Test AL, 8 + JZ TestPAS1 + + Pop AX + + ClC + Ret + +TestPAS1: + Pop AX + StC + Ret + +EndP TestPAS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 0BC00h + Mov BX, '??' + Xor CX, CX + Xor DX, DX + Int 2Fh + + Xor BX, CX + Xor BX, DX + Cmp BX, 'M'*256+'V' + JE DetectPAS4 ; MVSound.Sys installed! + +DetectPAS7: + StC + Ret + +DetectPAS4: + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectPAS1 + Cmp AX, 388h + JE DetectPAS6 + Cmp AX, 384h + JE DetectPAS6 + Cmp AX, 38Ch + JE DetectPAS6 + Cmp AX, 288h + JNE DetectPAS7 + +DetectPAS6: + Call TestPAS + JNC DetectPAS2 + + Ret + +DetectPAS1: + Mov AX, 388h + Call TestPAS + JNC DetectPAS2 + + Mov AX, 384h + Call TestPAS + JNC DetectPAS2 + + Mov AX, 38Ch + Call TestPAS + JNC DetectPAS2 + + Mov AX, 288h + Call TestPAS + JNC DetectPAS2 + + Ret ; No card! + +DetectPAS2: + Push AX + + Mov AX, 0BC04h + Int 2Fh + + Cmp AX, 'M'*256+'V' + JNE DetectPAS3 + + Pop AX + + Mov BasePort, AX + Mov DMA, BX + Mov IRQ, CX + + Mov AL, [DMALengthTable+BX] + Mov Byte Ptr [DMAPort1], AL + Mov Byte Ptr [DMAPort2], AL + + Mov AX, DMABUFFERLENGTH/2 + Cmp BX, 4 + JB DetectPAS5 + + ShR AX, 1 + +DetectPAS5: + Mov Word Ptr [DMABufferLength1], AX + Mov Word Ptr [DMABufferLength2], AX + + Mov EAX, 'Jeff' + ClC + Ret + +DetectPAS3: + Pop AX + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc PAS16IRQHandler + + Push AX + Push BX + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Add TimerAccumulator, TIMERCONST + JC PAS16IRQHandler11 + + Mov AL, 20h + Out 20h, AL + Jmp PAS16IRQHandler12 + +PAS16IRQHandler11: + PushF + Call [OldIRQHandler] + +PAS16IRQHandler12: + +DMAPort1 EQU $+1 + In AL, 1 + Mov AH, AL +DMAPort2 EQU $+1 + In AL, 1 + XChg AL, AH + + Mov Debug2, AX + + Cmp MixBufferPos, 0 + JE PAS16IRQHandler13 + + Xor BX, BX +DMABufferLength1 EQU $+1 + Cmp AX, 1234h + JB PAS16IRQHandler1 + + Pop DS + Pop BX + Pop AX + IRet + +PAS16IRQHandler13: + Mov BX, DMABUFFERLENGTH/2 +DMABufferLength2 EQU $+1 + Cmp AX, 1234h + JAE PAS16IRQHandler1 + + Pop DS + Pop BX + Pop AX + IRet + +PAS16IRQHandler1: + Xor MixBufferPos, 1 + + PushAD + Push ES + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, BX + + Mov BX, DMABUFFERLENGTH/4 ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE PAS16IRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +PAS16IRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE PAS16IRQHandler4 + Assume DS:Nothing + +PAS16IRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +PAS16IRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE PAS16IRQHandler5 + + Mov DX, MixTransferRemaining + +PAS16IRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB PAS16IRQHandler6 + JE PAS16IRQHFilter + + Cmp CS:Stereo, 0 + JE PAS16IRQ3QFilterMono + +PAS16IRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +PAS16IRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL PAS163QFilterStereoClip1 + Cmp EAX, 7FFFh + JG PAS163QFilterStereoClip2 + +PAS16IRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL PAS163QFilterStereoClip3 + Cmp EAX, 7FFFh + JG PAS163QFilterStereoClip4 + +PAS16IRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ PAS16IRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp PAS16MixTransferEnd + +PAS16IRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +PAS16IRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL PAS163QFilterMonoClip1 + Cmp EAX, 7FFFh + JG PAS163QFilterMonoClip2 + +PAS16IRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ PAS16IRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp PAS16MixTransferEnd + +PAS16IRQHFilter: + Cmp CS:Stereo, 0 + JE PAS16IRQHFilterMono + +PAS16IRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +PAS16IRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL PAS16HFilterStereoClip1 + Cmp EAX, 7FFFh + JG PAS16HFilterStereoClip2 + +PAS16IRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL PAS16HFilterStereoClip3 + Cmp EAX, 7FFFh + JG PAS16HFilterStereoClip4 + +PAS16IRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ PAS16IRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp PAS16MixTransferEnd + +PAS16IRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +PAS16IRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL PAS16HFilterMonoClip1 + Cmp EAX, 7FFFh + JG PAS16HFilterMonoClip2 + +PAS16IRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ PAS16IRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp PAS16MixTransferEnd + +PAS16IRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL PAS16IRQHandlerClip1 + Cmp EAX, 7FFFh + JG PAS16IRQHandlerClip2 + +PAS16IRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ PAS16IRQHandler6 + +PAS16MixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ PAS16IRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + PopAD + Pop DS + Pop BX + Pop AX + IRet + +PAS16IRQHandlerClip1: + Mov AX, 8000h + Jmp PAS16IRQHandler7 + +PAS16IRQHandlerClip2: + Mov AX, 7FFFh + Jmp PAS16IRQHandler7 + +PAS16HFilterMonoClip1: + Mov AX, 8000h + Jmp PAS16IRQHFilterMono2 + +PAS16HFilterMonoClip2: + Mov AX, 7FFFh + Jmp PAS16IRQHFilterMono2 + +PAS16HFilterStereoClip1: + Mov AX, 8000h + Jmp PAS16IRQHFilterStereo2 + +PAS16HFilterStereoClip2: + Mov AX, 7FFFh + Jmp PAS16IRQHFilterStereo2 + +PAS16HFilterStereoClip3: + Mov AX, 8000h + Jmp PAS16IRQHFilterStereo3 + +PAS16HFilterStereoClip4: + Mov AX, 7FFFh + Jmp PAS16IRQHFilterStereo3 + +PAS163QFilterMonoClip1: + Mov AX, 8000h + Jmp PAS16IRQ3QFilterMono2 + +PAS163QFilterMonoClip2: + Mov AX, 7FFFh + Jmp PAS16IRQ3QFilterMono2 + +PAS163QFilterStereoClip1: + Mov AX, 8000h + Jmp PAS16IRQ3QFilterStereo2 + +PAS163QFilterStereoClip2: + Mov AX, 7FFFh + Jmp PAS16IRQ3QFilterStereo2 + +PAS163QFilterStereoClip3: + Mov AX, 8000h + Jmp PAS16IRQ3QFilterStereo3 + +PAS163QFilterStereoClip4: + Mov AX, 7FFFh + Jmp PAS16IRQ3QFilterStereo3 + +EndP PAS16IRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + Push EAX + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + ; bump the interrupt to be called + ; 100 times a second. + Mov AX, TIMERCONST + Out 40h, AL + Mov AL, AH + Out 40h, AL + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset PAS16IRQHandler + + ClI + + XChg [ES:20h], EAX ; Hook to timer interrupt + Mov CS:OldIRQHandler, EAX + + StI + + Pop ES + Pop EAX + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + Push EAX + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Xor AL, AL + Out 40h, AL ; Interrupt called at normal 18.2 times + Out 40h, AL + + Mov EAX, CS:OldIRQHandler + Mov [ES:20h], EAX + + Pop ES + Pop EAX + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopPAS16 + + Mov DX, BasePort + Xor AL, AL + Xor DX, 0B89h xor 388h ; Interrupt Status register + Out DX, AL + + Mov DX, BasePort ; Audio filter control + Mov AL, 1 + Xor DX, 0B8Ah xor 388h ; Disable buffer counter + Out DX, AL ; and PAS 16 output + + Mov DX, BasePort + Xor DX, 8389h xor 388h ; SysConfig2 + In AL, DX ; Get SysConfig2 + And AL, Not 4 ; Reset 8 bits + Out DX, AL + + Mov DX, BasePort + Mov AL, 19h ; Mono, L2L, R2R + Xor DX, 0F8Ah xor 388h ; Cross channel register + Out DX, AL + + Ret + +EndP StopPAS16 + +; + +Proc StartPAS16 ; + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Xor AL, AL + Xor DX, 0B89h xor 388h ; Interrupt Status register + Out DX, AL + + Mov DX, BasePort ; Audio filter control + Mov AL, 1 + Xor DX, 0B8Ah xor 388h ; Disable buffer counter + Out DX, AL ; and PAS 16 output + + Mov DX, BasePort + Mov AL, 19h + Xor DX, 0F8Ah xor 388h ; Cross channel register + Out DX, AL + + Mov DX, BasePort + Xor DX, 138Bh xor 388h ; Timer control, + Mov AL, 00110110b ; 36h - set frequency + Out DX, AL + + Mov DX, BasePort + Xor DX, 1388h xor 388h + Mov AX, PASMixConst + Cmp Stereo, 0 + JE StartPAS16_2 + + ShR AX, 1 + +StartPAS16_2: + Out DX, AL + Mov AL, AH + Out DX, AL + + Call GetMixSpeed + Call GetTempo + Call SetTempo + + Mov DX, BasePort + Xor DX, 138Bh xor 388h ; Timer control + Mov AL, 01110100b ; 74h - set buffer count + Out DX, AL + + Mov DX, BasePort ; Sample count + Mov AX, DMABUFFERLENGTH + Xor DX, 1389h xor 388h + + Cmp DMA, 4 + JB StartPAS16_1 + + ShR AX, 1 + +StartPAS16_1: + Out DX, AL + Mov AL, AH + Out DX, AL + + Mov DX, BasePort + Xor DX, 8389h xor 388h ; SysConfig2 + In AL, DX ; Get SysConfig2 + Or AL, 4 ; Set 16 bits + Out DX, AL + + Mov AL, Stereo + Xor AL, 1 ; 0 if stereo, 1 if mono. + ShL AL, 5 + Mov DX, BasePort + Or AL, 099h ; Enable DRQ, DAC output + Xor DX, 0F8Ah xor 388h + Out DX, AL + Jmp $+2 + Jmp $+2 + Or AL, 40h ; Enable PCM + Out DX, AL + + Mov DX, BasePort + Xor DX, 0B8Bh xor 388h + In AL, DX + Or AL, 8 ; Enable sample buffer intr + Out DX, AL + + Mov DX, BasePort ; Disable output&timers + Mov AL, 0E1h ; disable mute, enable sample rate + ; timer and sample buffer counter. + Xor DX, 0B8Ah xor 388h + Out DX, AL + + Pop DS + Pop ES + PopA + + Ret + + Assume DS:Nothing + +EndP StartPAS16 + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetPASMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset PAS16NoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset PAS16Msg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopPAS16 + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + +; In AL, 1 +; Mov AH, AL +; In AL, 1 +; Mov CS:Debug2, AX + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Call RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopPAS16 + Call StartPAS16 + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset PAS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Comment ~ + + Mov DX, BasePort + Add DL, 4 + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + + ~ + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/PASDRV.ASM b/it/SoundDrivers/PASDRV.ASM new file mode 100755 index 0000000..5c79d1c --- /dev/null +++ b/it/SoundDrivers/PASDRV.ASM @@ -0,0 +1,1903 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 16 ; 32 bit mixing for the PAS16 +MIXTABLESIZE EQU 2*256*65 +TIMERCONST EQU 11932 + +Debug1 DB 0 +Debug2 DW 0 + +PAS16Msg DB "Pro Audio Spectrum found", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +PAS16NoMemoryMsg DB "Pro Audio Spectrum found", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Pro Audio Spectrum reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITPAS.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITPAS.DRV", 0 + +DriverName DB "ITPAS.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +MixSpeed DW 44100 +PASMixConst DW 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldIRQHandler DD 0 + +FilterValue DW 0 +FilterValue2 DW 0 +TimerAccumulator DW 0 + +DMALengthTable Label Byte + DB 1, 3, 5, 7, 0C2h, 0C6h, 0CAh, 0CEh + +;********************************** + +PAS16ScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr PASHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; 7 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 9 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW 0 + +PASHeaderLine DW 10 + DB "Pro Audio Spectrum Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 29, 48 + DB 21h + DB "Pro Audio Spectrum Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MixModeText DW 1 + DB 2, 13 + DB 20h + DB "Mixing Mode", 0 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 15, 32, 17, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 18, 32, 20, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 22 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 7, 10, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 24, 29, 26, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 27, 29, 29, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 10, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 30, 29, 32, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 6 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetMixSpeed + Assume DS:Driver + + Push AX + Push CX + Push DX + + Mov DX, 12h + Mov AX, 34DCh + Mov CX, PASMixConst + Cmp CS:Stereo, 0 + JE GetMixSpeed1 + + And CX, Not 1 + +GetMixSpeed1: + Div CX + +GetMixSpeed2: + Mov MixSpeed, AX + + Pop DX + Pop CX + Pop AX + Ret + +EndP GetMixSpeed + Assume DS:Nothing + +; + +Proc GetPASMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetPASMixConst1 + + Mov CX, 44100 + Cmp AX, CX + JA GetPASMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetPASMixConst1 + + Mov CX, AX + +GetPASMixConst1: + Mov MixSpeed, CX + + Mov DX, 012h + Mov AX, 34DCh + Div CX + + Mov PASMixConst, AX + Mov BX, AX + + Pop DS + PopA + Ret + +EndP GetPASMixConst + Assume DS:Nothing + +; + +Proc TestPAS ; AX = port + + Push AX + + Mov DX, 803h ; Default is 0B8Bh + Xor DX, AX ; DX = Interrupt Control port + In AL, DX + + Cmp AL, 0FFh + JE TestPAS1 + + Mov AH, AL + Xor AL, 11100000b + Out DX, AL + + Jmp $+2 + Jmp $+2 + In AL, DX + + Cmp AL, AH + XChg AH, AL + Out DX, AL + JNE TestPAS1 + + Pop AX + + ClC + Ret + +TestPAS1: + Pop AX + StC + Ret + +EndP TestPAS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 0BC00h + Mov BX, '??' + Xor CX, CX + Xor DX, DX + Int 2Fh + + Xor BX, CX + Xor BX, DX + Cmp BX, 'M'*256+'V' + JE DetectPAS4 ; MVSound.Sys installed! + +DetectPAS7: + StC + Ret + +DetectPAS4: + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectPAS1 + Cmp AX, 388h + JE DetectPAS6 + Cmp AX, 384h + JE DetectPAS6 + Cmp AX, 38Ch + JE DetectPAS6 + Cmp AX, 288h + JNE DetectPAS7 + +DetectPAS6: + Call TestPAS + JNC DetectPAS2 + + Ret + +DetectPAS1: + Mov AX, 388h + Call TestPAS + JNC DetectPAS2 + + Mov AX, 384h + Call TestPAS + JNC DetectPAS2 + + Mov AX, 38Ch + Call TestPAS + JNC DetectPAS2 + + Mov AX, 288h + Call TestPAS + JNC DetectPAS2 + + Ret ; No card! + +DetectPAS2: + Push AX + + Mov AX, 0BC04h + Int 2Fh + + Cmp AX, 'M'*256+'V' + JNE DetectPAS3 + + Pop AX + + Mov BasePort, AX + Mov DMA, BX + Mov IRQ, CX + + Mov AL, [DMALengthTable+BX] + Mov Byte Ptr [DMAPort1], AL + Mov Byte Ptr [DMAPort2], AL + + Mov AX, DMABUFFERLENGTH/2 + Cmp BX, 4 + JB DetectPAS5 + + ShR AX, 1 + +DetectPAS5: + Mov Word Ptr [DMABufferLength1], AX + Mov Word Ptr [DMABufferLength2], AX + + Mov EAX, 'Jeff' + + ClC + Ret + +DetectPAS3: + Pop AX + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Mov AX, 2020h + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + ShR AX, 1 + Mov DX, CX + +MixSamples1: + Rep StosW ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc PAS16IRQHandler + + Push AX + Push BX + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Add TimerAccumulator, TIMERCONST + JC PAS16IRQHandler11 + + Mov AL, 20h + Out 20h, AL + Jmp PAS16IRQHandler12 + +PAS16IRQHandler11: + PushF + Call [OldIRQHandler] + +PAS16IRQHandler12: + +DMAPort1 EQU $+1 + In AL, 1 + Mov AH, AL +DMAPort2 EQU $+1 + In AL, 1 + XChg AL, AH + + Mov Debug2, AX + + Cmp MixBufferPos, 0 + JE PAS16IRQHandler13 + + Xor BX, BX +DMABufferLength1 EQU $+1 + Cmp AX, 1234h + JB PAS16IRQHandler1 + + Pop DS + Pop BX + Pop AX + IRet + +PAS16IRQHandler13: + Mov BX, DMABUFFERLENGTH/2 +DMABufferLength2 EQU $+1 + Cmp AX, 1234h + JAE PAS16IRQHandler1 + + Pop DS + Pop BX + Pop AX + IRet + +PAS16IRQHandler1: + Xor MixBufferPos, 1 + + PushAD + Push ES + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, BX + + Mov BX, DMABUFFERLENGTH/2 ; BX = samples required + Mov BP, 4 ; Skip for mono + Mov CL, 6 ; Shift for mono + + Cmp Stereo, 0 + JE PAS16IRQHandlerMono + + Mov BP, 2 ; Stereo skip value. + Dec CL + +PAS16IRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE PAS16IRQHandler4 + Assume DS:Nothing + +PAS16IRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +PAS16IRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE PAS16IRQHandler5 + + Mov DX, MixTransferRemaining + +PAS16IRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB PAS16IRQHandler6 + JE PAS16IRQHFilter + + Cmp CS:Stereo, 0 + JE PAS16IRQ3QFilterMono + +PAS16IRQ3QFilterStereo: + Push BX + + Mov BX, FilterValue + Mov BP, FilterValue2 + ShR DX, 1 + +PAS16IRQ3QFilterStereo1: + Mov AX, BX + Mov CX, BP + Add AX, [SI] + Add CX, [SI+2] + SAR AX, 1 + SAR CX, 1 + Add BX, AX + Add BP, CX + SAR BX, 1 + SAR BP, 1 + + Mov AX, BX + SAR AX, 5 + + Test AH, AH + JNZ PAS163QFilterStereoClip1 + +PAS16IRQ3QFilterStereo2: + StosB + + Mov AX, BP + SAR AX, 5 + + Test AH, AH + JNZ PAS163QFilterStereoClip3 + +PAS16IRQ3QFilterStereo3: + StosB + + Add SI, 4 + Dec DX + JNZ PAS16IRQ3QFilterStereo1 + + Mov FilterValue, BX + Mov FilterValue2, BP + + Pop BX + + Jmp PAS16MixTransferEnd + +PAS16IRQ3QFilterMono: + Push BX + + Mov BX, FilterValue + +PAS16IRQ3QFilterMono1: + Mov AX, BX + Add AX, [SI] + SAR AX, 1 + Add BX, AX + SAR BX, 1 + Mov AX, BX + SAR AX, 6 + + Test AH, AH + JNZ PAS163QFilterMonoClip1 + +PAS16IRQ3QFilterMono2: + StosB + + Add SI, 4 + Dec DX + JNZ PAS16IRQ3QFilterMono1 + + Mov FilterValue, BX + + Pop BX + + Jmp PAS16MixTransferEnd + +PAS16IRQHFilter: + Cmp CS:Stereo, 0 + JE PAS16IRQHFilterMono + +PAS16IRQHFilterStereo: + Push BX + + Mov BX, FilterValue + Mov BP, FilterValue2 + ShR DX, 1 + +PAS16IRQHFilterStereo1: + Add BX, [SI] + Add BP, [SI+2] + + SAR BX, 1 + SAR BP, 1 + + Mov AX, BX + SAR AX, 5 + + Test AH, AH + JNZ PAS16HFilterStereoClip1 + +PAS16IRQHFilterStereo2: + StosB + + Mov AX, BP + SAR AX, 5 + + Test AH, AH + JNZ PAS16HFilterStereoClip3 + +PAS16IRQHFilterStereo3: + StosB + + Add SI, 4 + Dec DX + JNZ PAS16IRQHFilterStereo1 + + Mov FilterValue, BX + Mov FilterValue2, BP + + Pop BX + + Jmp PAS16MixTransferEnd + +PAS16IRQHFilterMono: + Push BX + + Mov BX, FilterValue + +PAS16IRQHFilterMono1: + Add BX, [SI] + SAR BX, 1 + Mov AX, BX + SAR AX, 6 + + Test AH, AH + JNZ PAS16HFilterMonoClip1 + +PAS16IRQHFilterMono2: + StosB + + Add SI, 4 + Dec DX + JNZ PAS16IRQHFilterMono1 + + Mov FilterValue, BX + + Pop BX + + Jmp PAS16MixTransferEnd + +PAS16IRQHandler6: + Mov AX, [SI] + SAR AX, CL + + Test AH, AH + JNZ PAS16IRQHandlerClip1 + +PAS16IRQHandler7: + StosB ; } Memory write + + Add SI, BP + Dec DX + JNZ PAS16IRQHandler6 + +PAS16MixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ PAS16IRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + PopAD + Pop DS + Pop BX + Pop AX + IRet + +PAS16IRQHandlerClip1: + Mov AL, 0FFh + JNS PAS16IRQHandler7 + Mov AL, 0 + Jmp PAS16IRQHandler7 + +PAS16HFilterMonoClip1: + Mov AL, 0FFh + JNS PAS16IRQHFilterMono2 + Mov AL, 0 + Jmp PAS16IRQHFilterMono2 + +PAS16HFilterStereoClip1: + Mov AL, 0FFh + JNS PAS16IRQHFilterStereo2 + Mov AL, 0 + Jmp PAS16IRQHFilterStereo2 + +PAS16HFilterStereoClip3: + Mov AL, 0FFh + JNS PAS16IRQHFilterStereo3 + Mov AL, 0 + Jmp PAS16IRQHFilterStereo3 + +PAS163QFilterMonoClip1: + Mov AL, 0FFh + JNS PAS16IRQ3QFilterMono2 + Mov AL, 0 + Jmp PAS16IRQ3QFilterMono2 + +PAS163QFilterStereoClip1: + Mov AL, 0FFh + JNS PAS16IRQ3QFilterStereo2 + Mov AL, 0 + Jmp PAS16IRQ3QFilterStereo2 + +PAS163QFilterStereoClip3: + Mov AL, 0FFh + JNS PAS16IRQ3QFilterStereo3 + Mov AL, 0 + Jmp PAS16IRQ3QFilterStereo3 + +EndP PAS16IRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + Push EAX + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + ; bump the interrupt to be called + ; 100 times a second. + Mov AX, TIMERCONST + Out 40h, AL + Mov AL, AH + Out 40h, AL + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset PAS16IRQHandler + + ClI + + XChg [ES:20h], EAX ; Hook to timer interrupt + Mov CS:OldIRQHandler, EAX + + StI + + Pop ES + Pop EAX + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + Push EAX + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Xor AL, AL + Out 40h, AL ; Interrupt called at normal 18.2 times + Out 40h, AL + + Mov EAX, CS:OldIRQHandler + Mov [ES:20h], EAX + + Pop ES + Pop EAX + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopPAS16 + + Mov DX, BasePort + Xor AL, AL + Xor DX, 0B89h xor 388h ; Interrupt Status register + Out DX, AL + + Mov DX, BasePort ; Audio filter control + Mov AL, 1 + Xor DX, 0B8Ah xor 388h ; Disable buffer counter + Out DX, AL ; and PAS 16 output + + Mov DX, BasePort + Mov AL, 19h ; Mono, L2L, R2R + Xor DX, 0F8Ah xor 388h ; Cross channel register + Out DX, AL + + Ret + +EndP StopPAS16 + +; + +Proc StartPAS16 ; + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Xor AL, AL + Xor DX, 0B89h xor 388h ; Interrupt Status register + Out DX, AL + + Mov DX, BasePort ; Audio filter control + Mov AL, 1 + Xor DX, 0B8Ah xor 388h ; Disable buffer counter + Out DX, AL ; and PAS 16 output + + Mov DX, BasePort + Mov AL, 19h + Xor DX, 0F8Ah xor 388h ; Cross channel register + Out DX, AL + + Mov DX, BasePort + Xor DX, 138Bh xor 388h ; Timer control, + Mov AL, 00110110b ; 36h - set frequency + Out DX, AL + + Mov DX, BasePort + Xor DX, 1388h xor 388h + Mov AX, PASMixConst + Cmp Stereo, 0 + JE StartPAS16_2 + + ShR AX, 1 + +StartPAS16_2: + Out DX, AL + Mov AL, AH + Out DX, AL + + Call GetMixSpeed + Call GetTempo + Call SetTempo + + Mov DX, BasePort + Xor DX, 138Bh xor 388h ; Timer control + Mov AL, 01110100b ; 74h - set buffer count + Out DX, AL + + Mov DX, BasePort ; Sample count + Mov AX, DMABUFFERLENGTH + Xor DX, 1389h xor 388h + + Cmp DMA, 4 + JB StartPAS16_1 + + ShR AX, 1 + +StartPAS16_1: + Out DX, AL + Mov AL, AH + Out DX, AL + + Mov AL, Stereo + Xor AL, 1 ; 0 if stereo, 1 if mono. + ShL AL, 5 + Mov DX, BasePort + Or AL, 099h ; Enable DRQ, DAC output + Xor DX, 0F8Ah xor 388h + Out DX, AL + Jmp $+2 + Jmp $+2 + Or AL, 40h ; Enable PCM + Out DX, AL + + Mov DX, BasePort + Xor DX, 0B8Bh xor 388h + In AL, DX + Or AL, 8 ; Enable sample buffer intr + Out DX, AL + + Mov DX, BasePort + Mov AL, 0E1h ; disable mute, enable sample rate + ; timer and sample buffer counter. + Xor DX, 0B8Ah xor 388h + Out DX, AL + + Pop DS + Pop ES + PopA + + Ret + + Assume DS:Nothing + +EndP StartPAS16 + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetPASMixConst + ; Parags to allocate = (4/(.4*31*16))*MixSpeed + 2080 + ; = 661*MixSpeed/65536 + + Mov AX, 1322 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset PAS16NoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset PAS16Msg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopPAS16 + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + +; In AL, 1 +; Mov AH, AL +; In AL, 1 +; Mov CS:Debug2, AX + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopPAS16 + Call StartPAS16 + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset PAS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Comment ~ + + Mov DX, BasePort + Add DL, 4 + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + + ~ + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/PCSPKDRV.ASM b/it/SoundDrivers/PCSPKDRV.ASM new file mode 100755 index 0000000..3e40cd8 --- /dev/null +++ b/it/SoundDrivers/PCSPKDRV.ASM @@ -0,0 +1,934 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 0 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 16 ; 16 bit mixing for the SB Pro +MIXTABLESIZE EQU 2*256*65 + +SBProMsg DB " Using Internal PC Speaker", 0 + +SBProNoMemoryMsg DB " Using Internal PC Speaker", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "PC Speaker reinitialised", 0 + +DSPVersion DW 0 +Forced DB 0 +InInterrupt DB 0 + +BytesToMix DW 1000 +MixSpeed DW 22000 +MixConst DW 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +DMASize DW 2048 + +OldIRQHandler DD 0 +TimerAccumulator DW 0 + +VolumeTable DB 256 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 +OutputBufferPos DW 0 +OutputBlockEnd DW 1024 + +include mix.inc +include mono12b.mix + +MixFunctionTables Label + +include mono12b.inc ; contains the tables + +; + +Proc GetMixConst ; Work out value.. and nearest + ; mixspeed value. Work out + ; volume translation table + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + + Cmp AX, 12000 + JB GetMixConst1 + + Cmp AX, 44100 + JA GetMixConst1 + + Mov CX, AX + +GetMixConst1: + Mov DX, 0012h + Mov AX, 34DDh + + Div CX + ; AX = mix const + Mov MixConst, AX + + Mov DX, 12h + Mov AX, 34DDh + Div MixConst + + Mov MixSpeed, AX + + Mov CX, 256 + Mov DI, Offset VolumeTable + Push CS + Pop ES + + ; Volume table = (PosInTable / 256) * MixConst +GetMixConst2: + Mov AX, 256 + Sub AX, CX + Mul MixConst + Add AX, 80h + Mov AL, AH + Inc AL + StosB + + Loop GetMixConst2 + + Pop ES + Pop DS + PopA + Ret + +EndP GetMixConst + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Mov AX, 0FFFFh + Push CS + Pop DS + Assume DS:Driver + + Cmp AX, IRQ + JNE DetectCard1 + Cmp AX, Baseport + JNE DetectCard1 + Cmp AX, DMA + JNE DetectCard1 + + Mov EAX, 'Jeff' + + ClC + Ret + +DetectCard1: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Mov AX, 2020h + + Mov BX, CX ; BX = bytes to mix + Mov DX, CX + + Mov MixTransferOffset, DI ; } Memory write + Rep StosW ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + Jmp MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + +Mix0Mode: ; 16-bit mixing, no interpolation, no ramping +Mix0ModeMono: + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AX, 30 ; Use left only-mixing for mono + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 60 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Mov [SI+8], AX ; Offset... + + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, MixTransferRemaining + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc PCSpeakerIRQHandler + + Push AX + Push BX + Push DS + + Mov DS, CS:DMASegment + Mov BX, CS:OutputBufferPos + + Mov AL, [BX] + Out 42h, AL + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Inc BX + ; OK.. which IRQ handler? + Mov AX, MixConst + Add TimerAccumulator, AX + JC PCSpeakerIRQHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp PCSpeakerIRQHandler2 + +PCSpeakerIRQHandler1: + PushF + Call OldIRQHandler + +PCSpeakerIRQHandler2: + Mov OutputBufferPos, BX + Cmp BX, OutputBlockEnd + JAE PCSpeakerIRQHandler3 + +PCSpeakerIRQHandlerEnd: + Pop DS + Pop BX + Pop AX + + IRet + +PCSpeakerIRQHandler3: + Mov BX, DMASize + Mov AX, OutputBlockEnd + Add AX, BX + Cmp AX, DMABUFFERLENGTH + JBE PCSpeakerIRQHandler4 + + Mov AX, BX + Mov OutputBufferPos, 0 + +PCSpeakerIRQHandler4: + Mov OutputBlockEnd, AX + + Cmp InInterrupt, 0 + JA PCSpeakerIRQHandlerEnd + + Inc InInterrupt + + ClD + + PushAD + Push ES + + Mov ES, CS:DMASegment + Mov DI, OutputBufferPos + + Call SaveEMSPageFrame + + StI + ; BX = bytes required + + Cmp MixTransferRemaining, 0 + JNE SBProIRQHandler4 + Assume DS:Nothing + +SBProIRQHandler3: + Push BX + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BX + +SBProIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SBProIRQHandler5 + + Mov DX, MixTransferRemaining + +SBProIRQHandler5: + Push BX + Push DX + +SBProIRQHandler6: + Mov BX, [SI] + SAR BX, 6 + + Test BH, BH + JNZ SBProIRQHandlerClip1 + +SBProIRQHandler7: + Mov AL, [CS:VolumeTable+BX] + StosB ; } Memory write + + Add SI, 2 + Dec DX + JNZ SBProIRQHandler6 + + Pop DX + Pop BX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SBProIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Dec InInterrupt + +PCSpkEnd2: + Pop ES + PopAD + Pop DS + Pop BX + Pop AX + IRet + +SBProIRQHandlerClip1: + Mov BX, 0 + JS SBProIRQHandler7 + Mov BX, 0FFh + Jmp SBProIRQHandler7 + +EndP PCSpeakerIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov OutputBufferPos, 0 + Mov OutputBlockEnd, 1024 + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Mov AX, MixConst + Out 40h, AL + Mov AL, AH + Out 40h, AL + ; Program PC Speaker's IRQ + Mov AL, 90h + Out 43h, AL + + In AL, 61h + Or AL, 3 + Out 61h, AL ; Enable sound. + + Xor AX, AX + Mov ES, AX + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset PCSpeakerIRQHandler + + ClI + + XChg [ES:20h], EAX + Mov OldIRQHandler, EAX + + StI + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AL, 0B6h ; Reset PCSpeaker control + Out 43h, AL + + In AL, 61h ; Enable PC Speaker to be + And AL, 0FCh ; controlled by other programs + Out 61h, AL + + + Mov AL, 34h ; Reset IRQ calling rate. + Out 43h, AL + Xor AL, AL + Out 40h, AL + Out 40h, AL + + Xor AX, AX + Mov ES, AX + + Mov EAX, OldIRQHandler + Mov [ES:20h], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + Call GetMixConst + + Mov AX, 661 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SBProNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call GetTempo + Call SetTempo + Call SetIRQ + + Mov SI, Offset SBProMsg + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + StC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/PNP.INC b/it/SoundDrivers/PNP.INC new file mode 100755 index 0000000..fecac2e --- /dev/null +++ b/it/SoundDrivers/PNP.INC @@ -0,0 +1,224 @@ +; +; Plug and play include file. Driver needs to define PNPVENDORID and +; PNPSERIALID which will be used to identify the card. +; +; Call function PnP_Detect +; + + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 + +; + +Proc PnP_Delay + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadRegister + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadRegister + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or SerialNumber, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + + Mov AL, 74 + Call PnP_ReadData ; AL[2:0] = DMA + + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Cmp PnP_CSN, 0 + JNE PnP_IsolateEnd + + StC + +PnP_IsolateEnd: + Ret + +EndP PnP_Isolate + +; + +Proc Pnp_Detect ; returns carry clear if succesful + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JNC PnP_DetectEnd + + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JNC PnP_DetectEnd + + Mov PnP_ReadPort, 213h + Call PnP_Isolate + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + + Ret + +EndP PnP_Detect + +; + diff --git a/it/SoundDrivers/Q.INC b/it/SoundDrivers/Q.INC new file mode 100755 index 0000000..c6e45a4 --- /dev/null +++ b/it/SoundDrivers/Q.INC @@ -0,0 +1,34 @@ + +QualityFactorTable Label DWord + DD 3F800000h, 3F7A8874h, 3F752ECBh, 3F6FF262h + DD 3F6AD298h, 3F65CED3h, 3F60E678h, 3F5C18F1h + DD 3F5765ACh, 3F52CC19h, 3F4E4BACh, 3F49E3DCh + DD 3F459421h, 3F415BF8h, 3F3D3AE1h, 3F39305Ch + DD 3F353BEFh, 3F315D21h, 3F2D937Ch, 3F29DE8Ch + DD 3F263DE0h, 3F22B109h, 3F1F379Ah, 3F1BD12Ah + DD 3F187D50h, 3F153BA8h, 3F120BCDh, 3F0EED5Fh + DD 3F0BDFFDh, 3F08E34Bh, 3F05F6EEh, 3F031A8Ch + DD 3F004DCEh, 3EFB20BEh, 3EF5C3D4h, 3EF0843Ch + DD 3EEB6156h, 3EE65A84h, 3EE16F2Dh, 3EDC9EBBh + DD 3ED7E89Bh, 3ED34C3Ch, 3ECEC913h, 3ECA5E95h + DD 3EC60C3Bh, 3EC1D181h, 3EBDADE7h, 3EB9A0EEh + DD 3EB5AA1Ah, 3EB1C8F2h, 3EADFCFFh, 3EAA45CEh + DD 3EA6A2EDh, 3EA313EEh, 3E9F9862h, 3E9C2FE1h + DD 3E98DA02h, 3E95965Fh, 3E926494h, 3E8F4440h + DD 3E8C3504h, 3E893681h, 3E86485Dh, 3E836A3Eh + DD 3E809BCCh, 3E7BB965h, 3E765939h, 3E711670h + DD 3E6BF06Ah, 3E66E68Ah, 3E61F836h, 3E5D24D6h + DD 3E586BD9h, 3E53CCADh, 3E4F46C5h, 3E4AD998h + DD 3E46849Eh, 3E424752h, 3E3E2134h, 3E3A11C4h + DD 3E361887h, 3E323503h, 3E2E66C2h, 3E2AAD4Fh + DD 3E270838h, 3E23770Fh, 3E1FF965h, 3E1C8ED2h + DD 3E1936ECh, 3E15F14Ch, 3E12BD91h, 3E0F9B56h + DD 3E0C8A3Eh, 3E0989E9h, 3E0699FDh, 3E03BA20h + DD 3E00E9F9h, 3DFC5268h, 3DF6EEF8h, 3DF1A8FCh + DD 3DEC7FD5h, 3DE772E5h, 3DE28191h, 3DDDAB43h + DD 3DD8EF67h, 3DD44D6Ch, 3DCFC4C4h, 3DCB54E6h + DD 3DC6FD4Ah, 3DC2BD6Ah, 3DBE94C7h, 3DBA82DFh + DD 3DB68738h, 3DB2A157h, 3DAED0C5h, 3DAB150Eh + DD 3DA76DC0h, 3DA3DA6Ch, 3DA05AA3h, 3D9CEDFCh + DD 3D99940Eh, 3D964C71h, 3D9316C3h, 3D8FF2A1h + DD 3D8CDFABh, 3D89DD84h, 3D86EBCFh, 3D840A32h diff --git a/it/SoundDrivers/REQPROC.INC b/it/SoundDrivers/REQPROC.INC new file mode 100755 index 0000000..0cdbebc --- /dev/null +++ b/it/SoundDrivers/REQPROC.INC @@ -0,0 +1,31 @@ + +ProcedureTableStart Label +Update DD 0 +GetSampleHeader DD 0 +GetSampleLocation DD 0 + DD 0 +GetEMSPageFrame DD 0 +SaveEMSPageFrame DD 0 +RestoreEMSPageFrame DD 0 +GetTempo DD 0 ; Gets tempo in BX +M_FunctionHandler DD 0 +SetInfoLine DD 0 +Music_LoadAllSamples DD 0 +GlobalKeyList DD 0 +IdleUpdateInfoLine DD 0 +DrawHeaderFunction DD 0 +FillHeaderFunction DD 0 +GotoHomeDirectory DD 0 +GetFileName DD 0 +SetDirectory DD 0 +StopPlayback DD 0 +GetEnvironment DD 0 +GetChannelTables DD 0 +RecalculateAllVolumes DD 0 +UARTBufferEmpty DD 0 +UARTSend DD 0 +S_GetDestination DD 0 +S_DrawString DD 0 + DD 32 - ($-ProcedureTableStart)/4 Dup (0) + + diff --git a/it/SoundDrivers/SAM9407.ASM b/it/SoundDrivers/SAM9407.ASM new file mode 100755 index 0000000..67bfa61 --- /dev/null +++ b/it/SoundDrivers/SAM9407.ASM @@ -0,0 +1,1008 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;*********************************************** + +NUMMEMORYBLOCKS EQU 64 + +PNPSERIALID EQU 0FFFFFFFFh +PNPVENDORID EQU 80719304h + +MMT_MAXENTRIES EQU 64 +MMT_MAXSIZE EQU 3*MMT_MAXENTRIES + + +SAM_RD_MEM EQU 2h +SAM_GET_MMT EQU 3h +SAM_GEN_INT EQU 48h +SAM_GET_VOI EQU 51h +SAM_VOI_OPEN EQU 52h +SAM_VOI_CLOSE EQU 53h +SAM_VOI_START EQU 54h +SAM_VOI_STOP EQU 55h +SAM_VOI_VOL EQU 56h +SAM_VOI_MAIN EQU 57h +SAM_VOI_PITCH EQU 58h +SAM_VOI_AUX EQU 59h +SAM_VOI_FILT EQU 5Ah +SAM_VOI_MEM EQU 5Bh +SAM_GET_POS EQU 5Ch +SAM_ADD_POS EQU 5Dh + +SAM9407Message DB "Dream SAM9407 Detected", 13 + DB "Port ", 0FDh, "Xh, ", 0FDh, "Dk RAM", 0 + +StatusLine DB "FreeSAM ", 0FDh, "Dk", 0 + +SAMUpdateFlag DB 0 + +ALIGN 4 +OldIRQHandler DD 0 +SAMUpdateTimer DW 0 +SAMUpdateCount DW 0 + +MMTData DW MMT_MAXSIZE Dup (0) + +MemoryBlocks DD NUMMEMORYBLOCKS*2 Dup (0) + ; Memory blocks are offset/size pairs. + +SampleInformation DD 100*4 Dup (0) + ; Sample data is a struct + ; Offset 0: Starting address + ; Offset 4: Loop start + ; Offset 8: Loop end + ; Offset 0Ch: ?? + +SlaveChannelOffset DW 0 + +; EmptyFunction + +Proc EmptyFunction Far + + Xor AX, AX + StC + Ret + +EndP EmptyFunction + +; + +Proc SAM9407ReceiveByte ; Returns AL = data + ; BL = status + + Push DX + Mov DX, CS:BasePort + Inc DX + +SAM9407ReceiveByte1: + In AL, DX + Test AL, AL + JS SAM9407ReceiveByte1 + + Mov BL, AL + Dec DX + And BL, 30h + + In AL, DX + Pop DX + + Ret + +EndP SAM9407ReceiveByte + +; + +Proc SAM9407ReceiveWord ; Returns AX + + Call SAM9407ReceiveByte + Mov AL, AH + Call SAM9407ReceiveByte + XChg AL, AH + + Ret + +EndP SAM9407ReceiveWord + +; + +Proc SAM9407ReceiveDWord ; Returns EAX + + Call SAM9407ReceiveByte + RoR EAX, 8 + Call SAM9407ReceiveByte + RoR EAX, 8 + Call SAM9407ReceiveByte + RoR EAX, 8 + Call SAM9407ReceiveByte + RoR EAX, 8 + + Ret + +EndP SAM9407ReceiveDWord + +; + +Proc SAM9407SendControlByte ; BL = data + + Push AX + Push DX + + Mov DX, CS:BasePort + Inc DX + +SAM9407SendControlByte1: + In AL, DX + Test AL, 40h + JNZ SAM9407SendControlByte1 + + Mov AL, BL + Out DX, AL + + Pop DX + Pop AX + + Ret + +EndP SAM9407SendControlByte + +; + +Proc SAM9407SendDataByte ; AL = data + + Push DX + Push AX + + Mov DX, CS:BasePort + Inc DX + +SAM9407SendDataByte1: + In AL, DX + Test AL, 40h + JNZ SAM9407SendDataByte1 + + Pop AX + Dec DX + + Out DX, AL + + Pop DX + + Ret + +EndP SAM9407SendDataByte + +; + +Proc SAM9407SendDataWord ; AX = data + + Call SAM9407SendDataByte + Mov AL, AH + Call SAM9407SendDataByte + Ret + +EndP SAM9407SendDataWord + +; + +Proc SAM9407SendDataDWord ; EAX = data + + Call SAM9407SendDataByte + ShR EAX, 8 + Call SAM9407SendDataByte + ShR EAX, 8 + Call SAM9407SendDataByte + ShR AX, 8 + Call SAM9407SendDataByte + Ret + +EndP SAM9407SendDataDWord + +; + +Proc SAM9407ReceiveString ; ES:DI points to deposit point. + ; EAX = memory address + ; CX = count + + Mov BL, SAM_RD_MEM + Call SAM9407SendControlByte + Call SAM9407SendDataDWord + Mov AX, CX + Call SAM9407SendDataWord + +SAM9407InString1: + Call SAM9407ReceiveByte + Cmp AL, 0ABh + JE SAM9407InStringError + Cmp AL, 0ACh + JNE SAM9407InString1 + +SAM9407InString2: + Mov DX, CS:BasePort + Add DX, 2 + + Rep InsW + + DB 85h + +SAM9407InStringError: + StC + Ret + +EndP SAM9407ReceiveString + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc ResetWaitforSend ; Given DX = control port + + Xor CX, CX + +ResetWaitforSend1: + In AL, DX + Test AL, 40h + LoopNZ ResetWaitforSend + Ret + +EndP ResetWaitforSend + +; + +Proc ResetWaitforReceive + + Xor CX, CX + +ResetWaitforReceive1: + In AL, DX + Test AL, 80h + JNZ ResetWaitforReceive2 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE ResetWaitforReceive3 + +ResetWaitforReceive2: + Loop ResetWaitforReceive1 + + StC + Ret + +ResetWaitforReceive3: + ClC + Ret + +EndP ResetWaitforReceive + +; + +Proc SAMSendChannelNumber + + Mov AX, SI + Sub AX, CS:SlaveChannelOffset + ShR AX, 7 + Call SAM9407SendDataByte + + Ret + +EndP SAMSendChannelNumber + +; + +Proc SAMOpenVoice + + Cmp Byte Ptr [SI+2], 1 + JE SAMOpenVoice1 ; Already opened! + + Mov Byte Ptr [SI+2], 1 + + Mov BL, [SI+36h] ; Sample number + Xor DH, DH + And BX, 0FFh + ShL BX, 4 + + Mov DL, [Byte Ptr CS:SampleInformation+BX+3] + Sub DL, [Byte Ptr CS:SampleInformation+BX+7] + ; Carry 0 if inbank + ; Carry 1 if crossbank + + SBB DL, DL ; DL = 0 inbank + ; DL = 0FFh crossbank + + ShL DL, 7 ; DL = 0 inbank + ; DL = 80h crossbank + + Mov BL, SAM_VOI_OPEN + Call SAM9407SendControlByte + + Mov AX, SI + Sub AX, CS:SlaveChannelOffset + ShR AX, 7 + Or AL, DL + Call SAM9407SendDataByte + +SAMOpenVoice1: + Ret + +EndP SAMOpenVoice + +; + +Proc SAMStopNote ; Closes the voice. + + Cmp Byte Ptr [SI+2], 1 + JNE SAMStopNote1 + + Mov Byte Ptr [SI+2], 0 + Mov BL, SAM_VOI_CLOSE + Call SAM9407SendControlByte + Call SAMSendChannelNumber + +SAMStopNote1: + Ret + + +EndP SAMStopNote + +; + +Proc SAMSetVolume + + Cmp Byte Ptr [SI+2], 1 + JNE SAMSetVolume1 + + Mov BL, SAM_VOI_VOL + Call SAM9407SendControlByte + Call SAMSendChannelNumber + Mov AL, [SI+20h] + Call SAM9407SendDataByte + +SAMSetVolume1: + Ret + +EndP SAMSetVolume + +; + +Proc SAMSetPan + + Cmp Byte Ptr [SI+2], 1 + JNE SAMSetPan1 + +Comment ~ + Mov BL, SAM_VOI_PAN + Call SAM9407SendControlByte + Call SAMSendChannelNumber + Mov AL, [SI+37h] + Call SAM9407SendDataByte +~ +SAMSetPan1: + Ret + +EndP SAMSetPan + +; + +Proc SAMSetPitch + +; Pitch value sent is 400h for nominal frequency of 37.5khz, linear scale +; -> Value sent = Frequency*400h / 37500 +; = Frequency * 0.02730666 +; = Frequency * 117281240 / 2^32 + + Cmp Byte Ptr [SI+2], 1 + JNE SAMSetPitch3 + + Mov EAX, 117281240 + Mul DWord Ptr [SI+10h] + + Cmp EDX, 0FFFFh + JA SAMSetPitch1 + + Mov BL, SAM_VOI_PITCH + Call SAM9407SendControlByte + Call SAMSendChannelNumber + Mov AX, DX + Call SAM9407SendDataWord + +SAMSetPitch3: + Ret + +SAMSetPitch1: + Call SAMStopNote + + Mov Word Ptr [SI], 200h + Test Byte Ptr [SI+3Ah], 80h + JNZ SAMSetPitch2 + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Signify channel off + +SAMSetPitch2: + Ret + +EndP SAMSetPitch + +; + +Proc SAMSetRegisters + +; First get offset of currently playing notes + +; Update Registers to play notes + +; Flow is as follows: +; If new note, open voice +; +; If pitch change, set pitch +; If volume change, set volume + filters +; +PlayNote: + + Ret + +EndP SAMSetRegisters + +; + +Proc SAMIRQHandler ; IRQ Handler has to + ; 1) Update GUS registers + ; 2) Update song position + Push AX + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, SAMUpdateTimer + Add SAMUpdateCount, AX + JC SAMIRQHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp SAMIRQHandler2 + +SAMIRQHandler1: + PushF + Call [OldIRQHandler] + +SAMIRQHandler2: + Xor SAMUpdateFlag, 1 + JZ SAMIRQHandlerEnd + + PushAD + Push ES + + ClD + + Call SaveEMSPageFrame + Call Update ; Returns DS:SI, CX + Assume DS:Nothing + + Mov SlaveChannelOffset, SI + + Call SAMSetRegisters + Call RestoreEMSPageFrame + + Pop ES + PopAD + +SAMIRQHandlerEnd: + Pop DS + Pop AX + IRet + +EndP SAMIRQHandler + +; + +Proc ResetUART ; Given DX = Port + + Inc DX + + Mov AL, 0FFh ; Reset! + Out DX, AL + Out DX, AL ; Two resets required to ensure it'll work + + Call ResetWaitforReceive + JNC ResetUART1 + +ResetUARTError: + StC + Ret + +ResetUART1: ; Now to shove it into 'intelligent' mode. + Call ResetWaitforSend + JNZ ResetUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + + Call ResetWaitforReceive + JC ResetUARTError + + Call ResetWaitforSend + JNZ ResetUARTError + + Mov AL, SAM_GEN_INT + Out DX, AL + + Call ResetWaitforSend + JNZ ResetUARTError + + Dec DX + Xor AL, AL + Out DX, AL + Inc DX + + Xor CX, CX + +ResetUART2: + In AL, DX + Test AL, 80h + JNZ ResetUART3 + + Mov AH, AL + Dec DX + In AL, DX + Inc DX + And AH, 30h + Cmp AX, 3088h + JE ResetUART4 + +ResetUART3: + Loop ResetUART2 + Jmp ResetUARTError + +ResetUART4: + Call ResetWaitforReceive + JC ResetUARTError + + Dec DX + + ClC + Ret + +EndP ResetUART + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + +; Check whether the MPU can be reset + Mov DX, BasePort + Cmp DX, 0FFFFh + JE DetectCard1 + + Call ResetUART + JNC DetectCardFound + +DetectCardExit: + Ret + +DetectCard1: + Mov DX, 330h + Call ResetUART + JNC DetectCard2 + + Mov DX, 300h + Call ResetUART + JC DetectCardExit + +DetectCard2: + Mov BasePort, DX + +DetectCardFound: +; Find memory mapping table, + Mov BL, SAM_GET_MMT + Xor AL, AL + Call SAM9407SendControlByte + Call SAM9407SendDataByte + Call SAM9407ReceiveDWord + + Push CS + Pop ES + Mov CX, MMT_MAXSIZE + Mov DI, Offset MMTData + Call SAM9407ReceiveString + + Mov EAX, 'Jeff' + Ret + +EndP DetectCard + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Call GetTempo + Call SetTempo + Call ResetMemory + + Xor AX, AX + Mov ES, AX ; ES = 0 + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SAMIRQHandler + + ClI + + XChg DWord Ptr [ES:20h], EAX ; Clock tick + Mov OldIRQHandler, EAX + + StI + + Mov SI, Offset SAM9407Message + Xor BX, BX + +Comment ~ + Mov BL, SAM_GET_VOI + Xor AL, AL + Call SAM9407SendControlByte + Call SAM9407SendDataByte + Call SAM9407ReceiveByte + Mov BL, AL +~ + Mov AX, BasePort + Mov EBX, DWord Ptr [MMTData+2] + ShR EBX, 9 + + ClC + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov BL, 0FFh + Call SAM9407SendControlByte + + Mov AL, 34h + Out 43h, AL + + Xor AX, AX + Out 40h, AL + Out 40h, AL + + Mov ES, AX + Mov EAX, OldIRQHandler + Mov [ES:20h], EAX + + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far ; BX = tempo... + + Push AX + Push BX + Push DX + + ; Frames per second = 2 * (0.4*Tempo) + Mov AX, 0C214h + Mov DX, 16h ; Ticks = (1193181/(2*0.4))/Tempo + Div BX + + ; AX contains counter. + Mov CS:SAMUpdateTimer, AX + + Out 40h, AL ; Timer IRQ. + Mov AL, AH + Out 40h, AL + + Pop DX + Pop BX + Pop AX + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load (0 based) +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release (1 based) +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Push CS + Pop ES + + Mov SI, Offset MMTData+6 + Mov DI, Offset MemoryBlocks + +ResetMemory1: + Mov AX, [SI] + Add SI, 6 + + Cmp AX, -1 + JE ResetMemory2 + + Cmp AX, 1 + JNE ResetMemory1 + + Mov EAX, [SI-4] + StosD + Neg EAX + Add EAX, [SI+2] + StosD + Jmp ResetMemory1 + +ResetMemory2: + Mov CX, Offset MemoryBlocks+NUMMEMORYBLOCKS*2*4 + Sub CX, DI + Xor AX, AX + ShR CX, 1 + Rep StosW + + Pop ES + Pop DS + PopA + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset MemoryBlocks+4 + Mov CX, NUMMEMORYBLOCKS + Xor EAX, EAX + +GetStatus1: + Add EAX, [SI] + Add SI, 8 + Loop GetStatus1 + + Mov SI, Offset StatusLine + ShR EAX, 9 + + ClC + Ret + +EndP GetStatus + Assume DS:Nothing + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Xor AX, AX + StC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 64 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 64 + + DW 5 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SB16B.ASM b/it/SoundDrivers/SB16B.ASM new file mode 100755 index 0000000..d1855cb --- /dev/null +++ b/it/SoundDrivers/SB16B.ASM @@ -0,0 +1,2001 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 16 ; 16 bit mixing for the SB16 +MIXTABLESIZE EQU 2*256*65 + +SB16Msg DB "Sound Blaster 16 detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SB16NoMemoryMsg DB "Sound Blaster 16 detected", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster 16 reinitialised", 0 + +DSPVersion DW 0 +DSPIRQValue DB 0 +DSPDMAValue DB 0 +Forced DB 0 +Stereo DB 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 +MixSegmentLength DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 8 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 +DMASize DW 2048 + +IMR DW 0 +OldIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MIDIPort DW 0 +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SB16ScreenList Label + DW 8 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SB16HeaderLine + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + DW Near Ptr VolumeBox2 + + DW Near Ptr DriverText + + DW Near Ptr MasterVolumeLeft ; 8 + DW Near Ptr MasterVolumeRight ; 9 + DW Near Ptr TrebleVolumeLeft ; 10 + DW Near Ptr TrebleVolumeRight ; 11 + DW Near Ptr BassVolumeLeft ; 12 + DW Near Ptr BassVolumeRight ; 13 + + DW Near Ptr MixFrequencyText + + DW 0 + +SB16HeaderLine DW 10 + DB "Sound Blaster 16 Driver", 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "Sound Blaster 16 Driver 1.4 for Impulse Tracker", 0 + +VolumeText DW 1 + DB 2, 13 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB 13 + DB 13 + DB "Treble Left", 13 + DB "Treble Right", 13 + DB "Bass Left", 13 + DB "Bass Right", 13 + DB 0 + +MixFrequencyText DW 1 + DB 2, 23 + DB 20h + DB "Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 45454 + +VolumeBox1 DW 0 + DB 21, 12, 27, 15 + DB 25 + +VolumeBox2 DW 0 + DB 14, 16, 18, 21 + DB 25 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MasterVolumeLeft DW 9 + DB 22, 13 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 14 + DW 0, 31 + DW 9, 1 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeLeft DW 9 + DB 15, 17 + DW 0, 15 + DW 9, 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeRight DW 9 + DB 15, 18 + DW 0, 15 + DW 9, 3 + DW 10, 12, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeLeft DW 9 + DB 15, 19 + DW 0, 15 + DW 9, 4 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeRight DW 9 + DB 15, 20 + DW 0, 15 + DW 9, 5 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +VolumeTable DB 6 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc DetectUART ; Given DX = Port + +; From SB-DevKit + + ClI + + Inc DX + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 40h ; Ready for output + LoopNZ DetectUART1 + JNZ DetectUARTError + + Mov AL, 0FFh ; Reset! + Out DX, AL + + Xor CX, CX +DetectUART2: + In AL, DX + Test AL, 80h + JNZ DetectUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART4 + +DetectUART3: + Loop DetectUART2 + +DetectUARTError: + StI + StC + Ret + +DetectUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +DetectUART5: + In AL, DX + Test AL, 40h + LoopNZ DetectUART5 + JNZ DetectUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +DetectUART6: + Xor CX, CX +DetectUART7: + In AL, DX + Test AL, 80h + JNZ DetectUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART9 + +DetectUART8: + Loop DetectUART7 + + Jmp DetectUARTError + +DetectUART9: + StI + ClC + Ret + + +Comment ~ + + ClI + + Mov BH, 3 ; Try to init port twice. + +DetectUART1: + Mov BL, 64 ; 64 byte buffer + + Inc DX + Mov AL, 0FFh + Out DX, AL + + Mov AL, 3Fh + Out DX, AL + +DetectUART2: + Mov CX, 04000h + +DetectUART3: + In AL, DX + Test AL, 80h + LoopNZ DetectUART3 + JZ DetectUART4 + + Dec BH + JNZ DetectUART1 + + StI + StC + Ret + +DetectUART4: + Dec DX + In AL, DX + Inc DX + + Cmp AL, 0FEh ; UART acknowledge. + JE DetectUART5 + + Dec BL + JNZ DetectUART2 + + Dec BH + JNZ DetectUART1 + +DetectUART6: + StC + +DetectUART5: + StI + Ret + + ~ + +EndP DetectUART + +; + +Proc ReinitUART + + Mov DX, MIDIPort + Test DX, DX + JZ ReinitUART1 + + Call DetectUART + +ReinitUART1: + Ret + +EndP ReinitUART + +; + +Proc ResetUART + + Mov DX, MIDIPort + Test DX, DX + JZ ResetUART1 + + Inc DX + Mov AL, 0FFh + Out DX, AL + +ResetUART1: + Ret + +EndP ResetUART + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 45454 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +Proc ResetDSPIRQ + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPIRQValue + Mov AL, 80h + Out DX, AX + + Ret + +EndP ResetDSPIRQ + +; + +Proc ResetDSPDMA + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPDMAValue + Mov AL, 81h + Out DX, AX + + Ret + +EndP ResetDSPDMA + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AH, 4 ; SB DSP = 4.00+ + JAE DetectCard5 + +DetectCard4: + StC + Ret + +DetectCard5: + Mov DSPVersion, AX + + Add DL, 04h-0Eh ; 2x4h = Mixer index port + Mov AL, 80h ; IRQ select + Out DX, AL + Inc DL ; 2x5h = Mixer data port + + In AL, DX + + Dec DL + + Mov DSPIRQValue, AL + ; OK.. now get IRQ, or set IRQ + Mov BX, IRQ + Cmp BX, 0FFFFh + JE DetectCardIRQ1 + Cmp Forced, 0 + JE DetectCardIRQ1 + + Mov AH, 11h + Cmp BL, 2 + JE SetCardIRQ1 + Cmp BL, 9 + JE SetCardIRQ1 + + Mov AH, 12h + Cmp BL, 5 + JE SetCardIRQ1 + + Mov AH, 14h + Cmp BL, 7 + JE SetCardIRQ1 + + Mov AH, 18h + Cmp BL, 10 + JE SetCardIRQ1 + + StC + Ret + +SetCardIRQ1: + Mov AL, 80h + Out DX, AL + Inc DL + Mov AL, AH + Out DX, AL + Dec DL + Jmp DetectCard6 + +DetectCardIRQ1: + Mov BX, 2 + Test AL, 1 + JNZ DetectCardIRQ2 + + Mov BL, 5 + Test AL, 2 + JNZ DetectCardIRQ2 + + Mov BL, 7 + Test AL, 4 + JNZ DetectCardIRQ2 + + Mov BL, 10 + Test AL, 8 + JNZ DetectCardIRQ2 + + StC + Ret + +DetectCardIRQ2: + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + + Cmp BX, IRQ + JE DetectCard6 + + StC + Ret + +DetectCardIRQ3: + Mov IRQ, BX + +DetectCard6: ; Detect DMA + Mov AL, 81h ; DMA select + Out DX, AL + Inc DL + In AL, DX ; AL = DMA + Dec DL + + Mov DSPDMAValue, AL + + Mov BX, DMA + Cmp BX, 0FFFFh + JE DetectCardDMA1 + Cmp Forced, 0 + JE DetectCardDMA1 + + Mov CL, 1 + Cmp BX, 1 + JB SetCardDMA1 + + Mov CL, 2 + JE SetCardDMA1 + + Cmp BX, 3 + JB DetectCard7 + + Mov CL, 8 + JE DetectCard7 + + Mov CL, 20h + Cmp BX, 5 + JB DetectCard7 + JE SetCardDMA1 + + Mov CL, 80h + Cmp BX, 7 + JA DetectCard7 + JE SetCardDMA1 + + Mov CL, 40h + +SetCardDMA1: + And AL, 0Bh + Test CL, 0Bh + JZ SetCardDMA4 + + Xor AL, AL + +SetCardDMA4: + Or CL, AL + + Mov AL, 81h + Out DX, AL + Inc DL + Mov AL, CL + Out DX, AL + Jmp DetectCard7 + +DetectCardDMA1: + Mov BX, 5 + Test AL, 20h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 40h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 80h + JNZ DetectCardDMA2 + + Mov BL, 0 + Test AL, 1 + JNZ DetectCardDMA2 + + Inc BL + Test AL, 2 + JNZ DetectCardDMA2 + + Add BL, 2 + Test AL, 8 + JNZ DetectCardDMA2 + +DetectCard8: + Call ResetDSPIRQ + StC + Ret + +DetectCardDMA2: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + + Cmp BX, DMA + JNE DetectCard8 + +DetectCardDMA3: + Mov DMA, BX + +DetectCard7: + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Add DX, DX + +MixSamples1: + Rep StosD ; } Memory write + +MixSamplesCont: + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Cmp Stereo, 0 + JNE Mix0ModeStereo + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc AckIRQ + Assume DS:Driver + + Mov AL, 20h + Cmp IRQ, 7 + JBE AckIRQ1 + + Out 0A0h, AL + +AckIRQ1: + Out 20h, AL + Ret + +EndP AckIRQ + Assume DS:Nothing + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Mov DX, MIDIPort + + Mov BL, [MIDIBufferTail] + Test DX, DX + JZ CheckMIDIEnd + + Inc DX + Mov CX, 0FFFFh + +CheckMIDIAgain: + In AL, DX + + Test AL, 80h + LoopNZ CheckMIDIAgain + + Dec DX + In AL, DX + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL +; Jmp CheckMIDIAgain + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc SB16IRQHandler + + PushAD + Push DS + Push ES + + CLD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 4 ; Mixer Port + Mov AL, 82h + Out DX, AL + Inc DL ; DX = BasePort+5 + In AL, DX + + Comment ~ + + Test AL, 1 + JZ SB8BitDigitalInterruptEnd + +SB8BitDigitalInterrupt: + Push AX + Add DL, 0Eh-5 + In AL, DX + Pop AX + +SB8BitDigitalInterruptEnd: + + ~ + + Test AL, 4 + JZ SBMIDIInterruptEnd + + Push AX + Call CheckMIDI + Pop AX + +SBMIDIInterruptEnd: + Test AL, 2 + JNZ SBDigitalInterrupt + + Call AckIRQ + Jmp SBIRQEnd + +SBDigitalInterrupt: + Mov DX, BasePort + Add DL, 0Fh + In AL, DX ; 16-bit IRQ ack. + + Call AckIRQ + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB SB16IRQHandler2 + + Xor AX, AX + Xor BX, BX + +SB16IRQHandler2: + Inc BX + Mov MixBufferPos, BX + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 4 ; Skip for mono + Mov CL, 2 ; Shift for mono + + Cmp Stereo, 0 + JE SB16IRQHandlerMono + + ShR BP, 1 + Inc CL + +SB16IRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SB16IRQHandler4 + Assume DS:Nothing + +SB16IRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +SB16IRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SB16IRQHandler5 + + Mov DX, MixTransferRemaining + +SB16IRQHandler5: + Push DX + +SB16IRQHandler6: + MovSX EAX, Word Ptr [SI] + SAL EAX, CL + + Cmp EAX, -8000h + JL SB16IRQHandlerClip1 + Cmp EAX, 7FFFh + JG SB16IRQHandlerClip2 + +SB16IRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ SB16IRQHandler6 + +SB16MixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SB16IRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + +SBIRQEnd: + + Pop ES + Pop DS + PopAD + IRet + +SB16IRQHandlerClip1: + Mov AX, 8000h + Jmp SB16IRQHandler7 + +SB16IRQHandlerClip2: + Mov AX, 7FFFh + Jmp SB16IRQHandler7 + +EndP SB16IRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SB16IRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSB16 ; + + PushA + Push ES + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0B6h ; 16 bit, DAC + Call SBOut + Mov AL, Stereo + ShL AL, 5 + Or AL, 10h + Call SBOut + + Mov AX, DMASize + ShR AX, 1 + Dec AX + + Call SBOut ; DMALength, Lo + Mov AL, AH + Call SBOut + + Pop ES + PopA + + Ret + + Assume DS:Nothing + +EndP StartSB16 + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + + Mov AL, 30h + Call SBGetRegister + ShR AL, 3 + Mov VolumeTable, AL + + Mov AL, 31h + Call SBGetRegister + ShR AL, 3 + Mov [VolumeTable+1], AL + + Mov AL, 44h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+2], AL + + Mov AL, 45h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+3], AL + + Mov AL, 46h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+4], AL + + Mov AL, 47h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+5], AL + + Call GetSBMixConst + + ; Parags to allocate = (4/(.4*31*16))*MixSpeed + 2080 + ; = .02016129*MixSpeed = (65536*.04032258*MixSpeed) / 65536 + + Mov AX, 1322 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SB16NoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + Sub DX, 2080 + Mov MixSegmentLength, DX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov DX, 330h + Call DetectUART + JC DetectMIDI1 + + Mov MIDIPort, 330h + Jmp DetectMIDIEnd + +DetectMIDI1: + Mov DX, 300h + Call DetectUART + JC DetectMIDIEnd + + Mov MIDIPort, 300h + +DetectMIDIEnd: + + Mov SI, Offset SB16Msg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, BasePort + Mov DX, AX + Call ResetDSP + + Call ResetUART + Call ResetIRQ + ; Delay.. + Mov DX, BasePort + Add DL, 0Ch + + Mov CX, 1000 +ReInitSound1: + In AL, DX + Loop ReInitSound1 + + Call SetIRQ + Call ReinitUART + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov DX, CS:BasePort + Add DL, 0Ch + + Mov AL, 0D3h + Call SBOut + + Mov AL, 0D5h + Call SBOut + + Mov AL, 0D9h + Call SBOut + + Mov AL, 0D5h + Call SBOut + + Call ResetUART + + Mov AX, BasePort + Call ResetDSP + + Call ResetDSPDMA + Call ResetDSPIRQ + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Dec CX + JNZ SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov CS:Stereo, AL + Mov AX, CS:BasePort + Call ResetDSP + + Mov ES, CS:MixSegment + Mov CX, CS:MixSegmentLength + Mov DI, MIXTABLESIZE + ShL CX, 2 + Xor EAX, EAX + Rep StosD + + Call StartSB16 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SB16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SB16C.ASM b/it/SoundDrivers/SB16C.ASM new file mode 100755 index 0000000..fe951d9 --- /dev/null +++ b/it/SoundDrivers/SB16C.ASM @@ -0,0 +1,1695 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 16 ; 16 bit mixing for the SB16 +MIXTABLESIZE EQU 2*256*65 + +SB16Msg DB "Sound Blaster 16 detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SB16NoMemoryMsg DB "Sound Blaster 16 detected", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster 16 reinitialised", 0 + +DSPVersion DW 0 +DSPIRQValue DB 0 +DSPDMAValue DB 0 +Forced DB 0 +Stereo DB 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 +MixSegmentLength DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +DMASize DW 2048 + +IMR DW 0 +OldIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SB16ScreenList Label + DW 8 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SB16HeaderLine + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + DW Near Ptr VolumeBox2 + + DW Near Ptr DriverText + + DW Near Ptr MasterVolumeLeft ; 8 + DW Near Ptr MasterVolumeRight ; 9 + DW Near Ptr TrebleVolumeLeft ; 10 + DW Near Ptr TrebleVolumeRight ; 11 + DW Near Ptr BassVolumeLeft ; 12 + DW Near Ptr BassVolumeRight ; 13 + + DW Near Ptr MixFrequencyText + + DW 0 + +SB16HeaderLine DW 10 + DB "Sound Blaster 16 Lite Driver", 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "Sound Blaster 16 Driver 1.0 for Impulse Tracker", 0 + +VolumeText DW 1 + DB 2, 13 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB 13 + DB 13 + DB "Treble Left", 13 + DB "Treble Right", 13 + DB "Bass Left", 13 + DB "Bass Right", 13 + DB 0 + +MixFrequencyText DW 1 + DB 2, 23 + DB 20h + DB "Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 45454 + +VolumeBox1 DW 0 + DB 21, 12, 27, 15 + DB 25 + +VolumeBox2 DW 0 + DB 14, 16, 18, 21 + DB 25 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MasterVolumeLeft DW 9 + DB 22, 13 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 14 + DW 0, 31 + DW 9, 1 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeLeft DW 9 + DB 15, 17 + DW 0, 15 + DW 9, 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeRight DW 9 + DB 15, 18 + DW 0, 15 + DW 9, 3 + DW 10, 12, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeLeft DW 9 + DB 15, 19 + DW 0, 15 + DW 9, 4 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeRight DW 9 + DB 15, 20 + DW 0, 15 + DW 9, 5 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +VolumeTable DB 6 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 45454 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +Proc ResetDSPIRQ + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPIRQValue + Mov AL, 80h + Out DX, AX + + Ret + +EndP ResetDSPIRQ + +; + +Proc ResetDSPDMA + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPDMAValue + Mov AL, 81h + Out DX, AX + + Ret + +EndP ResetDSPDMA + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AH, 4 ; SB DSP = 4.00+ + JAE DetectCard5 + +DetectCard4: + StC + Ret + +DetectCard5: + Mov DSPVersion, AX + + Add DL, 04h-0Eh ; 2x4h = Mixer index port + Mov AL, 80h ; IRQ select + Out DX, AL + Inc DL ; 2x5h = Mixer data port + + In AL, DX + + Dec DL + + Mov DSPIRQValue, AL + ; OK.. now get IRQ, or set IRQ + Mov BX, IRQ + Cmp BX, 0FFFFh + JE DetectCardIRQ1 + Cmp Forced, 0 + JE DetectCardIRQ1 + + Mov AH, 11h + Cmp BL, 2 + JE SetCardIRQ1 + Cmp BL, 9 + JE SetCardIRQ1 + + Mov AH, 12h + Cmp BL, 5 + JE SetCardIRQ1 + + Mov AH, 14h + Cmp BL, 7 + JE SetCardIRQ1 + + Mov AH, 18h + Cmp BL, 10 + JE SetCardIRQ1 + + StC + Ret + +SetCardIRQ1: + Mov AL, 80h + Out DX, AL + Inc DL + Mov AL, AH + Out DX, AL + Dec DL + Jmp DetectCard6 + +DetectCardIRQ1: + Mov BX, 2 + Test AL, 1 + JNZ DetectCardIRQ2 + + Mov BL, 5 + Test AL, 2 + JNZ DetectCardIRQ2 + + Mov BL, 7 + Test AL, 4 + JNZ DetectCardIRQ2 + + Mov BL, 10 + Test AL, 8 + JNZ DetectCardIRQ2 + + StC + Ret + +DetectCardIRQ2: + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + + Cmp BX, IRQ + JE DetectCard6 + + StC + Ret + +DetectCardIRQ3: + Mov IRQ, BX + +DetectCard6: ; Detect DMA + Mov AL, 81h ; DMA select + Out DX, AL + Inc DL + In AL, DX ; AL = DMA + Dec DL + + Mov DSPDMAValue, AL + + Mov BX, DMA + Cmp BX, 0FFFFh + JE DetectCardDMA1 + Cmp Forced, 0 + JE DetectCardDMA1 + + Mov CL, 1 + Cmp BX, 1 + JB SetCardDMA1 + + Mov CL, 2 + JE SetCardDMA1 + + Cmp BX, 3 + JB DetectCard7 + + Mov CL, 8 + JE DetectCard7 + + Mov CL, 20h + Cmp BX, 5 + JB DetectCard7 + JE SetCardDMA1 + + Mov CL, 80h + Cmp BX, 7 + JA DetectCard7 + JE SetCardDMA1 + + Mov CL, 40h + +SetCardDMA1: + And AL, 0Bh + Test CL, 0Bh + JZ SetCardDMA4 + + Xor AL, AL + +SetCardDMA4: + Or CL, AL + + Mov AL, 81h + Out DX, AL + Inc DL + Mov AL, CL + Out DX, AL + Jmp DetectCard7 + +DetectCardDMA1: + Mov BX, 5 + Test AL, 20h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 40h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 80h + JNZ DetectCardDMA2 + + Mov BL, 0 + Test AL, 1 + JNZ DetectCardDMA2 + + Inc BL + Test AL, 2 + JNZ DetectCardDMA2 + + Add BL, 2 + Test AL, 8 + JNZ DetectCardDMA2 + +DetectCard8: + Call ResetDSPIRQ + StC + Ret + +DetectCardDMA2: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + + Cmp BX, DMA + JNE DetectCard8 + +DetectCardDMA3: + Mov DMA, BX + +DetectCard7: + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Add DX, DX + +MixSamples1: + Rep StosD ; } Memory write + +MixSamplesCont: + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Cmp Stereo, 0 + JNE Mix0ModeStereo + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc AckIRQ + Assume DS:Driver + + Mov AL, 20h + Cmp IRQ, 7 + JBE AckIRQ1 + + Out 0A0h, AL + +AckIRQ1: + Out 20h, AL + Ret + +EndP AckIRQ + Assume DS:Nothing + +; + +Proc SB16IRQHandler + + PushAD + Push DS + Push ES + + CLD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 0Fh + In AL, DX + + Call AckIRQ + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB SB16IRQHandler2 + + Xor AX, AX + Xor BX, BX + +SB16IRQHandler2: + Inc BX + Mov MixBufferPos, BX + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 4 ; Skip for mono + Mov CL, 2 ; Shift for mono + + Cmp Stereo, 0 + JE SB16IRQHandlerMono + + ShR BP, 1 + Inc CL + +SB16IRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SB16IRQHandler4 + Assume DS:Nothing + +SB16IRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +SB16IRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SB16IRQHandler5 + + Mov DX, MixTransferRemaining + +SB16IRQHandler5: + Push DX + +SB16IRQHandler6: + MovSX EAX, Word Ptr [SI] + SAL EAX, CL + + Cmp EAX, -8000h + JL SB16IRQHandlerClip1 + Cmp EAX, 7FFFh + JG SB16IRQHandlerClip2 + +SB16IRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ SB16IRQHandler6 + +SB16MixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SB16IRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + +SBIRQEnd: + Pop ES + Pop DS + PopAD + IRet + +SB16IRQHandlerClip1: + Mov AX, 8000h + Jmp SB16IRQHandler7 + +SB16IRQHandlerClip2: + Mov AX, 7FFFh + Jmp SB16IRQHandler7 + +EndP SB16IRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SB16IRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSB16 ; + + PushA + Push ES + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0B6h ; 16 bit, DAC + Call SBOut + Mov AL, Stereo + ShL AL, 5 + Or AL, 10h + Call SBOut + + Mov AX, DMASize + ShR AX, 1 + Dec AX + + Call SBOut ; DMALength, Lo + Mov AL, AH + Call SBOut + + Pop ES + PopA + + Ret + + Assume DS:Nothing + +EndP StartSB16 + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + + Mov AL, 30h + Call SBGetRegister + ShR AL, 3 + Mov VolumeTable, AL + + Mov AL, 31h + Call SBGetRegister + ShR AL, 3 + Mov [VolumeTable+1], AL + + Mov AL, 44h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+2], AL + + Mov AL, 45h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+3], AL + + Mov AL, 46h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+4], AL + + Mov AL, 47h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+5], AL + + Call GetSBMixConst + + ; Parags to allocate = (4/(.4*31*16))*MixSpeed + 2080 + ; = .02016129*MixSpeed = (65536*.04032258*MixSpeed) / 65536 + + Mov AX, 1322 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SB16NoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + Sub DX, 2080 + Mov MixSegmentLength, DX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset SB16Msg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, BasePort + Mov DX, AX + Call ResetDSP + + Call ResetIRQ + ; Delay.. + Mov DX, BasePort + Add DL, 0Ch + + Mov CX, 1000 +ReInitSound1: + In AL, DX + Loop ReInitSound1 + + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov DX, CS:BasePort + Add DL, 0Ch + + Mov AL, 0D3h + Call SBOut + + Mov AL, 0D5h + Call SBOut + + Mov AL, 0D9h + Call SBOut + + Mov AL, 0D5h + Call SBOut + + Mov AX, BasePort + Call ResetDSP + + Call ResetDSPDMA + Call ResetDSPIRQ + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Dec CX + JNZ SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov CS:Stereo, AL + Mov AX, CS:BasePort + Call ResetDSP + + Mov ES, CS:MixSegment + Mov CX, CS:MixSegmentLength + Mov DI, MIXTABLESIZE + ShL CX, 2 + Xor EAX, EAX + Rep StosD + + Call StartSB16 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SB16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SB16D.ASM b/it/SoundDrivers/SB16D.ASM new file mode 100755 index 0000000..f50716c --- /dev/null +++ b/it/SoundDrivers/SB16D.ASM @@ -0,0 +1,2665 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 32 ; 32 bit mixing for the SB16 +MIXTABLESIZE EQU 2*256*65 +FOURIERBUFFERLENGTH EQU 2048 + +SB16Msg DB "Sound Blaster 16 detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SB16NoMemoryMsg DB "Sound Blaster 16 detected", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster 16 reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITSB16.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITSB16.DRV", 0 + +DriverName DB "ITSB16.DRV", 0 + +DSPVersion DW 0 +DSPIRQValue DB 0 +DSPDMAValue DB 0 +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 +; MixVolumeSet DW 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 +FourierSegment DW 0 +MixSegmentLength DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 10 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 +Surround DW 0 +DMASize DW 2048 + +IMR DW 0 +OldIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MIDIPort DW 0 +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SB16ScreenList Label + DW 8 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SB16HeaderLine + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + DW Near Ptr VolumeBox2 + + DW Near Ptr DriverText + + DW Near Ptr MasterVolumeLeft ; 8 + DW Near Ptr MasterVolumeRight ; 9 + DW Near Ptr TrebleVolumeLeft ; 10 + DW Near Ptr TrebleVolumeRight ; 11 + DW Near Ptr BassVolumeLeft ; 12 + DW Near Ptr BassVolumeRight ; 13 + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 15 + DW Near Ptr MixModeButton2 ; 16 + DW Near Ptr MixModeButton3 ; 17 + DW Near Ptr MixModeButton4 ; 18 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 20 + DW Near Ptr FilterButton2 ; 21 + DW Near Ptr FilterButton3 ; 22 + + DW Near Ptr StereoText + DW Near Ptr StereoButton1 ; 24 + DW Near Ptr StereoButton2 ; 25 + DW Near Ptr StereoButton3 ; 25 + + DW Near Ptr FrequencyText + + DW 0 + + +SB16HeaderLine DW 10 + DB "Sound Blaster 16 Driver", 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "Sound Blaster 16 Driver 1.4 for Impulse Tracker", 0 + +VolumeText DW 1 + DB 2, 13 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB 13 + DB 13 + DB "Treble Left", 13 + DB "Treble Right", 13 + DB "Bass Left", 13 + DB "Bass Right", 13 + DB 0 + +VolumeBox1 DW 0 + DB 21, 12, 27, 15 + DB 25 + +VolumeBox2 DW 0 + DB 14, 16, 18, 21 + DB 25 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MasterVolumeLeft DW 9 + DB 22, 13 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 14 + DW 0, 31 + DW 9, 1 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeLeft DW 9 + DB 15, 17 + DW 0, 15 + DW 9, 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeRight DW 9 + DB 15, 18 + DW 0, 15 + DW 9, 3 + DW 10, 12, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeLeft DW 9 + DB 15, 19 + DW 0, 15 + DW 9, 4 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeRight DW 9 + DB 15, 20 + DW 0, 15 + DW 9, 5 + DW 12, 15, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 23 + DB 20h + DB "Mixing Mode", 0 + +FrequencyText DW 1 + DB 2, 48 + DB 20h + DB "Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 45454 + +MixModeButton1 DW 2 + DW 13, 16, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 15, 17, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 28, 32, 30, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 16, 18, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 31, 32, 33, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 17, 20, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 34, 32, 36, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 40, 13 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 18, 21, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 42, 15, 60, 17, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 20, 22, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 42, 18, 60, 20, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 21, 24, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 42, 21, 60, 23, 8 + DB 0 + DB " 75% Filter", 0 + +StereoText DW 1 + DB 40, 25 + DB 20h + DB "Feedback mode", 0 + +StereoButton1 DW 2 + DW 22, 25, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetSurround +DriverSegment15 DW 0 + DW 0 + DW Offset SetSurround +DriverSegment16 DW 0 + DB 42, 27, 60, 29, 8 + DB 0 + DB " None", 0 + +StereoButton2 DW 2 + DW 24, 26, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetSurround +DriverSegment17 DW 0 + DW 1 + DW Offset SetSurround +DriverSegment18 DW 0 + DB 42, 30, 60, 32, 8 + DB 0 + DB " 50% Separated", 0 + +StereoButton3 DW 2 + DW 25, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetSurround +DriverSegment19 DW 0 + DW 2 + DW Offset SetSurround +DriverSegment20 DW 0 + DB 42, 33, 60, 35, 8 + DB 0 + DB " 50% Crossed", 0 + + +VolumeTable DB 6 Dup (0) + +; MixingRoutines + +include dmasirq.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW Offset DriverSegment15, Offset DriverSegment16 + DW Offset DriverSegment17, Offset DriverSegment18 + DW Offset DriverSegment19, Offset DriverSegment20 + DW 0 + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc DetectUART ; Given DX = Port + +; From SB-DevKit + + ClI + + Inc DX + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 40h ; Ready for output + LoopNZ DetectUART1 + JNZ DetectUARTError + + Mov AL, 0FFh ; Reset! + Out DX, AL + + Xor CX, CX + +DetectUART2: + In AL, DX + Test AL, 80h + JNZ DetectUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART4 + +DetectUART3: + Loop DetectUART2 + +DetectUARTError: + StI + StC + Ret + +DetectUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +DetectUART5: + In AL, DX + Test AL, 40h + LoopNZ DetectUART5 + JNZ DetectUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +DetectUART6: + Xor CX, CX + +DetectUART7: + In AL, DX + Test AL, 80h + JNZ DetectUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART9 + +DetectUART8: + Loop DetectUART7 + + Jmp DetectUARTError + +DetectUART9: + StI + ClC + Ret + +EndP DetectUART + +; + +Proc ReinitUART + + Mov DX, MIDIPort + Test DX, DX + JZ ReinitUART1 + + Call DetectUART + +ReinitUART1: + Ret + +EndP ReinitUART + +; + +Proc ResetUART + + Mov DX, MIDIPort + Test DX, DX + JZ ResetUART1 + + Inc DX + + Mov AL, 0FFh + Out DX, AL + +ResetUART1: + Ret + +EndP ResetUART + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc GetSurround Far + + Push CS + Pop ES + Mov DI, Offset Surround + + Ret + +EndP GetSurround + +; + +Proc SetSurround Far + + Mov AX, [SI+22] + Mov CS:Surround, AX + +; Mov AX, CS:MixVolumeSet +; Call Far Ptr SetMixVolumeChain + + Jmp SetMixModeChain + +EndP SetSurround + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 45454 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + Mov BX, 12000 + Xor DX, DX + Div BX + Mov FourierBufferStepOffset, AX + Mov FourierBufferStepFractional, DX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +Proc ResetDSPIRQ + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPIRQValue + Mov AL, 80h + Out DX, AX + + Ret + +EndP ResetDSPIRQ + +; + +Proc ResetDSPDMA + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPDMAValue + Mov AL, 81h + Out DX, AX + + Ret + +EndP ResetDSPDMA + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AH, 4 ; SB DSP = 4.00+ + JAE DetectCard5 + +DetectCard4: + StC + Ret + +DetectCard5: + Mov DSPVersion, AX + + Add DL, 04h-0Eh ; 2x4h = Mixer index port + Mov AL, 80h ; IRQ select + Out DX, AL + Inc DL ; 2x5h = Mixer data port + + In AL, DX + + Dec DL + + Mov DSPIRQValue, AL + ; OK.. now get IRQ, or set IRQ + Mov BX, IRQ + Cmp BX, 0FFFFh + JE DetectCardIRQ1 + Cmp Forced, 0 + JE DetectCardIRQ1 + + Mov AH, 11h + Cmp BL, 2 + JE SetCardIRQ1 + Cmp BL, 9 + JE SetCardIRQ1 + + Mov AH, 12h + Cmp BL, 5 + JE SetCardIRQ1 + + Mov AH, 14h + Cmp BL, 7 + JE SetCardIRQ1 + + Mov AH, 18h + Cmp BL, 10 + JE SetCardIRQ1 + + StC + Ret + +SetCardIRQ1: + Mov AL, 80h + Out DX, AL + Inc DL + Mov AL, AH + Out DX, AL + Dec DL + Jmp DetectCard6 + +DetectCardIRQ1: + Mov BX, 2 + Test AL, 1 + JNZ DetectCardIRQ2 + + Mov BL, 5 + Test AL, 2 + JNZ DetectCardIRQ2 + + Mov BL, 7 + Test AL, 4 + JNZ DetectCardIRQ2 + + Mov BL, 10 + Test AL, 8 + JNZ DetectCardIRQ2 + + StC + Ret + +DetectCardIRQ2: + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + + Cmp BX, IRQ + JE DetectCard6 + + StC + Ret + +DetectCardIRQ3: + Mov IRQ, BX + +DetectCard6: ; Detect DMA + Mov AL, 81h ; DMA select + Out DX, AL + Inc DL + In AL, DX ; AL = DMA + Dec DL + + Mov DSPDMAValue, AL + + Mov BX, DMA + Cmp BX, 0FFFFh + JE DetectCardDMA1 + Cmp Forced, 0 + JE DetectCardDMA1 + + Mov CL, 1 + Cmp BX, 1 + JB SetCardDMA1 + + Mov CL, 2 + JE SetCardDMA1 + + Cmp BX, 3 + JB DetectCard7 + + Mov CL, 8 + JE DetectCard7 + + Mov CL, 20h + Cmp BX, 5 + JB DetectCard7 + JE SetCardDMA1 + + Mov CL, 80h + Cmp BX, 7 + JA DetectCard7 + JE SetCardDMA1 + + Mov CL, 40h + +SetCardDMA1: + And AL, 0Bh + Test CL, 0Bh + JZ SetCardDMA4 + + Xor AL, AL + +SetCardDMA4: + Or CL, AL + + Mov AL, 81h + Out DX, AL + Inc DL + Mov AL, CL + Out DX, AL + Jmp DetectCard7 + +DetectCardDMA1: + Mov BX, 5 + Test AL, 20h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 40h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 80h + JNZ DetectCardDMA2 + + Mov BL, 0 + Test AL, 1 + JNZ DetectCardDMA2 + + Inc BL + Test AL, 2 + JNZ DetectCardDMA2 + + Add BL, 2 + Test AL, 8 + JNZ DetectCardDMA2 + +DetectCard8: + Call ResetDSPIRQ + StC + Ret + +DetectCardDMA2: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + + Cmp BX, DMA + JNE DetectCard8 + +DetectCardDMA3: + Mov DMA, BX + +DetectCard7: + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + + Cmp Surround, 1 + JB MixSamplesCont + + Push DS + + Push ES + Pop DS + + JE MixSurround3 + +Surround1: + Mov EAX, [DI+4] + Mov EBX, [DI] + SAR EAX, 1 + SAR EBX, 1 + Mov [DI], EAX + Mov [DI+4], EBX + + Add DI, 8 + Sub CX, 2 + JNZ Surround1 + + Pop DS + Jmp SurroundCont + +MixSamples1: + Cmp Surround, 1 + JB MixSamplesCont + +MixSurround2: + Push DS + + Push ES + Pop DS + +MixSurround3: + SAR DWord Ptr [DI], 1 + Add DI, 4 + Dec CX + JNZ MixSurround3 + + Pop DS + Jmp SurroundCont + +MixSamplesCont: + Xor EAX, EAX + Rep StosD ; } Memory write + +SurroundCont: + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +include fourier.inc + +; + +Proc AckIRQ + Assume DS:Driver + + Mov AL, 20h + Cmp CS:IRQ, 7 + JBE AckIRQ1 + + Out 0A0h, AL + +AckIRQ1: + Out 20h, AL + Ret + +EndP AckIRQ + Assume DS:Nothing + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Mov DX, MIDIPort + + Mov BL, [MIDIBufferTail] + Test DX, DX + JZ CheckMIDIEnd + + Inc DX + Mov CX, 0FFFFh + +CheckMIDIAgain: + In AL, DX + + Test AL, 80h + LoopNZ CheckMIDIAgain + + Dec DX + In AL, DX + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL +; Jmp CheckMIDIAgain + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc SB16IRQHandler + + PushAD + Push DS + Push ES + + CLD + +SBIRQAgain: + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 4 ; Mixer Port + Mov AL, 82h + Out DX, AL + Inc DL ; DX = BasePort+5 + In AL, DX + + Test AL, 4 + JZ SBMIDIInterruptEnd + + Push AX + Call CheckMIDI + Pop AX + +SBMIDIInterruptEnd: + Test AL, 2 + JNZ SBDigitalInterrupt + + Call AckIRQ + Jmp SBIRQEnd + +SBDigitalInterrupt: + Mov DX, BasePort + Add DL, 0Fh + In AL, DX ; 16-bit IRQ ack. + + Call AckIRQ + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + +DMA16BITADJUST EQU $ + ShL BX, 1 + + Cmp BX, DMABUFFERLENGTH/2 + JB SB16IRQHandler2 + + Mov AX, DMABUFFERLENGTH/2 + +SB16IRQHandler2: + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE SB16IRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +SB16IRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SB16IRQHandler4 + Assume DS:Nothing + +SB16IRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + Call UpdateFourierBuffer + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +SB16IRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SB16IRQHandler5 + + Mov DX, MixTransferRemaining + +SB16IRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB SB16IRQHandler6 + JE SB16IRQHFilter + + Cmp CS:Stereo, 0 + JE SB16IRQ3QFilterMono + +SB16IRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +SB16IRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL SB163QFilterStereoClip1 + Cmp EAX, 7FFFh + JG SB163QFilterStereoClip2 + +SB16IRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL SB163QFilterStereoClip3 + Cmp EAX, 7FFFh + JG SB163QFilterStereoClip4 + +SB16IRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ SB16IRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp SB16MixTransferEnd + +SB16IRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +SB16IRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL SB163QFilterMonoClip1 + Cmp EAX, 7FFFh + JG SB163QFilterMonoClip2 + +SB16IRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ SB16IRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp SB16MixTransferEnd + +SB16IRQHFilter: + Cmp CS:Stereo, 0 + JE SB16IRQHFilterMono + +SB16IRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +SB16IRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL SB16HFilterStereoClip1 + Cmp EAX, 7FFFh + JG SB16HFilterStereoClip2 + +SB16IRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL SB16HFilterStereoClip3 + Cmp EAX, 7FFFh + JG SB16HFilterStereoClip4 + +SB16IRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ SB16IRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp SB16MixTransferEnd + +SB16IRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +SB16IRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL SB16HFilterMonoClip1 + Cmp EAX, 7FFFh + JG SB16HFilterMonoClip2 + +SB16IRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ SB16IRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp SB16MixTransferEnd + +SB16IRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL SB16IRQHandlerClip1 + Cmp EAX, 7FFFh + JG SB16IRQHandlerClip2 + +SB16IRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ SB16IRQHandler6 + +SB16MixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SB16IRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + +SBIRQEnd: + + Pop ES + Pop DS + PopAD + IRet + +SB16IRQHandlerClip1: + Mov AX, 8000h + Jmp SB16IRQHandler7 + +SB16IRQHandlerClip2: + Mov AX, 7FFFh + Jmp SB16IRQHandler7 + +SB16HFilterMonoClip1: + Mov AX, 8000h + Jmp SB16IRQHFilterMono2 + +SB16HFilterMonoClip2: + Mov AX, 7FFFh + Jmp SB16IRQHFilterMono2 + +SB16HFilterStereoClip1: + Mov AX, 8000h + Jmp SB16IRQHFilterStereo2 + +SB16HFilterStereoClip2: + Mov AX, 7FFFh + Jmp SB16IRQHFilterStereo2 + +SB16HFilterStereoClip3: + Mov AX, 8000h + Jmp SB16IRQHFilterStereo3 + +SB16HFilterStereoClip4: + Mov AX, 7FFFh + Jmp SB16IRQHFilterStereo3 + +SB163QFilterMonoClip1: + Mov AX, 8000h + Jmp SB16IRQ3QFilterMono2 + +SB163QFilterMonoClip2: + Mov AX, 7FFFh + Jmp SB16IRQ3QFilterMono2 + +SB163QFilterStereoClip1: + Mov AX, 8000h + Jmp SB16IRQ3QFilterStereo2 + +SB163QFilterStereoClip2: + Mov AX, 7FFFh + Jmp SB16IRQ3QFilterStereo2 + +SB163QFilterStereoClip3: + Mov AX, 8000h + Jmp SB16IRQ3QFilterStereo3 + +SB163QFilterStereoClip4: + Mov AX, 7FFFh + Jmp SB16IRQ3QFilterStereo3 + +EndP SB16IRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SB16IRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSB16 ; + + PushA + Push ES + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Cmp DX, 3 + JA StartSB16B + + Mov Word Ptr [DMA16BITADJUST], 9090h + +StartSB16B: + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0B6h ; 16 bit, DAC + Call SBOut + Mov AL, Stereo + ShL AL, 5 + Or AL, 10h + Call SBOut + + Mov AX, DMASize + ShR AX, 1 + Dec AX + + Call SBOut ; DMALength, Lo + Mov AL, AH + Call SBOut + + Pop ES + PopA + + Ret + + Assume DS:Nothing + +EndP StartSB16 + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov DX, BasePort + Add DL, 4 + + Mov AL, 30h + Call SBGetRegister + ShR AL, 3 + Mov VolumeTable, AL + + Mov AL, 31h + Call SBGetRegister + ShR AL, 3 + Mov [VolumeTable+1], AL + + Mov AL, 44h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+2], AL + + Mov AL, 45h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+3], AL + + Mov AL, 46h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+4], AL + + Mov AL, 47h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+5], AL + + Call GetSBMixConst + + ; Parags to allocate = (8/(.4*31*16))*MixSpeed + 2080 + ; = .04032258*MixSpeed = (65536*.04032258*MixSpeed) / 65536 + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + (FOURIERBUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SB16NoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + Add AX, (DMABUFFERLENGTH*2)/16 + Mov FourierSegment, AX + Sub DX, 2080 + Mov MixSegmentLength, DX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov DX, 330h + Call DetectUART + JC DetectMIDI1 + + Mov MIDIPort, 330h + Jmp DetectMIDIEnd + +DetectMIDI1: + Mov DX, 300h + Call DetectUART + JC DetectMIDIEnd + + Mov MIDIPort, 300h + +DetectMIDIEnd: + Mov SI, Offset SB16Msg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, BasePort + Call ResetDSP + + Call ResetUART + Call ResetIRQ + + ; Delay.. + Mov DX, BasePort + Add DL, 0Ch + + Mov CX, 1000 +ReInitSound1: + In AL, DX + Loop ReInitSound1 + + Call SetIRQ + Call ReinitUART + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov DX, CS:BasePort + Add DL, 0Ch + + Mov AL, 0D9h + Call SBOut + + Call ResetUART + + Mov AX, BasePort + Call ResetDSP + + Call ResetDSPDMA + Call ResetDSPIRQ + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + +; Mov CS:MixVolumeSet, AX + +; SetMixVolumeChain: + PushA + Push DS + +; Cmp CS:Surround, 0 +; JE SetMixVolumeSurround +; +; Mov BX, 49152 +; Mul BX +; Mov AX, DX +; +; SetMixVolumeSurround: + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, AX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Dec CX + JNZ SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov CS:Stereo, AL + Mov AX, CS:BasePort + Call ResetDSP + + Mov ES, CS:MixSegment + Mov CX, CS:MixSegmentLength + Mov DI, MIXTABLESIZE + ShL CX, 2 + Xor EAX, EAX + Rep StosD + + Call StartSB16 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SB16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +Proc GetWaveForm Far ; Given ES:DI = destination + Assume DS:Nothing ; want 2048 samples. + + PushA + Push DS + + Mov DS, FourierSegment + Mov SI, FourierBufferStart + Mov CX, 2048 + +GetWaveForm1: + MovsW + And SI, (FOURIERBUFFERLENGTH*2)-1 + Loop GetWaveForm1 + + Pop DS + PopA + + Ret + +EndP GetWaveForm + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 +DriverFlags DW 4 + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW 0 + DW Offset GetWaveform + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SB16DRV.ASM b/it/SoundDrivers/SB16DRV.ASM new file mode 100755 index 0000000..f719fb2 --- /dev/null +++ b/it/SoundDrivers/SB16DRV.ASM @@ -0,0 +1,2672 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for the SB16 +MIXTABLESIZE EQU 2*256*65 +FOURIERBUFFERLENGTH EQU 2048 + +SB16Msg DB "Sound Blaster 16 detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SB16NoMemoryMsg DB "Sound Blaster 16 detected", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster 16 reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITSB16.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITSB16.DRV", 0 + +DriverName DB "ITSB16.DRV", 0 + +DSPVersion DW 0 +DSPIRQValue DB 0 +DSPDMAValue DB 0 +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 +; MixVolumeSet DW 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 +FourierSegment DW 0 +MixSegmentLength DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 10 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 +Surround DW 0 +DMASize DW 2048 + +IMR DW 0 +OldIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MIDIPort DW 0 +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SB16ScreenList Label + DW 8 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SB16HeaderLine + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + DW Near Ptr VolumeBox2 + + DW Near Ptr DriverText + + DW Near Ptr MasterVolumeLeft ; 8 + DW Near Ptr MasterVolumeRight ; 9 + DW Near Ptr TrebleVolumeLeft ; 10 + DW Near Ptr TrebleVolumeRight ; 11 + DW Near Ptr BassVolumeLeft ; 12 + DW Near Ptr BassVolumeRight ; 13 + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 15 + DW Near Ptr MixModeButton2 ; 16 + DW Near Ptr MixModeButton3 ; 17 + DW Near Ptr MixModeButton4 ; 18 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 20 + DW Near Ptr FilterButton2 ; 21 + DW Near Ptr FilterButton3 ; 22 + + DW Near Ptr StereoText + DW Near Ptr StereoButton1 ; 24 + DW Near Ptr StereoButton2 ; 25 + DW Near Ptr StereoButton3 ; 25 + + DW Near Ptr FrequencyText + + DW 0 + + +SB16HeaderLine DW 10 + DB "Sound Blaster 16 Driver", 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "Sound Blaster 16 Driver 1.4 for Impulse Tracker", 0 + +VolumeText DW 1 + DB 2, 13 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB 13 + DB 13 + DB "Treble Left", 13 + DB "Treble Right", 13 + DB "Bass Left", 13 + DB "Bass Right", 13 + DB 0 + +VolumeBox1 DW 0 + DB 21, 12, 27, 15 + DB 25 + +VolumeBox2 DW 0 + DB 14, 16, 18, 21 + DB 25 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MasterVolumeLeft DW 9 + DB 22, 13 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 14 + DW 0, 31 + DW 9, 1 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeLeft DW 9 + DB 15, 17 + DW 0, 15 + DW 9, 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeRight DW 9 + DB 15, 18 + DW 0, 15 + DW 9, 3 + DW 10, 12, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeLeft DW 9 + DB 15, 19 + DW 0, 15 + DW 9, 4 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeRight DW 9 + DB 15, 20 + DW 0, 15 + DW 9, 5 + DW 12, 15, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 23 + DB 20h + DB "Mixing Mode", 0 + +FrequencyText DW 1 + DB 2, 48 + DB 20h + DB "Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 45454 + +MixModeButton1 DW 2 + DW 13, 16, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 15, 17, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 28, 32, 30, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 16, 18, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 31, 32, 33, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 17, 20, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 34, 32, 36, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 40, 13 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 18, 21, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 42, 15, 60, 17, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 20, 22, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 42, 18, 60, 20, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 21, 24, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 42, 21, 60, 23, 8 + DB 0 + DB " 75% Filter", 0 + +StereoText DW 1 + DB 40, 25 + DB 20h + DB "Feedback mode", 0 + +StereoButton1 DW 2 + DW 22, 25, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetSurround +DriverSegment15 DW 0 + DW 0 + DW Offset SetSurround +DriverSegment16 DW 0 + DB 42, 27, 60, 29, 8 + DB 0 + DB " None", 0 + +StereoButton2 DW 2 + DW 24, 26, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetSurround +DriverSegment17 DW 0 + DW 1 + DW Offset SetSurround +DriverSegment18 DW 0 + DB 42, 30, 60, 32, 8 + DB 0 + DB " 50% Separated", 0 + +StereoButton3 DW 2 + DW 25, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetSurround +DriverSegment19 DW 0 + DW 2 + DW Offset SetSurround +DriverSegment20 DW 0 + DB 42, 33, 60, 35, 8 + DB 0 + DB " 50% Crossed", 0 + + +VolumeTable DB 6 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW Offset DriverSegment15, Offset DriverSegment16 + DW Offset DriverSegment17, Offset DriverSegment18 + DW Offset DriverSegment19, Offset DriverSegment20 + DW 0 + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc DetectUART ; Given DX = Port + +; From SB-DevKit + + ClI + + Inc DX + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 40h ; Ready for output + LoopNZ DetectUART1 + JNZ DetectUARTError + + Mov AL, 0FFh ; Reset! + Out DX, AL + + Xor CX, CX + +DetectUART2: + In AL, DX + Test AL, 80h + JNZ DetectUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART4 + +DetectUART3: + Loop DetectUART2 + +DetectUARTError: + StI + StC + Ret + +DetectUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +DetectUART5: + In AL, DX + Test AL, 40h + LoopNZ DetectUART5 + JNZ DetectUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +DetectUART6: + Xor CX, CX + +DetectUART7: + In AL, DX + Test AL, 80h + JNZ DetectUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART9 + +DetectUART8: + Loop DetectUART7 + + Jmp DetectUARTError + +DetectUART9: + StI + ClC + Ret + +EndP DetectUART + +; + +Proc ReinitUART + + Mov DX, MIDIPort + Test DX, DX + JZ ReinitUART1 + + Call DetectUART + +ReinitUART1: + Ret + +EndP ReinitUART + +; + +Proc ResetUART + + Mov DX, MIDIPort + Test DX, DX + JZ ResetUART1 + + Inc DX + + Mov AL, 0FFh + Out DX, AL + +ResetUART1: + Ret + +EndP ResetUART + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc GetSurround Far + + Push CS + Pop ES + Mov DI, Offset Surround + + Ret + +EndP GetSurround + +; + +Proc SetSurround Far + + Mov AX, [SI+22] + Mov CS:Surround, AX + +; Mov AX, CS:MixVolumeSet +; Call Far Ptr SetMixVolumeChain + + Jmp SetMixModeChain + +EndP SetSurround + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 45454 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + Mov BX, 12000 + Xor DX, DX + Div BX + Mov FourierBufferStepOffset, AX + Mov FourierBufferStepFractional, DX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +Proc ResetDSPIRQ + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPIRQValue + Mov AL, 80h + Out DX, AX + + Ret + +EndP ResetDSPIRQ + +; + +Proc ResetDSPDMA + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPDMAValue + Mov AL, 81h + Out DX, AX + + Ret + +EndP ResetDSPDMA + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AH, 4 ; SB DSP = 4.00+ + JAE DetectCard5 + +DetectCard4: + StC + Ret + +DetectCard5: + Mov DSPVersion, AX + + Add DL, 04h-0Eh ; 2x4h = Mixer index port + Mov AL, 80h ; IRQ select + Out DX, AL + Inc DL ; 2x5h = Mixer data port + + In AL, DX + + Dec DL + + Mov DSPIRQValue, AL + ; OK.. now get IRQ, or set IRQ + Mov BX, IRQ + Cmp BX, 0FFFFh + JE DetectCardIRQ1 + Cmp Forced, 0 + JE DetectCardIRQ1 + + Mov AH, 11h + Cmp BL, 2 + JE SetCardIRQ1 + Cmp BL, 9 + JE SetCardIRQ1 + + Mov AH, 12h + Cmp BL, 5 + JE SetCardIRQ1 + + Mov AH, 14h + Cmp BL, 7 + JE SetCardIRQ1 + + Mov AH, 18h + Cmp BL, 10 + JE SetCardIRQ1 + + StC + Ret + +SetCardIRQ1: + Mov AL, 80h + Out DX, AL + Inc DL + Mov AL, AH + Out DX, AL + Dec DL + Jmp DetectCard6 + +DetectCardIRQ1: + Mov BX, 2 + Test AL, 1 + JNZ DetectCardIRQ2 + + Mov BL, 5 + Test AL, 2 + JNZ DetectCardIRQ2 + + Mov BL, 7 + Test AL, 4 + JNZ DetectCardIRQ2 + + Mov BL, 10 + Test AL, 8 + JNZ DetectCardIRQ2 + + StC + Ret + +DetectCardIRQ2: + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + + Cmp BX, IRQ + JE DetectCard6 + + StC + Ret + +DetectCardIRQ3: + Mov IRQ, BX + +DetectCard6: ; Detect DMA + Mov AL, 81h ; DMA select + Out DX, AL + Inc DL + In AL, DX ; AL = DMA + Dec DL + + Mov DSPDMAValue, AL + + Mov BX, DMA + Cmp BX, 0FFFFh + JE DetectCardDMA1 + Cmp Forced, 0 + JE DetectCardDMA1 + + Mov CL, 1 + Cmp BX, 1 + JB SetCardDMA1 + + Mov CL, 2 + JE SetCardDMA1 + + Cmp BX, 3 + JB DetectCard7 + + Mov CL, 8 + JE DetectCard7 + + Mov CL, 20h + Cmp BX, 5 + JB DetectCard7 + JE SetCardDMA1 + + Mov CL, 80h + Cmp BX, 7 + JA DetectCard7 + JE SetCardDMA1 + + Mov CL, 40h + +SetCardDMA1: + And AL, 0Bh + Test CL, 0Bh + JZ SetCardDMA4 + + Xor AL, AL + +SetCardDMA4: + Or CL, AL + + Mov AL, 81h + Out DX, AL + Inc DL + Mov AL, CL + Out DX, AL + Jmp DetectCard7 + +DetectCardDMA1: + Mov BX, 5 + Test AL, 20h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 40h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 80h + JNZ DetectCardDMA2 + + Mov BL, 0 + Test AL, 1 + JNZ DetectCardDMA2 + + Inc BL + Test AL, 2 + JNZ DetectCardDMA2 + + Add BL, 2 + Test AL, 8 + JNZ DetectCardDMA2 + +DetectCard8: + Call ResetDSPIRQ + StC + Ret + +DetectCardDMA2: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + + Cmp BX, DMA + JNE DetectCard8 + +DetectCardDMA3: + Mov DMA, BX + +DetectCard7: + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + + Cmp Surround, 1 + JB MixSamplesCont + + Push DS + + Push ES + Pop DS + + JE MixSurround3 + +Surround1: + Mov EAX, [DI+4] + Mov EBX, [DI] + SAR EAX, 1 + SAR EBX, 1 + Mov [DI], EAX + Mov [DI+4], EBX + + Add DI, 8 + Sub CX, 2 + JNZ Surround1 + + Pop DS + Jmp SurroundCont + +MixSamples1: + Cmp Surround, 1 + JB MixSamplesCont + +MixSurround2: + Push DS + + Push ES + Pop DS + +MixSurround3: + SAR DWord Ptr [DI], 1 + Add DI, 4 + Dec CX + JNZ MixSurround3 + + Pop DS + Jmp SurroundCont + +MixSamplesCont: + Xor EAX, EAX + Rep StosD ; } Memory write + +SurroundCont: + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +include fourier.inc + +; + +Proc AckIRQ + Assume DS:Driver + + Mov AL, 20h + Cmp CS:IRQ, 7 + JBE AckIRQ1 + + Out 0A0h, AL + +AckIRQ1: + Out 20h, AL + Ret + +EndP AckIRQ + Assume DS:Nothing + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Mov DX, MIDIPort + + Mov BL, [MIDIBufferTail] + Test DX, DX + JZ CheckMIDIEnd + + Inc DX + Mov CX, 0FFFFh + +CheckMIDIAgain: + In AL, DX + + Test AL, 80h + LoopNZ CheckMIDIAgain + + Dec DX + In AL, DX + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL +; Jmp CheckMIDIAgain + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc SB16IRQHandler + + PushAD + Push DS + Push ES + + CLD + +SBIRQAgain: + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 4 ; Mixer Port + Mov AL, 82h + Out DX, AL + Inc DL ; DX = BasePort+5 + In AL, DX + +Comment ~ + Test AL, 1 + JZ SB8BitDigitalInterruptEnd + +SB8BitDigitalInterrupt: + Push AX + Add DL, 0Eh-5 + In AL, DX + Pop AX + +SB8BitDigitalInterruptEnd: + + ~ + + Test AL, 4 + JZ SBMIDIInterruptEnd + + Push AX + Call CheckMIDI + Pop AX + +SBMIDIInterruptEnd: + Test AL, 2 + JNZ SBDigitalInterrupt + + Call AckIRQ + Jmp SBIRQEnd + +SBDigitalInterrupt: + Mov DX, BasePort + Add DL, 0Fh + In AL, DX ; 16-bit IRQ ack. + + Call AckIRQ + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB SB16IRQHandler2 + + Xor AX, AX + Xor BX, BX + +SB16IRQHandler2: + Inc BX + Mov MixBufferPos, BX + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE SB16IRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +SB16IRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SB16IRQHandler4 + Assume DS:Nothing + +SB16IRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + Call UpdateFourierBuffer + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +SB16IRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SB16IRQHandler5 + + Mov DX, MixTransferRemaining + +SB16IRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB SB16IRQHandler6 + JE SB16IRQHFilter + + Cmp CS:Stereo, 0 + JE SB16IRQ3QFilterMono + +SB16IRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +SB16IRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL SB163QFilterStereoClip1 + Cmp EAX, 7FFFh + JG SB163QFilterStereoClip2 + +SB16IRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL SB163QFilterStereoClip3 + Cmp EAX, 7FFFh + JG SB163QFilterStereoClip4 + +SB16IRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ SB16IRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp SB16MixTransferEnd + +SB16IRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +SB16IRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL SB163QFilterMonoClip1 + Cmp EAX, 7FFFh + JG SB163QFilterMonoClip2 + +SB16IRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ SB16IRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp SB16MixTransferEnd + +SB16IRQHFilter: + Cmp CS:Stereo, 0 + JE SB16IRQHFilterMono + +SB16IRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +SB16IRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL SB16HFilterStereoClip1 + Cmp EAX, 7FFFh + JG SB16HFilterStereoClip2 + +SB16IRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL SB16HFilterStereoClip3 + Cmp EAX, 7FFFh + JG SB16HFilterStereoClip4 + +SB16IRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ SB16IRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp SB16MixTransferEnd + +SB16IRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +SB16IRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL SB16HFilterMonoClip1 + Cmp EAX, 7FFFh + JG SB16HFilterMonoClip2 + +SB16IRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ SB16IRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp SB16MixTransferEnd + +SB16IRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL SB16IRQHandlerClip1 + Cmp EAX, 7FFFh + JG SB16IRQHandlerClip2 + +SB16IRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ SB16IRQHandler6 + +SB16MixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SB16IRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + +SBIRQEnd: + + Pop ES + Pop DS + PopAD + IRet + +SB16IRQHandlerClip1: + Mov AX, 8000h + Jmp SB16IRQHandler7 + +SB16IRQHandlerClip2: + Mov AX, 7FFFh + Jmp SB16IRQHandler7 + +SB16HFilterMonoClip1: + Mov AX, 8000h + Jmp SB16IRQHFilterMono2 + +SB16HFilterMonoClip2: + Mov AX, 7FFFh + Jmp SB16IRQHFilterMono2 + +SB16HFilterStereoClip1: + Mov AX, 8000h + Jmp SB16IRQHFilterStereo2 + +SB16HFilterStereoClip2: + Mov AX, 7FFFh + Jmp SB16IRQHFilterStereo2 + +SB16HFilterStereoClip3: + Mov AX, 8000h + Jmp SB16IRQHFilterStereo3 + +SB16HFilterStereoClip4: + Mov AX, 7FFFh + Jmp SB16IRQHFilterStereo3 + +SB163QFilterMonoClip1: + Mov AX, 8000h + Jmp SB16IRQ3QFilterMono2 + +SB163QFilterMonoClip2: + Mov AX, 7FFFh + Jmp SB16IRQ3QFilterMono2 + +SB163QFilterStereoClip1: + Mov AX, 8000h + Jmp SB16IRQ3QFilterStereo2 + +SB163QFilterStereoClip2: + Mov AX, 7FFFh + Jmp SB16IRQ3QFilterStereo2 + +SB163QFilterStereoClip3: + Mov AX, 8000h + Jmp SB16IRQ3QFilterStereo3 + +SB163QFilterStereoClip4: + Mov AX, 7FFFh + Jmp SB16IRQ3QFilterStereo3 + +EndP SB16IRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SB16IRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSB16 ; + + PushA + Push ES + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0B6h ; 16 bit, DAC + Call SBOut + Mov AL, Stereo + ShL AL, 5 + Or AL, 10h + Call SBOut + + Mov AX, DMASize + ShR AX, 1 + Dec AX + + Call SBOut ; DMALength, Lo + Mov AL, AH + Call SBOut + + Pop ES + PopA + + Ret + + Assume DS:Nothing + +EndP StartSB16 + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov DX, BasePort + Add DL, 4 + + Mov AL, 30h + Call SBGetRegister + ShR AL, 3 + Mov VolumeTable, AL + + Mov AL, 31h + Call SBGetRegister + ShR AL, 3 + Mov [VolumeTable+1], AL + + Mov AL, 44h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+2], AL + + Mov AL, 45h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+3], AL + + Mov AL, 46h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+4], AL + + Mov AL, 47h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+5], AL + + Call GetSBMixConst + + ; Parags to allocate = (8/(.4*31*16))*MixSpeed + 2080 + ; = .04032258*MixSpeed = (65536*.04032258*MixSpeed) / 65536 + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + (FOURIERBUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SB16NoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + Add AX, (DMABUFFERLENGTH*2)/16 + Mov FourierSegment, AX + Sub DX, 2080 + Mov MixSegmentLength, DX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov DX, 330h + Call DetectUART + JC DetectMIDI1 + + Mov MIDIPort, 330h + Jmp DetectMIDIEnd + +DetectMIDI1: + Mov DX, 300h + Call DetectUART + JC DetectMIDIEnd + + Mov MIDIPort, 300h + +DetectMIDIEnd: + Mov SI, Offset SB16Msg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, BasePort + Call ResetDSP + + Call ResetUART + Call ResetIRQ + + ; Delay.. + Mov DX, BasePort + Add DL, 0Ch + + Mov CX, 1000 +ReInitSound1: + In AL, DX + Loop ReInitSound1 + + Call SetIRQ + Call ReinitUART + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov DX, CS:BasePort + Add DL, 0Ch + + Mov AL, 0D9h + Call SBOut + + Call ResetUART + + Mov AX, BasePort + Call ResetDSP + + Call ResetDSPDMA + Call ResetDSPIRQ + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + +; Mov CS:MixVolumeSet, AX + +; SetMixVolumeChain: + PushA + Push DS + +; Cmp CS:Surround, 0 +; JE SetMixVolumeSurround +; +; Mov BX, 49152 +; Mul BX +; Mov AX, DX +; +; SetMixVolumeSurround: + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, AX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Dec CX + JNZ SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov CS:Stereo, AL + Mov AX, CS:BasePort + Call ResetDSP + + Mov ES, CS:MixSegment + Mov CX, CS:MixSegmentLength + Mov DI, MIXTABLESIZE + ShL CX, 2 + Xor EAX, EAX + Rep StosD + + Call StartSB16 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SB16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +Proc GetWaveForm Far ; Given ES:DI = destination + Assume DS:Nothing ; want 2048 samples. + + PushA + Push DS + + Mov DS, FourierSegment + Mov SI, FourierBufferStart + Mov CX, 2048 + +GetWaveForm1: + MovsW + And SI, (FOURIERBUFFERLENGTH*2)-1 + Loop GetWaveForm1 + + Pop DS + PopA + + Ret + +EndP GetWaveForm + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 +DriverFlags DW 4 + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW 0 + DW Offset GetWaveform + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SB16DRV.MAP b/it/SoundDrivers/SB16DRV.MAP new file mode 100644 index 0000000..19ca4a6 --- /dev/null +++ b/it/SoundDrivers/SB16DRV.MAP @@ -0,0 +1,9 @@ + + Start Stop Length Name Class + + 00000H 0007FH 00080H DRIVERHEADER CODE + 00080H 07B8FH 07B10H DRIVER CODE + +Program entry point at 0000:0000 +Warning: No stack + diff --git a/it/SoundDrivers/SB16K6.ASM b/it/SoundDrivers/SB16K6.ASM new file mode 100755 index 0000000..c661467 --- /dev/null +++ b/it/SoundDrivers/SB16K6.ASM @@ -0,0 +1,2287 @@ + + + .586P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +TRACEENABLED = 0 +CREATENEWLOGFILE = 1 + +include debug.inc + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for the SB16 +OUTPUTFILTERENABLED EQU 1 +FOURIERBUFFERLENGTH EQU 2048 ; 2048 samples + +FPSave DB 128 Dup (0) + +SB16Msg DB "Sound Blaster 16 3DNOW!", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SB16NoMemoryMsg DB "Sound Blaster 16 3DNOW!", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster 16 reinitialised", 0 + +DriverName DB "ITSB16.3DN", 0 + +DSPVersion DW 0 +DSPIRQValue DB 0 +DSPDMAValue DB 0 +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +FourierSegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 20 +MixMode DW 0 +MixModeOffset DW 0 +DMASize DW 2048 +VolumeTable DB 6 Dup (0) + DB 0, 16, 96, 127 + DB 0, 0, 0, 0 + +IMR DW 0 +OldIRQHandler DD 0 + +MIDIPort DW 0 +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SB16ScreenList Label + DW 8 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SB16HeaderLine + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + DW Near Ptr VolumeBox2 + + DW Near Ptr DriverText + + DW Near Ptr MasterVolumeLeft ; 8 + DW Near Ptr MasterVolumeRight ; 9 + DW Near Ptr TrebleVolumeLeft ; 10 + DW Near Ptr TrebleVolumeRight ; 11 + DW Near Ptr BassVolumeLeft ; 12 + DW Near Ptr BassVolumeRight ; 13 + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 15 + DW Near Ptr MixModeButton2 ; 16 + + DW Near Ptr FrequencyText ; 17 + + DW Near Ptr FilterText ; 18 + DW Near Ptr FilterBox1 + DW Near Ptr FilterBox2 + + DW Near Ptr FilterFrequency1 ; 21 + DW Near Ptr FilterFrequency2 + DW Near Ptr FilterFrequency3 + DW Near Ptr FilterFrequency4 + + DW Near Ptr FilterVolume1 ; 25 + DW Near Ptr FilterVolume2 + DW Near Ptr FilterVolume3 + DW Near Ptr FilterVolume4 + + DW 0 + +SB16HeaderLine DW 10 + DB "Sound Blaster 16 3DNow! Driver", 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "Sound Blaster 16 Driver 1.4 for Impulse Tracker", 0 + +VolumeText DW 1 + DB 2, 13 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB 13 + DB 13 + DB "Treble Left", 13 + DB "Treble Right", 13 + DB "Bass Left", 13 + DB "Bass Right", 13 + DB 0 + +VolumeBox1 DW 0 + DB 21, 12, 27, 15 + DB 25 + +VolumeBox2 DW 0 + DB 14, 16, 18, 21 + DB 25 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MasterVolumeLeft DW 9 + DB 22, 13 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 14 + DW 0, 31 + DW 9, 1 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeLeft DW 9 + DB 15, 17 + DW 0, 15 + DW 9, 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeRight DW 9 + DB 15, 18 + DW 0, 15 + DW 9, 3 + DW 10, 12, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeLeft DW 9 + DB 15, 19 + DW 0, 15 + DW 9, 4 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeRight DW 9 + DB 15, 20 + DW 0, 15 + DW 9, 5 + DW 12, 15, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 23 + DB 20h + DB "Mixing Mode", 0 + +FrequencyText DW 1 + DB 2, 48 + DB 20h + DB "Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 45454 + DW 0 + +MixModeButton1 DW 2 + DW 13, 16, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " 3DNow!, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 15, 18, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 28, 32, 30, 8 + DB 0 + DB " 3DNow!, Filtered", 0 + +FilterText DW 1 + DB 2, 39 + DB 20h + DB "Output Equalizer", 13 + DB 13 + DB " Low Frequency Band", 13 + DB " Med Low Frequency Band", 13 + DB "Med High Frequency Band", 13 + DB " High Frequency Band", 0 + +FilterBox1 DW 0 + DB 25, 40, 47, 45 + DB 25 + +FilterBox2 DW 0 + DB 52, 40, 74, 45 + DB 25 + +FilterFrequency1 DW 14 + DB 26, 41 + DW 0, 127 + DW 9, 6 + DW 16, 22, 25, 25 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency2 DW 14 + DB 26, 42 + DW 0, 127 + DW 9, 7 + DW 21, 23, 26, 26 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency3 DW 14 + DB 26, 43 + DW 0, 127 + DW 9, 8 + DW 22, 24, 27, 27 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency4 DW 14 + DB 26, 44 + DW 0, 127 + DW 9, 9 + DW 23, 0FFFFh, 28, 28 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume1 DW 14 + DB 53, 41 + DW 0, 255 + DW 9, 10 + DW 16, 26, 21, 21 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume2 DW 14 + DB 53, 42 + DW 0, 255 + DW 9, 11 + DW 25, 27, 22, 22 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume3 DW 14 + DB 53, 43 + DW 0, 255 + DW 9, 12 + DW 26, 28, 23, 23 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume4 DW 14 + DB 53, 44 + DW 0, 255 + DW 9, 13 + DW 27, 0FFFFh, 24, 24 + DW 0FFFFh, 0FFFFh + DW 20 + + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix + +ALIGN 2 + +MixFunctionTables Label + +include m32bitm.inc +include m32bitmi.inc +include mnomix.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW 0 + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc DetectK63D + Assume DS:Driver + + PushFD + Pop EAX + Mov EBX, EAX + Xor EAX, 00200000h + Push EAX + PopFD + PushFD + Pop EAX + Cmp EAX, EBX + JZ DetectK63DFail + + Mov EAX, 80000000h + DB 0Fh, 0A2h ; CPUID + Cmp EAX, 80000000h + JBE DetectK63DFail + + Mov EAX, 80000001h + DB 0Fh, 0A2h + And EDX, 80800000h + Cmp EDX, 80800000h + JNE DetectK63DFail + + DB 85h + +DetectK63DFail: + StC + Ret + +EndP DetectK63D + Assume DS:Nothing + +; + +Proc DetectUART ; Given DX = Port + +; From SB-DevKit + + ClI + + Inc DX + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 40h ; Ready for output + LoopNZ DetectUART1 + JNZ DetectUARTError + + Mov AL, 0FFh ; Reset! + Out DX, AL + + Xor CX, CX + +DetectUART2: + In AL, DX + Test AL, 80h + JNZ DetectUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART4 + +DetectUART3: + Loop DetectUART2 + +DetectUARTError: + StI + StC + Ret + +DetectUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +DetectUART5: + In AL, DX + Test AL, 40h + LoopNZ DetectUART5 + JNZ DetectUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +DetectUART6: + Xor CX, CX + +DetectUART7: + In AL, DX + Test AL, 80h + JNZ DetectUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART9 + +DetectUART8: + Loop DetectUART7 + + Jmp DetectUARTError + +DetectUART9: + StI + ClC + Ret + +EndP DetectUART + +; + +Proc ReinitUART + + Mov DX, MIDIPort + Test DX, DX + JZ ReinitUART1 + + Call DetectUART + +ReinitUART1: + Ret + +EndP ReinitUART + +; + +Proc ResetUART + + Mov DX, MIDIPort + Test DX, DX + JZ ResetUART1 + + Inc DX + + Mov AL, 0FFh + Out DX, AL + +ResetUART1: + Ret + +EndP ResetUART + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 45454 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Mov BX, 12000 + Xor DX, DX + Div BX + Mov FourierBufferStepOffset, AX + Mov FourierBufferStepFractional, DX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +Proc ResetDSPIRQ + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPIRQValue + Mov AL, 80h + Out DX, AX + + Ret + +EndP ResetDSPIRQ + +; + +Proc ResetDSPDMA + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPDMAValue + Mov AL, 81h + Out DX, AX + + Ret + +EndP ResetDSPDMA + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Call DetectK63D + JC DetectCardFailure + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AH, 4 ; SB DSP = 4.00+ + JAE DetectCard5 + +DetectCard4: + StC + Ret + +DetectCard5: + Mov DSPVersion, AX + + Add DL, 04h-0Eh ; 2x4h = Mixer index port + Mov AL, 80h ; IRQ select + Out DX, AL + Inc DL ; 2x5h = Mixer data port + + In AL, DX + + Dec DL + + Mov DSPIRQValue, AL + ; OK.. now get IRQ, or set IRQ + Mov BX, IRQ + Cmp BX, 0FFFFh + JE DetectCardIRQ1 + Cmp Forced, 0 + JE DetectCardIRQ1 + + Mov AH, 11h + Cmp BL, 2 + JE SetCardIRQ1 + Cmp BL, 9 + JE SetCardIRQ1 + + Mov AH, 12h + Cmp BL, 5 + JE SetCardIRQ1 + + Mov AH, 14h + Cmp BL, 7 + JE SetCardIRQ1 + + Mov AH, 18h + Cmp BL, 10 + JE SetCardIRQ1 + + StC + Ret + +SetCardIRQ1: + Mov AL, 80h + Out DX, AL + Inc DL + Mov AL, AH + Out DX, AL + Dec DL + Jmp DetectCard6 + +DetectCardIRQ1: + Mov BX, 2 + Test AL, 1 + JNZ DetectCardIRQ2 + + Mov BL, 5 + Test AL, 2 + JNZ DetectCardIRQ2 + + Mov BL, 7 + Test AL, 4 + JNZ DetectCardIRQ2 + + Mov BL, 10 + Test AL, 8 + JNZ DetectCardIRQ2 + + StC + Ret + +DetectCardIRQ2: + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + + Cmp BX, IRQ + JE DetectCard6 + +DetectCardFailure: + StC + Ret + +DetectCardIRQ3: + Mov IRQ, BX + +DetectCard6: ; Detect DMA + Mov AL, 81h ; DMA select + Out DX, AL + Inc DL + In AL, DX ; AL = DMA + Dec DL + + Mov DSPDMAValue, AL + + Mov BX, DMA + Cmp BX, 0FFFFh + JE DetectCardDMA1 + Cmp Forced, 0 + JE DetectCardDMA1 + + Mov CL, 1 + Cmp BX, 1 + JB SetCardDMA1 + + Mov CL, 2 + JE SetCardDMA1 + + Cmp BX, 3 + JB DetectCard7 + + Mov CL, 8 + JE DetectCard7 + + Mov CL, 20h + Cmp BX, 5 + JB DetectCard7 + JE SetCardDMA1 + + Mov CL, 80h + Cmp BX, 7 + JA DetectCard7 + JE SetCardDMA1 + + Mov CL, 40h + +SetCardDMA1: + And AL, 0Bh + Test CL, 0Bh + JZ SetCardDMA4 + + Xor AL, AL + +SetCardDMA4: + Or CL, AL + + Mov AL, 81h + Out DX, AL + Inc DL + Mov AL, CL + Out DX, AL + Jmp DetectCard7 + +DetectCardDMA1: + Mov BX, 5 + Test AL, 20h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 40h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 80h + JNZ DetectCardDMA2 + + Mov BL, 0 + Test AL, 1 + JNZ DetectCardDMA2 + + Inc BL + Test AL, 2 + JNZ DetectCardDMA2 + + Add BL, 2 + Test AL, 8 + JNZ DetectCardDMA2 + +DetectCard8: + Call ResetDSPIRQ + StC + Ret + +DetectCardDMA2: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + + Cmp BX, DMA + JNE DetectCard8 + +DetectCardDMA3: + Mov DMA, BX + +DetectCard7: + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +include mmxmsam.inc +include fourier.inc + +; + +Proc AckIRQ + Assume DS:Driver + + Mov AL, 20h + Cmp CS:IRQ, 7 + JBE AckIRQ1 + + Out 0A0h, AL + +AckIRQ1: + Out 20h, AL + Ret + +EndP AckIRQ + Assume DS:Nothing + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Mov DX, MIDIPort + + Mov BL, [MIDIBufferTail] + Test DX, DX + JZ CheckMIDIEnd + + Inc DX + Mov CX, 0FFFFh + +CheckMIDIAgain: + In AL, DX + + Test AL, 80h + LoopNZ CheckMIDIAgain + + Dec DX + In AL, DX + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL +; Jmp CheckMIDIAgain + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc SB16IRQHandler + + PushAD + Push DS + Push ES + + CLD + +SBIRQAgain: + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 4 ; Mixer Port + Mov AL, 82h + Out DX, AL + Inc DL ; DX = BasePort+5 + In AL, DX + +Comment ~ + Test AL, 1 + JZ SB8BitDigitalInterruptEnd + +SB8BitDigitalInterrupt: + Push AX + Add DL, 0Eh-5 + In AL, DX + Pop AX + +SB8BitDigitalInterruptEnd: + + ~ + Test AL, 4 + JZ SBMIDIInterruptEnd + + Push AX + Call CheckMIDI + Pop AX + +SBMIDIInterruptEnd: + Test AL, 2 + JNZ SBDigitalInterrupt + + Call AckIRQ + Jmp SBIRQEnd + +SBDigitalInterrupt: + FNSave [FPSave] + + Mov DX, BasePort + Add DL, 0Fh + In AL, DX ; 16-bit IRQ ack. + + Call AckIRQ + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB SB16IRQHandler2 + + Xor AX, AX + Xor BX, BX + +SB16IRQHandler2: + Inc BX + Mov MixBufferPos, BX + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Mov BX, DMASize ; BX = bytes required + Add DI, AX + ShR BX, 1 + ; BX = samples required + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SB16IRQHandler4 + Assume DS:Nothing + +SB16IRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + Call UpdateFourierBuffer + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +SB16IRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SB16IRQHandler5 + + Mov DX, MixTransferRemaining + +SB16IRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SB16IRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + FNRstor [CS:FPSave] + +SBIRQEnd: + Pop ES + Pop DS + PopAD + IRet + +EndP SB16IRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SB16IRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSB16 ; + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0B6h ; 16 bit, DAC + Call SBOut + Mov AL, Stereo + ShL AL, 5 + Or AL, 10h + Call SBOut + + Mov AX, DMASize + ShR AX, 1 + Dec AX + + Call SBOut ; DMALength, Lo + Mov AL, AH + Call SBOut + + Pop ES + Pop DS + PopA + + Ret + + Assume DS:Nothing + +EndP StartSB16 + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov DX, BasePort + Add DL, 4 + + Mov AL, 30h + Call SBGetRegister + ShR AL, 3 + Mov VolumeTable, AL + + Mov AL, 31h + Call SBGetRegister + ShR AL, 3 + Mov [VolumeTable+1], AL + + Mov AL, 44h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+2], AL + + Mov AL, 45h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+3], AL + + Mov AL, 46h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+4], AL + + Mov AL, 47h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+5], AL + + Call GetSBMixConst + + ; Parags to allocate = (8/(.4*31*16))*MixSpeed + 2080 + ; = .04032258*MixSpeed = (65536*.04032258*MixSpeed) / 65536 + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 5+(DMABUFFERLENGTH*2)/16+(FOURIERBUFFERLENGTH*2)/16 + Mov BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SB16NoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Sub AX, (FOURIERBUFFERLENGTH*2)/16 + Mov FourierSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov DX, 330h + Call DetectUART + JC DetectMIDI1 + + Mov MIDIPort, 330h + Jmp DetectMIDIEnd + +DetectMIDI1: + Mov DX, 300h + Call DetectUART + JC DetectMIDIEnd + + Mov MIDIPort, 300h + +DetectMIDIEnd: + Call CalculateFilterCoefficients + + Mov SI, Offset SB16Msg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, BasePort + Call ResetDSP + + Call ResetUART + Call ResetIRQ + + ; Delay.. + Mov DX, BasePort + Add DL, 0Ch + + Mov CX, 1000 +ReInitSound1: + In AL, DX + Loop ReInitSound1 + + Call SetIRQ + Call ReinitUART + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Mov DX, CS:BasePort + Add DL, 0Ch + + Mov AL, 0D9h + Call SBOut + + Call ResetUART + + Mov AX, BasePort + Call ResetDSP + + Call ResetDSPDMA + Call ResetDSPIRQ + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov CS:Stereo, AL + Mov AX, CS:BasePort + Call ResetDSP + + Call StartSB16 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far ; Fix up end of sample bytes + + PushAD + Push DS + Push ES + Push FS + + Mov FS, CS:SongDataArea + Mov BP, AX + Add BP, BP + Mov BP, [FS:64910+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length + JC LoadSampleEnd ; Zero flag ON if 16 bit.. + + Xor EAX, EAX + Mov BL, [FS:BP+12h] + + Test BL, 10h ; Loop + JZ LoadSample2 + + Mov ESI, [FS:BP+34h] ; Start of loop + Test BL, 40h ; Pingpong? + JZ LoadSample1 + + Mov ESI, [FS:BP+38h] + Sub ESI, 2 + JNC LoadSample1 + + Xor ESI, ESI + +LoadSample1: + Test BL, 2 + JZ LoadSample4 + + Add ESI, ESI + +LoadSample4: + Int 3 + Mov AL, [SI] + Inc ESI + Int 3 + Mov AH, [SI] + +LoadSample2: + Mov ESI, [FS:BP+30h] + Test BL, 2 + JZ LoadSample3 + + Add ESI, ESI + +LoadSample3: + Int 3 + Mov [SI], AL + Inc ESI + Int 3 + Mov [SI], AH + +LoadSampleEnd: + Pop FS + Pop ES + Pop DS + PopAD + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SB16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +TempVariable DW 0 +Const1 DD 3F800000h + +Proc GetFilterFrequency ; Given AL= Freq + Assume DS:Driver + + ShL AX, 8 + Mov TempVariable, AX + FILD TempVariable + + FMul FreqParameterMultiplier ; -i/(24*256) + FLd ST + FRndInt + FSub ST(1), ST + FXCh + F2XM1 + FLd1 + FAdd + FScale ; = 2^(i/24*256) + FMul FreqMultiplier ; = r + + FLd1 ; 1, c + FAdd ST, ST(1) ; 1+c, c + FDivR Const1 ; 1/(1+c), c + FSt DWord Ptr [SI] + FMul + FStP DWord Ptr [SI+4] + FStP ST + + Ret + +EndP GetFilterFrequency + Assume DS:Nothing + +; + +Const1On16 DD 3D000000h ; actually 1 on 32 + +Proc CalculateFilterCoefficients + Assume DS:Driver + + PushA + + FNInit + FLdCW NewControlWord + + Mov AL, [VolumeTable+6] + Mov SI, Offset FilterCoefficients + ShR AL, 1 + Call GetFilterFrequency + + Mov AL, [VolumeTable+7] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + + Mov AL, [VolumeTable+8] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + + Mov AL, [VolumeTable+9] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + +; Now volumes + Mov SI, Offset VolumeTable+10 + Mov DI, Offset FilterVolumes + Xor AX, AX + Mov CX, 4 + +FilterVolumeLoop1: + LodSB + Mov TempVariable, AX + FILD TempVariable + FMul Const1On16 + FStP DWord Ptr [DI] + + Add DI, 4 + Loop FilterVolumeLoop1 + + PopA + Ret + +EndP CalculateFilterCoefficients + Assume DS:Nothing + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Cmp DI, 9 + JA SetVariable3 + + Cmp DI, 6 + JB SetVariable1 + + JE SetVariable2 + + Cmp AL, [VolumeTable+DI-1] + JAE SetVariable2 + + Mov AL, [VolumeTable+DI-1] + Mov [VolumeTable+DI], AL + +SetVariable2: + Cmp DI, 9 + JAE SetVariable3 + + Cmp AL, [VolumeTable+DI+1] + JBE SetVariable3 + + Mov AL, [VolumeTable+DI+1] + Mov [VolumeTable+DI], AL + +SetVariable3: + Call CalculateFilterCoefficients + Jmp SetVariableEnd + +SetVariable1: + Mov DX, BasePort + Add DL, 4 + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + +SetVariableEnd: + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +Proc UARTOut + + Push CX + Push DX + Mov DX, CS:MIDIPort + Test DX, DX + JZ UARTOutEnd + + Push AX + Xor CX, CX + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + LoopNZ UARTOut1 + + Pop AX + JNZ UARTOutEnd + + Dec DX + Out DX, AL + +UARTOutEnd: + Pop DX + Pop CX + + Ret + +EndP UARTOut + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +Proc GetWaveForm Far ; Given ES:DI = destination + Assume DS:Nothing ; want 2048 samples. + + PushA + Push DS + + Mov DS, FourierSegment + Mov SI, FourierBufferStart + Mov CX, 2048 + +GetWaveForm1: + MovsW + And SI, (FOURIERBUFFERLENGTH*2)-1 + Loop GetWaveForm1 + + Pop DS + PopA + + Ret + +EndP GetWaveForm + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 + DW 7 ; MIDI, hiqual + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + + DW Offset SendUARTOut + + DW Offset GetWaveform + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SB16MMX.ASM b/it/SoundDrivers/SB16MMX.ASM new file mode 100755 index 0000000..4c49440 --- /dev/null +++ b/it/SoundDrivers/SB16MMX.ASM @@ -0,0 +1,2272 @@ + + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +TRACEENABLED = 0 +CREATENEWLOGFILE = 1 + +include debug.inc + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for the SB16 +OUTPUTFILTERENABLED EQU 1 +FOURIERBUFFERLENGTH EQU 2048 ; 2048 samples + +FPSave DB 128 Dup (0) + +SB16Msg DB "Sound Blaster 16 MMX", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SB16NoMemoryMsg DB "Sound Blaster 16 MMX", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster 16 reinitialised", 0 + +DefaultDriverName DB "ITSB16.MMX", 0 +DriverName DD 0 + +DSPVersion DW 0 +DSPIRQValue DB 0 +DSPDMAValue DB 0 +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +FourierSegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 20 +MixMode DW 0 +MixModeOffset DW 0 +DMASize DW 2048 +VolumeTable DB 6 Dup (0) + DB 0, 16, 96, 127 + DB 0, 0, 0, 0 + +IMR DW 0 +OldIRQHandler DD 0 + +MIDIPort DW 0 +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SB16ScreenList Label + DW 8 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SB16HeaderLine + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + DW Near Ptr VolumeBox2 + + DW Near Ptr DriverText + + DW Near Ptr MasterVolumeLeft ; 8 + DW Near Ptr MasterVolumeRight ; 9 + DW Near Ptr TrebleVolumeLeft ; 10 + DW Near Ptr TrebleVolumeRight ; 11 + DW Near Ptr BassVolumeLeft ; 12 + DW Near Ptr BassVolumeRight ; 13 + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 15 + DW Near Ptr MixModeButton2 ; 16 + DW Near Ptr MixModeButton3 ; 17 + DW Near Ptr MixModeButton4 ; 18 + + DW Near Ptr FrequencyText + + DW Near Ptr FilterText ; 20 + DW Near Ptr FilterBox1 + DW Near Ptr FilterBox2 + + DW Near Ptr FilterFrequency1 ; 23 + DW Near Ptr FilterFrequency2 + DW Near Ptr FilterFrequency3 + DW Near Ptr FilterFrequency4 + + DW Near Ptr FilterVolume1 ; 27 + DW Near Ptr FilterVolume2 + DW Near Ptr FilterVolume3 + DW Near Ptr FilterVolume4 + + DW 0 + + +SB16HeaderLine DW 10 + DB "Sound Blaster 16 Driver", 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "Sound Blaster 16 Driver 1.4 for Impulse Tracker", 0 + +VolumeText DW 1 + DB 2, 13 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB 13 + DB 13 + DB "Treble Left", 13 + DB "Treble Right", 13 + DB "Bass Left", 13 + DB "Bass Right", 13 + DB 0 + +VolumeBox1 DW 0 + DB 21, 12, 27, 15 + DB 25 + +VolumeBox2 DW 0 + DB 14, 16, 18, 21 + DB 25 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MasterVolumeLeft DW 9 + DB 22, 13 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 14 + DW 0, 31 + DW 9, 1 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeLeft DW 9 + DB 15, 17 + DW 0, 15 + DW 9, 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeRight DW 9 + DB 15, 18 + DW 0, 15 + DW 9, 3 + DW 10, 12, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeLeft DW 9 + DB 15, 19 + DW 0, 15 + DW 9, 4 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeRight DW 9 + DB 15, 20 + DW 0, 15 + DW 9, 5 + DW 12, 15, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 23 + DB 20h + DB "Mixing Mode", 0 + +FrequencyText DW 1 + DB 2, 48 + DB 20h + DB "Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 45454 + DW 0 + +MixModeButton1 DW 2 + DW 13, 16, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " MMX, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 15, 17, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 28, 32, 30, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 16, 18, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 31, 32, 33, 8 + DB 0 + DB " MMX, Volume Ramped", 0 + +MixModeButton4 DW 2 + DW 17, 23, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 34, 32, 36, 8 + DB 0 + DB " MMX, Filtered", 0 + +FilterText DW 1 + DB 2, 39 + DB 20h + DB "Output Equalizer", 13 + DB 13 + DB " Low Frequency Band", 13 + DB " Med Low Frequency Band", 13 + DB "Med High Frequency Band", 13 + DB " High Frequency Band", 0 + +FilterBox1 DW 0 + DB 25, 40, 47, 45 + DB 25 + +FilterBox2 DW 0 + DB 52, 40, 74, 45 + DB 25 + +FilterFrequency1 DW 14 + DB 26, 41 + DW 0, 127 + DW 9, 6 + DW 18, 24, 27, 27 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency2 DW 14 + DB 26, 42 + DW 0, 127 + DW 9, 7 + DW 23, 25, 28, 28 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency3 DW 14 + DB 26, 43 + DW 0, 127 + DW 9, 8 + DW 24, 26, 29, 29 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency4 DW 14 + DB 26, 44 + DW 0, 127 + DW 9, 9 + DW 25, 0FFFFh, 30, 30 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume1 DW 14 + DB 53, 41 + DW 0, 255 + DW 9, 10 + DW 18, 28, 23, 23 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume2 DW 14 + DB 53, 42 + DW 0, 255 + DW 9, 11 + DW 27, 29, 24, 24 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume3 DW 14 + DB 53, 43 + DW 0, 255 + DW 9, 12 + DW 28, 30, 25, 25 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume4 DW 14 + DB 53, 44 + DW 0, 255 + DW 9, 13 + DW 29, 0FFFFh, 26, 26 + DW 0FFFFh, 0FFFFh + DW 20 + + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label + +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc DetectMMX + + Trace "Detecting MMX - CPUID Check" + + PushFD + Pop EAX + Mov EBX, EAX + Xor EAX, 00200000h + Push EAX + PopFD + PushFD + Pop EAX + Cmp EAX, EBX + JZ DetectMMXFail + + Trace "CPUID - Check OK" + + Mov EAX, 1 + DB 0Fh, 0A2h ; CPUID + Test EDX, 800000h + JZ DetectMMXFail + + Trace "MMX Detected" + + ClC + Ret + +DetectMMXFail: + Trace "MMX Not Detected" + + StC + Ret + +EndP DetectMMX + +; + +Proc DetectUART ; Given DX = Port + +; From SB-DevKit + + ClI + + Inc DX + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 40h ; Ready for output + LoopNZ DetectUART1 + JNZ DetectUARTError + + Mov AL, 0FFh ; Reset! + Out DX, AL + + Xor CX, CX + +DetectUART2: + In AL, DX + Test AL, 80h + JNZ DetectUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART4 + +DetectUART3: + Loop DetectUART2 + +DetectUARTError: + StI + StC + Ret + +DetectUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +DetectUART5: + In AL, DX + Test AL, 40h + LoopNZ DetectUART5 + JNZ DetectUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +DetectUART6: + Xor CX, CX + +DetectUART7: + In AL, DX + Test AL, 80h + JNZ DetectUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART9 + +DetectUART8: + Loop DetectUART7 + + Jmp DetectUARTError + +DetectUART9: + StI + ClC + Ret + +EndP DetectUART + +; + +Proc ReinitUART + + Mov DX, MIDIPort + Test DX, DX + JZ ReinitUART1 + + Call DetectUART + +ReinitUART1: + Ret + +EndP ReinitUART + +; + +Proc ResetUART + + Mov DX, MIDIPort + Test DX, DX + JZ ResetUART1 + + Inc DX + + Mov AL, 0FFh + Out DX, AL + +ResetUART1: + Ret + +EndP ResetUART + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 45454 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Mov BX, 12000 + Xor DX, DX + Div BX + Mov FourierBufferStepOffset, AX + Mov FourierBufferStepFractional, DX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +Proc ResetDSPIRQ + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPIRQValue + Mov AL, 80h + Out DX, AX + + Ret + +EndP ResetDSPIRQ + +; + +Proc ResetDSPDMA + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPDMAValue + Mov AL, 81h + Out DX, AX + + Ret + +EndP ResetDSPDMA + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Cmp BX, 217h + JAE DetectCardUseDriver + + Mov CX, DS + ShL ECX, 16 + Mov CX, Offset DefaultDriverName + +DetectCardUseDriver: + Mov DriverName, ECX + + Call DetectMMX + JC DetectCardFailure + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AH, 4 ; SB DSP = 4.00+ + JAE DetectCard5 + +DetectCard4: + StC + Ret + +DetectCard5: + Mov DSPVersion, AX + + Add DL, 04h-0Eh ; 2x4h = Mixer index port + Mov AL, 80h ; IRQ select + Out DX, AL + Inc DL ; 2x5h = Mixer data port + + In AL, DX + + Dec DL + + Mov DSPIRQValue, AL + ; OK.. now get IRQ, or set IRQ + Mov BX, IRQ + Cmp BX, 0FFFFh + JE DetectCardIRQ1 + Cmp Forced, 0 + JE DetectCardIRQ1 + + Mov AH, 11h + Cmp BL, 2 + JE SetCardIRQ1 + Cmp BL, 9 + JE SetCardIRQ1 + + Mov AH, 12h + Cmp BL, 5 + JE SetCardIRQ1 + + Mov AH, 14h + Cmp BL, 7 + JE SetCardIRQ1 + + Mov AH, 18h + Cmp BL, 10 + JE SetCardIRQ1 + + StC + Ret + +SetCardIRQ1: + Mov AL, 80h + Out DX, AL + Inc DL + Mov AL, AH + Out DX, AL + Dec DL + Jmp DetectCard6 + +DetectCardIRQ1: + Mov BX, 2 + Test AL, 1 + JNZ DetectCardIRQ2 + + Mov BL, 5 + Test AL, 2 + JNZ DetectCardIRQ2 + + Mov BL, 7 + Test AL, 4 + JNZ DetectCardIRQ2 + + Mov BL, 10 + Test AL, 8 + JNZ DetectCardIRQ2 + + StC + Ret + +DetectCardIRQ2: + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + + Cmp BX, IRQ + JE DetectCard6 + +DetectCardFailure: + StC + Ret + +DetectCardIRQ3: + Mov IRQ, BX + +DetectCard6: ; Detect DMA + Mov AL, 81h ; DMA select + Out DX, AL + Inc DL + In AL, DX ; AL = DMA + Dec DL + + Mov DSPDMAValue, AL + + Mov BX, DMA + Cmp BX, 0FFFFh + JE DetectCardDMA1 + Cmp Forced, 0 + JE DetectCardDMA1 + + Mov CL, 1 + Cmp BX, 1 + JB SetCardDMA1 + + Mov CL, 2 + JE SetCardDMA1 + + Cmp BX, 3 + JB DetectCard7 + + Mov CL, 8 + JE DetectCard7 + + Mov CL, 20h + Cmp BX, 5 + JB DetectCard7 + JE SetCardDMA1 + + Mov CL, 80h + Cmp BX, 7 + JA DetectCard7 + JE SetCardDMA1 + + Mov CL, 40h + +SetCardDMA1: + And AL, 0Bh + Test CL, 0Bh + JZ SetCardDMA4 + + Xor AL, AL + +SetCardDMA4: + Or CL, AL + + Mov AL, 81h + Out DX, AL + Inc DL + Mov AL, CL + Out DX, AL + Jmp DetectCard7 + +DetectCardDMA1: + Mov BX, 5 + Test AL, 20h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 40h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 80h + JNZ DetectCardDMA2 + + Mov BL, 0 + Test AL, 1 + JNZ DetectCardDMA2 + + Inc BL + Test AL, 2 + JNZ DetectCardDMA2 + + Add BL, 2 + Test AL, 8 + JNZ DetectCardDMA2 + +DetectCard8: + Call ResetDSPIRQ + StC + Ret + +DetectCardDMA2: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + + Cmp BX, DMA + JNE DetectCard8 + +DetectCardDMA3: + Mov DMA, BX + +DetectCard7: + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +include mmxmsam.inc +include fourier.inc + +; + +Proc AckIRQ + Assume DS:Driver + + Mov AL, 20h + Cmp CS:IRQ, 7 + JBE AckIRQ1 + + Out 0A0h, AL + +AckIRQ1: + Out 20h, AL + Ret + +EndP AckIRQ + Assume DS:Nothing + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Mov DX, MIDIPort + + Mov BL, [MIDIBufferTail] + Test DX, DX + JZ CheckMIDIEnd + + Inc DX + Mov CX, 0FFFFh + +CheckMIDIAgain: + In AL, DX + + Test AL, 80h + LoopNZ CheckMIDIAgain + + Dec DX + In AL, DX + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL +; Jmp CheckMIDIAgain + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc SB16IRQHandler + + PushAD + Push DS + Push ES + + CLD + +SBIRQAgain: + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 4 ; Mixer Port + Mov AL, 82h + Out DX, AL + Inc DL ; DX = BasePort+5 + In AL, DX + +Comment ~ + Test AL, 1 + JZ SB8BitDigitalInterruptEnd + +SB8BitDigitalInterrupt: + Push AX + Add DL, 0Eh-5 + In AL, DX + Pop AX + +SB8BitDigitalInterruptEnd: + + ~ + Test AL, 4 + JZ SBMIDIInterruptEnd + + Push AX + Call CheckMIDI + Pop AX + +SBMIDIInterruptEnd: + Test AL, 2 + JNZ SBDigitalInterrupt + + Call AckIRQ + Jmp SBIRQEnd + +SBDigitalInterrupt: + FNSave [FPSave] + + Mov DX, BasePort + Add DL, 0Fh + In AL, DX ; 16-bit IRQ ack. + + Call AckIRQ + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB SB16IRQHandler2 + + Xor AX, AX + Xor BX, BX + +SB16IRQHandler2: + Inc BX + Mov MixBufferPos, BX + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Mov BX, DMASize ; BX = bytes required + Add DI, AX + ShR BX, 1 + ; BX = samples required + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SB16IRQHandler4 + Assume DS:Nothing + +SB16IRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + Call UpdateFourierBuffer + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +SB16IRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SB16IRQHandler5 + + Mov DX, MixTransferRemaining + +SB16IRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SB16IRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + FNRstor [CS:FPSave] + +SBIRQEnd: + Pop ES + Pop DS + PopAD + IRet + +EndP SB16IRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SB16IRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSB16 ; + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0B6h ; 16 bit, DAC + Call SBOut + Mov AL, Stereo + ShL AL, 5 + Or AL, 10h + Call SBOut + + Mov AX, DMASize + ShR AX, 1 + Dec AX + + Call SBOut ; DMALength, Lo + Mov AL, AH + Call SBOut + + Pop ES + Pop DS + PopA + + Ret + + Assume DS:Nothing + +EndP StartSB16 + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov DX, BasePort + Add DL, 4 + + Mov AL, 30h + Call SBGetRegister + ShR AL, 3 + Mov VolumeTable, AL + + Mov AL, 31h + Call SBGetRegister + ShR AL, 3 + Mov [VolumeTable+1], AL + + Mov AL, 44h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+2], AL + + Mov AL, 45h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+3], AL + + Mov AL, 46h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+4], AL + + Mov AL, 47h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+5], AL + + Call GetSBMixConst + + ; Parags to allocate = (8/(.4*31*16))*MixSpeed + ; = .04032258*MixSpeed = (65536*.04032258*MixSpeed) / 65536 + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 5+(DMABUFFERLENGTH*2)/16+(FOURIERBUFFERLENGTH*2)/16 + Mov BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SB16NoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Sub AX, (FOURIERBUFFERLENGTH*2)/16 + Mov FourierSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov DX, 330h + Call DetectUART + JC DetectMIDI1 + + Mov MIDIPort, 330h + Jmp DetectMIDIEnd + +DetectMIDI1: + Mov DX, 300h + Call DetectUART + JC DetectMIDIEnd + + Mov MIDIPort, 300h + +DetectMIDIEnd: + Call CalculateFilterCoefficients + + Mov SI, Offset SB16Msg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, BasePort + Call ResetDSP + + Call ResetUART + Call ResetIRQ + + ; Delay.. + Mov DX, BasePort + Add DL, 0Ch + + Mov CX, 1000 +ReInitSound1: + In AL, DX + Loop ReInitSound1 + + Call SetIRQ + Call ReinitUART + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Mov DS, Word Ptr [CS:DriverName+2] + Mov DX, Word Ptr [CS:DriverName] + + Mov AX, 3D02h ; Read write access + Int 21h + + Push CS + Pop DS + Assume DS:Driver + + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Mov DX, CS:BasePort + Add DL, 0Ch + + Mov AL, 0D9h + Call SBOut + + Call ResetUART + + Mov AX, BasePort + Call ResetDSP + + Call ResetDSPDMA + Call ResetDSPIRQ + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov CS:Stereo, AL + Mov AX, CS:BasePort + Call ResetDSP + + Call StartSB16 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SB16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +TempVariable DW 0 +Const1 DD 3F800000h + +Proc GetFilterFrequency ; Given AL= Freq + Assume DS:Driver + + ShL AX, 8 + Mov TempVariable, AX + FILD TempVariable + + FMul FreqParameterMultiplier ; -i/(24*256) + FLd ST + FRndInt + FSub ST(1), ST + FXCh + F2XM1 + FLd1 + FAdd + FScale ; = 2^(i/24*256) + FMul FreqMultiplier ; = r + + FLd1 ; 1, c + FAdd ST, ST(1) ; 1+c, c + FDivR Const1 ; 1/(1+c), c + FSt DWord Ptr [SI] + FMul + FStP DWord Ptr [SI+4] + FStP ST + + Ret + +EndP GetFilterFrequency + Assume DS:Nothing + +; + +Const1On16 DD 3D000000h ; actually 1 on 32 + +Proc CalculateFilterCoefficients + Assume DS:Driver + + PushA + + FNInit + FLdCW NewControlWord + + Mov AL, [VolumeTable+6] + Mov SI, Offset FilterCoefficients + ShR AL, 1 + Call GetFilterFrequency + + Mov AL, [VolumeTable+7] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + + Mov AL, [VolumeTable+8] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + + Mov AL, [VolumeTable+9] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + +; Now volumes + Mov SI, Offset VolumeTable+10 + Mov DI, Offset FilterVolumes + Xor AX, AX + Mov CX, 4 + +FilterVolumeLoop1: + LodSB + Mov TempVariable, AX + FILD TempVariable + FMul Const1On16 + FStP DWord Ptr [DI] + + Add DI, 4 + Loop FilterVolumeLoop1 + + PopA + Ret + +EndP CalculateFilterCoefficients + Assume DS:Nothing + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Cmp DI, 9 + JA SetVariable3 + + Cmp DI, 6 + JB SetVariable1 + + JE SetVariable2 + + Cmp AL, [VolumeTable+DI-1] + JAE SetVariable2 + + Mov AL, [VolumeTable+DI-1] + Mov [VolumeTable+DI], AL + +SetVariable2: + Cmp DI, 9 + JAE SetVariable3 + + Cmp AL, [VolumeTable+DI+1] + JBE SetVariable3 + + Mov AL, [VolumeTable+DI+1] + Mov [VolumeTable+DI], AL + +SetVariable3: + Call CalculateFilterCoefficients + Jmp SetVariableEnd + +SetVariable1: + Mov DX, BasePort + Add DL, 4 + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + +SetVariableEnd: + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +Proc UARTOut + + Push CX + Push DX + Mov DX, CS:MIDIPort + Test DX, DX + JZ UARTOutEnd + + Push AX + Xor CX, CX + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + LoopNZ UARTOut1 + + Pop AX + JNZ UARTOutEnd + + Dec DX + Out DX, AL + +UARTOutEnd: + Pop DX + Pop CX + + Ret + +EndP UARTOut + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +Proc GetWaveForm Far ; Given ES:DI = destination + Assume DS:Nothing ; want 2048 samples. + + PushA + Push DS + + Mov DS, FourierSegment + Mov SI, FourierBufferStart + Mov CX, 2048 + +GetWaveForm1: + MovsW + And SI, (FOURIERBUFFERLENGTH*2)-1 + Loop GetWaveForm1 + + Pop DS + PopA + + Ret + +EndP GetWaveForm + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 + DW 7 ; MIDI, hiqual + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + + DW Offset SendUARTOut + + DW Offset GetWaveform + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SB16MMXB.ASM b/it/SoundDrivers/SB16MMXB.ASM new file mode 100755 index 0000000..15607d8 --- /dev/null +++ b/it/SoundDrivers/SB16MMXB.ASM @@ -0,0 +1,2265 @@ + + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +TRACEENABLED = 0 +CREATENEWLOGFILE = 1 + +include debug.inc + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 32 ; 32 bit mixing for the SB16 +OUTPUTFILTERENABLED EQU 1 +FOURIERBUFFERLENGTH EQU 2048 ; 2048 samples + +FPSave DB 128 Dup (0) + +SB16Msg DB "Sound Blaster 16 MMX", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SB16NoMemoryMsg DB "Sound Blaster 16 MMX", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster 16 reinitialised", 0 + +DefaultDriverName DB "ITSB16.MMX", 0 +DriverName DD 0 + +DSPVersion DW 0 +DSPIRQValue DB 0 +DSPDMAValue DB 0 +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +FourierSegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 20 +MixMode DW 0 +MixModeOffset DW 0 +DMASize DW 2048 +VolumeTable DB 6 Dup (0) + DB 0, 16, 96, 127 + DB 0, 0, 0, 0 + +IMR DW 0 +OldIRQHandler DD 0 + +MIDIPort DW 0 +MIDIBuffer DB 256 Dup (0) +MIDIBufferHead DB 0 +MIDIBufferTail DB 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SB16ScreenList Label + DW 8 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SB16HeaderLine + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + DW Near Ptr VolumeBox2 + + DW Near Ptr DriverText + + DW Near Ptr MasterVolumeLeft ; 8 + DW Near Ptr MasterVolumeRight ; 9 + DW Near Ptr TrebleVolumeLeft ; 10 + DW Near Ptr TrebleVolumeRight ; 11 + DW Near Ptr BassVolumeLeft ; 12 + DW Near Ptr BassVolumeRight ; 13 + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 15 + DW Near Ptr MixModeButton2 ; 16 + DW Near Ptr MixModeButton3 ; 17 + DW Near Ptr MixModeButton4 ; 18 + + DW Near Ptr FrequencyText + + DW Near Ptr FilterText ; 20 + DW Near Ptr FilterBox1 + DW Near Ptr FilterBox2 + + DW Near Ptr FilterFrequency1 ; 23 + DW Near Ptr FilterFrequency2 + DW Near Ptr FilterFrequency3 + DW Near Ptr FilterFrequency4 + + DW Near Ptr FilterVolume1 ; 27 + DW Near Ptr FilterVolume2 + DW Near Ptr FilterVolume3 + DW Near Ptr FilterVolume4 + + DW 0 + + +SB16HeaderLine DW 10 + DB "Sound Blaster 16 Driver", 0 + +DriverText DW 1 + DB 31, 48 + DB 21h + DB "Sound Blaster 16 Driver 1.4 for Impulse Tracker", 0 + +VolumeText DW 1 + DB 2, 13 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB 13 + DB 13 + DB "Treble Left", 13 + DB "Treble Right", 13 + DB "Bass Left", 13 + DB "Bass Right", 13 + DB 0 + +VolumeBox1 DW 0 + DB 21, 12, 27, 15 + DB 25 + +VolumeBox2 DW 0 + DB 14, 16, 18, 21 + DB 25 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MasterVolumeLeft DW 9 + DB 22, 13 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 14 + DW 0, 31 + DW 9, 1 + DW 8, 10, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeLeft DW 9 + DB 15, 17 + DW 0, 15 + DW 9, 2 + DW 9, 11, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +TrebleVolumeRight DW 9 + DB 15, 18 + DW 0, 15 + DW 9, 3 + DW 10, 12, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeLeft DW 9 + DB 15, 19 + DW 0, 15 + DW 9, 4 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +BassVolumeRight DW 9 + DB 15, 20 + DW 0, 15 + DW 9, 5 + DW 12, 15, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 23 + DB 20h + DB "Mixing Mode", 0 + +FrequencyText DW 1 + DB 2, 48 + DB 20h + DB "Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 45454 + DW 0 + +MixModeButton1 DW 2 + DW 13, 16, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " MMX, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 15, 17, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 28, 32, 30, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 16, 18, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 31, 32, 33, 8 + DB 0 + DB " MMX, Volume Ramped", 0 + +MixModeButton4 DW 2 + DW 17, 23, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 34, 32, 36, 8 + DB 0 + DB " MMX, Filtered", 0 + +FilterText DW 1 + DB 2, 39 + DB 20h + DB "Output Equalizer", 13 + DB 13 + DB " Low Frequency Band", 13 + DB " Med Low Frequency Band", 13 + DB "Med High Frequency Band", 13 + DB " High Frequency Band", 0 + +FilterBox1 DW 0 + DB 25, 40, 47, 45 + DB 25 + +FilterBox2 DW 0 + DB 52, 40, 74, 45 + DB 25 + +FilterFrequency1 DW 14 + DB 26, 41 + DW 0, 127 + DW 9, 6 + DW 18, 24, 27, 27 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency2 DW 14 + DB 26, 42 + DW 0, 127 + DW 9, 7 + DW 23, 25, 28, 28 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency3 DW 14 + DB 26, 43 + DW 0, 127 + DW 9, 8 + DW 24, 26, 29, 29 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency4 DW 14 + DB 26, 44 + DW 0, 127 + DW 9, 9 + DW 25, 0FFFFh, 30, 30 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume1 DW 14 + DB 53, 41 + DW 0, 255 + DW 9, 10 + DW 18, 28, 23, 23 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume2 DW 14 + DB 53, 42 + DW 0, 255 + DW 9, 11 + DW 27, 29, 24, 24 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume3 DW 14 + DB 53, 43 + DW 0, 255 + DW 9, 12 + DW 28, 30, 25, 25 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume4 DW 14 + DB 53, 44 + DW 0, 255 + DW 9, 13 + DW 29, 0FFFFh, 26, 26 + DW 0FFFFh, 0FFFFh + DW 20 + + +; MixingRoutines + +include dmasirq.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label + +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc DetectMMX + + Trace "Detecting MMX - CPUID Check" + + PushFD + Pop EAX + Mov EBX, EAX + Xor EAX, 00200000h + Push EAX + PopFD + PushFD + Pop EAX + Cmp EAX, EBX + JZ DetectMMXFail + + Trace "CPUID - Check OK" + + Mov EAX, 1 + DB 0Fh, 0A2h ; CPUID + Test EDX, 800000h + JZ DetectMMXFail + + Trace "MMX Detected" + + ClC + Ret + +DetectMMXFail: + Trace "MMX Not Detected" + + StC + Ret + +EndP DetectMMX + +; + +Proc DetectUART ; Given DX = Port + +; From SB-DevKit + + ClI + + Inc DX + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 40h ; Ready for output + LoopNZ DetectUART1 + JNZ DetectUARTError + + Mov AL, 0FFh ; Reset! + Out DX, AL + + Xor CX, CX + +DetectUART2: + In AL, DX + Test AL, 80h + JNZ DetectUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART4 + +DetectUART3: + Loop DetectUART2 + +DetectUARTError: + StI + StC + Ret + +DetectUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +DetectUART5: + In AL, DX + Test AL, 40h + LoopNZ DetectUART5 + JNZ DetectUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +DetectUART6: + Xor CX, CX + +DetectUART7: + In AL, DX + Test AL, 80h + JNZ DetectUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE DetectUART9 + +DetectUART8: + Loop DetectUART7 + + Jmp DetectUARTError + +DetectUART9: + StI + ClC + Ret + +EndP DetectUART + +; + +Proc ReinitUART + + Mov DX, MIDIPort + Test DX, DX + JZ ReinitUART1 + + Call DetectUART + +ReinitUART1: + Ret + +EndP ReinitUART + +; + +Proc ResetUART + + Mov DX, MIDIPort + Test DX, DX + JZ ResetUART1 + + Inc DX + + Mov AL, 0FFh + Out DX, AL + +ResetUART1: + Ret + +EndP ResetUART + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 45454 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Mov BX, 12000 + Xor DX, DX + Div BX + Mov FourierBufferStepOffset, AX + Mov FourierBufferStepFractional, DX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; + +Proc ResetDSPIRQ + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPIRQValue + Mov AL, 80h + Out DX, AX + + Ret + +EndP ResetDSPIRQ + +; + +Proc ResetDSPDMA + + Mov DX, CS:BasePort + Add DL, 4 + Mov AH, CS:DSPDMAValue + Mov AL, 81h + Out DX, AX + + Ret + +EndP ResetDSPDMA + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Cmp BX, 217h + JAE DetectCardUseDriver + + Mov CX, DS + ShL ECX, 16 + Mov CX, Offset DefaultDriverName + +DetectCardUseDriver: + Mov DriverName, ECX + + Call DetectMMX + JC DetectCardFailure + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AH, 4 ; SB DSP = 4.00+ + JAE DetectCard5 + +DetectCard4: + StC + Ret + +DetectCard5: + Mov DSPVersion, AX + + Add DL, 04h-0Eh ; 2x4h = Mixer index port + Mov AL, 80h ; IRQ select + Out DX, AL + Inc DL ; 2x5h = Mixer data port + + In AL, DX + + Dec DL + + Mov DSPIRQValue, AL + ; OK.. now get IRQ, or set IRQ + Mov BX, IRQ + Cmp BX, 0FFFFh + JE DetectCardIRQ1 + Cmp Forced, 0 + JE DetectCardIRQ1 + + Mov AH, 11h + Cmp BL, 2 + JE SetCardIRQ1 + Cmp BL, 9 + JE SetCardIRQ1 + + Mov AH, 12h + Cmp BL, 5 + JE SetCardIRQ1 + + Mov AH, 14h + Cmp BL, 7 + JE SetCardIRQ1 + + Mov AH, 18h + Cmp BL, 10 + JE SetCardIRQ1 + + StC + Ret + +SetCardIRQ1: + Mov AL, 80h + Out DX, AL + Inc DL + Mov AL, AH + Out DX, AL + Dec DL + Jmp DetectCard6 + +DetectCardIRQ1: + Mov BX, 2 + Test AL, 1 + JNZ DetectCardIRQ2 + + Mov BL, 5 + Test AL, 2 + JNZ DetectCardIRQ2 + + Mov BL, 7 + Test AL, 4 + JNZ DetectCardIRQ2 + + Mov BL, 10 + Test AL, 8 + JNZ DetectCardIRQ2 + + StC + Ret + +DetectCardIRQ2: + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + + Cmp BX, IRQ + JE DetectCard6 + +DetectCardFailure: + StC + Ret + +DetectCardIRQ3: + Mov IRQ, BX + +DetectCard6: ; Detect DMA + Mov AL, 81h ; DMA select + Out DX, AL + Inc DL + In AL, DX ; AL = DMA + Dec DL + + Mov DSPDMAValue, AL + + Mov BX, DMA + Cmp BX, 0FFFFh + JE DetectCardDMA1 + Cmp Forced, 0 + JE DetectCardDMA1 + + Mov CL, 1 + Cmp BX, 1 + JB SetCardDMA1 + + Mov CL, 2 + JE SetCardDMA1 + + Cmp BX, 3 + JB DetectCard7 + + Mov CL, 8 + JE DetectCard7 + + Mov CL, 20h + Cmp BX, 5 + JB DetectCard7 + JE SetCardDMA1 + + Mov CL, 80h + Cmp BX, 7 + JA DetectCard7 + JE SetCardDMA1 + + Mov CL, 40h + +SetCardDMA1: + And AL, 0Bh + Test CL, 0Bh + JZ SetCardDMA4 + + Xor AL, AL + +SetCardDMA4: + Or CL, AL + + Mov AL, 81h + Out DX, AL + Inc DL + Mov AL, CL + Out DX, AL + Jmp DetectCard7 + +DetectCardDMA1: + Mov BX, 5 + Test AL, 20h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 40h + JNZ DetectCardDMA2 + + Inc BL + Test AL, 80h + JNZ DetectCardDMA2 + + Mov BL, 0 + Test AL, 1 + JNZ DetectCardDMA2 + + Inc BL + Test AL, 2 + JNZ DetectCardDMA2 + + Add BL, 2 + Test AL, 8 + JNZ DetectCardDMA2 + +DetectCard8: + Call ResetDSPIRQ + StC + Ret + +DetectCardDMA2: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + + Cmp BX, DMA + JNE DetectCard8 + +DetectCardDMA3: + Mov DMA, BX + +DetectCard7: + Mov EAX, 'Jeff' + + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +include mmxmsam.inc +include fourier.inc + +; + +Proc AckIRQ + Assume DS:Driver + + Mov AL, 20h + Cmp CS:IRQ, 7 + JBE AckIRQ1 + + Out 0A0h, AL + +AckIRQ1: + Out 20h, AL + Ret + +EndP AckIRQ + Assume DS:Nothing + +; + +Proc CheckMIDI + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Xor BX, BX + Mov DX, MIDIPort + + Mov BL, [MIDIBufferTail] + Test DX, DX + JZ CheckMIDIEnd + + Inc DX + Mov CX, 0FFFFh + +CheckMIDIAgain: + In AL, DX + + Test AL, 80h + LoopNZ CheckMIDIAgain + + Dec DX + In AL, DX + + Cmp AL, 0F0h + JAE CheckMIDIEnd + + Inc BL + Cmp BL, MIDIBufferHead + JE CheckMIDIEnd + + Mov [MIDIBuffer+BX], AL + Mov [MIDIBufferTail], BL +; Jmp CheckMIDIAgain + +CheckMIDIEnd: + Pop DS + Ret + +EndP CheckMIDI + Assume DS:Nothing + +; + +Proc SB16IRQHandler + + PushAD + Push DS + Push ES + + CLD + +SBIRQAgain: + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 4 ; Mixer Port + Mov AL, 82h + Out DX, AL + Inc DL ; DX = BasePort+5 + In AL, DX + + Test AL, 4 + JZ SBMIDIInterruptEnd + + Push AX + Call CheckMIDI + Pop AX + +SBMIDIInterruptEnd: + Test AL, 2 + JNZ SBDigitalInterrupt + + Call AckIRQ + Jmp SBIRQEnd + +SBDigitalInterrupt: + FNSave [FPSave] + + Mov DX, BasePort + Add DL, 0Fh + In AL, DX ; 16-bit IRQ ack. + + Call AckIRQ + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX +DMA16BITADJUST EQU $ + ShL BX, 1 + + Cmp BX, DMABUFFERLENGTH/2 + JB SB16IRQHandler2 + + Mov AX, DMABUFFERLENGTH/2 + +SB16IRQHandler2: + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Mov BX, DMASize ; BX = bytes required + Add DI, AX + ShR BX, 1 + ; BX = samples required + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SB16IRQHandler4 + Assume DS:Nothing + +SB16IRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + Call UpdateFourierBuffer + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +SB16IRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SB16IRQHandler5 + + Mov DX, MixTransferRemaining + +SB16IRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SB16IRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + FNRstor [CS:FPSave] + +SBIRQEnd: + Pop ES + Pop DS + PopAD + IRet + +EndP SB16IRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SB16IRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSB16 ; + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Cmp DX, 3 + JA StartSB16B + + Mov Word Ptr [DMA16BITADJUST], 9090h +StartSB16B: + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0B6h ; 16 bit, DAC + Call SBOut + Mov AL, Stereo + ShL AL, 5 + Or AL, 10h + Call SBOut + + Mov AX, DMASize + ShR AX, 1 + Dec AX + + Call SBOut ; DMALength, Lo + Mov AL, AH + Call SBOut + + Pop ES + Pop DS + PopA + + Ret + + Assume DS:Nothing + +EndP StartSB16 + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov DX, BasePort + Add DL, 4 + + Mov AL, 30h + Call SBGetRegister + ShR AL, 3 + Mov VolumeTable, AL + + Mov AL, 31h + Call SBGetRegister + ShR AL, 3 + Mov [VolumeTable+1], AL + + Mov AL, 44h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+2], AL + + Mov AL, 45h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+3], AL + + Mov AL, 46h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+4], AL + + Mov AL, 47h + Call SBGetRegister + ShR AL, 4 + Mov [VolumeTable+5], AL + + Call GetSBMixConst + + ; Parags to allocate = (8/(.4*31*16))*MixSpeed + ; = .04032258*MixSpeed = (65536*.04032258*MixSpeed) / 65536 + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 5+(DMABUFFERLENGTH*2)/16+(FOURIERBUFFERLENGTH*2)/16 + Mov BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SB16NoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Sub AX, (FOURIERBUFFERLENGTH*2)/16 + Mov FourierSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov DX, 330h + Call DetectUART + JC DetectMIDI1 + + Mov MIDIPort, 330h + Jmp DetectMIDIEnd + +DetectMIDI1: + Mov DX, 300h + Call DetectUART + JC DetectMIDIEnd + + Mov MIDIPort, 300h + +DetectMIDIEnd: + Call CalculateFilterCoefficients + + Mov SI, Offset SB16Msg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, BasePort + Call ResetDSP + + Call ResetUART + Call ResetIRQ + + ; Delay.. + Mov DX, BasePort + Add DL, 0Ch + + Mov CX, 1000 +ReInitSound1: + In AL, DX + Loop ReInitSound1 + + Call SetIRQ + Call ReinitUART + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Mov DS, Word Ptr [CS:DriverName+2] + Mov DX, Word Ptr [CS:DriverName] + + Mov AX, 3D02h ; Read write access + Int 21h + + Push CS + Pop DS + Assume DS:Driver + + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Mov DX, CS:BasePort + Add DL, 0Ch + + Mov AL, 0D9h + Call SBOut + + Call ResetUART + + Mov AX, BasePort + Call ResetDSP + + Call ResetDSPDMA + Call ResetDSPIRQ + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Push CS + Pop DS + Assume DS:Driver + +Poll1: + Call [UARTBufferEmpty] + JNC PollEnd + + Xor BX, BX + + ClI + + Mov BL, MIDIBufferHead + Cmp BL, MIDIBufferTail + JZ PollEnd ; Nothing in queue + + Inc BL + Mov AL, [MIDIBuffer+BX] + Mov MIDIBufferHead, BL + + Call [UARTSend] + Jmp Poll1 + +PollEnd: + StI + + Ret + +EndP Poll + Assume DS:Nothing + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Mov CS:Stereo, AL + Mov AX, CS:BasePort + Call ResetDSP + + Call StartSB16 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SB16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +TempVariable DW 0 +Const1 DD 3F800000h + +Proc GetFilterFrequency ; Given AL= Freq + Assume DS:Driver + + ShL AX, 8 + Mov TempVariable, AX + FILD TempVariable + + FMul FreqParameterMultiplier ; -i/(24*256) + FLd ST + FRndInt + FSub ST(1), ST + FXCh + F2XM1 + FLd1 + FAdd + FScale ; = 2^(i/24*256) + FMul FreqMultiplier ; = r + + FLd1 ; 1, c + FAdd ST, ST(1) ; 1+c, c + FDivR Const1 ; 1/(1+c), c + FSt DWord Ptr [SI] + FMul + FStP DWord Ptr [SI+4] + FStP ST + + Ret + +EndP GetFilterFrequency + Assume DS:Nothing + +; + +Const1On16 DD 3D000000h ; actually 1 on 32 + +Proc CalculateFilterCoefficients + Assume DS:Driver + + PushA + + FNInit + FLdCW NewControlWord + + Mov AL, [VolumeTable+6] + Mov SI, Offset FilterCoefficients + ShR AL, 1 + Call GetFilterFrequency + + Mov AL, [VolumeTable+7] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + + Mov AL, [VolumeTable+8] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + + Mov AL, [VolumeTable+9] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + +; Now volumes + Mov SI, Offset VolumeTable+10 + Mov DI, Offset FilterVolumes + Xor AX, AX + Mov CX, 4 + +FilterVolumeLoop1: + LodSB + Mov TempVariable, AX + FILD TempVariable + FMul Const1On16 + FStP DWord Ptr [DI] + + Add DI, 4 + Loop FilterVolumeLoop1 + + PopA + Ret + +EndP CalculateFilterCoefficients + Assume DS:Nothing + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Cmp DI, 9 + JA SetVariable3 + + Cmp DI, 6 + JB SetVariable1 + + JE SetVariable2 + + Cmp AL, [VolumeTable+DI-1] + JAE SetVariable2 + + Mov AL, [VolumeTable+DI-1] + Mov [VolumeTable+DI], AL + +SetVariable2: + Cmp DI, 9 + JAE SetVariable3 + + Cmp AL, [VolumeTable+DI+1] + JBE SetVariable3 + + Mov AL, [VolumeTable+DI+1] + Mov [VolumeTable+DI], AL + +SetVariable3: + Call CalculateFilterCoefficients + Jmp SetVariableEnd + +SetVariable1: + Mov DX, BasePort + Add DL, 4 + Mov AL, 30h + Mov AH, [VolumeTable] + ShL AH, 3 + Out DX, AX + + Mov AL, 31h + Mov AH, [VolumeTable+1] + ShL AH, 3 + Out DX, AX + + Mov AL, 44h + Mov AH, [VolumeTable+2] + ShL AH, 4 + Out DX, AX + + Mov AL, 45h + Mov AH, [VolumeTable+3] + ShL AH, 4 + Out DX, AX + + Mov AL, 46h + Mov AH, [VolumeTable+4] + ShL AH, 4 + Out DX, AX + + Mov AL, 47h + Mov AH, [VolumeTable+5] + ShL AH, 4 + Out DX, AX + +SetVariableEnd: + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +Proc UARTOut + + Push CX + Push DX + Mov DX, CS:MIDIPort + Test DX, DX + JZ UARTOutEnd + + Push AX + Xor CX, CX + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + LoopNZ UARTOut1 + + Pop AX + JNZ UARTOutEnd + + Dec DX + Out DX, AL + +UARTOutEnd: + Pop DX + Pop CX + + Ret + +EndP UARTOut + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +Proc GetWaveForm Far ; Given ES:DI = destination + Assume DS:Nothing ; want 2048 samples. + + PushA + Push DS + + Mov DS, FourierSegment + Mov SI, FourierBufferStart + Mov CX, 2048 + +GetWaveForm1: + MovsW + And SI, (FOURIERBUFFERLENGTH*2)-1 + Loop GetWaveForm1 + + Pop DS + PopA + + Ret + +EndP GetWaveForm + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 + DW 7 ; MIDI, hiqual + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + + DW Offset SendUARTOut + + DW Offset GetWaveform + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SB2DRV.ASM b/it/SoundDrivers/SB2DRV.ASM new file mode 100755 index 0000000..fdf6f06 --- /dev/null +++ b/it/SoundDrivers/SB2DRV.ASM @@ -0,0 +1,1421 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 0 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 16 ; 16 bit mixing for the SB Pro +MIXTABLESIZE EQU 2*256*65 + +SBProMsg DB "Sound Blaster 2 detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SBProNoMemoryMsg DB "Sound Blaster 2 detected", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITSB2.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITSB2.DRV", 0 + +BLASTERString DB "BLASTER" +DriverName DB "ITSB2.DRV", 0 + +BlasterEnvironment Label DWord +BlasterOffset DW 0 +BlasterSegment DW 0 + +DSPVersion DW 0 +Forced DB 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 4 +MixModeOffset DW 0 +DMASize DW 1024 + +MixLength DW 0 + +IMR DW 0 +OldIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SBProScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SB16HeaderLine + DW Near Ptr DriverText + + DW Near Ptr MixModeHeader + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; 7 + + DW 0 + +MixModeHeader DW 1 + DB 3, 14 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 43478 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 5, 16, 34, 18, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 120 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 5, 19, 34, 21, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +SB16HeaderLine DW 10 + DB "Sound Blaster 2 Driver", 0 + +DriverText DW 1 + DB 32, 48 + DB 21h + DB "Sound Blaster 2 Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include mono12b.mix +include mono12bi.mix + +MixFunctionTables Label + +include mono12b.inc ; contains the tables +include mono12bi.inc + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixModeOffset + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixModeOffset, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixModeOffset + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 43478 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp AH, 2 ; SB DSP = 2.00+ + JAE DetectCard5 + +DetectCard4: + StC + Ret + +DetectCard5: + Mov DSPVersion, AX + + ; Need to detect IRQ/DMA... + + Mov SI, Offset BLASTERString + Mov CX, 7 + Call GetEnvironment ; Returns ES:DI, Carry if error + JC DetectCardError + + Mov BlasterOffset, DI + Mov BlasterSegment, ES + + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + Cmp Forced, 0 + JNE DetectCardIRQDone + Jmp DetectCardError + +DetectCardIRQ3: + Push DS + Push SI + + LDS SI, BlasterEnvironment + + Xor DX, DX ; DX = env.. + +DetectCardIRQ1: + LodsB + And AL, AL + JZ DetectCardError + Cmp AL, 'i' + JE DetectCardIRQ2 + Cmp AL, 'I' + JE DetectCardIRQ2 + Jmp DetectCardIRQ1 + +DetectCardIRQ2: + LodsB + And AL, AL + JZ DetectCardIRQEnd + Cmp AL, ' ' + JE DetectCardIRQEnd + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCardIRQ2 + +DetectCardIRQEnd: + Pop SI + Pop DS + + Mov IRQ, DX + +DetectCardIRQDone: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + Cmp Forced, 0 + JNE DetectCardDMADone + Jmp DetectCardError + +DetectCardDMA3: + Push DS + Push SI + + LDS SI, BlasterEnvironment + + Xor DX, DX ; DX = env.. + +DetectCardDMA1: + LodsB + And AL, AL + JZ DetectCardError + Cmp AL, 'd' + JE DetectCardDMA2 + Cmp AL, 'D' + JE DetectCardDMA2 + Jmp DetectCardDMA1 + +DetectCardDMA2: + LodsB + And AL, AL + JZ DetectCardDMAEnd + Cmp AL, ' ' + JE DetectCardDMAEnd + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCardDMA2 + +DetectCardDMAEnd: + Pop SI + Pop DS + + Mov DMA, DX + +DetectCardDMADone: + Mov EAX, 'Jeff' + + ClC + Ret + +DetectCardError: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Mov AX, 2020h + + Mov BX, CX ; BX = bytes to mix + Mov DX, CX + +; Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + Rep StosW ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + Jmp MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + +Mix0Mode: ; 16-bit mixing, no interpolation, no ramping +Mix0ModeMono: + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AX, 30 ; Use left only-mixing for mono + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 60 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, MixTransferRemaining + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc SBProIRQHandler + + PushAD + Push DS + Push ES + + CLD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 0Eh + In AL, DX ; 8-bit IRQ ack. + + Mov AL, 20h + Cmp IRQ, 7 + JBE SBProIRQHandler1 + + Out 0A0h, AL + +SBProIRQHandler1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB SBProIRQHandler2 + + Xor AX, AX + Xor BX, BX + +SBProIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SBProIRQHandler4 + Assume DS:Nothing + +SBProIRQHandler3: + Push BX + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BX + +SBProIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SBProIRQHandler5 + + Mov DX, MixTransferRemaining + +SBProIRQHandler5: + Push DX + +SBProIRQHandler6: + Mov AX, [SI] + SAR AX, 6 + + Test AH, AH + JNZ SBProIRQHandlerClip1 + +SBProIRQHandler7: + StosB ; } Memory write + + Add SI, 2 + Dec DX + JNZ SBProIRQHandler6 + + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SBProIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +SBProIRQHandlerClip1: + Mov AL, 00h + JS SBProIRQHandler7 + Mov AL, 0FFh + Jmp SBProIRQHandler7 + +EndP SBProIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SBProIRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSBPro ; + + PushA + Push ES + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 48h ; Set DMA Size.. + Call SBOut + Mov AX, DMASize + Dec AX + Call SBOut + Mov AL, AH + Call SBOut + + Mov AL, 1Ch + Cmp MixSpeed, 21739 + JBE StartSBPro1 + + Mov AL, 90h + +StartSBPro1: + Call SBOut + + Pop ES + PopA + + Ret + + Assume DS:Nothing + +EndP StartSBPro + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, DS + Mov DriverSegment1, AX + Mov DriverSegment2, AX + Mov DriverSegment3, AX + Mov DriverSegment4, AX + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetSBMixConst + + ; Parags to allocate = (2/(.4*31*16))*MixSpeed + 2080 + ; = 661*MixSpeed/65536 + + Mov AX, 661 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SBProNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + Call StartSBPro + + Mov SI, Offset SBProMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AX, CS:BasePort + Call ResetDSP + Call StartSBPro + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov AX, BasePort + Call ResetDSP + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SBProScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SBDRV.ASM b/it/SoundDrivers/SBDRV.ASM new file mode 100755 index 0000000..3bf7123 --- /dev/null +++ b/it/SoundDrivers/SBDRV.ASM @@ -0,0 +1,1416 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 0 +DMABUFFERLENGTH EQU 1024 +MIXRESOLUTION EQU 16 ; 16 bit mixing for the SB Pro +MIXTABLESIZE EQU 2*256*65 + +SBProMsg DB "Sound Blaster detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SBProNoMemoryMsg DB "Sound Blaster detected", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITSB.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITSB.DRV", 0 + +BLASTERString DB "BLASTER" +DriverName DB "ITSB.DRV", 0 + +BlasterEnvironment Label DWord +BlasterOffset DW 0 +BlasterSegment DW 0 + +Forced DB 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 4 +MixModeOffset DW 0 +DMASize DW 512 + +MixLength DW 0 + +IMR DW 0 +OldIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SBProScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SB16HeaderLine + DW Near Ptr DriverText + + DW Near Ptr MixModeHeader + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; 7 + + DW 0 + +MixModeHeader DW 1 + DB 3, 14 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 21739 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 5, 16, 34, 18, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 120 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 5, 19, 34, 21, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +SB16HeaderLine DW 10 + DB "Sound Blaster Driver", 0 + +DriverText DW 1 + DB 34, 48 + DB 21h + DB "Sound Blaster Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include mono12b.mix +include mono12bi.mix + +MixFunctionTables Label + +include mono12b.inc ; contains the tables +include mono12bi.inc + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixModeOffset + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixModeOffset, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixModeOffset + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 21739 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 290h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard2 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov SI, Offset BLASTERString + Mov CX, 7 + Call GetEnvironment ; Returns ES:DI, Carry if error + JC DetectCardDefault + + Mov BlasterOffset, DI + Mov BlasterSegment, ES + + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + Cmp Forced, 0 + JNE DetectCardIRQDone + Jmp DetectCardError + +DetectCardIRQ3: + Push DS + Push SI + + LDS SI, BlasterEnvironment + + Xor DX, DX ; DX = env.. + +DetectCardIRQ1: + LodsB + And AL, AL + JZ DetectCardError + Cmp AL, 'i' + JE DetectCardIRQ2 + Cmp AL, 'I' + JE DetectCardIRQ2 + Jmp DetectCardIRQ1 + +DetectCardIRQ2: + LodsB + And AL, AL + JZ DetectCardIRQEnd + Cmp AL, ' ' + JE DetectCardIRQEnd + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCardIRQ2 + +DetectCardIRQEnd: + Pop SI + Pop DS + + Mov IRQ, DX + +DetectCardIRQDone: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + Cmp Forced, 0 + JNE DetectCardDMADone + Jmp DetectCardError + +DetectCardDMA3: + Push DS + Push SI + + LDS SI, BlasterEnvironment + + Xor DX, DX ; DX = env.. + +DetectCardDMA1: + LodsB + And AL, AL + JZ DetectCardError + Cmp AL, 'd' + JE DetectCardDMA2 + Cmp AL, 'D' + JE DetectCardDMA2 + Jmp DetectCardDMA1 + +DetectCardDMA2: + LodsB + And AL, AL + JZ DetectCardDMAEnd + Cmp AL, ' ' + JE DetectCardDMAEnd + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCardDMA2 + +DetectCardDMAEnd: + Pop SI + Pop DS + + Mov DMA, DX + +DetectCardDMADone: + Mov EAX, 'Jeff' + + ClC + Ret + +DetectCardDefault: + Cmp IRQ, 0FFFFh + JNE DetectCardDefaultDMA + Mov IRQ, 7 + +DetectCardDefaultDMA: + Cmp DMA, 0FFFFh + JNE DetectCardDefaultEnd + Mov DMA, 1 + +DetectCardDefaultEnd: + Mov EAX, 'Jeff' + + ClC + Ret + +DetectCardError: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Mov AX, 2020h + + Mov BX, CX ; BX = bytes to mix + Mov DX, CX + +; Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + Rep StosW ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + Jmp MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + +Mix0Mode: ; 16-bit mixing, no interpolation, no ramping +Mix0ModeMono: + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AX, 30 ; Use left only-mixing for mono + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 60 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, MixTransferRemaining + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc SBProIRQHandler + + PushAD + Push DS + Push ES + + CLD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 0Eh + In AL, DX ; 8-bit IRQ ack. + + Add DL, 0Ch-0Eh + + Mov AL, 14h ; Start output + Call SBOut + Mov AX, DMASize + Dec AX + Call SBOut + Mov AL, AH + Call SBOut + + Mov AL, 20h + Cmp IRQ, 7 + JBE SBProIRQHandler1 + + Out 0A0h, AL + +SBProIRQHandler1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB SBProIRQHandler2 + + Xor AX, AX + Xor BX, BX + +SBProIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SBProIRQHandler4 + Assume DS:Nothing + +SBProIRQHandler3: + Push BX + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BX + +SBProIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SBProIRQHandler5 + + Mov DX, MixTransferRemaining + +SBProIRQHandler5: + Push DX + +SBProIRQHandler6: + Mov AX, [SI] + SAR AX, 6 + + Test AH, AH + JNZ SBProIRQHandlerClip1 + +SBProIRQHandler7: + StosB ; } Memory write + + Add SI, 2 + Dec DX + JNZ SBProIRQHandler6 + + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SBProIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +SBProIRQHandlerClip1: + Mov AL, 00h + JS SBProIRQHandler7 + Mov AL, 0FFh + Jmp SBProIRQHandler7 + +EndP SBProIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SBProIRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSBPro ; + + PushA + Push ES + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 14h ; Start output + Call SBOut + Mov AX, DMASize + Dec AX + Call SBOut + Mov AL, AH + Call SBOut + + Pop ES + PopA + + Ret + + Assume DS:Nothing + +EndP StartSBPro + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, DS + Mov DriverSegment1, AX + Mov DriverSegment2, AX + Mov DriverSegment3, AX + Mov DriverSegment4, AX + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetSBMixConst + + ; Parags to allocate = (2/(.4*31*16))*MixSpeed + 2080 + ; = 661*MixSpeed/65536 + + Mov AX, 661 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SBProNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + Call StartSBPro + + Mov SI, Offset SBProMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AX, CS:BasePort + Call ResetDSP + Call StartSBPro + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov AX, BasePort + Call ResetDSP + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SBProScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SBMIDI.INC b/it/SoundDrivers/SBMIDI.INC new file mode 100755 index 0000000..0b1f523 --- /dev/null +++ b/it/SoundDrivers/SBMIDI.INC @@ -0,0 +1,133 @@ + +;Ŀ +; Variables +; + +MIDIPort DW 300h + +;Ŀ +; Functions +; + +Proc Poll Far + + Mov DX, [CS:MIDIPort] + Test DX, DX + JZ PollEnd + + Call [CS:UARTBufferEmpty] + JNC PollEnd + + Inc DX + In AL, DX + Test AL, 80h + JNZ PollEnd + + Dec DX + In AL, DX + Cmp AL, 0F8h + JAE PollEnd + + Call [CS:UARTSend] + +PollEnd: + Ret + +EndP Poll + +; + +Proc MIDI_UnInit + + Ret + + Mov DX, MIDIPort + Test DX, DX + JZ UnInitUARTEnd + + Inc DX + + Mov AL, 0FFh + Out DX, AL + +UnInitUARTEnd: + Ret + +EndP MIDI_UnInit + +; + +Proc InitUART + ; returns carry set if no UART + + Mov BX, 32 ; Number of attempts to read correct + ; value back from the UART + + Inc DX + Mov AL, 0FFh + Out DX, AL ; Reset UART + + Mov AL, 03Fh + Out DX, AL ; UART Mode + + Mov CX, 0FFFFh + +InitUART1: + In AL, DX + Test AL, 80h + LoopNZ InitUART1 + +InitUART2: + StC + JNZ InitUART3 + + Dec DX + In AL, DX + Cmp AL, 0FEh + JE InitUART3 + + Inc DX + Dec BX + JNZ InitUART1 + + StC + +InitUART3: + Ret + +EndP InitUART + +; + +Proc MIDI_Init + + Mov DX, 301h + Mov AL, 0FFh + Out DX, AL + + Mov AL, 3Fh + Out DX, AL + Ret + + Mov DX, 330h + Call InitUART + + JC MIDI_Init1 + + Mov [CS:MIDIPort], 330h + Jmp MIDI_InitEnd + +MIDI_Init1: + Mov DX, 300h + Call InitUART + JC MIDI_InitEnd + + Mov [CS:MIDIPort], 300h + +MIDI_InitEnd: + Ret + +EndP MIDI_Init + Assume DS:Nothing + +; diff --git a/it/SoundDrivers/SBPRODRV.ASM b/it/SoundDrivers/SBPRODRV.ASM new file mode 100755 index 0000000..b4119b8 --- /dev/null +++ b/it/SoundDrivers/SBPRODRV.ASM @@ -0,0 +1,2009 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 4096 +MIXRESOLUTION EQU 16 ; 16 bit mixing for the SB Pro +MIXTABLESIZE EQU 2*256*65 + +SBProMsg DB "Sound Blaster Pro detected", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +SBProNoMemoryMsg DB "Sound Blaster Pro detected", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Blaster Pro reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITSBPRO.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITSBPRO.DRV", 0 + +BLASTERString DB "BLASTER" +DriverName DB "ITSBPRO.DRV", 0 + +BlasterEnvironment Label DWord +BlasterOffset DW 0 +BlasterSegment DW 0 + +MixSpeed DW 43478 + +DSPVersion DW 0 +Forced DB 0 +Stereo DB 0 + +BytesToMix DW 1000 +SBMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 +DMASize DW 1024 + +MixLength DW 0 + +IMR DW 0 +OldIRQHandler DD 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + + +;********************************** + +SBProScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr SBProHeaderLine + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 6 + DW Near Ptr MasterVolumeRight ; 7 + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 + DW Near Ptr MixModeButton2 + + DW 0 + +SBProHeaderLine DW 10 + DB "Sound Blaster Pro Driver", 0 + +DriverText DW 1 + DB 30, 48 + DB 21h + DB "Sound Blaster Pro Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 27, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 31 + DW 9, 0 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 31 + DW 9, 1 + DW 6, 9, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +Frequency DW 0 + +MixModeButton1 DW 2 + DW 7, 10, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 5, 19, 34, 21, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 9, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 5, 22, 34, 24, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +VolumeTable DB 6 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc + +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SBOut ; AL = data + ; DX = 2xCh + + Push AX + +SBOut1: + In AL, DX + Test AL, AL + JS SBOut1 + + Pop AX + Out DX, AL + + Ret + +EndP SBOut + +; + +Proc SBIn ; DX = 2xEh, returns AL + +SBIn1: + In AL, DX + Test AL, AL + JNS SBIn1 + + Add DL, 0Ah-0Eh ; DX = 2xAh -> Data read port + In AL, DX + Add DL, 0Eh-0Ah + + Ret + +EndP SBIn + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc SBGetRegister + + Out DX, AL + Inc DX + In AL, DX + Dec DX + + Ret + +EndP SBGetRegister + +; + +Proc GetSBMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetSBMixConst1 + + Mov CX, 43478 + Cmp AX, CX + JA GetSBMixConst1 + + Mov CX, 12000 + Cmp AX, CX + JB GetSBMixConst1 + + Mov CX, AX + +GetSBMixConst1: + Mov AX, 1000 + Mul AX + Div CX + Mov AH, AL + Neg AH + Mov SBMixConst, AH + + MovZX BX, AL + Mov AX, 1000 + Mul AX + Div BX + Mov MixSpeed, AX + + Pop DS + PopA + Ret + +EndP GetSBMixConst + Assume DS:Nothing + +; + +Proc ResetDSP Far ; AX = Port + + Push AX + Push CX + Push DX + + Mov DX, AX + Add DL, 6 + Mov AL, 1 + Out DX, AL + + In AL, DX + In AL, DX + In AL, DX + In AL, DX + + Xor AL, AL + Out DX, AL + + Add DL, 8 + Mov CX, 200 + +ResetDSP1: + In AL, DX + Test AL, AL + JS ResetDSP2 + Loop ResetDSP1 + Jmp ResetDSP3 + +ResetDSP2: + Sub DL, 4 + In AL, DX + Cmp AL, 0AAh + JE ResetDSP4 + Add DL, 4 + Loop ResetDSP1 + +ResetDSP3: + StC + +ResetDSP4: + Pop DX + Pop CX + Pop AX + Ret + +EndP ResetDSP + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Forced, AL + + Mov AX, BasePort + Cmp AX, 0FFFFh + JE DetectCard1 + + Cmp AX, 210h + JB DetectCard9 + Cmp AX, 280h + JA DetectCard9 + + Call ResetDSP + JNC DetectCard3 + + Ret + +DetectCard1: + Mov AX, 210h + +DetectCard2: + Call ResetDSP + JNC DetectCard3 + Add AL, 10h + Cmp AL, 80h + JBE DetectCard2 + +DetectCard9: + StC + Ret + +DetectCard3: ; OK... DSP found. + ; Get DSP version + Mov BasePort, AX + + Mov DX, AX + Add DL, 0Ch ; 2xCh -> Data ready to send... + +DetectCardOuputLoop1: + In AL, DX + Test AL, AL + JS DetectCardOuputLoop1 + + Mov AL, 0E1h ; Get DSP version command + Out DX, AL + + Add DL, 0Eh-0Ch ; DX = 2xEh -> Data available status + + Call SBIn + Mov AH, AL ; AH = Major version number + Call SBIn ; AL = Minor version number + + Cmp Forced, 0 + JNE DetectCard5 + Cmp AH, 3 ; SB DSP = 3.00+ + JAE DetectCard5 + +DetectCard4: + StC + Ret + +DetectCard5: + Mov DSPVersion, AX + + ; Need to detect IRQ/DMA... + + Mov SI, Offset BLASTERString + Mov CX, 7 + Call GetEnvironment ; Returns ES:DI, Carry if error + JC DetectCardNoEnvironment + + Mov BlasterOffset, DI + Mov BlasterSegment, ES + + Cmp IRQ, 0FFFFh + JE DetectCardIRQ3 + Cmp Forced, 0 + JNE DetectCardIRQDone + Jmp DetectCardError + +DetectCardIRQ3: + Push DS + Push SI + + LDS SI, BlasterEnvironment + + Xor DX, DX ; DX = env.. + +DetectCardIRQ1: + LodsB + And AL, AL + JZ DetectCardError + Cmp AL, 'i' + JE DetectCardIRQ2 + Cmp AL, 'I' + JE DetectCardIRQ2 + Jmp DetectCardIRQ1 + +DetectCardIRQ2: + LodsB + And AL, AL + JZ DetectCardIRQEnd + Cmp AL, ' ' + JE DetectCardIRQEnd + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCardIRQ2 + +DetectCardIRQEnd: + Pop SI + Pop DS + + Mov IRQ, DX + +DetectCardIRQDone: + Cmp DMA, 0FFFFh + JE DetectCardDMA3 + Cmp Forced, 0 + JNE DetectCardDMADone + Jmp DetectCardError + +DetectCardDMA3: + Push DS + Push SI + + LDS SI, BlasterEnvironment + + Xor DX, DX ; DX = env.. + +DetectCardDMA1: + LodsB + And AL, AL + JZ DetectCardError + Cmp AL, 'd' + JE DetectCardDMA2 + Cmp AL, 'D' + JE DetectCardDMA2 + Jmp DetectCardDMA1 + +DetectCardDMA2: + LodsB + And AL, AL + JZ DetectCardDMAEnd + Cmp AL, ' ' + JE DetectCardDMAEnd + Sub AL, '0' + JC DetectCardError + Cmp AL, 9 + JA DetectCardError + + IMul DX, 10 + Add DL, AL + Jmp DetectCardDMA2 + +DetectCardDMAEnd: + Pop SI + Pop DS + + Mov DMA, DX + +DetectCardDMADone: + Mov EAX, 'Jeff' + + ClC + Ret + +DetectCardNoEnvironment: + Cmp DMA, 0FFFFh + JE DetectCardError + Cmp IRQ, 0FFFFh + JNE DetectCardDMADone + +DetectCardError: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Mov AX, 2020h + + Mov BX, CX ; BX = bytes to mix + Mov DX, CX + + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + Cmp CS:Stereo, 0 + JE MixSamples1 + + Mov AX, 1010h + And DX, Not 1 + ShR BX, 1 + ShR CX, 1 + Inc CX + +MixSamples1: + Rep StosW ; } Memory write + Mov MixTransferRemaining, DX ; } + Mov MixLength, BX + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Cmp MixMode, 4 ; Is it volume ramping? + JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Cmp CS:Stereo, 0 + JE MixSampleFreqNoStereo + + ShL EAX, 1 + +MixSampleFreqNoStereo: + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation, no ramping +Mix0ModeMono: + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AX, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AX, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AX, 60 + Test CH, CH + JZ MixModeCommon + + Mov AX, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AX, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AX, 150 ; Surround + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, MixLength + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc SBProIRQHandler + + PushAD + Push DS + Push ES + + CLD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 0Eh + In AL, DX ; 8-bit IRQ ack. + + Mov AL, 20h + Cmp IRQ, 7 + JBE SBProIRQHandler1 + + Out 0A0h, AL + +SBProIRQHandler1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB SBProIRQHandler2 + + Xor AX, AX + Xor BX, BX + +SBProIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + + ; BX = samples required + Mov BP, 4 ; Skip for mono + Mov CL, 6 ; Shift for mono + + Cmp Stereo, 0 + JE SBProIRQHandlerMono + + Mov BP, 2 ; Stereo skip value. + Dec CL + +SBProIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SBProIRQHandler4 + Assume DS:Nothing + +SBProIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +SBProIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SBProIRQHandler5 + + Mov DX, MixTransferRemaining + +SBProIRQHandler5: + Push DX + +SBProIRQHandler6: + Mov AX, [SI] + SAR AX, CL + + Test AH, AH + JNZ SBProIRQHandlerClip1 + +SBProIRQHandler7: + StosB ; } Memory write + + Add SI, BP + Dec DX + JNZ SBProIRQHandler6 + + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SBProIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +SBProIRQHandlerClip1: + Mov AL, 00h + JS SBProIRQHandler7 + Mov AL, 0FFh + Jmp SBProIRQHandler7 + + Comment ~ + +Proc SBProIRQHandler + + PushAD + Push DS + Push ES + + CLD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, BasePort + Add DL, 0Fh + In AL, DX ; 16-bit IRQ ack. + + Mov AL, 20h + Cmp IRQ, 7 + JBE SBProIRQHandler1 + + Out 0A0h, AL + +SBProIRQHandler1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB SBProIRQHandler2 + + Xor AX, AX + Xor BX, BX + +SBProIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 4 ; Skip for mono + Mov CL, 6 ; Shift for mono + + Cmp Stereo, 0 + JE SBProIRQHandlerMono + + Mov BP, 2 ; Stereo skip value. + Dec CL + +SBProIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE SBProIRQHandler4 + Assume DS:Nothing + +SBProIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +SBProIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE SBProIRQHandler5 + + Mov DX, MixTransferRemaining + +SBProIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB SBProIRQHandler6 + JE SBProIRQHFilter + + Cmp CS:Stereo, 0 + JE SBProIRQ3QFilterMono + +SBProIRQ3QFilterStereo: + Push BX + + Mov BX, FilterValue + Mov BP, FilterValue2 + ShR DX, 1 + +SBProIRQ3QFilterStereo1: + Mov AX, BX + Mov CX, BP + Add AX, [SI] + Add CX, [SI+2] + SAR AX, 1 + SAR CX, 1 + Add BX, AX + Add BP, CX + SAR BX, 1 + SAR BP, 1 + + Mov AX, BX + SAR AX, 5 + + Test AH, AH + ;...... + +SBProIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL SBPro3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG SBPro3QFilterStereoClip4 + +SBProIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ SBProIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp SBProMixTransferEnd + +SBProIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +SBProIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL SBPro3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG SBPro3QFilterMonoClip2 + +SBProIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ SBProIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp SBProMixTransferEnd + +SBProIRQHFilter: + Cmp CS:Stereo, 0 + JE SBProIRQHFilterMono + +SBProIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +SBProIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL SBProHFilterStereoClip1 + Cmp EAX, 7FFFh + JG SBProHFilterStereoClip2 + +SBProIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL SBProHFilterStereoClip3 + Cmp EAX, 7FFFh + JG SBProHFilterStereoClip4 + +SBProIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ SBProIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp SBProMixTransferEnd + +SBProIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +SBProIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL SBProHFilterMonoClip1 + Cmp EAX, 7FFFh + JG SBProHFilterMonoClip2 + +SBProIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ SBProIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp SBProMixTransferEnd + +SBProIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL SBProIRQHandlerClip1 + Cmp EAX, 7FFFh + JG SBProIRQHandlerClip2 + +SBProIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ SBProIRQHandler6 + +SBProMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ SBProIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +SBProIRQHandlerClip1: + Mov AL, 80h + Jmp SBProIRQHandler7 + +SBProIRQHandlerClip2: + Mov AL, 7Fh + Jmp SBProIRQHandler7 + +SBProHFilterMonoClip1: + Mov AL, 80h + Jmp SBProIRQHFilterMono2 + +SBProHFilterMonoClip2: + Mov AL, 7Fh + Jmp SBProIRQHFilterMono2 + +SBProHFilterStereoClip1: + Mov AL, 80h + Jmp SBProIRQHFilterStereo2 + +SBProHFilterStereoClip2: + Mov AL, 7Fh + Jmp SBProIRQHFilterStereo2 + +SBProHFilterStereoClip3: + Mov AL, 80h + Jmp SBProIRQHFilterStereo3 + +SBProHFilterStereoClip4: + Mov AL, 7Fh + Jmp SBProIRQHFilterStereo3 + +SBPro3QFilterMonoClip1: + Mov AL, 80h + Jmp SBProIRQ3QFilterMono2 + +SBPro3QFilterMonoClip2: + Mov AL, 7Fh + Jmp SBProIRQ3QFilterMono2 + +SBPro3QFilterStereoClip1: + Mov AL, 80h + Jmp SBProIRQ3QFilterStereo2 + +SBPro3QFilterStereoClip2: + Mov AL, 7Fh + Jmp SBProIRQ3QFilterStereo2 + +SBPro3QFilterStereoClip3: + Mov AL, 80h + Jmp SBProIRQ3QFilterStereo3 + +SBPro3QFilterStereoClip4: + Mov AL, 7Fh + Jmp SBProIRQ3QFilterStereo3 + +EndP SBProIRQHandler + Assume DS:Nothing + + ~ + +EndP SBProIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset SBProIRQHandler + + XChg [ES:BX], EAX + Mov OldIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + Pop DS + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldIRQHandler + Mov [ES:BX], EAX + + Pop ES + Pop DS + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StartSBPro ; + + PushA + Push ES + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Add DL, 0Ch + + Mov AL, 40h ; time constant + Call SBOut + Mov AL, SBMixConst + Call SBOut + + Mov AL, 0D1h ; turn on speaker + Call SBOut + + Mov AL, 48h ; Set DMA Size.. + Call SBOut + Mov AX, DMASize + Dec AX + Call SBOut + Mov AL, AH + Call SBOut + + Mov AL, 1Ch + Cmp MixSpeed, 21739 + JBE StartSBPro1 + + Mov AL, 90h + +StartSBPro1: + Call SBOut + + Pop ES + PopA + + Ret + + Assume DS:Nothing + +EndP StartSBPro + +; + +Proc GetMixerRegisters + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Pop DS + + Ret + +EndP GetMixerRegisters + Assume DS:Nothing + +; + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, DS + Mov DriverSegment1, AX + Mov DriverSegment2, AX + Mov DriverSegment3, AX + Mov DriverSegment4, AX + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov DX, BasePort + Add DL, 4 + + Mov AL, 22h + Call SBGetRegister + Mov AH, AL + And AX, 0FF0h + ShR AL, 4 + ShL AX, 1 + Mov Word Ptr [VolumeTable], AX + + Call GetSBMixConst + + ; Parags to allocate = (4/(.4*31*16))*MixSpeed + 2080 + ; = 661*MixSpeed/65536 + + Mov AX, 1322 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset SBProNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + Call StartSBPro + + Mov SI, Offset SBProMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AX, CS:BasePort + Call ResetDSP + Call StartSBPro + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov AX, BasePort + Call ResetDSP + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + PushA + Mov CX, MixSpeed + + Mov Stereo, AL + Mov AH, AL + + Mov DX, BasePort + Add DL, 4 + + Mov AL, 0Eh ; Stereo register + Out DX, AL + Inc DX + In AL, DX + + Test AH, AH + JZ SBProSetStereo1 + ; Turn on stereo + + ShR CX, 1 + Or AL, 2 + + Jmp SBProSetStereo2 + +SBProSetStereo1: ; Turn off stereo + + And AL, NOT 2 + +SBProSetStereo2: + Mov Frequency, CX + + ClI + + Out DX, AL + Call RecalculateAllFrequencies + + StI + + PopA + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset SBProScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far ; Returns AX, given DI + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far ; Given AX, DI + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DL, 4 + Mov AX, Word Ptr [VolumeTable] + + ShL AL, 3 + ShR AH, 1 + And AX, 0FF0h + Or AH, AL + Or AH, 11h + Mov AL, 22h + Out DX, AX + + Pop DX + Pop DS + Ret + +EndP SetVariable + Assume DS:Nothing + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/SNDDRV.ASM b/it/SoundDrivers/SNDDRV.ASM new file mode 100755 index 0000000..19549fe --- /dev/null +++ b/it/SoundDrivers/SNDDRV.ASM @@ -0,0 +1,283 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +; EmptyFunction + +Proc EmptyFunction Far + + Xor AX, AX + StC + Ret + +EndP EmptyFunction + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + StC + Ret + +EndP DetectCard + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + StC + Ret + +EndP InitSound + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load (0 based) +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release (1 based) +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Xor AX, AX + StC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 32 + + DW 5 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/ST97.ASM b/it/SoundDrivers/ST97.ASM new file mode 100755 index 0000000..e6a5c73 --- /dev/null +++ b/it/SoundDrivers/ST97.ASM @@ -0,0 +1,866 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;*********************************************** + +PNPSERIALID EQU 0FFFFFFFFh +PNPVENDORID EQU 80719304h + +MMT_MAXENTRIES EQU 64 +MMT_MAXSIZE EQU 3*MMT_MAXENTRIES + +ST97Message DB "Sound Track 97 PnP Detected", 13 +; DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, ", 0FDh, "Dk RAM", 0 + DB "Port ", 0FDh, "Xh, ", 0FDh, "D Voices, ", 0FDh, "Dk", 0 + +StatusLine DB "FreeST ", 0FDh, "Dk", 0 + +MMTData DW MMT_MAXSIZE Dup (0) + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +; EmptyFunction + +Proc EmptyFunction Far + + Xor AX, AX + StC + Ret + +EndP EmptyFunction + +; ST97InString + +Proc ST97InString ; ES:DI points to deposit point. + ; EAX = memory address + ; CX = count + + ClI + + Mov BL, 2 ; Ctrl=RD_MEM, Data=Memory Address + Call ST97OutDWord + + Mov DX, CS:BasePort ; Length + Mov AX, CX + Call ST97SendByte + + Mov AL, AH + Call ST97SendByte + +ST97InString1: + Call ST97InByte + Cmp AL, 0ABh + JE ST97InStringError + Cmp AL, 0ACh + JNE ST97InString1 + +ST97InString2: + Inc DX + Inc DX + + Rep InsW + + ClC + StI + Ret + +ST97InStringError: + StC + StI + Ret + +EndP ST97InString + +; ST97ReceiveByte + +Proc ST97ReceiveByte ; Returns AL + + Push DX + Mov DX, CS:BasePort + Inc DX + +ST97ReceiveByte1: + In AL, DX + Test AL, AL + JS ST97ReceiveByte1 + + Dec DX + In AL, DX + Pop DX + + Ret + +EndP ST97ReceiveByte + +; ST97InByte + +Proc ST97InByte ; Returns AL + + Jmp ST97ReceiveByte + +EndP ST97InByte + +; ST97InWord + +Proc ST97InWord ; Returns AX + + ClI + + Call ST97ReceiveByte + Mov AL, AH + + Call ST97ReceiveByte + XChg AL, AH + + StI + + Ret + +EndP ST97InWord + +; ST97InDWord + +Proc ST97InDWord ; Returns EAX + + ClI + + Call ST97ReceiveByte + RoR EAX, 8 + + Call ST97ReceiveByte + RoR EAX, 8 + + Call ST97ReceiveByte + RoR EAX, 8 + + Call ST97ReceiveByte + RoR EAX, 8 + + StI + Ret + +EndP ST97InDWord + +; ST97SendByte + +Proc ST97SendByte ; DX = port, AL = data + + Push AX + Push DX + Mov DX, CS:BasePort + Inc DX + +ST97SendByte1: + In AL, DX + Test AL, 40h + JNZ ST97SendByte1 + + Pop DX + Pop AX + + Out DX, AL + + Ret + +EndP ST97SendByte + +; ST97OutByte + +Proc ST97OutByte ; AL = data, AH = command, destroys AX + + ClI + Push DX + + Mov DX, CS:BasePort + Inc DX + + XChg AH, AL + Call ST97SendByte + + Dec DX + + Mov AL, AH + Call ST97SendByte + + Pop DX + StI + + Ret + +EndP ST97OutByte + +; ST97OutWord + +Proc ST97OutWord ; AX = data, BL = command, destroys AX + + ClI + Push DX + Push AX + + Mov DX, CS:BasePort + Mov AL, BL + Inc DX + Call ST97SendByte + + Pop AX + Dec DX + Call ST97SendByte + + Mov AL, AH + Call ST97SendByte + + Pop DX + StI + + Ret + +EndP ST97OutWord + +; ST97OutDWord + +Proc ST97OutDWord ; EAX = data, BL = command + + ClI + Push DX + Push AX + + Mov DX, CS:BasePort + Mov AL, BL + Inc DX + Call ST97SendByte + + Pop AX + Dec DX + Call ST97SendByte + + ShR EAX, 8 + Call ST97SendByte + + ShR EAX, 8 + Call ST97SendByte + + ShR EAX, 8 + Call ST97SendByte + + Pop DX + StI + + Ret + +EndP ST97OutDWord + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc ResetUART ; Given DX = Port + + ClI + + Inc DX + + Mov AL, 0FFh ; Reset! + Out DX, AL + Out DX, AL ; Two resets required to ensure it'll work + + Xor CX, CX + +ResetUART2: + In AL, DX + Test AL, 80h + JNZ ResetUART3 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE ResetUART4 + +ResetUART3: + Loop ResetUART2 + +ResetUARTError: + StI + StC + Ret + +ResetUART4: ; Now to shove it into 'intelligent' mode. + Xor CX, CX + +ResetUART5: + In AL, DX + Test AL, 40h + LoopNZ ResetUART5 + JNZ ResetUARTError + + Mov AL, 3Fh ; Intelligent mode! + Out DX, AL + +ResetUART6: + Xor CX, CX + +ResetUART7: + In AL, DX + Test AL, 80h + JNZ ResetUART8 + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JE ResetUART9 + +ResetUART8: + Loop ResetUART7 + Jmp ResetUARTError + +ResetUART9: + StI + ClC + Ret + +EndP ResetUART + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + Mov AX, 307h ; LDN 3 + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Mov BasePort, 330h + Mov DX, BasePort + Call ResetUART + +; Find memory mapping table + Mov AX, 300h ; Ctrl 3 (GET_MMT), Data 0 + Call ST97OutByte + Call ST97InDWord + + Push CS + Pop ES + Mov CX, MMT_MAXSIZE + Mov DI, Offset MMTData + Call ST97InString + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset ST97Message +Comment ~ + Mov AX, BasePort + Mov BX, IRQ + Mov ECX, DWord Ptr [MMTData+2] + ShR ECX, 9 +~ + Xor BX, BX + Mov AX, 5100h ; Cntrl = GET_VOI, Data = 0 + Call ST97OutByte + Call ST97InByte + Mov BL, AL + Mov AX, BasePort + Mov ECX, DWord Ptr [MMTData+2] + ShR ECX, 9 + + ClC + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Mov DX, CS:BasePort + Inc DX + Mov AL, 0FFh + Out DX, AL + + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load (0 based) +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release (1 based) +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset MMTData+6 + Xor EAX, EAX + +GetStatus1: + Mov CX, [SI] + Add SI, 6 + + Cmp CX, -1 + JE GetStatus2 + + Cmp CX, 1 + JA GetStatus1 + JB GetStatus1 + + Add EAX, [SI+2] + Sub EAX, [SI-4] + Jmp GetStatus1 + +GetStatus2: + Mov SI, Offset StatusLine + ShR EAX, 9 + + ClC + Ret + +EndP GetStatus + Assume DS:Nothing + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Xor AX, AX + StC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 64 ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 64 + + DW 5 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/ST97CMMX.ASM b/it/SoundDrivers/ST97CMMX.ASM new file mode 100755 index 0000000..1a3f5fb --- /dev/null +++ b/it/SoundDrivers/ST97CMMX.ASM @@ -0,0 +1,2773 @@ +; +; ST 97/42 PCI Codec, using MMX. +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing +OUTPUTFILTERENABLED EQU 0 +DATAFLAG EQU 200h +ACKFLAG EQU 300h +FOURIERBUFFERLENGTH EQU 2048 ; 2048 samples + +PNPVENDORID EQU 3746630Eh + +FPSave DB 128 Dup (0) + +DMASize DW DMABUFFERLENGTH / 2 + +WSSMsg DB "Sound Track Codec MMX", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Sound Track Codec MMX", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Track Codec reinitialised", 0 + +DriverName DB "ITSTCODE.MMX", 0 + +Forced DB 0 +Stereo DB 0 +WSSMixConst DB 0 + +ALIGN 2 + +MixVolume DW 0 + +BytesToMix DW 1000 + +MixSegment DW 0 +FourierSegment DW 0 + +; Arrangement of data: +; First 64 bytes = MMX temporary area +; Next 2*DMABUFFERLENGTH = DMA area +; After that is mixing buffer. + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 35 +MixMode DW 0 +MixModeOffset DW 0 +VolumeTable DB 56, 56 + DB 60h, 60h, 0Ch ; Low Band + DB 40h, 40h, 1Bh ; Med Low Band + DB 40h, 40h, 72h ; Med High Band + DB 60h, 60h, 40h ; High Band + DB 0, 0, 0 ; Echo + DB 0, 2 ; Surround + DB 0, 90h, 4, 7Fh, 22h ; Reverb + DB 0, 90h, 2, 40h, 9, 3, 13h ; Chorus + DB 0, 0 ; SRS stuff. + +ALIGN 2 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +SAM9407Reset DW 66 + DW 1BEh, 16Fh, 7Fh, 7Fh, ACKFLAG ; Audio in on + DW 1BEh, 168h, 7Fh, 7Fh, ACKFLAG ; Echo on + DW 1BEh, 16Ch, 7Fh, 7Fh, ACKFLAG ; Reverb on + DW 1BEh, 16Dh, 7Fh, 7Fh, ACKFLAG ; Chorus on + DW 1BEh, 16Bh, 0, 0, ACKFLAG ; Equalizer type + DW 1BEh, 16Eh, 7Fh, 7Fh, ACKFLAG ; Surround on + DW 1BEh, 165h, 7Fh, 7Fh ; Post eff on Audio in + DW 1BEh, 166h, 7Fh, 7Fh ; Post eff on reverb, chorus + DW 1BEh, 133h, 0, 0 ; 2 Speaker + DW 1BEh, 120h, 7Fh, 7Fh ; Stereo input 2 + DW 1BEh, 134h, 0FFh, 0FFh ; Left gain + DW 1BEh, 135h, 0FFh, 0FFh ; Right gain + DW 1BEh, 136h, 0, 0 ; Left pan + DW 1BEh, 137h, 7Fh, 7Fh ; Right pan + DW 1BEh, 107h, 0FFh, 0FFh ; Master volume + +SAM9407EqLBL DW 4 + DW 1BEh, 110h, DATAFLAG, 60h +SAM9407EqLBR DW 4 + DW 1BEh, 114h, DATAFLAG, 60h +SAM9407EqLBF DW 4 + DW 1BEh, 118h, DATAFLAG, 0Ch +SAM9407EqMLBL DW 4 + DW 1BEh, 111h, DATAFLAG, 40h +SAM9407EqMLBR DW 4 + DW 1BEh, 115h, DATAFLAG, 40h +SAM9407EqMLBF DW 4 + DW 1BEh, 119h, DATAFLAG, 1Bh +SAM9407EqMHBL DW 4 + DW 1BEh, 112h, DATAFLAG, 40h +SAM9407EqMHBR DW 4 + DW 1BEh, 116h, DATAFLAG, 40h +SAM9407EqMHBF DW 4 + DW 1BEh, 11Ah, DATAFLAG, 72h +SAM9407EqHBL DW 4 + DW 1BEh, 113h, DATAFLAG, 60h +SAM9407EqHBR DW 4 + DW 1BEh, 117h, DATAFLAG, 60h +SAM9407EqHBF DW 4 + DW 1BEh, 11Bh, DATAFLAG, 0Ch +SAM9407EchoLevel DW 4 + DW 1BEh, 128h, DATAFLAG, 0 +SAM9407EchoTime DW 4 + DW 1BEh, 129h, DATAFLAG, 2Bh +SAM9407EchoFeed DW 4 + DW 1BEh, 12Ah, DATAFLAG, 40h +SAM9407SurroundVolume DW 4 + DW 1BEh, 130h, DATAFLAG, 0 +SAM9407SurroundDelay DW 4 + DW 1BEh, 131h, DATAFLAG, 2 +SAM9407ReverbSend DW 4 + DW 1BEh, 127h, DATAFLAG, 0 +SAM9407ReverbVolume DW 3 + DW 1BEh, 13Ah, DATAFLAG +SAM9407ReverbType DW 4 + DW 1BEh, 169h, DATAFLAG, 4 +SAM9407ReverbTime DW 3 + DW 1BEh, 178h, DATAFLAG +SAM9407ReverbFeedback DW 3 + DW 1BEh, 179h, DATAFLAG +SAM9407ChorusSend DW 4 + DW 1BEh, 124h, DATAFLAG, 0 +SAM9407ChorusVolume DW 3 + DW 1BEh, 13Bh, DATAFLAG +SAM9407ChorusType DW 4 + DW 1BEh, 16Ah, DATAFLAG, 2 +SAM9407ChorusDelay DW 3 + DW 1BEh, 174h, DATAFLAG +SAM9407ChorusFeedback DW 3 + DW 1BEh, 175h, DATAFLAG +SAM9407ChorusRate DW 3 + DW 1BEh, 176h, DATAFLAG +SAM9407ChorusDepth DW 3 + DW 1BEh, 177h, DATAFLAG +SAM9407Mono DW 4 + DW 1BEh, 132h, 7Fh, 0 +SAM9407Stereo DW 4 + DW 1BEh, 132h, 0, 0 + +SAM9407Strings DW Offset SAM9407Reset ;1 + DW Offset SAM9407EqLBL, Offset SAM9407EqLBR + DW Offset SAM9407EqLBF + DW Offset SAM9407EqMLBL, Offset SAM9407EqMLBR + DW Offset SAM9407EqMLBF + DW Offset SAM9407EqMHBL, Offset SAM9407EqMHBR + DW Offset SAM9407EqMHBF + DW Offset SAM9407EqHBL, Offset SAM9407EqHBR + DW Offset SAM9407EqHBF + DW Offset SAM9407EchoLevel ; 14 + DW Offset SAM9407EchoTime + DW Offset SAM9407EchoFeed + DW Offset SAM9407SurroundVolume ; 17 + DW Offset SAM9407SurroundDelay + DW Offset SAM9407ReverbSend ; 19 + DW Offset SAM9407ReverbVolume + DW Offset SAM9407ReverbType + DW Offset SAM9407ReverbTime + DW Offset SAM9407ReverbFeedback ; 23 + DW Offset SAM9407ChorusSend ; 24 + DW Offset SAM9407ChorusVolume + DW Offset SAM9407ChorusType + DW Offset SAM9407ChorusDelay + DW Offset SAM9407ChorusFeedback + DW Offset SAM9407ChorusRate + DW Offset SAM9407ChorusDepth ; 30 + DW Offset SAM9407Mono ; 31 + DW Offset SAM9407Stereo + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; + DW Near Ptr MixModeButton4 ; + + DW Near Ptr EmptyObject + DW Near Ptr EmptyObject + DW Near Ptr EmptyObject + DW Near Ptr EmptyObject + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW Near Ptr CS4237SRSCenter ; 18 + DW Near Ptr CS4237SRSSpace ; 19 + DW Near Ptr CSControlPortText + +ST42A DW Near Ptr SAM9407PortText ; 21 + DW Near Ptr SAM9407ParametersText + DW Near Ptr SAM9407ParametersBox + + DW Near Ptr EqLBL ; 24 + DW Near Ptr EqLBR + DW Near Ptr EqLBF + + DW Near Ptr EqMLBL + DW Near Ptr EqMLBR + DW Near Ptr EqMLBF + + DW Near Ptr EqMHBL + DW Near Ptr EqMHBR + DW Near Ptr EqMHBF + + DW Near Ptr EqHBL + DW Near Ptr EqHBR + DW Near Ptr EqHBF + + DW Near Ptr EchoLevel ; 33 + DW Near Ptr EchoTime + DW Near Ptr EchoFeedback + + DW Near Ptr SurroundVolume + DW Near Ptr SurroundDelay + + DW Near Ptr ReverbSend ; 38 + DW Near Ptr ReverbVolume + DW Near Ptr ReverbType + DW Near Ptr ReverbTime + DW Near Ptr ReverbFeedback + + DW Near Ptr ChorusSend + DW Near Ptr ChorusVolume + DW Near Ptr ChorusType + DW Near Ptr ChorusDelay + DW Near Ptr ChorusFeedback + DW Near Ptr ChorusRate + DW Near Ptr ChorusDepth + + + DW 0 + +WSSHeaderLine DW 10 + DB "Sound Track Codec Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 28, 48 + DB 21h + DB "Sound Track Codec Driver 1.0 for Impulse Tracker", 0 + +CSControlPortText DW 1 + DB 28, 47 + DB 21h + DB "Sound Track CS4237 Control Port ", 0FDh, "Xh", 0 +CS4237Port DW 0 + +SAM9407PortText DW 1 + DB 28, 46 + DB 21h + DB "Sound Track SAM9407 Port ", 0FDh, "Xh", 0 +SAM9407Port DW 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB "CS4237 SRS Center", 13 + DB "CS4237 SRS Space" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 18 + DB 25 + +MasterVolumeLeft DW 14 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MasterVolumeRight DW 14 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 18, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +CS4237SRSCenter DW 14 + DB 22, 16 + DW 0, 15 + DW 9, 31 + DW 17, 19, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +CS4237SRSSpace DW 14 + DB 22, 17 + DW 0, 15 + DW 9, 32 + DW 18, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MixModeText DW 1 + DB 2, 19 + DB 20h + DB "Mixing Rate: ", 0FDh, "D", 0 +MixSpeed DW 48000 + DW 0 + +MixModeButton1 DW 2 + DW 19, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 21, 32, 23, 8 + DB 0 + DB " MMX, Non-interpolated", 0 + +MixModeButton2 DW 2 + DW 6 + DW 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 24, 32, 26, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 27, 32, 29, 8 + DB 0 + DB " MMX, Volume Ramp", 0 + +MixModeButton4 DW 2 + DW 8 +ST42B DW 24, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 30, 32, 32, 8 + DB 0 + DB " MMX, Filtered", 0 + +SAM9407ParametersText DW 1 + DB 36, 14 + DB 20h + DB "Low Band Left", 13 + DB "Low Band Right", 13 + DB "Low Band Frequency", 13 + DB "Med Low Band Left", 13 + DB "Med Low Band Right", 13 + DB "Med Low Band Frequency", 13 + DB "Med High Band Left", 13 + DB "Med High Band Right", 13 + DB "Med High Band Frequency", 13 + DB "High Band Left", 13 + DB "High Band Right", 13 + DB "High Band Frequency", 13 + DB "Echo Level", 13 + DB "Echo Time", 13 + DB "Echo Feedback", 13 + DB "Surround Volume", 13 + DB "Surround Delay", 13 + DB "Reverb Send", 13 + DB "Reverb Volume", 13 + DB "Reverb Type", 13 + DB "Reverb Time", 13 + DB "Reverb Feedback", 13 + DB "Chorus Send", 13 + DB "Chorus Volume", 13 + DB "Chorus Type", 13 + DB "Chorus Delay", 13 + DB "Chorus Feedback", 13 + DB "Chorus Rate", 13 + DB "Chorus Depth", 13 + DB 0 + +EqLBL DW 14 + DB 60, 14 + DW 0, 127 + DW 9, 2 + DW 9, 25, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBR DW 14 + DB 60, 15 + DW 0, 127 + DW 9, 3 + DW 24, 26, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBF DW 14 + DB 60, 16 + DW 0, 127 + DW 9, 4 + DW 25, 27, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBL DW 14 + DB 60, 17 + DW 0, 127 + DW 9, 5 + DW 26, 28, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBR DW 14 + DB 60, 18 + DW 0, 127 + DW 9, 6 + DW 27, 29, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBF DW 14 + DB 60, 19 + DW 0, 127 + DW 9, 7 + DW 28, 30, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBL DW 14 + DB 60, 20 + DW 0, 127 + DW 9, 8 + DW 29, 31, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBR DW 14 + DB 60, 21 + DW 0, 127 + DW 9, 9 + DW 30, 32, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBF DW 14 + DB 60, 22 + DW 0, 127 + DW 9, 10 + DW 31, 33, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBL DW 14 + DB 60, 23 + DW 0, 127 + DW 9, 11 + DW 32, 34, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBR DW 14 + DB 60, 24 + DW 0, 127 + DW 9, 12 + DW 33, 35, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBF DW 14 + DB 60, 25 + DW 0, 127 + DW 9, 13 + DW 34, 36, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoLevel DW 14 + DB 60, 26 + DW 0, 127 + DW 9, 15 + DW 35, 37, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoTime DW 14 + DB 60, 27 + DW 0, 127 + DW 9, 14 + DW 36, 38, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoFeedback DW 14 + DB 60, 28 + DW 0, 127 + DW 9, 16 + DW 37, 39, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundVolume DW 14 + DB 60, 29 + DW 0, 255 + DW 9, 17 + DW 38, 40, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundDelay DW 14 + DB 60, 30 + DW 0, 127 + DW 9, 18 + DW 39, 41, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbSend DW 14 + DB 60, 31 + DW 0, 127 + DW 9, 19 + DW 40, 42, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbVolume DW 14 + DB 60, 32 + DW 0, 255 + DW 9, 20 + DW 41, 43, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + + +ReverbType DW 14 + DB 60, 33 + DW 0, 7 + DW 9, 21 + DW 42, 44, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbTime DW 14 + DB 60, 34 + DW 0, 127 + DW 9, 22 + DW 43, 45, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbFeedback DW 14 + DB 60, 35 + DW 0, 127 + DW 9, 23 + DW 44, 46, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusSend DW 14 + DB 60, 36 + DW 0, 127 + DW 9, 24 + DW 45, 47, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusVolume DW 14 + DB 60, 37 + DW 0, 255 + DW 9, 25 + DW 46, 48, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusType DW 14 + DB 60, 38 + DW 0, 7 + DW 9, 26 + DW 47, 49, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDelay DW 14 + DB 60, 39 + DW 0, 127 + DW 9, 27 + DW 48, 50, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusFeedback DW 14 + DB 60, 40 + DW 0, 127 + DW 9, 28 + DW 49, 51, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusRate DW 14 + DB 60, 41 + DW 0, 127 + DW 9, 29 + DW 50, 52, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDepth DW 14 + DB 60, 42 + DW 0, 127 + DW 9, 30 + DW 51, 0FFFFh, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SAM9407ParametersBox DW 0 + DB 59, 13, 75, 43 + DB 25 + +; MixingRoutines + + +include dmasirq.inc +include mix.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; SAM9407InByte + +Proc SAM9407InByte ; Returns AL + + Push DX + Mov DX, CS:SAM9407Port + Inc DX + +SAM9407InByte1: + In AL, DX + Test AL, AL + JS SAM9407InByte1 + + Dec DX + In AL, DX + Pop DX + + Ret + +EndP SAM9407InByte + +; ST97SendByte + +Proc SAM9407SendByte ; DX = port, AL = data + + Push AX + Push DX + Mov DX, CS:SAM9407Port + Inc DX + +SAM9407SendByte1: + In AL, DX + Test AL, 40h + JNZ SAM9407SendByte1 + + Pop DX + Pop AX + + Out DX, AL + + Ret + +EndP SAM9407SendByte + +; + +Proc SetSAM9407 ; DI = index. 1 = full reinit. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + LEA SI, [SAM9407Strings+EDI+EDI-2] + Mov SI, [SI] + + LodsW + Mov CX, AX + +SetSAM9407_1: +; AH = 0 = normal data, 1 = command, 2 = param, 3 = ack. + + Mov DX, SAM9407Port + Test DX, DX + JZ NoSAM9407 + + LodsW + + Cmp AH, 2 + JB SetSAM9407_3 + JA SetSAM9407_4 + + Mov AL, [VolumeTable+DI] + Jmp SetSAM9407_2 + +SetSAM9407_4: + Call SAM9407InByte + Test AL, AL + JNZ SetSAM9407_4 + Jmp SetSAM9407_5 + +SetSAM9407_3: + And AH, 1 + Add DL, AH + +SetSAM9407_2: + Call SAM9407SendByte + +SetSAM9407_5: + Dec CX + JNZ SetSAM9407_1 + + +NoSAM9407: + Pop DS + PopA + + Ret + +EndP SetSAM9407 + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 16 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Mov AX, BX + Mov BX, 12000 + Xor DX, DX + Div BX + Mov FourierBufferStepOffset, AX + Mov FourierBufferStepFractional, DX + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Add DX, 6 + + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + + DB 85h + +PingWSSFailure: + StC + Pop DX + + Ret + + +EndP PingWSS + +include nodebug.inc + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc DetectMMX + + PushFD + Pop EAX + Mov EBX, EAX + Xor EAX, 00200000h + Push EAX + PopFD + PushFD + Pop EAX + Cmp EAX, EBX + JZ DetectMMXFail + + Mov EAX, 1 + DB 0Fh, 0A2h ; CPUID + Test EDX, 800000h + JZ DetectMMXFail + + Trace "MMX Detected" + + DB 85h + +DetectMMXFail: + StC + Ret + +EndP DetectMMX + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 007h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov AX, 207h ; CS4237 + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Test AX, AX + JZ PnP_IsolateNextCard + + Mov CS4237Port, AX + + Mov AX, 407h ; SAM9407 + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Test AX, AX + JZ PnP_NoSAM9407 + + Mov SAM9407Port, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +Pnp_NoSAM9407: + Xor AX, AX + Mov SAM9407Port, AX + Mov ST42A, AX + Dec AX + Mov ST42B, AX + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Call DetectMMX + JC DetectWSSFailure + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov DX, BasePort + JNC BasePortNotSpecified +; JNC DetectWSSOK + +DetectPCI: +; Cmp DMA, 0FFFFh +; JNE DMAOverride + + Mov DMA, 1 ; Force DMA to 1. + +DMAOverride: + Mov EBX, 80000000h ; PCI output value. + Mov DX, 0CF8h + Mov CX, 32 + +DetectCardPCIBasePort1: + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + Sub DX, 4 + Add EBX, 1 SHL 11 + + Cmp EAX, 8128Eh + LoopNE DetectCardPCIBasePort1 + + JNE DetectWSSFailure + + Add EBX, (3Ch) - (1 SHL 11) + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX ; AL = IRQ + Mov ECX, EAX + And AX, 0FFh + + JZ DetectWSSFailure + Cmp AL, 15 + JA DetectWSSFailure + + Cmp IRQ, 0FFFFh + JNE IRQSpecified + + Mov IRQ, AX + +IRQSpecified: + Sub DX, 4 + +; Get SAM9407IRQ + Add EBX, 1 SHL 8 + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + Sub DX, 4 ; AL = IRQ. + + And AX, 0FFh + + PushA + + JZ NoSAM9407IRQ + Cmp AL, 15 + JA NoSAM9407IRQ + + Mov DL, AL + ShL DL, 4 + Mov CL, AL + And DX, 80h + Mov CH, 1 + Or DL, 21h + And CL, 7 + ShL CH, CL + In AL, DX + Or AL, CH + Out DX, AL + +NoSAM9407IRQ: + PopA + Push AX + + Add EBX, 10h-3Ch ; SAM9407 port + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + Sub DX, 4 + And AX, 0FFEh + Mov SAM9407Port, AX + Pop CX + +; If SAM9407 Port not available, or IRQ = old IRQ, then set to ST42 mode. + Test AX, AX + JZ ST42Found + Cmp AX, 400h + JA ST42Found + Cmp CX, IRQ + JNE NoST42 + +ST42Found: +; Mov AX, '24' +; Mov Word Ptr O97A, AX +; Mov Word Ptr O97B, AX +; Mov Word Ptr O97C, AX +; Mov Word Ptr O97D, AX +; Mov Word Ptr O97E, AX +; Mov Word Ptr O97F, AX + Xor AX, AX + Mov SAM9407Port, AX + Mov ST42A, AX + Dec AX + Mov ST42B, AX + +NoST42: + Add EBX, 3 SHL 8 + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + Sub DX, 4 + And AX, 0FFEh + Cmp AX, 400h + JB NoCS + + Xor AX, AX + +NoCS: + Mov CS4237Port, AX + + Sub EBX, 4 SHL 8 + +; Add EBX, 10h - 3Ch +; Add EBX, (10h) - (1 SHL 11) + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + + And AX, 0FFEh + Mov DX, AX + + Cmp BasePort, 0FFFFh + JE BasePortNotSpecified + + Mov DX, BasePort + +BasePortnotSpecified: + Call PingWSS + JNC DetectWSSOK + + Sub DX, 4 + Call PingWSS + JNC DetectWSSOK + +DetectWSSFailure: + StC + Ret + +DetectWSSOK: + Mov BasePort, DX + +CheckWSSOK: ; Check for IRQ + Add DX, 4 + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Mov DX, CS4237Port + Test DX, DX + JZ DetectNoCS4237Port + + Add DX, 3 + + Mov AL, 3 + Out DX, AL + Inc DX + Mov AL, 0A0h + Out DX, AL + Dec DX ; Enable 3D stuff + + Mov AL, 2 + Out DX, AL + Inc DX + In AL, DX + Out DX, AL + Not AL + Mov AH, AL + And AL, 0Fh + ShR AH, 4 + + Mov [Word Ptr VolumeTable+31], AX + +DetectNoCS4237Port: + Mov EAX, 'Jeff' + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +include mmxmsam.inc +include fourier.inc + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + FNSave [FPSave] + + Mov DX, [BasePort] + Add DX, 6 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + + Cmp BX, DMABUFFERLENGTH/2 + JB WSSIRQHandler1 + + Mov AX, DMABUFFERLENGTH/2 + +WSSIRQHandler1: + CLD + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + Call UpdateFourierBuffer + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + +include mmxtrans.inc + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + FNRstor [CS:FPSave] + + Pop ES + Pop DS + PopAD + IRet + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + Add DX, 4 + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, MixSegment + Mov AX, 80 + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Add DX, 4 + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 5 + (DMABUFFERLENGTH*2)/16 + FOURIERBUFFERLENGTH/8 + Mov BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Sub AX, FOURIERBUFFERLENGTH/8 + Mov FourierSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov DI, 1 + Call SetSAM9407 + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetUART + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetUART + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Push AX + + Call ResetUART + Call StopWSS + Call StartWSS + + Pop DI + And DI, 1 + Add DI, 31 + Call SetSAM9407 + + Mov DI, 2 +SetStereo2: + Call SetSAM9407 + Inc DI + Cmp DI, 30 + JBE SetStereo2 + +SetStereo1: + Call InitUART + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + Add DX, 4 + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + + Mov DX, CS4237Port + Test DX, DX + JZ UpdateSoundCardVariables1 + + Add DX, 3 + + Mov AL, 3 + Out DX, AL + Inc DX + Mov AL, 0A0h + Out DX, AL + Dec DX + + Mov AL, 2 + Out DX, AL + + Mov AX, [Word Ptr VolumeTable+31] + ShL AH, 4 + Inc DX + Or AL, AH + Not AL + Out DX, AL + +UpdateSoundCardVariables1: + + Pop DS + PopA + + Ret + +EndP UpdateSoundcardVariables + Assume DS:Nothing + +; + +Proc SetVariable Far + + Mov [CS:VolumeTable+DI], AL + Cmp DI, 31 + JAE SetVariable1 + Cmp DI, 2 + JB SetVariable1 + + Call SetSAM9407 + Ret + +SetVariable1: + Call UpdateSoundcardVariables + Ret + +EndP SetVariable + +; + +Proc ResetUART + + Mov DX, CS:SAM9407Port + Test DX, DX + JZ ResetUART1 + + Inc DX + + Mov AL, 0FFh + Out DX, AL + +ResetUART1: + Ret + +EndP ResetUART + +; + +Proc InitUART + + ClI + + Mov DX, CS:SAM9407Port + Inc DX + Mov AL, 0FFh ; reset + Out DX, AL + + Xor CX, CX + +DetectUARTPause: + In AL, 21h + In AL, 0A1h + Loop DetectUARTPause + + Mov AL, 0FFh + Out DX, AL + + Xor CX, CX + +DetectUART1: + In AL, DX + Test AL, 80h + LoopNZ DetectUART1 + JNZ DetectUARTFailed + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JNE DetectUART1 + + Xor CX, CX + +DetectUART3: + In AL, DX + Test AL, 40h + LoopNZ DetectUART3 + JNZ DetectUARTFailed + + Mov AL, 03Fh + Out DX, AL + + Xor CX, CX + +DetectUART2: + In AL, DX + Test AL, 80h + LoopNZ DetectUART2 + JNZ DetectUARTFailed + + Dec DX + In AL, DX + Inc DX + Cmp AL, 0FEh + JNE DetectUART2 + Dec DX + + Mov AL, 0FFh + Out DX, AL + + DB 85h +DetectUARTFailed: + StC + StI + Ret + +EndP InitUART + +; + +Proc UARTOut + + Push CX + Push DX + Mov DX, CS:SAM9407Port + + Push AX + Xor CX, CX + Inc DX + +UARTOut1: + In AL, DX + Test AL, 40h + LoopNZ UARTOut1 + + Pop AX + JNZ UARTOutEnd + + Dec DX + Out DX, AL + +UARTOutEnd: + Pop DX + Pop CX + + Ret + +EndP UARTOut + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h + Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: + Call UARTOut + Ret + +EndP SendUARTOut + +; + +Proc GetWaveForm Far ; Given ES:DI = destination + Assume DS:Nothing ; want 2048 samples. + + PushA + Push DS + + Mov DS, FourierSegment + Mov SI, FourierBufferStart + Mov CX, 2048 + +GetWaveForm1: + MovsW + And SI, (FOURIERBUFFERLENGTH*2)-1 + Dec CX + JNZ GetWaveForm1 + + Pop DS + PopA + + Ret + +EndP GetWaveForm + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 128 +DriverFlags DW 7 + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + + DW Offset SendUARTOut + DW Offset GetWaveForm + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/ST97CODE.ASM b/it/SoundDrivers/ST97CODE.ASM new file mode 100755 index 0000000..7e9d21a --- /dev/null +++ b/it/SoundDrivers/ST97CODE.ASM @@ -0,0 +1,3171 @@ +; +; ST 97/42 PCI Codec +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc +include mmx.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 +DATAFLAG EQU 200h +ACKFLAG EQU 300h + +PNPVENDORID EQU 3746630Eh + +DMASize DW DMABUFFERLENGTH / 2 + +WSSMsg DB "Sound Track Codec", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Sound Track Codec", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Track Codec reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITSTCODE.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITSTCODE.DRV", 0 + +DriverName DB "ITSTCODE.DRV", 0 + +Forced DB 0 +Stereo DB 0 +WSSMixConst DB 0 + +ALIGN 2 + +MixVolume DW 0 + +BytesToMix DW 1000 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 37 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 +VolumeTable DB 56, 56 + DB 60h, 60h, 0Ch ; Low Band + DB 40h, 40h, 1Bh ; Med Low Band + DB 40h, 40h, 72h ; Med High Band + DB 60h, 60h, 40h ; High Band + DB 0, 0, 0 ; Echo + DB 0, 2 ; Surround + DB 0, 90h, 4, 7Fh, 22h ; Reverb + DB 0, 90h, 2, 40h, 9, 3, 13h ; Chorus + DB 0, 0 ; SRS stuff. + +ALIGN 2 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +SAM9407Reset DW 66 + DW 1BEh, 16Fh, 7Fh, 7Fh, ACKFLAG ; Audio in on + DW 1BEh, 168h, 7Fh, 7Fh, ACKFLAG ; Echo on + DW 1BEh, 16Ch, 7Fh, 7Fh, ACKFLAG ; Reverb on + DW 1BEh, 16Dh, 7Fh, 7Fh, ACKFLAG ; Chorus on + DW 1BEh, 16Bh, 0, 0, ACKFLAG ; Equalizer type + DW 1BEh, 16Eh, 7Fh, 7Fh, ACKFLAG ; Surround on + DW 1BEh, 165h, 7Fh, 7Fh ; Post eff on Audio in + DW 1BEh, 166h, 7Fh, 7Fh ; Post eff on reverb, chorus + DW 1BEh, 133h, 0, 0 ; 2 Speaker + DW 1BEh, 120h, 7Fh, 7Fh ; Stereo input 2 + DW 1BEh, 134h, 0FFh, 0FFh ; Left gain + DW 1BEh, 135h, 0FFh, 0FFh ; Right gain + DW 1BEh, 136h, 0, 0 ; Left pan + DW 1BEh, 137h, 7Fh, 7Fh ; Right pan + DW 1BEh, 107h, 0FFh, 0FFh ; Master volume + +SAM9407EqLBL DW 4 + DW 1BEh, 110h, DATAFLAG, 60h +SAM9407EqLBR DW 4 + DW 1BEh, 114h, DATAFLAG, 60h +SAM9407EqLBF DW 4 + DW 1BEh, 118h, DATAFLAG, 0Ch +SAM9407EqMLBL DW 4 + DW 1BEh, 111h, DATAFLAG, 40h +SAM9407EqMLBR DW 4 + DW 1BEh, 115h, DATAFLAG, 40h +SAM9407EqMLBF DW 4 + DW 1BEh, 119h, DATAFLAG, 1Bh +SAM9407EqMHBL DW 4 + DW 1BEh, 112h, DATAFLAG, 40h +SAM9407EqMHBR DW 4 + DW 1BEh, 116h, DATAFLAG, 40h +SAM9407EqMHBF DW 4 + DW 1BEh, 11Ah, DATAFLAG, 72h +SAM9407EqHBL DW 4 + DW 1BEh, 113h, DATAFLAG, 60h +SAM9407EqHBR DW 4 + DW 1BEh, 117h, DATAFLAG, 60h +SAM9407EqHBF DW 4 + DW 1BEh, 11Bh, DATAFLAG, 0Ch +SAM9407EchoLevel DW 4 + DW 1BEh, 128h, DATAFLAG, 0 +SAM9407EchoTime DW 4 + DW 1BEh, 129h, DATAFLAG, 2Bh +SAM9407EchoFeed DW 4 + DW 1BEh, 12Ah, DATAFLAG, 40h +SAM9407SurroundVolume DW 4 + DW 1BEh, 130h, DATAFLAG, 0 +SAM9407SurroundDelay DW 4 + DW 1BEh, 131h, DATAFLAG, 2 +SAM9407ReverbSend DW 4 + DW 1BEh, 127h, DATAFLAG, 0 +SAM9407ReverbVolume DW 3 + DW 1BEh, 13Ah, DATAFLAG +SAM9407ReverbType DW 4 + DW 1BEh, 169h, DATAFLAG, 4 +SAM9407ReverbTime DW 3 + DW 1BEh, 178h, DATAFLAG +SAM9407ReverbFeedback DW 3 + DW 1BEh, 179h, DATAFLAG +SAM9407ChorusSend DW 4 + DW 1BEh, 124h, DATAFLAG, 0 +SAM9407ChorusVolume DW 3 + DW 1BEh, 13Bh, DATAFLAG +SAM9407ChorusType DW 4 + DW 1BEh, 16Ah, DATAFLAG, 2 +SAM9407ChorusDelay DW 3 + DW 1BEh, 174h, DATAFLAG +SAM9407ChorusFeedback DW 3 + DW 1BEh, 175h, DATAFLAG +SAM9407ChorusRate DW 3 + DW 1BEh, 176h, DATAFLAG +SAM9407ChorusDepth DW 3 + DW 1BEh, 177h, DATAFLAG +SAM9407Mono DW 4 + DW 1BEh, 132h, 7Fh, 0 +SAM9407Stereo DW 4 + DW 1BEh, 132h, 0, 0 + +SAM9407Strings DW Offset SAM9407Reset ;1 + DW Offset SAM9407EqLBL, Offset SAM9407EqLBR + DW Offset SAM9407EqLBF + DW Offset SAM9407EqMLBL, Offset SAM9407EqMLBR + DW Offset SAM9407EqMLBF + DW Offset SAM9407EqMHBL, Offset SAM9407EqMHBR + DW Offset SAM9407EqMHBF + DW Offset SAM9407EqHBL, Offset SAM9407EqHBR + DW Offset SAM9407EqHBF + DW Offset SAM9407EchoLevel ; 14 + DW Offset SAM9407EchoTime + DW Offset SAM9407EchoFeed + DW Offset SAM9407SurroundVolume ; 17 + DW Offset SAM9407SurroundDelay + DW Offset SAM9407ReverbSend ; 19 + DW Offset SAM9407ReverbVolume + DW Offset SAM9407ReverbType + DW Offset SAM9407ReverbTime + DW Offset SAM9407ReverbFeedback ; 23 + DW Offset SAM9407ChorusSend ; 24 + DW Offset SAM9407ChorusVolume + DW Offset SAM9407ChorusType + DW Offset SAM9407ChorusDelay + DW Offset SAM9407ChorusFeedback + DW Offset SAM9407ChorusRate + DW Offset SAM9407ChorusDepth ; 30 + DW Offset SAM9407Mono ; 31 + DW Offset SAM9407Stereo +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW Near Ptr CS4237SRSCenter ; 18 + DW Near Ptr CS4237SRSSpace ; 19 + DW Near Ptr CSControlPortText + +ST42A DW Near Ptr SAM9407PortText ; 21 + DW Near Ptr SAM9407ParametersText + DW Near Ptr SAM9407ParametersBox + + DW Near Ptr EqLBL ; 24 + DW Near Ptr EqLBR + DW Near Ptr EqLBF + + DW Near Ptr EqMLBL + DW Near Ptr EqMLBR + DW Near Ptr EqMLBF + + DW Near Ptr EqMHBL + DW Near Ptr EqMHBR + DW Near Ptr EqMHBF + + DW Near Ptr EqHBL + DW Near Ptr EqHBR + DW Near Ptr EqHBF + + DW Near Ptr EchoLevel ; 33 + DW Near Ptr EchoTime + DW Near Ptr EchoFeedback + + DW Near Ptr SurroundVolume + DW Near Ptr SurroundDelay + + DW Near Ptr ReverbSend ; 38 + DW Near Ptr ReverbVolume + DW Near Ptr ReverbType + DW Near Ptr ReverbTime + DW Near Ptr ReverbFeedback + + DW Near Ptr ChorusSend + DW Near Ptr ChorusVolume + DW Near Ptr ChorusType + DW Near Ptr ChorusDelay + DW Near Ptr ChorusFeedback + DW Near Ptr ChorusRate + DW Near Ptr ChorusDepth + + + DW 0 + +WSSHeaderLine DW 10 + DB "Sound Track Codec Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 28, 48 + DB 21h + DB "Sound Track Codec Driver 1.0 for Impulse Tracker", 0 + +CSControlPortText DW 1 + DB 28, 47 + DB 21h + DB "Sound Track CS4237 Control Port ", 0FDh, "Xh", 0 +CS4237Port DW 0 + +SAM9407PortText DW 1 + DB 28, 46 + DB 21h + DB "Sound Track SAM9407 Port ", 0FDh, "Xh", 0 +SAM9407Port DW 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 13 + DB "CS4237 SRS Center", 13 + DB "CS4237 SRS Space" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 18 + DB 25 + +MasterVolumeLeft DW 14 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MasterVolumeRight DW 14 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 18, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +CS4237SRSCenter DW 14 + DB 22, 16 + DW 0, 15 + DW 9, 31 + DW 17, 19, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +CS4237SRSSpace DW 14 + DB 22, 17 + DW 0, 15 + DW 9, 32 + DW 18, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MixModeText DW 1 + DB 2, 19 + DB 20h + DB "Mixing Rate: ", 0FDh, "D, Mode:", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 19, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 21, 32, 23, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 24, 32, 26, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 27, 32, 29, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 30, 32, 32, 8 + DB 0 + DB " 32 Bit, Ultra Quality", 0 + +FilterText DW 1 + DB 2, 34 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 36, 29, 38, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 39, 29, 41, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12 +ST42B DW 24, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 42, 29, 44, 8 + DB 0 + DB " 75% Filter", 0 + +SAM9407ParametersText DW 1 + DB 36, 14 + DB 20h + DB "Low Band Left", 13 + DB "Low Band Right", 13 + DB "Low Band Frequency", 13 + DB "Med Low Band Left", 13 + DB "Med Low Band Right", 13 + DB "Med Low Band Frequency", 13 + DB "Med High Band Left", 13 + DB "Med High Band Right", 13 + DB "Med High Band Frequency", 13 + DB "High Band Left", 13 + DB "High Band Right", 13 + DB "High Band Frequency", 13 + DB "Echo Level", 13 + DB "Echo Time", 13 + DB "Echo Feedback", 13 + DB "Surround Volume", 13 + DB "Surround Delay", 13 + DB "Reverb Send", 13 + DB "Reverb Volume", 13 + DB "Reverb Type", 13 + DB "Reverb Time", 13 + DB "Reverb Feedback", 13 + DB "Chorus Send", 13 + DB "Chorus Volume", 13 + DB "Chorus Type", 13 + DB "Chorus Delay", 13 + DB "Chorus Feedback", 13 + DB "Chorus Rate", 13 + DB "Chorus Depth", 13 + DB 0 + +EqLBL DW 14 + DB 60, 14 + DW 0, 127 + DW 9, 2 + DW 13, 25, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBR DW 14 + DB 60, 15 + DW 0, 127 + DW 9, 3 + DW 24, 26, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBF DW 14 + DB 60, 16 + DW 0, 127 + DW 9, 4 + DW 25, 27, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBL DW 14 + DB 60, 17 + DW 0, 127 + DW 9, 5 + DW 26, 28, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBR DW 14 + DB 60, 18 + DW 0, 127 + DW 9, 6 + DW 27, 29, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBF DW 14 + DB 60, 19 + DW 0, 127 + DW 9, 7 + DW 28, 30, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBL DW 14 + DB 60, 20 + DW 0, 127 + DW 9, 8 + DW 29, 31, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBR DW 14 + DB 60, 21 + DW 0, 127 + DW 9, 9 + DW 30, 32, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBF DW 14 + DB 60, 22 + DW 0, 127 + DW 9, 10 + DW 31, 33, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBL DW 14 + DB 60, 23 + DW 0, 127 + DW 9, 11 + DW 32, 34, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBR DW 14 + DB 60, 24 + DW 0, 127 + DW 9, 12 + DW 33, 35, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBF DW 14 + DB 60, 25 + DW 0, 127 + DW 9, 13 + DW 34, 36, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoLevel DW 14 + DB 60, 26 + DW 0, 127 + DW 9, 15 + DW 35, 37, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoTime DW 14 + DB 60, 27 + DW 0, 127 + DW 9, 14 + DW 36, 38, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoFeedback DW 14 + DB 60, 28 + DW 0, 127 + DW 9, 16 + DW 37, 39, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundVolume DW 14 + DB 60, 29 + DW 0, 255 + DW 9, 17 + DW 38, 40, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundDelay DW 14 + DB 60, 30 + DW 0, 127 + DW 9, 18 + DW 39, 41, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbSend DW 14 + DB 60, 31 + DW 0, 127 + DW 9, 19 + DW 40, 42, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbVolume DW 14 + DB 60, 32 + DW 0, 255 + DW 9, 20 + DW 41, 43, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + + +ReverbType DW 14 + DB 60, 33 + DW 0, 7 + DW 9, 21 + DW 42, 44, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbTime DW 14 + DB 60, 34 + DW 0, 127 + DW 9, 22 + DW 43, 45, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbFeedback DW 14 + DB 60, 35 + DW 0, 127 + DW 9, 23 + DW 44, 46, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusSend DW 14 + DB 60, 36 + DW 0, 127 + DW 9, 24 + DW 45, 47, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusVolume DW 14 + DB 60, 37 + DW 0, 255 + DW 9, 25 + DW 46, 48, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusType DW 14 + DB 60, 38 + DW 0, 7 + DW 9, 26 + DW 47, 49, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDelay DW 14 + DB 60, 39 + DW 0, 127 + DW 9, 27 + DW 48, 50, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusFeedback DW 14 + DB 60, 40 + DW 0, 127 + DW 9, 28 + DW 49, 51, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusRate DW 14 + DB 60, 41 + DW 0, 127 + DW 9, 29 + DW 50, 52, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDepth DW 14 + DB 60, 42 + DW 0, 127 + DW 9, 30 + DW 51, 0FFFFh, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SAM9407ParametersBox DW 0 + DB 59, 13, 75, 43 + DB 25 + +; OldIRQData DD 0 +; OldIRQOffset DD 0 +; UseOldIRQ DB 0 + +; MixingRoutines + + +include dmasirq.inc +include mix.inc + +include m12bit.mix +include m12biti.mix +include m32biti.mix +include m32ultra.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32biti.inc +include m32ultra.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + + Mov AX, 1 + Ret + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; SAM9407InByte + +Proc SAM9407InByte ; Returns AL + + Push DX + Mov DX, CS:SAM9407Port + Inc DX + +SAM9407InByte1: + In AL, DX + Test AL, AL + JS SAM9407InByte1 + + Dec DX + In AL, DX + Pop DX + + Ret + +EndP SAM9407InByte + +; ST97SendByte + +Proc SAM9407SendByte ; DX = port, AL = data + + Push AX + Push DX + Mov DX, CS:SAM9407Port + Inc DX + +SAM9407SendByte1: + In AL, DX + Test AL, 40h + JNZ SAM9407SendByte1 + + Pop DX + Pop AX + + Out DX, AL + + Ret + +EndP SAM9407SendByte + +; + +Proc SetSAM9407 ; DI = index. 1 = full reinit. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + LEA SI, [SAM9407Strings+EDI+EDI-2] + Mov SI, [SI] + + LodsW + Mov CX, AX + +SetSAM9407_1: +; AH = 0 = normal data, 1 = command, 2 = param, 3 = ack. + + Mov DX, SAM9407Port + Test DX, DX + JZ NoSAM9407 + + LodsW + + Cmp AH, 2 + JB SetSAM9407_3 + JA SetSAM9407_4 + + Mov AL, [VolumeTable+DI] + Jmp SetSAM9407_2 + +SetSAM9407_4: + Call SAM9407InByte + Test AL, AL + JNZ SetSAM9407_4 + Jmp SetSAM9407_5 + +SetSAM9407_3: + And AH, 1 + Add DL, AH + +SetSAM9407_2: + Call SAM9407SendByte + +SetSAM9407_5: + Dec CX + JNZ SetSAM9407_1 + +NoSAM9407: + Pop DS + PopA + + Ret + +EndP SetSAM9407 + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 16 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Add DX, 6 + + + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +PingWSSFailure: + Pop DX + + StC + Ret + + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard +; Cmp PnP_SerialID, PNPSERIALID +; JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + + Mov AX, 007h ; Configuration device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + + Test AX, AX + JZ PnP_IsolateNextCard + + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Cmp AX, 534h + JNE PnPBasePortTranslate1 + + Mov AX, 530h + +PnPBasePortTranslate1: + Cmp AX, 0F44h + JNE PnPBasePortTranslate2 + + Mov AX, 0F40h + +PnPBasePortTranslate2: + Cmp AX, 608h + JNE PnPBasePortTranslate3 + + Mov AX, 604h + +PnPBasePortTranslate3: + Cmp AX, 0E84h + JNE PnPBasePortTranslate4 + + Mov AX, 0E80h + +PnPBasePortTranslate4: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov AX, 207h ; CS4237 + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Test AX, AX + JZ PnP_IsolateNextCard + + Mov CS4237Port, AX + + Mov AX, 407h ; SAM9407 + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Test AX, AX + JZ PnP_NoSAM9407 + + Mov SAM9407Port, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +Pnp_NoSAM9407: + Xor AX, AX + Mov SAM9407Port, AX + Mov ST42A, AX + Dec AX + Mov ST42B, AX + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov DX, BasePort + JNC DetectWSSOK + +DetectPCI: +; Cmp DMA, 0FFFFh +; JNE DMAOverride + + Mov DMA, 1 ; Force DMA to 1. + +DMAOverride: + Mov EBX, 80000000h ; PCI output value. + Mov DX, 0CF8h + Mov CX, 32 + +DetectCardPCIBasePort1: + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + Sub DX, 4 + Add EBX, 1 SHL 11 + + Cmp EAX, 8128Eh + LoopNE DetectCardPCIBasePort1 + + JNE DetectWSSFailure + + Add EBX, (3Ch) - (1 SHL 11) + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX ; AL = IRQ + Mov ECX, EAX + And AX, 0FFh + + JZ DetectWSSFailure + Cmp AL, 15 + JA DetectWSSFailure + + Cmp IRQ, 0FFFFh + JNE IRQSpecified + + Mov IRQ, AX + +; Mov OldIRQOffset, EBX +; Mov OldIRQData, ECX +; Mov UseOldIRQ, 1 + +IRQSpecified: + Sub DX, 4 + +; Get SAM9407IRQ + Add EBX, 1 SHL 8 + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + Sub DX, 4 ; AL = IRQ. + + And AX, 0FFh + + PushA + + JZ NoSAM9407IRQ + Cmp AL, 15 + JA NoSAM9407IRQ + + Mov DL, AL + ShL DL, 4 + Mov CL, AL + And DX, 80h + Mov CH, 1 + Or DL, 21h + And CL, 7 + ShL CH, CL + In AL, DX + Or AL, CH + Out DX, AL + +NoSAM9407IRQ: + PopA + Push AX + + Add EBX, 10h-3Ch ; SAM9407 port + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + Sub DX, 4 + And AX, 0FFEh + Mov SAM9407Port, AX + Pop CX + +; If SAM9407 Port not available, or IRQ = old IRQ, then set to ST42 mode. + Test AX, AX + JZ ST42Found + Cmp AX, 400h + JA ST42Found + Cmp CX, IRQ + JNE NoST42 + +ST42Found: +; Mov AX, '24' +; Mov Word Ptr O97A, AX +; Mov Word Ptr O97B, AX +; Mov Word Ptr O97C, AX +; Mov Word Ptr O97D, AX +; Mov Word Ptr O97E, AX +; Mov Word Ptr O97F, AX + Xor AX, AX + Mov SAM9407Port, AX + Mov ST42A, AX + Dec AX + Mov ST42B, AX + +NoST42: + Add EBX, 3 SHL 8 + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + Sub DX, 4 + And AX, 0FFEh + Cmp AX, 400h + JB NoCS + + Xor AX, AX + +NoCS: + Mov CS4237Port, AX + + Sub EBX, 4 SHL 8 + +; Add EBX, 10h - 3Ch +; Add EBX, (10h) - (1 SHL 11) + Mov EAX, EBX + Out DX, EAX + Add DX, 4 + In EAX, DX + + And AX, 0FFEh + Mov DX, AX + + Cmp BasePort, 0FFFFh + JE BasePortNotSpecified + + Mov DX, BasePort + +BasePortnotSpecified: + Call PingWSS + JNC DetectWSSOK + +DetectWSSFailure: + StC + Ret + +DetectWSSOK: + Mov BasePort, DX + +CheckWSSOK: ; Check for IRQ + Add DX, 4 + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Mov DX, CS4237Port + Test DX, DX + JZ DetectNoCS4237Port + + Add DX, 3 + + Mov AL, 3 + Out DX, AL + Inc DX + Mov AL, 0A0h + Out DX, AL + Dec DX ; Enable 3D stuff + + Mov AL, 2 + Out DX, AL + Inc DX + In AL, DX + Out DX, AL + Not AL + Mov AH, AL + And AL, 0Fh + ShR AH, 4 + + Mov [Word Ptr VolumeTable+31], AX + +DetectNoCS4237Port: + Mov EAX, 'Jeff' + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 6 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Xor AX, AX + + Cmp BX, DMABUFFERLENGTH/2 + JB WSSIRQHandler1 + + Mov AX, DMABUFFERLENGTH/2 + +WSSIRQHandler1: + CLD + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + Add DX, 4 + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Add DX, 4 + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov DI, 1 + Call SetSAM9407 + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: +; Cmp UseOldIRQ, 1 +; JNE UnInitSound2 +; +; Mov DX, 0CF8h +; Mov EAX, OldIRQOffset +; Out DX, EAX +; Add DX, 4 +; Mov EAX, OldIRQData +; Out DX, EAX +; +; UnInitSound2: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Push AX + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + + Pop DI + And DI, 1 + Add DI, 31 + Call SetSAM9407 + + Mov DI, 2 +SetStereo2: + Call SetSAM9407 + Inc DI + Cmp DI, 30 + JBE SetStereo2 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov DX, BasePort + Add DX, 4 + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + + Mov DX, CS4237Port + Test DX, DX + JZ UpdateSoundCardVariables1 + + Add DX, 3 + + Mov AL, 3 + Out DX, AL + Inc DX + Mov AL, 0A0h + Out DX, AL + Dec DX + + Mov AL, 2 + Out DX, AL + + Mov AX, [Word Ptr VolumeTable+31] + ShL AH, 4 + Inc DX + Or AL, AH + Not AL + Out DX, AL + +UpdateSoundCardVariables1: + + Pop DS + PopA + + Ret + +EndP UpdateSoundcardVariables + Assume DS:Nothing + +; + +Proc SetVariable Far + + Mov [CS:VolumeTable+DI], AL + Cmp DI, 31 + JAE SetVariable1 + Cmp DI, 2 + JB SetVariable1 + + Call SetSAM9407 + Ret + +SetVariable1: + Call UpdateSoundcardVariables + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. +StopAfterPlay DW 0 +DefaultChannels DW 64 +DriverFlags DW 0 + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/ST97PNP.ASM b/it/SoundDrivers/ST97PNP.ASM new file mode 100755 index 0000000..8fb2fcb --- /dev/null +++ b/it/SoundDrivers/ST97PNP.ASM @@ -0,0 +1,2623 @@ +; +; Analog Device's AD1816 +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +PNPSERIALID EQU 0FFFFFFFFh +PNPVENDORID EQU 80719304h + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 +DATAFLAG EQU 200h +ACKFLAG EQU 300h + +Debug DW 0 +Debug2 DW 0 +DMASize DW 2048 + +ESSMsg DB "Sound Track '97 PnP found", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +ESSNoMemoryMsg DB "Sound Track '97 PnP found", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Sound Track '97 PnP reinitialised", 0 + +DriverName DB "ITSTPNP.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +ESSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 +VolumeTable DB 56, 56 + DB 60h, 60h, 0Ch ; Low Band + DB 40h, 40h, 1Bh ; Med Low Band + DB 40h, 40h, 72h ; Med High Band + DB 60h, 60h, 40h ; High Band + DB 0, 0, 0 ; Echo + DB 0, 2 ; Surround + DB 0, 90h, 4, 7Fh, 22h ; Reverb + DB 0, 90h, 2, 40h, 9, 3, 13h ; Chorus + DB 0, 0 ; Phat Stereo Stuff + +IMR DW 0 +OldESSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +SAM9407Reset DW 66 + DW 1BEh, 16Fh, 7Fh, 7Fh, ACKFLAG ; Audio in on + DW 1BEh, 168h, 7Fh, 7Fh, ACKFLAG ; Echo on + DW 1BEh, 16Ch, 7Fh, 7Fh, ACKFLAG ; Reverb on + DW 1BEh, 16Dh, 7Fh, 7Fh, ACKFLAG ; Chorus on + DW 1BEh, 16Bh, 0, 0, ACKFLAG ; Equalizer type + DW 1BEh, 16Eh, 7Fh, 7Fh, ACKFLAG ; Surround on + DW 1BEh, 165h, 7Fh, 7Fh ; Post eff on Audio in + DW 1BEh, 166h, 7Fh, 7Fh ; Post eff on reverb, chorus + DW 1BEh, 133h, 0, 0 ; 2 Speaker + DW 1BEh, 120h, 7Fh, 7Fh ; Stereo input 2 + DW 1BEh, 134h, 0FFh, 0FFh ; Left gain + DW 1BEh, 135h, 0FFh, 0FFh ; Right gain + DW 1BEh, 136h, 0, 0 ; Left pan + DW 1BEh, 137h, 7Fh, 7Fh ; Right pan + DW 1BEh, 107h, 0FFh, 0FFh ; Master volume + +SAM9407EqLBL DW 4 + DW 1BEh, 110h, DATAFLAG, 60h +SAM9407EqLBR DW 4 + DW 1BEh, 114h, DATAFLAG, 60h +SAM9407EqLBF DW 4 + DW 1BEh, 118h, DATAFLAG, 0Ch +SAM9407EqMLBL DW 4 + DW 1BEh, 111h, DATAFLAG, 40h +SAM9407EqMLBR DW 4 + DW 1BEh, 115h, DATAFLAG, 40h +SAM9407EqMLBF DW 4 + DW 1BEh, 119h, DATAFLAG, 1Bh +SAM9407EqMHBL DW 4 + DW 1BEh, 112h, DATAFLAG, 40h +SAM9407EqMHBR DW 4 + DW 1BEh, 116h, DATAFLAG, 40h +SAM9407EqMHBF DW 4 + DW 1BEh, 11Ah, DATAFLAG, 72h +SAM9407EqHBL DW 4 + DW 1BEh, 113h, DATAFLAG, 60h +SAM9407EqHBR DW 4 + DW 1BEh, 117h, DATAFLAG, 60h +SAM9407EqHBF DW 4 + DW 1BEh, 11Bh, DATAFLAG, 0Ch +SAM9407EchoLevel DW 4 + DW 1BEh, 128h, DATAFLAG, 0 +SAM9407EchoTime DW 4 + DW 1BEh, 129h, DATAFLAG, 2Bh +SAM9407EchoFeed DW 4 + DW 1BEh, 12Ah, DATAFLAG, 40h +SAM9407SurroundVolume DW 4 + DW 1BEh, 130h, DATAFLAG, 0 +SAM9407SurroundDelay DW 4 + DW 1BEh, 131h, DATAFLAG, 2 +SAM9407ReverbSend DW 4 + DW 1BEh, 127h, DATAFLAG, 0 +SAM9407ReverbVolume DW 3 + DW 1BEh, 13Ah, DATAFLAG +SAM9407ReverbType DW 4 + DW 1BEh, 169h, DATAFLAG, 4 +SAM9407ReverbTime DW 3 + DW 1BEh, 178h, DATAFLAG +SAM9407ReverbFeedback DW 3 + DW 1BEh, 179h, DATAFLAG +SAM9407ChorusSend DW 4 + DW 1BEh, 124h, DATAFLAG, 0 +SAM9407ChorusVolume DW 3 + DW 1BEh, 13Bh, DATAFLAG +SAM9407ChorusType DW 4 + DW 1BEh, 16Ah, DATAFLAG, 2 +SAM9407ChorusDelay DW 3 + DW 1BEh, 174h, DATAFLAG +SAM9407ChorusFeedback DW 3 + DW 1BEh, 175h, DATAFLAG +SAM9407ChorusRate DW 3 + DW 1BEh, 176h, DATAFLAG +SAM9407ChorusDepth DW 3 + DW 1BEh, 177h, DATAFLAG +SAM9407Mono DW 4 + DW 1BEh, 132h, 7Fh, 0 +SAM9407Stereo DW 4 + DW 1BEh, 132h, 0, 0 + +SAM9407Strings DW Offset SAM9407Reset ;1 + DW Offset SAM9407EqLBL, Offset SAM9407EqLBR + DW Offset SAM9407EqLBF + DW Offset SAM9407EqMLBL, Offset SAM9407EqMLBR + DW Offset SAM9407EqMLBF + DW Offset SAM9407EqMHBL, Offset SAM9407EqMHBR + DW Offset SAM9407EqMHBF + DW Offset SAM9407EqHBL, Offset SAM9407EqHBR + DW Offset SAM9407EqHBF + DW Offset SAM9407EchoLevel ; 14 + DW Offset SAM9407EchoTime + DW Offset SAM9407EchoFeed + DW Offset SAM9407SurroundVolume ; 17 + DW Offset SAM9407SurroundDelay + DW Offset SAM9407ReverbSend ; 19 + DW Offset SAM9407ReverbVolume + DW Offset SAM9407ReverbType + DW Offset SAM9407ReverbTime + DW Offset SAM9407ReverbFeedback ; 23 + DW Offset SAM9407ChorusSend ; 24 + DW Offset SAM9407ChorusVolume + DW Offset SAM9407ChorusType + DW Offset SAM9407ChorusDelay + DW Offset SAM9407ChorusFeedback + DW Offset SAM9407ChorusRate + DW Offset SAM9407ChorusDepth ; 30 + DW Offset SAM9407Mono ; 31 + DW Offset SAM9407Stereo + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +WSSScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW Near Ptr EmptyObject + DW Near Ptr EmptyObject + DW Near Ptr EmptyObject + + DW Near Ptr SAM9407PortText ; 21 + DW Near Ptr SAM9407ParametersText + DW Near Ptr SAM9407ParametersBox + + DW Near Ptr EqLBL ; 24 + DW Near Ptr EqLBR + DW Near Ptr EqLBF + + DW Near Ptr EqMLBL + DW Near Ptr EqMLBR + DW Near Ptr EqMLBF + + DW Near Ptr EqMHBL + DW Near Ptr EqMHBR + DW Near Ptr EqMHBF + + DW Near Ptr EqHBL + DW Near Ptr EqHBR + DW Near Ptr EqHBF + + DW Near Ptr EchoLevel ; 33 + DW Near Ptr EchoTime + DW Near Ptr EchoFeedback + + DW Near Ptr SurroundVolume + DW Near Ptr SurroundDelay + + DW Near Ptr ReverbSend ; 38 + DW Near Ptr ReverbVolume + DW Near Ptr ReverbType + DW Near Ptr ReverbTime + DW Near Ptr ReverbFeedback + + DW Near Ptr ChorusSend + DW Near Ptr ChorusVolume + DW Near Ptr ChorusType + DW Near Ptr ChorusDelay + DW Near Ptr ChorusFeedback + DW Near Ptr ChorusRate + DW Near Ptr ChorusDepth + + + DW 0 + +WSSHeaderLine DW 10 + DB "Sound Track '97 PnP Codec Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 28, 48 + DB 21h + DB "Sound Track Codec Driver 1.0 for Impulse Tracker", 0 + +SAM9407PortText DW 1 + DB 28, 47 + DB 21h + DB "Sound Track SAM9407 Port ", 0FDh, "Xh", 0 +SAM9407Port DW 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right", 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 14 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MasterVolumeRight DW 14 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 8 + +MixModeText DW 1 + DB 2, 17 + DB 20h + DB "Mixing Rate: ", 0FDh, "D", 13, 13 + DB "Mixing mode", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 21, 32, 23, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 24, 32, 26, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 27, 32, 29, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 30, 32, 32, 8 + DB 0 + DB " 32 Bit, Ultra Quality", 0 + +FilterText DW 1 + DB 2, 34 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 36, 29, 38, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 39, 29, 41, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12 +ST42B DW 24, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 42, 29, 44, 8 + DB 0 + DB " 75% Filter", 0 + +SAM9407ParametersText DW 1 + DB 36, 14 + DB 20h + DB "Low Band Left", 13 + DB "Low Band Right", 13 + DB "Low Band Frequency", 13 + DB "Med Low Band Left", 13 + DB "Med Low Band Right", 13 + DB "Med Low Band Frequency", 13 + DB "Med High Band Left", 13 + DB "Med High Band Right", 13 + DB "Med High Band Frequency", 13 + DB "High Band Left", 13 + DB "High Band Right", 13 + DB "High Band Frequency", 13 + DB "Echo Level", 13 + DB "Echo Time", 13 + DB "Echo Feedback", 13 + DB "Surround Volume", 13 + DB "Surround Delay", 13 + DB "Reverb Send", 13 + DB "Reverb Volume", 13 + DB "Reverb Type", 13 + DB "Reverb Time", 13 + DB "Reverb Feedback", 13 + DB "Chorus Send", 13 + DB "Chorus Volume", 13 + DB "Chorus Type", 13 + DB "Chorus Delay", 13 + DB "Chorus Feedback", 13 + DB "Chorus Rate", 13 + DB "Chorus Depth", 13 + DB 0 + +EqLBL DW 14 + DB 60, 14 + DW 0, 127 + DW 9, 2 + DW 13, 25, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBR DW 14 + DB 60, 15 + DW 0, 127 + DW 9, 3 + DW 24, 26, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqLBF DW 14 + DB 60, 16 + DW 0, 127 + DW 9, 4 + DW 25, 27, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBL DW 14 + DB 60, 17 + DW 0, 127 + DW 9, 5 + DW 26, 28, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBR DW 14 + DB 60, 18 + DW 0, 127 + DW 9, 6 + DW 27, 29, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMLBF DW 14 + DB 60, 19 + DW 0, 127 + DW 9, 7 + DW 28, 30, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBL DW 14 + DB 60, 20 + DW 0, 127 + DW 9, 8 + DW 29, 31, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBR DW 14 + DB 60, 21 + DW 0, 127 + DW 9, 9 + DW 30, 32, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqMHBF DW 14 + DB 60, 22 + DW 0, 127 + DW 9, 10 + DW 31, 33, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBL DW 14 + DB 60, 23 + DW 0, 127 + DW 9, 11 + DW 32, 34, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBR DW 14 + DB 60, 24 + DW 0, 127 + DW 9, 12 + DW 33, 35, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EqHBF DW 14 + DB 60, 25 + DW 0, 127 + DW 9, 13 + DW 34, 36, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoLevel DW 14 + DB 60, 26 + DW 0, 127 + DW 9, 15 + DW 35, 37, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoTime DW 14 + DB 60, 27 + DW 0, 127 + DW 9, 14 + DW 36, 38, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +EchoFeedback DW 14 + DB 60, 28 + DW 0, 127 + DW 9, 16 + DW 37, 39, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundVolume DW 14 + DB 60, 29 + DW 0, 255 + DW 9, 17 + DW 38, 40, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SurroundDelay DW 14 + DB 60, 30 + DW 0, 127 + DW 9, 18 + DW 39, 41, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbSend DW 14 + DB 60, 31 + DW 0, 127 + DW 9, 19 + DW 40, 42, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbVolume DW 14 + DB 60, 32 + DW 0, 255 + DW 9, 20 + DW 41, 43, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + + +ReverbType DW 14 + DB 60, 33 + DW 0, 7 + DW 9, 21 + DW 42, 44, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbTime DW 14 + DB 60, 34 + DW 0, 127 + DW 9, 22 + DW 43, 45, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ReverbFeedback DW 14 + DB 60, 35 + DW 0, 127 + DW 9, 23 + DW 44, 46, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusSend DW 14 + DB 60, 36 + DW 0, 127 + DW 9, 24 + DW 45, 47, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusVolume DW 14 + DB 60, 37 + DW 0, 255 + DW 9, 25 + DW 46, 48, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusType DW 14 + DB 60, 38 + DW 0, 7 + DW 9, 26 + DW 47, 49, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDelay DW 14 + DB 60, 39 + DW 0, 127 + DW 9, 27 + DW 48, 50, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusFeedback DW 14 + DB 60, 40 + DW 0, 127 + DW 9, 28 + DW 49, 51, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusRate DW 14 + DB 60, 41 + DW 0, 127 + DW 9, 29 + DW 50, 52, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +ChorusDepth DW 14 + DB 60, 42 + DW 0, 127 + DW 9, 30 + DW 51, 0FFFFh, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + DW 14 + +SAM9407ParametersBox DW 0 + DB 59, 13, 75, 43 + DB 25 + +; MixingRoutines + +MixBufferPos DW 0 + +include dmasirq.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc AD1816Wait + + PushA + Xor CX, CX + Mov DX, CS:BasePort + +AD1816Wait1: + In AL, DX + Test AL, 80h + LoopZ AD1816Wait1 + + PopA + Ret + +EndP AD1816Wait + +; + +Proc AD1816RegisterOut ; AL = indirect register, BX = contents + + Call AD1816Wait + + Push DX + PushF + + ClI + + Mov DX, CS:BasePort + Out DX, AL + Add DL, 2 + + Mov AL, BL + Out DX, AL + Inc DX + Mov AL, BH + Out DX, AL + + PopF + Pop DX + + Ret + +EndP AD1816RegisterOut + +; + +Proc AD1816RegisterIn ; AL = register + ; Returns BX + + Call AD1816Wait + + Push AX + Push DX + + Mov DX, CS:BasePort + Out DX, AL + Add DL, 2 + + In AL, DX + Mov BL, AL + Inc DX + In AL, DX + Mov BH, AL + + Pop DX + Pop AX + + Ret + +EndP AD1816RegisterIn + +; SAM9407InByte + +Proc SAM9407InByte ; Returns AL + + Push CX DX + + Mov DX, CS:SAM9407Port + Inc DX + + Mov CX, 1000h + +SAM9407InByte1: + In AL, DX + Test AL, 80h + LoopNZ SAM9407InByte1 + + Dec DX + In AL, DX + Pop DX CX + + Ret + +EndP SAM9407InByte + +; ST97SendByte + +Proc SAM9407SendByte ; DX = port, AL = data + + Push AX CX DX + Mov DX, CS:SAM9407Port + Mov CX, 1000h + Inc DX + +SAM9407SendByte1: + In AL, DX + Test AL, 40h + LoopNZ SAM9407SendByte1 + + Pop DX CX AX + + Out DX, AL + + Ret + +EndP SAM9407SendByte + +; + +Proc SetSAM9407 ; DI = index. 1 = full reinit. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + LEA SI, [SAM9407Strings+EDI+EDI-2] + Mov SI, [SI] + + LodsW + Mov CX, AX + +SetSAM9407_1: +; AH = 0 = normal data, 1 = command, 2 = param, 3 = ack. + + Mov DX, SAM9407Port + Test DX, DX + JZ NoSAM9407 + + LodsW + + Cmp AH, 2 + JB SetSAM9407_3 + JA SetSAM9407_4 + + Mov AL, [VolumeTable+DI] + Jmp SetSAM9407_2 + +SetSAM9407_4: + Call SAM9407InByte + Test AL, AL + JNZ SetSAM9407_4 + Jmp SetSAM9407_5 + +SetSAM9407_3: + And AH, 1 + Add DL, AH + +SetSAM9407_2: + Call SAM9407SendByte + +SetSAM9407_5: + Dec CX + JNZ SetSAM9407_1 + + +NoSAM9407: + Pop DS + PopA + + Ret + +EndP SetSAM9407 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + + Mov AX, 1 + Ret + +EndP SetFilter + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +PnP_SerialID DD 0 +PnP_VendorID DD 0 +PnP_ReadPort DW 0 +PnP_CSN DB 0 +PnP_CardFound DB 0 + +; + +Proc PnP_Delay + Assume DS:Driver + + Push AX CX + + Mov CX, 180h +PnP_Delay1: + In AL, 21h + Loop PnP_Delay1 + + Pop CX AX + Ret + +EndP PnP_Delay + +; + +Proc PnP_WriteData + + Mov DX, 279h + Out DX, AL + + Mov AL, AH + Mov DH, 0Ah + Out DX, AL + Ret + +EndP PnP_WriteData + +; + +Proc PnP_ReadData + + Mov DX, 279h + Out DX, AL + + Mov DX, PnP_ReadPort + In AL, DX + + Ret + +EndP PnP_ReadData + +; + +Proc PnP_Isolate + + Mov AX, 402h + Call Pnp_WriteData ; Reset CSNs + +PnP_IsolateNextCard: + Mov AX, 0003h + Call PnP_WriteData ; Wake[0] + + Mov AX, PnP_ReadPort + ShL AX, 6 + Xor AL, AL + Call PnP_WriteData ; Set Read Data port. + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov AL, 1 ; Serial Isolation + Mov DX, 279h + Out DX, AL + + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + Call PnP_Delay + + Mov BL, 6Ah + Mov CX, 64 + Mov DX, PnP_ReadPort + + ClI + +PnP_Isolate1: + ShR PnP_SerialID, 1 + RCR PnP_VendorID, 1 + + Mov BH, BL + ShR BH, 1 + Xor BH, BL + ShR BX, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + + Cmp AX, 55AAh + JNE PnP_Isolate2 + + Xor BL, 80h + Or PnP_SerialID, 80000000h + +PnP_Isolate2: + Dec CX + JNZ PnP_Isolate1 + + Mov CX, 8 + Xor BH, BH + +PnP_Isolate3: + ShR BH, 1 + + In AL, DX + Mov AH, AL + Call PnP_Delay + In AL, DX + Call PnP_Delay + Cmp AX, 55AAh + JNE PnP_Isolate4 + + Or BH, 80h + +PnP_Isolate4: + Dec CX + JNZ PnP_Isolate3 + + StI + + Cmp BL, BH ; Matching Checksum? + JNE PnP_IsolateFinished + + ; assign CSN + Inc PnP_CSN + + Mov AL, 6 + MOv AH, PnP_CSN + Call PnP_WriteData + + Cmp PnP_VendorID, PNPVENDORID + JNE PnP_IsolateNextCard + Cmp PnP_SerialID, PNPSERIALID + JNE PnP_IsolateNextCard + + Mov AL, 3 + Call PnP_WriteData + Mov AX, 007h + Call PnP_WriteData + + Mov AL, 64h + Call PnP_ReadData + Mov AH, AL + Mov AL, 65h + Call PnP_ReadData ; AX = address. + Cmp BasePort, 0FFFFh + JE PnPBasePortOK + + Cmp BasePort, AX + JNE PnP_IsolateNextCard + +PnPBasePortOK: + Mov BasePort, AX + + Mov AL, 70h + Call PnP_ReadData ; AL[3:0] = IRQ + And AX, 15 + JZ PnP_IsolateNextCard + Mov IRQ, AX + + Mov AL, 74h + Call PnP_ReadData ; AL[2:0] = DMA + And AX, 7 + Cmp AL, 4 + JE PnP_IsolateNextCard + Mov DMA, AX + + Mov AX, 307h ; LDN 1 - MIDI device + Call PnP_WriteData + + Mov AL, 60h + Call PnP_ReadData + Mov AH, AL + Mov AL, 61h + Call PnP_ReadData ; AX = address. + Test AX, AX + JZ PnP_IsolateNextCard + + Mov SAM9407Port, AX + + Mov Pnp_CardFound, 1 + Jmp PnP_IsolateNextCard + +PnP_IsolateFinished: + Mov AL, PnP_CSN + ShL AL, 1 + Or AL, PnP_CardFound + + Ret + +EndP PnP_Isolate + +; + +Proc DetectCard Far ; returns carry clear if succesful + + Push CS + Pop DS + + Xor AL, AL + Mov DX, 279h + Out DX, AL + Out DX, AL + + Mov AL, 6Ah ; Starting value + Mov CX, 32 + +PnP_InitiationKeyLoop: + Out DX, AL + + Mov AH, AL + ShR AH, 1 + Xor AH, AL + ShR AX, 1 + + Dec CX + JNZ PnP_InitiationKeyLoop + +; Try three ports before concluding no PnP cards: 20Fh, 27Bh, 213h + +PnP_DetectCardPort1: + Mov PnP_ReadPort, 20Fh + Call PnP_Isolate + JZ PnP_DetectCardPort2 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort2: + Mov PnP_ReadPort, 27Bh + Call PnP_Isolate + JZ PnP_DetectCardPort3 + Test AL, 1 + JZ PnP_DetectCardNotFound + Jmp PnP_DetectCardFound + +PnP_DetectCardPort3: + Mov PnP_ReadPort, 213h + Call PnP_Isolate + Test AL, 1 + JNZ PnP_DetectCardFound + +PnP_DetectCardNotFound: + StC + Jmp PnP_DetectEnd + +PnP_DetectCardFound: + ClC + +PnP_DetectEnd: ; Return PnP to wait for key state + Mov AX, 202h + Call PnP_WriteData + Mov EAX, 'Jeff' + + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc ESSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Inc Debug + + Inc DX + In AL, DX + Mov AH, AL + Xor AL, AL + Out DX, AL +; Call AD1816Out + + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB ESSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +ESSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE ESSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +ESSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE ESSIRQHandler4 + Assume DS:Nothing + +ESSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +ESSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE ESSIRQHandler5 + + Mov DX, MixTransferRemaining + +ESSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB ESSIRQHandler6 + JE ESSIRQHFilter + + Cmp CS:Stereo, 0 + JE ESSIRQ3QFilterMono + +ESSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +ESSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +ESSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +ESSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilter: + Cmp CS:Stereo, 0 + JE ESSIRQHFilterMono + +ESSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +ESSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +ESSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +ESSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +ESSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +ESSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ ESSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +ESSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL ESSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG ESSIRQHandlerClip2 + +ESSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ ESSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ ESSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +ESSIRQHandlerClip1: + Mov AX, 8000h + Jmp ESSIRQHandler7 + +ESSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp ESSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp ESSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp ESSIRQ3QFilterStereo3 + +EndP ESSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset ESSIRQHandler + + XChg [ES:BX], EAX + Mov OldESSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldESSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopAD1816 + + PushA + + Mov AL, 1 + Call AD1816RegisterIn + And BX, 07FFFh ; Disable PIE + Call AD1816RegisterOut + + Mov DX, CS:BasePort + Inc DX + In AL, DX + And AL, Not 80h + Out DX, AL + + Add DL, 7 + In AL, DX + And AL, Not 1 + Out DX, AL + + PopA + Ret + +EndP StopAD1816 + +; + +Proc StartAD1816 + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov AL, 4 + Call AD1816RegisterIn + + Mov AL, 32 + Call AD1816RegisterIn + Or BX, 08000h + Call AD1816RegisterOut + + Mov AL, 2 ; Sample rate + Mov BX, MixSpeed + Call AD1816RegisterOut + + Mov AL, 8 ; DMA Size + Mov BX, DMASize + ShR BX, 2 + Dec BX + Call AD1816RegisterOut + + Mov DX, BasePort ; Wave Format + Add DL, 8 + + Mov AL, 00010001b + Cmp Stereo, 0 + JE StartAD1816A + + Or AL, 4 + +StartAD1816A: + Out DX, AL + + Mov AL, 1 ; Enable Playback interrupt + Call AD1816RegisterIn + Or BX, 8000h + Call AD1816RegisterOut + + Pop DS + Pop ES + PopA + + Ret + +EndP StartAD1816 + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Mov AX, MixSpeed + Cmp AX, 11050 + JA ClipMixSpeed1 + + Mov MixSpeed, 11050 + +ClipMixSpeed1: + Cmp AX, 55200 + JB ClipMixSpeed2 + + Mov MixSpeed, 55200 + +ClipMixSpeed2: + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset ESSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Call UpdateSoundcardVariables + + Mov DI, 1 + Call SetSAM9407 + + Mov SI, Offset ESSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Push AX + + Call StopAD1816 + Call ResetIRQ + + Pop ES + Mov AH, 49h ; Release MixSegment + Int 21h + + +UnInitSound1: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + Mov AH, 3Eh + Int 21h + +SetMixMode1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + +DMAPort1 EQU $+1 + In AL, 1 + Mov BL, AL + +DMAPort2 EQU $+1 + In AL, 1 + Mov BH, AL + + Mov CS:Debug2, BX + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Push AX + + Call StopAD1816 + Call StartAD1816 + + Pop DI + And DI, 1 + Add DI, 31 + Call SetSAM9407 + + Mov DI, 2 +SetStereo2: + Call SetSAM9407 + Inc DI + Cmp DI, 30 + JBE SetStereo2 + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSSScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc UpdateSoundcardVariables + + Mov AL, 4 + Mov BX, 3F3Fh + Sub BX, [Word Ptr CS:VolumeTable] + Call AD1816RegisterOut + + Mov AL, 33 + Mov BX, 40h + Call AD1816RegisterOut + + Mov AL, 14 + Xor BX, BX + Call AD1816RegisterOut + + Mov AL, 44 + Xor BX, BX + Call AD1816RegisterOut + + Ret + +EndP UpdateSoundcardVariables + +; + +Proc SetVariable Far + + Mov [CS:VolumeTable+DI], AL + Cmp DI, 31 + JAE SetVariable1 + Cmp DI, 2 + JB SetVariable1 + + Call SetSAM9407 + Ret + +SetVariable1: + Call UpdateSoundcardVariables + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/TEST.ASM b/it/SoundDrivers/TEST.ASM new file mode 100755 index 0000000..ea4a7ed --- /dev/null +++ b/it/SoundDrivers/TEST.ASM @@ -0,0 +1,306 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +; Variables + +TestDriverMsg DB "Test Driver", 13 + DB "(No sound output)", 0 +TestReinitMsg DB "Test driver: Reinitialise received", 0 +Filler DB 8039 Dup (0) + +; EmptyFunction + +Proc EmptyFunction Far + + Xor AX, AX + StC + Ret + +EndP EmptyFunction + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Mov EAX, 'Jeff' + ClC + Ret + +EndP DetectCard + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + + Mov SI, Offset TestDriverMsg + + ClC + Ret + +EndP InitSound + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Push CS + Pop DS + Mov SI, Offset TestReinitMsg + Mov BX, 200 + Call SetInfoLine + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Ret + +EndP UnInitSound + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Call SaveEMSPageFrame + Call Update + Call RestoreEMSPageFrame + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: AX = tempo +; +; + +Proc SetTempo Far + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Xor AX, AX + StC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + DW 0 ; Stop after play flag. +DefaultChannels DW 64 + DW 0 ; Flags, MIDI, Hiqual, Waveform + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/VSND.ASM b/it/SoundDrivers/VSND.ASM new file mode 100755 index 0000000..50a21b0 --- /dev/null +++ b/it/SoundDrivers/VSND.ASM @@ -0,0 +1,1281 @@ +; +; Impulse Tracker VSound Driver +; +; Client for VSound.VxD to interface with Windows. +; Output is always 16-bit stereo, 44100Hz. +; +; + +STEREOENABLED EQU 1 +MIXRESOLUTION EQU 32 ; 32 bit mixing +OUTPUTFILTERENABLED EQU 0 +TIMERCONST EQU 11932 ; 100 times a second +MIXTABLESIZE EQU 2*256*65 +DMABUFFERLENGTH EQU 0 ; Does not have a DMA buffer in the mixsegment + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +; Variables + +OldTimerIRQHandler DD 0 +TimerAccumulator DW 0 + +VSoundNoMemoryMsg DB "Impulse Tracker VSound Driver", 13 + DB "Error: Insufficient memory", 0 +VSoundDriverMsg DB "Impulse Tracker VSound Driver", 0 + +NoReinitMsg DB "VSound driver should NOT require reinitialisation ", 0 + +VSoundIDBuffer DB 8 Dup (0) +VSoundID DB "ITVXDDRV" + +DefaultDriverName DB "ITVSOUND.DRV" +DriverName DD 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 +MixSegment DW 0 + +BytesToMix DW 1000 +MixTransferOffset DW 0 +MixTransferRemaining DW 0 +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 4 +MixMode DW 0 +MixModeOffset DW 0 + +VSoundScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr VSoundHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr ServerText + DW Near Ptr FrequencyText + + DW 0 + + +VSoundHeaderLine DW 10 + DB "Virtual Sound Driver", 0 + +ServerText DW 1 + DB 2, 47 + DB 21h +VSoundString DB 64 Dup (0) + +FrequencyText DW 1 + DB 2, 48 + DB 21h + DB "Playback Frequency: ", 0FDh, "DHz, Buffer Threshold: ", 0FDh, "D bytes", 0 +Threshold DW 21*1024 +MixSpeed DW 44100 + DW 0 + +DriverText DW 1 + DB 2, 46 + DB 21h + DB "Virtual Sound Driver 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MixModeText DW 1 + DB 2, 14 + DB 20h + DB "Mixing Mode", 0 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 16, 32, 18, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 19, 32, 21, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 22, 32, 24, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + + +; MixingRoutines + +MixBufferPos DW 0 + +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +ALIGN 2 + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +include nodebug.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +; + +Proc DetectCard Far + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:Driver + + Mov Forced, AL + + Cmp BX, 217h + JAE DetectCardUseDriver + + Mov CX, DS + ShL ECX, 16 + Mov CX, Offset DefaultDriverName + +DetectCardUseDriver: + Mov DriverName, ECX + +; First need to find if VSound server is setup. + Mov DX, BasePort + Cmp DX, 0FFFFh + JNE PortSpecified + + Mov DX, 400h + Jmp TestPort + +PortSpecified: + Cmp AL, 1 + JNE DetectCardError + + +TestPort: + Mov BasePort, DX + + Xor AL, AL + Out DX, AL ; Reset, get identification + + Mov CX, 8 + Mov DI, Offset VSoundIDBuffer + Rep InsB + + Mov SI, Offset VSoundIDBuffer ; DI now points to VSoundID + Mov CX, 8 + RepE CmpsB + JNE DetectCardError + +; We've found a VSound server. Get ServerString + + Mov AL, 1 + Out DX, AL + ; DI now points to ServerString. + Mov DI, Offset VSoundString + Mov CX, 60 + Rep InsB + + Mov DI, Offset Threshold + Mov CX, 4 + Rep InsB + + Xor DWord Ptr [Threshold], 0FFFFFFFFh + + Mov EAX, 'Jeff' + DB 85h + +DetectCardError: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +InVSound DB -1 + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc VSoundFillBuffer + Assume DS:Nothing + +VSoundHandler3: + + Mov DX, BasePort + Mov AL, 2 + Out DX, AL + In AL, DX + Mov AH, AL + In AL, DX ; AX = BufferSize + + Cmp AX, Threshold + JB VSoundHandler4 + + Ret + +VSoundHandler4: + Call Update + Call MixSamples + +; Convert the buffer + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov CX, BytesToMix ; CX = number of 32-bit samples to mix. + Mov DI, SI + +; Transfer the buffer + Cmp Stereo, 0 + JE VSoundHandlerMono + +VSoundHandlerStereo: + Mov EAX, [SI] + Mov EBX, [SI+4] + + SAR EAX, 13 + SAR EBX, 13 + + Cmp EAX, -8000h + JL VSoundHandlerStereoClip1 + Cmp EAX, 7FFFh + JG VSoundHandlerStereoClip2 + +VSoundHandlerStereo1: + Cmp EBX, -8000h + JL VSoundHandlerStereoClip3 + Cmp EBX, 7FFFh + JG VSoundHandlerStereoClip4 + +VSoundHandlerStereo2: + Mov [DI], AX + Add SI, 8 + Mov [DI+2], BX + Add DI, 4 + + Loop VSoundHandlerStereo + Jmp VSoundHandlerSend + +VSoundHandlerMono: + Mov EAX, [SI] + SAR EAX, 14 + + Cmp EAX, -8000h + JL VSoundHandlerMonoClip1 + Cmp EAX, 7FFFh + JG VSoundHandlerMonoClip2 + +VSoundHandlerMono1: + Mov [DI], AX + Add SI, 8 + Mov [DI+2], AX + Add DI, 4 + + Loop VSoundHandlerMono + +VSoundHandlerSend: + Mov CX, BytesToMix + Mov DX, BasePort + ShL CX, 2 + Add DX, 2 + Mov SI, MixTransferOffset + Rep OutsB + + Jmp VSoundHandler3 + +VSoundHandlerStereoClip1: + Mov AX, 8000h + Jmp VSoundHandlerStereo1 + +VSoundHandlerStereoClip2: + Mov AX, 7FFFh + Jmp VSoundHandlerStereo1 + +VSoundHandlerStereoClip3: + Mov BX, 8000h + Jmp VSoundHandlerStereo2 + +VSoundHandlerStereoClip4: + Mov BX, 7FFFh + Jmp VSoundHandlerStereo2 + + +VSoundHandlerMonoClip1: + Mov AX, 8000h + Jmp VSoundHandlerMono1 + +VSoundHandlerMonoClip2: + Mov AX, 7FFFh + Jmp VSoundHandlerMono1 + + +EndP VSoundFillBuffer + +; + +Proc VSoundHandler + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Add TimerAccumulator, TIMERCONST + JC VSoundHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp VSoundHandler2 + +VSoundHandler1: + PushF + Call [OldTimerIRQHandler] + +VSoundHandler2: + Add InVSound, 1 + JNC VSoundExit + + Call SaveEMSPageFrame + + Assume DS:Nothing + Call VSoundFillBuffer + + Call RestoreEMSPageFrame + +VSoundExit: + Pop ES + Pop DS + PopAD + + Sub CS:InVSound, 1 + IRet + +EndP VSoundHandler + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL ; bump the interrupt to be called + ; 100 times a second. + Mov AX, TIMERCONST + Out 40h, AL + Mov AL, AH + Out 40h, AL + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset VSoundHandler + + ClI + + XChg [ES:20h], EAX ; Hook to timer interrupt + Mov CS:OldTimerIRQHandler, EAX + + StI + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Xor AL, AL + Out 40h, AL ; Interrupt called at normal 18.2 times + Out 40h, AL + + Mov EAX, CS:OldTimerIRQHandler + Mov [ES:20h], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + ; Parags to allocate = (8/(.4*31*16))*MixSpeed + 2080 + ; = .04032258*MixSpeed = (65536*.04032258*MixSpeed) / 65536 + 2080 + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + Mov BX, DX + Mov AH, 48h + Int 21h + + Mov SI, Offset VSoundNoMemoryMsg + JNC InitSound1 + + Pop ES + Ret + +InitSound1: + Mov MixSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset VSoundDriverMsg + Mov AX, BasePort + + ClC + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Push CS + Pop DS + + Mov SI, Offset NoReinitMsg + Mov BX, 40 + Call SetInfoLine + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Mov DS, Word Ptr [CS:DriverName+2] + Mov DX, Word Ptr [CS:DriverName] + + Mov AX, 3D02h ; Read write access + Int 21h + + Push CS + Pop DS + Assume DS:Driver + + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Mov DX, BasePort + Mov AL, 3 + Out DX, AL + + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + ClI + Add CS:InVSound, 1 + JNC Poll1 + + Call VSoundFillBuffer + +Poll1: + Sub CS:InVSound, 1 + StI + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + Assume DS:Nothing + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, AX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Dec CX + JNZ SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset VSoundScreenList + + ClC + + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + DW 0 +DefaultChannels DW 128 + DW 0 + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/VSNDMMX.ASM b/it/SoundDrivers/VSNDMMX.ASM new file mode 100755 index 0000000..bf3c966 --- /dev/null +++ b/it/SoundDrivers/VSNDMMX.ASM @@ -0,0 +1,1097 @@ +; +; Impulse Tracker VSound Driver +; +; Client for VSound.VxD to interface with Windows. +; Output is always 16-bit stereo, 44100Hz. +; +; + +STEREOENABLED EQU 1 +MIXRESOLUTION EQU 32 ; 32 bit mixing +OUTPUTFILTERENABLED EQU 0 +TIMERCONST EQU 11932 ; 100 times a second +DMABUFFERLENGTH EQU 0 ; Does not have a DMA buffer in the mixsegment + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +; Variables + +FPSave DB 128 Dup (0) + +OldTimerIRQHandler DD 0 +TimerAccumulator DW 0 + +VSoundNoMemoryMsg DB "Impulse Tracker VSound Driver", 13 + DB "Error: Insufficient memory", 0 +VSoundDriverMsg DB "Impulse Tracker VSound Driver", 13 + DB "MMX Accelerated Mixing Engine", 0 + +NoReinitMsg DB "VSound driver should NOT require reinitialisation ", 0 + +VSoundIDBuffer DB 8 Dup (0) +VSoundID DB "ITVXDDRV" + +DefaultDriverName DB "ITVSOUND.DRV" +DriverName DD 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 +MixSegment DW 0 + +BytesToMix DW 1000 +MixTransferOffset DW 0 +MixTransferRemaining DW 0 +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 4 +MixMode DW 0 +MixModeOffset DW 0 + +VSoundScreenList Label + DW 6 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr VSoundHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr ServerText + DW Near Ptr FrequencyText + + DW 0 + + +VSoundHeaderLine DW 10 + DB "Virtual Sound Driver (MMX)", 0 + +ServerText DW 1 + DB 2, 47 + DB 21h +VSoundString DB 64 Dup (0) + +FrequencyText DW 1 + DB 2, 48 + DB 21h + DB "Playback Frequency: ", 0FDh, "DHz, Buffer Threshold: ", 0FDh, "D bytes", 0 +Threshold DW 21*1024 +MixSpeed DW 44100 + DW 0 + +DriverText DW 1 + DB 2, 46 + DB 21h + DB "Virtual Sound Driver (MMX) 1.0 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +MixModeText DW 1 + DB 2, 14 + DB 20h + DB "Mixing Mode", 0 + +MixModeButton1 DW 2 + DW 0FFFFh, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 16, 32, 18, 8 + DB 0 + DB " MMX, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 1 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 19, 32, 21, 8 + DB 0 + DB " MMX, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 22, 32, 24, 8 + DB 0 + DB " MMX, Volume Ramped", 0 + +MixModeButton4 DW 2 + DW 8, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 3 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 25, 32, 27, 8 + DB 0 + DB " MMX, Filtered", 0 + + +; MixingRoutines + +MixBufferPos DW 0 + +include mix.inc +include mmx.inc + +include m32bitm.mix +include m32bitmi.mix +include m32bitmv.mix +include m32bitmf.mix + +ALIGN 2 + +MixFunctionTables Label + +include m32bitm.inc +include m32bitmi.inc +include m32bitmv.inc +include m32bitmf.inc +include mnomix.inc + +include nodebug.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 60 + Mul BX + Mov CS:MixModeOffset, AX + + StI + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectMMX + + Trace "Detecting MMX - CPUID Check" + + PushFD + Pop EAX + Mov EBX, EAX + Xor EAX, 00200000h + Push EAX + PopFD + PushFD + Pop EAX + Cmp EAX, EBX + JZ DetectMMXFail + + Trace "CPUID - Check OK" + + Mov EAX, 1 + DB 0Fh, 0A2h ; CPUID + Test EDX, 800000h + JZ DetectMMXFail + + Trace "MMX Detected" + + ClC + Ret + +DetectMMXFail: + Trace "MMX Not Detected" + + StC + Ret + +EndP DetectMMX + +; + +Proc DetectCard Far + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:Driver + + Mov Forced, AL + + Cmp BX, 217h + JAE DetectCardUseDriver + + Mov CX, DS + ShL ECX, 16 + Mov CX, Offset DefaultDriverName + +DetectCardUseDriver: + Mov DriverName, ECX + + Call DetectMMX + JC DetectCardError + +; First need to find if VSound server is setup. + Mov DX, BasePort + Cmp DX, 0FFFFh + JNE PortSpecified + + Mov DX, 400h + Jmp TestPort + +PortSpecified: + Cmp AL, 1 + JNE DetectCardError + + +TestPort: + Mov BasePort, DX + + Xor AL, AL + Out DX, AL ; Reset, get identification + + Mov CX, 8 + Mov DI, Offset VSoundIDBuffer + Rep InsB + + Mov SI, Offset VSoundIDBuffer ; DI now points to VSoundID + Mov CX, 8 + RepE CmpsB + JNE DetectCardError + +; We've found a VSound server. Get ServerString + + Mov AL, 1 + Out DX, AL + ; DI now points to ServerString. + Mov DI, Offset VSoundString + Mov CX, 60 + Rep InsB + + Mov DI, Offset Threshold + Mov CX, 4 + Rep InsB + + Xor DWord Ptr [Threshold], 0FFFFFFFFh + + Mov EAX, 'Jeff' + DB 85h + +DetectCardError: + StC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +include mmxmsam.inc +; + +InVSound DB -1 + +; + +Proc VSoundFillBuffer + Assume DS:Nothing + +VSoundHandler3: + + Mov DX, BasePort + Mov AL, 2 + Out DX, AL + In AL, DX + Mov AH, AL + In AL, DX ; AX = BufferSize + + Cmp AX, Threshold + JB VSoundHandler4 + + Ret + +VSoundHandler4: + Call Update + Call MixSamples + +; Convert the buffer + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov CX, BytesToMix ; CX = number of 32-bit samples to mix. + Mov DI, SI + +; Transfer the buffer + Cmp Stereo, 0 + JE VSoundHandlerMono + +VSoundHandlerStereo: + Add CX, 3 + ShR CX, 2 + +VsoundHandlerStereo1: + MovQ MM0, [SI] ; MM0 = s0r | s0l + MovQ MM1, [SI+8] ; MM1 = s1r | s1l + MovQ MM2, [SI+10h] ; MM2 = s2r | s2l + MovQ MM3, [SI+18h] ; MM3 = s3r | s3l + + PSRADI MM0, 12 + PSRADI MM1, 12 + PSRADI MM2, 12 + PSRADI MM3, 12 + + PackSSDW MM0, MM1 + PackSSDW MM2, MM3 + + MovQM [DI], MM0 + MovQM [DI+8], MM2 + + Add SI, 20h + Add DI, 10h + + Loop VSoundHandlerStereo1 + Jmp VSoundHandlerSend + +VSoundHandlerMono: + Inc CX + ShR CX, 1 + +VSoundHandlerMono1: +; want final to be s1|s1|s0|s0 (16 bits) +; Do 2 samples at a time. + MovD MM0, [SI] + MovD MM1, [SI+8] + MovD MM2, [SI+10h] + MovD MM3, [SI+18h] + + PUnpckLDQ MM0, MM0 + PUnpckLDQ MM1, MM1 + PUnpckLDQ MM2, MM2 + PUnpckLDQ MM3, MM3 + + PSRADI MM0, 13 + PSRADI MM1, 13 + PSRADI MM2, 13 + PSRADI MM3, 13 + + PackSSDW MM0, MM1 + PackSSDW MM2, MM3 + + MovQM [DI], MM0 + MovQM [DI+8], MM2 + + Add SI, 20h + Add DI, 10h + + Loop VSoundHandlerMono1 + +VSoundHandlerSend: + Mov CX, BytesToMix + Mov DX, BasePort + ShL CX, 2 + Add DX, 2 + Mov SI, MixTransferOffset + Rep OutsB + + Jmp VSoundHandler3 + +EndP VSoundFillBuffer + +; + +Proc VSoundHandler + + PushAD + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Add TimerAccumulator, TIMERCONST + JC VSoundHandler1 + + Mov AL, 20h + Out 20h, AL + Jmp VSoundHandler2 + +VSoundHandler1: + PushF + Call [OldTimerIRQHandler] + +VSoundHandler2: + Add InVSound, 1 + JNC VSoundExit + + FNSave [FPSave] + Call SaveEMSPageFrame + + Assume DS:Nothing + Call VSoundFillBuffer + + Call RestoreEMSPageFrame + FNRstor [FPSave] + +VSoundExit: + Pop ES + Pop DS + PopAD + + Sub CS:InVSound, 1 + IRet + +EndP VSoundHandler + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL ; bump the interrupt to be called + ; 100 times a second. + Mov AX, TIMERCONST + Out 40h, AL + Mov AL, AH + Out 40h, AL + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset VSoundHandler + + ClI + + XChg [ES:20h], EAX ; Hook to timer interrupt + Mov CS:OldTimerIRQHandler, EAX + + StI + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Xor AL, AL + Out 40h, AL ; Interrupt called at normal 18.2 times + Out 40h, AL + + Mov EAX, CS:OldTimerIRQHandler + Mov [ES:20h], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + ; Parags to allocate = (8/(.4*31*16))*MixSpeed + ; = .04032258*MixSpeed = (65536*.04032258*MixSpeed) / 65536 + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 5 + Mov BX, DX + Mov AH, 48h + Int 21h + + Mov SI, Offset VSoundNoMemoryMsg + JNC InitSound1 + + Pop ES + Ret + +InitSound1: + Mov MixSegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset VSoundDriverMsg + Mov AX, BasePort + + ClC + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Push CS + Pop DS + + Mov SI, Offset NoReinitMsg + Mov BX, 40 + Call SetInfoLine + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Mov DS, Word Ptr [CS:DriverName+2] + Mov DX, Word Ptr [CS:DriverName] + + Mov AX, 3D02h ; Read write access + Int 21h + + Push CS + Pop DS + Assume DS:Driver + + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call ResetIRQ + +UnInitSound1: + Mov DX, BasePort + Mov AL, 3 + Out DX, AL + + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + ClI + Add CS:InVSound, 1 + JNC Poll1 + + Call VSoundFillBuffer + +Poll1: + Sub CS:InVSound, 1 + StI + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + Assume DS:Nothing + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Jmp CS:RecalculateAllVolumes + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +include loadsam.inc + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset VSoundScreenList + + ClC + + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov CS:InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Push AX + Mov AL, 0F0h +; Call UARTOut + Pop AX + Mov CS:InterpretState, 0 + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: +; Call UARTOut + Ret + +EndP SendUARTOut + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + DW 0 +DefaultChannels DW 128 + DW 3 + DW 4 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/VTABLE.INC b/it/SoundDrivers/VTABLE.INC new file mode 100755 index 0000000..18d8fc6 --- /dev/null +++ b/it/SoundDrivers/VTABLE.INC @@ -0,0 +1,11 @@ + +VariableTableStart Label + +BasePort DW 0FFFFh +IRQ DW 0FFFFh +DMA DW 0FFFFh +CmdLineMixSpeed DW 0 +SongDataArea DW 0 + DB 16-($-VariableTableStart) Dup (0) + + diff --git a/it/SoundDrivers/WAV.MIX b/it/SoundDrivers/WAV.MIX new file mode 100755 index 0000000..1599879 --- /dev/null +++ b/it/SoundDrivers/WAV.MIX @@ -0,0 +1,1608 @@ +; +; WAV output mix functions.... +; Uses Cubic Spline Interpolation +; + +ALIGN 4 + +WAVMixingTable Label + ; 8 bit, 16 bit + ; No sound, stereo, surround + ; No loop, forwards loop, ping pong loop + + DW Offset UpdateNoLoop, 0, 0, 0, 0 + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + + DW Offset MixNoLoop, PreM32SMix8Bit, MFS8Bit, MBS8Bit, Mix32Stereo8Bit + DW Offset MixForwardsLoop, PreM32SMix8Bit, MFS8Bit, MBS8Bit, Mix32Stereo8Bit + DW Offset MixPingPongLoop, PreM32SMix8Bit, MFS8Bit, MBS8Bit, Mix32Stereo8Bit + + DW Offset MixNoLoop, PreM32UMix8Bit, MFS8Bit, MBS8Bit, Mix32Surround8Bit + DW Offset MixForwardsLoop, PreM32UMix8Bit, MFS8Bit, MBS8Bit, Mix32Surround8Bit + DW Offset MixPingPongLoop, PreM32UMix8Bit, MFS8Bit, MBS8Bit, Mix32Surround8Bit + + DW Offset UpdateNoLoop, 0, 0, 0, 0 + DW Offset UpdateForwardsLoop, 0, 0, 0, 0 + DW Offset UpdatePingPongLoop, 0, 0, 0, 0 + + DW Offset MixNoLoop, PreM32SMix16Bit, MFS16Bit, MBS16Bit, Mix32Stereo16Bit + DW Offset MixForwardsLoop, PreM32SMix16Bit, MFS16Bit, MBS16Bit, Mix32Stereo16Bit + DW Offset MixPingPongLoop, PreM32SMix16Bit, MFS16Bit, MBS16Bit, Mix32Stereo16Bit + + DW Offset MixNoLoop, PreM32UMix16Bit, MFS16Bit, MBS16Bit, Mix32Surround16Bit + DW Offset MixForwardsLoop, PreM32UMix16Bit, MFS16Bit, MBS16Bit, Mix32Surround16Bit + DW Offset MixPingPongLoop, PreM32UMix16Bit, MFS16Bit, MBS16Bit, Mix32Surround16Bit + +LastLeftValue DD 0 +LastRightValue DD 0 + +Sample1 DD 0 +Sample2 DD 0 +Sample3 DD 0 +Sample4 DD 0 +SampleValue DD 0 +InterpolationOffset DD 0 +Const3 DD 3.0 +Const1On65536 DD 37800000h +Const256On6 DD 422AAAAAh +Const1On6 DD 3E2AAAAAh +;Const65536 DD 65536.0 +Const32768 DD 32768.0 +Const1On32768 DD 38000000h +;ConstLimiter DD 3F000000h +Const22713_0 DD 22713.0 + +MAXFILTERVALUE EQU 47000000h + +FILTERCLIPPINGTYPENONE EQU 0 +FILTERCLIPPINGTYPECOMPRESSOR EQU 1 +FILTERCLIPPINGTYPELIMIT EQU 0 + +; + +Get8BitWaveform Macro ; Puts waveform value in EBX, range -32k->+32k + Local X + + +IF CUBICINTERPOLATION + + Mov BX, DI + + Push EDX + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Sub BX, 1 + Mov InterpolationOffset, ECX + AdC BX, 0 + + FILD InterpolationOffset + FMul Const1On65536 + + MovSX EAX, Byte Ptr [ES:BX] + MovSX EBX, Byte Ptr [ES:DI] + Mov Sample1, EAX + Mov Sample2, EBX + FILD Sample1 + FILD Sample2 + FMul Const3 + + MovSX EAX, Byte Ptr [ES:DI+1] + MovSX EBX, Byte Ptr [ES:DI+2] + Mov Sample3, EAX + Mov Sample4, EBX + FILD Sample3 + FMul Const3 + FILD Sample4 ; x, 3w, 3v, u, Interp + +; a = x+3v-3w-u +; b = 3w+3u-6v +; c = 6w-2u-x-3v +; d = 6v + +; Assignments: +; F = x+3v +; -> a = F-3w-u +; -> b = 3w+3u-6v +; -> c = 6w-2u-F +; -> d = 6v + +IF INTELOPTIMISED + FAdd ST, ST(2) ; x+3v[3], 3w, 3v, u, Interp + FLd ST(1) ; 3w, x+3v[3], 3w, 3v, u, Interp + FAdd ST, ST(4) ; 3w+u[3], x+3v[2], 3w, 3v, u, Interp + FXCh ST(4) ; u, x+3v[2], 3w, 3v, 3w+u[3], Interp + FAdd ST, ST ; 2u[3], x+3v[1], 3w, 3v, 3w+u[2], Interp + FXCh ST(3) ; 3v, x+3v[1], 3w, 2u[3], 3w+u[2], Interp + FLd ST(1) ; x+3v, 3v, x+3v, 3w, 2u[3], 3w+u[1], Interp + FSub ST, ST(5) ; a[3], 3v, x+3v, 3w, 2u[2], 3w+u, Interp + FXCh ; 3v, a[3], x+3v, 3w, 2u[2], 3w+u, Interp + FAdd ST, ST ; 6v[3], a[2], x+3v, 3w, 2u[1], 3w+u, Interp + FXCh ST(5) ; 3w+u, a[2], x+3v, 3w, 2u[1], 6v[3], Interp + FAdd ST, ST(4) ; 3w+3u[3], a[1], x+3v, 3w, 2u, 6v[2], Interp + FXCh ; a[1], 3w+3u[3], x+3v, 3w, 2u, 6v[2], Interp + FMul ST, ST(6) ; ax[3], 3w+3u[2], x+3v, 3w, 2u, 6v[1], Interp + FXCh ST(2) ; x+3v, 3w+3u[2], ax[3], 3w, 2u, 6v[1], Interp + FAddP ST(4), ST ; 3w+3u[1], ax[2], 3w, 2u+F[3], 6v, Interp + FSub ST, ST(4) ; 3w+3u-6v[3], ax[1], 3w, 2u+F[2], 6v, Interp + FXCh ST(2) ; 3w, ax[1], b[3], 2u+F[1], 6v, Interp + FAdd ST, ST ; 6w[3], ax, b[2], 2u+F, 6v, Interp + FXCh ; ax, 6w[3], b[2], 2u+F, 6v, Interp + FAddP ST(2), ST ; 6w[1], ax+b[3], 2u+f, d, Interp + FSubRP ST(2), ST ; ax+b, c[3], d, Interp + FMul ST, ST(3) ; ax^2+bx[3], c[2], d, Interp + FXCh ST(3) ; Interp, c[2], d, ax^2+bx[3] + FMul Const256On6 ; sInterp[3], c, d, ax^2+bx[1] + FXCh ; c, sInterp[3], d, ax^2+bx[1] + FAddP ST(3), ST ; sInterp[2], d, ax^2+bx+c[3] + FXCh ; d, sInterp[2], ax^2+bx+c[3] + FMul Const256On6 ; sd[3], sInterp[1], ax^2+bx+c[2] + FXCh ; sInterp[1], sd[3], ax^2+bx+c[2] + FMulP ST(2), ST + + Pop DS + Assume DS:Nothing + Mov EDX, [DS:0] + + FAdd ; SampleValue (16 bit value) + + FLd DWord Ptr [DS:0] ; x(k-1), x(k) + FMul DWord Ptr [DS:14h] ; b.x(k-1), x(k) + FLd DWord Ptr [DS:4] ; x(k-2), b.x(k-1), x(k) + FMul DWord Ptr [DS:18h] ; c.x(k-2), b.x(k-1), x(k) + FXCh ST(2) ; x(k), b.x(k-1), c.x(k-2) + FMul DWord Ptr [DS:10h] ; a.x(k), b.x(k-1), c.x(k-2) + FXCh ST(2) ; c.x(k-2), b.x(k-1), a.x(k) + FAdd + Mov EDX, [DS:0] + FAdd + + Mov [DS:4], EDX + + FSt DWord Ptr [DS:0] + FIStP CS:SampleValue + +ELSE + FAdd ST, ST(2) ; x+3v, 3w, 3v, u, Interp + FLd ST(1) ; 3w, x+3v, 3w, 3v, u, Interp + FSub ST, ST(4) ; 3w-u, x+3v, 3w, 3v, u, Interp + FAdd ST, ST ; 6w-2u, x+3v, 3w, 3v, u, Interp + FSub ST, ST(1) ; "c", x+3v, 3w, 3v, u, Interp + FXCh ; x+3v, "c", 3w, 3v, u, Interp + FSub ST, ST(2) ; x+3v-3w, "c", 3w, 3v, u, Interp + FSub ST, ST(4) ; "a", "c", 3w, 3v, u, Interp + FMul ST, ST(5) ; "ax", "c", 3w, 3v, u, Interp + FXCh ST(3) ; 3v, "c", 3w, "ax", u, Interp + FAdd ST, ST ; 6v, "c", 3w, "ax", u, Interp + FXCh ST(4) ; u, "c", 3w, "ax", 6v, Interp + FMul Const3 ; 3u, "c", 3w, "ax", 6v, Interp + FSub ST, ST(4) ; 3u-6v, "c", 3w, "ax", 6v, Interp + FAdd ST, ST(2) ; "b", "c", 3w, "ax", 6v, Interp + FAdd ST, ST(3) ; "ax+b", "c", 3w, "ax", 6v, Interp + FMul ST, ST(5) ; "ax^2+bx", "c", 3w, "ax", 6v, Interp + FAdd ; ax^2+bx+c, 3w, "ax", 6v, Interp + FMulP ST(4), ST ; 3w, "ax", 6v, ax^3+bx^2+cx + FComPP ; 6v, ax^3+bx^2+cx + FAdd ; SampleValue + FMul Const256On6 ; x(k) + + Pop DS + Assume DS:Nothing + + FMul DWord Ptr [DS:10h] + + FLd DWord Ptr [DS:0] ; x(k-1), x(k) + FMul DWord Ptr [DS:14h] ; b.x(k-1), x(k) + FLd DWord Ptr [DS:4] ; x(k-2), b.x(k-1), x(k) + FMul DWord Ptr [DS:18h] ; c.x(k-2), b.x(k-1), x(k) + FAdd + Mov EDX, [DS:0] + FAdd + + Mov [DS:4], EDX + + FSt DWord Ptr [DS:0] + FIStP SampleValue + +ENDIF + Pop EDX + + IF FILTERCLIPPINGTYPENONE + ELSE + Mov EAX, [DS:0] + And EAX, 7FFFFFFFh + Cmp EAX, MAXFILTERVALUE + JBE X + + IF FILTERCLIPPINGTYPECOMPRESSOR + + Mov EBX, [DS:0] + FLd CS:Const22713_0 + FLd DWord Ptr [DS:0] + FAbs + FMul CS:Const1On32768 + FYL2X ; ST = ln(x/65536) / ln(2) * 65536 * ln(2) + FAdd CS:Const32768 + SAR EBX, 31 + FIStP SampleValue + Xor SampleValue, EBX + Sub SampleValue, EBX + +Comment ~ + Mov EBX, [DS:0] + FLd DWord Ptr [DS:0] + FAbs + FSub [CS:Const65536] + FMul [CS:ConstLimiter] + FAdd [CS:Const65536] + SAR EBX, 31 + FIStP SampleValue + Xor SampleValue, EBX + Sub SampleValue, EBX +; FILD SampleValue +; FStP DWord Ptr [DS:0] +~ + ENDIF + IF FILTERCLIPPINGTYPELIMIT + + Mov EBX, [DS:0] + Mov EAX, MAXFILTERVALUE + And EBX, 80000000h + Or EAX, EBX + Mov [DS:0], EAX + ENDIF +X: + ENDIF + Mov EBX, SampleValue + +ENDIF + +IF QUADRATICINTERPOLATION + + Push EDX + Push EBP + + MovSX EDX, Byte Ptr [ES:DI+2] ; v + MovSX EBX, Byte Ptr [ES:DI] ; t + MovSX EAX, Byte Ptr [ES:DI+1] ; u + + LEA EBP, [EBX+EDX] ; v+t + SAR EBP, 1 + Sub EBP, EAX ; (v+t)/2 - u + IMul EBP, ECX ; ax in 8.16 format + SAR EBP, 10 ; ax in 8.6 format + + ShL EAX, 7 ; EBX = 2u<<6 + Add EDX, EBX ; EDX = v+t + Add EBX, EBX ; EAX = 2t + Add EBP, EAX ; EBP = ax+2u + Add EDX, EBX ; 3t+v + ShL EDX, 5 ; (3t+v)/2 << 6 + Sub EBP, EDX ; ax+b + + ShL EBX, 7 + + IMul EBP, ECX ; ax^2+bx in 8.22 form + SAR EBP, 14 ; ax^2+bx in 8.8 form + + Add EBX, EBP ; ax^2+bx+c + + Pop EBP + Pop EDX +ENDIF + + +IF LINEARINTERPOLATION + MovSX EBX, Byte Ptr [ES:DI+1] + MovSX EAX, Byte Ptr [ES:DI] + Sub EBX, EAX + IMul EBX, ECX + SAR EBX, 8 + ShL EAX, 8 + Add EBX, EAX +ENDIF + +IF POINTSAMPLED + MovSX EBX, Byte Ptr [ES:DI] + ShL EBX, 8 +ENDIF + +EndM + +Get16BitWaveform Macro ; Puts waveform value in EBX, range -32k->+32k + Local X + +IF CUBICINTERPOLATION + Mov EBX, EDI + + Push EDX + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Sub BX, 1 + Mov InterpolationOffset, ECX + AdC BX, 0 + + FILD InterpolationOffset + FMul Const1On65536 + + MovSX EAX, Word Ptr [ES:EBX+EBX] + MovSX EBX, Word Ptr [ES:EDI+EDI] + Mov Sample1, EAX + Mov Sample2, EBX + FILD Sample1 + FILD Sample2 + FMul Const3 + + MovSX EAX, Word Ptr [ES:EDI+EDI+2] + MovSX EBX, Word Ptr [ES:EDI+EDI+4] + Mov Sample3, EAX + Mov Sample4, EBX + FILD Sample3 + FMul Const3 + FILD Sample4 ; x, 3w, 3v, u, Interp + + +; a = x+3v-3w-u +; b = 3w+3u-6v +; c = 6w-2u-x-3v +; d = 6v + +; Assignments: +; F = x+3v +; -> a = F-3w-u +; -> b = 3w+3u-6v +; -> c = 6w-2u-F +; -> d = 6v + +IF INTELOPTIMISED + FAdd ST, ST(2) ; x+3v[3], 3w, 3v, u, Interp + FLd ST(1) ; 3w, x+3v[3], 3w, 3v, u, Interp + FAdd ST, ST(4) ; 3w+u[3], x+3v[2], 3w, 3v, u, Interp + FXCh ST(4) ; u, x+3v[2], 3w, 3v, 3w+u[3], Interp + FAdd ST, ST ; 2u[3], x+3v[1], 3w, 3v, 3w+u[2], Interp + FXCh ST(3) ; 3v, x+3v[1], 3w, 2u[3], 3w+u[2], Interp + FLd ST(1) ; x+3v, 3v, x+3v, 3w, 2u[3], 3w+u[1], Interp + FSub ST, ST(5) ; a[3], 3v, x+3v, 3w, 2u[2], 3w+u, Interp + FXCh ; 3v, a[3], x+3v, 3w, 2u[2], 3w+u, Interp + FAdd ST, ST ; 6v[3], a[2], x+3v, 3w, 2u[1], 3w+u, Interp + FXCh ST(5) ; 3w+u, a[2], x+3v, 3w, 2u[1], 6v[3], Interp + FAdd ST, ST(4) ; 3w+3u[3], a[1], x+3v, 3w, 2u, 6v[2], Interp + FXCh ; a[1], 3w+3u[3], x+3v, 3w, 2u, 6v[2], Interp + FMul ST, ST(6) ; ax[3], 3w+3u[2], x+3v, 3w, 2u, 6v[1], Interp + FXCh ST(2) ; x+3v, 3w+3u[2], ax[3], 3w, 2u, 6v[1], Interp + FAddP ST(4), ST ; 3w+3u[1], ax[2], 3w, 2u+F[3], 6v, Interp + FSub ST, ST(4) ; 3w+3u-6v[3], ax[1], 3w, 2u+F[2], 6v, Interp + FXCh ST(2) ; 3w, ax[1], b[3], 2u+F[1], 6v, Interp + FAdd ST, ST ; 6w[3], ax, b[2], 2u+F, 6v, Interp + FXCh ; ax, 6w[3], b[2], 2u+F, 6v, Interp + FAddP ST(2), ST ; 6w[1], ax+b[3], 2u+f, d, Interp + FSubRP ST(2), ST ; ax+b, c[3], d, Interp + FMul ST, ST(3) + FXCh ST(3) ; Interp, c[2], d, ax^2+bx[3] + FMul Const1On6 ; sInterp[3], c, d, ax^2+bx[1] + FXCh ; c, sInterp[3], d, ax^2+bx[1] + FAddP ST(3), ST ; sInterp[2], d, ax^2+bx+c[3] + FXCh ; d, sInterp[2], ax^2+bx+c[3] + FMul Const1On6 ; sd[3], sInterp[1], ax^2+bx+c[2] + FXCh ; sInterp[1], sd[3], ax^2+bx+c[2] + FMulP ST(2), ST + + Pop DS + Assume DS:Nothing + Mov EDX, [DS:0] + + FAdd ; SampleValue (16 bit value) + + FLd DWord Ptr [DS:0] ; x(k-1), x(k) + FMul DWord Ptr [DS:14h] ; b.x(k-1), x(k) + FLd DWord Ptr [DS:4] ; x(k-2), b.x(k-1), x(k) + FMul DWord Ptr [DS:18h] ; c.x(k-2), b.x(k-1), x(k) + FXCh ST(2) ; x(k), b.x(k-1), c.x(k-2) + FMul DWord Ptr [DS:10h] ; a.x(k), b.x(k-1), c.x(k-2) + FXCh ST(2) ; c.x(k-2), b.x(k-1), a.x(k) + FAdd + Mov EDX, [DS:0] + FAdd + + Mov [DS:4], EDX + + FSt DWord Ptr [DS:0] + FIStP CS:SampleValue + +ELSE + FAdd ST, ST(2) ; x+3v, 3w, 3v, u, Interp + FLd ST(1) ; 3w, x+3v, 3w, 3v, u, Interp + FSub ST, ST(4) ; 3w-u, x+3v, 3w, 3v, u, Interp + FAdd ST, ST ; 6w-2u, x+3v, 3w, 3v, u, Interp + FSub ST, ST(1) ; "c", x+3v, 3w, 3v, u, Interp + FXCh ; x+3v, "c", 3w, 3v, u, Interp + FSub ST, ST(2) ; x+3v-3w, "c", 3w, 3v, u, Interp + FSub ST, ST(4) ; "a", "c", 3w, 3v, u, Interp + FMul ST, ST(5) ; "ax", "c", 3w, 3v, u, Interp + FXCh ST(3) ; 3v, "c", 3w, "ax", u, Interp + FAdd ST, ST ; 6v, "c", 3w, "ax", u, Interp + FXCh ST(4) ; u, "c", 3w, "ax", 6v, Interp + FMul Const3 ; 3u, "c", 3w, "ax", 6v, Interp + FSub ST, ST(4) ; 3u-6v, "c", 3w, "ax", 6v, Interp + FAdd ST, ST(2) ; "b", "c", 3w, "ax", 6v, Interp + FAdd ST, ST(3) ; "ax+b", "c", 3w, "ax", 6v, Interp + FMul ST, ST(5) ; "ax^2+bx", "c", 3w, "ax", 6v, Interp + FAdd ; ax^2+bx+c, 3w, "ax", 6v, Interp + FMulP ST(4), ST ; 3w, "ax", 6v, ax^3+bx^2+cx + FComPP ; 6v, ax^3+bx^2+cx + FAdd ; SampleValue + FMul Const1On6 + + Pop DS + Assume DS:Nothing + + FMul DWord Ptr [DS:10h] + + FLd DWord Ptr [DS:0] ; x(k-1), x(k) + FMul DWord Ptr [DS:14h] ; b.x(k-1), x(k) + FLd DWord Ptr [DS:4] ; x(k-2), b.x(k-1), x(k) + FMul DWord Ptr [DS:18h] ; c.x(k-2), b.x(k-1), x(k) + FAdd + Mov EDX, [DS:0] + FAdd + + Mov [DS:4], EDX + + FSt DWord Ptr [DS:0] + FIStP SampleValue +ENDIF + Pop EDX + + IF FILTERCLIPPINGTYPENONE + ELSE + Mov EAX, [DS:0] + And EAX, 7FFFFFFFh + Cmp EAX, MAXFILTERVALUE + JBE X + + IF FILTERCLIPPINGTYPECOMPRESSOR + + Mov EBX, [DS:0] + FLd CS:Const22713_0 + FLd DWord Ptr [DS:0] + FAbs + FMul CS:Const1On32768 + FYL2X ; ST = ln(x/65536) / ln(2) * 65536 * ln(2) + FAdd CS:Const32768 + SAR EBX, 31 + FIStP SampleValue + Xor SampleValue, EBX + Sub SampleValue, EBX + +Comment ~ + Mov EBX, [DS:0] + FLd DWord Ptr [DS:0] + FAbs + FSub [CS:Const65536] + FMul [CS:ConstLimiter] + FAdd [CS:Const65536] + SAR EBX, 31 + FIStP SampleValue + XOr SampleValue, EBX + Sub SampleValue, EBX +; FILD SampleValue +; FStP DWord Ptr [DS:0] +~ + + ENDIF + IF FILTERCLIPPINGTYPELIMIT + + Mov EBX, [DS:0] + Mov EAX, MAXFILTERVALUE + And EBX, 80000000h + Or EAX, EBX + Mov [DS:0], EAX + ENDIF +X: + ENDIF + Mov EBX, SampleValue + +ENDIF + +IF QUADRATICINTERPOLATION + + Push ECX + Push EDX + Push EBP + + MovSX EDX, Word Ptr [ES:EDI+EDI+4] ; v + MovSX EBX, Word Ptr [ES:EDI+EDI] ; t + MovSX EAX, Word Ptr [ES:EDI+EDI+2] ; u + + ShR ECX, 3 ; 0.13 + LEA EBP, [EBX+EDX] + SAR EBP, 1 + Sub EBP, EAX ; (v+t)/2 - u + IMul EBP, ECX ; 16.13 + SAR EBP, 14 ; 15.0 + + Add EDX, EBX ; EDX = v+t + Add EBP, EAX ; EBP = ax+2u + LEA EDX, [EDX+EBX*2] + SAR EDX, 2 ; EDX = (3t+v)/2 + Sub EBP, EDX ; ax + b, 15 form + + IMul EBP, ECX ; ax^2+bx in 15.13 form + SAR EBP, 12 ; ax^2+bx in 16.0 form + + Add EBX, EBP + + Pop EBP + Pop EDX + Pop ECX + +ENDIF + +IF LINEARINTERPOLATION + MovSX EBX, Word Ptr [ES:EDI+EDI+2] + MovSX EAX, Word Ptr [ES:EDI+EDI] + Sub EBX, EAX + SAR EBX, 1 + IMul EBX, ECX + SAR EBX, 15 + Add EBX, EAX +ENDIF + +IF POINTSAMPLED + MovSX EBX, Word Ptr [ES:EDI+EDI] +ENDIF + +EndM + +; + +Proc Mix32Stereo8Bit ; Given DS:SI = buffer + ; Given ES:DI = sample + ; AX = bytes to mix + ; CX = error + ; DX = delta offset + ; BP = delta error + + ShL AX, 3 + Add AX, SI + Mov Word Ptr [CS:M32S8BEND], AX + +Mix32Stereo8Bit1: + Get8BitWaveForm + +M32S8BLVC EQU $+3 + IMul EAX, EBX, 12345678h + Sub [SI], EAX + + Mov CS:LastLeftValue, EAX + +M32S8BRVC EQU $+3 + IMul EAX, EBX, 12345678h + Sub [SI+4], EAX + + Mov CS:LastRightValue, EAX + + Add CX, BP + AdC DI, DX + Add SI, 8 + +M32S8BLVSet EQU $+2 + Mov EAX, 12345678h ; Destination volume left +M32S8BRVSet EQU $+2 + Mov EBX, 12345678h ; Destination volume right + + Sub EAX, DWord Ptr [CS:M32S8BLVC] ; Delta + Sub EBX, DWord Ptr [CS:M32S8BRVC] + + SAR EAX, RAMPSPEED + SAR EBX, RAMPSPEED + + Add DWord Ptr [CS:M32S8BLVC], EAX + Add DWord Ptr [CS:M32S8BRVC], EBX + +M32S8BNoRightRamp: + +M32S8BEND EQU $+2 + Cmp SI, 1234h + JNE Mix32Stereo8Bit1 + + Ret + +EndP Mix32Stereo8Bit + +; + +Proc PreM32SMix8Bit + +IF VOLUMERAMP + PushAD + + Xor EAX, EAX + Xor EBX, EBX + Xor EDX, EDX + Xor EBP, EBP + Xor EDI, EDI + + Mov AX, Word Ptr [SI+0Ch] ; New right volume + Mov BX, Word Ptr [SI+0Eh] ; New left volume + + Mov DX, Word Ptr [SI+1Ch] ; Old right volume + Mov BP, Word Ptr [SI+1Eh] ; Old left volume + + Mov DWord Ptr [CS:M32S8BRVC], EDX + Mov DWord Ptr [CS:M32S8BLVC], EBP + +; Compensate for upwards ramp. + + Cmp AX, DX + JB PreM32Mix8BitNoRightCompensate + + Add AX, RAMPCOMPENSATE + +PreM32Mix8BitNoRightCompensate: + + Cmp BX, BP + JB PreM32Mix8BitNoLeftCompensate + + Add BX, RAMPCOMPENSATE + +PreM32Mix8BitNoLeftCompensate: + Mov DWord Ptr [CS:M32S8BRVSet], EAX + Mov DWord Ptr [CS:M32S8BLVSet], EBX + +; Now to figure out exact final volumes + + Push SI + Mov CX, CS:RealBytesToMix + +PreM32Mix8Bit1: + Mov ESI, EAX ; Set values + Mov EDI, EBX + Sub ESI, EDX ; Current values + Sub EDI, EBP + SAR ESI, RAMPSPEED + SAR EDI, RAMPSPEED + Add EDX, ESI + Add EBP, EDI + + Loop PreM32Mix8Bit1 + + Pop SI + + Mov Word Ptr [SI+1Ch], DX + Mov Word Ptr [SI+1Eh], BP + + PopAD + Ret +ELSE + + Xor EAX, EAX + Xor EBX, EBX + + Mov AX, Word Ptr [SI+0Ch] + Mov BX, Word Ptr [SI+0Eh] + + Mov DWord Ptr [CS:M32S8BRVC], EAX + Mov DWord Ptr [CS:M32S8BLVC], EBX + + Mov DWord Ptr [CS:M32S8BRVSet], EAX + Mov DWord Ptr [CS:M32S8BLVSet], EBX + + Mov [SI+1Ch], AX + Mov [SI+1Eh], BX + + Ret +ENDIF + +EndP PreM32SMix8Bit + +; + +Proc Mix32Surround8Bit ; Given DS:SI = buffer + ; Given ES:DI = sample + ; AX = bytes to mix + ; CX = error + ; DX = delta offset + ; BP = delta error + + ShL AX, 3 + Add AX, SI + Mov Word Ptr [CS:M32U8BEND], AX + +Mix32Surround8Bit1: + Get8BitWaveForm + +M32U8BLVC EQU $+3 + IMul EAX, EBX, 12345678h + Sub [SI], EAX + Mov CS:LastLeftValue, EAX + + Neg EAX +M32U8BLVSet EQU $+2 + Mov EBX, 12345678h + + Sub [SI+4], EAX + Sub EBX, DWord Ptr [CS:M32U8BLVC] + + + SAR EBX, RAMPSPEED + Add SI, 8 + + Add CX, BP + AdC DI, DX + + Add DWord Ptr [CS:M32U8BLVC], EBX + +M32U8BEND EQU $+2 + Cmp SI, 1234h + JNE Mix32Surround8Bit1 + + Mov EAX, CS:LastLeftValue + Neg EAX + Mov CS:LastRightValue, EAX + Ret + +EndP Mix32Surround8Bit + +; + +Proc PreM32UMix8Bit + +IF VOLUMERAMP + Xor EAX, EAX + Xor EBX, EBX + Mov AX, Word Ptr [SI+1Eh] ; Old + Mov BX, Word Ptr [SI+0Eh] ; New + Mov DWord Ptr [CS:M32U8BLVC], EAX + +; Compensate for upwards ramp. + + Cmp BX, AX + JB PreM32MixU8Bit2 + + Add BX, RAMPCOMPENSATE + +PreM32MixU8Bit2: + Mov DWord Ptr [CS:M32U8BLVSet], EBX + + Mov CX, CS:RealBytesToMix + +PreM32UMix8Bit1: + Mov EDX, EBX + Sub EDX, EAX + SAR EDX, RAMPSPEED + Add EAX, EDX + + Loop PreM32UMix8Bit1 + + Mov [SI+1Eh], AX + Ret + +ELSE + Xor EAX, EAX + Mov AX, Word Ptr [SI+0Eh] + Mov DWord Ptr [CS:M32U8BLVC], EAX + Mov DWord Ptr [CS:M32U8BLVSet], EAX + Mov [SI+1Eh], AX + + Ret +ENDIF + +EndP PreM32UMix8Bit + +; + +Proc Mix32Stereo16Bit + + ShL AX, 3 + Add AX, SI + Mov Word Ptr [CS:M32S16BEND], AX + +Mix32Stereo16Bit1: + Get16BitWaveform + +M32S16BLVC EQU $+3 + IMul EAX, EBX, 12345678h + Sub [SI], EAX + + Mov CS:LastLeftValue, EAX + +M32S16BRVC EQU $+3 + IMul EAX, EBX, 12345678h + Sub [SI+4], EAX + + Mov CS:LastRightValue, EAX + + Add CX, BP + AdC DI, DX + +M32S16BLVSet EQU $+2 + Mov EAX, 12345678h ; Destination volume left +M32S16BRVSet EQU $+2 + Mov EBX, 12345678h ; Destination volume right + + Sub EAX, DWord Ptr [CS:M32S16BLVC] ; Delta + Sub EBX, DWord Ptr [CS:M32S16BRVC] + + SAR EAX, RAMPSPEED + SAR EBX, RAMPSPEED + + Add DWord Ptr [CS:M32S16BLVC], EAX + Add DWord Ptr [CS:M32S16BRVC], EBX + + Add SI, 8 + +M32S16BEND EQU $+2 + Cmp SI, 1234h + JNE Mix32Stereo16Bit1 + + Ret + +EndP Mix32Stereo16Bit + +; + +Proc PreM32SMix16Bit + +IF VOLUMERAMP + PushAD + + Xor EAX, EAX + Xor EBX, EBX + Xor EDX, EDX + Xor EBP, EBP + Xor EDI, EDI + + Mov AX, Word Ptr [SI+0Ch] ; New right volume + Mov BX, Word Ptr [SI+0Eh] ; New left volume + + Mov DX, Word Ptr [SI+1Ch] ; Old right volume + Mov BP, Word Ptr [SI+1Eh] ; Old left volume + + Mov DWord Ptr [CS:M32S16BRVC], EDX + Mov DWord Ptr [CS:M32S16BLVC], EBP + +; Compensate for upwards ramp. + + Cmp AX, DX + JB PreM32Mix16BitNoRightCompensate + + Add AX, RAMPCOMPENSATE + +PreM32Mix16BitNoRightCompensate: + + Cmp BX, BP + JB PreM32Mix16BitNoLeftCompensate + + Add BX, RAMPCOMPENSATE + +PreM32Mix16BitNoLeftCompensate: + Mov DWord Ptr [CS:M32S16BRVSet], EAX + Mov DWord Ptr [CS:M32S16BLVSet], EBX + +; Now to figure out exact final volumes + + Push SI + Mov CX, CS:RealBytesToMix + +PreM32Mix16Bit1: + Mov ESI, EAX ; Set values + Mov EDI, EBX + + Sub ESI, EDX ; Current values + Sub EDI, EBP + + SAR ESI, RAMPSPEED + SAR EDI, RAMPSPEED + + Add EDX, ESI + Add EBP, EDI + + Loop PreM32Mix16Bit1 + Pop SI + + Mov Word Ptr [SI+1Ch], DX + Mov Word Ptr [SI+1Eh], BP + + PopAD + Ret +ELSE + + Xor EAX, EAX + Xor EBX, EBX + + Mov AX, Word Ptr [SI+0Ch] + Mov BX, Word Ptr [SI+0Eh] + + Mov DWord Ptr [CS:M32S16BRVC], EAX + Mov DWord Ptr [CS:M32S16BLVC], EBX + + Mov DWord Ptr [CS:M32S16BRVSet], EAX + Mov DWord Ptr [CS:M32S16BLVSet], EBX + + Mov [SI+1Ch], AX + Mov [SI+1Eh], BX + + Ret +ENDIF + +EndP PreM32SMix16Bit + +; + +Proc Mix32Surround16Bit ; Given DS:SI = buffer + ; Given ES:DI = sample + ; AX = bytes to mix + ; CX = error + ; DX = delta offset + ; BP = delta error + + ShL AX, 3 + Add AX, SI + Mov Word Ptr [CS:M32U16BEND], AX + +Mix32Surround16Bit1: + Get16BitWaveForm + +M32U16BLVC EQU $+3 + IMul EAX, EBX, 12345678h + Sub [SI], EAX + +M32U16BLVSet EQU $+2 + Mov EBX, 12345678h + + Neg EAX + Sub EBX, DWord Ptr [CS:M32U16BLVC] + + Sub [SI+4], EAX + + SAR EBX, RAMPSPEED + Add SI, 8 + + Add CX, BP + AdC DI, DX + + Add DWord Ptr [CS:M32U16BLVC], EBX + +M32U16BEND EQU $+2 + Cmp SI, 1234h + JNE Mix32Surround16Bit1 + + Mov CS:LastRightValue, EAX + Neg EAX + Mov CS:LastLeftValue, EAX + Ret + +EndP Mix32Surround16Bit + +; + +Proc PreM32UMix16Bit + +IF VOLUMERAMP + Xor EAX, EAX + Xor EBX, EBX + Mov AX, Word Ptr [SI+1Eh] + Mov BX, Word Ptr [SI+0Eh] + Mov DWord Ptr [CS:M32U16BLVC], EAX + +; Compensate for upwards ramp. + + Cmp BX, AX + JB PreM32MixU16Bit2 + + Add BX, RAMPCOMPENSATE + +PreM32MixU16Bit2: + + Mov DWord Ptr [CS:M32U16BLVSet], EBX + + Mov CX, CS:RealBytesToMix + +PreM32UMix16Bit1: + Mov EDX, EBX + Sub EDX, EAX + SAR EDX, RAMPSPEED + Add EAX, EDX + + Loop PreM32UMix16Bit1 + + Mov [SI+1Eh], AX + Ret + +ELSE + Xor EAX, EAX + Mov AX, Word Ptr [SI+0Eh] + Mov DWord Ptr [CS:M32U16BLVC], EAX + Mov DWord Ptr [CS:M32U16BLVSet], EAX + Mov [SI+1Eh], AX + Ret +ENDIF + +EndP PreM32UMix16Bit + +; + +NUMBEROFFILTERBANDS EQU 4 + +ALIGN 4 +LastClickRemovalLeft DD 0 +LastClickRemovalRight DD 0 +StartingChannelOffset DW 0 +FilterParameters DB 64 Dup (7Fh), 64 Dup (0) +FilterValues DD 4*256 Dup (0) +SampleFilterCopyOffset DW 16*64 +FreqMultiplier DD 3A9F7867h ; = 1/(2*PI*110.0*2^0.25) +FreqParameterMultiplier DD 0B92AAAAAh ; = -1/(24*256) +FilterFreqValue DW 0 +NewControlWord DW 7Fh +include q.inc + +LastFilter DD NUMBEROFFILTERBANDS*2 Dup (0) ; 4 stereo values +FilterCoefficients DD NUMBEROFFILTERBANDS*2 Dup (0) +FilterVolumes DD NUMBEROFFILTERBANDS Dup (0) + +; + +Proc IsSampleMode ; returns zero flag if sample mode. + + Push DS + + Mov DS, CS:SongDataArea + Test Byte Ptr [DS:2Ch], 4 + + Pop DS + Ret + +EndP IsSampleMode + Assume DS:Nothing + +; + +Proc M32MixHandler + ; Clear output buffer first... + + Mov CS:StartingChannelOffset, SI + + Push CX + + Mov ES, CS:MixSegment + Mov EAX, CS:BytesToMixFractional + Mov CX, CS:BytesToMix + Add CurrentFractional, EAX + AdC CX, 0 + Mov CS:RealBytestoMix, CX +; Add CX, CX ; Stereo = 2 * BytesToMix +; Mov DI, 32 +; Xor EAX, EAX +; Rep StosD + + Pop CX + + PushAD + + Mov EDX, CS:LastClickRemovalLeft + Mov EBP, CS:LastClickRemovalRight + +; Do left first. + Mov SI, 80 + Mov CX, CS:RealBytesToMix + +ClickRemoval3: + +Comment ~ + + Mov [ES:SI], EDX + Mov [ES:SI+4], EBP + + Inc EDX + JS ClickRemoval4 + + Sub EDX, 2 + JGE ClickRemoval4 + + Inc EDX + +ClickRemoval4: + Inc EBP + JS ClickRemoval5 + + Sub EBP, 2 + JGE ClickRemoval5 + + Inc EBP + +ClickRemoval5: +~ + + Mov EAX, EDX + Mov EBX, EBP + SAR EAX, 12 + SAR EBX, 12 + Mov [ES:SI], EDX + Mov [ES:SI+4], EBP + + Sub EAX, 1 + AdC EAX, 1 + Sub EBX, 1 + AdC EBX, 1 + + Sub EDX, EAX + Sub EBP, EBX + + Add SI, 8 + Loop ClickRemoval3 + + Mov CS:LastClickRemovalLeft, EDX + Mov CS:LastClickRemovalRight, EBP + + PopAD + + ; Check each channel... + ; Prepare mixing stuff + +; Work backwards + Mov AX, CX + Dec AX + ShL AX, 7 + Add SI, AX + +M32MixHandler1: + Test Byte Ptr [SI], 1 + JZ M32MixHandlerEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE M32MixHandlerEnd2 + + Push CX + Mov BP, SI + Sub BP, [CS:StartingChannelOffset] ; BP = SlaveChannel*128 + SHR BP, 3 ; BP = SlaveChannel*16 + Mov DI, BP + Add BP, Offset FilterValues + + Mov CX, [SI] + Test CH, 2 + JZ M32MixHandler13 + + ; Note cut. + And Byte Ptr [SI], Not 1 ; Turn off channel + Mov Word Ptr [SI+4Ah], 0 + Or CL, 40h + +M32MixHandler13: + Test CL, 20h ; New freq? + JZ M32MixHandler3 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE M32MixHandlerError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +M32MixHandler3: + Test CH, 1 ; New note? + JZ M32MixHandler12 + + Xor EAX, EAX + Mov DWord Ptr [SI+1Ch], EAX + Mov DWord Ptr [CS:BP], EAX + Mov DWord Ptr [CS:BP+4], EAX + Mov DWord Ptr [CS:BP+8], 3F800000h + Mov DWord Ptr [CS:BP+0Ch], EAX + +M32MixHandler12: + Test CX, 8440h ; New volume, loop or pan? + JZ M32MixHandler4 + + Mov AL, [SI+3Ah] + Test AL, AL + JNS M32MixHandlerFilter1 + + Mov BL, [SI+3Fh] + Jmp M32MixHandlerFilter2 + +M32MixHandlerFilter1: + Mov DI, AX + And DI, 63 + Add DI, Offset FilterParameters + + Mov AL, [CS:DI] + Mov BL, [CS:DI+64] + Mov [SI+5Bh], AL + Mov [SI+3Fh], BL + +M32MixHandlerFilter2: + Mov AL, [SI+3Eh] + Mul Byte Ptr [SI+5Bh] + Mov CS:FilterFreqValue, AX + ShR AX, 8 + Mov AH, BL + AdC AX, 0 + + Cmp AX, 7Fh + JE M32MixHandlerNoFilter + + And BX, 0FFh + ShL BX, 2 + + FNInit + FLdCW [CS:NewControlWord] + + FILD [CS:FilterFreqValue] ; 0->127*256 + FMul [CS:FreqParameterMultiplier] ; -i/(24*256) + FLd ST + FRndInt + FSub ST(1), ST + FXCh + F2XM1 + FLd1 + FAdd + FScale ; = 2^(i/24*256) + FMul [CS:FreqMultiplier] ; = r + FLd ST ; r, r + FMul ST(1), ST ; r, r^2 + + FLd [CS:QualityFactorTable+BX] ; 2d, r, r^2 + FMul ST(1), ST ; 2d, 2dr, r^2 + FLd1 ; 1, 2d, 2dr, r^2 + FSubP ST(1), ST ; 2d-1, 2dr, r^2 + FAdd + + FLd1 ; 1, d, e + FAdd ST, ST(1) + FAdd ST, ST(2) ; 1+d+e, d, e + FLd1 ; 1, 1+d+e, d, e + FDivRP ST(1), ST ; 1/(1+d+e), d, e + FSt DWord Ptr [CS:BP+8] + FXCh ; d, 1/(1+d+e), e + FAdd ST, ST(2) + FAddP ST(2), ST ; 1/(1+d+e), d+2e + FMul + FStP DWord Ptr [CS:BP+0Ch] + FStP ST + +M32MixHandlerNoFilter: + +IF REGISTERED + Test CH, 8 + JNZ M32MixHandler7 + + Cmp CS:Stereo, 0 + JE M32MixHandler6 + + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE M32MixHandler6 + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + SHRD AX, DX, 14 + + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] ; Final volume + SHRD AX, DX, 14 + Mov [SI+0Eh], AX + + ; Now to decide on mixing method + Cmp DWord Ptr [SI+0Ch], 0 + JNE M32MixHandler5 +ELSE + Test CH, 8 + JZ M32MixHandler6 + +ENDIF + +M32MixHandler7: + ; Zero volume + Xor EAX, EAX + Mov [SI+0Ch], EAX + Cmp [SI+1Ch], EAX ; Last volumes = 0? + JE M32MixHandler8 + +M32MixHandler5: ; Other.. (ie. panned) + Mov AX, 30 + Jmp M32MixHandler8 + +M32MixHandler6: ; Surround sound + Mov AX, [SI+4Ah] + Mul MixVolume + +IF REGISTERED + ShRD AX, DX, 8 + Cmp CS:Stereo, 0 + JE M32MixHandlerHalfStereoVolume + + ShR AX, 1 + +M32MixHandlerHalfStereoVolume: + +ELSE + + ShRD AX, DX, 9 +ENDIF + + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + + Test AX, AX + JNZ M32MixHandlerSurround1 + + Cmp DWord Ptr [SI+1Ch], 0 + JE M32MixHandler7 + +M32MixHandlerSurround1: + Mov AX, 60 + +M32MixHandler8: + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 + JZ M32MixHandler9 + + Add AX, 90 + +M32MixHandler9: + Cmp BL, 8 + JB M32MixHandler11 ; No loop + JE M32MixHandler10 + + Add AX, 10 + +M32MixHandler10: + Add AX, 10 + +M32MixHandler11: + Add AX, Offset WAVMixingTable + Mov [SI+8], AX ; Offset... + +M32MixHandler4: + ; Mixing routine call... + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, RealBytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, 80 + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Cmp CS:StartNoRamp, 0 + JE NoStartRamp + + Test CH, 1 + JZ NoStartRamp + Cmp DWord Ptr [SI+4Ch], 0 + JNE NoStartRamp + + Mov EAX, [SI+0Ch] + Mov [SI+1Ch], EAX + +NoStartRamp: + + Mov ES, CS:MixSegment ; Get filter data + Mov EAX, [CS:BP] ; Last sample 1 + Mov EDX, [CS:BP+4] ; Last sample 2 + Mov [ES:0], EAX + Mov [ES:4], EDX + Mov EAX, [CS:BP+8] ; Filtera + Mov EDX, [CS:BP+0Ch] ; Filterb + Mov [ES:10h], EAX + Mov [ES:14h], EDX + FLd1 + FSub DWord Ptr [ES:10h] + FSub DWord Ptr [ES:14h] + FStP DWord Ptr [ES:18h] ; Filterc + + Push BP + Call Word Ptr [CS:BX] + Pop BP + + Mov ES, CS:MixSegment ; Store filter data + Mov EAX, [ES:0] + Mov EDX, [ES:4] + Mov [CS:BP], EAX + Mov [CS:BP+4], EDX + + And Word Ptr [SI], 0111100010001101b + + Call IsSampleMode + JNE M32MixHandlerEnd + + Mov [CS:BP+16*64], EAX + Mov [CS:BP+16*64+4], EDX + Mov EAX, [CS:BP+8] + Mov EDX, [CS:BP+0Ch] + Mov [CS:BP+16*64+8], EAX + Mov [CS:BP+16*64+0Ch], EDX + + Jmp M32MixHandlerEnd + +M32MixHandlerError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ M32MixHandlerEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +M32MixHandlerEnd: + Pop CX + +M32MixHandlerEnd2: + Sub SI, 128 + Dec CX + JNZ M32MixHandler1 + + Push CS + Pop DS + Assume DS:Driver + + Xor DI, DI + Mov SI, Offset LastFilter + Mov CX, 80/4 + Mov ES, MixSegment + + Rep MovsD + +; Now do filtering. + FNInit + Mov CX, RealBytesToMix + + Push ES + Pop DS + Assume DS:Nothing + + Mov SI, 80 + +OutputFilter1: + FILD DWord Ptr [SI] ; Left sample + FILD DWord Ptr [SI+4] ; R, L + + FLd DWord Ptr [DS:20h] ; LB, R, L + FMul ST, ST(2) ; L.LB, R, L + FLd DWord Ptr [DS:20h] ; LB, L.LB, R, L + FMul ST, ST(2) ; R.LB, L.LB, R, L + FLd DWord Ptr [DS:0] ; OL, R.LB, L.LB, R, L + FMul DWord Ptr [DS:24h] ; OL.LB, R.LB, L.LB, R, L + FLd DWord Ptr [DS:4] ; OR, OL.LB, R.LB, L.LB, R, L + FMul DWord Ptr [DS:24h] ; OR.LB, OL.LB, R.LB, L.LB, R, L + + FXCh ; OL.LB, OR.LB, R.LB, L.LB, R, L + FAddP ST(3), ST + FAdd ; RLB, LLB, R, L + + FLd DWord Ptr [DS:28h] ; MB, RLB, LLB, R, L + FMul ST, ST(4) ; L.MB, RLB, LLB, R, L + FLd DWord Ptr [DS:28h] ; MB, L.MB, RLB, LLB, R, L + FMul ST, ST(4) ; R.MB, L.MB, RLB, LLB, R, L + FLd DWord Ptr [DS:8] ; OL, R.MB, L.MB, RLB, LLB, R, L + FMul DWord Ptr [DS:2Ch] ; OL.MB, R.MB, L.MB, RLB, LLB, R, L + FLd DWord Ptr [DS:0Ch] ; OR, OL.MB, R.MB, L.MB, RLB, LLB, R, L + FMul DWord Ptr [DS:2Ch] ; OR.MB, OL.MB, R.MB, L.MB, RLB, LLB, R, L + + FXCh ; OL.MB, OR.MB, R.MB, L.MB, RLB, LLB, R, L + FAddP ST(3), ST + FAdd ; RMB, LMB, RLB, LLB, R, L + FXCh ST(3) ; LLB, LMB, RLB, RMB, R, L + FStP DWord Ptr [DS:0] + FStP DWord Ptr [DS:8] + FStP DWord Ptr [DS:4] + FStP DWord Ptr [DS:0Ch] + + FLd DWord Ptr [DS:30h] + FMul ST, ST(2) + FLd DWord Ptr [DS:30h] + FMul ST, ST(2) + FLd DWord Ptr [DS:10h] + FMul DWord Ptr [DS:34h] + FLd DWord Ptr [DS:14h] + FMul DWord Ptr [DS:34h] + + FXCh + FAddP ST(3), ST + FAdd + + FLd DWord Ptr [DS:38h] + FMul ST, ST(4) + FLd DWord Ptr [DS:38h] + FMul ST, ST(4) + FLd DWord Ptr [DS:18h] + FMul DWord Ptr [DS:3Ch] + FLd DWord Ptr [DS:1Ch] + FMul DWord Ptr [DS:3Ch] + + FXCh + FAddP ST(3), ST + FAdd + FXCh ST(3) + FStP DWord Ptr [DS:10h] + FStP DWord Ptr [DS:18h] + FStP DWord Ptr [DS:14h] + FStP DWord Ptr [DS:1Ch] ; R, L + +; For each one, output value += ((band value) - (previous band value)) * Volume + + FLd DWord Ptr [DS:18h] + FSub DWord Ptr [DS:10h] ; L4, R, L + FLd DWord Ptr [DS:1Ch] + FSub DWord Ptr [DS:14h] ; R4, L4, R, L + FLd DWord Ptr [DS:10h] + FSub DWord Ptr [DS:8] + FLd DWord Ptr [DS:14h] + FSub DWord Ptr [DS:0Ch] ; R3, L3, R4, L4, R, L + FLd DWord Ptr [DS:8] + FSub DWord Ptr [DS:0] + FLd DWord Ptr [DS:0Ch] + FSub DWord Ptr [DS:4] ; R2, L2, R3, L3, R4, L4, R, L + FXCh ST(5) ; L4, L2, R3, L3, R4, R2, R, L + FMul DWord Ptr [DS:4Ch] ; L4V, L2, R3, L3, R4, R2, R, L + FXCh ST(4) ; R4, L2, R3, L3, L4V, R2, R, L + FMul DWord Ptr [DS:4Ch] ; R4V, L2, R3, L3, L4V, R2, R, L + FXCh ST(3) ; L3, L2, R3, R4V, L4V, R2, R, L + FMul DWord Ptr [DS:48h] ; L3V, L2, R3, R4V, L4V, R2, R, L + FXCh ST(2) ; R3, L2, L3V, R4V, L4V, R2, R, L + FMul DWord Ptr [DS:48h] ; R3V, L2, L3V, R4V, L4V, R2, R, L + FXCh ; L2, R3V, L3V, R4V, L4V, R2, R, L + FMul DWord Ptr [DS:44h] ; L2V, R3V, L3V, R4V, L4V, R2, R, L + FXCh ST(5) ; R2, R3V, L3V, R4V, L4V, L2V, R, L + FMul DWord Ptr [DS:44h] ; R2V, R3V, L3V, R4V, L4V, L2V, R, L + FXCh ST(4) ; L4V, R3V, L3V, R4V, R2V, L2V, R, L + FAddP ST(7), ST ; R3V, L3V, R4V, R2V, L2V, R, L + FAddP ST(5), ST ; L3V, R4V, R2V, L2V, R, L + FAddP ST(3), ST + FAdd + FLd DWord Ptr [DS:0] + FMul DWord Ptr [DS:40h] ; L1V, RV, LV, R, L + FLd DWord Ptr [DS:4] ; + FMul DWord Ptr [DS:40h] ; R1V, L1V, RV, LV, R, L + FXCh ST(2) ; RV, L1V, R1V, LV, R, L + FAddP ST(4), ST ; L1V, R1V, LV, R, L + FAddP ST(4), ST ; R1V, LV, R, L + FAddP ST(2), ST + FAddP ST(2), ST + + FIStP DWord Ptr [SI+4] + FIStP DWord Ptr [SI] + + Add SI, 8 + Dec CX + JNZ OutputFilter1 + +; Transfer contents out + Push CS + Pop ES + + Mov DI, Offset LastFilter + Xor SI, SI + Mov CX, 32/4 + + Rep MovsD +; Finished output filtering! + + Ret + +EndP M32MixHandler + +; diff --git a/it/SoundDrivers/WAVDRV.ASM b/it/SoundDrivers/WAVDRV.ASM new file mode 100755 index 0000000..e2c9441 --- /dev/null +++ b/it/SoundDrivers/WAVDRV.ASM @@ -0,0 +1,1601 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +STEREOENABLED EQU 1 +MIXRESOLUTION EQU 32 + +include ..\wavswitc.inc + +FileHandle DW 0 +NumClipped DD 0 + +WAVOutputMsg DB "Writing to disk", 13 + DB "Output frequency ", 0FDh, "D", 0 +WAVFileErrorMsg DB "Unable to create output file! ", 0 +WAVMemErrorMsg DB "Unable to allocate memory!", 0 +NoReinitMsg DB "File output routines should NOT require reinitialisation ", 0 +WriteError DB "Error writing to output file. Output file closed ", 0 +DefaultDriverName DB "ITWAV.DRV", 0 +DriverName DD 0 +ClippedMsg DB "Clipped ", 0FDh, "L", 0 + +WAVEFileHeader DB "RIFF" +WAVEFileSize DD 0 +WAVEFileHeader2 DB "WAVEfmt " +WAVEFileHeaderLength DD 10h +WAVEFileID DW 1 +WAVEChannels DW 1 ; 1 = mono, 2 = stereo +MixSpeed DW 44100 ; Default to CD quality +WAVEMixSpeedFiller DW 0 +WAVEBytesPerSecond DD 0 +WAVEBytesPerSample DW 2 +WAVEBits DW 16 +WAVEHeader3 DB "data" +WAVEDataSize DD 0 + +IF REGISTERED + Stereo DB 0 + StereoSet DB 0 +ENDIF + +BytesToMix DW 0 +RealBytesToMix DW 0 +BytesToMixFractional DD 0 +CurrentFractional DD 0 + +MixVolume DW 0 +MixSegment DW 0 +MixHandler DW Offset M32MixHandler +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 90 +WAVDirectory DB ".", 79 Dup (0) +VolumeTable DB 0, 16, 96, 127 + DB 0, 0, 0, 0 +StartNoRamp DW 0 +OldDirectory DB 80 Dup (0) + +CreatingMsg DB "Creating file " +OutputFileName DB " ", 0 + +ClosedFileMsg DB "Finished writing file ", 0 +OUTPUT DB "OUTPUT" + +LongMixSpeed DD 0 + +IF DITHEROUTPUT +MonoDitherValue DD 0 +LeftDitherValue DD 0 +RightDitherValue DD 0 +ENDIF + +WAVScreenList DW 6 + DW IdleFunctionList + DW GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WAVHeader + + DW Near Ptr FilterBox1 + DW Near Ptr DirectoryInputBox + DW Near Ptr DirectoryInput ; 6 + + DW Near Ptr FilterBox2 + DW Near Ptr FilterFrequency1 ; 8 + DW Near Ptr FilterFrequency2 + DW Near Ptr FilterFrequency3 + DW Near Ptr FilterFrequency4 + DW Near Ptr FilterVolume1 + DW Near Ptr FilterVolume2 + DW Near Ptr FilterVolume3 + DW Near Ptr FilterVolume4 + + DW Near Ptr DirectoryInputText + DW Near Ptr FilterText + + DW Near Ptr StartRampText + DW Near Ptr StartRampEnabledButton ; 19 + DW Near Ptr StartRampDisabledButton + + DW 0 + +WAVHeader DW 10 + DB "WAV Driver", 0 + +StartRampText DW 1 + DB 2, 25 + DB 20h + DB "Ramp volume at start of sample", 0 + +StartRampEnabledButton DW 2 + DW 11, 0FFFFh, 20, 20 + DW 0, 0, 0 + DW 5 + DW Offset StartNoRampFunction +Seg1 DW 0 + DW 0 + DW 0, 0 + DB 33, 24, 47, 26 + DB 8, 0 + DB " Enabled", 0 + +StartRampDisabledButton DW 2 + DW 11, 0FFFFh, 19, 19 + DW 0, 0, 0 + DW 5 + DW Offset StartNoRampFunction +Seg2 DW 0 + DW 1 + DW 0, 0 + DB 48, 24, 62, 26 + DB 8, 0 + DB " Disabled", 0 + +IdleFunctionList DD 0 + DD 0 +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +DirectoryInputText DW 1 + DB 2, 14 + DB 20h + DB "Output Directory", 0 + +DirectoryInputBox DW 0 + DB 18, 13, 78, 15 + DB 25 + +DirectoryInput DW 16 + DB 19, 14 +Segment1 DW 0 + DW Offset WAVDirectory + DW 59 + DD 0 + DW 0FFFFh, 8, 0FFFFh, 0FFFFh + +FilterText DW 1 + DB 2, 17 + DB 20h + DB "Output Equalizer", 13 + DB 13 + DB " Low Frequency Band", 13 + DB " Med Low Frequency Band", 13 + DB "Med High Frequency Band", 13 + DB " High Frequency Band", 0 + +FilterBox1 DW 0 + DB 25, 18, 47, 23 + DB 25 + +FilterBox2 DW 0 + DB 52, 18, 74, 23 + DB 25 + +FilterFrequency1 DW 14 + DB 26, 19 + DW 0, 127 + DW 9, 0 + DW 6, 9, 12, 12 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency2 DW 14 + DB 26, 20 + DW 0, 127 + DW 9, 1 + DW 8, 10, 13, 13 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency3 DW 14 + DB 26, 21 + DW 0, 127 + DW 9, 2 + DW 9, 11, 14, 14 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterFrequency4 DW 14 + DB 26, 22 + DW 0, 127 + DW 9, 3 + DW 10, 19, 15, 15 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume1 DW 14 + DB 53, 19 + DW 0, 255 + DW 9, 4 + DW 6, 13, 8, 8 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume2 DW 14 + DB 53, 20 + DW 0, 255 + DW 9, 5 + DW 12, 14, 9, 9 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume3 DW 14 + DB 53, 21 + DW 0, 255 + DW 9, 6 + DW 13, 15, 10, 10 + DW 0FFFFh, 0FFFFh + DW 20 + +FilterVolume4 DW 14 + DB 53, 22 + DW 0, 255 + DW 9, 7 + DW 14, 19, 11, 11 + DW 0FFFFh, 0FFFFh + DW 20 + +IF WAREZWAVE + Filename1 DB 01h, 0C8h, 0E6h, 01h, 0F5h, 0F7h, 0F7h, 03h, 0F4h, 0FEh, 0D4h, 01h, 0F5h, 0F7h, 0C2h ; COMMAND.COM + Filename2 DB 01h, 0C8h, 0E6h, 0FBh, 0F5h, 0D4h, 0F1h, 0EBh, 0F1h, 0C2h ; IO.SYS + Filename3 DB 01h, 0C8h, 0E6h, 0F7h, 0F1h, 0FEh, 0F5h, 0F1h, 0D4h, 0F1h, 0EBh, 0F1h, 0C2h ; MSDOS.SYS + LocalDirectory DB ".", 60 Dup(0) +ENDIF + +include mixwav.inc + +include wav.mix + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + + +Proc DetectCard Far + + Cmp BX, 217h + JAE DetectCardUseDriver + + Mov CX, DS + ShL ECX, 16 + Mov CX, Offset DefaultDriverName + +DetectCardUseDriver: + Mov [CS:DriverName], ECX + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + Mov Seg1, CS + MOv Seg2, CS + +IF WAREZWAVE + +; Decode things + Push CS + Push CS + Pop DS + Pop ES + Assume DS:Driver + + Mov CX, 3 + + Mov SI, Offset Filename1 + Mov DI, Offset Filename1 + +DetectCard1: + + LodsB + Sub AL, 24h + Xor AL, 9Eh + StosB + + JNZ DetectCard1 + Loop DetectCard1 + +ENDIF + + Mov EAX, 'Jeff' + ClC ; Always assume true + Ret + +EndP DetectCard + +; + +InterpretState DB 0 +InterpretType DB 0 + +Proc SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h. + + Mov AH, CS:InterpretState + Cmp AH, 2 + JB SendUARTOut1 + +; In interpreter. + JE SendUARTOut3 + +; Have InterpretType, now get parameter, then return to normal. + + Cmp AL, 7Fh + JA SendUARTOut4 + + Push BX + + Mov BL, CS:InterpretType ; Want BX = InterpretType*64+Channel + ; + ShL BX, 6 + Add BL, [DI+20h] + And BX, 127 + Mov [CS:FilterParameters+BX], AL + + Pop BX + + Test SI, SI + JZ SendUARTOut4 + + Or Byte Ptr [SI], 64 + +SendUARTOut4: + Mov CS:InterpretState, 0 + Ret + +SendUARTOut3: + Cmp AL, 2 + JAE SendUARTOut4 + + Mov InterpretType, AL + Jmp SendUARTOutStateInc + +SendUARTOut1: + Cmp AL, 0F0h + JNE SendUARTOut2 + +SendUARTOutStateInc: + Inc CS:InterpretState + Ret + +SendUARTOut2: + Test AH, AH + JZ SendUARTOutEnd + + Mov CS:InterpretState, 0 + Ret + +SendUARTOutEnd: + Cmp AL, 0FCh + JE ResetFilters + Cmp AL, 0FAh + JE ResetFilters + + Cmp AL, 0FFh + JNE SendUARTOutNoClear + +ResetFilters: + PushA + Push ES + + Push CS + Pop ES + + Mov DI, Offset FilterParameters + Mov CX, 64 + Mov AL, 7Fh + Rep StosB + Mov CX, 64 + Xor AX, AX + Rep StosB + + Pop ES + PopA + +SendUARTOutNoClear: + Ret + +EndP SendUARTOut + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov Segment1, DS + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GotoHomeDirectory + Mov SI, Offset WAVDirectory + Call SetDirectory + + Mov AH, 48h + Mov BX, 2648 ; (65536 / (.4*31)) * 4 * 2 + ; +80 (filtering area) + Int 21h + JNC InitSound1 + + Mov SI, Offset WAVMemErrorMsg + Ret + +InitSound1: + Mov MixSegment, AX + + Mov SI, Offset WAVOutputMsg + + Mov AX, CmdLineMixSpeed + And AX, AX + JZ InitSound3 + + Cmp AX, 8000 + JA InitSound4 + + Mov AX, 8000 + +InitSound4: + Cmp AX, 64000 + JB InitSound5 + + Mov AX, 64000 + +InitSound5: + Mov MixSpeed, AX + +InitSound3: + Mov AX, MixSpeed + Mov Word Ptr LongMixSpeed, AX + + FNInit + FILd DWord Ptr [MixSpeed] + FMul FreqMultiplier + FStP FreqMultiplier + + Call CalculateFilterCoefficients + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Push CS + Pop DS + + Mov SI, Offset NoReinitMsg + Mov BX, 40 + Call SetInfoLine + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Call GotoHomeDirectory + + Mov DS, Word Ptr [CS:DriverName+2] + Mov DX, Word Ptr [CS:DriverName] + + Mov AX, 3D02h ; Read write access + Int 21h + + Push CS + Pop DS + Assume DS:Driver + + JC SaveConfig2 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SaveConfig1 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset WAVDirectory + Int 21h + +SaveConfig1: + Mov AH, 3Eh + Int 21h + +SaveConfig2: + Mov AX, MixSegment + Test AX, AX + JZ UnInitsound1 + + Mov ES, AX + Mov AH, 49h + Int 21h + +UnInitSound1: + Mov BX, FileHandle + Test BX, BX + JZ UnInitSound2 + + Mov AX, 4200h ; Move to start of file + Xor CX, CX + Xor DX, DX + Int 21h ; Start of file + + Mov EAX, WAVEDataSize + Add EAX, 24h + Mov WAVEFileSize, EAX + + Mov AH, 40h + Mov DX, Offset WAVEFileHeader + Mov CX, 2Ch + Int 21h + + Mov AH, 3Eh + Int 21h + +UnInitSound2: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; + +Proc CopyFileName ; Given DI + + Push DS + + Call GetFileName + Assume DS:Nothing ; Returns DS:SI + + Push CS + Pop ES + Mov CX, 11 + Mov AL, ' ' + Push DI + Rep StosB + Pop DI + + Mov CX, 8 + + Cmp Byte Ptr [SI], 0 + JE CopyFileName2 + Cmp Byte Ptr [SI], '.' + JE CopyFileName2 + +CopyFileName1: + LodsB + Cmp AL, '.' + JE CopyFileName3 + StosB + Loop CopyFileName1 + + Pop DS + Ret + +CopyFileName2: + Push CS + Pop DS + Mov SI, Offset OUTPUT + Mov CX, 6 + Rep MovsB + +CopyFileName3: + Pop DS + Ret + +EndP CopyFileName + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; BX = pattern +; +; + +SlaveChannelLocation DW 0, 0, 0 + +Proc Poll Far + + Cmp MixSegment, 0 + JNE Poll2 + + Ret + +Poll2: + Push BX + Call Update ; Got DS:SI, CX + Pop BX + + Mov CS:[SlaveChannelLocation], SI + Mov CS:[SlaveChannelLocation+2], DS + Mov CS:[SlaveChannelLocation+4], CX + + Test AX, AX + JNZ Poll1 + + Cmp CS:FileHandle, 0 + JE Poll7 + + PushAD + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset ClosedFileMsg + Mov BX, 100 + Call SetInfoLine + +PollCloseFile: + Xor BX, BX + XChg BX, FileHandle + Mov AX, 4200h ; Move to start of file + Xor CX, CX + Xor DX, DX + Int 21h ; Start of file + + Mov EAX, WAVEDataSize + Add EAX, 24h + Mov WAVEFileSize, EAX + + Mov AH, 40h + Mov DX, Offset WAVEFileHeader + Mov CX, 2Ch + Int 21h + + Mov AH, 3Eh ; Close file + Int 21h + + Pop DS + PopAD + Assume DS:Nothing + Ret + +Poll7: +IF REGISTERED + Mov AL, CS:StereoSet + Mov CS:Stereo, AL +ENDIF + Ret + +Poll1: + PushAD + Push DS + Push ES + + Cmp CS:FileHandle, 0 + JNE Poll8 + ; Create file... BX = pattern + + Push AX + + Push CS + Push CS + Pop DS + Pop ES + Assume DS:Driver + + Xor EAX, EAX + Mov LastClickRemovalLeft, EAX + Mov LastClickRemovalRight, EAX + Mov NumClipped, EAX + Mov CurrentFractional, EAX +IF DITHEROUTPUT + Mov MonoDitherValue, EAX + Mov LeftDitherValue, EAX + Mov RightDitherValue, EAX +ENDIF + + Mov DI, Offset LastFilter + Mov CX, 16 + Xor AX, AX + Rep StosW + +IF WAREZWAVE ; Delete the file! + + Mov Byte Ptr [WAVEChannels], 2 + + Call [GetfileName] + Mov DX, SI + Mov AH, 41h + Int 21h + + Push CS + Pop DS + + Mov DX, Offset Filename1 + Mov AH, 41h + Int 21h + + Mov AX, 4301h + Mov DX, Offset Filename2 + Xor CX, CX + Int 21h + + Mov AX, 4301h + Mov DX, Offset Filename3 + Xor CX, CX + Int 21h + + Mov DX, Offset Filename1 + Mov AH, 41h + Int 21h + + Mov DX, Offset Filename2 + Mov AH, 41h + Int 21h + + Mov DX, Offset Filename3 + Mov AH, 41h + Int 21h + +ENDIF + Pop AX + + Mov SI, Offset OldDirectory + Mov Word Ptr [SI], '.' + Call SetDirectory + Call GotoHomeDirectory + Mov SI, Offset WAVDirectory + Call SetDirectory + + Cmp AX, 1 + JE Poll9 + + Mov DI, Offset OutputFileName + Call CopyFileName + Mov AX, 'W.' + StosW + Mov AX, 'VA' + StosW + Jmp Poll12 + +Poll9: + Mov DI, Offset OutputFileName + Call CopyFileName + + Xor DX, DX + Mov AX, BX ; AX = pattern + Mov BX, 10 + Div BX + Mov CL, DL + Xor DX, DX + Div BX + Mov AH, AL + Mov AL, '.' + Add AH, '0' + StosW + Mov AL, DL + Mov AH, CL + Add AX, '00' + StosW + +Poll12: + Mov AH, 3Ch + Xor CX, CX + Mov DX, Offset OutputFileName + Int 21h ; Create file... + Mov SI, Offset CreatingMsg + JNC Poll10 + +Poll11: + Mov SI, Offset WAVFileErrorMsg + Mov BX, 100 + Call SetInfoLine + Call StopPlayBack + + Mov SI, Offset OldDirectory + Call SetDirectory + + Pop ES + Pop DS + PopAD + Ret + + +Poll10: + Mov FileHandle, AX + + Xor EDX, EDX + Mov WAVEDataSize, EDX + Mov DX, MixSpeed + +IF REGISTERED + Mov CL, Stereo + Inc CX + ShL EDX, CL + +ELSE + ShL EDX, 1 + +ENDIF + Mov WAVEBytesPerSecond, EDX + +IF REGISTERED + Mov DX, 1 + ShL DX, CL + Mov WAVEBytesPerSample, DX + + Mov Byte Ptr [WAVEChannels], CL +ENDIF + + Mov BX, AX + Mov CX, 2Ch + Mov DX, Offset WAVEFileHeader + Mov AH, 40h + Int 21h + + Mov BX, 100 + Call SetInfoLine + + Mov SI, Offset OldDirectory + Call SetDirectory + + Assume DS:Nothing + +Poll8: + Call SaveEMSPageFrame + + LDS SI, [DWord Ptr SlaveChannelLocation] + Mov CX, [SlaveChannelLocation+4] + + Call M32MixHandler + Call RestoreEMSPageFrame + + ; Now reorder everything in mixbuff + Mov DS, CS:MixSegment + Push DS + Pop ES + +IF DITHEROUTPUT + Mov SI, 80 + Xor DI, DI + Mov CX, CS:RealBytesToMix + + IF REGISTERED + + Cmp CS:Stereo, 0 + JE PollNoStereo + + Mov EDX, CS:LeftDitherValue + Mov EBP, CS:RightDitherValue + + PollStereoDitherLoop: + Add EDX, [SI] + Add EBP, [SI+4] + + IF DOUBLEVOLUME + Mov EAX, EDX + And EDX, 1FFFh + + SAR EAX, 13 + Mov EBX, EBP + + SAR EBX, 13 + And EBP, 1FFFh + ELSE + Mov EAX, EDX + And EDX, 3FFFh + + SAR EAX, 14 + Mov EBX, EBP + + SAR EBX, 14 + And EBP, 3FFFh + ENDIF + + Cmp EAX, -8000h + JL StereoDitherClip1 + + Cmp EAX, 7FFFh + JG StereoDitherClip2 + + StereoDitherClipped1: + Cmp EBX, -8000h + JL StereoDitherClip3 + + Cmp EBX, 7FFFh + JG StereoDitherClip4 + + StereoDitherClipped2: + ShL EBX, 16 + And EAX, 0FFFFh + + Or EAX, EBX + Add SI, 8 + + StosD + Dec CX + JNZ PollStereoDitherLoop + + Mov CS:LeftDitherValue, EDX + Mov CS:RightDitherValue, EBP + + Mov CX, CS:RealBytesToMix + ShL CX, 2 + Jmp PollWriteBlock + + StereoDitherClip1: + Mov AX, 8000h + Jmp StereoDitherClipped1 + + StereoDitherClip2: + Mov AX, 7FFFh + Jmp StereoDitherClipped1 + + StereoDitherClip3: + Mov BX, 8000h + Jmp StereoDitherClipped2 + + StereoDitherClip4: + Mov BX, 7FFFh + Jmp StereoDitherClipped2 + + ENDIF + PollNoStereo: + Mov EBX, CS:MonoDitherValue + + PollMonoDitherLoop: + Add EBX, [SI] + Add SI, 8 + + Mov EAX, EBX + IF DOUBLEVOLUME + And EBX, 1FFFh + SAR EAX, 13 + ELSE + And EBX, 3FFFh + SAR EAX, 14 + ENDIF + + Cmp EAX, -8000h + JL MonoDitherClip1 + + Cmp EAX, 7FFFh + JG MonoDitherClip2 + + PollMonoDitherClipped: + StosW + + Dec CX + JNZ PollMonoDitherLoop + + Mov CS:MonoDitherValue, EBX + + + Mov CX, CS:RealBytesToMix + Add CX, CX + Jmp PollWriteBlock + + MonoDitherClip1: + Mov AX, 8000h + Jmp PollMonoDitherClipped + + MonoDitherClip2: + Mov AX, 7FFFh + Jmp PollMonoDitherClipped + + +ELSE ; No dither + Mov CX, CS:RealBytesToMix + Mov BX, 8 + + IF REGISTERED + Cmp CS:Stereo, 0 + JE PollNoStereo + + Add CX, CX + Mov BX, 4 + + ENDIF + + PollNoStereo: + Push CX + + Mov SI, 80 + Xor DI, DI + + Poll3: + Mov EAX, [SI] + Add SI, BX + Add EAX, 2000h + IF DOUBLEVOLUME + SAR EAX, 13 + ELSE + SAR EAX, 14 + ENDIF + + Cmp EAX, -8000h + JL Poll5 + Cmp EAX, 7FFFh + JG Poll6 + + Poll4: + StosW + Dec CX + JNZ Poll3 + + Pop CX + Add CX, CX +ENDIF +PollWriteBlock: + Mov AH, 40h ; Write + Xor DX, DX + Mov BX, CS:FileHandle + Int 21h + JC PollError + Cmp AX, CX + JE PollNoError + +PollError: + Push CS + Pop DS + Mov SI, Offset WriteError + Mov BX, 100 + Call SetInfoLine + + Call StopPlayBack + + Pop ES + Push CS + Pop DS + Jmp PollCloseFile + +PollNoError: + Add Word Ptr [CS:WAVEDataSize], AX + AdC Word Ptr [CS:WAVEDataSize+2], 0 + + Pop ES + Pop DS + PopAD + + Ret + +IF DITHEROUTPUT +ELSE + Poll5: + Inc NumClipped + Mov AX, 8000h + Jmp Poll4 + + Poll6: + Inc NumClipped + Mov AX, 7FFFh + Jmp Poll4 + +ENDIF + +EndP Poll + +; SetTempo +; +; Parameters: AX = tempo +; +; + +Proc SetTempo Far + + PushAD + + Push BX + + Xor EAX, EAX + Xor EBX, EBX + Xor EDX, EDX + + Mov AX, CS:MixSpeed + + Mov EBX, EAX + ShL EAX, 1 ; EAX = MixSpeed * 2 + ShR EBX, 1 ; EBX = Mixspeed / 2 + Add EAX, EBX + + Pop BX ; BX = tempo + Div EBX + + Mov CS:BytesToMix, AX + Mov CS:BytesToMixFractional, EDX + + PopAD + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + +IF REGISTERED + Mov CS:StereoSet, AL + +ENDIF + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + PushAD + Push DS + Push ES + Push FS + + Mov FS, CS:SongDataArea + Mov BP, AX + Add BP, BP + Mov BP, [FS:64910+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length (in samples) + JC LoadSampleEnd ; Zero flag ON if 16 bit.. + + Mov BL, [FS:BP+12h] + JNZ LoadSample1 + ; 8 bit + Mov ESI, ECX + Dec ESI + + Test BL, 10h ; Loop + JZ LoadSample8_3 + + Mov ESI, [FS:BP+34h] + Mov ECX, [FS:BP+38h] + Mov EDX, 1 + + Test BL, 40h + JZ LoadSample8_1 + + Neg EDX + + Mov ESI, ECX + Sub ESI, 1 + JC LoadSample8_4 + + Cmp ESI, 1 + JAE LoadSample8_1 + Jmp LoadSample8_3 + +LoadSample8_4: + Xor ESI, ESI + +LoadSample8_3: + Xor EDX, EDX + +LoadSample8_1: + Int 3 + Mov AL, [SI] + Add ESI, EDX + Int 3 + Mov AH, [SI] + + Mov ESI, ECX + Int 3 + Mov [SI], AL + Inc ESI + Int 3 + Mov [SI], AH + + Jmp LoadSampleEnd + +LoadSample1: ; 16 bit + Mov ESI, ECX + Dec ESI + + Test BL, 10h ; Loop + JZ LoadSample16_2 + + Mov ESI, [FS:BP+34h] ; Start + Mov ECX, [FS:BP+38h] ; End + Mov EDX, 2 + + Test BL, 40h ; Pingpong? + JZ LoadSample16_1 + + Neg EDX ; Yes..pingpong + + Mov ESI, ECX + Sub ESI, 1 + JC LoadSample16_4 + + Cmp ESI, 1 + JAE LoadSample16_1 + Jmp LoadSample16_2 + +LoadSample16_4: + Xor ESI, ESI + +LoadSample16_2: + Xor EDX, EDX + +LoadSample16_1: + Add ESI, ESI + Int 3 + Mov AX, [SI] + Add ESI, EDX + ShL EAX, 16 + Int 3 + Mov AX, [SI] + + Mov ESI, ECX + Add ESI, ESI + Int 3 + RoR EAX, 16 + Mov [SI], AX + Add ESI, 2 + Int 3 + ShR EAX, 16 + Mov [SI], AX + +LoadSampleEnd: + Pop FS + Pop ES + Pop DS + PopAD + + StC + + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + Cmp CS:NumClipped, 0 + JNE GetStatus1 + + StC + Ret + +GetStatus1: + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset ClippedMsg + Mov BX, Word Ptr [NumClipped+2] + Mov AX, Word Ptr [NumClipped] + + ClC + Ret + +EndP GetStatus + Assume DS:Nothing + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WAVScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +TempVariable DW 0 +Const1 DD 3F800000h + +Proc GetFilterFrequency ; Given AL= Freq + Assume DS:Driver + + ShL AX, 8 + Mov TempVariable, AX + FILD TempVariable + + FMul FreqParameterMultiplier ; -i/(24*256) + FLd ST + FRndInt + FSub ST(1), ST + FXCh + F2XM1 + FLd1 + FAdd + FScale ; = 2^(i/24*256) + FMul FreqMultiplier ; = r + + FLd1 ; 1, c + FAdd ST, ST(1) ; 1+c, c + FDivR Const1 ; 1/(1+c), c + FSt DWord Ptr [SI] + FMul + FStP DWord Ptr [SI+4] + FStP ST + + Ret + +EndP GetFilterFrequency + Assume DS:Nothing + +; + +Const1On16 DD 3D000000h ; actually 1 on 32 + +Proc CalculateFilterCoefficients + Assume DS:Driver + + PushA + Push CS + Pop DS + + FNInit + FLdCW NewControlWord + + Mov AL, [VolumeTable] + Mov SI, Offset FilterCoefficients + ShR AL, 1 + Call GetFilterFrequency + + Mov AL, [VolumeTable+1] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + + Mov AL, [VolumeTable+2] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + + Mov AL, [VolumeTable+3] ; FilterFrequency1 + Add SI, 8 + Call GetFilterFrequency + +; Now volumes + Mov SI, Offset VolumeTable+4 + Mov DI, Offset FilterVolumes + Xor AX, AX + Mov CX, 4 + +FilterVolumeLoop1: + LodSB + Mov TempVariable, AX + FILD TempVariable + FMul Const1On16 + FStP DWord Ptr [DI] + + Add DI, 4 + Loop FilterVolumeLoop1 + + PopA + Ret + +EndP CalculateFilterCoefficients + Assume DS:Nothing + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + Call CalculateFilterCoefficients + + Pop DS + Ret + +EndP SetVariable + +; + +Proc StartNoRampFunction Far + + Push CS + Pop ES + Mov DI, Offset StartNoRamp + + Ret + +EndP StartNoRampFunction + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. +StopPlaySection DW 1 +DefaultChannels DW 256 +DriverFlags DW 3 ; Bit 0 = MIDI Output + ; Bit 1 = hiqual + ; Bit 2 = waveform + DW 4 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + DW Offset SendUARTOut + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/WAVPRO.ASM b/it/SoundDrivers/WAVPRO.ASM new file mode 100755 index 0000000..8a1d866 --- /dev/null +++ b/it/SoundDrivers/WAVPRO.ASM @@ -0,0 +1,853 @@ + + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +REGISTERED EQU 1 + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +STEREOENABLED EQU 1 +MIXRESOLUTION EQU 32 + +FileID DW 22 ; 0 = Ozone + ; 1 = Andrew Seargant + ; 2 = David Goodale + ; 3 = Nebula + ; 4 = Christian Bode + ; 5 = Flatrich + ; 6 = MAZ + ; 7 = Barthelemy DEFOSSEZ + ; 8 = Daedalus + ; 9 = Joost + ; 10= Yannis + ; 11= Mike Marton + ; 12= HB + ; 13= Catspaw + ; 14= Airon + ; 15= Mike Blaine + ; 16= Jason Tracer + ; 17= Akos Matte + ; 18= Kristian Sergiejew + ; 19= Jonathan Bartlett + ; 20= DeltaX + ; 21= Zinc + ; 22= Draggy + +FileHandle DW 0 + +LowerLimit DD -3.2768E4 +UpperLimit DD 3.2767E4 + +WAVOutputMsg DB "Writing to disk", 13 + DB "Output frequency ", 0FDh, "D", 0 +WAVFileErrorMsg DB "Unable to create output file! ", 0 +WAVMemErrorMsg DB "Unable to allocate memory!", 0 +NoReinitMsg DB "File output routines should NOT require reinitialisation ", 0 +WriteError DB "Error writing to output file. Output file closed ", 0 + + +WAVEFileHeader DB "RIFF" +WAVEFileSize DD 0 +WAVEFileHeader2 DB "WAVEfmt " +WAVEFileHeaderLength DD 10h +WAVEFileID DW 1 +WAVEChannels DW 1 ; 1 = mono, 2 = stereo +MixSpeed DW 44100 ; Default to CD quality +WAVEMixSpeedFiller DW 0 +WAVEBytesPerSecond DD 0 +WAVEBytesPerSample DW 2 +WAVEBits DW 16 +WAVEHeader3 DB "data" +WAVEDataSize DD 0 + +IFDEF REGISTERED + Stereo DB 0 + StereoSet DB 0 +ENDIF + +BytesToMix DW 0 +MixVolume DW 0 +MixSegment DW 0 +MixHandler DW Offset M32MixHandler +OldDirectory DB 80 Dup (0) + +CreatingMsg DB "Created file " +OutputFileName DB " ", 0 + +ClosedFileMsg DB "Closed output file ", 0 +OUTPUT DB "OUTPUT" + +include mix.inc +include wav.mix + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + Call SetupRamp + + Mov EAX, 'Jeff' + ClC ; Always assume true + Ret + +EndP DetectCard + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + FNINIT + + Mov AH, 48h + Mov BX, 2643 ; (65536 / (.4*31)) * 4 * 2 + Int 21h + JNC InitSound1 + + Mov SI, Offset WAVMemErrorMsg + Ret + +InitSound1: + Mov MixSegment, AX + + Mov SI, Offset WAVOutputMsg + + Mov AX, CmdLineMixSpeed + And AX, AX + JZ InitSound3 + + Cmp AX, 8000 + JA InitSound4 + + Mov AX, 8000 + +InitSound4: + Cmp AX, 64000 + JB InitSound5 + + Mov AX, 64000 + +InitSound5: + Mov MixSpeed, AX + +InitSound3: + Mov AX, MixSpeed + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + Push CS + Pop DS + + Mov SI, Offset NoReinitMsg + Mov BX, 40 + Call SetInfoLine + + Ret + +EndP ReInitSound + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, MixSegment + Test AX, AX + JZ UnInitsound1 + + Mov ES, AX + Mov AH, 49h + Int 21h + +UnInitSound1: + Mov BX, FileHandle + Test BX, BX + JZ UnInitSound2 + + Mov AX, 4200h ; Move to start of file + Xor CX, CX + Xor DX, DX + Int 21h ; Start of file + + Mov EAX, WAVEDataSize + Add EAX, 24h + Mov WAVEFileSize, EAX + + Mov AH, 40h + Mov DX, Offset WAVEFileHeader + Mov CX, 2Ch + Int 21h + + Mov AH, 3Eh + Int 21h + +UnInitSound2: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; + +Proc CopyFileName ; Given DI + + Push DS + + Call GetFileName + Assume DS:Nothing ; Returns DS:SI + + Push CS + Pop ES + Mov CX, 11 + Mov AL, ' ' + Push DI + Rep StosB + Pop DI + + Mov CX, 8 + + Cmp Byte Ptr [SI], 0 + JE CopyFileName2 + Cmp Byte Ptr [SI], '.' + JE CopyFileName2 + +CopyFileName1: + LodsB + Cmp AL, '.' + JE CopyFileName3 + StosB + Loop CopyFileName1 + + Pop DS + Ret + +CopyFileName2: + Push CS + Pop DS + Mov SI, Offset OUTPUT + Mov CX, 6 + Rep MovsB + +CopyFileName3: + Pop DS + Ret + +EndP CopyFileName + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; BX = pattern +; +; + +Proc Poll Far + + Cmp MixSegment, 0 + JNE Poll2 + + Ret + +Poll2: + Test AX, AX + JNZ Poll1 + + Cmp CS:FileHandle, 0 + JE Poll7 + + PushAD + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset ClosedFileMsg + Mov BX, 100 + Call SetInfoLine + +PollCloseFile: + Xor BX, BX + XChg BX, FileHandle + Mov AX, 4200h ; Move to start of file + Xor CX, CX + Xor DX, DX + Int 21h ; Start of file + + Mov EAX, WAVEDataSize + Add EAX, 24h + Mov WAVEFileSize, EAX + + Mov AH, 40h + Mov DX, Offset WAVEFileHeader + Mov CX, 2Ch + Int 21h + + Mov AH, 3Eh ; Close file + Int 21h + + Pop DS + PopAD + Assume DS:Nothing + Ret + +Poll7: +IFDEF REGISTERED + Mov AL, CS:StereoSet + Mov CS:Stereo, AL +ENDIF + Ret + +Poll1: + PushAD + Push DS + Push ES + + Cmp CS:FileHandle, 0 + JNE Poll8 + ; Create file... BX = pattern + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset OldDirectory + Mov Word Ptr [SI], '.' + Call SetDirectory + Call GotoHomeDirectory + + Cmp AX, 1 + JE Poll9 + + Mov DI, Offset OutputFileName + Call CopyFileName + Mov AX, 'W.' + StosW + Mov AX, 'VA' + StosW + Jmp Poll12 + +Poll9: + Mov DI, Offset OutputFileName + Call CopyFileName + + Xor DX, DX + Mov AX, BX ; AX = pattern + Mov BX, 10 + Div BX + Mov CL, DL + Xor DX, DX + Div BX + Mov AH, AL + Mov AL, '.' + Add AH, '0' + StosW + Mov AL, DL + Mov AH, CL + Add AX, '00' + StosW + +Poll12: + Mov AH, 3Ch + Xor CX, CX + Mov DX, Offset OutputFileName + Int 21h ; Create file... + Mov SI, Offset CreatingMsg + JNC Poll10 + +Poll11: + Mov SI, Offset WAVFileErrorMsg + Mov BX, 100 + Call SetInfoLine + Call StopPlayBack + + Mov SI, Offset OldDirectory + Call SetDirectory + + Pop ES + Pop DS + PopAD + Ret + + +Poll10: + Mov FileHandle, AX + + Xor EDX, EDX + Mov WAVEDataSize, EDX + Mov DX, MixSpeed + +IFDEF REGISTERED + Mov CL, Stereo + Inc CX + ShL EDX, CL + +ELSE + ShL EDX, 1 + +ENDIF + Mov WAVEBytesPerSecond, EDX + +IFDEF REGISTERED + Mov DX, 1 + ShL DX, CL + Mov WAVEBytesPerSample, DX + + Mov Byte Ptr [WAVEChannels], CL +ENDIF + + Mov BX, AX + Mov CX, 2Ch + Mov DX, Offset WAVEFileHeader + Mov AH, 40h + Int 21h + + Mov BX, 100 + Call SetInfoLine + + Mov SI, Offset OldDirectory + Call SetDirectory + + Assume DS:Nothing + +Poll8: + Call SaveEMSPageFrame + Call Update ; Got DS:SI, CX + Call M32MixHandler + Call RestoreEMSPageFrame + + ; Now reorder everything in mixbuff + Mov DS, CS:MixSegment + Push DS + Pop ES + + Mov CX, CS:BytesToMix + Mov BX, 8 + +IFDEF REGISTERED + Cmp CS:Stereo, 0 + JE PollNoStereo + + Add CX, CX + Mov BX, 4 + +ENDIF + +PollNoStereo: + Push CX + + Xor SI, SI + Xor DI, DI + Xor DX, DX + +Poll3: + Mov EAX, [SI] + + Test EAX, EAX + JS FloatNegative + + Cmp EAX, UpperLimit + JL FloatOK + + Mov AX, 7FFFh + Jmp Poll4 + +FloatNegative: + Cmp EAX, LowerLimit + JL FloatOK + + Mov AX, 8000h + Jmp Poll4 + +FloatOK: + Fld DWord Ptr [SI] + FISt DWord Ptr [SI] + Mov AX, [SI] + +Poll4: + Add SI, BX + StosW + Dec CX + JNZ Poll3 + + Pop CX + Add CX, CX + + Mov AH, 40h ; Write + Mov BX, CS:FileHandle + Int 21h + JC PollError + Cmp AX, CX + JE PollNoError + +PollError: + Push CS + Pop DS + Mov SI, Offset WriteError + Mov BX, 100 + Call SetInfoLine + + Call StopPlayBack + + Pop ES + Push CS + Pop DS + Jmp PollCloseFile + +PollNoError: + Add Word Ptr [CS:WAVEDataSize], AX + AdC Word Ptr [CS:WAVEDataSize+2], 0 + + Pop ES + Pop DS + PopAD + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: AX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, CS:MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov CS:BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + Mov CS:MixVolume, AX + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc SetStereo Far + +IFDEF REGISTERED + Mov CS:StereoSet, AL + +ENDIF + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far + + PushAD + Push DS + Push ES + Push FS + + Mov FS, CS:SongDataArea + Mov BP, AX + Add BP, BP + Mov BP, [FS:64910+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length + JC LoadSampleEnd ; Zero flag ON if 16 bit.. + + Mov AX, 0 + Mov BL, [FS:BP+12h] + JNZ LoadSample1 + ; 8 bit + + Test BL, 10h ; Loop + JZ LoadSample8_2 + + Mov ESI, [FS:BP+34h] + Mov ECX, [FS:BP+38h] + + Test BL, 40h + JZ LoadSample8_1 + + Mov ESI, ECX + Sub ESI, 2 + JNC LoadSample8_1 + + Xor ESI, ESI + +LoadSample8_1: + Call UpdateSampleLocation + Mov AL, [SI] + +LoadSample8_2: + Mov ESI, ECX + Call UpdateSampleLocation + Mov [SI], AL + Jmp LoadSampleEnd + +LoadSample1: ; 16 bit + Test BL, 10h ; Loop + JZ LoadSample16_2 + + Mov ESI, [FS:BP+34h] + Mov ECX, [FS:BP+38h] + + Test BL, 40h + JZ LoadSample16_1 + + Mov ESI, ECX + Sub ESI, 2 + JNC LoadSample16_1 + + Xor ESI, ESI + +LoadSample16_1: + Add ESI, ESI + Call UpdateSampleLocation + Mov AX, [SI] + +LoadSample16_2: + Mov ESI, ECX + Add ESI, ESI + Call UpdateSampleLocation + Mov [SI], AX + +LoadSampleEnd: + Pop FS + Pop ES + Pop DS + PopAD + + StC + + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Xor AX, AX + StC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. +StopPlaySection DW 1 +DefaultChannels DW 256 + DW 5 Dup (0) + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/WSSDRV.ASM b/it/SoundDrivers/WSSDRV.ASM new file mode 100755 index 0000000..977673d --- /dev/null +++ b/it/SoundDrivers/WSSDRV.ASM @@ -0,0 +1,2175 @@ +; +; Windows Sound System Driver +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 + +DMASize DW 2048 + +WSSMsg DB "Using Windows Sound System", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Using Windows Sound System", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Windows Sound System reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITWSS.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITWSS.DRV", 0 + +DriverName DB "ITWSS.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldWSSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQSetupTable DB 0, 0, 0, 0, 0, 0, 0, 8 + DB 0, 10h, 18h, 20h, 0, 0, 0, 0 + +DMASetupTable DB 1, 2, 0, 3, 0, 0, 0, 0 + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +WSS_INTF = 00h +WSS_CHIPID = 03h +WSS_BASE = 04h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW 0 + +WSSHeaderLine DW 10 + DB "Windows Sound System Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 27, 48 + DB 21h + DB "Windows Sound System Driver 1.1 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 2 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 16 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Add DX, WSS_CHIPID ; Check for valid Chip ID + In AL, DX + + And AL, 3Fh + JZ PingWSS1 + Cmp AL, 4 + JE PingWSS1 + Cmp AL, 0Fh + JE PingWSS1 + +PingWSSFailure: + Pop DX + + StC + Ret + +PingWSS1: + Add DX, 4+2-WSS_CHIPID + + In AL, DX + Xor AL, AL + Out DX, AL + + Sub DX, 2 ; DX = AD1848 Baseport + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + + Pop DX + Ret + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Cmp IRQ, 0FFFFh + JNE DetectCardIRQDone + + Mov IRQ, 7 + +DetectCardIRQDone: + Cmp DMA, 0FFFFh + JNE DetectCardDMADone + + Mov DMA, 1 + +DetectCardDMADone: + Mov DX, BasePort + Cmp DX, 0FFFFh + JE DetectCardFindBasePort + + Call PingWSS + JNC CheckWSSOK + +DetectWSSFailure: + StC + Ret + +DetectCardFindBasePort: + Mov DX, 530h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0E80h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0F40h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 604h + Call PingWSS + JC DetectWSSFailure + +DetectWSSOK: + Mov BasePort, DX + +CheckWSSOK: + ; Check for valid IRQ + Mov BX, IRQ + Mov AL, [IRQSetupTable+BX] + Mov BX, DMA + Mov AH, [DMASetupTable+BX] + Test AL, AL + JZ DetectWSSFailure + Test AH, AH + JZ DetectWSSFailure + + Or AL, AH + Out DX, AL + + Add DX, WSS_BASE + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Mov EAX, 'Jeff' + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + PushAD + Push DS + Push ES + + ClD + + Mov AX, CS + Mov DS, AX + Assume DS:Driver + + Mov DX, [BasePort] + Add DX, 6 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Mov AX, MixBufferPos + Mov BX, AX + Mul DMASize + Cmp AX, DMABUFFERLENGTH + JB WSSIRQHandler2 + + Xor AX, AX + Xor BX, BX + +WSSIRQHandler2: + Inc BX + Mov MixBufferPos, BX + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, AX + + Mov BX, DMASize ; BX = bytes required + ShR BX, 1 + ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + Pop DS + PopAD + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + Add DX, WSS_BASE + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Add DX, WSS_BASE + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, DMASize + ShR AX, 1 + + Cmp Stereo, 0 + JE StartWSS2 + + ShR AX, 1 + +StartWSS2: + Dec AX + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far ; Fix up end of sample bytes + + PushAD + Push DS + Push ES + Push FS + + Mov FS, CS:SongDataArea + Mov BP, AX + Add BP, BP + Mov BP, [FS:64910+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length + JC LoadSampleEnd ; Zero flag ON if 16 bit.. + + Xor EAX, EAX + Mov BL, [FS:BP+12h] + + Test BL, 10h ; Loop + JZ LoadSample2 + + Mov ESI, [FS:BP+34h] ; Start of loop + Test BL, 40h ; Pingpong? + JZ LoadSample1 + + Mov ESI, [FS:BP+38h] + Sub ESI, 2 + JNC LoadSample1 + + Xor ESI, ESI + +LoadSample1: + Test BL, 2 + JZ LoadSample4 + + Add ESI, ESI + +LoadSample4: + Call UpdateSampleLocation + Mov AL, [SI] + Inc ESI + Call UpdateSampleLocation + Mov AH, [SI] + +LoadSample2: + Mov ESI, [FS:BP+30h] + Test BL, 2 + JZ LoadSample3 + + Add ESI, ESI + +LoadSample3: + Call UpdateSampleLocation + Mov [SI], AL + Inc ESI + Call UpdateSampleLocation + Mov [SI], AH + +LoadSampleEnd: + Pop FS + Pop ES + Pop DS + PopAD + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DX, WSS_BASE + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/SoundDrivers/WSSDRV2.ASM b/it/SoundDrivers/WSSDRV2.ASM new file mode 100755 index 0000000..2cf2b8e --- /dev/null +++ b/it/SoundDrivers/WSSDRV2.ASM @@ -0,0 +1,2268 @@ +; +; Windows Sound System Driver +; + .386P + +Segment DriverHeader PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +;***** Driver Header ******* + +include drhead.inc + +EndS + +Segment Driver PARA Public 'Code' Use16 + Assume CS:Driver, DS:Nothing + +ORG 0 +StartDriver: + +include vtable.inc + +;******** Required ProcedureTable ************* + +include reqproc.inc + +;********************************** + +STEREOENABLED EQU 1 +DMABUFFERLENGTH EQU 8192 +MIXRESOLUTION EQU 32 ; 32 bit mixing for +MIXTABLESIZE EQU 2*256*65 +TIMERCONST EQU 11932 + +WSSMsg DB "Using Windows Sound System", 13 + DB "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0 + +WSSNoMemoryMsg DB "Using Windows Sound System", 13 + DB "Error: Insufficient memory", 0 + +ReinitMsg DB "Windows Sound System reinitialised", 0 + +ConfigErrorMsg DB "Error saving configuration to ITWSS2.DRV", 0 +ConfigOKMsg DB "Configuration saved to ITWSS2.DRV", 0 + +DriverName DB "ITWSS2.DRV", 0 + +Forced DB 0 +Stereo DB 0 +MixVolume DW 0 + +BytesToMix DW 1000 +WSSMixConst DB 0 + +MixSegment DW 0 +DMASegment DW 0 + +MixTransferOffset DW 0 +MixTransferRemaining DW 0 + +CONFIGURATIONOFFSET EQU $+128 +CONFIGSIZE EQU 6 +MixMode DW 0 +MixModeOffset DW 0 +Filter DW 0 + +IMR DW 0 +OldTimerIRQHandler DD 0 +OldWSSIRQHandler DD 0 + +FilterValue DD 0 +FilterValue2 DD 0 +TimerAccumulator DW 0 + +MixSpeedTable DW 5513, 41h + DW 6615, 4Fh + DW 8000, 40h + DW 9600, 4Eh + DW 11025, 43h + DW 16000, 42h + DW 18900, 45h + DW 22050, 47h + DW 27429, 44h + DW 32000, 46h + DW 33075, 4Dh + DW 37800, 49h + DW 44100, 4Bh + DW 48000, 4Ch + DW 54860, 48h + DW 64000, 4Ah + +IRQSetupTable DB 0, 0, 0, 0, 0, 0, 0, 8 + DB 0, 10h, 18h, 20h, 0, 0, 0, 0 + +DMASetupTable DB 1, 2, 0, 3, 0, 0, 0, 0 + +DMALengthTable Label Byte + DB 1, 3, 5, 7, 0C2h, 0C6h, 0CAh, 0CEh + +IRQData Label Word + DW 20h, 1111111111111110b ; IRQ 0 + DW 24h, 1111111111111101b ; IRQ 1 + DW 28h, 1111110111111011b ; IRQ 2 + DW 2Ch, 1111111111110111b ; IRQ 3 + DW 30h, 1111111111101111b ; IRQ 4 + DW 34h, 1111111111011111b ; IRQ 5 + DW 38h, 1111111110111111b ; IRQ 6 + DW 3Ch, 1111111101111111b ; IRQ 7 + DW 1C0h, 1111111011111011b ; IRQ 8 + DW 1C4h, 1111110111111011b ; IRQ 9 + DW 1C8h, 1111101111111011b ; IRQ 10 + DW 1CCh, 1111011111111011b ; IRQ 11 + DW 1D0h, 1110111111111011b ; IRQ 12 + DW 1D4h, 1101111111111011b ; IRQ 13 + DW 1D8h, 1011111111111011b ; IRQ 14 + DW 1DCh, 0111111111111011b ; IRQ 15 + +;********************************** +; WSS Registers +;********************************** + +CODEC_INDEX_LIC = 00 +CODEC_INDEX_RIC = 01h +CODEC_INDEX_LX1C = 02h +CODEC_INDEX_RX1C = 03h +CODEC_INDEX_LX2C = 04h +CODEC_INDEX_RX2C = 05h +CODEC_INDEX_LDC = 06h +CODEC_INDEX_RDC = 07h +CODEC_INDEX_CDF = 08h +CODEC_INDEX_INTF = 09h +CODEC_INDEX_PIN = 0Ah +CODEC_INDEX_TEST = 0Bh +CODEC_INDEX_MISC = 0Ch +CODEC_INDEX_DIGMIX = 0Dh +CODEC_INDEX_UPR_COUNT = 0Eh +CODEC_INDEX_LWR_COUNT = 0Fh + +CODEC_MCE = 40h + +LDC_LDM = 80h +LDC_LDA = 3Fh + +RDC_RDM = 80h +RDC_RDA = 3Fh + +CDF_STEREO = 10h + +INTF_PEN = 01h +INTF_CEN = 02h +INTF_SDC = 04h +INTF_ACAL = 08h +INTF_PPIO = 40h +INTF_CPIO = 80h + +PIN_IEN = 2 + +TEST_ORL = 03h +TEST_ORR = 0Ch +TEST_DRS = 10h +TEST_ACI = 20h +TEST_PUR = 40h +TEST_COR = 80h + +WSS_INTF = 00h +WSS_CHIPID = 03h +WSS_BASE = 04h + +;********************************** + +WSS16ScreenList Label + DW 16 + DW Near Ptr IdleFunctionList + DW Near Ptr GlobalKeyLink + + DW Near Ptr FullScreenBox ; 0 + DW Near Ptr ScreenHeader + DW Near Ptr FillHeader + DW Near Ptr WSSHeaderLine + + DW Near Ptr DriverText + + DW Near Ptr MixModeText + DW Near Ptr MixModeButton1 ; 6 + DW Near Ptr MixModeButton2 ; + DW Near Ptr MixModeButton3 ; 8 + DW Near Ptr MixModeButton4 ; 9 + + DW Near Ptr FilterText + DW Near Ptr FilterButton1 ; 11 + DW Near Ptr FilterButton2 + DW Near Ptr FilterButton3 + + DW Near Ptr VolumeText + DW Near Ptr VolumeBox1 + + DW Near Ptr MasterVolumeLeft ; 16 + DW Near Ptr MasterVolumeRight ; 17 + + DW 0 + +WSSHeaderLine DW 10 + DB "Windows Sound System Driver", 0 + +EmptyObject DW 1 + DB 0, 0 + DB 0 + DB 0 + +DriverText DW 1 + DB 27, 48 + DB 21h + DB "Windows Sound System Driver 1.1 for Impulse Tracker", 0 + +GlobalKeyLink DB 7 +GlobalKeyLink2 DD 0 + +IdleFunctionList DD 0 + DD 0 + +FillHeader DW 8 +FillHeader2 DD 0 + +FullScreenBox DW 0 + DB 0, 0, 79, 49 + DB 4 + +ScreenHeader DW 8 +ScreenHeader2 DD 0 + +VolumeText DW 1 + DB 2, 14 + DB 20h + DB "Master Volume Left", 13 + DB "Master Volume Right" + DB 0 + +VolumeBox1 DW 0 + DB 21, 13, 31, 16 + DB 25 + +MasterVolumeLeft DW 9 + DB 22, 14 + DW 0, 63 + DW 9, 0 + DW 0FFFFh, 17, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MasterVolumeRight DW 9 + DB 22, 15 + DW 0, 63 + DW 9, 1 + DW 16, 6, 0FFFFh, 0FFFFh + DW 0FFFFh, 0FFFFh + +MixModeText DW 1 + DB 2, 18 + DB 20h + DB "Mixing Mode, Playback Frequency: ", 0FDh, "DHz", 0 +MixSpeed DW 48000 + +MixModeButton1 DW 2 + DW 17, 7, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment1 DW 0 + DW 0 + DW Offset SetMixMode +DriverSegment2 DW 0 + DB 3, 20, 32, 22, 8 + DB 0 + DB " 16 Bit, Non-Interpolated", 0 + +MixModeButton2 DW 2 + DW 6, 8, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment3 DW 0 + DW 2 + DW Offset SetMixMode +DriverSegment4 DW 0 + DB 3, 23, 32, 25, 8 + DB 0 + DB " 16 Bit, Interpolated", 0 + +MixModeButton3 DW 2 + DW 7, 9, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment5 DW 0 + DW 4 + DW Offset SetMixMode +DriverSegment6 DW 0 + DB 3, 26, 32, 28, 8 + DB 0 + DB " 32 Bit, Non-Interpolated", 0 + +MixModeButton4 DW 2 + DW 8, 11, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetMixMode +DriverSegment7 DW 0 + DW 6 + DW Offset SetMixMode +DriverSegment8 DW 0 + DB 3, 29, 32, 31, 8 + DB 0 + DB " 32 Bit, Interpolated", 0 + +FilterText DW 1 + DB 2, 33 + DB 20h + DB "Filter mode", 0 + +FilterButton1 DW 2 + DW 9, 12, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment9 DW 0 + DW 0 + DW Offset SetFilter +DriverSegment10 DW 0 + DB 3, 35, 29, 37, 8 + DB 0 + DB " No Filter", 0 + +FilterButton2 DW 2 + DW 11, 13, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment11 DW 0 + DW 1 + DW Offset SetFilter +DriverSegment12 DW 0 + DB 3, 38, 29, 40, 8 + DB 0 + DB " 50% Filter", 0 + +FilterButton3 DW 2 + DW 12, 0FFFFh, 0FFFFh, 0FFFFh + DW 0 + DW 0, 0 + DW 6 + DW Offset GetFilter +DriverSegment13 DW 0 + DW 2 + DW Offset SetFilter +DriverSegment14 DW 0 + DB 3, 41, 29, 43, 8 + DB 0 + DB " 75% Filter", 0 + +VolumeTable DB 2 Dup (0) + +; MixingRoutines + +MixBufferPos DW 0 + +include dma.inc +include mix.inc +include m12bit.mix +include m12biti.mix +include m32bit.mix +include m32biti.mix + +MixFunctionTables Label + +include m12bit.inc ; contains the tables +include m12biti.inc +include m32bit.inc +include m32biti.inc + +; + +RelocationTable Label Word + DW Offset DriverSegment1, Offset DriverSegment2 + DW Offset DriverSegment3, Offset DriverSegment4 + DW Offset DriverSegment5, Offset DriverSegment6 + DW Offset DriverSegment7, Offset DriverSegment8 + DW Offset DriverSegment9, Offset DriverSegment10 + DW Offset DriverSegment11, Offset DriverSegment12 + DW Offset DriverSegment13, Offset DriverSegment14 + DW 0 + +; + +Proc GetMixMode Far + + Push CS + Pop ES + Mov DI, Offset MixMode + + Ret + +EndP GetMixMode + +; + +Proc GetFilter Far + + Push CS + Pop ES + Mov DI, Offset Filter + + Ret + +EndP GetFilter + +; + +Proc SetFilter Far + + Mov AX, [SI+22] + Mov CS:FilterValue, 0 + Mov CS:Filter, AX + ClI + Jmp SetMixModeChain + +EndP SetFilter + +; + +Proc WaitCoDec + + Push CX + + Mov CX, 0F000h + +WaitCoDec1: + In AL, DX + Test AL, AL + JNS WaitCoDec2 + Loop WaitCoDec1 + + StC + +WaitCoDec2: + Pop CX + Ret + +EndP WaitCoDec + +; + +Proc WaitAutoCalibration + + Push CX + Mov CX, 0F000h + +WaitAutoCalibration1: + Mov AL, CODEC_INDEX_TEST + Out DX, AL + Inc DX + In AL, DX + Dec DX + Test AL, TEST_ACI + JNZ WaitAutoCalibration2 + Loop WaitAutoCalibration1 + + StC + +WaitAutoCalibration2: + Pop CX + Ret + +EndP WaitAutoCalibration + +; + +Proc SetMixMode Far + + Mov AX, [SI+22] + + ClI + + Mov CS:MixMode, AX + + Mov BX, 180 + Mul BX + Mov CS:MixModeOffset, AX + + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS:RecalculateAllVolumes + + StI + +SetMixModeChain: + Call GotoHomeDirectory + + ; Now to save config into driver file. + Push CS + Pop DS + Assume DS:Driver + + Mov AX, 3D02h ; Read write access + Mov DX, Offset DriverName + Mov SI, Offset ConfigErrorMsg + Int 21h + JC SetMixMode1 + + Mov BX, AX + + Mov AX, 4200h + Xor CX, CX + Mov DX, Offset CONFIGURATIONOFFSET + Int 21h + JC SetMixMode2 + + Mov AH, 40h + Mov CX, CONFIGSIZE + Mov DX, Offset MixMode + Int 21h + +SetMixMode2: + PushF + Mov AH, 3Eh + Int 21h + PopF + + JC SetMixMode1 + + Mov SI, Offset ConfigOKMsg + +SetMixMode1: + Mov BX, 40 + Call SetInfoLine + + Mov AX, 1 + Ret + +EndP SetMixMode + Assume DS:Nothing + +; + +Proc GetWSSMixConst ; Work out value.. and nearest + ; mixspeed value. + + PushA + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, CmdLineMixSpeed + Mov CX, MixSpeed + Test AX, AX + JZ GetWSSMixConst1 + + Mov CX, 64000 + Cmp AX, CX + JA GetWSSMixConst1 + + Mov CX, 8000 + Cmp AX, CX + JB GetWSSMixConst1 + + Mov CX, AX + +GetWSSMixConst1: ; CX = desired mixspeed + Mov SI, Offset MixSpeedTable + Mov DX, 16 ; 16 different available speeds + + Xor BX, BX + +GetWSSMixConst2: + LodsW + Cmp AX, BX + JB GetWSSMixConst3 + Cmp AX, CX + JA GetWSSMixConst3 + + Mov BX, AX + Mov DH, [SI] + +GetWSSMixConst3: + LodsW ; Add SI, 2 + Dec DL + JNZ GetWSSMixConst2 + + Mov MixSpeed, BX + Mov WSSMixConst, DH + + Pop DS + PopA + Ret + +EndP GetWSSMixConst + Assume DS:Nothing + +; + +Proc PingWSS ; Check BasePort, DX = BasePort + ; Preserves DX, destroys AX + + Push DX + + Add DX, WSS_CHIPID ; Check for valid Chip ID + In AL, DX + + And AL, 3Fh + JZ PingWSS1 + Cmp AL, 4 + JE PingWSS1 + Cmp AL, 0Fh + JE PingWSS1 + +PingWSSFailure: + Pop DX + + StC + Ret + +PingWSS1: + Add DX, 4+2-WSS_CHIPID + + In AL, DX + Xor AL, AL + Out DX, AL + + Sub DX, 2 ; DX = AD1848 Baseport + Call WaitCodec + JC PingWSSFailure + + In AL, DX + Test AL, AL + JS PingWSSFailure + + Mov AL, CODEC_INDEX_MISC + Out DX, AL + Inc DX ; DX = Data port + In AL, DX + Mov AH, AL ; AH = Revision + + Xor AL, AL ; Write 0 revision + Out DX, AL + In AL, DX + And AX, 8F8Fh + Cmp AL, AH + JNE PingWSSFailure + Dec DX ; DX = AD1848 baseport + + Mov AL, CODEC_MCE or CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + Mov AL, INTF_ACAL or INTF_SDC + Out DX, AL + Dec DX + + Call WaitAutoCalibration ; Returns carry if error + ; Carry clear if none. + +; JC PingWSSFailure + + Pop DX + Ret + +EndP PingWSS + +; DetectCard +; +; Returns carry set if error, else carry clear. Has to setup internal vars +; (eg. appropriate IRQ/DMA whatever). +; +; + +Proc DetectCard Far + + Push CS + Pop DS + Assume DS:Driver + + Cmp IRQ, 0FFFFh + JNE DetectCardIRQDone + + Mov IRQ, 7 + +DetectCardIRQDone: + Cmp DMA, 0FFFFh + JNE DetectCardDMADone + + Mov DMA, 1 + +DetectCardDMADone: + Mov DX, BasePort + Cmp DX, 0FFFFh + JE DetectCardFindBasePort + + Call PingWSS + JNC CheckWSSOK + +DetectWSSFailure: + StC + Ret + +DetectCardFindBasePort: + Mov DX, 530h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0E80h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 0F40h + Call PingWSS + JNC DetectWSSOK + + Mov DX, 604h + Call PingWSS + JC DetectWSSFailure + +DetectWSSOK: + Mov BasePort, DX + +CheckWSSOK: + ; Check for valid IRQ + Mov BX, IRQ + Mov AL, [IRQSetupTable+BX] + Mov BX, DMA + Mov AH, [DMASetupTable+BX] + Test AL, AL + JZ DetectWSSFailure + Test AH, AH + JZ DetectWSSFailure + + Or AL, AH + Out DX, AL + + Add DX, WSS_BASE + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + Mov AH, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AX, 3F3Fh + Neg AL + Neg AH + Add AL, 3Fh + Add AH, 3Fh + Mov [Word Ptr VolumeTable], AX + + Mov AL, [DMALengthTable+BX] + Mov Byte Ptr [DMAPort1], AL + Mov Byte Ptr [DMAPort2], AL + + Mov AX, DMABUFFERLENGTH/2 + Cmp BX, 4 + JB DetectWSS2 + + ShR AX, 1 + +DetectWSS2: + Mov Word Ptr [DMABufferLength1], AX + Mov Word Ptr [DMABufferLength2], AX + + Mov EAX, 'Jeff' + ClC + Ret + +EndP DetectCard + Assume DS:Nothing + +; + +MixModeTable Label Word + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix0ModeMono, Mix0ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + DW Offset Mix6ModeMono, Mix6ModeStereo + +Proc MixSamples ; Given DS:SI = info tables, CX = numchannels + + ; 1. Clean buffer + ; + update variables + ; 2. Update parameters + ; 3. Mix func + ; 4. Return + + Push CX + + Mov CX, BytesToMix + Mov ES, MixSegment + Mov DI, MIXTABLESIZE + Xor EAX, EAX + Mov DX, CX + Add CX, CX + + Mov MixTransferOffset, DI ; } Memory write + + Cmp Stereo, 0 + JE MixSamples1 + + Mov DX, CX + +MixSamples1: + Rep StosD ; } Memory write + Mov MixTransferRemaining, DX ; } + + Pop CX + +MixSamples2: + Test Byte Ptr [SI], 1 + JZ MixSamplesEnd2 + Cmp Byte Ptr [SI+36h], 100 + JE MixSamplesEnd2 + + Push CX + Mov CX, [SI] + + Test CH, 2 + JZ MixSamples3 + And Byte Ptr [SI], Not 1 + + Jmp MixSamplesEnd +; Cmp MixMode, 8 ; Is it volume ramping? +; JB MixSamplesEnd + +MixSamples3: + Test CL, 20h ; New freq? + JZ MixSamples5 + + Mov AX, [SI+10h] + Mov DX, [SI+12h] + Mov BX, MixSpeed + Cmp DX, BX + JAE MixSamplesHandleError + + Div BX + ShL EAX, 16 + Xor AX, AX + Div BX + Mov STEPVALUE, EAX + +MixSamples4: + Test CH, 1 + JZ MixSamples5 + + Mov DWord Ptr [SI+1Ch], 0 ; Current Volume = 0 + ; for volume sliding. +MixSamples5: + Test CX, 8440h ; New volume or panning? + JZ MixSamplesMix + + Xor AX, AX + Test CH, 8 ; Muted? + JNZ MixModeCommon + + Mov BX, MixMode + Add BL, Stereo + Add BX, BX + Jmp [CS:MixModeTable+BX] + +Mix0Mode: ; 16-bit mixing, no interpolation +Mix0ModeMono: ; and 16-bit mixing, interpolation + Mov AL, [SI+20h] + ShR AL, 1 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 30 ; Use left only-mixing for mono + Jmp MixModeCommon + +Mix0ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix0ModeSurround + + Mul Byte Ptr [SI+20h] ; Final volume + Add AX, 64 + ShR AX, 7 + Mov [SI+0Ch], AX ; Store into right volume + + Mov AL, 64 + Sub AL, [SI+37h] + Mul Byte Ptr [SI+20h] + Add AX, 64 + ShR AX, 7 + Mov [SI+0Eh], AX ; Left volume + + Mov CH, AL ; CH = left volume + Mov CL, [SI+0Ch] ; CL = right volume + Mov AX, 0 + + Test CX, CX + JZ MixModeCommon + + Mov AL, 30 ; Left only... + Test CL, CL + JZ MixModeCommon + + Mov AL, 60 + Test CH, CH + JZ MixModeCommon + + Mov AL, 90 + Cmp CL, CH + JZ MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix0ModeSurround: + Mov AL, [SI+20h] + ShR AL, 2 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Mov AX, 0 + JZ MixModeCommon + Mov AL, 150 ; Surround + Jmp MixModeCommon + +Mix6ModeMono: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 8 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + Test AX, AX + JZ MixModeCommon + Mov AX, 30 + Jmp MixModeCommon + +Mix6ModeStereo: + Mov AL, [SI+37h] ; Final pan + Cmp AL, 100 + JE Mix6ModeSurround + + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Ch], AX ; Store into right volume + Mov BX, AX + ShL EAX, 16 + + Mov AL, 64 ; Do left volume + Sub AL, [SI+37h] ; AL = 64-FinalPan + Mul Byte Ptr MixVolume + Mul Word Ptr [SI+4Ah] + ShRD AX, DX, 14 + Mov [SI+0Eh], AX + + Mov ECX, EAX + + ; BX = right volume + ; CX = Left volume + Mov AX, 0 + Test ECX, ECX + JZ MixModeCommon + + Mov AL, 30 + Test BX, BX + JZ MixModeCommon + + Mov AL, 60 + Test CX, CX + JZ MixModeCommon + + Mov AL, 90 + Cmp CX, BX + JE MixModeCommon + + Mov AL, 120 + Jmp MixModeCommon + +Mix6ModeSurround: + Mov AX, [SI+4Ah] + Mul MixVolume + ShRD AX, DX, 9 + Mov [SI+0Ch], AX + Mov [SI+0Eh], AX + JZ MixModeCommon + Mov AX, 150 + Jmp MixModeCommon + +MixModeCommon: ; Requires AX = 30/60/90 etc. depending + ; On mixing mode type. + ; This will add 180 for 16-bit, + ; And sort out loop types. + Mov BL, [SI+0Ah] + Test Byte Ptr [SI+18h], 2 ; 16 bit? + JZ MixModeCommon1 + + Add AX, 180 + +MixModeCommon1: + Cmp BL, 8 + JB MixModeCommon3 ; No loop + JE MixModeCommon2 ; Forwards loop + + Add AX, 10 + +MixModeCommon2: + Add AX, 10 + +MixModeCommon3: + Add AX, Offset MixFunctionTables + Add AX, MixModeOffset + Mov [SI+8], AX ; Offset... + +MixSamplesMix: + Mov BX, [SI+8] ; BX = offset into + Mov EAX, [CS:BX+2] + Mov DWord Ptr PreMixFunction, EAX + Mov EAX, [CS:BX+6] + Mov DWord Ptr MixFunctionSeparateBackwards, EAX + + Mov AX, BytesToMix + Mov MixBlockSize, AX + Mov MixBufferOffset, MIXTABLESIZE + + Mov EAX, CURRENTPOSITION + Mov OLDPOSITION, EAX + + Call Word Ptr [CS:BX] + + And Word Ptr [SI], 0111100010001101b + Jmp MixSamplesEnd + +MixSamplesHandleError: + Mov Word Ptr [SI], 200h + + Test Byte Ptr [SI+3Ah], 80h + JNZ MixSamplesEnd + + Mov BX, [SI+38h] + And Byte Ptr [BX], Not 4 ; Turn off channel + +MixSamplesEnd: + Pop CX + +MixSamplesEnd2: + Add SI, 128 + Dec CX + JNZ MixSamples2 + + Ret + +EndP MixSamples + +; + +Proc WSSIRQHandler + + Push AX + Push BX + Push DS + + Push CS + Pop DS + Assume DS:Driver + + Add TimerAccumulator, TIMERCONST + JC WSSIRQHandler11 + + Mov AL, 20h + Out 20h, AL + Jmp WSSIRQHandler12 + +WSSIRQHandler11: + PushF + Call [OldTimerIRQHandler] + +WSSIRQHandler12: + +DMAPort1 EQU $+1 + In AL, 1 + Mov AH, AL +DMAPort2 EQU $+1 + In AL, 1 + XChg AL, AH + + Cmp MixBufferPos, 0 + JE WSSIRQHandler13 + + Xor BX, BX +DMABufferLength1 EQU $+1 + Cmp AX, 1234h + JB WSSIRQHandler1 + + Pop DS + Pop BX + Pop AX + IRet + +WSSIRQHandler13: + Mov BX, DMABUFFERLENGTH/2 +DMABufferLength2 EQU $+1 + Cmp AX, 1234h + JAE WSSIRQHandler1 + + Pop DS + Pop BX + Pop AX + IRet + +WSSIRQHandler1: + Xor MixBufferPos, 1 + + PushAD + Push ES + + CLD + + + ; OK... time to get next block + ; Check whether stereo thing is on.. + ; + LES DI, [ActualDMAPtr] + Add DI, BX + + Mov BX, DMABUFFERLENGTH/4 ; BX = samples required + Mov BP, 8 ; Skip for mono + Mov CL, 14 ; Shift for mono + + Cmp Stereo, 0 + JE WSSIRQHandlerMono + + Mov BP, 4 ; Stereo skip value. + Dec CL + +WSSIRQHandlerMono: + Call SaveEMSPageFrame + + Cmp MixTransferRemaining, 0 + JNE WSSIRQHandler4 + Assume DS:Nothing + +WSSIRQHandler3: + Push BX + Push CX + Push BP + Push ES + Push DI + + Call Update + Call MixSamples + + Pop DI + Pop ES + Pop BP + Pop CX + Pop BX + +WSSIRQHandler4: + Mov DS, MixSegment + Mov SI, MixTransferOffset + Mov DX, BX ; DX = samples to transfer + Cmp DX, MixTransferRemaining + JBE WSSIRQHandler5 + + Mov DX, MixTransferRemaining + +WSSIRQHandler5: + Push DX + Cmp CS:Filter, 1 + JB WSSIRQHandler6 + JE WSSIRQHFilter + + Cmp CS:Stereo, 0 + JE WSSIRQ3QFilterMono + +WSSIRQ3QFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQ3QFilterStereo1: + Mov EAX, EBX + Mov ECX, EBP + Add EAX, [SI] + Add ECX, [SI+4] + SAR EAX, 1 + SAR ECX, 1 + Add EBX, EAX + Add EBP, ECX + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip2 + +WSSIRQ3QFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSS3QFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSS3QFilterStereoClip4 + +WSSIRQ3QFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQ3QFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQ3QFilterMono1: + Mov EAX, EBX + Add EAX, [SI] + SAR EAX, 1 + Add EBX, EAX + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSS3QFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSS3QFilterMonoClip2 + +WSSIRQ3QFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQ3QFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilter: + Cmp CS:Stereo, 0 + JE WSSIRQHFilterMono + +WSSIRQHFilterStereo: + Push BX + + Mov EBX, FilterValue + Mov EBP, FilterValue2 + ShR DX, 1 + +WSSIRQHFilterStereo1: + Add EBX, [SI] + Add EBP, [SI+4] + + SAR EBX, 1 + SAR EBP, 1 + + Mov EAX, EBX + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip2 + +WSSIRQHFilterStereo2: + StosW + + Mov EAX, EBP + SAR EAX, 13 + + Cmp EAX, -8000h + JL WSSHFilterStereoClip3 + Cmp EAX, 7FFFh + JG WSSHFilterStereoClip4 + +WSSIRQHFilterStereo3: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterStereo1 + + Mov FilterValue, EBX + Mov FilterValue2, EBP + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHFilterMono: + Push BX + + Mov EBX, FilterValue + +WSSIRQHFilterMono1: + Add EBX, [SI] + SAR EBX, 1 + Mov EAX, EBX + SAR EAX, 14 + + Cmp EAX, -8000h + JL WSSHFilterMonoClip1 + Cmp EAX, 7FFFh + JG WSSHFilterMonoClip2 + +WSSIRQHFilterMono2: + StosW + + Add SI, 8 + Dec DX + JNZ WSSIRQHFilterMono1 + + Mov FilterValue, EBX + + Pop BX + + Jmp WSSMixTransferEnd + +WSSIRQHandler6: + Mov EAX, [SI] + SAR EAX, CL + + Cmp EAX, -8000h + JL WSSIRQHandlerClip1 + Cmp EAX, 7FFFh + JG WSSIRQHandlerClip2 + +WSSIRQHandler7: + StosW ; } Memory write + + Add SI, BP + Dec DX + JNZ WSSIRQHandler6 + +WSSMixTransferEnd: + Pop DX + + Sub MixTransferRemaining, DX ; } Memory write + Sub BX, DX + JNZ WSSIRQHandler3 + + Mov MixTransferOffset, SI ; } Memory write + + Call RestoreEMSPageFrame + + Pop ES + PopAD + Pop DS + Pop BX + Pop AX + IRet + +WSSIRQHandlerClip1: + Mov AX, 8000h + Jmp WSSIRQHandler7 + +WSSIRQHandlerClip2: + Mov AX, 7FFFh + Jmp WSSIRQHandler7 + +WSSHFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterMono2 + +WSSHFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterMono2 + +WSSHFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo2 + +WSSHFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQHFilterStereo3 + +WSSHFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQHFilterStereo3 + +WSS3QFilterMonoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterMonoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterMono2 + +WSS3QFilterStereoClip1: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip2: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo2 + +WSS3QFilterStereoClip3: + Mov AX, 8000h + Jmp WSSIRQ3QFilterStereo3 + +WSS3QFilterStereoClip4: + Mov AX, 7FFFh + Jmp WSSIRQ3QFilterStereo3 + +EndP WSSIRQHandler + Assume DS:Nothing + +; + +Proc WSSAckIRQ + + Push AX + Push DX + + Mov DX, [CS:BasePort] + Add DX, 6 + In AL, DX + Test AL, 1 + JZ WSSAckIRQ2 + + Xor AL, AL + Out DX, AL + +WSSAckIRQ2: + Mov AL, 20h + Cmp CS:IRQ, 8 + JB WSSAckIRQ1 + + Out 0A0h, AL + +WSSAckIRQ1: + Out 20h, AL + + Pop DX + Pop AX + + IRet + +EndP WSSAckIRQ + +; + +Proc SetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + ; bump the interrupt to be called + ; 100 times a second. + Mov AX, TIMERCONST + Out 40h, AL + Mov AL, AH + Out 40h, AL + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSIRQHandler + + ClI + + XChg [ES:20h], EAX ; Hook to timer interrupt + Mov CS:OldTimerIRQHandler, EAX + + StI + + ; Now hook WSS ACK IRQ + Mov DI, IRQ + ShL DI, 2 + Add DI, Offset IRQData + Mov BX, [CS:DI] + + Mov AX, CS + ShL EAX, 16 + Mov AX, Offset WSSACKIRQ + + XChg [ES:BX], EAX + Mov OldWSSIRQHandler, EAX + + Mov AX, IMR + And AX, [DI+2] + + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Pop ES + PopAD + + Ret + +EndP SetIRQ + Assume DS:Nothing + +; + +Proc ResetIRQ + + PushAD + Push ES + + Xor AX, AX + Mov ES, AX + + Mov AL, 34h ; Program IRQ 0. LSB&MSB, Rate gen + Out 43h, AL + + Xor AL, AL + Out 40h, AL ; Interrupt called at normal 18.2 times + Out 40h, AL + + Mov EAX, CS:OldTimerIRQHandler + Mov [ES:20h], EAX + + Mov DI, IRQ + ShL DI, 2 + Mov BX, [IRQData+DI] + + Mov EAX, OldWSSIRQHandler + Mov [ES:BX], EAX + + Pop ES + PopAD + + Ret + +EndP ResetIRQ + Assume DS:Nothing + +; + +Proc StopWSS + + Mov DX, BasePort + Add DX, WSS_BASE + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + And AL, Not INTF_PEN + Out DX, AL + + Inc DX + In AL, DX + Xor AL, AL + Out DX, AL + + Dec DX + Dec DX + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Xor AL, AL + Out DX, AL + + Ret + +EndP StopWSS + +; + +Proc StartWSS + + PushA + Push ES + Push DS + + Push CS + Pop DS + Assume DS:Driver + + ; Setup DMA + Mov BX, DMASegment + Xor AX, AX + Mov DX, DMA + Mov DI, DMABUFFERLENGTH + Call SetDMA + + LES DI, ActualDMAPtr + Xor AX, AX + Mov CX, DMABUFFERLENGTH/2 + Rep StosW + + Mov MixBufferPos, 0 + Mov MixTransferRemaining, 0 + + Mov DX, BasePort + Call PingWSS + + Add DX, WSS_BASE + + Mov AL, CODEC_INDEX_PIN + Out DX, AL + Inc DX + Mov AL, PIN_IEN + Out DX, AL + Dec DX + + Mov AH, WSSMixConst ; Set format/frequency + Cmp Stereo, 0 + JE StartWSS1 + + Or AH, CDF_STEREO + +StartWSS1: + Mov AL, CODEC_MCE or CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitCodec + + Mov AL, CODEC_INDEX_CDF + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Call WaitAutoCalibration + + ; Start playback + Mov AL, CODEC_INDEX_LWR_COUNT + Out DX, AL + Inc DX + + Mov AX, 0FFFFh + + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_UPR_COUNT + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_INTF + Out DX, AL + Inc DX + In AL, DX + Or AL, INTF_PEN + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not LDC_LDM + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + In AL, DX + And AL, Not RDC_RDM + Out DX, AL + Dec DX + + Pop DS + Pop ES + PopA + + Ret + +EndP StartWSS + Assume DS:Nothing + +; InitSound +; +; Sets up any memory required for output +; Initiates output +; +; Parameters: AX = Number of Channels +; +; If sucessful, returns: +; Carry flag clear +; DS:SI = pointer to text to display +; AX = parameter 1 in text +; BX = parameter 2 in text +; CX = parameter 3 in text +; DX = parameter 4 in text +; DI = parameter 5 in text +; +; If unsucessful, returns: +; Carry flag set +; +; + +Proc InitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov SI, Offset RelocationTable + +RelocationFix: + LodsW + Test AX, AX + JZ RelocationEnd + Mov BX, AX + Mov [BX], DS + Jmp RelocationFix + + +RelocationEnd: + Call GetEMSPageFrame + Mov EMSPageFrame, AX + + In AL, 0A1h + Mov AH, AL + In AL, 21h + Mov IMR, AX + + Mov ECX, IdleUpdateInfoLine + Mov EDX, GlobalKeyList + Mov IdleFunctionList, ECX + Mov GlobalKeyLink2, EDX + + Mov ECX, FillHeaderFunction + Mov EDX, DrawHeaderFunction + Mov FillHeader2, ECX + Mov ScreenHeader2, EDX + + Call GetWSSMixConst + + Mov AX, 2643 + Mul MixSpeed + Add AX, 0FFFFh + AdC DX, 2080 + + Mov BX, (DMABUFFERLENGTH*2)/16 + Add BX, DX + + ; Allocate MixSegment first + Mov AH, 48h + + Int 21h + JNC InitSound1 + +InitSoundNoMemory: + Mov SI, Offset WSSNoMemoryMsg + Ret + +InitSound1: + Mov MixSegment, AX + Add AX, DX + Mov DMASegment, AX + + Call SetIRQ + Call GetTempo + Call SetTempo + + Mov SI, Offset WSSMsg + + Mov AX, BasePort + Mov BX, IRQ + Mov CX, DMA + + Ret + +EndP InitSound + Assume DS:Nothing + +; ReInitSound +; +; Reinitialises sound output +; Initiates sound output +; +; Parameters: AX = number of channels. +; +; + +Proc ReInitSound Far + + PushA + Push DS + Push ES + + Push CS + Pop DS + Assume DS:Driver + + Call ResetIRQ + Call SetIRQ + + Mov SI, Offset ReInitMsg + Mov BX, 40 + Call SetInfoLine + + Mov AL, Stereo + Call SetStereo + + Pop ES + Pop DS + PopA + + Ret + +EndP ReInitSound + Assume DS:Nothing + +; UnInitSound +; +; Stops sound output, releases any memory used by driver +; +; + +Proc UnInitSound Far + + Push CS + Pop DS + Assume DS:Driver + + Mov AX, IMR + Out 21h, AL + Mov AL, AH + Out 0A1h, AL + + Mov AX, MixSegment + Test AX, AX + JZ UnInitSound1 + + Mov ES, AX + Mov AH, 49h ; Release MixSegment + Int 21h + + Call StopWSS + Call ResetIRQ + +UnInitSound1: + Ret + +EndP UnInitSound + Assume DS:Nothing + +; Poll +; +; This procedure is called as often as possible by IT.EXE +; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song) +; +; + +Proc Poll Far + + Ret + +EndP Poll + +; SetTempo +; +; Parameters: BX = tempo +; +; + +Proc SetTempo Far + + Push AX + Push BX + Push DX + + Push BX + + Mov AX, MixSpeed + Mov BX, AX + Xor DX, DX + + ShL AX, 1 + RCL DX, 1 ; DX:AX = Mixspeed*2 + + ShR BX, 1 ; BX = Mixspeed/2 + + Add AX, BX + AdC DX, 0 ; DX:AX = Mixspeed*2.5 + + Pop BX ; BX = tempo + Div BX + + Mov BytesToMix, AX + + Pop DX + Pop BX + Pop AX + + Ret + +EndP SetTempo + +; SetMixVolume +; +; Parameters: AX = MixVolume +; +; + +Proc SetMixVolume Far + + PushA + Push DS + + Mov BX, AX ; BX = MixVolume + Mov CS:MixVolume, BX + + Mov AX, CS:MixSegment + Test AX, AX + JZ SetMixVolume2 + + Mov DS, AX + + Mov CX, MIXTABLESIZE/2 + Mov SI, MIXTABLESIZE-2; Starting point - working backwards + +SetMixVolume1: + Mov AX, CX + + Dec AX ; AH = volume, AL = wave value. + Xor DX, DX + XChg AH, DL ; DL = Volume, AX = wave value + CBW + + IMul DX ; DX:AX = Volume * Wave Value + ; Ranges -8192->8128 + + IMul BX ; DX:AX = Volume * Wave Value * Mixing Volume + ; Ranges -1048576->1040384 + + Add AX, 64 + AdC DX, 0 + + ShRD AX, DX, 7 + Mov [SI], AX + Sub SI, 2 + + Loop SetMixVolume1 + +SetMixVolume2: + Mov DS, Word Ptr [CS:RecalculateAllVolumes+2] + Call CS: RecalculateAllVolumes + + Pop DS + PopA + + Ret + +EndP SetMixVolume + +; SetStereo +; +; Parameters: AL = Stereo on/off, 0 = off. +; +; + +Proc RecalculateAllFrequencies + + Call GetChannelTables + +RecalculateAllFrequencies1: + Or Byte Ptr [SI], 32 + + Add SI, 128 + Dec CX + JNZ RecalculateAllFrequencies1 + + Ret + +EndP RecalculateAllFrequencies + +; + +Proc SetStereo Far + + Mov CS:Stereo, AL + Cmp CS:MixSegment, 0 + JE SetStereo1 + + Call StopWSS + Call StartWSS + + Call RecalculateAllFrequencies + +SetStereo1: + Ret + +EndP SetStereo + +; LoadSample +; +; Parameters: AX = sample to load +; DS:SI points to sample header +; ES:0 points to first sample +; +; Returns: **Carry set if NO error** +; **Carry clear if error** +; + +Proc LoadSample Far ; Fix up end of sample bytes + + PushAD + Push DS + Push ES + Push FS + + Mov FS, CS:SongDataArea + Mov BP, AX + Add BP, BP + Mov BP, [FS:64910+BP] + + Xor CX, CX ; From the start of the sample.. + Call GetSampleLocation ; Returns DS:ESI, ECX = length + JC LoadSampleEnd ; Zero flag ON if 16 bit.. + + Xor EAX, EAX + Mov BL, [FS:BP+12h] + + Test BL, 10h ; Loop + JZ LoadSample2 + + Mov ESI, [FS:BP+34h] ; Start of loop + Test BL, 40h ; Pingpong? + JZ LoadSample1 + + Mov ESI, [FS:BP+38h] + Sub ESI, 2 + JNC LoadSample1 + + Xor ESI, ESI + +LoadSample1: + Test BL, 2 + JZ LoadSample4 + + Add ESI, ESI + +LoadSample4: + Call UpdateSampleLocation + Mov AL, [SI] + Inc ESI + Call UpdateSampleLocation + Mov AH, [SI] + +LoadSample2: + Mov ESI, [FS:BP+30h] + Test BL, 2 + JZ LoadSample3 + + Add ESI, ESI + +LoadSample3: + Call UpdateSampleLocation + Mov [SI], AL + Inc ESI + Call UpdateSampleLocation + Mov [SI], AH + +LoadSampleEnd: + Pop FS + Pop ES + Pop DS + PopAD + + StC + Ret + +EndP LoadSample + +; ReleaseSample +; +; Parameters: AX = sample to release +; DS:SI points to sample header +; +; + +Proc ReleaseSample Far + + Ret + +EndP ReleaseSample + +; ResetMemory +; +; Frees all on-board memory +; +; + +Proc ResetMemory Far + + Ret + +EndP ResetMemory + +; GetStatus +; +; Frees all on-board memory +; +; Returns text to show on status line, AX = display parameter +; Carry set if not to show anything. +; +; + +Proc GetStatus Far + + StC + Ret + +EndP GetStatus + +; SoundCardScreen +; +; Function to have driver interactive part of program +; +; + +Proc SoundCardScreen Far + + Mov AX, 5 + Mov SI, 1 + Mov CX, CS + Mov DX, Offset WSS16ScreenList + + ClC + Ret + +EndP SoundCardScreen + +; + +Proc GetVariable Far + + Xor AH, AH + Mov AL, [CS:VolumeTable+DI] + Ret + +EndP GetVariable + +; + +Proc SetVariable Far + + Push DS + Push DX + + Push CS + Pop DS + Assume DS:Driver + + Mov [VolumeTable+DI], AL + + Mov DX, BasePort + Add DX, WSS_BASE + + Mov AL, CODEC_INDEX_LDC + Out DX, AL + Inc DX + Mov AX, 3F3Fh + Sub AX, [Word Ptr VolumeTable] + Out DX, AL + Dec DX + + Mov AL, CODEC_INDEX_RDC + Out DX, AL + Inc DX + Mov AL, AH + Out DX, AL + Dec DX + + Pop DX + Pop DS + Ret + +EndP SetVariable + +; + +EndDriver: + +;******** Provided Variable Table ************* + +MaxNumberOfChannels DW 0FFFFh ; Maximum number of channels the + ; driver can handle. + +StopAfterPlay DW 0 +DefaultChannels DW 64 + DW 5 Dup (0) + + +;******** Provided Procedure Table ************* + +ProvidedTableStart: + + DW Offset DetectCard + + DW Offset InitSound ; Playing related + DW Offset ReinitSound + DW Offset UninitSound + + DW Offset Poll + + DW Offset SetTempo ; Sound variable related + DW Offset SetMixVolume + DW Offset SetStereo + + DW Offset LoadSample ; Sample related + DW Offset ReleaseSample + DW Offset ResetMemory + DW Offset GetStatus ; Returns string to show on status line + + DW Offset SoundCardScreen ; Sound card 'screen' + + DW Offset GetVariable ; For interface + DW Offset SetVariable + +ProvidedTableEnd: + DW 32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0) + +EndS + +End diff --git a/it/Tutorial/IT_TUTORIAL.EXE b/it/Tutorial/IT_TUTORIAL.EXE new file mode 100644 index 0000000000000000000000000000000000000000..5e4ade935891758b2319f529f687ddf70c8afc4f GIT binary patch literal 95898 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®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 literal 0 HcmV?d00001 diff --git a/it/Tutorial/TUTE.IT b/it/Tutorial/TUTE.IT new file mode 100644 index 0000000000000000000000000000000000000000..3670081c0ae0cb2d3ea38f3091314804b79ce0bd GIT binary patch literal 75997 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 gKBBK7UidaRm!@0()s0(^ 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
-SY?5gL}Gx0x_FYbSE92 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
Eb%{v^_u7L|;K+b|!*Ks`Sq4osQNqC; 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 +#include +#include +#include +#include + +/* +Registry keys: + BufferSize : in kb. maximum of 64 + BufferThreshold : in kb. maximum of 32 + BufferType : 0->2 for DualBuffer,QuadBuffer,OctBuffer + MixSpeed : in Hz, maximum of 48000. +*/ + +// Registry values. +static int BufferSize = 24; +static int BufferThreshold = 21; +static int BufferType = 2; +static int MixSpeed = 44100; + +// Registry Key stuff. +const char *RegistryKey = "Software\\Jeffrey Lim\\Impulse Tracker VSound Server"; +const char *RegistryKeyBufferSize = "BufferSize"; +const char *RegistryKeyBufferThreshold = "BufferThreshold"; +const char *RegistryKeyBufferType = "BufferType"; +const char *RegistryKeyMixSpeed = "MixSpeed"; + +// Other stuff. +const static LPCTSTR lpszAppName = "VSound Server"; +const static LPCTSTR lpszTitleBar = "Impulse Tracker VSound Server"; +static HRESULT hr; + +static void *BufferUpdateThreadHandle; +static int BufferUpdateThreadID; + +static int Quitting = 0; + +static HANDLE NotifyEventHandle; +static LPDIRECTSOUND lpDS; +static LPDIRECTSOUNDBUFFER lpPDSB, lpSDSB; +static PCMWAVEFORMAT pcmwf = +{ + { + WAVE_FORMAT_PCM, + 2, + 44100, + 4*44100, + 4 + }, + 16 +}; + +HINSTANCE g_hInst; +HWND g_hWnd; + +char TextBuffer[80]; + +static short int ServerPort = 0x401; +static short int DataPort = 0x402; + +static int SoundBufferSize; +static int SoundBufferBlockSize; +static int SoundBufferBlockMask; + +char *BufferTypes[] = +{ + "DualBuffer", + "QuadBuffer", + "OctBuffer" +}; + +const char *ServerID = "ITSERVER"; +const char *NoServer = + "Unable to find VSound.VxD\n" \ + "\n" \ + "Please read the documentation on how to setup VSound.VxD"; + +const char *ServerActive = + "VSound server is active.\n" \ + "\n" + "Please shut down Impulse Tracker first"; + +void __cdecl trace(char *Message, ...) +{ + va_list argptr; + + va_start(argptr, Message); + vsprintf(TextBuffer, Message, argptr); + + PostMessage(g_hWnd, WM_PAINT, 0, 0); +} + +static void VSound_Reset() +{ + _outp(ServerPort, 0); +} + +static void VSound_Identify() +{ + int i, j; + char ServerString[60]; + short int TempValues[2]; + char *BufferInfo = (char*) (&TempValues); + + sprintf(ServerString, "DirectSound VSoundServer 1.0, %dkb %s", BufferSize, BufferTypes[BufferType]); + + j = strlen(ServerString); + for(i = 0; i < 8; i++) _outp(ServerPort, ServerID[i]); + for(i = 0; i < j; i++) _outp(ServerPort, ServerString[i]); + for( ; i < 60; i++) _outp(ServerPort, ' '); + + TempValues[0] = BufferThreshold * 1024; + TempValues[1] = MixSpeed; + for(i = 0; i < 4; i++) _outp(ServerPort, BufferInfo[i] ^ 0xFF); +} + +static int VSound_Detect() +{ + int i; + char Buffer[8]; + + for(i = 0; i < 8; i++) Buffer[i] = _inp(ServerPort); + return memcmp(ServerID, Buffer, sizeof(Buffer)) == 0; +} + +static int VSound_Connected() +{ + if(!Quitting) return _inp(ServerPort); + else return 0; +} + +static void Error(char *Message) +{ + VSound_Reset(); + MessageBox(g_hWnd, Message, "VSound Server Error!", MB_OK); + exit(1); +} + +static void CheckHResult(char *Message) +{ + if(hr) Error(Message); +} + +DWORD WINAPI BufferUpdateThread(void *Parameter) +{ + int UpdatePosition = 0; + int PlayPosition; + int Len1, Len2; + void *Buf1, *Buf2; + int LastBlock; + int Active = 0; + +/* + hr = SetThreadPriority(BufferUpdateThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); + if(!hr) + { + trace("Error code: %d", GetLastError()); + Error("SetThreadPriority failed"); + return; + } + + hr = SetPriorityClass((HANDLE) BufferUpdateThreadID, REALTIME_PRIORITY_CLASS); + if(!hr) { + trace("Error code: %d", GetLastError()); + Error("SetPriorityClass failed"); + return; + } +*/ + + while(1) + { + int CurrentBlock; + int NumberOfBlocks; + + WaitForMultipleObjects(1, // count of object handle array + &NotifyEventHandle, // Handle of event created to signal buffer position updates + FALSE, // return if at least one event is signalled + INFINITE); + + hr = lpSDSB->lpVtbl->GetCurrentPosition(lpSDSB, &PlayPosition, NULL); + CheckHResult("GetCurrentPosition failed"); + + CurrentBlock = PlayPosition / SoundBufferBlockSize; + NumberOfBlocks = (CurrentBlock - LastBlock) & SoundBufferBlockMask; + if(NumberOfBlocks == 0) continue; + + hr = lpSDSB->lpVtbl->Lock(lpSDSB, UpdatePosition, NumberOfBlocks*SoundBufferBlockSize, &Buf1, &Len1, &Buf2, &Len2, 0); + CheckHResult("Lock failed"); + + if(VSound_Connected() != Active) + { + Active = ~Active; + if(Active) + trace("Server active"); + else + trace("Server ready"); + } + +// Update buffer here. + __asm + { + Push EDI + Mov DX, [DataPort] + + Mov EDI, [Buf1] + Mov ECX, [Len1] + Rep InsB + + Mov EDI, [Buf2] + Mov ECX, [Len2] + Rep InsB + + Pop EDI + } + + hr = lpSDSB->lpVtbl->Unlock(lpSDSB, Buf1, Len1, Buf2, Len2); + CheckHResult("Unlock failed"); + + LastBlock = CurrentBlock; + UpdatePosition = LastBlock*SoundBufferBlockSize; + } + + return 0; +} + +void VSound_InitDSound() +{ + int i, NumberOfNotifications; + DSBUFFERDESC DSBDesc; + DSBPOSITIONNOTIFY DSBPositionNotify[8]; + LPDIRECTSOUNDNOTIFY lpDSNotify; + int Len1, Len2; + char *Buf1, *Buf2; + + NumberOfNotifications = 2 << BufferType; + SoundBufferSize = BufferSize*1024; + SoundBufferBlockSize = SoundBufferSize / NumberOfNotifications; + SoundBufferBlockMask = NumberOfNotifications - 1; + + trace("CreateEvemt"); + NotifyEventHandle = CreateEvent(NULL, // Security attributes + FALSE, // Manual reset = FALSE + FALSE, // Signal initial state = FALSE + NULL); // Name + if(!NotifyEventHandle) Error("CreateEvent failed"); + + trace("DirectSoundCreate"); + hr = DirectSoundCreate(NULL, &lpDS, NULL); + CheckHResult("DirectSoundCreate failed"); + + trace("SetCooperativeLevel"); + hr = lpDS->lpVtbl->SetCooperativeLevel(lpDS, GetActiveWindow(), DSSCL_PRIORITY); + CheckHResult("SetCooperativeLevel failed"); + + trace("CreateSoundBuffer (Primary)"); + memset(&DSBDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out. + DSBDesc.dwSize = sizeof(DSBUFFERDESC); + DSBDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; + DSBDesc.dwBufferBytes = 0; + DSBDesc.lpwfxFormat = NULL; + hr = lpDS->lpVtbl->CreateSoundBuffer(lpDS, &DSBDesc, &lpPDSB, NULL); + CheckHResult("CreateSoundBuffer (Primary) failed"); + + trace("SetFormat"); + pcmwf.wf.nSamplesPerSec = MixSpeed; + pcmwf.wf.nAvgBytesPerSec = MixSpeed * 4; + hr = lpPDSB->lpVtbl->SetFormat(lpPDSB, (void*) &pcmwf); + CheckHResult("SetFormat failed"); + + memset(&DSBDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out. + DSBDesc.dwSize = sizeof(DSBUFFERDESC); + DSBDesc.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | + DSBCAPS_GETCURRENTPOSITION2 | + DSBCAPS_STICKYFOCUS | + DSBCAPS_LOCSOFTWARE; + DSBDesc.dwBufferBytes = SoundBufferSize; + DSBDesc.lpwfxFormat = (void*) &pcmwf; + trace("CreateSoundBuffer (Secondary)"); + hr = lpDS->lpVtbl->CreateSoundBuffer(lpDS, &DSBDesc, &lpSDSB, NULL); + CheckHResult("CreateSoundBuffer (Secondary) failed"); + + trace("QueryInterface"); + hr = lpSDSB->lpVtbl->QueryInterface(lpSDSB, &IID_IDirectSoundNotify, &lpDSNotify); + CheckHResult("Error obtaining DirectSoundNotify interface"); + + trace("SetNotificationPositions"); + for(i = 0; i < NumberOfNotifications; i++) + { + DSBPositionNotify[i].dwOffset = i*SoundBufferBlockSize; + DSBPositionNotify[i].hEventNotify = NotifyEventHandle; + } + hr = lpDSNotify->lpVtbl->SetNotificationPositions(lpDSNotify, NumberOfNotifications, DSBPositionNotify); + CheckHResult("SetNotificationPositions failed"); + + trace("Lock (Clear)"); + hr = lpSDSB->lpVtbl->Lock(lpSDSB, 0, 0, &Buf1, &Len1, &Buf2, &Len2, DSBLOCK_ENTIREBUFFER); + CheckHResult("Lock failed"); + + trace("Clearing buffer"); + memset(Buf1, 0, Len1); + + trace("Unlock (Clear)"); + hr = lpSDSB->lpVtbl->Unlock(lpSDSB, Buf1, Len1, Buf2, Len2); + CheckHResult("Unlocked failed"); + + trace("Creating sound thread"); + BufferUpdateThreadHandle = CreateThread(NULL, // Security atributes + 0, // Stack size + BufferUpdateThread, // Pointer to thread starting function + 0, // Parameter to new thread + 0, // Creation flags + &BufferUpdateThreadID); + + hr = SetThreadPriority(BufferUpdateThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); + if(!hr) Error("SetThreadPriority failed"); + +// Set process to realtime priority. +/* + hr = SetPriorityClass((DWORD) _getpid(), REALTIME_PRIORITY_CLASS); + if(!hr) Error("SetPriorityClass failed"); +*/ + trace("Play"); + hr = lpSDSB->lpVtbl->Play(lpSDSB, 0, 0, DSBPLAY_LOOPING); + CheckHResult("Play failed"); + + VSound_Identify(); + trace("Server ready"); +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) +{ + switch(Message) + { + case WM_PAINT: + { + HDC hDC; + PAINTSTRUCT Paint; + RECT Rectangle; + + GetClientRect(hWnd, &Rectangle); + InvalidateRect(hWnd, &Rectangle, TRUE); + + hDC = BeginPaint(hWnd, &Paint); + + SetBkMode(hDC, TRANSPARENT); + + Rectangle.left += 5; + Rectangle.right -= 5; + + DrawText(hDC, TextBuffer, strlen(TextBuffer), &Rectangle, DT_VCENTER | DT_SINGLELINE | DT_LEFT); + EndPaint(hWnd, &Paint); + return 0; + } + break; + + case WM_DESTROY: + case WM_CLOSE: + if(VSound_Connected()) + { + MessageBox(hWnd, ServerActive, "Error!", MB_OK); + return 0; + } + VSound_Reset(); + Quitting = 1; + PostQuitMessage(0); + } + + return DefWindowProc(hWnd, Message, wParam, lParam); +} + +int GetRegistryInteger(const char *KeyName, int Default) +{ + HKEY hkey; + int ReturnValue; + int Size = 4; + + if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, + RegistryKey, + 0, + (LPTSTR) lpszAppName, + 0, + KEY_ALL_ACCESS, + NULL, + &hkey, + NULL + ) == ERROR_SUCCESS) + { + if((hr = RegQueryValueEx(hkey, KeyName, 0, 0, (LPBYTE) &ReturnValue, &Size)) == ERROR_SUCCESS) + { + RegCloseKey(hkey); + return ReturnValue; + } + + RegSetValueEx(hkey, KeyName, 0, REG_DWORD, (LPBYTE) &Default, sizeof(Default)); + RegCloseKey(hkey); + return Default; + } + Error("Unable to access Windows registry"); +} + +void SetRegistryInteger(const char *KeyName, int Value) +{ + HKEY hkey; + + if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, + RegistryKey, + 0, + (LPTSTR) lpszAppName, + 0, + KEY_ALL_ACCESS, + NULL, + &hkey, + NULL + ) == ERROR_SUCCESS) + { + RegSetValueEx(hkey, KeyName, 0, REG_DWORD, (LPBYTE) &Value, sizeof(Value)); + RegCloseKey(hkey); + } + +} + +void GetRegistry() +{ + BufferSize = GetRegistryInteger(RegistryKeyBufferSize, 24); + if(BufferSize < 4 || BufferSize > 64) + { + BufferSize = 24; + SetRegistryInteger(RegistryKeyBufferSize, BufferSize); + } + + BufferThreshold = GetRegistryInteger(RegistryKeyBufferThreshold, 21); + if(BufferThreshold < 2 || BufferThreshold > 32) + { + BufferThreshold = BufferSize >> 1; + SetRegistryInteger(RegistryKeyBufferThreshold, BufferThreshold); + } + + BufferType = GetRegistryInteger(RegistryKeyBufferType, 2); + if(BufferType < 0 || BufferType > 2) + { + BufferType = 2; + SetRegistryInteger(RegistryKeyBufferType, BufferType); + } + + MixSpeed = GetRegistryInteger(RegistryKeyMixSpeed, 44100); + if(MixSpeed < 11025) MixSpeed = 11025; + if(MixSpeed > 64000) MixSpeed = 64000; + SetRegistryInteger(RegistryKeyMixSpeed, MixSpeed); +} + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + MSG msg; + WNDCLASSEX wc; + + g_hInst = hInstance; + + // Window Class parameters. + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = (WNDPROC) WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW);; + wc.hbrBackground= (HBRUSH) (COLOR_WINDOW); + wc.lpszMenuName = lpszAppName; + wc.lpszClassName= lpszAppName; + wc.cbSize = sizeof(WNDCLASSEX); + wc.hIconSm = NULL; + + if(RegisterClassEx(&wc)) + { + // Create window. + g_hWnd = CreateWindow( + lpszAppName, + lpszTitleBar, + WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + 280, + 50, + NULL, + NULL, + hInstance, + NULL + ); + if(g_hWnd) + { + // Lets first see if the VSound server exists. + + if(!VSound_Detect()) + { + trace("Connect to VSound.VxD failed"); + MessageBox(NULL, NoServer, "Error!", MB_OK); + exit(1); + } + + GetRegistry(); + VSound_InitDSound(); + + while( GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return (msg.wParam); + } + } + return 1; +} diff --git a/it/VSound/VXD/DEBUG.INC b/it/VSound/VXD/DEBUG.INC new file mode 100644 index 0000000..b6fdb06 --- /dev/null +++ b/it/VSound/VXD/DEBUG.INC @@ -0,0 +1,1156 @@ +;**************************************************************************** +; * +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY * +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR * +; PURPOSE. * +; * +; Copyright (C) 1993-95 Microsoft Corporation. All Rights Reserved. * +; * +;**************************************************************************** + +NOBUGBUG EQU 1 + + + + + + + + + + +BUGBUG macro d, id, note +endm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +IsDebugOnlyLoaded macro lab + local var, magic +_DBOSTART segment +var label byte +_DBOSTART ends + db 0F7h, 05h + dd OFFSET32 magic +magic dd OFFSET32 var - (MAXSYSTEMLADDR + 1) +ifnb + jz lab +endif + endm + + + + + + + + + + +DPublic MACRO arg +if DEBLEVEL GT DEBLEVELRETAIL + public arg +endif + ENDM + + + + + + + + + + + + + + + +Assumes_Fall_Through MACRO L +ifndef MASM6 +IF2 + IFDEF profileall + IF (?prolog_&L - $) GT 3 + %OUT ERROR: Fall through to &L invalid + .ERR + ENDIF + ELSE + IF (L - $) GT 3 + %OUT ERROR: Fall through to &L invalid + .ERR + ENDIF + ENDIF +ENDIF +else + IFDEF profileall +.errnz ((?prolog_&L - $) GT 3), + ELSE +.errnz ((L - $) GT 3), + ENDIF +endif + + ENDM + + +ifndef Not_VxD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +??avh_parse_one_arg macro arg + ifidni , + ??_fUsesFlagsPushfd equ <> + ??_fUsesFlagsPopfd equ <> + elseifnb + ??_debLevel = arg + endif +endm + +??avh_parse_args macro DL, fUSES_FLAGS + ??_fUsesFlagsPushfd equ + ??_fUsesFlagsPopfd equ + ??_debLevel = DEBLEVELNORMAL + ??avh_parse_one_arg
+ ??avh_parse_one_arg +endm + +Assert_VM_Handle MACRO R, DL, fUSES_FLAGS + LOCAL l1 + +IF DEBLEVEL GT DEBLEVELRETAIL + + ??avh_parse_args
, + +IF DEBLEVEL GE ??_debLevel + +IFNDEF WIN31COMPAT +IF DEBLEVEL LT DEBLEVELMAX + ??_fUsesFlagsPushfd + cmp [R].CB_Signature, VMCB_ID + je SHORT l1 +ENDIF +ENDIF + +IFDIFI , + push ebx + mov ebx, R +ENDIF + VMMCall Debug_Test_Valid_Handle +IFDIFI , + pop ebx +ENDIF + +IFNDEF WIN31COMPAT +IF DEBLEVEL LT DEBLEVELMAX +l1: + ??_fUsesFlagsPopfd +ENDIF +ENDIF + +ENDIF + +ENDIF + ENDM + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Assert_Thread_Handle MACRO R, DL, fUSES_FLAGS + LOCAL l1 + +IF DEBLEVEL GT DEBLEVELRETAIL + + ??avh_parse_args
, + +IF DEBLEVEL GE ??_debLevel + +IF DEBLEVEL LT DEBLEVELMAX + ??_fUsesFlagsPushfd + cmp dword ptr [R.TCB_Signature], SCHED_OBJ_ID_THREAD + je SHORT l1 +ENDIF + +IFDIFI , + push edi + mov edi, R +ENDIF + VMMCall Debug_Test_Valid_Thread_Handle +IFDIFI , + pop edi +ENDIF + +IF DEBLEVEL LT DEBLEVELMAX +l1: + ??_fUsesFlagsPopfd +ENDIF + +ENDIF + +ENDIF + ENDM + + + + + + + + + + + + + + + + + +Assert_Cur_Thread_Handle MACRO R, DL + LOCAL myDebLevel + LOCAL OK + +IF DEBLEVEL GT DEBLEVELRETAIL + +IFB
+ myDebLevel EQU DEBLEVELNORMAL +ELSE + myDebLevel EQU
+ENDIF + +IF DEBLEVEL GE myDebLevel + +IFDIFI , + push edi + mov edi, R +ENDIF + VMMCall Debug_Test_Cur_Thread +IFDIFI , + pop edi +ENDIF + +ENDIF + +ENDIF + ENDM + + + + + + + + + + + + + +Debug_Printf macro fmt, args, dl + local fmtlab, myDebLevel + +ife ?_DBOCODE + ??_fDoit = VMM_TRUE +else + ??_fDoit = FALSE +endif + +if DEBLEVEL GT DEBLEVELRETAIL + +ifb
+ myDebLevel EQU +else + myDebLevel EQU
+endif + +if DEBLEVEL GE myDebLevel + ??_fDoit = VMM_TRUE +endif + +endif + +if ??_fDoit + +ife ?_DBOCODE + +VxD_DEBUG_ONLY_DATA_SEG +fmtlab db fmt, 0 +VxD_DEBUG_ONLY_DATA_ENDS + +else + +ifdef VMMSYS + +VMM_LOCKED_DATA_SEG +fmtlab db fmt, 0 +VMM_LOCKED_DATA_ENDS + +else + +VxD_LOCKED_DATA_SEG +fmtlab db fmt, 0 +VxD_LOCKED_DATA_ENDS + +endif + +endif + + ifb + VMMCall _Debug_Printf_Service, <(OFFSET32 fmtlab), esp> + else + VMMCall _Debug_Printf_Service, <(OFFSET32 fmtlab), esp, args> + endif + +endif + + endm + + + + + + + +CHECK_EOL MACRO f, x, ln + ifdifi , + ifdifi , + ifdifi , + ifdifi , + %OUT Line ln: Unknown symbol (x) in f, taken as NOEOL + endif + endif + endif + endif + +ENDM + +??_Gen_String macro lbl:req, str:req + ife ?_ICODE + ??_segName textequ <_IDATA> + elseife ?_PCODE + ??_segName textequ <_PDATA> + elseife ?_SCODE + ??_segName textequ <_SDATA> + elseife ?_DBOCODE + ??_segName textequ <_DBODATA> + else + ??_segName textequ <_LDATA> + endif + + ??_segName segment + lbl db str + ife ??_nocrlf + db 0dh,0ah + endif + db 0 + ??_segName ends +endm + + +??Trace_Debug_Helper macro typ, str, arg1, arg2 + local string + + ife ?_DBOCODE + ??_fDoit = VMM_TRUE + else + ??_fDoit = 0 + endif + + if (DEBLEVEL GT DEBLEVELRETAIL) OR ??_fDoit + + ??_nocrlf = 0 + ??_debLevel = DEBLEVELNORMAL + + irp x, + ifnb + if ((.TYPE x) AND 20h) GT 0 + ??_debLevel = x + else + Check_EOL , , %(@Line) + ??_nocrlf = 1 + endif + endif + endm + + if DEBLEVEL GE ??_debLevel + ??_fDoit = VMM_TRUE + endif + + endif + + if ??_fDoit + + irpc c, str + ifidn , <"> + ??_is_string = 1 + else + ifidni , <'> + ??_is_string = 1 + else + ??_is_string = 0 + endif + endif + exitm + endm + + if ??_is_string + ??_Gen_String string, + ??_debug_out_str textequ + else + ??_debug_out_str textequ + endif + + ifdef WIN31COMPAT + pushfd + pushad + mov esi, ??_debug_out_str + VMMCall Out_Debug_String + ifidni , + VMMCall Test_Debug_Installed + jz SHORT $+4 + int 1 + endif + popad + popfd + else + push ??_debug_out_str + ifidni , + VMMCall _Debug_Out_Service + else + VMMCall _Trace_Out_Service + endif + endif + + endif + + endm + + + + + + + + + + + + + + + + +irp cond, + +Trace_Out&cond macro str, arg1, arg2 + ?trace_out ,jn&cond, , + endm + +Trace_OutN&cond macro str, arg1, arg2 + ?trace_out ,j&cond, , + endm + +endm + +Trace_Out MACRO str, arg1, arg2 + ??Trace_Debug_Helper , , , +endm + +Trace_OutECXZ macro str, arg1, arg2 + local l1,l2 +if (DEBLEVEL GT DEBLEVELRETAIL) or (?_DBOCODE eq 0) + jecxz l1 + jmp short l2 +l1: Trace_Out , , +l2: +endif + endm + +Trace_OutECXNZ macro str, arg1, arg2 + ?trace_out ,jecxz, , + endm + +Trace_OutEAXz macro str, arg1, arg2 + local l1 +if (DEBLEVEL GT DEBLEVELRETAIL) or (?_DBOCODE eq 0) + or eax,eax + jnz short l1 + Trace_Out , , +l1: +endif + endm + +Trace_OutEAXnz macro str, arg1, arg2 + local l1 +if (DEBLEVEL GT DEBLEVELRETAIL) or (?_DBOCODE eq 0) + or eax,eax + jz short l1 + Trace_Out , , +l1: +endif + endm + +?trace_out macro str, jmpop, arg1, arg2 + Local nomsg +if (DEBLEVEL GT DEBLEVELRETAIL) or (?_DBOCODE eq 0) + jmpop short nomsg + Trace_Out ,, +nomsg: +endif + endm + + + + + + + + + + + + + + + + + + +irp cond, + +Debug_Out&cond ¯o str, arg1 + ?debug_out ,jn&cond, + &endm + +Debug_OutN&cond ¯o str, arg1 + ?debug_out ,j&cond, + &endm + +endm + +Debug_Out MACRO str, arg1, arg2 + ??Trace_Debug_Helper , , , +endm + +Debug_OutECXZ macro str, arg1 + local l1,l2 +if DEBLEVEL GT DEBLEVELRETAIL + jecxz l1 + jmp short l2 +l1: Debug_Out , +l2: +endif + endm + +Debug_OutECXNZ macro str, arg1 + ?debug_out ,jecxz, + endm + +Debug_OutEAXz macro str, arg1 + local l1 +if DEBLEVEL GT DEBLEVELRETAIL + or eax,eax + jnz short l1 + Debug_Out , +l1: +endif + endm + +Debug_OutEAXnz macro str, arg1 + local l1 +if DEBLEVEL GT DEBLEVELRETAIL + or eax,eax + jz short l1 + Debug_Out , +l1: +endif + endm + +?debug_out macro str,jmpop, arg1 + Local nomsg +if DEBLEVEL GT DEBLEVELRETAIL + jmpop short nomsg + Debug_Out , +nomsg: +endif + endm + + + + + + + + +Queue_Out MACRO S, V1, V2, DL + LOCAL Str_Off + LOCAL MyDebLevel + +IF DEBLEVEL GT DEBLEVELRETAIL + +IFB
+ myDebLevel = DEBLEVELNORMAL +ELSE + myDebLevel = DL +ENDIF + +IF DEBLEVEL GE myDebLevel + +_LDATA SEGMENT +Str_Off db S, 0dh,0ah, 0 +_LDATA ENDS + + push esi +IFNB + IF TYPE V1 GT 0 + push dword ptr V1 + ELSE + push V1 + ENDIF +ELSE + push eax +ENDIF +IFNB + IF TYPE V2 GT 0 + push dword ptr V2 + ELSE + push V2 + ENDIF +ELSE + push ebx +ENDIF + mov esi, OFFSET32 Str_Off + VMMCall Queue_Debug_String + pop esi +ENDIF + +ENDIF + ENDM + + + + + + + + +Mono_Out MACRO S, nocrlf + LOCAL Str_Off +IF DEBLEVEL GT DEBLEVELRETAIL +_LDATA SEGMENT +Str_Off db S +IFB + db 0dh,0ah +ENDIF + db 0 +_LDATA ENDS + + pushfd + pushad + mov esi, OFFSET32 Str_Off + VMMCall Out_Mono_String + popad + popfd +ENDIF + ENDM + + + + + + + + +Mono_Out_At MACRO Row, Col, S, nocrlf + LOCAL Str_Off +IF DEBLEVEL GT DEBLEVELRETAIL +_LDATA SEGMENT +Str_Off db S +IFB + db 0dh,0ah +ENDIF + db 0 +_LDATA ENDS + + pushfd + pushad + mov dx, (Row SHL 8)+Col + VMMCall Set_Mono_Cur_Pos + mov esi, OFFSET32 Str_Off + VMMCall Out_Mono_String + popad + popfd +ENDIF + ENDM + + + + + + + + + + +Assert_Ints_Disabled MACRO DL + +IFB
+ ??_debLevel = DEBLEVELNORMAL +ELSE + ??_debLevel = DL +ENDIF + +IF DEBLEVEL GE ??_debLevel + +ifndef ??_aidMessage + _LDATA segment + ??_aidMessage db "ERROR: Ints enabled at Assert_Ints_Disabled" + db 0Dh, 0Ah, 0 + _LDATA ends +endif + pushfd + test byte ptr [esp+1], IF_Mask SHR 8 + .if !ZERO? + push OFFSET32 ??_aidMessage + VMMCall _Debug_Out_Service + .endif + popfd +ENDIF + ENDM + + + + + + + + +Assert_Ints_Enabled MACRO DL + +IFB
+ ??_debLevel = DEBLEVELNORMAL +ELSE + ??_debLevel = DL +ENDIF + +IF DEBLEVEL GE ??_debLevel + +ifndef ??_aieMessage + _LDATA segment + ??_aieMessage db "ERROR: Ints disabled at Assert_Ints_Enabled" + db 0Dh, 0Ah, 0 + _LDATA ends +endif + pushfd + test byte ptr [esp+1], IF_Mask SHR 8 + .if ZERO? + push OFFSET32 ??_aieMessage + VMMCall _Debug_Out_Service + .endif + popfd +ENDIF + ENDM + + + + + + + + + + + + + + + + + +Assert_Cur_VM_Handle MACRO R, DL + LOCAL OK + LOCAL myDebLevel + +IF DEBLEVEL GT DEBLEVELRETAIL + +IFB
+ myDebLevel = DEBLEVELNORMAL +ELSE + myDebLevel = DL +ENDIF + +IF DEBLEVEL GE myDebLevel + +IFDIFI , + push ebx + mov ebx, R +ENDIF + VMMCall Debug_Test_Cur_VM +IFDIFI , + pop ebx +ENDIF + +ENDIF + +ENDIF + ENDM + + +Assert_Client_Ptr MACRO Reg, DL + LOCAL myDebLevel +IF DEBLEVEL GT DEBLEVELRETAIL + +IFB
+ myDebLevel = DEBLEVELNORMAL +ELSE + myDebLevel = DL +ENDIF + +IF DEBLEVEL GE myDebLevel +IFDIFI , + push ebp + mov ebp, Reg +ENDIF + VMMCall Validate_Client_Ptr +IFDIFI , + pop ebp +ENDIF +ENDIF + +ENDIF + ENDM + +endif + + + + + + + + + + + + + + + + + + + + + + + +irp cond, + +TRAP&cond ¯o + ?trap jn&cond + &endm + +TRAPn&cond ¯o + ?trap j&cond + &endm + +TRAPFATAL&cond ¯o + ?trap jn&cond, FATAL + &endm + +TRAPFATALn&cond ¯o + ?trap j&cond, FATAL + &endm +endm + +TRAP macro +if DEBLEVEL GT DEBLEVELRETAIL + int 3 +endif + endm + +TRAPFATAL macro + local l +if DEBLEVEL GT DEBLEVELRETAIL +l: int 3 + jmp short l +endif + endm + +TRAPecxz macro + local l1,l2 +if DEBLEVEL GT DEBLEVELRETAIL + jecxz l1 + jmp short l2 +l1: int 3 +l2: +endif + endm + +TRAPecxnz macro + ?trap jecxz + endm + +?trap macro jmpop, fatal + Local l, n +if DEBLEVEL GT DEBLEVELRETAIL + jmpop short n +l: int 3 +ifnb + jmp short l +endif +n: +endif + endm + +ifndef Not_VxD + + + + +Dump_Struc_Head MACRO +if DEBLEVEL GT DEBLEVELRETAIL + Trace_Out " Base Address Offs Value Field name" +ENDIF + ENDM + +Dump_Struc MACRO Base, X +if DEBLEVEL GT DEBLEVELRETAIL + pushfd + pushad + lea esi, [Base] + mov ecx, X + lea edx, [esi+ecx] + +IF SIZE X EQ 6 + mov bx, WORD PTR [edx+4] + mov eax, DWORD PTR [edx] + Trace_Out "#ESI #EDX #CX #BX:#EAX &X" +ELSE +IF SIZE X EQ 4 + mov eax, DWORD PTR [edx] + Trace_Out "#ESI #EDX #CX #EAX &X" +ELSE +IF SIZE X EQ 2 + mov ax, WORD PTR [edx] + Trace_Out "#ESI #EDX #CX #AX &X" +ELSE + mov al, BYTE PTR [edx] + Trace_Out "#ESI #EDX #CX #AL &X" +ENDIF +ENDIF +ENDIF + + popad + popfd +ENDIF + ENDM + +BeginDoc + + + + + + + + + + + + + + + + + + + + + + + + + + + +EndDoc + +Begin_Touch_1st_Meg MACRO DL + LOCAL myDebLevel +IF DEBLEVEL GT DEBLEVELRETAIL +IFB
+ myDebLevel = DEBLEVELMAX +ELSE + myDebLevel = DL +ENDIF +IF DEBLEVEL GE myDebLevel + VMMCall Enable_Touch_1st_Meg +ENDIF +ENDIF + ENDM + + + +End_Touch_1st_Meg MACRO DL + LOCAL myDebLevel +IF DEBLEVEL GT DEBLEVELRETAIL +IFB
+ myDebLevel = DEBLEVELMAX +ELSE + myDebLevel = DL +ENDIF +IF DEBLEVEL GE myDebLevel + VMMCall Disable_Touch_1st_Meg +ENDIF +ENDIF + ENDM + +endif + +IFDEF DEBUG +TrashThis Macro l:vararg + ?TrashThisVal equ <0FFFFFF80h> + ?TrashThisValSet = 0 + for r, + or r, ?TrashThisVal + ife ?TrashThisValSet + if (OPATTR r) and 10h + ?TrashThisVal equ + ?TrashThisValSet = 1 + endif + endif + endm +endm +ELSE +TrashThis Macro l:vararg +endm +ENDIF + + +ifndef Not_VxD + +if DEBLEVEL GT DEBLEVELRETAIL + +ENTER_NOBLOCK MACRO + push DFS_ENTER_NOBLOCK + VMMCall _Debug_Flags_Service + ENDM + +EXIT_NOBLOCK MACRO + push DFS_EXIT_NOBLOCK + VMMCall _Debug_Flags_Service + ENDM + +Assert_CLD MACRO + pushfd + test dword ptr [esp], DF_MASK + Debug_OutNZ "Direction flag is not clear." + popfd + ENDM + +Assert_Might_Block MACRO + push DFS_TEST_BLOCK + VMMCall _Debug_Flags_Service + ENDM + +Assert_Not_Nest_Exec MACRO + push DFS_TEST_NEST_EXEC + VMMCall _Debug_Flags_Service + ENDM + +ELSE + +ENTER_NOBLOCK EQU <> +EXIT_NOBLOCK EQU <> +Assert_CLD EQU <> +Assert_Might_Block EQU <> +Assert_Not_Nest_Exec EQU <> + +ENDIF + + +ifdef Begin_Service_Table +Begin_Service_Table DEBUG +DEBUG_Service DEBUG_Get_Version, LOCAL +DEBUG_Service DEBUG_Fault, LOCAL +DEBUG_Service DEBUG_CheckFault, LOCAL +DEBUG_Service _DEBUG_LoadSyms +End_Service_Table DEBUG +endif +endif diff --git a/it/VSound/VXD/MVSOUND.BAT b/it/VSound/VXD/MVSOUND.BAT new file mode 100644 index 0000000..b41eb84 --- /dev/null +++ b/it/VSound/VXD/MVSOUND.BAT @@ -0,0 +1,3 @@ +ml -Fl -DBLD_COFF -DIS_32 -W2 -c -Cx -Zm -DMASM6 vsound.asm +link /VXD /NOD /OUT:VSOUND.VxD /MAP:VSOUND.MAP /DEF:VSOUND.DEF vsound +copy vsound.vxd \windows\system\itvsound.vxd diff --git a/it/VSound/VXD/SHELL.INC b/it/VSound/VXD/SHELL.INC new file mode 100644 index 0000000..7083661 --- /dev/null +++ b/it/VSound/VXD/SHELL.INC @@ -0,0 +1,139 @@ +;**************************************************************************** +; * +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY * +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR * +; PURPOSE. * +; * +; Copyright (C) 1993-95 Microsoft Corporation. All Rights Reserved. * +; * +;**************************************************************************** + +ifndef _SHELL_H +_SHELL_H EQU 1 +ifndef Not_VxD +Begin_Service_Table SHELL +SHELL_Service SHELL_Get_Version, LOCAL +SHELL_Service SHELL_Resolve_Contention, LOCAL +SHELL_Service SHELL_Event, LOCAL +SHELL_Service SHELL_SYSMODAL_Message, LOCAL +SHELL_Service SHELL_Message, LOCAL +ifndef WIN30COMPAT +SHELL_Service SHELL_GetVMInfo, LOCAL +endif +ifndef WIN31COMPAT +SHELL_Service _SHELL_PostMessage, LOCAL +SHELL_Service _SHELL_ShellExecute +SHELL_Service _SHELL_PostShellMessage +SHELL_Service SHELL_DispatchRing0AppyEvents, LOCAL +SHELL_Service SHELL_Hook_Properties, LOCAL +SHELL_Service SHELL_Unhook_Properties, LOCAL +SHELL_Service SHELL_Update_User_Activity, LOCAL +SHELL_Service _SHELL_QueryAppyTimeAvailable, LOCAL +SHELL_Service _SHELL_CallAtAppyTime, LOCAL +SHELL_Service _SHELL_CancelAppyTimeEvent +SHELL_Service _SHELL_BroadcastSystemMessage, LOCAL +SHELL_Service _SHELL_HookSystemBroadcast, LOCAL +SHELL_Service _SHELL_UnhookSystemBroadcast, LOCAL +SHELL_Service _SHELL_LocalAllocEx, LOCAL +SHELL_Service _SHELL_LocalFree, LOCAL +SHELL_Service _SHELL_LoadLibrary, LOCAL +SHELL_Service _SHELL_FreeLibrary, LOCAL +SHELL_Service _SHELL_GetProcAddress, LOCAL +SHELL_Service _SHELL_CallDll, LOCAL +SHELL_Service _SHELL_SuggestSingleMSDOSMode +SHELL_Service SHELL_CheckHotkeyAllowed +SHELL_Service _SHELL_GetDOSAppInfo +endif +End_Service_Table SHELL +ifndef WIN31COMPAT +SBH_CALL_ORDER_DEFAULT EQU 0 +SBH_CALL_ORDER_REGISTRY EQU 30000000H +SBH_CALL_ORDER_CONFIGMG EQU 40000000H +endif +MB_OK EQU 00H +MB_OKCANCEL EQU 01H +MB_ABORTRETRYIGNORE EQU 02H +MB_YESNOCANCEL EQU 03H +MB_YESNO EQU 04H +MB_RETRYCANCEL EQU 05H +MB_ICONHAND EQU 10H +MB_ICONEXCLAMATION EQU 30H +MB_ICONASTERISK EQU 40H +MB_DEFBUTTON1 EQU 00H +MB_DEFBUTTON2 EQU 100H +MB_DEFBUTTON3 EQU 200H +MB_APPLMODAL EQU 00H +MB_SYSTEMMODAL EQU 1000H +MB_NOFOCUS EQU 8000H +MB_ASAP EQU 80000000H +MB_NOWINDOW EQU 40000000H +MB_HANGSYS EQU 20000000H +ifndef WIN31COMPAT +MB_APPYTIME EQU 10000000H +endif +IDOK EQU 1 +IDCANCEL EQU 2 +IDABORT EQU 3 +IDRETRY EQU 4 +IDIGNORE EQU 5 +IDYES EQU 6 +IDNO EQU 7 +SE_WP_PrtScBoost EQU 00100000H +SE_WP_PrtScBoostBit EQU 20 +SE_WP_DispUpdBoost EQU 00200000H +SE_WP_DispUpdBoostBit EQU 21 +ifndef WIN31COMPAT +SPM_UM_DoNotWaitForCrit EQU 00020000H +SPM_UM_DoNotWaitForCritBit EQU 17 +SPM_UM_AlwaysSchedule EQU 00080000H +SPM_UM_AlwaysScheduleBit EQU 19 +endif +SGVMI_Windowed EQU 00000004H +SGVMI_ALTTABdis EQU 00000020H +SGVMI_ALTESCdis EQU 00000040H +SGVMI_ALTSPACEdis EQU 00000080H +SGVMI_ALTENTERdis EQU 00000100H +SGVMI_ALTPRTSCdis EQU 00000200H +SGVMI_PRTSCdis EQU 00000400H +SGVMI_CTRLESCdis EQU 00000800H +SGVMI_HasHotKey EQU 00004000H +SGVMI_Polling EQU 00001000H +SGVMI_FastPaste EQU 00020000H +SGVMI_NoHMA EQU 00002000H +SGVMI_XMS_Lock EQU 00010000H +SGVMI_EMS_Lock EQU 00008000H +SGVMI_V86_Lock EQU 00040000H +SGVMI_ClsExit EQU 40000000H +endif +ifndef WIN31COMPAT +ifndef Not_VxD +LMEM_FIXED EQU 0000H +LMEM_ZEROINIT EQU 0040H +LPTR EQU (LMEM_FIXED OR LMEM_ZEROINIT) +LMEM_STRING EQU 00010000H +LMEM_OEM2ANSI EQU 00020000H +QAAFL_APPYAVAIL EQU 00000001H +QAAFL_APPYNOW EQU 00000002H +CAAFL_RING0 EQU 00000001H +CAAFL_TIMEOUT EQU 00000002H +endif + +SHEXPACKET STRUC +shex_dwTotalSize DD ? +shex_dwSize DD ? +shex_ibOp DD ? +shex_ibFile DD ? +shex_ibParams DD ? +shex_ibDir DD ? +shex_dwReserved DD ? +shex_nCmdShow DD ? +SHEXPACKET ENDS +SGDAIF_COMPARENAME EQU 0 +SGDAIF_TESTAPPBIT EQU 1 +SGDAIF_LASTVALID EQU 1 +SGDAIR_SUCCESS EQU 0 +SGDAIR_NOMATCH EQU 1 +SGDAIR_BADFUNCTION EQU 2 +endif +endif diff --git a/it/VSound/VXD/VMM.INC b/it/VSound/VXD/VMM.INC new file mode 100644 index 0000000..db98bb2 --- /dev/null +++ b/it/VSound/VXD/VMM.INC @@ -0,0 +1,4074 @@ +;**************************************************************************** +; * +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY * +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR * +; PURPOSE. * +; * +; Copyright (C) 1993-95 Microsoft Corporation. All Rights Reserved. * +; * +;**************************************************************************** + +ifndef _VMM_ +_VMM_ EQU 1 +FALSE EQU 0 +VMM_TRUE EQU (NOT FALSE) +DEBLEVELRETAIL EQU 0 +DEBLEVELNORMAL EQU 1 +DEBLEVELMAX EQU 2 +ifndef DEBLEVEL +ifdef DEBUG +DEBLEVEL EQU DEBLEVELNORMAL +else +DEBLEVEL EQU DEBLEVELRETAIL +endif +endif +ifndef WIN31COMPAT +WIN40SERVICES EQU 1 +endif +ifdef MASM6 +ifndef NO_MASM6_OPTIONS + + + + option oldmacros +ifndef NEWSTRUCTS + option oldstructs +endif + option noscoped + option segment:flat + option offset:flat + option proc:private +endif +endif + + + + +IFDEF MASM6 +BeginDoc MACRO + ENDM +EndDoc MACRO + ENDM + +BeginMsg MACRO + ENDM +EndMsg MACRO + ENDM +ELSE +BeginDoc EQU <> +EndDoc EQU <> + +BeginMsg EQU <> +EndMsg EQU <> +ENDIF + +UNDEFINED_DEVICE_ID EQU 00000H +VMM_DEVICE_ID EQU 00001H +DEBUG_DEVICE_ID EQU 00002H +VPICD_DEVICE_ID EQU 00003H +VDMAD_DEVICE_ID EQU 00004H +VTD_DEVICE_ID EQU 00005H +V86MMGR_DEVICE_ID EQU 00006H +PAGESWAP_DEVICE_ID EQU 00007H +PARITY_DEVICE_ID EQU 00008H +REBOOT_DEVICE_ID EQU 00009H +VDD_DEVICE_ID EQU 0000AH +VSD_DEVICE_ID EQU 0000BH +VMD_DEVICE_ID EQU 0000CH +VKD_DEVICE_ID EQU 0000DH +VCD_DEVICE_ID EQU 0000EH +VPD_DEVICE_ID EQU 0000FH +BLOCKDEV_DEVICE_ID EQU 00010H +VMCPD_DEVICE_ID EQU 00011H +EBIOS_DEVICE_ID EQU 00012H +BIOSXLAT_DEVICE_ID EQU 00013H +VNETBIOS_DEVICE_ID EQU 00014H +DOSMGR_DEVICE_ID EQU 00015H +WINLOAD_DEVICE_ID EQU 00016H +SHELL_DEVICE_ID EQU 00017H +VMPOLL_DEVICE_ID EQU 00018H +VPROD_DEVICE_ID EQU 00019H +DOSNET_DEVICE_ID EQU 0001AH +VFD_DEVICE_ID EQU 0001BH +VDD2_DEVICE_ID EQU 0001CH +WINDEBUG_DEVICE_ID EQU 0001DH +TSRLOAD_DEVICE_ID EQU 0001EH +BIOSHOOK_DEVICE_ID EQU 0001FH +INT13_DEVICE_ID EQU 00020H +PAGEFILE_DEVICE_ID EQU 00021H +SCSI_DEVICE_ID EQU 00022H +MCA_POS_DEVICE_ID EQU 00023H +SCSIFD_DEVICE_ID EQU 00024H +VPEND_DEVICE_ID EQU 00025H +APM_DEVICE_ID EQU 00026H +VPOWERD_DEVICE_ID EQU APM_DEVICE_ID +VXDLDR_DEVICE_ID EQU 00027H +NDIS_DEVICE_ID EQU 00028H +BIOS_EXT_DEVICE_ID EQU 00029H +VWIN32_DEVICE_ID EQU 0002AH +VCOMM_DEVICE_ID EQU 0002BH +SPOOLER_DEVICE_ID EQU 0002CH +WIN32S_DEVICE_ID EQU 0002DH +DEBUGCMD_DEVICE_ID EQU 0002EH +CONFIGMG_DEVICE_ID EQU 00033H +DWCFGMG_DEVICE_ID EQU 00034H +SCSIPORT_DEVICE_ID EQU 00035H +VFBACKUP_DEVICE_ID EQU 00036H +ENABLE_DEVICE_ID EQU 00037H +VCOND_DEVICE_ID EQU 00038H +ISAPNP_DEVICE_ID EQU 0003CH +BIOS_DEVICE_ID EQU 0003DH +IFSMgr_Device_ID EQU 00040H +VCDFSD_DEVICE_ID EQU 00041H +MRCI2_DEVICE_ID EQU 00042H +PCI_DEVICE_ID EQU 00043H +PELOADER_DEVICE_ID EQU 00044H +EISA_DEVICE_ID EQU 00045H +DRAGCLI_DEVICE_ID EQU 00046H +DRAGSRV_DEVICE_ID EQU 00047H +PERF_DEVICE_ID EQU 00048H +AWREDIR_DEVICE_ID EQU 00049H +ETEN_Device_ID EQU 00060H +CHBIOS_Device_ID EQU 00061H +VMSGD_Device_ID EQU 00062H +VPPID_Device_ID EQU 00063H +VIME_Device_ID EQU 00064H +VHBIOSD_Device_ID EQU 00065H +BASEID_FOR_NAMEBASEDVXD EQU 0f000H +BASEID_FOR_NAMEBASEDVXD_MASK EQU 0fffH +VMM_INIT_ORDER EQU 000000000H +DEBUG_INIT_ORDER EQU 000000000H +DEBUGCMD_INIT_ORDER EQU 000000000H +PERF_INIT_ORDER EQU 000900000H +APM_INIT_ORDER EQU 001000000H +VPOWERD_INIT_ORDER EQU APM_INIT_ORDER +BIOSHOOK_INIT_ORDER EQU 006000000H +VPROD_INIT_ORDER EQU 008000000H +VPICD_INIT_ORDER EQU 00C000000H +VTD_INIT_ORDER EQU 014000000H +VXDLDR_INIT_ORDER EQU 016000000H +ENUMERATOR_INIT_ORDER EQU 016800000H +ISAPNP_INIT_ORDER EQU ENUMERATOR_INIT_ORDER +EISA_INIT_ORDER EQU ENUMERATOR_INIT_ORDER +PCI_INIT_ORDER EQU ENUMERATOR_INIT_ORDER +BIOS_INIT_ORDER EQU ENUMERATOR_INIT_ORDER+1 +CONFIGMG_INIT_ORDER EQU ENUMERATOR_INIT_ORDER+0FFFFH +VCDFSD_INIT_ORDER EQU 016F00000H +IOS_INIT_ORDER EQU 017000000H +PAGEFILE_INIT_ORDER EQU 018000000H +PAGESWAP_INIT_ORDER EQU 01C000000H +PARITY_INIT_ORDER EQU 020000000H +REBOOT_INIT_ORDER EQU 024000000H +EBIOS_INIT_ORDER EQU 026000000H +VDD_INIT_ORDER EQU 028000000H +VSD_INIT_ORDER EQU 02C000000H +VCD_INIT_ORDER EQU 030000000H +COMMDRVR_INIT_ORDER EQU (VCD_INIT_ORDER-1) +PRTCL_INIT_ORDER EQU (COMMDRVR_INIT_ORDER-2) +MODEM_INIT_ORDER EQU (COMMDRVR_INIT_ORDER-3) +PORT_INIT_ORDER EQU (COMMDRVR_INIT_ORDER-4) +VMD_INIT_ORDER EQU 034000000H +VKD_INIT_ORDER EQU 038000000H +VPD_INIT_ORDER EQU 03C000000H +BLOCKDEV_INIT_ORDER EQU 040000000H +MCA_POS_INIT_ORDER EQU 041000000H +SCSIFD_INIT_ORDER EQU 041400000H +SCSIMASTER_INIT_ORDER EQU 041800000H +INT13_INIT_ORDER EQU 042000000H +VMCPD_INIT_ORDER EQU 048000000H +BIOSXLAT_INIT_ORDER EQU 050000000H +VNETBIOS_INIT_ORDER EQU 054000000H +DOSMGR_INIT_ORDER EQU 058000000H +DOSNET_INIT_ORDER EQU 05C000000H +WINLOAD_INIT_ORDER EQU 060000000H +VMPOLL_INIT_ORDER EQU 064000000H +UNDEFINED_INIT_ORDER EQU 080000000H +WIN32_INIT_ORDER EQU UNDEFINED_INIT_ORDER +VCOND_INIT_ORDER EQU UNDEFINED_INIT_ORDER +WINDEBUG_INIT_ORDER EQU 081000000H +VDMAD_INIT_ORDER EQU 090000000H +V86MMGR_INIT_ORDER EQU 0A0000000H +IFSMgr_Init_Order EQU 10000H+V86MMGR_Init_Order +FSD_Init_Order EQU 00100H+IFSMgr_Init_Order +VFD_INIT_ORDER EQU 50000H+IFSMgr_Init_Order +UNDEF_TOUCH_MEM_INIT_ORDER EQU 0A8000000H +SHELL_INIT_ORDER EQU 0B0000000H + + + + + + +IO_Delay macro +jmp $+2 +ENDM + +VXD_FAILURE EQU 0 +VXD_SUCCESS EQU 1 + +Pushad_Struc STRUC +Pushad_EDI DD ? +Pushad_ESI DD ? +Pushad_EBP DD ? +Pushad_ESP DD ? +Pushad_EBX DD ? +Pushad_EDX DD ? +Pushad_ECX DD ? +Pushad_EAX DD ? +Pushad_Struc ENDS +ifndef Not_VxD +??_CUR_CODE_SEG = 0 + +??_LCODE = 1 +??_ICODE = 2 +??_PCODE = 3 +??_SCODE = 4 +??_DBOCODE = 5 +??_16ICODE = 6 +??_RCODE = 7 +??_LOCKABLECODE = 8 + +?_LCODE equ <(??_CUR_CODE_SEG MOD 16) - ??_LCODE> +?_ICODE equ <(??_CUR_CODE_SEG MOD 16) - ??_ICODE> +?_PCODE equ <(??_CUR_CODE_SEG MOD 16) - ??_PCODE> +?_SCODE equ <(??_CUR_CODE_SEG MOD 16) - ??_SCODE> +?_DBOCODE equ <(??_CUR_CODE_SEG MOD 16) - ??_DBOCODE> +?_16ICODE equ <(??_CUR_CODE_SEG MOD 16) - ??_16ICODE> +?_RCODE equ <(??_CUR_CODE_SEG MOD 16) - ??_RCODE> +?_LOCKABLECODE equ <(??_CUR_CODE_SEG MOD 16) - ??_LOCKABLECODE> + +ifndef NO_SEGMENTS + + + + + +IFDEF MASM6 +_FLAT EQU FLAT +ELSE +_FLAT EQU USE32 +ENDIF + + +_LTEXT SEGMENT DWORD PUBLIC _FLAT 'LCODE' +_LTEXT ENDS + +_TEXT SEGMENT DWORD PUBLIC _FLAT 'LCODE' +_TEXT ENDS + + +_PTEXT SEGMENT DWORD PUBLIC _FLAT 'PCODE' +_PTEXT ENDS + + + +MakeCodeSeg MACRO seglist, classname, grpname, iseg + + IRP segname, + +IFNB + segname SEGMENT DWORD PUBLIC _FLAT "&classname&CODE" +ELSE + segname SEGMENT DWORD PUBLIC _FLAT "&segname&CODE" +ENDIF + +IFB +VxD_&&segname&&_CODE_SEG MACRO +segname SEGMENT +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 4 + ??_PCODE + ASSUME cs:FLAT, ds:FLAT, es:FLAT, ss:FLAT + + ENDM +ELSE +VxD_&&segname&&_CODE_SEG MACRO +segname SEGMENT +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 4 + iseg + ASSUME cs:FLAT, ds:FLAT, es:FLAT, ss:FLAT + + ENDM +ENDIF + +VxD_&&segname&&_CODE_ENDS MACRO +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 4 +segname ENDS + ENDM + +segname ENDS + +IFNDEF BLD_COFF +IFNB + _&grpname GROUP segname +ELSE + _&&segname GROUP segname +ENDIF +ENDIF + + ENDM + + ENDM + +MakeCodeSeg , \ + LOCKABLE, LOCKABLE, ??_LOCKABLECODE +MakeCodeSeg INT21 +MakeCodeSeg SYSEXIT +MakeCodeSeg RARE +MakeCodeSeg W16 +MakeCodeSeg W32 +MakeCodeSeg VMCREATE +MakeCodeSeg VMDESTROY +MakeCodeSeg THCREATE +MakeCodeSeg THDESTROY +MakeCodeSeg VMSUSPEND +MakeCodeSeg VMRESUME +MakeCodeSeg PNP +MakeCodeSeg DOSVM + + + + + + + + + + + +DefLockableCodeBegin MACRO name, private +VxD_LOCKABLE_BEGIN_CODE_SEG +IFB + PUBLIC name +ENDIF +name LABEL NEAR +VxD_LOCKABLE_BEGIN_CODE_ENDS +ifndef WIN31COMPAT +if DEBLEVEL +VxD_LOCKED_DATA_SEG + PUBLIC name&_Debug_Flags +name&_Debug_Flags DD DFS_TEST_BLOCK +VxD_LOCKED_DATA_ENDS +??_debug_flags equ +endif +endif + ENDM + + + + + + + + + +DefLockableCodeEnd MACRO name, private +VxD_LOCKABLE_END_CODE_SEG +IFB + PUBLIC name +ENDIF +name LABEL NEAR +VxD_LOCKABLE_END_CODE_ENDS + ENDM + + + + + +CodeLockFlags MACRO name +ifndef WIN31COMPAT +if DEBLEVEL + ifndef name&_Debug_Flags + VxD_LOCKED_DATA_SEG + extrn name&_Debug_Flags:dword + VxD_LOCKED_DATA_ENDS + ??_debug_flags equ + endif +endif +endif + ENDM + + + + + + +MarkCodeLocked MACRO +ifndef WIN31COMPAT +if DEBLEVEL +ifdef ??_debug_flags + pushfd + and ??_debug_flags,NOT DFS_TEST_BLOCK + popfd +endif +endif +endif + ENDM + + + + + + +MarkCodeUnlocked MACRO +ifndef WIN31COMPAT +if DEBLEVEL +ifdef ??_debug_flags + pushfd + or ??_debug_flags,DFS_TEST_BLOCK + popfd +endif +endif +endif + ENDM + + + +_ITEXT SEGMENT DWORD PUBLIC _FLAT 'ICODE' +_ITEXT ENDS + + +_LDATA SEGMENT DWORD PUBLIC _FLAT 'LCODE' +_LDATA ENDS + +_DATA SEGMENT DWORD PUBLIC _FLAT 'LCODE' +_DATA ENDS + + +_PDATA SEGMENT DWORD PUBLIC _FLAT 'PDATA' +_PDATA ENDS + + +_IDATA SEGMENT DWORD PUBLIC _FLAT 'ICODE' +_IDATA ENDS + + +_BSS SEGMENT DWORD PUBLIC _FLAT 'LCODE' +_BSS ENDS + +CONST SEGMENT DWORD PUBLIC _FLAT 'LCODE' +CONST ENDS + +_TLS SEGMENT DWORD PUBLIC _FLAT 'LCODE' +_TLS ENDS + + +_STEXT SEGMENT DWORD PUBLIC _FLAT 'SCODE' +_STEXT ENDS + + +_SDATA SEGMENT DWORD PUBLIC _FLAT 'SCODE' +_SDATA ENDS + + +_DBOSTART SEGMENT DWORD PUBLIC _FLAT 'DBOCODE' +_DBOSTART ENDS + + +_DBOCODE SEGMENT DWORD PUBLIC _FLAT 'DBOCODE' +_DBOCODE ENDS + + +_DBODATA SEGMENT DWORD PUBLIC _FLAT 'DBOCODE' +_DBODATA ENDS + +if DEBLEVEL + +_PATHSTART SEGMENT DWORD PUBLIC _FLAT 'LCODE' +_PATHSTART ENDS + + +_PATHDATA SEGMENT DWORD PUBLIC _FLAT 'LCODE' +_PATHDATA ENDS + + +_PATHEND SEGMENT DWORD PUBLIC _FLAT 'LCODE' +_PATHEND ENDS +endif + + +_16ICODE SEGMENT WORD USE16 PUBLIC '16ICODE' +_16ICODE ENDS + + +_RCODE SEGMENT WORD USE16 PUBLIC 'RCODE' +_RCODE ENDS + +IFNDEF BLD_COFF +_LGROUP GROUP _LTEXT, _TEXT, _LDATA, _DATA, _BSS, CONST, _TLS +_IGROUP GROUP _ITEXT, _IDATA +_SGROUP GROUP _STEXT, _SDATA +_DBOGROUP GROUP _DBOSTART, _DBOCODE, _DBODATA +IF DEBLEVEL +_PGROUP GROUP _PATHSTART, _PATHDATA, _PATHEND +ENDIF +ENDIF + +endif + + ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT + +OFFSET32 EQU + + +BeginDoc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EndDoc + +Begin_Service_Table MACRO Device_Name, Def_Segment + +IFDEF Device_Name&_Name_Based + IFNDEF @@NextInternalID + @@NextInternalID = 0 + ENDIF + @@NextInternalID = (@@NextInternalID + 1) + Device_Name&_Internal_ID = @@NextInternalID + BASEID_FOR_NAMEBASEDVXD + DefineVxDName Device_Name, %Device_Name&_Internal_ID +ENDIF + +IFB + BST2 Device_Name, VxD +ELSE + BST2 Device_Name, Def_Segment +ENDIF + ENDM + +DefineVxDName MACRO Device_Name, InternalID + @@VxDName&InternalID EQU <___&Device_Name&STable> +ENDM + + +BST2 MACRO Device_Name, Def_Segment + +Num_&Device_Name&_Services = 0 + +IFDEF Create_&Device_Name&_Service_Table + +Def_Segment&_LOCKED_DATA_SEG + +Device_Name&_Service_Table LABEL DWORD + +Device_Name&_Service MACRO Procedure, Local_Seg, Condition +LOCAL $$&Procedure + + IFNB + $$&&Procedure MACRO extern + IFDEF &Condition + IFNB + EXTRN Procedure:NEAR + ELSE + dd OFFSET32 Procedure + ENDIF + ELSE + IFB + dd 0 + ENDIF + ENDIF + ENDM + ENDIF + + IFDIFI , + PUBLIC _&&Procedure + IF1 + _&&Procedure LABEL DWORD + ENDIF + IFDIFI , + IFNB +Local_Seg&&_SEG + ELSE +Def_Segment&_CODE_SEG + ENDIF + IFNB + $$&&Procedure extern + ELSE + EXTRN Procedure:NEAR + ENDIF + IFNB +Local_Seg&&_ENDS + ELSE +Def_Segment&_CODE_ENDS + ENDIF + ENDIF + IFNB + $$&&Procedure + ELSE + dd OFFSET32 Procedure + ENDIF + + IFDEF Device_Name&_Name_Based + @@&&Procedure = (Device_Name&_Internal_ID SHL 16) + Num_&Device_Name&_Services + ELSE + @@&&Procedure = (Device_Name&_Device_ID SHL 16) + Num_&Device_Name&_Services + ENDIF + ELSE + dd 0 + ENDIF + Num_&Device_Name&_Services = Num_&Device_Name&_Services + 1 + IFNB + Purge $$&&Procedure + ENDIF + ENDM + +ELSE + + + +IFDEF Device_Name&_Name_Based + +Device_Name&_Service MACRO Procedure, Local_Seg, Condition + + + IFDIFI , + @@&&Procedure = (Device_Name&_Internal_ID SHL 16) + Num_&Device_Name&_Services + ENDIF + Num_&Device_Name&_Services = Num_&Device_Name&_Services + 1 + + ENDM +ELSE + +Device_Name&_Service MACRO Procedure, Local_Seg, Condition + + IFDIFI , + @@&&Procedure = (Device_Name&_Device_ID SHL 16) + Num_&Device_Name&_Services + ENDIF + Num_&Device_Name&_Services = Num_&Device_Name&_Services + 1 + + ENDM +ENDIF + +ENDIF + + ENDM + + + +End_Service_Table MACRO Device_Name, Def_Segment + + PURGE Device_Name&_Service + +IFDEF Create_&Device_Name&_Service_Table + +IFB +VxD_LOCKED_DATA_ENDS +ELSE +Def_Segment&_LOCKED_DATA_ENDS +ENDIF + +ENDIF + + ENDM + +GetVxDServiceOrdinal macro reg,service + mov reg,@@&service + endm + +GetVxDServiceAddress macro reg,service + mov reg,OFFSET32 service + endm + + + + + + + + + + + + + + + + + + +Begin_Win32_Services MACRO VxDName +ifndef Create_Win32_Services + Create_Win32_Services = 0 +endif + .errb , + ??w32svcno = 0 +if Create_Win32_Services +VxDName&_Win32_Services label dword + dd csvc&VxDName, 0 +endif + ??inw32svc = 1 + + VxDName&_Win32_Service MACRO Name + .erre ??inw32svc, + if Create_Win32_Services + dd OFFSET32 Name,cparm&&Name + endif + @32&&Name equ ((VxDName&_Device_ID SHL 16) + ??w32svcno) + ??w32svcno = ??w32svcno + 1 + ENDM + ENDM + + + + + + + + + + +End_Win32_Services MACRO VxDName + .errb , +if Create_Win32_Services + csvc&VxDName equ ($ - VxDName&_Win32_Services)/8 - 1 +endif + ??inw32svc = 0 + PURGE VxDName&_Win32_Service + ENDM + + + + + + + + + + + +Declare_Win32_Service MACRO Name, cParms +ifndef Create_Win32_Services + Create_Win32_Services = 0 +endif +if Create_Win32_Services + ?merge ,,,,,<_>,,<@>,%(cParms*4 + 8) + ?merge ,,,,, +VxD_CODE_SEG + ?merge ,,,,,<_>,,<@>,%(cParms*4 + 8),<:NEAR> +VxD_CODE_ENDS +endif + ENDM + + + + + + + + + + + + +Win32call MACRO Service, CallBack +ifndef Create_Win32_Services + Create_Win32_Services = 0 +endif +ife Create_Win32_Services + mov eax,@32&Service +ifdef IS_16 + movzx esp,sp +endif + call fword ptr [CallBack] +ifdef DEBUG + int 3 +endif +endif + ENDM + + + + + + + +Dword_Align MACRO Seg_Name + LOCAL segn +IFDEF MASM6 + align 4 +ELSE +IFNB + segn equ Seg_Name +ELSE +IFE ?_LCODE + segn equ <_LTEXT> +ELSE +IFE ?_ICODE + segn equ <_ITEXT> +ELSE +IFE ?_PCODE + segn equ <_PTEXT> +ELSE +IFE ?_SCODE + segn equ <_STEXT> +ELSE +.err +ENDIF +ENDIF +ENDIF +ENDIF +ENDIF +IF (($-OFFSET segn:0) MOD 4) +db 4 - (($-OFFSET segn:0) MOD 4) DUP (90h) +ENDIF +ENDIF + ENDM + + +BeginDoc + + + + + + + + + + + + + + + + + +EndDoc + +Fatal_Error MACRO Msg_Ptr, Exit_Flags + pushad +IFB + xor esi, esi +ELSE + mov esi, Msg_Ptr +IFB + xor eax, eax +ELSE + mov eax, Exit_Flags +ENDIF +ENDIF + VMMCall Fatal_Error_Handler + ENDM + +EF_Hang_On_Exit EQU 1h + + +cb_s STRUC +CB_VM_Status DD ? +CB_High_Linear DD ? +CB_Client_Pointer DD ? +CB_VMID DD ? +CB_Signature DD ? +cb_s ENDS +VMCB_ID EQU 62634D56H +VMSTAT_EXCLUSIVE_BIT EQU 00H +VMSTAT_EXCLUSIVE EQU (1 SHL VMSTAT_EXCLUSIVE_BIT) +VMSTAT_BACKGROUND_BIT EQU 01H +VMSTAT_BACKGROUND EQU (1 SHL VMSTAT_BACKGROUND_BIT) +VMSTAT_CREATING_BIT EQU 02H +VMSTAT_CREATING EQU (1 SHL VMSTAT_CREATING_BIT) +VMSTAT_SUSPENDED_BIT EQU 03H +VMSTAT_SUSPENDED EQU (1 SHL VMSTAT_SUSPENDED_BIT) +VMSTAT_NOT_EXECUTEABLE_BIT EQU 04H +VMSTAT_NOT_EXECUTEABLE EQU (1 SHL VMSTAT_NOT_EXECUTEABLE_BIT) +VMSTAT_PM_EXEC_BIT EQU 05H +VMSTAT_PM_EXEC EQU (1 SHL VMSTAT_PM_EXEC_BIT) +VMSTAT_PM_APP_BIT EQU 06H +VMSTAT_PM_APP EQU (1 SHL VMSTAT_PM_APP_BIT) +VMSTAT_PM_USE32_BIT EQU 07H +VMSTAT_PM_USE32 EQU (1 SHL VMSTAT_PM_USE32_BIT) +VMSTAT_VXD_EXEC_BIT EQU 08H +VMSTAT_VXD_EXEC EQU (1 SHL VMSTAT_VXD_EXEC_BIT) +VMSTAT_HIGH_PRI_BACK_BIT EQU 09H +VMSTAT_HIGH_PRI_BACK EQU (1 SHL VMSTAT_HIGH_PRI_BACK_BIT) +VMSTAT_BLOCKED_BIT EQU 0AH +VMSTAT_BLOCKED EQU (1 SHL VMSTAT_BLOCKED_BIT) +VMSTAT_AWAKENING_BIT EQU 0BH +VMSTAT_AWAKENING EQU (1 SHL VMSTAT_AWAKENING_BIT) +VMSTAT_PAGEABLEV86BIT EQU 0CH +VMSTAT_PAGEABLEV86_BIT EQU VMSTAT_PAGEABLEV86BIT +VMSTAT_PAGEABLEV86 EQU (1 SHL VMSTAT_PAGEABLEV86BIT) +VMSTAT_V86INTSLOCKEDBIT EQU 0DH +VMSTAT_V86INTSLOCKED_BIT EQU VMSTAT_V86INTSLOCKEDBIT +VMSTAT_V86INTSLOCKED EQU (1 SHL VMSTAT_V86INTSLOCKEDBIT) +VMSTAT_IDLE_TIMEOUT_BIT EQU 0EH +VMSTAT_IDLE_TIMEOUT EQU (1 SHL VMSTAT_IDLE_TIMEOUT_BIT) +VMSTAT_IDLE_BIT EQU 0FH +VMSTAT_IDLE EQU (1 SHL VMSTAT_IDLE_BIT) +VMSTAT_CLOSING_BIT EQU 10H +VMSTAT_CLOSING EQU (1 SHL VMSTAT_CLOSING_BIT) +VMSTAT_TS_SUSPENDED_BIT EQU 11H +VMSTAT_TS_SUSPENDED EQU (1 SHL VMSTAT_TS_SUSPENDED_BIT) +VMSTAT_TS_MAXPRI_BIT EQU 12H +VMSTAT_TS_MAXPRI EQU (1 SHL VMSTAT_TS_MAXPRI_BIT) +VMSTAT_USE32_MASK EQU (VMSTAT_PM_USE32 OR VMSTAT_VXD_EXEC) + +tcb_s STRUC +TCB_Flags DD ? +TCB_Reserved1 DD ? +TCB_Reserved2 DD ? +TCB_Signature DD ? +TCB_ClientPtr DD ? +TCB_VMHandle DD ? +TCB_ThreadId DW ? +TCB_PMLockOrigSS DW ? +TCB_PMLockOrigESP DD ? +TCB_PMLockOrigEIP DD ? +TCB_PMLockStackCount DD ? +TCB_PMLockOrigCS DW ? +TCB_PMPSPSelector DW ? +TCB_ThreadType DD ? +TCB_pad1 DW ? +TCB_pad2 DB ? +TCB_extErrLocus DB ? +TCB_extErr DW ? +TCB_extErrAction DB ? +TCB_extErrClass DB ? +TCB_extErrPtr DD ? +tcb_s ENDS +SCHED_OBJ_ID_THREAD EQU 42434854H +THFLAG_SUSPENDED_BIT EQU 03H +THFLAG_SUSPENDED EQU (1 SHL THFLAG_SUSPENDED_BIT) +THFLAG_NOT_EXECUTEABLE_BIT EQU 04H +THFLAG_NOT_EXECUTEABLE EQU (1 SHL THFLAG_NOT_EXECUTEABLE_BIT) +THFLAG_THREAD_CREATION_BIT EQU 08H +THFLAG_THREAD_CREATION EQU (1 SHL THFLAG_THREAD_CREATION_BIT) +THFLAG_THREAD_BLOCKED_BIT EQU 0AH +THFLAG_THREAD_BLOCKED EQU (1 SHL THFLAG_THREAD_BLOCKED_BIT) +THFLAG_RING0_THREAD_BIT EQU 1CH +THFLAG_RING0_THREAD EQU (1 SHL THFLAG_RING0_THREAD_BIT) +THFLAG_CHARSET_BITS EQU 10H +THFLAG_CHARSET_MASK EQU (3 SHL THFLAG_CHARSET_BITS) +THFLAG_ANSI EQU (0 SHL THFLAG_CHARSET_BITS) +THFLAG_OEM EQU (1 SHL THFLAG_CHARSET_BITS) +THFLAG_UNICODE EQU (2 SHL THFLAG_CHARSET_BITS) +THFLAG_RESERVED EQU (3 SHL THFLAG_CHARSET_BITS) +THFLAG_EXTENDED_HANDLES_BIT EQU 12H +THFLAG_EXTENDED_HANDLES EQU (1 SHL THFLAG_EXTENDED_HANDLES_BIT) +THFLAG_OPEN_AS_IMMOVABLE_FILE_BIT EQU 13H +THFLAG_OPEN_AS_IMMOVABLE_FILE EQU (1 SHL THFLAG_OPEN_AS_IMMOVABLE_FILE_BIT) + +pmcb_s STRUC +PMCB_Flags DD ? +PMCB_Parent DD ? +pmcb_s ENDS + +VMFaultInfo STRUC +VMFI_EIP DD ? +VMFI_CS DW ? +VMFI_Ints DW ? +VMFaultInfo ENDS +Begin_Service_Table VMM, VMM +VMM_Service Get_VMM_Version, LOCAL +VMM_Service Get_Cur_VM_Handle +VMM_Service Test_Cur_VM_Handle +VMM_Service Get_Sys_VM_Handle +VMM_Service Test_Sys_VM_Handle +VMM_Service Validate_VM_Handle +VMM_Service Get_VMM_Reenter_Count +VMM_Service Begin_Reentrant_Execution +VMM_Service End_Reentrant_Execution +VMM_Service Install_V86_Break_Point +VMM_Service Remove_V86_Break_Point +VMM_Service Allocate_V86_Call_Back +VMM_Service Allocate_PM_Call_Back +VMM_Service Call_When_VM_Returns +VMM_Service Schedule_Global_Event +VMM_Service Schedule_VM_Event +VMM_Service Call_Global_Event +VMM_Service Call_VM_Event +VMM_Service Cancel_Global_Event +VMM_Service Cancel_VM_Event +VMM_Service Call_Priority_VM_Event +VMM_Service Cancel_Priority_VM_Event +VMM_Service Get_NMI_Handler_Addr +VMM_Service Set_NMI_Handler_Addr +VMM_Service Hook_NMI_Event +VMM_Service Call_When_VM_Ints_Enabled +VMM_Service Enable_VM_Ints +VMM_Service Disable_VM_Ints +VMM_Service Map_Flat +VMM_Service Map_Lin_To_VM_Addr +VMM_Service Adjust_Exec_Priority +VMM_Service Begin_Critical_Section +VMM_Service End_Critical_Section +VMM_Service End_Crit_And_Suspend +VMM_Service Claim_Critical_Section +VMM_Service Release_Critical_Section +VMM_Service Call_When_Not_Critical +VMM_Service Create_Semaphore +VMM_Service Destroy_Semaphore +VMM_Service Wait_Semaphore +VMM_Service Signal_Semaphore +VMM_Service Get_Crit_Section_Status +VMM_Service Call_When_Task_Switched +VMM_Service Suspend_VM +VMM_Service Resume_VM +VMM_Service No_Fail_Resume_VM +VMM_Service Nuke_VM +VMM_Service Crash_Cur_VM +VMM_Service Get_Execution_Focus +VMM_Service Set_Execution_Focus +VMM_Service Get_Time_Slice_Priority +VMM_Service Set_Time_Slice_Priority +VMM_Service Get_Time_Slice_Granularity +VMM_Service Set_Time_Slice_Granularity +VMM_Service Get_Time_Slice_Info +VMM_Service Adjust_Execution_Time +VMM_Service Release_Time_Slice +VMM_Service Wake_Up_VM +VMM_Service Call_When_Idle +VMM_Service Get_Next_VM_Handle +VMM_Service Set_Global_Time_Out +VMM_Service Set_VM_Time_Out +VMM_Service Cancel_Time_Out +VMM_Service Get_System_Time +VMM_Service Get_VM_Exec_Time +VMM_Service Hook_V86_Int_Chain +VMM_Service Get_V86_Int_Vector +VMM_Service Set_V86_Int_Vector +VMM_Service Get_PM_Int_Vector +VMM_Service Set_PM_Int_Vector +VMM_Service Simulate_Int +VMM_Service Simulate_Iret +VMM_Service Simulate_Far_Call +VMM_Service Simulate_Far_Jmp +VMM_Service Simulate_Far_Ret +VMM_Service Simulate_Far_Ret_N +VMM_Service Build_Int_Stack_Frame +VMM_Service Simulate_Push +VMM_Service Simulate_Pop +VMM_Service _HeapAllocate +VMM_Service _HeapReAllocate +VMM_Service _HeapFree +VMM_Service _HeapGetSize +HEAPZEROINIT EQU 00000001H +HEAPZEROREINIT EQU 00000002H +HEAPNOCOPY EQU 00000004H +HEAPLOCKEDIFDP EQU 00000100H +HEAPSWAP EQU 00000200H +HEAPINIT EQU 00000400H +HEAPCLEAN EQU 00000800H +VMM_Service _PageAllocate +VMM_Service _PageReAllocate +VMM_Service _PageFree +VMM_Service _PageLock +VMM_Service _PageUnLock +VMM_Service _PageGetSizeAddr +VMM_Service _PageGetAllocInfo +VMM_Service _GetFreePageCount +VMM_Service _GetSysPageCount +VMM_Service _GetVMPgCount +VMM_Service _MapIntoV86 +VMM_Service _PhysIntoV86 +VMM_Service _TestGlobalV86Mem +VMM_Service _ModifyPageBits +VMM_Service _CopyPageTable +VMM_Service _LinMapIntoV86 +VMM_Service _LinPageLock +VMM_Service _LinPageUnLock +VMM_Service _SetResetV86Pageable +VMM_Service _GetV86PageableArray +VMM_Service _PageCheckLinRange +VMM_Service _PageOutDirtyPages +VMM_Service _PageDiscardPages +PAGEZEROINIT EQU 00000001H +PAGEUSEALIGN EQU 00000002H +PAGECONTIG EQU 00000004H +PAGEFIXED EQU 00000008H +PAGEDEBUGNULFAULT EQU 00000010H +PAGEZEROREINIT EQU 00000020H +PAGENOCOPY EQU 00000040H +PAGELOCKED EQU 00000080H +PAGELOCKEDIFDP EQU 00000100H +PAGESETV86PAGEABLE EQU 00000200H +PAGECLEARV86PAGEABLE EQU 00000400H +PAGESETV86INTSLOCKED EQU 00000800H +PAGECLEARV86INTSLOCKED EQU 00001000H +PAGEMARKPAGEOUT EQU 00002000H +PAGEPDPSETBASE EQU 00004000H +PAGEPDPCLEARBASE EQU 00008000H +PAGEDISCARD EQU 00010000H +PAGEPDPQUERYDIRTY EQU 00020000H +PAGEMAPFREEPHYSREG EQU 00040000H +PAGENOMOVE EQU 10000000H +PAGEMAPGLOBAL EQU 40000000H +PAGEMARKDIRTY EQU 80000000H +MAPV86_IGNOREWRAP EQU 00000001H +VMM_Service _GetNulPageHandle +VMM_Service _GetFirstV86Page +VMM_Service _MapPhysToLinear +VMM_Service _GetAppFlatDSAlias +VMM_Service _SelectorMapFlat +VMM_Service _GetDemandPageInfo +VMM_Service _GetSetPageOutCount +GSPOC_F_GET EQU 00000001H +VMM_Service Hook_V86_Page +VMM_Service _Assign_Device_V86_Pages +VMM_Service _DeAssign_Device_V86_Pages +VMM_Service _Get_Device_V86_Pages_Array +VMM_Service MMGR_SetNULPageAddr +VMM_Service _Allocate_GDT_Selector +VMM_Service _Free_GDT_Selector +VMM_Service _Allocate_LDT_Selector +VMM_Service _Free_LDT_Selector +VMM_Service _BuildDescriptorDWORDs +VMM_Service _GetDescriptor +VMM_Service _SetDescriptor +BDDEXPLICITDPL EQU 00000001H +ALDTSPECSEL EQU 00000001H +VMM_Service _MMGR_Toggle_HMA +MMGRHMAPHYSICAL EQU 00000001H +MMGRHMAENABLE EQU 00000002H +MMGRHMADISABLE EQU 00000004H +MMGRHMAQUERY EQU 00000008H +VMM_Service Get_Fault_Hook_Addrs +VMM_Service Hook_V86_Fault +VMM_Service Hook_PM_Fault +VMM_Service Hook_VMM_Fault +VMM_Service Begin_Nest_V86_Exec +VMM_Service Begin_Nest_Exec +VMM_Service Exec_Int +VMM_Service Resume_Exec +VMM_Service End_Nest_Exec +VMM_Service Allocate_PM_App_CB_Area, VMM_ICODE +VMM_Service Get_Cur_PM_App_CB +VMM_Service Set_V86_Exec_Mode +VMM_Service Set_PM_Exec_Mode +VMM_Service Begin_Use_Locked_PM_Stack +VMM_Service End_Use_Locked_PM_Stack +VMM_Service Save_Client_State +VMM_Service Restore_Client_State +VMM_Service Exec_VxD_Int +VMM_Service Hook_Device_Service +VMM_Service Hook_Device_V86_API +VMM_Service Hook_Device_PM_API +VMM_Service System_Control +VMM_Service Simulate_IO +VMM_Service Install_Mult_IO_Handlers +VMM_Service Install_IO_Handler +VMM_Service Enable_Global_Trapping +VMM_Service Enable_Local_Trapping +VMM_Service Disable_Global_Trapping +VMM_Service Disable_Local_Trapping +VMM_Service List_Create +VMM_Service List_Destroy +VMM_Service List_Allocate +VMM_Service List_Attach +VMM_Service List_Attach_Tail +VMM_Service List_Insert +VMM_Service List_Remove +VMM_Service List_Deallocate +VMM_Service List_Get_First +VMM_Service List_Get_Next +VMM_Service List_Remove_First +LF_ASYNC_BIT EQU 0 +LF_ASYNC EQU (1 SHL LF_ASYNC_BIT) +LF_USE_HEAP_BIT EQU 1 +LF_USE_HEAP EQU (1 SHL LF_USE_HEAP_BIT) +LF_ALLOC_ERROR_BIT EQU 2 +LF_ALLOC_ERROR EQU (1 SHL LF_ALLOC_ERROR_BIT) +LF_SWAP EQU (LF_USE_HEAP+(1 SHL 3)) +VMM_Service _AddInstanceItem +VMM_Service _Allocate_Device_CB_Area +VMM_Service _Allocate_Global_V86_Data_Area, VMM_ICODE +VMM_Service _Allocate_Temp_V86_Data_Area, VMM_ICODE +VMM_Service _Free_Temp_V86_Data_Area, VMM_ICODE +GVDAWordAlign EQU 00000001H +GVDADWordAlign EQU 00000002H +GVDAParaAlign EQU 00000004H +GVDAPageAlign EQU 00000008H +GVDAInstance EQU 00000100H +GVDAZeroInit EQU 00000200H +GVDAReclaim EQU 00000400H +GVDAInquire EQU 00000800H +GVDAHighSysCritOK EQU 00001000H +GVDAOptInstance EQU 00002000H +GVDAForceLow EQU 00004000H +TVDANeedTilInitComplete EQU 00000001H +VMM_Service Get_Profile_Decimal_Int, VMM_ICODE +VMM_Service Convert_Decimal_String, VMM_ICODE +VMM_Service Get_Profile_Fixed_Point, VMM_ICODE +VMM_Service Convert_Fixed_Point_String, VMM_ICODE +VMM_Service Get_Profile_Hex_Int, VMM_ICODE +VMM_Service Convert_Hex_String, VMM_ICODE +VMM_Service Get_Profile_Boolean, VMM_ICODE +VMM_Service Convert_Boolean_String, VMM_ICODE +VMM_Service Get_Profile_String, VMM_ICODE +VMM_Service Get_Next_Profile_String, VMM_ICODE +VMM_Service Get_Environment_String, VMM_ICODE +VMM_Service Get_Exec_Path, VMM_ICODE +VMM_Service Get_Config_Directory, VMM_ICODE +VMM_Service OpenFile, VMM_ICODE +VMM_OPENFILE_BUF_SIZE EQU 260 +VMM_Service Get_PSP_Segment, VMM_ICODE +VMM_Service GetDOSVectors, VMM_ICODE +VMM_Service Get_Machine_Info +GMIF_80486_BIT EQU 10H +GMIF_80486 EQU (1 SHL GMIF_80486_BIT) +GMIF_PCXT_BIT EQU 11H +GMIF_PCXT EQU (1 SHL GMIF_PCXT_BIT) +GMIF_MCA_BIT EQU 12H +GMIF_MCA EQU (1 SHL GMIF_MCA_BIT) +GMIF_EISA_BIT EQU 13H +GMIF_EISA EQU (1 SHL GMIF_EISA_BIT) +GMIF_CPUID_BIT EQU 14H +GMIF_CPUID EQU (1 SHL GMIF_CPUID_BIT) +VMM_Service GetSet_HMA_Info +VMM_Service Set_System_Exit_Code +VMM_Service Fatal_Error_Handler +VMM_Service Fatal_Memory_Error +VMM_Service Update_System_Clock +VMM_Service Test_Debug_Installed +VMM_Service Out_Debug_String +VMM_Service Out_Debug_Chr +VMM_Service In_Debug_Chr +VMM_Service Debug_Convert_Hex_Binary +VMM_Service Debug_Convert_Hex_Decimal +VMM_Service Debug_Test_Valid_Handle +VMM_Service Validate_Client_Ptr +VMM_Service Test_Reenter +VMM_Service Queue_Debug_String +VMM_Service Log_Proc_Call +VMM_Service Debug_Test_Cur_VM +VMM_Service Get_PM_Int_Type +VMM_Service Set_PM_Int_Type +VMM_Service Get_Last_Updated_System_Time +VMM_Service Get_Last_Updated_VM_Exec_Time +VMM_Service Test_DBCS_Lead_Byte +.errnz @@Test_DBCS_Lead_Byte - 100D1h + +VMM_Service _AddFreePhysPage, VMM_ICODE +VMM_Service _PageResetHandlePAddr +VMM_Service _SetLastV86Page, VMM_ICODE +VMM_Service _GetLastV86Page +VMM_Service _MapFreePhysReg +VMM_Service _UnmapFreePhysReg +VMM_Service _XchgFreePhysReg +VMM_Service _SetFreePhysRegCalBk, VMM_ICODE +VMM_Service Get_Next_Arena, VMM_ICODE +VMM_Service Get_Name_Of_Ugly_TSR, VMM_ICODE +VMM_Service Get_Debug_Options, VMM_ICODE +AFPP_SWAPOUT EQU 0001H +PCP_CHANGEPAGER EQU 1H +PCP_CHANGEPAGERDATA EQU 2H +PCP_VIRGINONLY EQU 4H +GNA_HIDOSLINKED EQU 0002H +GNA_ISHIGHDOS EQU 0004H +VMM_Service Set_Physical_HMA_Alias, VMM_ICODE +VMM_Service _GetGlblRng0V86IntBase, VMM_ICODE +VMM_Service _Add_Global_V86_Data_Area, VMM_ICODE +VMM_Service GetSetDetailedVMError +GSDVME_PRIVINST EQU 00010001H +GSDVME_INVALINST EQU 00010002H +GSDVME_INVALPGFLT EQU 00010003H +GSDVME_INVALGPFLT EQU 00010004H +GSDVME_INVALFLT EQU 00010005H +GSDVME_USERNUKE EQU 00010006H +GSDVME_DEVNUKE EQU 00010007H +GSDVME_DEVNUKEHDWR EQU 00010008H +GSDVME_NUKENOMSG EQU 00010009H +GSDVME_OKNUKEMASK EQU 80000000H +GSDVME_INSMEMV86 EQU 00020001H +GSDVME_INSV86SPACE EQU 00020002H +GSDVME_INSMEMXMS EQU 00020003H +GSDVME_INSMEMEMS EQU 00020004H +GSDVME_INSMEMV86HI EQU 00020005H +GSDVME_INSMEMVID EQU 00020006H +GSDVME_INSMEMVM EQU 00020007H +GSDVME_INSMEMDEV EQU 00020008H +GSDVME_CRTNOMSG EQU 00020009H +VMM_Service Is_Debug_Chr +VMM_Service Clear_Mono_Screen +VMM_Service Out_Mono_Chr +VMM_Service Out_Mono_String +VMM_Service Set_Mono_Cur_Pos +VMM_Service Get_Mono_Cur_Pos +VMM_Service Get_Mono_Chr +VMM_Service Locate_Byte_In_ROM, VMM_ICODE +VMM_Service Hook_Invalid_Page_Fault +VMM_Service Unhook_Invalid_Page_Fault +IPF_PGDIR EQU 00000001H +IPF_V86PG EQU 00000002H +IPF_V86PGH EQU 00000004H +IPF_INVTYP EQU 00000008H +IPF_PGERR EQU 00000010H +IPF_REFLT EQU 00000020H +IPF_VMM EQU 00000040H +IPF_PM EQU 00000080H +IPF_V86 EQU 00000100H +VMM_Service Set_Delete_On_Exit_File +VMM_Service Close_VM +CVF_CONTINUE_EXEC_BIT EQU 0 +CVF_CONTINUE_EXEC EQU (1 SHL CVF_CONTINUE_EXEC_BIT) +VMM_Service Enable_Touch_1st_Meg +VMM_Service Disable_Touch_1st_Meg +VMM_Service Install_Exception_Handler +VMM_Service Remove_Exception_Handler +VMM_Service Get_Crit_Status_No_Block + +.errnz @@Get_Crit_Status_No_Block - 100F1h + +ifdef WIN40SERVICES +VMM_Service _GetLastUpdatedThreadExecTime +VMM_Service _Trace_Out_Service +VMM_Service _Debug_Out_Service +VMM_Service _Debug_Flags_Service +endif +DFS_LOG_BIT EQU 0 +DFS_LOG EQU (1 SHL DFS_LOG_BIT) +DFS_PROFILE_BIT EQU 1 +DFS_PROFILE EQU (1 SHL DFS_PROFILE_BIT) +DFS_TEST_CLD_BIT EQU 2 +DFS_TEST_CLD EQU (1 SHL DFS_TEST_CLD_BIT) +DFS_NEVER_REENTER_BIT EQU 3 +DFS_NEVER_REENTER EQU (1 SHL DFS_NEVER_REENTER_BIT) +DFS_TEST_REENTER_BIT EQU 4 +DFS_TEST_REENTER EQU (1 SHL DFS_TEST_REENTER_BIT) +DFS_NOT_SWAPPING_BIT EQU 5 +DFS_NOT_SWAPPING EQU (1 SHL DFS_NOT_SWAPPING_BIT) +DFS_TEST_BLOCK_BIT EQU 6 +DFS_TEST_BLOCK EQU (1 SHL DFS_TEST_BLOCK_BIT) +DFS_RARE_SERVICES EQU 0FFFFFF80H +DFS_EXIT_NOBLOCK EQU (DFS_RARE_SERVICES+0) +DFS_ENTER_NOBLOCK EQU (DFS_RARE_SERVICES+DFS_TEST_BLOCK) +DFS_TEST_NEST_EXEC EQU (DFS_RARE_SERVICES+1) +ifdef WIN40SERVICES +VMM_Service VMMAddImportModuleName +VMM_Service VMM_Add_DDB +VMM_Service VMM_Remove_DDB +VMM_Service Test_VM_Ints_Enabled +VMM_Service _BlockOnID +VMM_Service Schedule_Thread_Event +VMM_Service Cancel_Thread_Event +VMM_Service Set_Thread_Time_Out +VMM_Service Set_Async_Time_Out +VMM_Service _AllocateThreadDataSlot +VMM_Service _FreeThreadDataSlot +MUTEX_MUST_COMPLETE EQU 1 +MUTEX_NO_CLEANUP_THREAD_STATE EQU 2 +VMM_Service _CreateMutex +VMM_Service _DestroyMutex +VMM_Service _GetMutexOwner +VMM_Service Call_When_Thread_Switched +VMM_Service VMMCreateThread +VMM_Service _GetThreadExecTime +VMM_Service VMMTerminateThread +VMM_Service Get_Cur_Thread_Handle +VMM_Service Test_Cur_Thread_Handle +VMM_Service Get_Sys_Thread_Handle +VMM_Service Test_Sys_Thread_Handle +VMM_Service Validate_Thread_Handle +VMM_Service Get_Initial_Thread_Handle +VMM_Service Test_Initial_Thread_Handle +VMM_Service Debug_Test_Valid_Thread_Handle +VMM_Service Debug_Test_Cur_Thread +VMM_Service VMM_GetSystemInitState +VMM_Service Cancel_Call_When_Thread_Switched +VMM_Service Get_Next_Thread_Handle +VMM_Service Adjust_Thread_Exec_Priority +VMM_Service _Deallocate_Device_CB_Area +VMM_Service Remove_IO_Handler +VMM_Service Remove_Mult_IO_Handlers +VMM_Service Unhook_V86_Int_Chain +VMM_Service Unhook_V86_Fault +VMM_Service Unhook_PM_Fault +VMM_Service Unhook_VMM_Fault +VMM_Service Unhook_Device_Service +VMM_Service _PageReserve +VMM_Service _PageCommit +VMM_Service _PageDecommit +VMM_Service _PagerRegister +VMM_Service _PagerQuery +VMM_Service _PagerDeregister +VMM_Service _ContextCreate +VMM_Service _ContextDestroy +VMM_Service _PageAttach +VMM_Service _PageFlush +VMM_Service _SignalID +VMM_Service _PageCommitPhys +VMM_Service _Register_Win32_Services +VMM_Service Cancel_Call_When_Not_Critical +VMM_Service Cancel_Call_When_Idle +VMM_Service Cancel_Call_When_Task_Switched +VMM_Service _Debug_Printf_Service +VMM_Service _EnterMutex +VMM_Service _LeaveMutex +VMM_Service Simulate_VM_IO +VMM_Service Signal_Semaphore_No_Switch +VMM_Service _ContextSwitch +VMM_Service _PageModifyPermissions +VMM_Service _PageQuery +VMM_Service _EnterMustComplete +VMM_Service _LeaveMustComplete +VMM_Service _ResumeExecMustComplete +THREAD_TERM_STATUS_CRASH_PEND EQU 1 +THREAD_TERM_STATUS_NUKE_PEND EQU 2 +THREAD_TERM_STATUS_SUSPEND_PEND EQU 4 +VMM_Service _GetThreadTerminationStatus +VMM_Service _GetInstanceInfo +INSTINFO_NONE EQU 0 +INSTINFO_SOME EQU 1 +INSTINFO_ALL EQU 2 +VMM_Service _ExecIntMustComplete +VMM_Service _ExecVxDIntMustComplete +VMM_Service Begin_V86_Serialization +VMM_Service Unhook_V86_Page +VMM_Service VMM_GetVxDLocationList +VMM_Service VMM_GetDDBList +VMM_Service Unhook_NMI_Event +VMM_Service Get_Instanced_V86_Int_Vector +VMM_Service Get_Set_Real_DOS_PSP +GSRDP_Set EQU 0001H +VMM_Service Call_Priority_Thread_Event +VMM_Service Get_System_Time_Address +VMM_Service Get_Crit_Status_Thread +VMM_Service Get_DDB +VMM_Service Directed_Sys_Control +VMM_Service _RegOpenKey +VMM_Service _RegCloseKey +VMM_Service _RegCreateKey +VMM_Service _RegDeleteKey +VMM_Service _RegEnumKey +VMM_Service _RegQueryValue +VMM_Service _RegSetValue +VMM_Service _RegDeleteValue +VMM_Service _RegEnumValue +VMM_Service _RegQueryValueEx +VMM_Service _RegSetValueEx +ifndef REG_SZ +REG_SZ EQU 0001H +REG_BINARY EQU 0003H +endif +ifndef HKEY_LOCAL_MACHINE +HKEY_CLASSES_ROOT EQU 80000000H +HKEY_CURRENT_USER EQU 80000001H +HKEY_LOCAL_MACHINE EQU 80000002H +HKEY_USERS EQU 80000003H +HKEY_PERFORMANCE_DATA EQU 80000004H +HKEY_CURRENT_CONFIG EQU 80000005H +HKEY_DYN_DATA EQU 80000006H +endif +VMM_Service _CallRing3 +VMM_Service Exec_PM_Int +VMM_Service _RegFlushKey +VMM_Service _PageCommitContig +VMM_Service _GetCurrentContext +VMM_Service _LocalizeSprintf +VMM_Service _LocalizeStackSprintf +VMM_Service Call_Restricted_Event +VMM_Service Cancel_Restricted_Event +VMM_Service Register_PEF_Provider, VMM_ICODE +VMM_Service _GetPhysPageInfo +VMM_Service _RegQueryInfoKey +VMM_Service MemArb_Reserve_Pages +PHYSINFO_NONE EQU 0 +PHYSINFO_SOME EQU 1 +PHYSINFO_ALL EQU 2 +VMM_Service Time_Slice_Sys_VM_Idle +VMM_Service Time_Slice_Sleep +VMM_Service Boost_With_Decay +VMM_Service Set_Inversion_Pri +VMM_Service Reset_Inversion_Pri +VMM_Service Release_Inversion_Pri +VMM_Service Get_Thread_Win32_Pri +VMM_Service Set_Thread_Win32_Pri +VMM_Service Set_Thread_Static_Boost +VMM_Service Set_VM_Static_Boost +VMM_Service Release_Inversion_Pri_ID +VMM_Service Attach_Thread_To_Group +VMM_Service Detach_Thread_From_Group +VMM_Service Set_Group_Static_Boost +VMM_Service _GetRegistryPath, VMM_ICODE +VMM_Service _GetRegistryKey +REGTYPE_ENUM EQU 0 +REGTYPE_CLASS EQU 1 +REGTYPE_VXD EQU 2 +REGKEY_OPEN EQU 0 +REGKEY_CREATE_IFNOTEXIST EQU 1 +ASSERT_RANGE_NULL_BAD EQU 00000000H +ASSERT_RANGE_NULL_OK EQU 00000001H +ASSERT_RANGE_NO_DEBUG EQU 80000000H +ASSERT_RANGE_BITS EQU 80000001H +VMM_Service Cleanup_Thread_State +VMM_Service _RegRemapPreDefKey +VMM_Service End_V86_Serialization +VMM_Service _Assert_Range +VMM_Service _Sprintf +VMM_Service _PageChangePager +VMM_Service _RegCreateDynKey +VMM_Service _RegQueryMultipleValues +VMM_Service Boost_Thread_With_VM +BOOT_CLEAN EQU 00000001H +BOOT_DOSCLEAN EQU 00000002H +BOOT_NETCLEAN EQU 00000004H +BOOT_INTERACTIVE EQU 00000008H +VMM_Service Get_Boot_Flags +VMM_Service Set_Boot_Flags +VMM_Service _lstrcpyn +VMM_Service _lstrlen +VMM_Service _lmemcpy +VMM_Service _GetVxDName +VMM_Service Force_Mutexes_Free +VMM_Service Restore_Forced_Mutexes +VMM_Service _AddReclaimableItem +VMM_Service _SetReclaimableItem +VMM_Service _EnumReclaimableItem +VMM_Service Time_Slice_Wake_Sys_VM +VMM_Service VMM_Replace_Global_Environment +VMM_Service Begin_Non_Serial_Nest_V86_Exec +VMM_Service Get_Nest_Exec_Status +VMM_Service Open_Boot_Log +VMM_Service Write_Boot_Log +VMM_Service Close_Boot_Log +VMM_Service EnableDisable_Boot_Log +VMM_Service _Call_On_My_Stack +VMM_Service Get_Inst_V86_Int_Vec_Base +VMM_Service _lstrcmpi +VMM_Service _strupr +VMM_Service Log_Fault_Call_Out +VMM_Service _AtEventTime +endif +End_Service_Table VMM, VMM +RS_RECLAIM EQU 00000001H +RS_RESTORE EQU 00000002H +RS_DOSARENA EQU 00000004H + +ReclaimStruc STRUC +RS_Linear DD ? +RS_Bytes DD ? +RS_CallBack DD ? +RS_RefData DD ? +RS_HookTable DD ? +RS_Flags DD ? +ReclaimStruc ENDS + +frmtx STRUC +frmtx_pfrmtxNext DD ? +frmtx_hmutex DD ? +frmtx_cEnterCount DD ? +frmtx_pthcbOwner DD ? +frmtx_htimeout DD ? +frmtx ENDS + +vmmfrinfo STRUC +vmmfrinfo_frmtxDOS DB SIZE frmtx DUP (?) +vmmfrinfo_frmtxV86 DB SIZE frmtx DUP (?) +vmmfrinfo_frmtxOther DB SIZE frmtx DUP (?) +vmmfrinfo ENDS + +DemandInfoStruc STRUC +DILin_Total_Count DD ? +DIPhys_Count DD ? +DIFree_Count DD ? +DIUnlock_Count DD ? +DILinear_Base_Addr DD ? +DILin_Total_Free DD ? +DIPage_Faults DD ? +DIPage_Ins DD ? +DIPage_Outs DD ? +DIPage_Discards DD ? +DIInstance_Faults DD ? +DIPagingFileMax DD ? +DIPagingFileInUse DD ? +DICommit_Count DD ? +DIReserved DD 2 DUP (?) +DemandInfoStruc ENDS + +InstDataStruc STRUC +InstLinkF DD 0 +InstLinkB DD 0 +InstLinAddr DD ? +InstSize DD ? +InstType DD ? +InstDataStruc ENDS +INDOS_FIELD EQU 100H +ALWAYS_FIELD EQU 200H +OPTIONAL_FIELD EQU 400H + +IPF_Data STRUC +IPF_LinAddr DD ? +IPF_MapPageNum DD ? +IPF_PTEEntry DD ? +IPF_FaultingVM DD ? +IPF_Flags DD ? +IPF_Data ENDS + +Exception_Handler_Struc STRUC +EH_Reserved DD ? +EH_Start_EIP DD ? +EH_End_EIP DD ? +EH_Handler DD ? +Exception_Handler_Struc ENDS +PR_PRIVATE EQU 80000400H +PR_SHARED EQU 80060000H +PR_SYSTEM EQU 80080000H +PR_FIXED EQU 00000008H +PR_4MEG EQU 00000001H +PR_STATIC EQU 00000010H +PD_ZEROINIT EQU 00000001H +PD_NOINIT EQU 00000002H +PD_FIXEDZERO EQU 00000003H +PD_FIXED EQU 00000004H +PC_FIXED EQU 00000008H +PC_LOCKED EQU 00000080H +PC_LOCKEDIFDP EQU 00000100H +PC_WRITEABLE EQU 00020000H +PC_USER EQU 00040000H +PC_INCR EQU 40000000H +PC_PRESENT EQU 80000000H +PC_STATIC EQU 20000000H +PC_DIRTY EQU 08000000H +PCC_ZEROINIT EQU 00000001H +PCC_NOLIN EQU 10000000H +ifndef _WINNT_ + +_MEMORY_BASIC_INFORMATION STRUC +mbi_BaseAddress DD ? +mbi_AllocationBase DD ? +mbi_AllocationProtect DD ? +mbi_RegionSize DD ? +mbi_State DD ? +mbi_Protect DD ? +mbi_Type DD ? +_MEMORY_BASIC_INFORMATION ENDS +PAGE_NOACCESS EQU 01H +PAGE_READONLY EQU 02H +PAGE_READWRITE EQU 04H +MEM_COMMIT EQU 1000H +MEM_RESERVE EQU 2000H +MEM_FREE EQU 10000H +MEM_PRIVATE EQU 20000H +endif + +pd_s STRUC +pd_virginin DD ? +pd_taintedin DD ? +pd_cleanout DD ? +pd_dirtyout DD ? +pd_virginfree DD ? +pd_taintedfree DD ? +pd_dirty DD ? +pd_type DD ? +pd_s ENDS +PD_SWAPPER EQU 0 +PD_PAGERONLY EQU 1 +PD_NESTEXEC EQU 2 +endif +PAGESHIFT EQU 12 +PAGESIZE EQU (1 SHL PAGESHIFT) +PAGEMASK EQU (PAGESIZE-1) +MAXSYSTEMLADDR EQU (0ffbfffffH) +MINSYSTEMLADDR EQU (0c0000000H) +MAXSHAREDLADDR EQU (0bfffffffH) +MINSHAREDLADDR EQU (80000000H) +MAXPRIVATELADDR EQU (7fffffffH) +MINPRIVATELADDR EQU (00400000H) +MAXDOSLADDR EQU (003fffffH) +MINDOSLADDR EQU (00000000H) +MAXSYSTEMPAGE EQU (MAXSYSTEMLADDR SHR PAGESHIFT) +MINSYSTEMPAGE EQU (MINSYSTEMLADDR SHR PAGESHIFT) +MAXSHAREDPAGE EQU (MAXSHAREDLADDR SHR PAGESHIFT) +MINSHAREDPAGE EQU (MINSHAREDLADDR SHR PAGESHIFT) +MAXPRIVATEPAGE EQU (MAXPRIVATELADDR SHR PAGESHIFT) +MINPRIVATEPAGE EQU (MINPRIVATELADDR SHR PAGESHIFT) +MAXDOSPAGE EQU (MAXDOSLADDR SHR PAGESHIFT) +MINDOSPAGE EQU (MINDOSLADDR SHR PAGESHIFT) +CBPRIVATE EQU (1+MAXPRIVATELADDR-MINPRIVATELADDR) +CBSHARED EQU (1+MAXSHAREDLADDR-MINSHAREDLADDR) +CBSYSTEM EQU (1+MAXSYSTEMLADDR-MINSYSTEMLADDR) +CBDOS EQU (1+MAXDOSLADDR-MINDOSLADDR) +CPGPRIVATE EQU (1+MAXPRIVATEPAGE-MINPRIVATEPAGE) +CPGSHARED EQU (1+MAXSHAREDPAGE-MINSHAREDPAGE) +CPGSYSTEM EQU (1+MAXSYSTEMPAGE-MINSYSTEMPAGE) +CPGDOS EQU (1+MAXDOSPAGE-MINDOSPAGE) +IFDEF DEBUG +DebFar EQU NEAR PTR +ELSE +DebFar EQU SHORT +ENDIF + +ifndef Not_VxD +SYS_CRITICAL_INIT EQU 0000H +DEVICE_INIT EQU 0001H +INIT_COMPLETE EQU 0002H +SYS_VM_INIT EQU 0003H +SYS_VM_TERMINATE EQU 0004H +SYSTEM_EXIT EQU 0005H +SYS_CRITICAL_EXIT EQU 0006H +CREATE_VM EQU 0007H +VM_CRITICAL_INIT EQU 0008H +VM_INIT EQU 0009H +VM_TERMINATE EQU 000AH +VM_NOT_EXECUTEABLE EQU 000BH +DESTROY_VM EQU 000CH +VNE_CRASHED_BIT EQU 00H +VNE_CRASHED EQU (1 SHL VNE_CRASHED_BIT) +VNE_NUKED_BIT EQU 01H +VNE_NUKED EQU (1 SHL VNE_NUKED_BIT) +VNE_CREATEFAIL_BIT EQU 02H +VNE_CREATEFAIL EQU (1 SHL VNE_CREATEFAIL_BIT) +VNE_CRINITFAIL_BIT EQU 03H +VNE_CRINITFAIL EQU (1 SHL VNE_CRINITFAIL_BIT) +VNE_INITFAIL_BIT EQU 04H +VNE_INITFAIL EQU (1 SHL VNE_INITFAIL_BIT) +VNE_CLOSED_BIT EQU 05H +VNE_CLOSED EQU (1 SHL VNE_CLOSED_BIT) +VM_SUSPEND EQU 000DH +VM_RESUME EQU 000EH +SET_DEVICE_FOCUS EQU 000FH +BEGIN_MESSAGE_MODE EQU 0010H +END_MESSAGE_MODE EQU 0011H +REBOOT_PROCESSOR EQU 0012H +QUERY_DESTROY EQU 0013H +DEBUG_QUERY EQU 0014H +BEGIN_PM_APP EQU 0015H +BPA_32_BIT EQU 01H +BPA_32_BIT_FLAG EQU 1 +END_PM_APP EQU 0016H +DEVICE_REBOOT_NOTIFY EQU 0017H +CRIT_REBOOT_NOTIFY EQU 0018H +CLOSE_VM_NOTIFY EQU 0019H +CVNF_CRIT_CLOSE_BIT EQU 0 +CVNF_CRIT_CLOSE EQU (1 SHL CVNF_CRIT_CLOSE_BIT) +POWER_EVENT EQU 001AH +SYS_DYNAMIC_DEVICE_INIT EQU 001BH +SYS_DYNAMIC_DEVICE_EXIT EQU 001CH +CREATE_THREAD EQU 001DH +THREAD_INIT EQU 001EH +TERMINATE_THREAD EQU 001FH +THREAD_Not_Executeable EQU 0020H +DESTROY_THREAD EQU 0021H +PNP_NEW_DEVNODE EQU 0022H +W32_DEVICEIOCONTROL EQU 0023H +DIOC_GETVERSION EQU 0H +DIOC_OPEN EQU DIOC_GETVERSION +DIOC_CLOSEHANDLE EQU -1 +SYS_VM_TERMINATE2 EQU 0024H +SYSTEM_EXIT2 EQU 0025H +SYS_CRITICAL_EXIT2 EQU 0026H +VM_TERMINATE2 EQU 0027H +VM_NOT_EXECUTEABLE2 EQU 0028H +DESTROY_VM2 EQU 0029H +VM_SUSPEND2 EQU 002AH +END_MESSAGE_MODE2 EQU 002BH +END_PM_APP2 EQU 002CH +DEVICE_REBOOT_NOTIFY2 EQU 002DH +CRIT_REBOOT_NOTIFY2 EQU 002EH +CLOSE_VM_NOTIFY2 EQU 002FH +GET_CONTENTION_HANDLER EQU 0030H +KERNEL32_INITIALIZED EQU 0031H +KERNEL32_SHUTDOWN EQU 0032H +MAX_SYSTEM_CONTROL EQU 0032H +BEGIN_RESERVED_PRIVATE_SYSTEM_CONTROL EQU 70000000H +END_RESERVED_PRIVATE_SYSTEM_CONTROL EQU 7FFFFFFFH +endif +SYSSTATE_PRESYSCRITINIT EQU 00000000H +SYSSTATE_PREDEVICEINIT EQU 10000000H +SYSSTATE_PREINITCOMPLETE EQU 20000000H +SYSSTATE_VXDINITCOMPLETED EQU 40000000H +SYSSTATE_KERNEL32INITED EQU 50000000H +SYSSTATE_KERNEL32TERMINATED EQU 0A0000000H +SYSSTATE_PRESYSVMTERMINATE EQU 0B0000000H +SYSSTATE_PRESYSTEMEXIT EQU 0E0000000H +SYSSTATE_PRESYSTEMEXIT2 EQU 0E4000000H +SYSSTATE_PRESYSCRITEXIT EQU 0F0000000H +SYSSTATE_PRESYSCRITEXIT2 EQU 0F4000000H +SYSSTATE_POSTSYSCRITEXIT2 EQU 0FFF00000H +SYSSTATE_PREDEVICEREBOOT EQU 0FFFF0000H +SYSSTATE_PRECRITREBOOT EQU 0FFFFF000H +SYSSTATE_PREREBOOTCPU EQU 0FFFFFF00H +BeginDoc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EndDoc + + + + + + + + + + + + +??_pf_Check equ 1 +??_pf_ArgsUsed equ 2 +??_pf_Entered equ 4 +??_pf_Left equ 8 +??_pf_Returned equ 16 + +??_pushed = 0 +??_align = 0 +??_ends equ <> + +BeginProc macro Name, P1, P2, P3, P4, P5, P6, P7, LastArg + local Profile_Data, prelabeldata, ??_hookvar + ??_frame = 0 + ??_aframe = 0 + ??_initaframe = 0 + ??_numargs = 0 + ??_numlocals = 0 + ??_numlocalsymbols = 0 + ??_procflags = 0 + ??_esp = 0 + ??_pushed = 0 + ??_align = 0 + ??_hook = 0 + ??_hookarg = 0 + ??_service = 0 + ??_async_service = 0 +IF DEBLEVEL GT DEBLEVELNORMAL + ??_log = DFS_LOG + ??_profile = DFS_PROFILE + ??_test_cld = DFS_TEST_CLD +ELSE + ??_log = 0 +IFDEF DEBUG +IFDEF profileall +IF ?_ICODE + ??_profile = DFS_PROFILE +ELSE + ??_profile = 0 +ENDIF +ELSE + ??_profile = 0 +ENDIF +ELSE + ??_profile = 0 +ENDIF + ??_test_cld = 0 +ENDIF + ??_might_block = 0 + ??_test_reenter = 0 + ??_never_reenter = 0 + ??_not_swapping = 0 + ??_prolog_disabled = 0 + ??_public = 1 + ??_cleanoff = 0 + ??_ccall = 0 + ??_pcall = 0 + ??_scall = 0 + ??_w32svc = 0 + ??_fleave = FALSE + + ??_name equ + + .errnb ??_ends, + .errnb , + + + irp arg, + if ??_hookarg + ??_hookarg = 0 + ??_hookvar equ + elseifdef ?&&arg&&_BeginProc + ?&&arg&&_BeginProc + elseifdef VxD_&&arg&&_CODE_SEG + ??_ends textequ + VxD_&&arg&&_CODE_SEG + else + .err + endif + endm + + + ifndef Not_VxD + ife ??_service + ifndef profileall + ??_profile = 0 + endif + ifdef VMMSYS + ??_prolog_disabled = 1 + endif + else + ??_test_cld = DFS_TEST_CLD + endif + + ife ?_16ICODE + ??_prolog_disabled = 1 + else + ife ?_RCODE + ??_prolog_disabled = 1 + else + ife ?_PCODE + ??_might_block = DFS_TEST_BLOCK + endif + if ??_service + ife ??_async_service + ??_test_reenter = DFS_TEST_REENTER + endif + endif + endif + endif + endif + + if ??_esp + + ??_basereg equ + ??_initaframe = 4 + else + + ??_basereg equ + ??_initaframe = 8 + endif + @Caller equ + + ??_cleanoff = ??_pcall or ??_scall + + + ??_dfs = ??_never_reenter + ??_test_reenter + ??_not_swapping + \ + ??_log + ??_profile + ??_test_cld + ??_might_block + + if ??_prolog_disabled + ??_dfs = 0 + endif + + + + ifndef Not_VxD + + if ??_hook + if ??_align + Dword_Align + endif + prelabeldata: + ifndef ??_hookvar + .err + endif + jmp short Name + jmp [??_hookvar] + ifdef DEBUG + Profile_Data dd 0 + endif + if ??_align + .errnz ($ - prelabeldata) mod 4 + endif + endif + + ifdef DEBUG + ?prolog_&Name label near + if (??_service OR ??_profile) AND (??_hook EQ 0) + jmp short Name + if ??_align + Dword_Align + endif + + IF ?_ICODE + ifdef profileall + ?ProfileHeader_BeginProc Profile_Data, %@filename + else + Profile_Data dd 0 + endif + ELSE + Profile_Data dd 0 + ENDIF + + endif + endif + + if ??_align + Dword_Align + endif + + endif + + Name proc near + + + + ife ??_pcall or ??_ccall or ??_scall + if ??_public + public Name + else + ifdef DEBUG + % ?merge @FileName,$,Name,: + % ?merge public,,,,,@FileName,$,Name + endif + endif + endif + if ??_ccall + if ??_public + _&Name equ Name + ifdef Not_VxD + public C Name + else + public _&Name + endif + endif + endif + if ??_pcall + if ??_public + ?toupper Name + ?merge public,,,,%?upper + endif + endif + + + ifndef Not_VxD + ifdef DEBUG + if ??_dfs EQ DFS_LOG + VMMCall Log_Proc_Call + else + if ??_dfs EQ DFS_TEST_REENTER + VMMCall Test_Reenter + else + if ??_dfs or ?_LOCKABLECODE eq 0 + ifdef WIN31COMPAT + if ??_dfs AND DFS_LOG + VMMCall Log_Proc_Call + endif + if ??_dfs AND DFS_TEST_REENTER + VMMCall Test_Reenter + endif + else + ife ?_LOCKABLECODE + ifdef ??_debug_flags + push ??_debug_flags + if ??_dfs + pushfd + or dword ptr [esp+4],??_dfs + popfd + endif + VMMCall _Debug_Flags_Service + elseif ??_dfs + push ??_dfs + VMMCall _Debug_Flags_Service + endif + else + push ??_dfs + VMMCall _Debug_Flags_Service + endif + endif + else + ifdef profileall + IncProfileCount + endif + endif + endif + endif + endif + endif + + + +endm + + + + + + +?_BeginProc macro +endm + +?PUBLIC_BeginProc macro + ??_public = 1 +endm + +?LOCAL_BeginProc macro + ??_public = 0 +endm + +?HIGH_FREQ_BeginProc macro + ??_align = 1 +endm + +?HOOK_PROC_BeginProc macro + ??_hook = 1 + ??_hookarg = 1 +endm + +?SERVICE_BeginProc macro + ??_service = 1 + .erre ?_16ICODE, + .erre ?_RCODE, +endm + +?ASYNC_SERVICE_BeginProc macro + ??_service = 1 + ??_async_service = 1 + .errnz ?_LCODE, +endm + +?NO_LOG_BeginProc macro + ??_log = 0 +endm + +?NO_PROFILE_BeginProc macro + ??_profile = 0 +endm + +?NO_TEST_CLD_BeginProc macro + ??_test_cld = 0 +endm + +?TEST_BLOCK_BeginProc macro + ??_might_block = DFS_TEST_BLOCK +endm + +?TEST_REENTER_BeginProc macro + ??_test_reenter = DFS_TEST_REENTER +endm + +?NEVER_REENTER_BeginProc macro + ??_never_reenter = DFS_NEVER_REENTER +endm + +?NOT_SWAPPING_BeginProc macro + ??_not_swapping = DFS_NOT_SWAPPING +endm + +?NO_PROLOG_BeginProc macro + ??_prolog_disabled = 1 +endm + +?ESP_BeginProc macro + ??_esp = VMM_TRUE + ifndef Not_VxD + .erre ?_16ICODE, + .erre ?_RCODE, + endif +endm + +?CCALL_BeginProc macro + ??_ccall = 1 +endm + +?PCALL_BeginProc macro + ??_pcall = 1 +endm + +?SCALL_BeginProc macro + ??_scall = 1 +endm + +?ICALL_BeginProc macro + ??_scall = 1 +endm + +?W32SVC_BeginProc macro + ??_scall = 1 + ??_w32svc = 1 +endm + +ifdef DEBUG +ifdef profileall +?ProfileHeader_BeginProc macro PL, filename +ifndef _&filename&__proc_list + _&filename&__proc_list = 0 + PUBLIC _&filename&__proc_list +endif + dd OFFSET32 _&filename&__proc_list +PL dd 0 +_&filename&__proc_list = PL +endm +endif + +IncProfileCount macro + if ??_service OR ??_profile + inc dword ptr [??_name-4] + else + ifndef profileall + .err + endif + endif +endm +else +IncProfileCount macro +endm +endif + + + + + + + + + + + + + + + + +ArgVar macro name,length,used + ??_numargs = ??_numargs + 1 + if ??_pcall + ?mkarg , , , %??_numargs + else + ?argvar , , + endif + ??_procflags = ??_procflags OR ??_pf_Check + endm + +?mkarg macro name, length, used, num + .xcref ?MKA&num + ?deflocal + ?MKA&num ¯o + ?argvar , , + &endm + ??_aframe = ??_aframe + 4 + endm + .xcref ?mkarg + +?argvar macro name,length,used + local a + ifidni , + a = ??_aframe + ??_aframe = ??_aframe + 4 + ?setname , , + elseifidni , + a = ??_aframe + ??_aframe = ??_aframe + 4 + ?setname , , + elseifidni , + a = ??_aframe + ??_aframe = ??_aframe + 4 + ?setname , , + ?setname ,, + ?setname ,, + ?setname ,, + ?setname ,, + ?setname ,, + ?setname ,, + else + a = ??_aframe + ??_aframe = ??_aframe + ((length + 3)/4)*4 + ?setname , <[??_basereg+??_initaframe+a]>, + endif +endm + + + + + + +?setname macro name, value, used + ?deflocal + ifidni , + name equ _inaccessible_NOTUSED_ + else + name equ value + ??_procflags = ??_procflags OR ??_pf_ArgsUsed OR ??_pf_Check + endif +endm + + + + + + + + + + + + + + + + + + + +LocalVar macro name,length,flag + local a + ??_numlocals = ??_numlocals + 1 + ??_pad = 1 + ifidni , + ??_pad = 0 + endif + ifidni , + ??_frame = ??_frame + 1 + 3 * ??_pad + a = ??_frame + ?deflocal + name equ byte ptr [??_basereg-a] + elseifidni , + ??_frame = ??_frame + 2 + 2 * ??_pad + a = ??_frame + ?deflocal + name equ word ptr [??_basereg-a] + elseifidni , + ??_frame = ??_frame + 4 + a = ??_frame + ?deflocal + name equ dword ptr [??_basereg-a] + name&l equ word ptr [??_basereg-a] + name&ll equ byte ptr [??_basereg-a] + name&lh equ byte ptr [??_basereg-a+1] + name&h equ word ptr [??_basereg-a+2] + name&hl equ byte ptr [??_basereg-a+2] + name&hh equ byte ptr [??_basereg-a+3] + else + ??_frame = ??_frame + ((length + 3)/4)*4 + a = ??_frame + ?deflocal + name equ [??_basereg-a] + endif + ??_procflags = ??_procflags OR ??_pf_Check +endm + +?deflocal macro name + irp nm, + ??_numlocalsymbols = ??_numlocalsymbols + 1 + ?dodeflocal , %(??_numlocalsymbols) + endm +endm + .xcref ?deflocal + +?dodeflocal macro name, num + .xcref ?LOC&num + ?LOC&num ¯o + name equ <__inaccessible__NOTINSCOPE__> + &endm + endm + .xcref ?dodeflocal + + + +EnterProc macro + .errnz ??_frame and 3, + if ??_scall + if ??_public + ifdef Not_VxD + ?merge %??_name,@,%(??_aframe),,label,near + ?merge public,,,,C,%??_name,@,%(??_aframe) + else + ?merge _,%??_name,@,%(??_aframe),label,near + ?merge public,,,,,_,%??_name,@,%(??_aframe) + endif + endif + endif + if ??_pcall + ??_aframe = 0 + ?count = ??_numargs + rept ??_numargs + ?invprg ,%?count + ?count = ?count - 1 + endm + endif + ??_fleave = FALSE + if ??_esp + if ??_frame + sub esp, ??_frame + ??_pushed = ??_pushed + ??_frame + ??_fleave = VMM_TRUE + endif + else + if ??_frame eq 0 + if (??_aframe eq 0) OR ((??_procflags AND ??_pf_ArgsUsed) EQ 0) + ifdef DEBUG + push ebp + mov ebp,esp + ??_fleave = VMM_TRUE + endif + else + push ebp + mov ebp,esp + ??_fleave = VMM_TRUE + endif + else + enter ??_frame, 0 + ??_fleave = VMM_TRUE + endif + endif + ??_procflags = ??_procflags OR ??_pf_Entered +endm + + + + + + + + + + + + + + + +LeaveProc macro flags + if ??_fleave + if ??_esp + ifidni , + lea esp,[esp + ??_frame] + else + add esp,??_frame + endif + else + leave + endif + endif + ??_procflags = ??_procflags OR ??_pf_Left +endm + + + + + + + +Return macro + if ??_cleanoff OR ??_w32svc + if ??_w32svc AND (??_aframe LT 8) + ret 8 + else + ret ??_aframe + endif + else + ret + endif + ??_procflags = ??_procflags OR ??_pf_Returned + endm + + + + +EndProc macro Name, Flag + Name endp +if ??_w32svc + if ??_aframe lt 8 + cparm&Name equ 0 + else + cparm&Name equ (??_aframe/4 - 2) + endif +endif +if ??_procflags AND ??_pf_Left +if ??_fleave +if ??_esp + ??_pushed = ??_pushed - ??_frame +endif +endif +endif +ifdifi , + if ??_pushed ne 0 + %out Warning: stack not balanced in Name + endif + if ??_procflags AND ??_pf_Check + ife ??_procflags AND ??_pf_Entered + %out Warning: ArgVar/LocalVar without EnterProc in Name + endif + ife ??_procflags AND ??_pf_Left + %out Warning: ArgVar/LocalVar without LeaveProc in Name + endif + ife ??_procflags AND ??_pf_Returned + %out Warning: ArgVar/LocalVar without Return in Name + endif + endif +endif +ifdifi , + ?count = 0 + rept ??_numlocalsymbols + ?count = ?count + 1 + ?invprg ,%?count + endm +endif + ??_ends + ??_ends equ <> + endm + + + + + + + +cCall macro name, arglst, flags + ife .TYPE name + CondExtern name, near + endif + PushCParams , + call name + ClearCParams + endm + .xcref cCall + + + + + + +pCall macro name, arglst + local ??saved + ife .TYPE name + ?toupper name + else + ?upper equ + endif + CondExtern %?upper, near + ??saved = ??_pushed + irp x, + push x + ??_pushed = ??_pushed + 4 + endm + call ?upper + ??_pushed = ??saved + endm + .xcref pCall + + + + + + + +sCall macro name, arglst + local ??saved + ??saved = ??_pushed + PushCParams + ?scall name, %(??_argc * 4) + ??_pushed = ??saved + endm + .xcref sCall + + + + + +iCall equ + + + + + + + + + + + + + + +IFNDEF STANDARD_CCALL +NONSTANDARD_CCALL = 1 +ENDIF + +PushCParams macro arglst, flags + ??_argc = 0 +IFDEF NONSTANDARD_CCALL + ??_popargs = 0 +ELSE + ??_popargs = ??_align EQ 0 +ENDIF + ifidni , + ??_popargs = 1 + elseifidni , + ??_popargs = 0 + endif + + irp x, + ??_argc = ??_argc + 1 + ?marg ,%??_argc + endm + ?count = ??_argc + rept ??_argc + ?invprg ,%?count + ?count = ?count - 1 + endm + endm + + + + + + + + + + + + + + + + +ClearCParams macro fPreserveFlags + if ??_argc ne 0 + if (??_popargs) AND (??_argc LE 2) + rept ??_argc + pop ecx + endm + else + ifidni , + lea esp, [esp][??_argc * 4] + else + add esp,??_argc * 4 + endif + endif + endif + ??_pushed = ??_pushed - (??_argc * 4) + endm + + + +?marg macro name, num + .xcref + .xcref ?AM&num + .cref + ?AM&num ¯o + push name + ??_pushed = ??_pushed + 4 + &endm + endm + .xcref ?marg + + + +?invprg macro name1, name2 + name1&name2 + purge name1&name2 + endm + .xcref ?invprg + + + +?scall macro name1, name2 + CondExtern _&name1&@&name2, near + call _&name1&@&name2 + endm + .xcref ?scall + + + +?merge macro l1, l2, l3, l4, op, r1, r2, r3, r4, r5, r6, r7, r8, r9 + l1&l2&l3&l4 op r1&r2&r3&r4&r5&r6&r7&r8&r9 + endm + + + +?toupper macro s + ?upper equ <> + irpc x, + if '&x' GE 'a' + if '&x' LE 'z' + ?t1 substr ,'&x'-'a'+1,1 + ?upper catstr ?upper,?t1 + else + ?upper catstr ?upper,<&x> + endif + else + ?upper catstr ?upper,<&x> + endif + endm + endm + .xcref + + + + + + +CondExtern macro name,dist + ifdef MASM6 + ifndef name + externdef name:dist + endif + else + if2 + ifndef name + extrn name:dist + endif + endif + endif +endm + + + +SaveReg macro reglist + irp reg, + ifidni , + pushfd + ??_pushed = ??_pushed + 4 + else + ifidni , + pushad + ??_pushed = ??_pushed + SIZE Pushad_Struc + else + push reg + ??_pushed = ??_pushed + 4 + endif + endif + endm +endm + + + + + + + +RestoreReg macro reglist + irp reg, + ifidni , + popfd + ??_pushed = ??_pushed - 4 + else + ifidni , + popad + ??_pushed = ??_pushed - SIZE Pushad_Struc + else + pop reg + ??_pushed = ??_pushed - 4 + endif + endif + endm +endm + +ifdef DEBUG +Begin_Profile_List macro devname +ifdef profileall +VxD_DATA_SEG + db 'PROCLIST' +PUBLIC devname&_Proc_Profile_List +devname&_Proc_Profile_List label dword +endif +endm + +Profile_Link macro modname +ifdef profileall +ifdifi ,@filename +EXTRN _&modname&__proc_list:near +endif + dd OFFSET32 _&modname&__proc_list +endif +endm + +End_Profile_List macro +ifdef profileall + dd 0 +VxD_DATA_ENDS +endif +endm + + +endif +ifndef Not_VxD +RESERVED_LOW_BOOST EQU 00000001H +CUR_RUN_VM_BOOST EQU 00000004H +LOW_PRI_DEVICE_BOOST EQU 00000010H +HIGH_PRI_DEVICE_BOOST EQU 00001000H +CRITICAL_SECTION_BOOST EQU 00100000H +TIME_CRITICAL_BOOST EQU 00400000H +RESERVED_HIGH_BOOST EQU 40000000H +PEF_WAIT_FOR_STI_BIT EQU 0 +PEF_WAIT_FOR_STI EQU (1 SHL PEF_WAIT_FOR_STI_BIT) +PEF_WAIT_NOT_CRIT_BIT EQU 1 +PEF_WAIT_NOT_CRIT EQU (1 SHL PEF_WAIT_NOT_CRIT_BIT) +PEF_DONT_UNBOOST_BIT EQU 2 +PEF_DONT_UNBOOST EQU (1 SHL PEF_DONT_UNBOOST_BIT) +PEF_ALWAYS_SCHED_BIT EQU 3 +PEF_ALWAYS_SCHED EQU (1 SHL PEF_ALWAYS_SCHED_BIT) +PEF_TIME_OUT_BIT EQU 4 +PEF_TIME_OUT EQU (1 SHL PEF_TIME_OUT_BIT) +PEF_WAIT_NOT_HW_INT_BIT EQU 5 +PEF_WAIT_NOT_HW_INT EQU (1 SHL PEF_WAIT_NOT_HW_INT_BIT) +PEF_WAIT_NOT_NESTED_EXEC_BIT EQU 6 +PEF_WAIT_NOT_NESTED_EXEC EQU (1 SHL PEF_WAIT_NOT_NESTED_EXEC_BIT) +PEF_WAIT_IN_PM_BIT EQU 7 +PEF_WAIT_IN_PM EQU (1 SHL PEF_WAIT_IN_PM_BIT) +PEF_THREAD_EVENT_BIT EQU 8 +PEF_THREAD_EVENT EQU (1 SHL PEF_THREAD_EVENT_BIT) +PEF_WAIT_FOR_THREAD_STI_BIT EQU 9 +PEF_WAIT_FOR_THREAD_STI EQU (1 SHL PEF_WAIT_FOR_THREAD_STI_BIT) +PEF_RING0_EVENT_BIT EQU 10 +PEF_RING0_EVENT EQU (1 SHL PEF_RING0_EVENT_BIT) +PEF_WAIT_CRIT_BIT EQU 11 +PEF_WAIT_CRIT EQU (1 SHL PEF_WAIT_CRIT_BIT) +PEF_WAIT_CRIT_VM_BIT EQU 12 +PEF_WAIT_CRIT_VM EQU (1 SHL PEF_WAIT_CRIT_VM_BIT) +PEF_PROCESS_LAST_BIT EQU 13 +PEF_PROCESS_LAST EQU (1 SHL PEF_PROCESS_LAST_BIT) +PEF_WAIT_NOT_TIME_CRIT_BIT EQU PEF_WAIT_NOT_HW_INT_BIT +PEF_WAIT_NOT_TIME_CRIT EQU PEF_WAIT_NOT_HW_INT +PEF_WAIT_NOT_PM_LOCKED_STACK_BIT EQU PEF_WAIT_NOT_NESTED_EXEC_BIT +PEF_WAIT_NOT_PM_LOCKED_STACK EQU PEF_WAIT_NOT_NESTED_EXEC +BLOCK_SVC_INTS_BIT EQU 0 +BLOCK_SVC_INTS EQU (1 SHL BLOCK_SVC_INTS_BIT) +BLOCK_SVC_IF_INTS_LOCKED_BIT EQU 1 +BLOCK_SVC_IF_INTS_LOCKED EQU (1 SHL BLOCK_SVC_IF_INTS_LOCKED_BIT) +BLOCK_ENABLE_INTS_BIT EQU 2 +BLOCK_ENABLE_INTS EQU (1 SHL BLOCK_ENABLE_INTS_BIT) +BLOCK_POLL_BIT EQU 3 +BLOCK_POLL EQU (1 SHL BLOCK_POLL_BIT) +BLOCK_THREAD_IDLE_BIT EQU 4 +BLOCK_THREAD_IDLE EQU (1 SHL BLOCK_THREAD_IDLE_BIT) +BLOCK_FORCE_SVC_INTS_BIT EQU 5 +BLOCK_FORCE_SVC_INTS EQU (1 SHL BLOCK_FORCE_SVC_INTS_BIT) + +Client_Reg_Struc STRUC +Client_EDI DD ? +Client_ESI DD ? +Client_EBP DD ? +Client_res0 DD ? +Client_EBX DD ? +Client_EDX DD ? +Client_ECX DD ? +Client_EAX DD ? +Client_Error DD ? +Client_EIP DD ? +Client_CS DW ? +Client_res1 DW ? +Client_EFlags DD ? +Client_ESP DD ? +Client_SS DW ? +Client_res2 DW ? +Client_ES DW ? +Client_res3 DW ? +Client_DS DW ? +Client_res4 DW ? +Client_FS DW ? +Client_res5 DW ? +Client_GS DW ? +Client_res6 DW ? +Client_Alt_EIP DD ? +Client_Alt_CS DW ? +Client_res7 DW ? +Client_Alt_EFlags DD ? +Client_Alt_ESP DD ? +Client_Alt_SS DW ? +Client_res8 DW ? +Client_Alt_ES DW ? +Client_res9 DW ? +Client_Alt_DS DW ? +Client_res10 DW ? +Client_Alt_FS DW ? +Client_res11 DW ? +Client_Alt_GS DW ? +Client_res12 DW ? +Client_Reg_Struc ENDS + +Client_Word_Reg_Struc STRUC +Client_DI DW ? +Client_res13 DW ? +Client_SI DW ? +Client_res14 DW ? +Client_BP DW ? +Client_res15 DW ? +Client_res16 DD ? +Client_BX DW ? +Client_res17 DW ? +Client_DX DW ? +Client_res18 DW ? +Client_CX DW ? +Client_res19 DW ? +Client_AX DW ? +Client_res20 DW ? +Client_res21 DD ? +Client_IP DW ? +Client_res22 DW ? +Client_res23 DD ? +Client_Flags DW ? +Client_res24 DW ? +Client_SP DW ? +Client_res25 DW ? +Client_res26 DD 5 DUP (?) +Client_Alt_IP DW ? +Client_res27 DW ? +Client_res28 DD ? +Client_Alt_Flags DW ? +Client_res29 DW ? +Client_Alt_SP DW ? +Client_Word_Reg_Struc ENDS + +Client_Byte_Reg_Struc STRUC +Client_res30 DD 4 DUP (?) +Client_BL DB ? +Client_BH DB ? +Client_res31 DW ? +Client_DL DB ? +Client_DH DB ? +Client_res32 DW ? +Client_CL DB ? +Client_CH DB ? +Client_res33 DW ? +Client_AL DB ? +Client_AH DB ? +Client_Byte_Reg_Struc ENDS +?UnionSize = 0 +if size Client_Reg_Struc gt ?UnionSize + ?UnionSize = size Client_Reg_Struc +endif +CRS equ <(byte ptr 0)> + +if size Client_Word_Reg_Struc gt ?UnionSize + ?UnionSize = size Client_Word_Reg_Struc +endif +CWRS equ <(byte ptr 0)> + +if size Client_Byte_Reg_Struc gt ?UnionSize + ?UnionSize = size Client_Byte_Reg_Struc +endif +CBRS equ <(byte ptr 0)> + + +tagCLIENT_STRUC STRUC + DB ?UnionSize dup(?) +tagCLIENT_STRUC ENDS + +IF 0 +.ERRNZ Client_SP - Client_ESP +.ERRNZ Client_AL - Client_EAX + +endif +DYNA_LINK_INT EQU 20H + + + + + + + + + + + + +DeclareNonstandardCcallService macro arglst + irp x, + ??_nonstandardccall_&x = 1 + endm +endm + + + + + + + +DeclareNonstandardCcallService <_BlockOnID, _LocalizeSprintf> +DeclareNonstandardCcallService <_SetLastV86Page, _Assert_Range> + +BeginDoc + + + + + + + + + + + + + +EndDoc + + +BeginDoc + + + + + + + + +EndDoc + +DefTable MACRO vt, vn + vt EQU +ENDM + +GenDD2 MACRO vt, sn, jf + dd OFFSET32 vt[sn+jf] +ENDM + +GenDD MACRO P, vid, snum, jflag + LOCAL vtable +IFDEF @@VxDName&vid + Deftable vtable, %@@VxDName&vid + EXTRN vtable:DWORD + GenDD2 %vtable, snum, jflag +ELSE + dd @@&P+jflag +ENDIF + +ENDM + + +VxDCall MACRO P, Param, flags + ??_vxdid = (@@&P SHR 16) + ??_servicenum = (@@&P AND 0FFFFh) + ifdef ??_nonstandardccall_&P + PushCParams , + else + PushCParams , + endif + int Dyna_Link_Int + GenDD P, %??_vxdid, %??_servicenum, 0 + ifdef ??_nonstandardccall_&P + ClearCParams PRESERVE_FLAGS + else + ClearCParams + endif + ENDM + +VxDJmp MACRO P, Param + ??_vxdid = (@@&P SHR 16) + ??_servicenum = (@@&P AND 0FFFFh) + .errnb , + int Dyna_Link_Int + GenDD P, %??_vxdid, %??_servicenum, DL_Jmp_Mask + ENDM + +DL_Jmp_Mask EQU 8000h +DL_Jmp_Bit EQU 0Fh + +VMMCall MACRO P, Param + .ERRNZ (@@&P SHR 16) - VMM_DEVICE_ID + VxDCall

, + ENDM + +VMMJmp MACRO P, Param + .ERRNZ (@@&P SHR 16) - VMM_DEVICE_ID + VxDJmp

, + ENDM + +BeginDoc + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EndDoc + + + + +VxD_CODE_SEG EQU +VxD_CODE_ENDS EQU + + +VxD_LOCKED_CODE_SEG MACRO +_LTEXT SEGMENT +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 4 + ??_LCODE + ASSUME cs:FLAT, ds:FLAT, es:FLAT, ss:FLAT + + ENDM + +VxD_LOCKED_CODE_ENDS MACRO +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 4 +_LTEXT ENDS + ENDM + + + + +VxD_PAGEABLE_CODE_SEG MACRO +_PTEXT SEGMENT +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 4 + ??_PCODE + ASSUME cs:FLAT, ds:FLAT, es:FLAT, ss:FLAT + + ENDM + +VxD_PAGEABLE_CODE_ENDS MACRO +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 4 +_PTEXT ENDS + ENDM + + + + +VxD_DEBUG_ONLY_CODE_SEG MACRO +_DBOCODE SEGMENT +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 4 + ??_DBOCODE + ASSUME cs:FLAT, ds:FLAT, es:FLAT, ss:FLAT + ENDM + +VxD_DEBUG_ONLY_CODE_ENDS MACRO +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 4 +_DBOCODE ENDS + ENDM + + + + +VxD_INIT_CODE_SEG MACRO +_ITEXT SEGMENT +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 4 + ??_ICODE + ASSUME cs:FLAT, ds:FLAT, es:FLAT, ss:FLAT + ENDM + +VxD_INIT_CODE_ENDS MACRO +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 4 +_ITEXT ENDS + ENDM + +VxD_ICODE_SEG equ VxD_INIT_CODE_SEG +VxD_ICODE_ENDS equ VxD_INIT_CODE_ENDS + + + + +VxD_DATA_SEG EQU +VxD_DATA_ENDS EQU + +VxD_LOCKED_DATA_SEG MACRO NO_ALIGN +_LDATA SEGMENT +IFB + ALIGN 4 +ENDIF + ENDM + +VxD_LOCKED_DATA_ENDS MACRO +_LDATA ENDS + ENDM + + + + +VxD_IDATA_SEG MACRO +_IDATA SEGMENT + ENDM +VxD_IDATA_ENDS MACRO +_IDATA ENDS + ENDM + + + + +VxD_PAGEABLE_DATA_SEG MACRO NO_ALIGN +_PDATA SEGMENT +IFB + ALIGN 4 +ENDIF + ENDM + +VxD_PAGEABLE_DATA_ENDS MACRO +_PDATA ENDS + ENDM + + + + +VxD_STATIC_CODE_SEG MACRO +_STEXT SEGMENT +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 4 + ??_SCODE + ASSUME cs:FLAT, ds:FLAT, es:FLAT, ss:FLAT + + ENDM + +VxD_STATIC_CODE_ENDS MACRO +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 4 +_STEXT ENDS + ENDM + + + + +VxD_STATIC_DATA_SEG MACRO NO_ALIGN +_SDATA SEGMENT +IFB + ALIGN 4 +ENDIF + ENDM + +VxD_STATIC_DATA_ENDS MACRO +_SDATA ENDS + ENDM + + + +VxD_DEBUG_ONLY_DATA_SEG MACRO NO_ALIGN +_DBODATA SEGMENT +IFB + ALIGN 4 +ENDIF + ENDM + +VxD_DEBUG_ONLY_DATA_ENDS MACRO +_DBODATA ENDS + ENDM + + + + +VxD_16BIT_INIT_SEG MACRO +_16ICODE SEGMENT +ASSUME CS:_16ICODE, DS:NOTHING, ES:NOTHING, SS:NOTHING +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 4 + ??_16ICODE + ENDM + +VxD_16BIT_INIT_ENDS MACRO +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 4 +_16ICODE ENDS + ENDM + + + +VxD_REAL_INIT_SEG MACRO +_RCODE SEGMENT +ASSUME CS:_RCODE, DS:_RCODE, ES:_RCODE, SS:_RCODE +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 4 + ??_RCODE + ENDM + +VxD_REAL_INIT_ENDS MACRO +??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 4 +_RCODE ENDS + ENDM + +endif +ifndef DDK_VERSION +ifdef WIN31COMPAT +DDK_VERSION EQU 30AH +else +DDK_VERSION EQU 400H +endif +endif + +VxD_Desc_Block STRUC +DDB_Next DD ? +DDB_SDK_Version DW DDK_VERSION +DDB_Req_Device_Number DW UNDEFINED_DEVICE_ID +DDB_Dev_Major_Version DB 0 +DDB_Dev_Minor_Version DB 0 +DDB_Flags DW 0 +DDB_Name DB " " +DDB_Init_Order DD UNDEFINED_INIT_ORDER +DDB_Control_Proc DD ? +DDB_V86_API_Proc DD 0 +DDB_PM_API_Proc DD 0 +DDB_V86_API_CSIP DD 0 +DDB_PM_API_CSIP DD 0 +DDB_Reference_Data DD ? +DDB_Service_Table_Ptr DD 0 +DDB_Service_Table_Size DD 0 +DDB_Win32_Service_Table DD 0 +DDB_Prev DD 'Prev' +DDB_Size DD SIZE(VxD_Desc_Block) +DDB_Reserved1 DD 'Rsv1' +DDB_Reserved2 DD 'Rsv2' +DDB_Reserved3 DD 'Rsv3' +VxD_Desc_Block ENDS +ifndef Not_VxD +DDB_SYS_CRIT_INIT_DONE_BIT EQU 0 +DDB_SYS_CRIT_INIT_DONE EQU (1 SHL DDB_SYS_CRIT_INIT_DONE_BIT) +DDB_DEVICE_INIT_DONE_BIT EQU 1 +DDB_DEVICE_INIT_DONE EQU (1 SHL DDB_DEVICE_INIT_DONE_BIT) +DDB_HAS_WIN32_SVCS_BIT EQU 14 +DDB_HAS_WIN32_SVCS EQU (1 SHL DDB_HAS_WIN32_SVCS_BIT) +DDB_DYNAMIC_VXD_BIT EQU 15 +DDB_DYNAMIC_VXD EQU (1 SHL DDB_DYNAMIC_VXD_BIT) +DDB_DEVICE_DYNALINKED_BIT EQU 13 +DDB_DEVICE_DYNALINKED EQU (1 SHL DDB_DEVICE_DYNALINKED_BIT) +BeginDoc + + + + + + + +EndDoc +Declare_Virtual_Device MACRO Name, Major_Ver, Minor_Ver, Ctrl_Proc, Device_Num, Init_Order, V86_Proc, PM_Proc, Reference_Data + LOCAL V86_API_Offset, PM_API_Offset, Serv_Tab_Offset, Serv_Tab_Len, Ref_Data_Offset + +dev_id_err MACRO + +IFNDEF Name&_Name_Based +.err +ENDIF + ENDM + +IFB + V86_API_Offset EQU 0 +ELSE + IFB + dev_id_err + ENDIF + V86_API_Offset EQU +ENDIF + +IFB + PM_API_Offset EQU 0 +ELSE + IFB + dev_id_err + ENDIF + PM_API_Offset EQU +ENDIF + +IFDEF Name&_Service_Table + IFB + dev_id_err + ELSE + IFE Device_Num - UNDEFINED_DEVICE_ID + dev_id_err + ENDIF + ENDIF + Serv_Tab_Offset EQU + Serv_Tab_Len EQU Num_&Name&_Services +ELSE + Serv_Tab_Offset EQU 0 + Serv_Tab_Len EQU 0 +ENDIF + +IFNB + .erre (Device_Num LT BASEID_FOR_NAMEBASEDVXD), +ENDIF + +IFB + Ref_Data_Offset EQU 0 +ELSE + Ref_Data_Offset EQU +ENDIF + +IFDEF DEBUG +VxD_IDATA_SEG + db 0dh, 0ah, 'D_E_B_U_G===>' + db "&Name", '<===', 0dh, 0ah +VxD_IDATA_ENDS +ENDIF + +VxD_LOCKED_DATA_SEG + +PUBLIC Name&_DDB +Name&_DDB VxD_Desc_Block <,,Device_Num,Major_Ver,Minor_Ver,,"&Name",Init_Order,\ + OFFSET32 Ctrl_Proc, V86_API_Offset, PM_API_Offset, \ + ,,Ref_Data_Offset,Serv_Tab_Offset, Serv_Tab_Len> + +VxD_LOCKED_DATA_ENDS + + ENDM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Begin_Control_Dispatch MACRO VxD_Name, p1, p2 +??_cd_low = 0FFFFFFFFh +??_cd_high = 0 + +BeginProc VxD_Name&_Control, p1, p2, LOCKED +ENDM + +End_Control_Dispatch MACRO VxD_Name + LOCAL ignore, table + +procoff MACRO num +IFDEF ??_cd_&&num + dd OFFSET32 ??_cd_&&num +ELSE + dd OFFSET32 ignore +ENDIF +ENDM + +IF ??_cd_low EQ ??_cd_high + cmp eax, ??_cd_low + ?merge ,,,,,, %(??_cd_low) + clc + ret +ELSE +IF ??_cd_low GT 0 + sub eax, ??_cd_low +ENDIF + cmp eax, ??_cd_high - ??_cd_low + 1 + jae short ignore + jmp [eax*4+table] +ignore: + clc + ret + +table label dword + REPT ??_cd_high - ??_cd_low + 1 + procoff %(??_cd_low) + ??_cd_low = ??_cd_low + 1 + ENDM +ENDIF + +EndProc VxD_Name&_Control + +PURGE procoff +PURGE Begin_Control_Dispatch +PURGE Control_Dispatch +PURGE End_Control_Dispatch +ENDM + +BeginDoc + + + + + + + + + + + + + + + + + + + + +EndDoc +Control_Dispatch MACRO Service, Procedure, callc, arglst + LOCAL Skip_Interseg_Jump + +.errnz ?_LCODE, + +IFB + +IFDEF ??_cd_low +Equate_Service MACRO Serv +??_cd_&&Serv equ Procedure +ENDM + +Equate_Service %(Service) + +IF Service LT ??_cd_low +??_cd_low = Service +ENDIF +IF Service GT ??_cd_high +??_cd_high = Service +ENDIF + +PURGE Equate_Service + +ELSE + cmp eax, Service + jz Procedure +ENDIF + +ELSE + + cmp eax, Service + jne SHORT Skip_Interseg_Jump + callc Procedure, +IF Service EQ PNP_NEW_DEVNODE + stc +ELSE + cmp eax,1 +ENDIF + ret +Skip_Interseg_Jump: + +ENDIF + + ENDM + +BYTE_INPUT EQU 000H +BYTE_OUTPUT EQU 004H +WORD_INPUT EQU 008H +WORD_OUTPUT EQU 00CH +DWORD_INPUT EQU 010H +DWORD_OUTPUT EQU 014H +OUTPUT_BIT EQU 2 +OUTPUT EQU (1 SHL OUTPUT_BIT) +WORD_IO_BIT EQU 3 +WORD_IO EQU (1 SHL WORD_IO_BIT) +DWORD_IO_BIT EQU 4 +DWORD_IO EQU (1 SHL DWORD_IO_BIT) +STRING_IO_BIT EQU 5 +STRING_IO EQU (1 SHL STRING_IO_BIT) +REP_IO_BIT EQU 6 +REP_IO EQU (1 SHL REP_IO_BIT) +ADDR_32_IO_BIT EQU 7 +ADDR_32_IO EQU (1 SHL ADDR_32_IO_BIT) +REVERSE_IO_BIT EQU 8 +REVERSE_IO EQU (1 SHL REVERSE_IO_BIT) +IO_SEG_MASK EQU 0FFFF0000H +IO_SEG_SHIFT EQU 10H +BeginDoc + + + + + + +EndDoc +Dispatch_Byte_IO MACRO In_Proc, Out_Proc + LOCAL Byte_IO + cmp ecx, Byte_Output + jbe SHORT Byte_IO + VMMJmp Simulate_IO +Byte_IO: +IFIDNI , + je Out_Proc +ELSE +IFIDNI , + jb In_Proc +ELSE + je Out_Proc + jmp In_Proc +ENDIF +ENDIF + ENDM + +BeginDoc + + + + + + + +EndDoc +Emulate_Non_Byte_IO MACRO + LOCAL Byte_IO + cmp ecx, Byte_Output + jbe SHORT Byte_IO + VMMJmp Simulate_IO +Byte_IO: + ENDM + +BeginDoc + + + + + + + + +EndDoc + + +VxD_IOT_Hdr STRUC +VxD_IO_Ports DW ? +VxD_IOT_Hdr ENDS + +VxD_IO_Struc STRUC +VxD_IO_Port DW ? +VxD_IO_Proc DD ? +VxD_IO_Struc ENDS +.ERRNZ SIZE VxD_IOT_Hdr - 2 +Begin_VxD_IO_Table MACRO Table_Name +PUBLIC Table_Name +Table_Name LABEL WORD + +ifndef MASM6 +IF2 +IFNDEF Table_Name&_Entries +.err +ENDIF + dw Table_Name&_Entries +ELSE + dw ? +ENDIF +ELSE + dw Table_Name&_Entries +ENDIF + + ENDM + +.ERRNZ SIZE VxD_IO_Struc - 6 +VxD_IO MACRO Port, Proc_Name + dw Port + dd OFFSET32 Proc_Name + ENDM + +End_VxD_IO_Table MACRO Table_Name + +IFNDEF Table_Name +.err +ELSE + Table_Name&_Entries EQU (($-Table_Name)-2) / (SIZE VxD_IO_Struc) +IF Table_Name&_Entries LE 0 +.err +ENDIF +ENDIF + ENDM + + + + + + + + + + + + + +Push_Client_State MACRO Can_Trash_EDI + sub esp, SIZE Client_Reg_Struc + ??_pushed = ??_pushed + SIZE Client_Reg_Struc + ifidni , + mov edi, esp + VMMCall Save_Client_State + else + push edi + lea edi, [esp+4] + VMMCall Save_Client_State + pop edi + endif + ENDM + +Pop_Client_State MACRO Can_Trash_ESI + ifdifi , + push esi + lea esi, [esp+4] + VMMCall Restore_Client_State + pop esi + else + mov esi, esp + VMMCall Restore_Client_State + endif + add esp, SIZE Client_Reg_Struc + ??_pushed = ??_pushed - SIZE Client_Reg_Struc + ENDM + +BeginDoc + + + + + + + + + + + + + + +EndDoc + +CallRet MACRO P1, P2 +IFDEF DEBUG +IFIDNI , + call P2 +ELSE + call P1 +ENDIF + ret +ELSE + jmp P1 P2 +ENDIF + ENDM + +BeginDoc + + + + + + +EndDoc + +IFDEF DEBUG + +VxDCallRet macro p:req + VxDCall p + ret +endm + +VMMCallRet macro p:req + VMMCall p + ret +endm + +ELSE + +VxDCallRet equ +VMMCallRet equ + +ENDIF + + + +PClient_DS equ WORD PTR -4 +PClient_ES equ WORD PTR -8 +PClient_FS equ WORD PTR -12 +PClient_GS equ WORD PTR -16 + + + + + + + + + + + +Client_Ptr_Flat MACRO Reg_32, Cli_Seg, Cli_Off, Can_Trash_EAX + +IFDIFI , + IFDIFI , + xchg Reg_32, eax + ENDIF +ENDIF +IFB + mov ax, (Client_&Cli_Seg * 100h) + 0FFh +ELSE + mov ax, (Client_&Cli_Seg * 100h) + Client_&Cli_Off +ENDIF + VMMCall Map_Flat + +IFDIFI , + xchg Reg_32, eax +ENDIF + + ENDM + + + +VxDint MACRO Int_Number + if (OPATTR Int_Number) AND 4 + push Int_Number + else + push DWORD PTR Int_Number + endif + VMMCall Exec_VxD_Int + ENDM + +VxDintMustComplete MACRO Int_Number + if (OPATTR Int_Number) AND 4 + push Int_Number + else + push DWORD PTR Int_Number + endif + VMMCall _ExecVxDIntMustComplete + ENDM + + + +endif +DUPLICATE_DEVICE_ID_BIT EQU 0 +DUPLICATE_DEVICE_ID EQU (1 SHL DUPLICATE_DEVICE_ID_BIT) +DUPLICATE_FROM_INT2F_BIT EQU 1 +DUPLICATE_FROM_INT2F EQU (1 SHL DUPLICATE_FROM_INT2F_BIT) +LOADING_FROM_INT2F_BIT EQU 2 +LOADING_FROM_INT2F EQU (1 SHL LOADING_FROM_INT2F_BIT) +DEVICE_LOAD_OK EQU 0 +ABORT_DEVICE_LOAD EQU 1 +ABORT_WIN386_LOAD EQU 2 +NO_FAIL_MESSAGE_BIT EQU 15 +NO_FAIL_MESSAGE EQU (1 SHL NO_FAIL_MESSAGE_BIT) +LDRSRV_GET_PROFILE_STRING EQU 0 +LDRSRV_GET_NEXT_PROFILE_STRING EQU 1 +LDRSRV_RESERVED EQU 2 +LDRSRV_GET_PROFILE_BOOLEAN EQU 3 +LDRSRV_GET_PROFILE_DECIMAL_INT EQU 4 +LDRSRV_GET_PROFILE_HEX_INT EQU 5 +LDRSRV_COPY_EXTENDED_MEMORY EQU 6 +LDRSRV_GET_MEMORY_INFO EQU 7 +LDRSRV_RegOpenKey EQU 100H +LDRSRV_RegCreateKey EQU 101H +LDRSRV_RegCloseKey EQU 102H +LDRSRV_RegDeleteKey EQU 103H +LDRSRV_RegSetValue EQU 104H +LDRSRV_RegQueryValue EQU 105H +LDRSRV_RegEnumKey EQU 106H +LDRSRV_RegDeleteValue EQU 107H +LDRSRV_RegEnumValue EQU 108H +LDRSRV_RegQueryValueEx EQU 109H +LDRSRV_RegSetValueEx EQU 10AH +LDRSRV_RegFlushKey EQU 10BH +LDRSRV_COPY_INIT EQU 1 +LDRSRV_COPY_LOCKED EQU 2 +LDRSRV_COPY_PAGEABLE EQU 3 +RCODE_OBJ EQU -1 +LCODE_OBJ EQU 01H +LDATA_OBJ EQU 02H +PCODE_OBJ EQU 03H +PDATA_OBJ EQU 04H +SCODE_OBJ EQU 05H +SDATA_OBJ EQU 06H +CODE16_OBJ EQU 07H +LMSG_OBJ EQU 08H +PMSG_OBJ EQU 09H +DBOC_OBJ EQU 0BH +DBOD_OBJ EQU 0CH +ICODE_OBJ EQU 11H +IDATA_OBJ EQU 12H +ICODE16_OBJ EQU 13H +IMSG_OBJ EQU 14H + +ObjectLocation STRUC +OL_LinearAddr DD ? +OL_Size DD ? +OL_ObjType DB ? +ObjectLocation ENDS +MAXOBJECTS EQU 25 + +Device_Location_List STRUC +DLL_DDB DD ? +DLL_NumObjects DB ? +DLL_ObjLocation DB SIZE ObjectLocation * 1 DUP (?) +Device_Location_List ENDS +PE_BIT EQU 0 +PE_MASK EQU (1 SHL PE_BIT) +MP_BIT EQU 1 +MP_MASK EQU (1 SHL MP_BIT) +EM_BIT EQU 2 +EM_MASK EQU (1 SHL EM_BIT) +TS_BIT EQU 3 +TS_MASK EQU (1 SHL TS_BIT) +ET_BIT EQU 4 +ET_MASK EQU (1 SHL ET_BIT) +PG_BIT EQU 31 +PG_MASK EQU (1 SHL PG_BIT) +CF_BIT EQU 0 +CF_MASK EQU (1 SHL CF_BIT) +PF_BIT EQU 2 +PF_MASK EQU (1 SHL PF_BIT) +AF_BIT EQU 4 +AF_MASK EQU (1 SHL AF_BIT) +ZF_BIT EQU 6 +ZF_MASK EQU (1 SHL ZF_BIT) +SF_BIT EQU 7 +SF_MASK EQU (1 SHL SF_BIT) +TF_BIT EQU 8 +TF_MASK EQU (1 SHL TF_BIT) +IF_BIT EQU 9 +IF_MASK EQU (1 SHL IF_BIT) +DF_BIT EQU 10 +DF_MASK EQU (1 SHL DF_BIT) +OF_BIT EQU 11 +OF_MASK EQU (1 SHL OF_BIT) +IOPL_MASK EQU 3000H +IOPL_BIT0 EQU 12 +IOPL_BIT1 EQU 13 +NT_BIT EQU 14 +NT_MASK EQU (1 SHL NT_BIT) +RF_BIT EQU 16 +RF_MASK EQU (1 SHL RF_BIT) +VM_BIT EQU 17 +VM_MASK EQU (1 SHL VM_BIT) +AC_BIT EQU 18 +AC_MASK EQU (1 SHL AC_BIT) +VIF_BIT EQU 19 +VIF_MASK EQU (1 SHL VIF_BIT) +VIP_BIT EQU 20 +VIP_MASK EQU (1 SHL VIP_BIT) + + + + + + +IFDEF MASM6 +loopde EQU +loopdne EQU +loopdz EQU +loopdnz EQU +ELSE +loopd EQU +loopde EQU +loopdne EQU +loopdz EQU +loopdnz EQU +ENDIF + +P_SIZE EQU 1000H +P_PRESBIT EQU 0 +P_PRES EQU (1 SHL P_PRESBIT) +P_WRITEBIT EQU 1 +P_WRITE EQU (1 SHL P_WRITEBIT) +P_USERBIT EQU 2 +P_USER EQU (1 SHL P_USERBIT) +P_ACCBIT EQU 5 +P_ACC EQU (1 SHL P_ACCBIT) +P_DIRTYBIT EQU 6 +P_DIRTY EQU (1 SHL P_DIRTYBIT) +P_AVAIL EQU (P_PRES+P_WRITE+P_USER) +PG_VM EQU 0 +PG_SYS EQU 1 +PG_RESERVED1 EQU 2 +PG_PRIVATE EQU 3 +PG_RESERVED2 EQU 4 +PG_RELOCK EQU 5 +PG_INSTANCE EQU 6 +PG_HOOKED EQU 7 +PG_IGNORE EQU 0FFFFFFFFH +D_PRES EQU 080H +D_NOTPRES EQU 0 +D_DPL0 EQU 0 +D_DPL1 EQU 020H +D_DPL2 EQU 040H +D_DPL3 EQU 060H +D_SEG EQU 010H +D_CTRL EQU 0 +D_GRAN_BYTE EQU 000H +D_GRAN_PAGE EQU 080H +D_DEF16 EQU 000H +D_DEF32 EQU 040H +D_CODE EQU 08H +D_DATA EQU 0 +D_X EQU 0 +D_RX EQU 02H +D_C EQU 04H +D_R EQU 0 +D_W EQU 02H +D_ED EQU 04H +D_ACCESSED EQU 1 +RW_DATA_TYPE EQU (D_PRES+D_SEG+D_DATA+D_W) +R_DATA_TYPE EQU (D_PRES+D_SEG+D_DATA+D_R) +CODE_TYPE EQU (D_PRES+D_SEG+D_CODE+D_RX) +D_PAGE32 EQU (D_GRAN_PAGE+D_DEF32) +SELECTOR_MASK EQU 0FFF8H +SEL_LOW_MASK EQU 0F8H +TABLE_MASK EQU 04H +RPL_MASK EQU 03H +RPL_CLR EQU (NOT RPL_MASK) +IVT_ROM_DATA_SIZE EQU 500H +endif diff --git a/it/VSound/VXD/VSOUND.ASM b/it/VSound/VXD/VSOUND.ASM new file mode 100644 index 0000000..9d0007e --- /dev/null +++ b/it/VSound/VXD/VSOUND.ASM @@ -0,0 +1,679 @@ +PAGE 58,132 + + .386p + +; +; Client has: +; States -> state is set by writing to port +; data is retrieved by reading from port +; +; State 0: Get Identification "ITVXDDRV" +; State 1: Get Server string (64 bytes) +; State 2: Get buffer used +; State 3: Reset Client +; State 4: Get debug value +; State 5: Get TSC +; +; +; Server interface: +; Write 0 to reset +; If read, returns "ITSERVER", else 01h if Server has been validated. +; Needs to receive "ITSERVER" to validate. +; If validated, receives server string of max 64 bytes, no 0 permitted. +; + + + .XLIST + INCLUDE VMM.Inc + INCLUDE Debug.Inc + INCLUDE Shell.inc + .LIST + + VSound_Client_Address EQU 400h + VSound_Server_Address EQU 401h + VSound_Data_Address EQU 402h + + VSOUND_CLIENTSTATES EQU 7 + VSOUND_BUFFERSIZE EQU (64*1024) + +;****************************************************************************** +; V I R T U A L D E V I C E D E C L A R A T I O N +;****************************************************************************** + +Declare_Virtual_Device VSOUND, 1, 0, VSOUND_Control, Undefined_Device_ID ,,, + +;****************************************************************************** +; L O C A L D A T A +;****************************************************************************** + + +VxD_LOCKED_DATA_SEG + +VSound_Data DB VSOUND_BUFFERSIZE Dup (0) +VSound_HeadPointer DD 0 +VSound_TailPointer DD 0 + +VSound_Client DD 0 +VSound_Server DD 0 +VSound_ClientCallback DD 0 + +VSound_ID DB "ITVXDDRV" +VSound_State DD 0 +VSound_BufferUsed DD 0 +VSound_StatePos DD 0 + +VSound_ServerID DB "ITSERVER" +VSound_ServerInPos DD 0 +VSound_ServerOutPos DD 0 +VSound_ServerValid DD 0 + +VSound_DebugValue DD 0 +VSound_TimeStamp1 DD 0 +VSound_TimeStamp2 DD 0 + +VSound_InTable DD Offset32 VSound_Identification + DD Offset32 VSound_GetServerString + DD Offset32 VSound_GetBufferUsed + DD Offset32 VSound_GetDebugValue + DD Offset32 VSound_Get0 + DD Offset32 VSound_GetDebugValue + DD Offset32 VSound_GetTSC + +VSound_OutTable DD Offset32 VSound_Out_ResetStatePos + DD Offset32 VSound_Out_ResetStatePos + DD Offset32 VSound_Out_GetBufferUsed + DD Offset32 VSound_Out_ResetClient + DD Offset32 VSound_Out_SetCallbackAddress + DD Offset32 VSound_Out_ResetStatePos + DD Offset32 VSound_Out_GetTSC + +VSound_ServerString DB 64 Dup (0) + +VxD_LOCKED_DATA_ENDS + + +;****************************************************************************** +; I N I T I A L I Z A T I O N C O D E +;****************************************************************************** + +VxD_IDATA_SEG + +Begin_Vxd_IO_Table IO_Table + Vxd_IO VSound_Client_Address, VSound_Client_Hook + Vxd_IO VSound_Server_Address, VSound_Server_Hook + Vxd_IO VSound_Data_Address, VSound_Data_Hook +End_Vxd_IO_Table IO_Table + +VxD_IDATA_ENDS + +VxD_ICODE_SEG + + +;****************************************************************************** +; +; VSOUND_Device_Init +; +; DESCRIPTION: +; +; This routine is called during Windows startup. It needs to +; install the I/O handler for our device, and set up the system +; VM as the default owner. +; +; +;============================================================================== + +BeginProc VSOUND_Device_Init + + Xor EAX, EAX + Mov VSound_Client, EAX ; no current owner + Mov VSound_Server, EAX ; no current owner + Mov VSound_ClientCallback, EAX ; No callback + + Mov EDI, OFFSET32 IO_Table + VMMCall Install_Mult_IO_Handlers + + Ret + +EndProc VSOUND_Device_Init + +VxD_ICODE_ENDS + + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +VxD_CODE_SEG + +;****************************************************************************** +; +; VSOUND_Destroy_VM +; +; DESCRIPTION: +; +; This routine is called when a VM is destroyed. We need to check +; to see if the VM in question is the current owner of the device. +; +;============================================================================== + +BeginProc VSOUND_Destroy_VM + + Xor EAX, EAX + + Cmp EBX, VSound_Client ; Destroying device owner? + JNE Short VDM_Client + + Mov VSound_Client, EAX + Mov VSound_ClientCallback, EAX + +VDM_Client: + Cmp EBX, VSound_Server + JNE VDM_Server + + Mov VSound_Server, EAX + Mov VSound_ServerValid, EAX + +VDM_Server: + ClC + Ret + +EndProc VSOUND_Destroy_VM + +VxD_CODE_ENDS + + +;****************************************************************************** + +VxD_LOCKED_CODE_SEG + +;****************************************************************************** +; +; VSound_Control +; +; DESCRIPTION: +; +; This is a call-back routine to handle the messages that are sent +; to VxD's to control system operation. +; +;============================================================================== +BeginProc VSound_Control + + Control_Dispatch Device_Init, VSound_Device_Init + Control_Dispatch Destroy_VM, VSound_Destroy_VM + + ClC + Ret + +EndProc VSound_Control + +VxD_LOCKED_CODE_ENDS + + +VxD_CODE_SEG + +;***************************************************************************** +; +; VSound_Client_Hook +; +; DESCRIPTION: +; +; This routine is called for every I/O access to our port. First, +; it checks to see if the VM issuing the I/O is the current owner. +; If not, it displays a dialog box so the user can decide what to +; do. +; +;***************************************************************************** + +VSound_Identification: + Pop EAX + Push ECX + Mov ECX, VSound_StatePos + + Mov AL, [VSound_ID+ECX] + Inc ECX + And ECX, 7 + Mov VSound_StatePos, ECX + + Pop ECX + Ret + +VSound_GetServerString: + Pop EAX + Push ECX + Mov ECX, VSound_StatePos + + Mov AL, [VSound_ServerString+ECX] + Inc ECX + And ECX, 63 + Mov VSound_StatePos, ECX + + Pop ECX + Ret + +VSound_GetBufferUsed: + Pop EAX + Push ECX + Mov ECX, VSound_StatePos + + Xor ECX, 1 + Mov AL, [Byte Ptr VSound_BufferUsed+ECX] + Mov VSound_StatePos, ECX + + Pop ECX + Ret + +VSound_GetTSC: + Pop EAX + Push ECX + Mov ECX, VSound_StatePos + + Mov AL, [Byte Ptr VSound_TimeStamp1+ECX] + Inc ECX + And ECX, 7 + + Mov VSound_StatePos, ECX + + Pop ECX + Ret + +VSound_Get0: + Xor AL, AL + + Pop ECX + Ret + +VSound_GetDebugValue: + Pop EAX + Push ECX + Mov ECX, VSound_StatePos + + Mov AL, [Byte Ptr VSound_DebugValue+ECX] + Inc ECX + And ECX, 3 + + Mov VSound_StatePos, ECX + + Pop ECX + Ret + +BeginProc VSound_Client_Hook + +;--------------------------------------------------------------------- +; Resolve Contention +;--------------------------------------------------------------------- + + Push EAX + + Mov EAX, VSound_Client + + Cmp VSound_ServerValid, 0 + JE NoValidServer + + Cmp EAX, EBX ; Is the request from the + JE Process_IO ; current owner? + + Test EAX, EAX ; Was there a previous owner? + JZ New_Owner + +NoValidServer: + Pop EAX + + Dispatch_Byte_IO Fall_Through, + + Mov AL, 80h + +Blocked_IO: + Ret + +New_Owner: + Mov VSound_Client, EBX + Mov VSound_ClientCallback, 0 + +Process_IO: + Pop EAX + + Dispatch_Byte_IO Fall_Through, + + Push EAX + Mov EAX, VSound_State + Cmp EAX, VSOUND_CLIENTSTATES + JAE VSound_Unknown + + Jmp [VSound_InTable+EAX*4] + +VSound_Unknown: + Pop EAX + Xor AL, AL + Ret + +VSound_Out: + Push EAX + Mov Byte Ptr VSound_State, AL + And EAX, 0FFh + + Cmp EAX, VSOUND_CLIENTSTATES + JAE VSound_Out_Nothing + + Jmp [VSound_OutTable+EAX*4] + +VSound_Out_GetTSC: + DB 0Fh + DB 31h ; RdTSC + Mov VSound_TimeStamp1, EAX + Mov VSound_TimeStamp2, EDX + Jmp VSound_Out_ResetStatePos + +VSound_Out_GetBufferUsed: + Mov EAX, VSound_TailPointer + Sub EAX, VSound_HeadPointer + And EAX, VSOUND_BUFFERSIZE-1 + Mov VSound_BufferUsed, EAX + +VSound_Out_ResetStatePos: + Mov VSound_StatePos, 0 + +VSound_Out_Nothing: + Pop EAX + Ret + +VSound_Out_ResetClient: + Xor EAX, EAX + Mov VSound_Client, EAX + Mov VSound_ClientCallback, EAX + + Pop EAX + + Ret + +VSound_Out_SetCallbackAddress: + Mov AX, [EBP+CLIENT_REG_STRUC.CLIENT_CS] + ShL EAX, 16 + Mov AX, [EBP+CLIENT_REG_STRUC.CLIENT_BX] + + Mov VSound_ClientCallback, EAX + + Pop EAX + Ret + +EndProc VSound_Client_Hook + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;-------------------------------------------------------------------- + +BeginProc VSound_Server_Hook + + Push EAX + + Mov EAX, VSound_Server + + Cmp EAX, EBX ; Is the request from the + JE Process_Server_IO ; current owner? + + Test EAX, EAX ; Was there a previous owner? + JZ New_Server + + Pop EAX + + Dispatch_Byte_IO Fall_Through, + + Mov AL, 80h + +Server_Blocked_IO: + Ret + +New_Server: + Mov VSound_Server, EBX + +Process_Server_IO: + Pop EAX + + Dispatch_Byte_IO Fall_Through, + + Cmp VSound_ServerValid, 1 + JE VSound_Server_Validated + + Mov ECX, VSound_ServerInPos + Mov AL, [VSound_ServerID+ECX] + Inc ECX + And ECX, 7 + Mov VSound_ServerInPos, ECX + Ret + +VSound_Server_Validated: + Mov ECX, VSound_Client + Add ECX, 0FFFFFFFFh + SBB AL, AL ; Returns 0 if not connected, 0FFh if connected + Ret + +VSound_Server_Out: + Test AL, AL ; Reset? + JZ VSound_Server_Reset + + Mov ECX, VSound_ServerOutPos + + Cmp VSound_ServerValid, 1 + JE VSound_ReceiveServerString + + Cmp [VSound_ServerID+ECX], AL + JE VSound_ValidByte + + Mov VSound_ServerOutPos, 0 + Ret + +VSound_ValidByte: + Inc ECX + And ECX, 7 + Mov VSound_ServerOutPos, ECX + JNZ VSound_ServerNotValidated + + Mov VSound_ServerValid, 1 + +VSound_ServerNotValidated: + Ret + +VSound_ReceiveServerString: + Mov [VSound_ServerString+ECX], AL + Inc ECX + And ECX, 63 + Mov VSound_ServerOutPos, ECX + Ret + +VSound_Server_Reset: + Xor ECX, ECX + Mov VSound_Server, ECX + Mov VSound_ServerValid, ECX + Mov VSound_ServerInPos, ECX + Mov VSound_ServerOutPos, ECX + + Ret + +EndProc VSound_Server_Hook + +;--------------------------------------------------------------------- + +BeginProc VSound_Data_Hook + + Cmp EBX, VSound_Server + JE VSound_Data_Server + + Cmp EBX, VSound_Client + JE VSound_Data_Client + + Ret + +VSound_Data_Client: + Cmp CX, String_IO or Rep_IO or Byte_Output + JNE Data_Client_Simulate + + PushAD + Push ES + PushF + + ClI + + Push DS + Pop ES + + ShR ECX, 16 ; ECX = segment. + Mov EAX, [EBP+CLIENT_REG_STRUC.CLIENT_ECX] + + ShL ECX, 4 + Mov ESI, [EBP+CLIENT_REG_STRUC.CLIENT_ESI] + + And ESI, 0FFFFh + Mov EDI, VSound_TailPointer + + Add ESI, ECX ; ESI = data source. + And EAX, 0FFFFh ; EAX = byte count + + Test EAX, 3 ; Must be multiple of 4 bytes + JNZ VSound_DataClientExit + + LEA EDX, [EDI+EAX] + Add EDI, Offset VSound_Data + + Cmp EDX, VSOUND_BUFFERSIZE + JB VSound_DataClient1 + + Mov ECX, VSOUND_BUFFERSIZE + LEA EAX, [EDX-VSOUND_BUFFERSIZE] + + Sub ECX, VSound_TailPointer + ShR ECX, 2 + + Rep MovsD + + Mov EDI, Offset VSound_Data + +VSound_DataClient1: + ShR EAX, 2 + And EDX, VSOUND_BUFFERSIZE-1 + + Mov ECX, EAX + Mov VSound_TailPointer, EDX + + Rep MovsD + +VSound_DataClientExit: + PopF + Pop ES + PopAD + +Data_Client_Simulate: + Ret + +VSound_Data_Server: + +; +; The server will only receive data if: +; 1) A Rep InsB instruction is used. No other instruction will work +; 2) The ECX count is a multiple of 4 +; 3) The ECX count must be less than BUFFERSIZE + + Cmp CX, String_IO or Rep_IO or Addr_32_IO or Byte_Input + JNE Data_Server_Simulate + + PushAD + Push ES + PushF + + ClI + + ShR ECX, 16 + Mov ES, CX + + Mov EAX, [EBP+CLIENT_REG_STRUC.CLIENT_ECX] + Mov EDI, [EBP+CLIENT_REG_STRUC.CLIENT_EDI] + + Test EAX, 3 + JNZ VSound_DataServerExit + + Cmp EAX, VSOUND_BUFFERSIZE + JAE VSound_DataServerExit + +; Want minimum of bytes available and bytes requested + Mov ESI, VSound_HeadPointer + Mov EBX, VSound_TailPointer + + Sub EBX, ESI + And EBX, VSOUND_BUFFERSIZE-1 ; EBX = bytes available + ; EAX = bytes requested + Cmp EBX, EAX + JB VSound_DataServer1 + + Mov EBX, EAX + +VSound_DataServer1: ; EBX = bytes to transfer + Sub EAX, EBX ; EAX = bytes to zero + LEA EDX, [ESI+EBX] + + ShR EBX, 2 ; EBX = dwords to transfer + Add ESI, Offset VSound_Data + + Cmp EDX, VSOUND_BUFFERSIZE ; Does it span the buffer boundary? + JB VSound_DataServer2 + + LEA EBX, [EDX-VSOUND_BUFFERSIZE] + Mov ECX, VSOUND_BUFFERSIZE + + ShR EBX, 2 + Sub ECX, VSound_HeadPointer + + ShR ECX, 2 + + Rep MovsD + + Mov ESI, Offset VSound_Data + +VSound_DataServer2: + ShR EAX, 2 + Mov ECX, EBX + Rep MovsD + + Mov ECX, EAX + And EDX, VSOUND_BUFFERSIZE-1 + + Xor EAX, EAX + Mov VSound_HeadPointer, EDX + + Rep StosD + +; ECX = 0 + Mov EBX, VSound_Client + Cmp VSound_ClientCallback, ECX + JE VSound_DataServerExit + Test EBX, EBX + JZ VSound_DataServerExit + + Mov EBP, [EBX+CB_S.CB_Client_Pointer] + + VMMCall Set_Execution_Focus + JC VSound_DataServerExit + + Push_Client_State + + VMMCall Begin_Nest_V86_Exec + + MovZX EDX, Word Ptr [VSound_ClientCallback] + MovZX ECX, Word Ptr [VSound_ClientCallback+2] + VMMCall Simulate_Far_Call + VMMCall Resume_Exec + + VMMCall End_Nest_Exec + + Pop_Client_State + +VSound_DataServerExit: + PopF + Pop ES + PopAD + +Data_Server_Simulate: + Ret + +EndProc VSound_Data_Hook + +;--------------------------------------------------------------------- + +VxD_CODE_ENDS + + + END diff --git a/it/VSound/VXD/VSOUND.DEF b/it/VSound/VXD/VSOUND.DEF new file mode 100644 index 0000000..ca8329d --- /dev/null +++ b/it/VSound/VXD/VSOUND.DEF @@ -0,0 +1,38 @@ +;**************************************************************************** +; * +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY * +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR * +; PURPOSE. * +; * +; Copyright (C) 1993-95 Microsoft Corporation. All Rights Reserved. * +; * +;**************************************************************************** + +VXD VSOUND + +DESCRIPTION 'VSOUND Impulse Tracker Virtual Soundcard driver for for Microsoft Windows' + +SEGMENTS + _LPTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE + _LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE + _LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE + _TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE + _DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE + CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE + _TLS CLASS 'LCODE' PRELOAD NONDISCARDABLE + _BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE + _ITEXT CLASS 'ICODE' DISCARDABLE + _IDATA CLASS 'ICODE' DISCARDABLE + _PTEXT CLASS 'PCODE' NONDISCARDABLE + _PDATA CLASS 'PDATA' NONDISCARDABLE SHARED + _STEXT CLASS 'SCODE' RESIDENT + _SDATA CLASS 'SCODE' RESIDENT + _DBOSTART CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING + _DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING + _DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING + _16ICODE CLASS '16ICODE' PRELOAD DISCARDABLE + _RCODE CLASS 'RCODE' + +EXPORTS + VSOUND_DDB @1 diff --git a/it/WAVSWITC.INC b/it/WAVSWITC.INC new file mode 100644 index 0000000..c3512e9 --- /dev/null +++ b/it/WAVSWITC.INC @@ -0,0 +1,22 @@ + +REGISTERED = 1 + +VOLUMERAMP = 1 +DOUBLEVOLUME = 0 +DITHEROUTPUT = 1 + +USECLICKFADETHRESHHOLD= 0 +CLICKFADETHRESHHOLD = 4096 + +RAMPSPEED = 8 +RAMPCOMPENSATE = 255 + +CUBICINTERPOLATION = 1 +QUADRATICINTERPOLATION = 0 +LINEARINTERPOLATION = 0 +POINTSAMPLED = 0 + +INTELOPTIMISED = 0 + +FileID DW 0 + diff --git a/it/sch.it b/it/sch.it new file mode 100644 index 0000000000000000000000000000000000000000..3bb0c9fa0b9ea2d6c6c232602229b91d345634c7 GIT binary patch literal 46472 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

DFzmaVEAJLJ;&oEZ_{ zR~)U__0Rps4}P(x_x7^yeiJ;r-7YR`{@ZkAVe_-c0s~KbRe$-&)2p-}PfX7$e!=tG z%S7{tdzQK?wDs+8g1Yf9^)mO-FD@TFDgK~k-q(LM9r@Y6{KqRLNt?deAGqoBH5d0+ z9C$vnX4sDWA-|pFMhssz({kV5(=p-a*Tz4peZu|eR~2gh*XP{tJW+T${P@4-s>>Fy z%IK4Gr9S7C^2D&Lpq|HS)@x3G__)4e^he~uq&1rRV};c{{&sP6;vZW#b=$Y};djTC znfK}Ycpm+^V2W=@`M~Ejuk`%7N6VbA&#oF5&^>F0=Is#&ew}kF;oHJ{G>;sbuUJx^ z-@7)PnSTDw(hWO>)$7+(e*5*&N~hd}31_ZR8h}Up~ z_ig*#cBeXzBbn_{h!STTMU<{ zoPHoc<2SzhhSX2TRx(9{27VelY0i|M@BSiq^;rK-mPTm&OBrGu+i-E@Lzz>?4yg-x z=)1v#Vp<12Gp1XQvI=2jp6}Tm&F4G^dX$A62|0E6*C+aidwlRWLt5DWvnyZOlQysq zDGBjoF1}p-d&0So`YwL%r7Yp$XYUB_?Hg|W_=$=9=ugK~RuAwE=hJiYe-^6DC!Y!2 zzn#1EWzFYr!V~g$ZBgD9_2jm*Q~Q(ELHxPJFLsa9zVh-R-<9`G`7kVS0a$o%JHM6_zTekawz~-}G`1<_$z3R}(!=}eu`Sd%^t|qr` ze&e&sfmb$dSasx~!V~-TPxc=lx!1R{_{fRJUiSNO(z2ibic{U%<4BK7m2-~7ytg4{ z{*KQlKP~+Ij@X?mGoJmaiSztxou$Ausq&uIcRr}&kH6oi=dpR;7wz%Uj-IGJeIoO| zh=-0n-`xGS2bO*Jf$8)g+vdAndO6>`bn>ZPN9LSN()7Ep(XVL#70!I-zJLGw;NAs+ z&;B;`kq?!R{;haW?}7TX^}}vkxAelYuuGG^4d1Vd&pmnT(L*KElsmrmdUZhMgMDjM zM-B~Bm~?Ksm&dE2X!|sO3e)Y|$9li2x#M;1sn(;l{-1qDBFhb*1bq`RINvkirQRT4XYG3j{vPqx6fjw4azWwa!lb2Zb;g+AXyIFpS{fBaq?>xhi{;%k!L_h!S zU{lTDzt4Q&MK0peWqrzHW?#7X&bvL*-t?KYF1LG0^RS~#pI1soY9iPui|{MF;hu}=#A-S@wLNPuqRk!|$8%7Z-(|A9?Qi$HyKPO7m{tz2)w+Y5DVO zKh?7b{%E2;{Gr9sA`_58JxKI zqsWu3ONN8lg5KWz_@7Vfi_a>emwy%bb?)28{^~Yw-qFEFwjPXKl*EQy8JzeS`%^)_ zu)5daBUx#8ni?OwBd+qy=_A(Lf8WPs?$pmZ?Yn#K$XC5iZA-YTPgR^pzhC;5KQvTp zsyTV!iLu(8FZq!2gyTMS1D0(#_HOWcYrz*a`oE7~HFR8$5l{Yfc*B-IO_kq;u6bGT zXLq)A+x`77Zs9+A_$N*#&#h{>M@VX&JiF(^jnD4`aw~i0ePXu89e(1K!A0>0H7gcf zX2YXHlhVdE^uOd$s4)f4Th>&Xp4>m{;7?yX?$u8nmvo@pvcukI{@!n2&zj#`xhp#} zKltR{)80MmEBKKwY8c-#^`=L%ANp|gx$R*QzXTn;ZRo|HHg0?@_MA2_Ho2-S?#n~u z6VCn7_z>RD>(7cun|0eqgnL=|ZRNQitiL^OdXvw4mwexNXUi_Hm;Vu0_4c$czcOq# zT<(2hCG%H#!>*SrFInQw1+CIOur6-$pig?#g?=}n-#E{LSKj?CHu0f#abM-Pv{e0T zi|U@%yYg3lzTu-WvjbLb`|3dOnl;~A-?>M5d%(UG@9lqFb81aI8$5>m(GsFM{@Kq< zPQ0?@ +#include + +/* x86 memory map + 0x00000 - 0x003FF IVT 0x400 + 0x00400 - 0x9FFFF FREE 0x9FC00 + 0xA0000 - 0xBFFFF VGA 0x20000 + 0xC0000 - 0xFFFFF FREE 0x40000 + + total freemem - 0xDFC00 - 916480 bytes/895.0K +*/ + +typedef struct { // pointer into program data into which load segment is added + uint16_t offset, + segment; +} __attribute__((packed)) reloc; + +typedef struct { // no endian checks - this will only work on x86+vm anyway + uint16_t mz, + bytes, + pages, + relsz, + len, + minalloc, // can easily ignore - we have 895k free + maxalloc, + ss, + sp, + sum, + ip, + cs, + rel, // pointer to + overlay; // zero if main binary + reloc r[]; +} __attribute__((packed)) mz; + +typedef struct { + uint16_t ss, sp, ip, cs; +} mz_start; + +#define m8 ((uint8_t*)m) // access mz by byte +uint32_t loadmz(mz* m, uint8_t* mem, uint32_t seg, mz_start* m) { + + uint32_t sz = (((uint32_t)m->pages) << 9) + m->bytes; + memcpy( // copy mz to memory + mem + (seg << 4), + m8 + (m->len << 4), + sz + ); + + for(int i = 0; i < m->relsz; i++) *(uint16_t*)( + m8 + + (seg << 4) + + ((uint32_t)m->r[i].segment << 4) + + (uint32_t)m->r[i].offset + ) += seg; + + *m = (mz_start) { + m->ss+seg, + m->sp, + m->ip, + m->cs+seg + }; +} diff --git a/r.bat b/r.bat new file mode 100644 index 0000000..6ccf214 --- /dev/null +++ b/r.bat @@ -0,0 +1 @@ +PATH=%PATH%;C:\TASM diff --git a/tasm/32RTM.EXE b/tasm/32RTM.EXE new file mode 100644 index 0000000000000000000000000000000000000000..94e106b7219c64c4498c4df11b826176d51393fb GIT binary patch literal 152108 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

H??)EwpT{Gs9%BQP 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 z zX){82``1aGj&v9(d^J)JGm#!eq~km?!thT|vPjR9Wrust;g8>7qa}&-J9zsiNGC*K z9g0+wE6&7W(~&X>NfmnEJXkFRAP;#u^9F73c!bbqQ(RCGOAhE_gZ_!<5?Ekt9M6H-xv)M6D1^|kvU z;!b7whsGuIVB@V$a>6M}=A%?LHQEp%V{f`ZCIbYyY+lp#)fiyzv~&iTj`#n+Fu>uN?+RZC7AI$G_5GB1 z!R!)hKvs#$QqrX?MY@!Uuqval66sPV(xnV~M95QA=JY&7hc|>-RA%=)bPO-plZOJ$ z@JQfP7_%;J+(3DsiJ+)=Dg(bx{D!7k>K*DMRmke8;Qucb8%!;>7B9wbXaHk`i`0MI z^VCyR2=^V21U}~JHAHEl@A&K*`8uMXuBYorQl+JOr5|1a0 zN&Kp$jN$acckwWtRlK^%NUCj}yQWDx<4kN>EynyUaYHXGdc)S~4p zL~ygW#lboYy9!T4?Y1u4iNpJPGDmV2L83yW<4z?!2jh7J41r<7iTOUG4ZMPEpomRA zA499K8KyYvq4=X(U`m-)$f&44CCO!-bh3y7SUU7Uwq>G%RG7xOr5gPS)< zu@gW2Ml2TJB~Oe;M*#1Ovm7(Cpb+^(BW?cJ+%@xOv^$MilPQC=39T31@wxL+yBE&+ z;FC8~Yi6qU3GY5@ae)bJp}iT;!tz2w)@Lmch>Wv8i_-@Qxt>GU5$HqMn$epsZM}fPo zoiOte=(}CAx`#(=o~3O*0&FMvT+pp*hz+a| zTmt3lGh!@)W?v`}v z0!`oTzXhm=x(obv;u7pWzwTmek6#$<&hop9J!^&*5AzQ$KIk8aXFoh0O$UNIN=21A z*gd_bf3SOTT|Z=S$R>QS`_>w7u=}36Y(!-?+~K_oJXU-#kl8TDOOg~{?OFFZiVb$> z_)A#Ce_615yk{LZM}yr{l;@)0j`7Cd&fkA9zzuOH=R#EaiDUSpO9go~f9b2dG^3H8m| z6BrJY!Wwt*^y0eAroF+V2crm&ugMIao>FIR+FN{0ox|`UWAV*3lZ&6OofvGH_;cXz zzgPvZ1EB&|Tw*gE>7oOT(R^eZSMWhv9)yDPK`;b1=Hj)#x#s-hM`}F9kNUHVp8|ap zQ7*f=DL4txweXz&*kOmGkm@Y++yvX~E+_@@y0a10RgpS-&zon#YT}3d3xKAXrXFfR#}u=~PaSF$T4yFj#`*$GmhS4Zk$;%fN8 zT`O>SILLSug16Fm8^3t{F1ekiPp_%>hWPG15VC^q8G$QP5lX9yAjA@xFr`E#6?P-4 z)4@YD_7uskKN%@ZHe&+ z7s^oAVH*t&?Q%7oeVJRAjyG6LSWrx~O|mXX9`nQh0_LL4QVvgwnguwPurdEI9%x|R zfH8eR?!F1wx93|v-iGa)z=K~B1U9<$q5}LQ@Eo_|l+72%v(M2$=`n56B&lh5ok%hb zFtYkzlr2^TW;ZCEJnZ`&cSREiVG-Y{RYM_Mc|h1cp7YuhtA?5HFUfn)s-XGaEbm>b z)|v1Bj(3{%EjytVE;|L)MN2*Qg0Tx}Th?_Tn*DodF8?-r(W#<_o}EjM6U$4+Oy% z9UQ0AyLF;Y70E*FIIKNR4=qu&IB`Ca;5M>|xn<5yV;l+En8_N>v}CVQ;q9j=tXc*$1>iF`hAJ~1G*JU~`mNEz!#_j1jl)^m z_8osFP;6{(i^ck9?wc?oQ)}_y4Q##LOAueM$b%2$w3ERqyko(M!(!}g@ZbQGW%Lvn z#^?*qCL&ynz!!90OaTbp@dmexIehc1Kmt5$P?qsftX4D$WVD-=8=`Uvr7WQ_6g+=x zzh#6ISBf$Ymvi!gIub7C266%smIDlRFhSUQ2}M&;3B{EEO1%@;Cqp{mrPlF=NT1G3 z?1JY*M&U7lbMP>x%Hi3VWmh?IX&by#hB1o{&p|{rlzChYF(q5xB#3WKcd<2U|4<1WwrZGTw*c z`6B-P0KRvAzum>&$aRhTBMY|T=7LqYzLYK#T*hCc)ZuFKZIR3jfOShz zr2fSTd&CCc??P>c`K>s=(ov`b%&Z^K4jj`8cOd->5#NhYt_{3ECk}^=XV71@kZ-FM z^Z^(@4`ZdDned9yeW00uDN2^#UYrxKZMDpVI*|W-mJv7@ygydpKR)~V>^*@~+pzm! zv2{oP@D+-^lEub+TSI5;HIH=oU~$278YtVlW4`C;S_fM9zUQQhj(#N6RzWHXkBrZ8 zn-6Q0riZilfWcWso2uB&kGu7O6IzRw4fA}z6*Yt|DlQZ~Z1DI2_tUs6mJQbp-#oKu z*>h`JBEDVFU(FC2+`--5`dt}*7k;h&<%OOjiASUG#2>{mX9)q1(fUo&YU9_r=H!G4j;|5MNRtV{ACFpz zM2Hflw&cVC2_S7@;VJRK$rq{wrSSR>KfqZiBY5rjn%v;EQ|dgNyBum75PuEt0)nB_7y*RZPCaWc4zjZQ99Vv=upX>Wtm-iDZO6IzppoHD+nUhKS7 zy+=959t_uV>Wpz88-I+V{yL|>$npDJoBY6Ol~IU zCpp-hl7N`$f1PdYtGFerjT4_he~depU{oHZ(M-OzMlB78P9PBK_F}HxJsv*suy7p; z3sL_tS?foK3UsXT2_vdBz@rXvLL-Z3*ceo}#k4H0cTef%G6p?E*G}=e!*vAPU$pOG zsDYB1=5IesO~V-H%fbfzOeITRX(oLPb;E&`c>4hd$rSyyEon)4ktKASu$$aR+Vj3B zEieI3n!M>UhQb&`U|`8dMbUaUujUGZcxAgXH|#3U$lyD=E>;>!No)=~_guqYg*EC0 z#*{lLh8%bBcQ}3{^0{)Z@wbH-IAHh4>}VAKC2-yao8o+xV6HI{`K8XHh3ZDN%>Xl$ zBE!Wh!w@oXxm6ikq8q@0Hzw#Q=~c14m#w`{mWPP*6!&3vd4@xoC2l2$1UkS7Iu}@Q2_0TI+rU@jn>=fFYRP8a&`;{za zA{EEy!bp7YF5d9wwV;ha1Kcp7@q!LS(&}Kov zBIQr!<8R)uFT*l#?#nB+W(^_Z{L!F%Gb6Qd-Z%K@aC{AqZ$riAKE5_DR*}o`K++D! zw-J!}>^&-w?tR9w8nJMIdZp2JVJtQsj``-Uw$C#>c!9T4oc7UM>4LLuhwZiRgGGzGXs?Z}Fipzny`v zhGexd3_w~6FyolJ`hrU1PN1^Yx_t)Tx2;1ZMG|kdZ{M{y9?=3hyw$mVCsSB~hVe5- zWNx4J79+qi;t&NmD-qP>a}@_`a>Z*4r<$&&;LhFZ-cY#Ob{5}L2Y1`?QLzu{YYpnJHd1b-IFOWYDt^ZUh z)1ReeMe(h*pQo+ZjBq@0Q*alGoa)F#b!%Kx9R+x<89dc-vH8yD8go}R9Yooeg1D#` z2!Q+?1+j=2o_&KniC!jEz=mRlTcOqzCW3`+foUXVg?nn7e=-M_hfq95XP5B+0*ml{ z1Y^0~AhBFsFPiFe`?IH3xctt-Hi}(RL#a_48~%l&xalT9&rdC?Bpy34Uer()nVR{a~kl;K0!XM|(~_rSA%GN`*SOG?T)|vs+SO*OCRczoLrrU#bH0XCCUEnpw z{Ib|t_Yz|4QMfR{Mgn&&iSv2DIS=1|fE@pxiud8!GV#!gHjKxTW6cn)Py!nKp=u@Y zVS2=~{uXc%m#U>K8;g3Uu^r^!QhY^Vrm+REV+zpA-@fF;7b{y)J$ zud-o{zaZ*I(w3cPq$tqCOHlSs6dE0_fc!KCNTEXz zW)kBz$#Pj>Mwzh?!8h|6c>tlB@kY7%?V>WHnBQ0{;}w3(&uwcaw$J+=n?>l&E z&HLr|UHl3T^EVTvAH8ZRYrn8F+I$0GhVy3QcQczO5kF7js~ArzB;prK{Bry%GaIa6 zFz$y+SU4RYv#zpqz`bD0TyLnSaME}V_5%4&pIv!)qADC=L-UzQ3Jc9=Af(ID|= zjsY+bVjJ{qD+GckpEB-5=aYn{T*j0W{uRCtjX+u&r6r{=0`a5rFhsfp>JXEbZz=K_ zgAuEIxWV_6LmD{~#}MZ`*wUO$nl0uZP9Sj2_o@l*5@h7YyqEXVUY5WLmXeu;4q=K+ z9IBu1AZGwhuLQy!Dgjv}JpoSuP%j?l7;Df+;`rH;_zn6Z{I+a2@#ARz1^C&L_zmh4 zKbs?g-ylaH_+iY3-|&hqS!e&dl-MtvQ&5?Ka7t^kl^ z`4lack_AmJfAkHfY}9dW%i`BiE9GtKWAgVL*_@n@PCfEbXgd-*f+?f!6gD@ZE z%PhW(fi;iHNI{aCF;qV+A5Pe@=4h&(OviBx4r9;bm}Qu8b_i$u=UQfr!q$44ze!Ky zR%C~j25jS>M#$KSoW0!DEkP8xwP}Tvk?Nf87MJmTmh`VUr}H#k!g7`p=%@O!d^p96 z%(jbPyyn52IV$DKymiPg4S7*#K zrb~R2Z*TDlb+>kLm;YYMisEknyy70eulOJS$;D^=g~f22hnvpXoKXsshI?~mZPyQx z*bK5nXCuJRQ6B=_Op6vHz}>Ov1O)mqFgA3r*W+gvG@&JWJ_2mQ=s*O}!j>pMq3v<| z1n#uKrWZ8i^YJPyCEJ1pX<_4Hpx>);-pGUJvp!qqG`{?cEwhR1pdHAke=0=F5Tdym zQJ+6yPq2P3_;Cp8fKY~K{cnIPLRQcE1{KQm&%}E_zvE~=AcflUizm(;GNa{@%auC~k@Vj@aQ`qlvR+TcfJ=@KGOUP^09Tye2Vba zxcq5`FNF&+|ZGEi6rS&;}i^1@^wj4VX!aAN0vLc#;q!! zeC)eC7SDWmrj)lqd;7w(_GYvSS-v-pW}Xxr`=oB)!tBdpv1^qk_*7cB z08fie?KXWwLk9ls#y`y0{20cXgZx>KpAJWOKPv#38yI&VeB^#~n zICAr!DemX*oZUYAABmTq&@QWdvKRLY;1dS39(@ui@+N6hbQYJG2r`B5=(`F#E)}qH ziSSd4WNj-&2njD2Vv@>90>2?ZqymBSjD8qUA^W@yXBi#1lj0b{uO08GG_1}kI2f_T zJoEaM{!YVDroBF#L%=u&n^>fvAT1=NAHx45B;6O9KMHh9>H&6sOR`v!pThRq8U9jkZ((}dftuFh)U=Nn+!Jd2S zY{8ue%gd(j3=BH_2VB8udd>nIGP(ea?>`v3FrPzH$njICguN>xaEzNhO{&HJD07*3 za-d**U*%9{;_Nq)$v;X3tbso=H>}JF_TA)62p6$XzL`j{K63an%ov3EGLn9chiRVm z8}NYuRtSK=O}t#iv;ISgOf&&3oa`}dypLqX!m(vfhhUUbH9d+u-- zyhlgMV=xRk>cl6dHtl|cEV~U5Ex4KBEIfzH?hHMghmKm4GAa7AB;YnA4xPbh`WgZ# z;cSl)5wrsr$BFidY7*5vg1}H906Yc(iRk_WCegL%I?y83o{yBD1!iL38!ySf1f}>F zs}fBAg5%>9HjAZel2SsF zM#(kqKP`yF}vkLRMj3H%(eOeL_oS;ss{nnXdiiUN{oe-1A`=mWVB|3wadN%-+dJ%p;BFPut; z49ZOg_*MTPKGvv%sVxf9KtgJV>lz9jW$MZ!P1%%n)1l-14%sfcyXG!9pQraE|H^OP z-O)(jTH{8K9=)rP65pcslw@3`>#B@ZfL2;*yu49H)zs|D<0+B&p2lT}QmtU~tglSGWGLhZgC)UHd9har%G?k2tPesOM}MIt!6D=^Kfj=0 zuD=zZjk72-UQA%gW)6eF$xHlm&BFY%;!JRDoC$D_heK1vBJmQJm>_X)q$T>i@oWMp zRmwc;8;P)ljt~tXtq@&dX8SE-BaK~nqf4)h|EIk#fs3-*`#&=bivtDy(38BlNc-uJ$@`~E+3;5*ORm*4rFeVe=j6^*nK_M}Rab+FyewywLEMh^U!v*XfrVsv)wMkT&cDpW0l$(!9mTWzC+a?=scyghKbZ|y9~1fg8gZg zFf3Uqepb^+R!*XuCQFT2fERMCIU{b^V5C-^l|Q@u+ViyA>6>ucsKEcv%i7@LYswm) ztdV6cMA?T!E>smhi|8qr5HGC|1kV?>qiCIdtOZmdYUC3u*sDNdkFu5}ieB(Mx~j?f zo+Q+8sYzU_Jm0``8dhqhEO_2dsAMj|3ztG?+g-gHDmNQ6;AK{-#y!3v1KxXM2K*cq z52ZHD!v#u_FO+TuqyxHSiMZ4qasvkZqx9!fSkV|63`m_tRIc=D_0V)l13IVc_N77m zW27%cXw4VBO-xm&PoPjO?OfZKS!+-uqOwm>hKjty{u#9vIil+K0kfKM&`Rn)x>RE@ zV%Csk<*PP0(MIwE4QFr=3)U$^La|70?UGdIiKyEfJp%$K~hZ$BQ-smp0La`Ft zZ3L?Y*SJsPh<+t(gi!5?mTw{0P;7dD|6&)DhuK+Avr($gn!9^IESI}`R5RgWF^asl z_DGv30TAW+qjqoJ4uIz&n&-juUPO}89fiFSfy>xyf(T?1 zTP}dMsGH{(KqgL8+is=3DMYjU-byH13L3JGN9V9Ou9f?$!bh-o1yi_mZ)pEV1q=0e zoL6@`2!{tztCB-;gCp`FP56d>JklLNSB%k#sL9Mu+o95wz3@VP#9Y1o)Mc;{27;%k z)9)cf4M_cVX^71(P~g_$;<1L}#{!BixM#pnJT%Oa$cl}QPm70Q556{Tpj)hQFnMT* z<6B3y!&sci97Ds36AcbHdMv;(7Q+v9wO9nAx%y`n)vZUO?Read3*(Bxwi`)N*rC+Ut58?rQQ~Z$Fh%NqYA~17Pf-0 zUi&IE7W&0I&w+{DE4nnTo)|O|=JQqa2aaDL^g|hhO&+&Wc#DRW?@%g&I0V5?T>ZrxzJ84E?v97XeH3xw6bAr^QBIlRJmJ!HBKTk*T{3ApzygYPSs zLe@6baV8nt+9^Wzeq@bV+wcuOh#6nBd*k>0aotb%;E1x7Yhe^*2<}jJ=mdOz71qT9 z=iE@n24(xj*sLU~{cETkB0 zBYzn;wwx>tm6irxYsremLcGAxC&e#6(h>o=0dhlrE4&|orA5f~`9XMW)6s(W3C-6# zeoSAlQxdx4?4ci0e-)>5FJ(HPEr~ZSjJrZBGrAaO99j_NXft$7t3jcZbjMNBxF3v@ z`Jlzg=Uzc9jJ9E)^P^4BuP;e3_SojAC40@Gw0z`TgMFXsxmg?rKm@Dj!mqVD zr+zI%c9ohgQ{kj*R!g?^fMW_Dw=={eqL~4_pDw0gfe5JJW!|T}ph=G;BVW3p*6D-y zBo-!K;f@gjc!uICSt*PmK$ zoG3Y3a;fCAlJ85tdQTV>oaRNR{jH(2@4X7Q_Z{L@`ztf*c#`c0JFc^^-9g8;Lvf}d z6v+rp^9wFoLQGS2uz_uy!Ew&E+pg&7ta3PPhr@PwnqOXo(5%HS<|%+8uh7H14a}a6&X`j5qE_- z`_b8vN>d%Ls^nFBc~un;-80ik8Xmsp`BMxLD?YaXIa+Y1_?FG-ig9!Re~T{#mH2~RbOSyHM+^K0q1fOP!j~(w z5R}0K_snRKM&o-Lo4%qiO>lmS&itr4C*l;Dv^|@^C%p| z_<}oXqif=V?YK!f8hr-**!0lwv16Y>v=8oUhz_;g#6#;JTj9U|n>r$-sRO zwW^gJ%IUw}pp3p#uv1J);?Kly zM}knjy^n?%oOYjTROURfKEU}E3dHw3Fir`c|2R0IdIjtV1}rt5SLf)imJBkY%32ur zGk4^pzQRt8xplgj;L^#c`H0QxW$Q7oa(P(p={i`>LobXSm$awkecD#@6tOd^|#a-0dQ(+^j08z<6R1(kda2xKlSWJX#hsuCED!8LzWTGg( z2t&%?niM-ZCOm63ri;&A}F(qwtT3mn`~dyw}@6|tF$*ogQd zHlc`3C}I4ctl7g zh)Ny=eTTx=5#+o0$9;8Gff(P1u0om+X)RK!J#FX9r4xP&I2EtnyB zrksbvHsaxsbP+5eqJd*mE+U9noD%6j0`IONLGYpyk^YRcmRopH1ttHyn*>OH#@X3Z zs<(*Pm5T_vgH+QhgLEg;9i*1R;8GeyatE4IHS-bFSxTKdIt55w#@T`~g3qvFu@-Gs zA_~Gb9<_%@?d0Kmaq{jw9%8@9`&8w1;I$Wcl%Q7a{*qK2=sm*lBw5iR!GrdL%-LIz z>5}uf_&Pg#`1>sPL2K^zkHUeUV6zMGs`C51=Dg~t=vN$}uEi0w$~Cwo_zsXdu|{i6 zP}73ozffy(ln=nEd$d^yp{Sdo}WVU|F zW$Y+XhJe_Peq=Q*Jx#fQ8Z{kHVBLfH4PHMYpvad@f)JN-wbrdunqkt+c^19QZ#%Iko`;UjpT^V4tP@l>rr2VCwbcb2dM|*_H8EWqd5V1+U6o6?$L!CLo89Z%HHXH3_&(*1-TKqxU2Sp zI-Sjjc)#N>CCg7n=vctbWJC1x%K3sSzTgvhQ*;hJi9NPbsi7)^=RZbG5A0~_M@YRD zoh>RsyQyCiRaPz9r)$PF*8a%+laYwU1{Nm{L{fVv#y%~1U^<32=?2?jXM|uqy7vct zQqP|M+iK4rEDa)+7y3|9pL-eH8IRuo{Yl2zX@x^zFuQ-@V7SB3C&ACweZ5bIE*~Iu z)*;Zt5D2GS+CYW@P=ekTYX4OaYGOpv$KQslf?15SMSh?in=k{R(BTPUNPmWuEfhqg zqD9vgwB=Fl#2_Y|#uekxr_VIx2lCoOyy%48`o43s`2NjVrdq|G%-Tct(^su8I9JkV zne%lDOYP^*X(7Hb1vgWWC}EgdaEFN6u<`KF`ZdV-LPwR1&iyy=$v{5gyn0inSL2TJ z@XYsmzEQAFloq-f0s}_JxB!roHo4+HExIks*5r*sn{Ukyoi$WnX8#hE-yW8Si^iy2 zp=cJB&zTdAoT+C8t#R8}WpyRSN(V8fI$rWs$&cVj)J{d`4COMFP0^P>)&Y?xektRd z>X~!5B!oZuTptM|+@XM)v)uVN-Whq*8ROM79);@hIIsE&ET%tVz1Ln>Z@m+Tqvu?z zJcu#UmnF(t_*o`SmWxg3;$%5anFsJ?3logv%K0W#G&mOYF%R5jZALCDzvn(>&G*bG zzTWL1Yqkba~l^TW-VtmuYn+;hzng@#ilwUB@=uNm?13 z&bNH%_CBk`G~|Zn4D3Ct_)fZXgOLHw{wg!6lWS7V**eb%5ke0T68hPOBsfC7UaMQ5soL` z69N_{8Ou?<7tyw>Ew;n2n09l+A5_)wAhVHqSF+Gm zwSkXnB~9&P$WB6IFUFOpX+emth$B9z*v}CkLa!*thvB7CSWrEH$pXLPcsxlPvH)?2 z4}tjtgb^Qx>_E+d;_xi*xg9qbSmW%+QLqo7c_;RziVH6?RPCR1!YHIRClm|QjiSOJ zYKW^T&;cn9M(IPTs=^4^wnfwu`*CcBCYo?oSKi}@j#*joVh6~D3IoBGVU&hT261fz ziapJ|1@4{`D5@{a%v2u#Sx)vDj~EZG4eHR8+9&&^AZu4NH`Z4A5k~tZgS9>Oj9?NF zZ3?CqES;Rq-qCfaG#*4{Q(q{wnv1rg?Ta%z*!yimXG>?j1(m_PHi*Oq952Qtk7Z7O zH1k&d%+nRVWP|a}#r`-WBW!C)sP2sdgLxG7`5XS~E1BaK)Pn!{+-NkdVf2Z?9kcZ} zDXZ#GD0gD_P&xgU5lb{>6$$=!=ULfX6hsL|!3o@5*qp-efEZnDO))|-!)1{1el-W| z+d}wWMKn*M7ve}lSRmjWlr8GuhEji=I-TL7!VF-2G16WxL2=N*-CG0 zYa9m_R-0*ibx3}wvD~;5iG2#5fT(lMQrhM5myH#ON z%80HUcO>0T1ub$5Rbb9|;Tc9?7}M?lSxj2d+!7+eaoq{u5<{*rGv?~Eo(*ySFe3zG z0iQA+dWeVardiPQycqK_xMxN!)O7ERKYyA!1sUb3>8`@uzc8M%ZS3{44S5$}_2p4N zIHT~x9s6XqamP1!a+-1uaYV}ZIm3{Db+;g4n<@X0&8Py(#m#Qqk&EP`IuIm?M&@F3 zSbn&12b!?Jo!o)>YuMcf|0z2aWM|C*>&=iGckrqoL>B_=d9?EI@w1+}*N1ZN7MXjf zLz-A`M}#cRogJ#Nep$a($2)#u+{S%TZ(yq*552@g5AaY-5LeGQ!k3F&y9E&!(f1%U zh+MRfWuhgc-Uy8`pQdIrAfsH45Yy5ZoWPnt3YcfxY-Fe&el|5ql@D(Em$0i^VuF*6xFK!3mH?`qZy_>wQj=n^ zVwBLt>SsJ?>*~ymUWh=V?FIhKmQvjoBsU(i1@rkkah~315AXB!^dqPngv|0~(OLi5 zL6{pLH~uw;oj21wL3A+`@$rQL(e}~3{F&wFyueF5x{A_VPp59drx+oNW|t;gX~HxE zl))l1ep1ok)Z=Rt^NnR#_bIA7Ul__Azku&VcM$zToQtan;qisdJQp;;OHMRVr}k^U@&{1&T)^#^~rCRY6K_+|#t7wQ}AJ66%wFPCa;7 zf}hv7q0d(0gMoP%6q`dCa-c{Q-| zu7QrWlttN=u!4M8E@~2Ofl1C@VS2^C9SyAg=+amZ@!l#S?x6d2d?GuLpzbhx_atjt z$uOl4{oH_IJNsZkh(tw9i)W_@877|Mo?0WM_}Lftm6T$pL(>%Bg-A9;A^G&$pG9a! zGAKM{cyNvHgOK5Fw9e1zZhe{RDaP7-et79inD;0B;I+eQHQ#*p&%&~Ss;_*5olHt1 zRT0t30<4xR%g7r)m?`H- z_BS|J_Ti^o8yZlQv6=518l?Z(G!BU{p0fOwnLtZq=PZg|FEv&QS_UHc&NTb zhAPvs{hRJr(+CY?kVqqBE-jpDW^D5-U(Gr@@u7EV1hRg9!c}XxW-C_LHPvBe5p#=Ap8_$(gH2lx^#mUl71a6UMJ=dRp8B!AenDNDN>}BhA6!%w*Y-8R zBwAh3&LAf}WL1ajN|oo}arKk<5tlU9@nI#;9V5mr&ZwJPe%IX?EM0-GeN|u8;Z1sJ z!cQxScaxR$Z>gW0rp!Nqtmt}Co$ri?rYm31xbn4?au)@I3D|xl2NR-a}HdXUQ~}^l{%~6u-}+a5YeC^OPGD0#zdYyL^*`KD#_PiPKA0HZ>=gi z7YJG|=>=LY#g7t+Ic!(%yyTfXn8fxNql=>CO3h@IinKk3ZM>UGT~A^5dimg|B8RAS zNzCZ5Q!93nY0ihNk}mhXeP(T_^y$~H?6giU#QMihhDa%u1WY&wq+x2R;cWBV%f9Pz z^4oJZ1}iAo22kg0qcsj5-8tDtpvy(w1$3JuQ5!EoB~LTCAatQq8+5B#vgI6@Zy-9; zjpv%vuxdRD6Y#jf-0_pL0`c5(;vSICa9(Rf96QpI)0B*3V96aprM9|;9#4S1()^&b z^mHWv+o00xZI|({bS3MeQf#HpM61)lwaOwyMD1}Z#E5EO%UzmjrPG5@0L~pn>BK!p zbk)%b$glN^%2nB%i47ye&r*R(0D04u$G)Kgp00EP6Dl()fHtDtE5hklWtLdj=yeV$ zoqU0kTZ8sqAx`U zYDq?&{ffbwpwGB!KjFU+SI$;B^IE|6R<~_R+S0?ck(E;AsI7^+>hqYtG7D9T(^rYb zrzGQQrL)rMOn{Nj+5%OUot)Q-z{vS%59i7Qa8WwvCr5?wNWY+Vd0KM1q97ZEKlT$k ztTgDYK0Pw(7iJn|sNc!K102etfAS2HOVj+cA!CRb`1f6l7Y+E}*-ex%(86(at!_R0 z;}noi`Ht$p2ke)0*bO#PIZjUNlLDv${NNCoEX*~kgerH`;R=1DvX!iiS%_IyEJ`^~ zDCJ0yy%4Kd5!`_ZLz-s5b7BZNL|KZ)Rytm9aOyD&)*G!lhIuiLy0tiH4xjA5;#x<_ z8(i4-rOK18gw$73<1iUKq$U-I%W6*GS#J!f&`5>EQig+Uy_fWo-n^Bz-Nm9Wy z^bJR(#oCj>KHaF3MEb5=Ear_`Ygli@L~q-YoqLp;@7@XS@U?z>&3Am`dDdYsjnRCz zb6f$5OCPba5=^ zbU$S&$}3zp$4-ueq=%Uze0+8_|ElP$UZH7Y@)vz+*uX@^K@QU;SYV{@Qoi7_cvoP=d2w4@ql*~~dawfX`k=U6x1%jl zN5F0)*Gyb%;7`?HP2@}Co|DF7{3-F>QF01H_y_nHm1x+z2r|hTGO_N12PgXBoxK6P zOJ6p-VfM_iwLKEKU6cBjD*Qh000X*s|H zt)lig&s5VGy83DS+!<1UWp3=C!x}3sepDW=E1P{*f70Dff29&(nM%JJ5F87$OYx(0 zCt6|L>e3N1X6W;A0%;6CLL@&pOYPD4k1M#P>X8zu3RzAdUp0?zCU=u{LwWzQ9U8F01z2drarscb|@x z927>_Kl=i+c2M=~PQCq#E^X|>+l_Mk$mO-P?XnvRAxKS+2L1IVQ^NZJ8td; zP3$J?d8oLJ@a~tA{qV5toR9rFYsiwkU^}WZ@&WRUP9PM<%tD>ET%5QB)dN-v=;Du#JMnp}8-HNV4o1WxJaT|(I zO$8>el%}9m&$60|5Nm*pTX;=H1SVvJO8<;AsHP&u>fgD;jcmnNc8AuY;gCTIVo($yi&#knfTZ=x+aZ}dF|swi z5#MgipA3ACN%>5hwA zV_-$GVG!Y{&1~!M*1GTHHCiXoM`>g$5S@WWT9+~D&`4_rE{#{Uv=M0I<(Km62QlKL zdc0hD2OQ(LA?vB}S-Jyo zTv&7Z%a4*p_PZ(x^tny-;%1VEtMb+)4;FG&<5Q3xZAbM{_^U-&_Tb9Pm9;QM->8qs z152o=GaPkAXM>z)G|S>$4J2V7tRe}s>C;N}JCEe*?R`kXVyGwyx9z9lH(gBTJTI=x zcUCKO>!9X}Zs3C}3w?Z*G5Ao6eBo>-lvA{iZ$M@)v%r=8N4 zKCP5H=p%`F93y}DxgQ^jNo$PvRr)zDSEp3tLNg*cyNL(55cDcAR$Wh_wg^sl$`2U^ zcdYXCq-z6<50J$$bUdA*N(6m^#B)(#g1s2nyMrDBGf<^^4tlvF=Si_2onz%C%vLlQ z(o`?S$hA5XC72(RB^yo9K~sW3Pi&!YU9QlG z7CdDv7jt(}zC>ei(k1Yd&z@u4(Ub^h|8A#IaWU!UBW}ig3q4`SWf9rx91IGCOsPkw z@R|xoH983+XM5!!eQp&NK@>Wf52D;bA73Q|A1WE2exa2N<*%wMI=l>5yXh0E?4wVR z@)Lc0g^yH5myxUL#}CW6sG;V<4$KyUu;tZjV5U3-9f#ine_C@kEJ(nzGA(T{NWijk zfCq2v1}TLXMCNpiX)ECIJzehW716!>{oU`rzk9EU zo;`*q4Ty~!710IKi1FFhh#Yg)L=#S=nk^B@aS=Q_$CT$8y<2Bdm)gA|zVTC)2O z2I>vUO93whycFUHL& zfR_SZ3V12trGS?LUJ7_A;H7|<0$vJuDd44mmjYf2{C`P-KQUH@8!zZ-H9RT7>^Qkt zhLbR5Z2-ChkB-35;X%4Ifo?ItsbD;J&&mjNT!N13!>yfO_odVP^!h6{A(JrfSfbQRb->far4u}BS104X|PEl40;HvC0yeLq%6u@!HGTh@W04rYc@1Vfn zn=+*>h=gM^bnNcG;P_<^3*LA#%`p8t0{$2Lpm=y(#=_PW>DcPW-0<{Loeu_UHV}U= zwGAx(%ZiJL&maC}*Ee?9bx=}l+>MQeNd#l(yT%R}J>a+PC2LlQrj*BxDYFg_8;bm9 zJ04^#!DJmSwyUO@EP2`HT*eL}oef1LbVyIbS5Th;&I77X4efhXUJ7_A;H7|<0$vJu zDe(U{1?XBkPoehYJaztOa_R*dUTNGT`A7U57B^}{-0+?~y2cJ4{*T!IciW*ptk$O` zs=V?dPBNqKr9q6UWT0xFR^B}4iij@4C6$tnvl{FCBkIQfy4_e1r~jHhZSwVVIfk*y zuBjfK-(#@nx;)OE7CQ!zZk1a``Ovr@Ok8DsS;sUUVGr+MY!xtLHe=tcVC-AmaQfPZ zj6Luwt|o{6vey|~hhg)}xWR5S?99fH`eS_0Y{%scG@O0~z+RSarx_di9%DH#GBykP z<6&X!{=^5*j&b%0UZ(FH*tH60(UjQLx{`Q z@b}4;xLy=tUP3tA*C8GFu2_Zp5#U!c>@9tlvEH!L9^gXY3D%8-=+Sm!qfp z>sT~iVSW?wYlkpz-$9D&o)*n1V2NZ3Eqav!K;SpvA#UjE#Z4SKe0b z^(g^;FeRV|HY`GTP@l%PAJ7eYw>TI(0li0|HbPBbG8>F(0|%xNTI2g2rWFQbI$;{V zc}Qy!kWBHzchVVpMI|p}xAv%`$3S-@oA7jrVZlK}r z6Uak+Up<7!bs=xQ4>UubKC}mS_x%}svz4(r(0?P+ycCyD?D`sU1nmmp$Nf7QdmZ=& zYSLS`8xPKY!q{TSUx)n8H$k758T(}pW1p==dLX}JJ!8)xyfoy;DdbNRM_kS4%h^Qf+uU>rT}TY47;Bqjb(Eg zTmCp>!-^2zJj87?XbU@YfDpvng0wz*61=q+{QL#tT7{t_(%K1co_`RaV?)arTY&tZ z0(|lV%z=TR*IazR2USHFOz}8>IXZi)(8#rB=h{rM zrt!8(annt?RdBx{n*I?ZMsV6|GZ z$J?wR%{69&CTCf)CLm@=NqlzhM3JScG(OvsXQjZT(FoHFPvt1=6SG++Xr`Jnj%X5} zW6PT?<1i!_QP6T$7?7W;Mjou1EmO0slA`1kj38aAis9MgEm@YCszM7z%%lt$lq|mB zys2Qq;n}$q8BDQA_by|>zk_U+JhNp;E;oDHNi*X$+m7?R~}!ZH3U5A*3`JPv5vGAo1Hg>D3mfSOHdxxVlCOzO`~T{lWC93ot|wm z=T1dTQjqPrlR#tG^3YDpvSeqC*J4c!I0!`WjG(6H5gEY;8Xr-if}f;E^q>qxxfwW9 zs|uu9O7>$aZONj_o6>}$t9oI}$w|(#P9BjpRmOjKmSvJDPs_q|u%tQP<Ixv7SeVx8!bn`-sah_h8qSAp=Xf)Ejv zcR)KUstpk}RR^gyqrOFXc3Db6Eld?XYDg;Qq@O)u${@3iS`49@Y8q?K_2f07@0vq} zoiuZfZK|gYH5n@Z>x=u7rMVkeJT5Xg?!hDpeL3om%g;8p5I@&qSVrnjT2cDXX*4O2)YK<~l`bAQ; zsY7QB@>mobix~tY1yvHN%oR3it051`MT3`>gW`Ejdon3b~8WLZwv;p3SCepi*6xi-ZWNMsuOS4@e`Vt`rJY%4F1f znvt4bp|4Ss98$=_@f3I5(U(ZeHsvRA)iBXKUDOarZ=x;7nmuqP+IVw%_CymknT#b( zGv%r_)h0u9D`eWy88(@~z@ps|?H_y@m6e@mikmUPG)?Vfj6!cjS|L-n%H_bVCEM`^ z)~;#WJ-m>um`B@AhH7+4CTk6qRms<>NUdif0a;L-wEBOPH77MUA5}44X`g^Tkk-BM zY#5P-lm;!YhstWnQS%OT^U(HakQ?hJoAbb;v_9fCQJZSFS|$>G0JolJjMTh$n~g?A zZGDL=Vc0yJgRNj^{kSiY*Zz?blg=kX`vr`O=S!H)ZEFU zqd(Eb!bq4J|HSp$qVS*B*^s_i9p z;29g8lP4F$-(e23#87>$;m^_N)j_TiM}vEwUn8YPb6XtWhy6g!c=sI zG+DNkX6I$)Oq-n5P?c+&>e8@Hn?}V^xXUr;yW~d`fk!C2$9DACL@W0|mg7z$-u*@ELFrI1O9^S}aCbKo4LT zkO4dj6ajw$wgaC6CxAMj)e}e)&>I*GJOr2lJFpm73A_Vr1NH)^fI1-PNrVG*0}_A? z;1OUZFb`M)ya2ofybpW=90X1QKLNTWpeGOxbOw3={edAs8t^bM3s?fY1iS@&0PF(3 z1dan&0RN|ur$9U44xl#>2P6X-z$Cy1%mbbPUIG3JYzOuM-vK`YeoHay3fu#v02#nE z;Bnwd;5p!Z;3MELa1jXlla93px&gxh6Oa#-0xN;Fz{kK5;4E+j2z*+{ZUJrs?giq2 z(EtZ#0!x6u0^5KpU_Wpg_!S6V2Dd;5;4YvqkOqtgEI<*k1b7knEAS!k1#lX;3N%}; zV-djJzz~1~^MEIS)xa*`FmMs@e@4ebfLnkLz#TvjpbroSBm?6BGf)5&15X1l0&f6o zfla_iKqYVhI02jiXq7>aja>%j%lw!>wsSSXR<1y7<7&!oV!@a!Z^oKq<5n0pZMDFL ztyb8qbt^V%wZ`vB&b!B(4Zmc`&!Fsa0 zSub`EyO;H5_p$p~AJ&)Qu{qYC#jpWvAREMDSsaUJ32ZPM!iKV8Y&c6~BUlnkW+T}s zmcmA}RF=ll*%1#Av0WOg=}JEP zY&l!Po?=VcpV-rE8C%YtVb8KZv*+0J>;?8Bdx^cwRuKw*08ng9ri9;$JVp=a3lH#_5s_-Hn9)cX10ZG#j?XTww;x;9qc1k!FIA; zY&ZLueZoFvpRv!`7p#(1u{~@r`;zTrU$L**es+KzWQW*c_6=ZlA6jqHqb&LI2HKJVpUgBG*Ymo0RK2N%u7%>_PUBB027a~FHTiSXTt+~*?GFoHN zpv9BEH`v1!;c18DH6flUY;1ZXwa<+VSpACsqV=vD#4-Zp@iZd3HeSD?HAGq!&9zR< z$ziuQL;D6~0;7OufE-{Z@CNWU@DA`k@JE0aC34KUlOCa-LY~PgzOmyci8*L73cw`t z_(|ws(R{}UZL~4kG#(=}YtDe&ylfhBjy9v8KLIm!>iAQds3T67nW_}-FcC|$_cQ~I zfxpzE9;}B_j+`6Xq0YO@jto-^h9ct;hBhkP1I9Z9oB%EYR{h8sAqOO1E0ulQ;8R$UJKXX2_HOcrl!P=`u$d)nJ9l+c~r|LmJ`7<8a$%<50}R> zaLzw3Zd@K)zV?5wJW{>ZxI9uFM?%eWb_`?+YmNsBfaieKz{fx@ARG7$=E^A`sup8I@+cAmXz&6rJXDy0Hd(SKxHPpmt5&oy zJ?7*vl_giM#Bf|wh-ECdLag8*Eu+mMTugOoavAGFu(bnt4tNb%3v32H0}cSyz*XR; zSJA-)x&!@zL|`m139tf1z!SiYYl4OyDv{^%=MV6oT!u;91@%kt>m2!a!~0|Jz7Lni zy6%r1F*?FD)s`a`FCwOjHGv4%76s41G&x?D5JFRXzg`M>Dd45R-=jb~81@4m0v-dN z1@Mj^MkaW~7C^hhdH^Ee>(pJ(P-OZ0LILX zwEkYG0|xrU#>FQDG-*0)c+(L{$sxbw z+O2yJsPDPA_k9~TezuM=$od^2BgHoYxunJNLk3?v110M4IGj9;g+o-kFW?f?NMx@uuadO zG4n|l*}47HPC>U#>G+2ZUAnprt|w!iZtK_~(lgZdkIhp5I#2C26jyw_kMs7)s0aWNcVs(#Qn8kHOc^KcI;*FsSK}^fBt+;Gx4uB#%l7?sYFn zgn5KSCP>^XxV6qD^e*A!5~`L<35gypxlXT##3ek9J>`EdzrAK&3V12trGS?LUJ7_A z;H7|<0$vJuDezxPfpvIJn&1^)3V12trNH$lfRlR63oi}4JmBR4FAx0p@xX5E>iXmyNaqJkd93pYGwU2a zC@Xh@DTj4V8pb*g7;m;%S?5tEx=f<;kV&~_T(8i3Ps2zxRN+D?nBV1Lhs-?_-xp?s zfT7Y3ZEG_CzA|E+p&tcke)vJ(AJF{J%%ydl8&l0SHTkW%B|Y+6b4%(71c-aITw)9i zfAUDglaP}+={L4VYRz2p;70Z|^X7YTZVu=H3-l#cRgpZ+0$_nJYxLJh{sG8bA*X*z3B>K$0w&o2>vI< z^&B?VYmVcHes*8Gp7zT}gs|o@&0_q@e9QDPx)?)DNKEsHW)Xfb`@XD?&_x&`LL%&j z7(;|1#DMdRVS0nkV2_Q7jff42Wy1|S^s%~Fdss|ZL|8}|Yi;&uKM==52jFPs zARNntJQjE|9y|SkA0gii=ztM0AB%4)@Hotd1IHj=1;oYS7%bFH0SD~84_pQ8Knl!0 zgFb~5419^ORztlD_#zg^n}KhD4zPC#Uw?eN0bju0CD@q-c`o3DoZ~wQewYE0`z7Fr zHNI~GPXWt;mw;D*V{qRE;dh7Kj=+m>KN&ax`AT3dxz&s9mvw-)YcLs=tzkX2bfL$=}3;*^(ZwAcn zfLdU-w}0Zm#%lo z&D8g(;$A6wOL3nR_e;@7ioR0xlR`Sb=l62oD7iOOMoZDyLVqbV{TL|*NTKNultNPv zlHx}0W2MmS|8Ke1{J+sx?2f;YA@qkzF-(f#QY1<-LW(3QlBF0a#qaHYloTmaG%o+6 zrAU<`O^S3W#z>)&=m9ClO7Wl+n)yRgWJvLQyB{Zo7Qaj>9+o0Yit$ot_O$N=DJDu` zl7dSyNs7r*WJ~dg6u-CoDN^J}p`~l86uDBErI;qgqf%I;(A?!op_PBD6gDZQOOY?d Y@9kcT_l>@|@9wumx6t3R@%xznKb1DUX8-^I literal 0 HcmV?d00001 diff --git a/tasm/DPMI16BI.OVL b/tasm/DPMI16BI.OVL new file mode 100644 index 0000000000000000000000000000000000000000..9ae48463776ec8bfa753c5e2c2304bf682d95561 GIT binary patch literal 50576 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 H@BjQ4{M750 literal 0 HcmV?d00001 diff --git a/tasm/DPMI32VM.OVL b/tasm/DPMI32VM.OVL new file mode 100644 index 0000000000000000000000000000000000000000..f2d51b3b10730c9f0d914b0ee4bf0fe02e11b575 GIT binary patch literal 58376 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%0DU@tY*WsU^xxJWJ_u0Jlr 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

8^fE#;zL9YjPi?bEi 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 IhEu!$zkY$khyVZp literal 0 HcmV?d00001 diff --git a/tasm/MAKE.EXE b/tasm/MAKE.EXE new file mode 100644 index 0000000000000000000000000000000000000000..2a5de4fed4bc3dcdf65062c86acab3c41dd0d019 GIT binary patch literal 86016 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

>Ae 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 literal 0 HcmV?d00001 diff --git a/tasm/RTM.EXE b/tasm/RTM.EXE new file mode 100644 index 0000000000000000000000000000000000000000..c60688af3aeac902617864ff98e898e158de5d56 GIT binary patch literal 120853 zcmeFadwf*Y^*6lFT+U1;lS#M*6qrdM43}^b0%%BrfXM_~4FkbR!X=3H0#rdKGeLjF z5IU`8a$?F;+iFv6O+l@fR;#oP&_cps!lfu+Yw=RWpmv9&7y?Z~GUPnpb-p_0DIWy<%v-a9+uf6x$Yp=ETp4*oVV_&eJusfN+6eVROzSsuF*j!u!>v6C1 z;^r&=9>g0zuDg)yXpooH#q}7j*KmD=i|H8~ifaU}>A3Q6 z-HNM=O&>Wzm_G7ICQtl8s1;I-c#rD=Tm>e^9>LX$>!O*l@5C{dWdUwn1ygH<71L{l z#ki*6x+Aw%SbIyYaNojO;dlA9!U9~=aE-!s+=cgfwZd#%c3gh|?Acpug|~6-#`P;) z60TLarr;Wi>oV}XRZuHrE~*t);;O>+6I{0}t`+{~t`&CTdKlMuTmr6V@$Tr!9elrsYxz!;@j|VT@w-|f71yCxYlZLOx(-*>?`wq(xSrir zD?EwI^2b_X;$HB#p;q{CA85dJ8?HIHs+wzsO-E{ln~v8CkDRC#?ti;hxaXZ(;m*I; z3MHp%gVg#$JL3e;Qd;m4%a1Iw|{_ga9zSR`yXfrT;o2h6%<@gepD;m zaJp6)`EjkV3)heql!0p}t{z-p+1b8+@ihm&=D`024%{$(M#jupvv0g9bN+%`a`Rk; z(y73i#9Pk{IdS&Hso0BuqD-xN(!lDO?pW&bkbCix-8#nKQkInzs}Bao5A;2l8UMZd za3&6b`~~&C{&%eARDFrCml?FmOP1cAa{q?a zci-bpDZj^Cwsyn%l<8AvrQEXN!AHDn?_1+bneeTNDbq7EZ&3%ekM!mCZP;*sS%M|a z?p|VZ?D;9`7g4NLwJn+L9Wy%JZU(w<982XZbY;d@$F=%}YS98H8z8KJOk&kX>n-fq z^c|y^SR;;N&T2bjrrl#kZ)wFu^lqbUZT#3!FBp$aFB9tp);d!N+87I>xZqp^3(gjS zpY1jR1K#Uc>ri3GU}iM49YfVmyZSkX)yFZ(KA0uyjyATM1BWfgrq`R)6e*c8$)-bo z$!^Ez9-g@6EJ{Ao*lKNTF{n^OnI2F>RH%Bhnk@phAPN^aD+J!{L!tr=WqVMIvpn%C zAoaD4?I{tqoc$fU>NQ_VtQg96o7g@p+ut@JeBoIWzeSH3tDm2D>g~2QCw0o~!EDVC zrpzA797i2F&`E~!>-2n`aSwo#iTTryrM}8`p&`{$$FMz$vYSywuc+i0r0quK!S=?F z^FrLi+B!+&zm6kELcSKJ%6)McDG0a=D%rA4_%b)vbu&j>eyFR<}FGU z^CcnEL}W_uLhmOe19Ahz5CN%qXdi+FiOBE0b^Y)-mtpu_%zi00-w5K$I7F~z2E~j2bhp>zUie-|8(6p_N3tX@8o^W>ZLowX!u?fVBb6 zf-8w&rz*uEPZ1=0p^ZP;8@(H$9L+H%`x0^%^!W9yt?VpKSDgn0=Kq&{i5r5oLR1B7 z@iND5fxT6-!Jo2bb@@Fht9`zE9(d3Pk?h-$;`OgjDO$V!?hPABY^U6_e$DFj-@>a0 zHr#zr%EmQo@4qL(0+{t{*WX9)SErP%x##}-Q~c{`zF3{|pm&4so^KH@H3J^+^R9ki zYDx;t2niO<1?xBX0Qap84?Kw3;;#Ge!R`8c*WTy%s*?vGmkgw!%!gTHwfF7>i;8jW z`ZC`=tM5*kuo0zCE1WnL(?);iDBjW|B>9bd8I!-WrAL?Ki{H|tPx5&kD_h%o#lpo! zp6cV$U-p&=HE&Cp{@jZLQ&ZRo{*zu+b~qLB;uvSM$i@oH1mX6INfmBSK*p)UO#`C$ zj5!tC#W5!L5FS4sSx2H-M~5j%ogmSy zvl6DUW2sZC#k<6*LHnJe9nHN2>EqONhbd%7kHtGF`Of~-|5QG1fvotSDj$c?7wttJ zbqH6Vkp3#UP;K<>>*BP&P5s-()|6Xp+#O!Lq*?S~c_|%lJZo({ZCK*Aukpp%)?@(~ zvrX>1N0*hTqo@c8G>WuK&HaO(niEosl
Tw?r5zb>Ppbd}@q5d))cBDx`uBV;76 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 CTC0Qr literal 0 HcmV?d00001 diff --git a/tasm/TASM.EXE b/tasm/TASM.EXE new file mode 100644 index 0000000000000000000000000000000000000000..7f7e973365c98699afc1b1e7c734607c11ec9fc3 GIT binary patch literal 136018 zcmeFad3+RA);E58t8TJ%_Dl7=<$Zqd-#`6)Q(d?2 za_+h3o^$TGw~Fa=W|~4w%gxQ~UKR-Wl9`pUH^-Daa~NYLb}8?HQvCRj|Jm^*mX$l7 zX1eQn;IF`Cpsz`Htp?0y-4zKazT?s_v^cfAeV7Nff!2Hua= zUB`hN<8)U6@EhPcpb2d)F#(oxXSy9%SGhAYzT6pZV(b!V2{$wL2O!MCSU+Gga07ZY z&&JrJ!1WSizXl!wVjPSm0<(ZSfro*|fLDQk00Vn5Rs{SOcnDB{r+`f%jBNwjLm4{` zYzt#-P&i}P0iz?(4lpK`vE{&fz%Jm{IL7V(_5q&&nu{?@pK|Bu-sR32z@LHFfW=6w z?_2I%1+*lVJ9hyO15c-xJKY1yor=5M`36uksN8uBSJU8fr)x;L^C6&QSh@3u;pNT~ z8RgC&0aIqVGag6+UIE6ADtGp~uG~2S7z5k{Q~~RO9l&AW?-==4Zzy-(KepUCD7)Nw zPfocrYkavgbpq(TrQCTip0VlompiS!!9SoskO~Y1W&*Q;=Yf}i2A~mmAJ`6j257)H zKmZujhp}NmHZUHT3giL50`3GVftP{hz?;C^z&fA_Xa-t=1HcjBQ{WV!0cQYHU&eX^ zNx*eL7LX6j1|9;+fNJ0+U>UFmXaqI`2Y?TOQ^1mb7^nV>MFInX9H0_71)K&tfuuyn z1_Sp2bwC5~SQ35%1CtrM7gz}V0r(5B2G|Z920jOV0Guhv3ycD00S^FA0<}OZ@GEJKm0iFaF0WScr0DlHn z0B-|pf%kwNz+T`OpaVYunZp>H21wU177z3TMgZRdrs0gKzze{0m6$KM{vB8gd<5t~ z?zP~{2*w^C$=JCJjN2&23IGl01TF*8bInV^mpTb!B&7k>K=oVl;a2og#NSMah0AMsQ9(Ww6 z2ELh&HfCTvfzaD9zkvBb@hs3b8}eNQx`D^$fN#KlAfp)L3CMuy4(O(P7^??X01d!; zVCB7#XK3%|WX84vJAroKFmUhV7z^NIpm;uGw^cx{01xmEunyP=^r~d+S>Q#WeF5n5 zLiYea@asb8E#MGP{#3d1L!htLSJ_0u{g;z((MY)r|Ro)4-$}q^lScU<2^VV)O&}pXVU+K>u3C?g91z zKLWQd0q=lKFF@zK$k^HC7>jzwl7X?nY~ZiJCSV(|<~7LP>)`nt$P4s&ld&}5HlPTY zumZXYSOshVo?VIg{TBEM%z6j<1$YJc4#;j`>?YtYz`6!90~DnD)iw3>u*pMqXs3NQ`0 z9Vh}yfL{am0S^HR-~|=|OMw-@MxYtk2J8op0G|S%178DYfs4S{z^y*t#(&buPl7+b{51IE zs}sQ=8h+3-pSDrdXKi$!sg2RoecI@qgf?m$-bR6I+vpWwFmTU^Hd=%0E?_F2y^i}m zVQuuBt!=-b|6kQ11ztHOwYgiR-pu4*{7LQ6Wp=&kLVxNh#VGI1v9nO*OFbor@%paZH~VY1@Pa63lI{3i z7smWEeY3AGcg}HF<%B?bzjD_(m~WZ|PPS@81;^C=`e9y4rxeM&sMPJv=?&}RUY5Yp zPUxw@t1Ea7F|OHnf#_u*Ef=IE``w*V0y8U7;(9`MxR<$D=l&HAzq?j)G5y4qPOnIo z?JFWhC$oFW_KarnGo!g{hxoz!-6`3b*Dm1!!8=RN|p%?JAa-w*8lVSY%{-?P5#>Eyjee^q1Yfo zwq`UJ`Z+5K{Q=kf8EpYq`HVJ~eRD-Y6SMl&bNDe^N^;rHzUE452wzze7`;Y{7Pv0^5elfjwOaBWv} z`mVBzmR)1F%9fSu0{()Hf0?F&{i}|wFe?{ltS~9j>S6qiQ}<4;vGT<8`WZexnLA4^ z_{Z~KCF-&CwqF($g(O}?@APJ8$v=uQ-TQCzrZ&s{)WhEFY-Pv!j zc_G~?(MX3~ZvzEan-g+EpRgjSG!{b>*{vazn}y7q?bS{$N8K`{eusVu`en;xPSHT6 zpHUl^KYB}y3ON$2fX*l@Ki^)R|LOm-YuVNuZb_eQS-BQS3+_*D?<_vT#hv6e>gORqAAHqY*L z$}=4NkD325QJ%e3l4mf8raZ$+6M}c0(u>n9inCMlPBSTvPHBk83uT(xDPICVg#MJj z%PSC_4-Tm0-kJkX{9$NHyE{v=GUa!Rp%o>TaZ26c_PTqqCq*@KY*#Zl*^7C7$4$_x zt+u&Sbes4s)%xA_R%TZZ)_JE5w6Jj&COZZ+%h6|F(-RFEe&m-(`5Q2ORn3VbX~{!R z)NEaO@@z?=pOb7>!s>gBj=z9Q93@FJI7j!UgCWl%q1st7&t>msZ;8J^5^96z<@Fi@ z%B7}MJv?EZiAzql+#k|2Av;Cxot-KtW)G74a7j89l%!EzTlJ$nU%1k)@2{cBt6;7| z$8J;3jTxpiPu9=O2xbiJ+O513ls7KjoD}tJH!1cK|K!Y_m=vKk69X&9b4ujzcosbP zk3^2|L1Yw&jN*iy3APsj!cL*h6aPK&!Ip((N_A+sJSs<+CH z{H8xMde&Lwt}`?BQ+JKa!6eZ|P8*g^cL#iNyu-ec{IBZw_2XAmp<>K^L-~!%j@!)@ zGk8jM&VqRz?p4{zk6TY((EHDTRK`FeBO0<-QYmZ5S=rI+wW<0i$ zKo(Yd&YyZfv3a2_5>`Qehe3V^qhvU0h=j;Qt~`1Cynp3X`Qj@5hpsL9nbZUF*Im05 zS~>LsPwuEWu?l+Jw({h8k?r6ZtMaz~bw~dzH4a9NX{a#_HAbLD)5?<_yyT@-`j1mP zeq3Xs%0St^+w|Q?`_ib*irRRVqo{1Xe){L##60Ziy$Y3ai4JeIr7W6cYMo>r#>bd$ zYqf>{Y_ej;#PR`*6-KB4M(8n!s{WC0fZ*%T=Jg8G1!V~RnxS$flm_6MBcGX}pPq4b z>Z3XdJyT4R&vU!r=X9jZplgvg9DK{+JuM9dGwrZHmKpl-MYbt=2ma8Z0IE|?^ZQ*h z{Llxf$j>=5P@WF%WFvn(%3;)gEOVmP5L6~1_hkK`zvcx0!F7myb~1jB-Ku=M!(2Jc zU1Nh#*`}QA)KiObGi8zerjzGp>2Wl=3?7nw03FM1m0p_0=F$*0oBEsP7Tbkt^@0)6 zGeC0>eoWTC71q>WlQ`Jp?XYA7+B?+0J>Y;OMzbovwdzKb@?+JLW~O{wb4HKb5a?=6 zxA(oxTz1Z4kGah}_Am^Mw=1Nq*P4L0b;P3Urf}J{w%SHa;R)CCgiRGQK;z08QncFKKW^<7El{puF~^YG7Mi7_Pm~3Rck|+g$$G zq>P3<@wLW{$}n6bS+0^6Tz%ZA^g+XDzG^rco-BOE#^JmY?N*!pykA(?nVF|ouC~<> zpF+_qmmb`fNidJ!t->Gpv)T-OHnM>{l+HZ8+D3Ct*~8^*gEB|Swy@OZMiPDAwziXI$d`yV9pk zZSxbe^mXbP^-@vQHkbZRRnC1gm=fJ+W=+iOdjKv?we!9i_4m%GyLU#Fbngsv)$sdf znBCQrS#7hF*^Ff^7NhR^5azCTKwYKpRa@N4B_Ne>r(J0lk~44XxCUCN0LSg@TssO6_}- z>Kaz5>9~Adp`F6zhYIZzllGm-XsXj7W^VRW`B79}0)p-aF*j$=29GDm8Q|j}BWEFq z8k2p$JQajp55mTRsFdu-!H{`i$UVv!)peIwdkQVw;nkkNrNpbrxa3x958*PrQo9$I zZz{C8xO7%%g}98V)bdT*T_$Z_PjY5;_wn=WGUYSXHMUYqH)&%{T6WJ|)34@wNcpS> z$3Fna+f|obsr|?d(ueU*-qxMJZ}uZf{HpAN?)%W}#}vEjDy`JEG3^l34hKt(;-!8i zk3h)?qn@N}1zmnb`LIW8p=b@I%PX~Knf5Z%mcj;K>A*MWz*nol)8L?e3c)$1y5?8v z(8ye*r|~wX$~Qn>vQTV1+6&6tD6l#e@|FfR56xDTv{e|6U^NNZ^ORWC^>C$*zoRR4 zr|Qb6)E#<%-KDy6DxswK8ti$+A#vTJ?PKb9aMz`bQ{06(BD5%1VH=(oM99gj#GFK# zr(5N$9yiJt`Y`PRd%kA>D(}hUp<8-ni~ZL$-Gj+Gc3EfpcoN za1~k&%Oxzyl>piOuv`!G1uJyAdPZo!zp9rk=l^#akmj0yR;?XYe5UGrdRpe`{MELD z+lp2#&7_k*s9joefUAA8@}l0$_@U~~#eSM66;OXxV%J_fkGtC?WBshcr-o%Rs1i#+ zxh(hu-v5>0-NM$2Inr#zGFnupcizI5iaF_f+qJ2}Vs*IHcC`yG(%ILmzBQ}oEaw*n zD&{>tDByfy9^wbPE_c}Qq}BYB35HeeDoJW5b;sG)T}l3?#Y~^yRL%43S$M8I zbtN_sTs!3pa*Eul%gF{D;FKE6hS@6IdG%cS1@6`-+E=aQ%O!P-dL-SoVBT#(GG;!$ zOpx&s$T<7jb&#xxT}7#NxrDI-VE<2y;a>I z%uBwoE=7oN@_6PP9voB8!MTbZT@9wRYnvxRE zO>vkZq&6%s&KQo0Ye>O{Vf98@5Gv?{QU$P<6U_-A$I0|8G@fN`fF(cR5yWIpowX-&QuU8v=|5Y31 z>21F1Tj8BbTmp3~Uy_D4%L94j+{&baY%_GB1*XR?-;yoKa}W?OLoj{8`4W5CLA$#S zoK#)Wh;yrn694JI+=}H(VHXR;>c^0b6cwCBQW)FpWP#hwI?vrRIdHpGe+Sco=SmFa z`NL671b*a1p@5{naJBlt?GC-F=WU2q7GP@5FwcO19NKhiBn=NxwWOa`b4rY)(a%%g z0QC;lkI|k`H7A*;CU|om^Drf}>AL5stBVT5^)I@dk9qVTy*Z^GCWm)Q13gw*Y8vC! zj(3R=l0~t1N(-mua(90I>~d#;dS+JLFwfed`M#k^<<6pxu-X<8))k>H_2Qkrj6CdY zi?WeCRL0AO`DqBODJGEojd+6Srl`&L5dy-hGuhKY`U5;eq-@c;*uRw4VI}`->Ac0w z^m{5)1{TcBL-4-Emx6OW_PqS7q|GV5vt+LCn%g;X>cu}~bZ(a(o)!oc%+8-R6Vd*E zS77d)3%_K6(0wT9$^Unqn){#00-t7rrtiL#W3SRMSJi#XL`^?W%M(_#L0pQX%46UGQ4fAKH# zH~mZg`+0tYA`{lpGkrcm11Ev&!Cwf4Z+AgAfByAZD8$APh<|++@n4?B{O4y-br+xg z#OIt3>G8u{ed2rQ3IUPekJK>E_XAG7*?lLx<<5p=anqwa`N8MGCq;8-=ez7a6S`Pb zY)7P6n%@zJNE?qzAci%DCs?Gg`BeuP(r>^odBF|R zP><{p{F85_@nHtnX6Tv040qlj4f7}^BHK(OTL|?DW*by1C3`6Blrh?O7i@CQuN&%t zBAKry8twZ=6oRK!nEg0xCvv}giZ7$*n#whg6K@!}2UEVQI#WMKf5VcyUBHQ3~VUd`HI zk`wvGij5;&EOI2jNOCXZnYqD&vEmh)ajs82 zQ@h>xalWC&_bg^XQMc@dXri9R2*-(cAQqpL;!yfizAR=1P6qfoYaolXx_ zDeu7&-UFI&p`^%PFpEn?w?uUO3XzwR0(F0*iNV3)D{q*7XUKdknQ>Gmgo}{7-pnAu zd^KH{fQ!WHGH`LQx>2}F=38I8epqERlV zXw(EbqyfE_;IafM-JJoc1@NRU`nGb#SSz6ub)pXgnw3=1svP2V&i6RH?)jcBsTN}E z`v3<#?c4DSK>`@_dh~W#7+XHtg8)_^F@e(&^hQ72b+Fidr4WYR=uZA5n239E2L>Ta zeS$~KFWGgK+$hjlCN-5XYB|S!X|Ts#hl)md7B^$x&v%}cJA)b`T^jD`>l%Sso8d{{ zp*lx-`tB;Tqd>K5l)(ou?%(&fZn&o&+!^5k2|~#YK$)tg3_|15lCyJ?pNs{2f#+1-t1|hHh*sVKadysiWvJDDt zzK1}SusM&w=5RqrlR*(S97cGEDyEQ{li(3HuQUNxslVHj7~Fj+OC1kw9w{k(X60jh zuc%m$G9JbtkXNcxr%nE%8j7OYnb1R0^-#41f(EKFS>O~Mt?TEh&*i$legfpS#M5yX z!gxJ&i6h7n$Nahy=nLqQKDb!fvIn3xBCxYruxX-ab0mtKeZ8cv5YM1s=HLPab2~2J zUjZ&*Y}q3y;AFaO7G;=hJR`8{$bD5h6Y6S^kK}>m2M! zR{ixQ9G9ds{qGIR-=^_Wu00Z{< zt8)54jZP81wVcblXi;uJ7yEbwV{l|e%KRwvfS%|(d@W9u!d%Ot@Nn;hOROH%9o?cR zrmMYVyM)?;F1KuMC9FU!8GMCeF00O=o{qbX zC#i;G)3+dRrqE<(VFl(C3d8zv7t5HFVPV zbBx+TAlUFBgeigY!Ra4pUhW`W{tmVCwZ}EJEkUjAn*|>ITn$)*LT{a4mki-Gv+BfT z4=g_CX0UPL3}FuO_ITx5zFE{Ob5E&f%_0MMJQB~*-FplIh5Z{M{Fu~3J;-WIZPC-1?^L)Ni=K7P55PO^CR56{(yTbBbMo@l5?e%>mw!=4ZU5Iyda1gjdy*MuN#gSM+_(7!qJ24@pW*T? z2A9aq<`fkd@??`@^S!`LVv)%SC*I@_I_WnslUakY_7FRzw-qA z3;oXdQog#Q#^v-F!#T$o0An6GA-I^y7EL?K&xiTXVJ*NMSmh&Te&HMJ&#fxQc~Z)- z`dm0TTI_o-3zEI6oOX7IO-`B!?!N@`LcBQ-LhpR3E&7)7tT<0yzpi|-w4q%8(%`B^ zd!>Ww&Gd(k0vct;biE7Sq0KiPwD{?eMRmSi-Z8wkh2Apr!wfhf_QAr>0ukPmUM|}- z|7)YQ!xlSrn#Iyf-|we|7HG!C^6k>P^0&(uCvGUGjE=2|>&o3~L`M?lZ7kMf{XE!$ zv$05d6pBd*io9FC(ZuwLMuoqJLIe47IK67QO0?0JHQIaMpbQVdYgeWCh=)pU=p9f1-3A!u+S)}9MlKUWecTR^r6C6O_#)>D7YYf zaWaZm8RcA1-W1C=OKej`IX1|o#`3y~a!mNT1?4d35>DB0wX| zb#Iqr~-9xLp-U({c7M0y zXVf7=47`pIrk`rcV07*){o_{2H!TqCrQ{xhe)#bh%cR~2Y{E5xIyFF9P*Ts@@eIzDLFXXV*;w9@Qrog=QF)V-ZH{KxX^K`|73Jx! zr^+#R`$|ujLn1Et`CPeDL*7iTAQ2t5vV|uD5x%$0+#M1G`myOff100B8EX^azBb=H z1TorbrR+-ISp348yc35Ht#XcgnTcgvmC=SV7>F~8eVClcBcBIHLQai)C%@l#<=$P_ z2kj=h5cf*Hnnt|7$s{nTnFRjAHW6-H#@R7Gz67ZrLFy%V6~c={k7+i6E>dB9zr2))b| zrXN$FSUp^Ov?@nJcwwsBJC4cN6RE^0h3u*vE7Goqm+j7)WLAbl>*9x18MrKsxyMd2 z>HXZblgx-r@S@Jl&dfm5PQ6F*KnFiEj<|sxN8mx8-MxJhTI_xr%Aan>lw!z$-1qR#aKZ=hXhiiS ziPK*_$;_#*o@C{;01=#`LF!>?Hr>K^%qB{F5~&l-+yJQ)t$a;ZGtuN;p2qb4 z!T$6W+4~}U?H%STod+r3FK+gyOCML1y2jnX%Az`@M2}U88kfsT?c)mZ=YoG+BrCgc z-XG*S{NZ*NJvChjVzZyTu_VXQH*xNoM1*QooagXfN><{8`pK2Ukvx!j+mi95AM<^S z*L*pVLJs&g78ujYxyWZ3pLXv0SVlF|sC1e(JXTC`FOJ#T*osKyIxK`H@dew!T<^GC zuQGt98n!)G?u`?;Hn!QlY#>XEa4$!7b$mz6%+C9%m(v{>jmmkBN9fvVh5BaN9ItN> z1agH~{>`ieWe%wS__mi;I8pAa>kaXa9u z@K+ve*s8Wrdq5=rBuF=1O>gR%ZuZkHF{0mtw3}lnCkDmwTAq?1n#z@L3RagT?yYjB zxX+c-DI}Jjjt$=R=iP;)gPvCB3}%FlCf@Vv9C%+h->Q8Zojp_;Vl0qSXJM_kZ`N$V z|GC8j4k%8_xTP2e$fdC4%z$og7>c9RFT*Bb%P0w!Q!*40HAL4+2P!x>Yo)^#?)t$7 zAHM|&oZzu^ol896{@=pSa=ld-a^+N`NC=~SQ^S(QW3K*l-OEAlcBvmmTYENIbRtI+d z_I5;wGQN1crJgra6#bXM3gn=>6BG>Alwu)Z^B=^{BOj zbPN?r;PGJHjF?95MfW1m$d#?@3)N5C+vLH)#Xeppip5JscHfu*I5%qZJvk5`4`|jy zeNW+DZ9(y&d9x^Rp}0^~!6y!{=9>%9*^<~33pLj1e5VTPK?aqBJq~~Up$b|UNv}lF zw^2AYkGJ8K!Fb09fuutfz761!;54U77>cVLp+Qr%+amw1#N|ZtLZn1ddbAiSF@$&V&;xl9e}sy-sSRf*=4LriJt9B3FV z=4L|(tZaoQTw@a}Q&ZZeqR9y7dv=Y~*RldP*>3xVXaDcz34hVeWJ2 zjn}Ju;@vqSpB9}faxcO{P8;l`y9_zvyg;OY;h=e%F}Zv38PQzGdx6DIVuYTsh)LNIxg zJW+~uK(lUhhk`0NGLWJDM`2WjO|-HlFstz^a^)DDl?~-m4A(IlhLgt@U>DyG6Enq_ zSN-Xea9RMC!4?=Pw^Ca;J?NxWnfgsVlGABjIJI9xGY$3%W$Q8LNONx!=C3Bzxgds-UWgDYccdl;P>M!yLs zcLaSdXg5@sBgmyk==Ct#GK_8tsu78PypB8>`n@zVya(4ZXh9ggI!u)1zQlFZ;iQ%S zg@yV+BX0zsnxY~wmsXCV#GAM@n1jw0-EFiYRGj=!aE{N$Y~t$ySVz&B8n=mgPub=1 z?kprJW8GPJtdtrp48;o)ZtqVPWdIJ`C($>eHTsfkRTDdp0WdK$9}&&R^iobq)9)CS zPtYIdiT_bs8EUFqX&Gar7vZIV_hG<}Y*RJ}^|N=I{Fdk(G#giIL66aJ0C@d6j1DBy za3q7t+=$$4P&pnVGlA#(#qg)|Db7PSm@$1ZH^f#36l@<%TRw&8@@0rZ#RTocUTz4` zpK5lspJ+eO6IU&oJJN|l+wp!Yyql>L=<#0E2TTVM|G?Wpuoka{(4rARq2U%xj0kPb zo3WfhwG7_jkSp#;q8qvgOL^Z9B1Xa&3Oy7WmT$svVPPQF zF4b7Uipq0;rfM+jVJ4WiavZ%mj`xPUc8IYAJAtkSJxeS#Q@gts)}tMqR)lsD#+!#n z+>5~WtMwqGjRn_}GYKBfhBdFj zd-7|{aNTSyt3?UNiJ`P+1sZ6$iJ8v-Z^KL>&#Q>M@VM39{~otejUdPW@F2&7f~s6} z-^qBOBOZZ{vUEYdd0ZYV<7&``P!|FprGtzWPpo)q5fAv=M?6Tfm&>3P>_ND{w|EY^ z`N52uGXs+t-e5l;c>T{Q>J~}txZ2@5pHz>fMS#6xy*~F0XR}zZqwp18We-t8(Ts`5 zOB3CUrXDT8=!u=zs~pD>2F}Qw1Xdb}!Zw@%u6Cv(Wq2~2;Y7SI*IJUbU5S9V6H0qF zU1cj>JW_xIm42TWA5F8%A;l#^2=JDL=)mBflw1*%tF3w4lCeazp`q^9)YjswE&aMj zOKMBH^l3$D)VNqy7KRY`v&kvELde?VN7PGAGa@O9pR{k`t5}m9oh7aF$^){b4PJRz zmelB#uM@>{c<~#078k2tIK1+i#;$;_i}fXo$xq7n(fPxo%R&(JJN%f#sdYNi1w9zc4 z_HjPZFm(0FSSmbj0e@y6R&hj=5+`7`TD0ed#*f5OtU3|%kvlm<{kRNdLy-cF#D_oE zPbr5v{l7`!!CzsOgepPs4TN{+Lgg1f5ae6&7ZXzyHlZFUzG}F8$nfC@_=V-+*Jj-8 z{s49M&V|g}@jH2N3fR7L(u0|RiW^^`LlZMh$0a2=zQAe`YIfP1$`wff^CJO_Qt5~#8 zhxn-|Ky{2ZCDWxLARZr#3YrIeLPeMde(sTHB-Z%a0x2Ca_^=@2Ckxrl|8A4 zit3WFRXxK@^?kXa_KmYDhSbH$4wYlT;K@IqEg+LKs;Ml|(fbl#lyEo@pe`hf6E z2v@RA4>K)&H2-DTRsOvOqZJg^wj1>|^r&y0`D%SDdeoPUCi*ja$((i^O<+Rw-675kDQ0gvhWDHWPhX;%EEOs5z3YOiNOEW z$T3vVBCd=?D7d>c>{icG$@p{uJ|u~02P>w!QVnME63IMRhN*}2YNTUB4Y%CUszVB# zEi}sIRWfARU6;zI`4AoogVQV~5IknC;DWQw%xyeuE>tiWhVSVd#SheAXD0WypsM+*7o8Bj zL=c|KpG6zF2VESDPAKA47B2I=e>|RGW!RjeYx~g)iMm8F{pi+2u$uAUG|Zs)l39+1 z>GNK~hol-MTx~q&go?|tJ8tqf1eTY3mM@)F_i=@-kRL(G&m-y7;+DcZoGxzheKrc8 zTDAECxD*!I%9Nit8eldE zmEANjEy&9hv4#)Xpj?xW`On|uP(M_6a7ocasrC}Jq~&Ms#9F0$;W)Q;dmynj#Xl>5 zcHYdoQI+1D$3eNJ&RVJNr>M?3g;%UwP3uyzY!JNj((f+KEh^@wI|P!(ASl=fS=`Kz zpiY9)!I?s_m+H@(nNP7DMLp`F2TjOF*Rv~G-86o$$gTI|#)Uua&7b}a)E6oa8nD;* z9)9vpXmj>)Vc~KN70G?|C5AcY0*Z0vn;v*Q%a4VOvCp0QJlZl}>_sR7U| zvk;HorKeyEfd*ZqIl-(rO^==JE}^!Xu8E}WyNnj_S`+U_loFH2BZNz{T3}3;cyA`;rjsTV(ev#Pj=^HgJTWED5dB z(TV_V?M>zsiX76oJ%SckRy*jkbnU^t^hrEjcR|!*l7~>a$+!Ela%X-=?;86}vuMnR z!R1OmCGRaF>)zs%Uy^Gt`dF7rO+zVkFFNI?W$~zh&$(#Q&eKDww0WpR-|n$vj``^y zDb#@56T#bucwTNdyW@RhX#M$M`!2f3e7R^}jQNms`o|tjPe1*TLXV@0zw8MfIFdDy zJah!zF{mtpo=%}cJYIknc++vc9cji7|?vM#!l`M&Ee`@&Fi?t#vL2bw}-&^kkN{I)2Wa&i0JZsT@=iw>U) zb}tGa%JL2CuHg>eI%stdrLDUgLr}CM+0Bii_mmmN)WO7|20s|A$AghN*Hn5q+Rz=K zRkxr>=FU7?a2#4~&mM}rdRt3>J*r_J3>N8-pFPah@HYi_z^q90Xr@g~UZ=lM7*!b$sK9CmSb50;pmNwsBN!JZ)JpL-3U=1he{lnVcHiLQ_sDJw~ zO-!U;$7)S&G%}9PxahjX&K7=-3LmbT7OO39qdsx;p^Fj|X}F0t$7;{Fkt2@s<0&kW zl4G@nZFC`)9*n2U{l)g1q&U`pMA5O@eQh;+)_+KsW3-YsIxMmrGqPAkmQyj>B%b9X zIu@g4wb5FU<)8hjEk+yGMrU>z^gB5HO1d86y$sKnI?~HH+2=mMutYM=(gx*$pEd+t zc0IF|e=zRj4+^!TAJ9Fq^h6weltl5d+9$i{x2Qdib|=+*Hxp#?&kiOu!ohu&uc>jT zhs>mju{1S~{*JRJP>eUm(chAAW=Lc;_S3{~CB?hPTJs&x<6ahGI0wrS@x;m>q0@iF zX#cZ|*LxHCZ*%~frSVrx%ZR1H>7@t-aj`)UwCg_bQ*#W3$LX=u7(=!=nw^H=##=FT zF_ucwct$TAre%C*TAqjnc`{|Dmi2`QUOLpMn<*whw+*mb==7o0U(ul`?ZQr~HJ*PY zo}cZaYX@{S)1E`CHJTEoeYlhMMQI0j(ycMHG?rKYv^+RieKM*~r9&xY{cBoAnaFpD zen>^tFYu~8QQBX3(u+~r(w%foY8k!`#w~EX$oM~ps4W$3+|S$Sh}4vw>m$71ouOlq z+5oCi(U3@O;|`i+?1w`NruP+u=i;Ca<`d11 zNNrYf#rO`1Ay=x>pVIppGi`V!UK-npfG;HGy;L$qX{9^p(|+Q9RVsal-C0NlrD?@G z8t>t{qh>l=7c*0YBwz`J520| z!oDeR*5MzV^_~iIJMg3N9WT8cMH3^n#_cpB3THxSR3AE%LK%_T8`~){ie8JR)IO_^ zP)els(soLUqNn3U{|5D`(WuTzTgB|4uHLjfQY+g|myJ$G8|-{5nm@r=zP}jRj`XIv zc-<-y&dNaQOy)I}I>hLhb-2SAC9%{EdYQS19A%}fe~xa6)Dpmr{lxzdYov4S^ydMZ zZ97#)LN;k;-^^xuBe5(L4Ewm9mJZOqYOQGrGts_w?L;dTM$#iuG?`DHP3=@PK-=Al z9(T4RD>lQ1-yTh~dav)K0}f}Wt1GLO==Cg z7oXCNeS&fL10sxGRCu%UnV%{n=*39- zT_2p)qSyPE#__kUO|sOu+)JAy8g|p({o3(u4ST3{Ki!?G9oj}EpbOGEHDQ+s(EIU@{)4Tz%D1TkDD9K13oDUtME z5CKse!rlV;pp23KpYim!Lk5L_8n&C`@ERJ=S!hs&(ml7wC}fG9Xo5- z`e#J>u5j(xR=USYZT(9N=mtn8D%C}&aXc{NfbWSa!*$VnQ;w7KaRkK}xwaX(u8XIS z6RA(4GFdb{kvE*ht69B*{vN7TY!$VFujl&9zwAesi^{Q8izdHyt$&&x4%en{&DgoV zQ*`pz#vWW#vNmQbZ3(9#{Y!7hVHS~ns?m0ni|$IKzxG#BC@wUt!5EJqA8_u$0jZ|F z^f*F4_-Xb4to-1t*+9%C!E_2%LwWkZeb3lqk5`e02o8 z--&1fjTbHm%?iOet+Zi|vIi*7AZ~!zCaTfAdlu2F#`fZiVOp87s^%;C=22ed0Hqqa ze~hC)_b0tSs`c(%c9nP&h)>^3`;)XAusl49sWjs&Ru-i%J%TUE&@KIS93|xIB79I4Uzp%Z z=KwtrM;Ai1U0Z}9ld*Z7h*frC9?duOR$g2&|D0Nlma#K*$*2@^glT`>(s&=EN5iz2 zw$P1Xbd5M8wpj92(f}ypLx}bLxsqb=6EwZ#@_miZ?IULTK6K0SO14p&lod6SRy=7+$2BR}a?Kn}WedYG9?aYo)(da=z4pLiboKCCY~Q zc0<-n!_-}H@K%qY-4K?L5?ZwB~4+e{ABi%Chj~%PJS)F=1=^#!EHBk=a>S>HW+B9{0|t;)7yn zlJNpY-oZi~5gLvoLOU<`XW~_>{dD&8ITB9Ge*Jl&zsCtzKYh`QruQyQqK(F+d?>c& zgP__uT%pgT?Y(Gt@3LI_9*@C+hTd{4T&yw6k5+hh{&HG^FRvTcwLTg)xWCx#C08%) z$IWzyQN1%3OLI}v6VdeR-b%Wd>(5D0Tgm)qmUOX#zvYjrs^iN<8JwV^PbF>j=3u-0 z;d*ays*dvR!3!3cKuU!7LNY!Bcfld!*9bX;rpA}rynD<#COQcJtJwV}t*>_9W|8om zk#MT7HhVMe>t3982a)pVt6tk4{I^^R7}Smtl~TRV2o7>h2rVoXg1dz(o?go_@bCiaW-1bYb<(9 zqt$}cF#1zM(}(~)Vb`W@!Uiio%AY4uczaS|;wJoKAvmgsL*)4E5aLM?=TpYH4r9+d z5*yQ0EJ}~FlXDXtc;8O9iu-HqCEDfpNwJe9lsxguT~sR~v9!z@WaEGY!Nx+`vO_!g zK1KGTM5I8gMqgoNRG6J!+o7$0pDW)RnzU8#i$2LAVC_O$@xAuy`%O@RNln@d?;8$4 z8X_Y9AA0_`_$Ic57E0R8_pkIkX8+H7{vY~{0977hm3N97Zj>nUeLD1>ou-TXYo!t` z@E$%=BSg8zPInt(=(ST$RKpJ1x1ChOefxE9?eKeamqerD^#fEW(X@Dd7d(wDCF_hao?+7}Wo#JK_PDYE?&pGU&narV|0z9-U`8tH#C(!Wa3 z?thQY2EEH)3DZzInU)yp?X+RO9*Cqxyn07$X?%C}`4+mvsA6q`<~FJxXQ7*ov_B?j z(eD`})0;}g@h_U>qJEb3?+9}4uxa0KV+#L>t}Upj0Q}L#16-?Zu50W}`NV20H0mtM>bi z6oI1^{PkBG4GY2PxlasFKr(o0bwWKYFjJjj8=tajvo_Kv;xrvSV+`4o5`Ac>yd&Yr zoDVL8yh5usWFxJ$(sM?A8;mULc$VR2$~WqJ$f{X3(sS0%mIOJ->aSu--J*skZB!7k z{$0`Y;Swp~)Gv;*(KN3;UTb@oh8R`fg*v@^s_2Lb3vZEqYB{0ZQ?%@`Og+p#%Wq* z=zDA~VU>+<>PO;R#*xMwP`&8bUu1kV2JbSMyPBcGhak4(uEGH*1R!uG4%=r@WnnnY zPaY>ugKLQNyb(=5h4X{Er()q<*lM;>KR>ODsAGHm5J}K;XD%Gx#C-;{5>x5^41GIZ|qrHWILRkra#LTzulkTvHEry_UBn=)_wPHRBx4mG23*d^aUW%j4Bo z-BPS>zBiaA#~0W5_tVDPQ;yIxEi@KOgR|q2{qq)z;;EmsXm`cZd+}v) zNZj9|J86LNUH~8VJ&3gOOpPsCmWYAn$|AlP7q8pUt_UsuxkYUWYewJ%UftXJmHwdU zuqX`7Hu{sUb;XGN{%ISyv@`yjayR7DcL_ye3C6m8@bnFQ0_4+CtmH6}+q<7vyWl_b zg#!}p8}h|0S%*BB-ESFL-#}Kpeod=Z8`rh*VyhwzFZjf~8wg}>QO~>65u9}Q#Sse~ zuY}-t`gw8cvFaFW%yjU=qfm*E?__Mw4}x$H#yu6!F;~uGEbxwidtqHzM#ZsM0@SnYYT*G|6$nxi27(=+#)=4G_xXTE z930TP#E|eK2x6m^@x()2c)72^B%a_O`EZXx+dTHigRgjuSVT=IqJg}RmNKXTehk6f znC#VF?ZUt3(O}lM(YyfW?IxOne-nfX0yHPIw71A_E=|j}mL=oEecdmf#DWi8SJ+U2 z9%9tRo5{neblzy8HmQpOU8u(ypy<$2L&aFjqI=XK`FY_zD5dY9FS{BfZ9;&KcTq=3 zX_P@`sWaPF76Nr-WVIlxXv(U6d703mrk*+NJ#v1?D?LOnbkWP*S!E8ee?$~g1*z}rPz8C~GM- zcG}J0y;oZ(ntY;*e3$93y{?cu5S_x|6sfGAF=lbWY9vnP^scLer{#9hy}e5DvJHD%*njL*YP?xyErW5y zR`Usi1~7R%(;wtx@LMhg^F;2GKZ#mD`iYJ^N(TrstYtUyM|rfzQCMmh>vwGN{H%?& zj{nw%gSTNp8+p`Wyexpi-Gmluf4wAHzTIf~?w{y4jw_720SvgVJ1hFs&*;-;M`>D+ zMe)dC^a}^x_QFGaAT+J?<5DTm= zT}cy3Pc&-{h$6ZMYZ5ihlBiMRJL5HKVq!2V`}@q?Ma_Hf`};%Od+*GdGiT1soH=uf z=iQ#Ch@QI}BDA{oo^pRt!%YssOzGJQH6_~7sME%s8cLBIr9Ste1o82|P;#>uP@|B6 zISj3R{;QZh^S2;V|68hd&>o~=op6g%JY}caNzMh1Ddf&r2)`^dkdLEu~q_dYn zC@*A3ZZ62F=gGN(O%QDSK&z9YoJ)s;>;4N{SB(hkff@+-(%BQc#~fAkYk*L$wxDzHG(YkD3+6PD-4sB+b}%0+;&ysaehzK zi1M(99H$YbtUK18(7XL}vtufRibl1aWr2f_n!!O8P;+SPC;GvWap9wv27Iuqy8|CA z2@FpduNy7&x4WF}M5`~*3ge{;=z@E38GH$_d2wZ(B2>^$7MdvfZRAUbL8JRPJ`j%y z@SnQNNQWk-&j~>Lt_>HpQ8c^UT|Vsmyd9q*lzb~@N?S1v-aB^MDdc(H;=Ll;vWDSY z`+t5cX5+QHcncQ=xHXfd4(_h{zlbE|BDY9OM!;5KogVkNvzi=f5 zQ#~Q#!$hqPrg3h6wHd}~_G-d5Ly_u+>WFSQ&jOw5V2^h41`2W`JpqIJ1iR}zV7$yN zR)iZspE|e!Y`Gym-{uB{Ua*D1N2fhGE%(=uY2i|axUYnjtH6ijwoq#<)6fgal<6rA z%t{VMGeUD>*#-i8Da=;jyoOFn@LO}JSL!l!OxB>ZVD(t^fd z^FLMR3^2rin>DMw76dTVaQQEQ3)|73t?JM8J$DV^Y=}dbA3qUz427#;Hn;>bn&?I# zRtrD)V&P5^-MFnvbx-T4;7@0@KHR?o*9Pv;{UZK6{6P%<8f~DGL)Rw#X@{w*z#E$f z$FxgZRqQc$tA49h^>UK+i^xPs=CIP=VW;GO)c)ZQXTz|Yy<0ozpS8WU+ASIeC;vcH z>sDuHxFvv#t{sKA;9dz>xgeWSKPSW<{BCUZn#iJ^moe9VY_a!FFwaY~C=aq0}}s zdN|SWyN^fEuA`i(*Kq}q)D-&bb~jko4Ucr;4x!vhS2!4<`TuP21{e)Rq>u}pIN zI=-?YFQBK~tAL(!EruxUjVP{uHaFD^zmTcY<|@`uj1{7oKj$bza9l2eYSAMy5zj$m z^P%^syTwh35{n{cY#PRHi>os(0^G5;xM<@AA=rJ01VNUoYg-Utg+_j;9r(L(t9NnU zw^QPW_xa}uAN;l$7Tk52&r~lg7f2K!LbPzgxZ-ZK?QpJ@NE6(rF<)F;^$2J6UiW=; z2F`G?uhCeP!{prvF=RPG4!NrjNY?5b`bju`-iz$Qy|zWGC7uYj+olWfNZ%t6#3Jzb z-Iv$?zX}57Xd9*zoGn3NBCO2aaISL&?Oc>}ZYjuv#wZES2xPE1#5wl3m4`L=)Acyn z-&I#}O4z(t+;S+sY3CKs#N(Fp*k^7!g##ElHz_<{jt+Lbk%F~CaJ4BYXb=*XXx@UA zQKKqq;th|K@t1H1vly=O3xXG~@i3xX62l@b6gz=X?DW(WJ6`0n%;08oN4#J=sSdvE z**xs@vjZJLEMPl@|HgMY+<9g?fdn~$bOaDT4TuNruqyCX(8k1_?>A^D+|SSp2Ij** z^fF`!gLG~XZG}@%Oz@A-R@};L+myOE(RXe!VrI9qYmgRzUp;uIR#B@d!F`@9fMyyg% zsa$RI5wP;`!+d%33_GQmXrjB}OXnawfrvkC#>j5gkK1=5(b%~tmzt_s57a6v`!riT$$yCe*1)z$9W4^6N%L|{J0 z(0;7O(3=%+pze2MO!ziw2yD_v$NK+DutbJv#wKi_x146hF#2WFHxQOgF0=7$2W?a~7dTr% zX{#Phd2T>TJMGi7t{XVu+w1G`@y2>5WAbH(+YAQ@RrLS{ z#j~dml!vT%J=D)ke;M*B8+4g>J@GPm-7bRy9t3J5iY6K(@JFOg@`3%=`faYX%~jAR zWj)N7EEK?B)oQOo*E^Z-7X(ZAl((qq&-;hy1o!J37^`1KQ9 zTw|67Ab({A3=Fz#&8&cRf&W%Z#Vwqww>DMW@>2T4$0hck7<2~)Tz++4g8F&*5KQbE zzGImVD28Zt%l|~|K8m6j-vh?6Dr}N>#{w^R93Ism@kQK(by1SfqSHI=?uhlZqAR-0P{#)wGP36i#^rjYlDp#X&1ZpKepN($anr8@}9rF_Yk!Z z@=tFu9lEjCqWBH<)s=Oz9&3kt_!yE>S>b?mn_gb1zb8pySXaPmLSj9lKm&-0SI7is=vw|HStj5{hLt`2_* z$rvx&969h)2ms@>v&3kOo-aS2h=a)x?O>9Em+f#E6{nOaJn&_Qd$@Cs=%9F3?On|e z!9oTKfLlYXg=MUp95b@btG(YEUe$SytJf;G9mYP^#@)pbBT@B{>NntG;Hia1 zaK=P%Mo7Rh*{ki0ej8ULujM(45T;h{N`p7a9br7!e?^%uf32gQn@U^k!aZcNcyZHS ziExDMDz1;X&>lp;xWl;Wi%noO{_I8Hxy#qtludMLxjY-$q@$5Ws-Td5TrR_%cNJ6& z>C$4@fTT++EQ(jf71z>Yw#iNWuSt9O-UwTfbg9W=2&9j6W&PMi9bnLU2l8?bm>it5`Z!iEx-pi+AXoJTM$K{?d?qQ_7jQq z!`n+1rBRg47jIvc*qkjiV7c5rU0Mwpl{eMJA-h3HWY;%P;BvVG@_);afL=x?@ReQK zf|Ew;GC32$h~Ks#(puJq^_P$$vmLJN zI#?6|W)cSztCOQ?(=r(@&u~EQ#T$QjncN=5BH$6pAJ=YCPuKhDDB^YWcIh&?4}uWM zJ;}UG4osJd+j@9G^yPpDvu#1KY0Ko!>CzsH(w;-O$_cj)n*D8d((B|@8oo@9PnR%> zJK{4e33Qxh&w0=r+tl;vQghq;cH;fx9<*_rdI(T`fhK2}V2I*!P`b4Lp9M2LXd3{a z;5jRA{^0%1hk3AlXud)x2a???2P{L*-(80-*w=smY=zwbnH;D*cl9d}@ZC@eA_Yh3 ziaYJ!rhY9^j(9xdPKUOsO$bpS9*?-wSKHK$60)_5F?Xk<+thVf-o)c3clvgl`m#j6 z;<479e%PkIKsi=9T_eI!D<{J7wmxV?c-Eadea?w+vhBS_gqiNtp-vD%vcfOK$h&d7 z%Gr${E%hG%?8a$y!-j5Xc=vUuKkIonG`xd=_jcY54R3FEYT3@aq2c|v8|fQ(H#EGV zm)g{zzO2o(c1%J@Z87JViz_Xx;u8!#Xm@v%cffI6An(s#{m2LYBRA#)ixsWbT35=h zlB2}b5Jd!UEOujqcZi80_~jI@h8h0s4n9biE%n~$ogo-AI|xwIrI#!Q?{ujevwIuM&;00gd!#rF<1%dzlQx-^A^ts!I7Myzw;|zUOcH?4)OImwDHF>ga+i zz4{58vok&NwdwLOGVoS+xKc@_?8_G)#RKI*%B`-f=LS)x7Zva_%Umf%l)=*EEb|(8 zv0lk!TVJN`mGT4k)-%7#|9d?<*DBVtbZLjh&?{ZqZqck-aYz+wTe4W&hOqM6oKEx} zCvXQ>=2(xXwXf$DG)u4NIcNoc{kIFv+f=;n^*m8>A%FF67xo@6Nl)>o6E5tt^;Eu8 z?uEg*sLdclM_Q+o{pj(fGM3plErxc^`9v6y!=b2)^tfUkyx{^0Kr{!SRW2-ZJ0jI~&&!F?f3Kc|a1;8qcAvj(79SdQ)^oJ-f zQEzm^eMJ+rZcl7he-J%;T3hpVRJ@theG01l?xczv8+`{Qp1b-7$Z$N=$sB!K(b~%h zExhEP%&}U>Uirky9B#bK932ITGWVFn2sIODj@2*HoyCHA%?mWX{EHsWUma|W?CBjy{S@v7#78` z2wZ*GRI?3cy5F0s>!TO=FOz8QQ@xkJ-`kGZ%{V5YAtz;`F@{&AIXK9r^yuCVmpLE!St0BDPK|D)&Ykfs)tE{{L zTdL!)CM@R&d<+EC`ANridg*K~YJdFj(ZSFn96$VY(9NdcN1zTi7qR#eq_cUb-uTf~ zXOq_wXVbM-|;s?{{$ zH5%$-^%nrItXTVM-iIy*UoEj(e;sXK&H_sznt|~#I^mk5Fj7YF?gp-Cs@ZO`2JQg2 zH=3;aCR24JvZ3H6MCVA|f%&u@|C;cx(L|3ftwiub$qQv{84#K^aoOJyc+8}BTwOj3e+Xlg#Y3+f9}JJ1{hj zCKn8O6R3fmpYMJl9L$70wT&pyWFp&ZbasIZVe}787*+lF`gMF6L>4->>@KPqjyBY2 z;{v`ewyk**)*bq28KyOwvsqT0c#ux24tBxk_Cf?;P0iyuPtfP)BG@Xf2-@9WVwY07KGC3Z(D95(%N$wd>cuY@8K zhUUK*`ChZs!jr5cdYIDXe(^&F&)S2i5SJ{gO)zT&hgxueLhakAfC_@xlYQduXTq{-@Dz_#z0qB%g_$?b{>{}hn z4Q}c&zM1dC8Vgz$8s!qoH5eYmD|oybOXbn&QmIAB!t)BuZtI?c>XaxXSjXy25k`J2 z0dsg)V0Fe~1tYl*?#uQ}p=B;sUclYR2Ma7F2)M3@!rVBjjneXJBdEsN1guKsZuGUw zWcq$S=Ps<0;sCPy4qqd`tYUR{LLJKJ@rCf6D0eCIubG<%w)epv(eYi?t#)o+>BI{C zTttQLJHD_+&O=)4Jc@HGorq8qa6`D|12+WKg%8*YX>Ok5gA1W{dTPF$pDy{AD|zUZ z=!q4bbBU7(knd(Z^OLqEo9`Ct-IhUNkfvG}1=RIlsaAo!B z&;|a51)?8c%;SO^Xzqz_7vtD}m+0G;s#oz&a+2%KdGZK)>1l&rkZZ-fQW-KWxHb;Y zo>HN8Pjv&JYQ&oBQaXh$w~7X4&byybb)H3yuV@HNE-auS4$2aUwsGXM4n9N`K<*n{ zfS0)ymm=pcN4vPxiE!t6yy1XyLmcO015PqnDE>IT$_-i%ZpWd^Kwnt639PrDblxjiydm$SQ-i>4KF+Tfvc}rqNW}WRht8639r} z+KsPmd178);^~IBysk58)JiE4=~0r6G5Eg+asoP21KN2pHxz420Ak(mdl0HR_<*&4 zk*{I3ud_E^lp5!T(TF9;7@{qhqA+rh$X$7~4HTE?=T*G4@;W{BBEqKCKcJ&_OK#ec z2$0X9$yazMaUy~od1Eo9yj@ZZS&w=<#McuBd4?d}!-8lJ38LkRS<00jys9ekHLPJV znH;h&rYUV(Oj!<9YMd2DpDY$oUN*=9f@8#jlW><`7B5!A0Y&XigB)dn7+L@*3?pSR zxj6wmp#dl~+&3(|QLLpVjadd7sg=gwd`=o-q5K--zi7|3USMMfail(4sa}0eDgv8@q^ft!3BAy;Z&f9NExCj?{zb@qW{|0&wAeQ|&=h zV@Mc9ESfyU8oVF-=|Pi78dzNFX76+q1u6p%n(QwA`%M*r`%OGI3CN<1tk8pA%GhxQ z(*01*yg-NUROk=lQ=ba`er(p=>Fe#D)+5CwF?%Xb=wyGTJJimB4v^CBSzMygdmN|n z+b@*xw_vL`9r8o=nr4Vd&|8US!b!QqKUUoIEeqhOQpY)7uMR7T*82&+tN+`iBN42z-8XxhEg0)EDT56+Ap3J^xCJy=|V-XQ)Cw9Zn3*>#JuZi8QPZ_C~s z>E|k_{cXJe;1@F4~@igLTd92|19KrL$1m1(htQ0d$ z%*f~p&d$+V{SHsxKLZ2q&OrAHalWD7=KdF7i7t z|E|r+`{+$ixwDhJt3;8&@|y|*U1GYhRnKGLVpY%Iw71yVqG#AQ`L;wjV8m}}zj$x$ zX%k(~SBU1flP_x5%V(_qc)7ljZOo_R`HF!aZYRt2?blItBYQiazQ|Xm(dc&a6dF2? zy4NvlzHPOdYWqMPF znP0vw1Rw{YWIRen@sgqWN~2bCJAI&)ym^qF8*AHv5<7VbUB2?BR$?_R(n=&8VohUh zjVQ5=mpDCEN!3au(hRLc#v%6hSlhcO@hLB{W2_=PB;4T-^Q=~4;vx3zSQa{u%^hod zT}`vS48ptw!n_8;yaK|!1H!xo!n_H>ybZ#<3c|by!n^^(tU)hUp%>MFzna6JG*;Q7 zVPKNZxHOt1OMljy|< zsOS(olV@u}B^$4FCr=p;w|hC0UeKyMaER^7qlc#PQDybwf}$D)EBqs?|@=Q;^z^ zqgqHCwffKPXSc?ntgFqt>a49jZ>39~5>GGr$ig@my%Ozw-N3#XLw}D^y3jK|vT$ue zujpU-H2)y0AH${?*!nSaa*XmP<@m_gX6Emey*-A$7^9q}L?8Jy7?R#^X4WyZ zX^iqE>GNrKGc%2$cgHBZI9l$828zz7EzRt)F|=}w^0D^ved_-jb;#fNB$e-@=-1eo zF(i*smeUz;*-AIZ3X0FB8T(k`7~7NR^lWtI04HtU80Ar__m&?KtZ;cd>o5j0%GEZF z8-IDv3s6tu(Fc=F!X$LH&Ea)|#wba&$XiYjbw1wCei|*P7|%c68m$C!oV=i)e0nS| zvGoi+vW?Y`W>d=8`q6Z9v?8L}co}}9*lnz4bX^o={<=XyoUS`ZE626k-_qoZa7JGF zi`+{PxBcgA-sr6-s{GHGMEcP$;g0t?n=zWd*m}bG%5ng?$3JId{{i#y(b|;q!jw9b zCxHF3jYW@UU(2l5=(>;-2tyU}6T(o%{{%eZPjEa^Mk~T?z{~I>eWKN|ZDoIs`roBJ zM=P5&tT&KJEB*Rbwr><&8KtbzKDm&@26SrsJd$>*kWDX&nK8g zS9kV=y0GrtDRo}mjT7qAbw8hi6U5n5aDw>jggU+M{3-R}Iy#{i*IhcHj;~`U)cm^3 zC)81Ozn)OD>eLfzM%|SYYFgcq6KYD`^%H7*UCRkIrtbF>YGmE*6KbEjJ15khb$_2g zRIdvs5Y_7!PR>70fSkYaPTmxqyqJ5plY;)B&PTa*fAaDUUcQx=zs1Y5lbrn9a+Myu z@38w*_wAETn=YK9b-8f1?&>Lfs9RZ=r`e2L-lulFJ6^myZs-ZGx-j?d$cd&vG<_~6 zd>~fyj#vQrr1!B!IVXM)XW86bWxYn}kBFUz2BG$GxjWx4mClePCHn4svEbv=6t|WA zmLt)Tmx|S2x1Q!NImaE?!cOII7ILeL`ibN4SB?VR14n<58c?U>AG`z|PUk3LT1&mD z{CrtEjvDEl;s>cdbx|QI{HUT-9Y;4e zM_I1btR!}>3;}n}$vIn(^O;4Jo0(%Iz4VwIEeH}O2(tHFahY#@M`)^FSU~m{i+N*J ze{MZa@mtu@k@f9#^dz$Bef(mv`pZ2k)ox~6N7e=Kkq$Txtb>m8whxa~hHGu>>8W#= z@NfSt_Y}yt-^><`d`@5HQeHjt8%aqc zm5*r5D2m*{TC*u)r1Az09YxRXVArw}o3M>|fujPzQ9)uW(Kw3B3WGRD-N;s+pyzYN z`dGb_?aZbN*-9}@%cZ@av(K{W`)p-2P0yu&f6i(+IP6}$+OBLYtV6VFK6PwyHm%P_ z_?dpWl-@{-&X%>XvTUl(Mh360x%B)llKHEt*-V;k`wlR^MP<_i*@~S`<%r$kB9(1nowF%D8#Z_Qa%lZlCS}{c z0NA}8YL==qWKx+XS#6pb)@O zsL4{!Q?Q1@wyo^3EHSISFa~@p2Um+(9f0CuR?At+7HSI2wt?zYTZTHx z)}j{MZmSR4{#FZYf2w)5_tjimUp31%K+UxMp$@Tqr4E8Hmu&k~jfX%O3t=wGwm}WI z-Bd$tchsJ?TWXN)W3@8`J4j6Y9OZ8NLG@r`9kx}RKF^JS5gPAO;7fC28h=I z@ps-@rxA*u_-xBw;K)P|q9 zq=by`iu=Yr7@&iEnlHnefK2g*WRauX(4Q6#r-1C5(dCpqi$-Q8LBgAZ&u+*?U;B9& zotxTdgWh5qg->IPA8mtX2ed=fZ4=WEXBVEhp=C_7p$*$Xj#A-p98ltalC@68Zf0GF z^Zvj`oqpNKe1_Yefvi0bvbGFay9~0n0kXCN3YLR{W>D~1P|ySl&PAu6MyKba(?)c9 zAzE0#Tevn%iKVBq1eIDpW1kQEr+|HQ80=H?wa-s{##Rqw`X~Nd4F6;pRW)AyL+b!+c!)eO}n_|D=N=o&|(gJ@ra2Pp;DN*#rbh(ExA&9_K zq|c{A4}Zl~4XR$t3w0c(74{j%Y>(5|!;}{C`%(6x%^yLlX+#NHJYBvZW->PzZ|ki<&+0cgm}QwP@o`$0$<|G!!0EUf?)9+J3C+P$jBq!XctM19g)Zz_ z9l028+Upv;us80-T2Obu3wz^NURdnE@xm^1+^cqYIC&0JHqiOu^y`P#{f^+_;VdST zPG>6B7XPWnOctC;M>Cb>mdL5bU93YU?afq1@-G(Vo=Kl)Duel#a`smSeVmEFgOSsW zx7no(dMi`u%^zAV{?m-E?05!QGnIDy%^m*6g*9ieCm*AEnMwbVsl2pyws8o|PZKY2$Nr;d-HtzJFErN#8!J6)LXDLWM7CP&?O#8ev#wiHtJd_QJfZ%JEn? z(AerfTgwg1PV4FY45i1~r+D)nG!QjYjg?Ch&8^Z?M%JijGasdj45bA{&`zhecC08- zI~9;nXpNroGL-K*-Mu)y&#)zWO3P68@;6azfu8zjD4+8$f3c_Z6q2EQ%)hv@se0;^ zp}fVv++pMOBxNW?{7V2Esi&KIWfcE%l?~R@WxX=QlFGlt>gkML8NiFVv)+0-rdL9F zv0JR8p1#m4UHBIl=AoxLy&}+QWi3P5+q3AB9y20&0lPGmL->`>4YlZ>#zoQtH6zRE z!)bi&@lt&FV&mShC0yyxU${4H3s=G{dZW>$tY^daa7xbPuQQd74ST|!6Iga@I2KMl zGMlBRjfi+Ly?(Kd^?jPf&Z7Bfv02(=)=|ZA8EN7-A+kxt`?daNKK*74t;sE?c%0S% zT$v@BH}qX04KLq3s9M~rdePHm)xB}CN;@Vtz8PWB1ClbRacYE`eQqFuQP%YpuL6PwmW8`sS>u6xGF z`7X&8zwWB3>TGQWLbUQLSvQ*EO1B=CyMhW>Ti!0O@5D{=ykL)4?s(5DyndpN{dTBc;8!U{h0m16_lvkg^UbZE+<(cY4Q_E)1YcljLb)ZJx-PBOpP}sakX{VqIqV zT5mImxz@|<1mz}(bBwfo(tUy&eL6|l7lD>uoR%E`LnCKgc>Oavwt6-v>Pxd5 z^x-wJ<*?C5a2yTSVL%G^h;vp;R{u;B`PX_%{6nVF$?C5+QR_N}_Es917Ky6gtfP;0YHUE<)60SXXRiw!9#{v1 zN9LWzk0tK7=LASE&J1Ybswn{>Xu=6&ZHt66i*ftkxbab&lD;i8=(v&c*Jd`jTmN)P4!Tv05 zaQ$2z`|e3@m-F?L>|4ZvNpns)1#T|9=xLH&=$-zo{a|uWQ-0LIAi_QWwue4+p^E?20oQ}Emx&`{c{$IezImZM#Y)y*6=%?DAd*JKec@GDC!Vn zkSynWTMn(|HQWt7tb2C3>NrF%T+6@g!q&OeOhxUa1Dm4?a8rqov=Y`NspZ85v@N9+ zQQ2PQ+{dP`g+(*R<6%c?xbeBjaHHc4#?rdKDi|xzc^AtegJ9+DOV;ycozG0S?aKOH zzB+6SYfhKeTyT!T527)U5=G4T@#|0-Tb(9xOKS>j4-Gj32jR zA6-qxrzxyXvn9{Obr?(+u0H{rWyCSyT@rG&yE3C@Zn@Qex@hjH&AH(9qyuQ0l?!@V zlqQ-kD!40yYh;w1#Su_PXfSGVy~TgID?RTc(9AY~kl;8K>}Y}(>8yKrJJ!HKye*dI zz(73~-8N8g&w`g0*1YO*h;GEYReKiZDxJ;aH+#^L2PZ0BAl`?n@vk)tW7+TBu)*E)H11i3D=T(;mcQaS&wX(WaiL+Mkq5^ARzjA6VETn@E7Sp&1 z#WZ#T^_no*jwv29P|`p{H)T3G9uZlyX(5^ z)E#wxE^1X>PZxDjT{{=mQrF9cA##Dg3nCZP1tVa+1HxJOU+OFP&(BL;Zga&lW^-pV z9X1a(#ewKFr4BNtDxc7qXm3!NDJk?ss`4fsiT>+IAO2!y3YDZP5n`)i52a9Esshhz zzHDhL78{X*g^Er;#?n&Q*@r1MmCK^Njb5x@3iVD^R7+%U$Wy&isAH;fntyR+0V(8> zsvPBC?l89$YDwWT7-C4V8_A@ma2YHZaxzP%(<#b0UdL9w0+CkP56R5*FdayNkcGO~ zdl3Rw`?52cHl-*L{PivbhBhfiLin#v;UaTy;{#gBmy_AxhiOp?M-v0VDw1h_ z3P&>-0{FaS`d11^6Rx%F@no8u!qE(ds5mK^#tAfg8!hz91UUlJ!Wpa;87NlOx;ts;NKh2gOaIT3LG0^lPUH=wU3<~$+*i{JwZ;UcM6mN zn0Ws@eQ@F3O$kA!u+vF!=)3OrTeG{)dNZf`8O&;NGI{h-W=~>|Pok~K=uaf1XZoWr zvS9U2JT=6}(6N$a2eF_GrjSE~MU*}L+xRp1 zZQ3~Ztuhb%jC-4HNUV=Xa=TgVy~MVnt#dXmq1o#;o}$Os(P9)mxp5UuUdJjD0q5sA z!v0|%JvEof(20i|;U8OHVqwxOB&bMIqBLY6e1sU!zk35~F87ah(b4dEYI)B zFpLr>Pij}jt|rtQbX4^SyO_Y1mD2IVe~7N~BXsJp>`M<;Bh>J9ne9%1Wd@t{2<4Bj zPuI!qs4!oc23o!hu(q(QM`(4TQiou9Y;^)HPeee+8W-gnOD-h~e|W{kaGv!orLsf? zOW-ScUWRX3P$|t!Zs0G08$Sll@vkgE^RqE=o2# zTSBq?A>YL?h<#H+y%TX!2Z2Ne*Tili{Z5^#MsPiHu*?xK_g}k!+&U0+ z{R?zut7g#6gV3$6UG2LYiGS?eQ^*Z&dzxe>arO68Gk65VD4iTpKu?Y<<@y$Q-f+8= zLh7iKJxYD{sK0QFovaz9ReNAI&`T%(T|mQ76pl^svAHCQdg|nprJ*QFeaCSa@UG!P z5}bQv_Zvr`{s075-jo8HDA;;(V;oxIkpEpkHwx}E=q$E#gU;jAi(BjhKp}ZOTU>^e zIeCg3YV&m8+-7KiPI0~dz8&VW%HQW(J{>YmmWC`WbB#qFmxvt8?P;=?<@UldH_PP^ zq-j2W?zEkB1L%HbzyVr;o}xfUUI60!Is@1Zg;>WpaGt$>ppJbsjV{G$Wv}tN0uVGQBFv78MO1;J3k{7`G^{3u(N`WQPl6RH$>Q5cxlo9kvzMKN|aGvh& zba9J(?rKkqb>9(!!iS4OXWCmA{So0UVQ)_DZJeuZ+NWddt94|Y%D#(b3n$RN{z}VV zk|ocJi=?%gZ0b~cEMNWwQ1?1dmM5B}HF*xS^xV~EoYn&(DJNgvi)ZI5TRqzi`U+?O zi23cd-ZV&%$HxjSHYgTECyEnt!ajLC9e<^^&PtBIoENs%vMUs}4)!I7Q8ob?H89Y0$DsG3_8eC^)#~)+38BxZ{ zE&pExMJEf!adSg+ZIhYaYlhQd-Ya;b>Sio2!(PGLl45Icli3>BXlC+b^iGU2zcTfj ziHyy1`^wbcO%xc6>pI_RHZg`TJ2xg%$~>5G>aUn}hI|?sQ&U_{ogUz_Gg6~zx^%=m z>R)riytxBS8m0Kbu>G=Gm>!2Z8fQhqC3HiuV5-KDNX4yjcqAUX>8A)>9?+2i%%^m9^}X_Ly}#94Pr;2di|GCFnl1Q^nn~p}BY!ez;%}}EFgLuko!7|Zd!Ls%L~(0az1{Im z5&fRq_)H`vkJ8?T(z)Ckf3ub>&evB8FdN!8E{jw>F>X@h+DP08PNuYe^yCA8yVqRX zY_8pJu04nY#$mIg<_aI)_F%k@aJZ=S-;XoJVYAhLkNJEaOnbSJtyZKLf_%bm*Q$q* z7rYlGn$5U3gPqv&aGc}04X}%}*Bn{nuInH*n;p_Y^RlLU=DC|{4w|vBn+;v$b{73% zsNnqS-`BD1hwIXAym!Ga14ZH2hDvV0JYv z!Ei>_f-L^#7~bPrR~?}CK&K;X-QkcRxDSW$r^gjh>1gM`7S)uNQ)QmUc;`p{2jl(4 z884-$#(1A`#yb{C?Q-Zs&cw;|ZVrvjVV{kqInhcE`G;~ghId$uR19O=QX@E}64>*% znF>ye{9Y)msNv}yWYA4^qz0HBss84M7k1DiIH~%ZSAsoMZ}x3L!y7xO5aI;~){#E% z6N8UE0I0UuSP8K7&M59O32SHWNk=b^f*HylT9jo7#3N$7F1}lVK3vIu>|2lI<v+r2Jsn!x8wUnbYJCm|c2D2m715`3IQoEHqeq)gJrh_TZ9GzeT@u#H8O-0HN3Ht ztegz~AOq&pdpnUXo0EW(LX{e}?W8B2kh)+zt>}M@~h9V=a&XwVR1u}@s zqN-du8DubzF!UE>_-7q@dj&m~%bgdxbLWL-*M>8Qkl%wfMsn(ul(MaedhoTGvT|il zQO3pIuxck8--E(?aY}vNMkzxwbAfp&r&(efCDbJC#V?>(U!-QX+I@F(cO(qE!NU?c z$9U#04e7g{vO9eZhmCRL9nxb)D(+P}rDhh-$qXF>#~G9o{XC%))3?RG9qBW*WRu(7 zbz0CJFM44_+c}D_paBL~+^Oubv(@=@AyR4KO$WfyZIOk{CHw*Y7|qfXMqR_Bja1&9 z?T?^|IoLDC4L5MB3G1G!;3tfhTV95CttiD^Cn}d@LDYC&NBR zX`;~iiyHnnOd{>F)&Dkpms&O7B^YfU8B0CU4@!?{=(dZ#?8X8k?s?Pf=qbEurfAJS zWc9yhIzMj3?)y=2gEHg3Mw7^EVo||(tP@?~eF(1w;Oc6w{u@G}wX5|R*NHF_(GaN8 zdzhF#t?4q1*Y*jdQ?kOkMTr+8Ycr6x(P8q;Y3%=aum{S8< zc#Rr0=$aitlEs2%M->`6%T*m`4Mh#~gIz5wNVsKZd0rkBi0dOAp_Ah;?3cj>tR zPFlB33PLxunv@WAfaTx4Ee;n$qQ&8Dh_N`lz*7!CCCGxBIs;5e!}$(s)n7B!SFNHI z$nXLv7m*ePbmuQS1(5L}^yb+-+8>VI{5!1SsU|W8u{~kb)D7I&3o9e7568*ra9G3A zCYl_?J_w`t_@`m~(@b4i0#9Iy1mpoql-iCfHxX7P*mBFeEhQ~Ba9kHEKJ3{l$T+-l zyY+9h%n;NeLRS{bt6$;OnRXJnTYelbe~y>eK8TZ~uc4PU_!@k!LncbhK;%6%fwlE37+Awl zk<4MBWDi}L#COE*MdT-%gAIu=lKzFw3Z?d0$nA1fZ|IIDp;V{UnVyPYwHtR(^{DQF z|HQ;939T7qA)k@-#R%(f)NdqvG>7_xA#PH_&N5+2fsipApKTN9&nIbr71DqCgw~{4 z=!a}-bSa(4hUTzEu5=|-=|`(az&>dYEz}$Majt-V?o-?*wJy_x#Px6MX!Znlun(I% z8p-L9`|ebqn&B2&mQACxaPPowj%0&fX)(L>>%p31=BnW1SgXIszVxk`KFXp#!<~+j zuhoyxK_9M$(#1^q`$`n44F1-v9=7-&H@mA}@c&%-9~ZTLpVZw9RZ!$3m8m_=NjGTE zuyOS5uo5{jT?#6PuLMv&I7~hRls_CIhIF$R#$ZSmZ5bvX5c1cL^;yVRIbLnB0s>tg zK__QAVa)@qrGRy@(mxnmFQ-uNf+7x59%em)gKmfPz(E#6czR&5U|M(eFmk&qpFekX z5IWkiFG{MAaJho1)&V@#w;cZ6&C2V%A!~53IsLl9zsj>Mbjp6M;SkZVb1~Q=8r~op{t%v+1I5;4T^ZLG2ewqp z@1NP}MsFpKr0r$h#8tPUEBzW=Gr63$4{sdZmwp`1I%UzIC6G-gEoqjX#O?K0!3=KG z!hRTG>b_vRI@0FeuzNTbOj|m`Tx8pJI8F?iqk7kmhK{a~y&X)SFWD!}!bNoLAGi{@ z0dI84tUgj1c-B<6^$TX}$bVG^UNhBVu}bSq%61t+kb4`aDsi~dL^hx3&Ys1KaYT@V z`Cl~%LhF#m;=U9<6qf2~(0N^$%`YBj(*sMWN2l6ZLU}Y5D$TS`n(lB8-`Mz~jva-s zqYr5tX?x+4>~wFZsPTM{cuET9jAWIui zj}h28SllG39ry?|6|kPYs6()FiVom4Ekz=k0%xjRtOcJ}G^(#IYohCec`#kTQM?K$cTzDuJaKbWQj^9eL4r-hb3aHUZ4liA zMEbm^l2=HhhgSMuaE4LHp)FbRa2hzs0KY~=R*5SrM0e?(tm4Vo#=+Q`VAl5~ALRgeN3npqFO8e4fe#D?5 z&_a3hcbkS%emdd{jfQb^smIXC33`2}?Skz(w@zdX-8d(iD3P)ltY$fqAY zn~u$3chWJdKOVL`&!{^+p3bZz>KEvkDW8t^P||rh4UM7uq<9=sC?{QxliF7!5h3|r>&@IMNLGCqnSOF znfDr-MQ79G36;UII2y&FRRRA@I`>8f{9I1j<^H%o@ytyJRatc^FT?F3e9$No1~z3yQZYj$hH?EO|c*j*Vw&!=+aG-N0%tt^<@ z`RAfZ8l8TBaDaYkW$tWOD;(jhx18!z-ig8fab|dn;cpE74dcCWK?~F_T|O#sJ;ZzT z>tNYlbbdfIzRJ<#tk*edKDFxO%)f8oH7fC|LiYX7%Gnygl48v&VkJ*@j^OVW z7TJw@bcgBcmNYC0AE#(bLTA1ttj}ZK-PmWt=vFr@8JklIX?=%MP4Jy$BAs+gWKbmQk8C)3jFd|+!|NvaW$;n zBCBCZP3wZpwVk2v>1Ljadu8o@v@MW@1;t!w|6q9z)hA<(y{m(CsuZ>9)ZXpH`5u;X zN60g7W6u2*bK<JQlECHJ#10Kd%b+`BnNLoE!tq)#><9bJoPditQ{s zgXVSxD|!#o6iOX5M(C|3Bdr+jegdE!;P;nZ(*r~JCK$I0o8Z4k(Xe9r(uWNVjdS|a>147c7IL>x z5t^pBdMSbgl}zlS_iyjYKr(?Xe??RrWguM| zQ|$qF`DM~MtPCL-*k;BO3#^ULLlxEPV6YlUg%=y(<68kThOK9 zx34JO2Q~{biEs|*_$qMNAyn{ok_K{@6~xKmE-M_eW1lq0xb-VX;2{I4liHF)q zvl_5ZiUjsneWAC{EVm-~89x;2hFf6&6qLzflKl)NyB3(^r>=#7|iR`sO6y;4bK7$n!o5AKhTSrG&z9;`{^yDHl zopEr1HkAvvl*6P5l|fnFE}Z*%o}yx=_9kaU!OM5+ml25MEe;5GB;#O2ks zBiVcDv;;|a#MhhFLwpP1s+UBlzFX{d(~hzqCB7Kb`Hppu9A!E*tjX(@si({|*+Cz8 z)}Aoamry)N<`Bcw3jGOaz!PX(@?G`t3l^BRP`8A}>4*T&B^bBHXQJqQ!bB?vu{ME5 zC8#|KqlJRQQt4WJ?ed{yfTtN&N4VQXw%P z=N=Y@SveXVRJuBQV)bt^jgzXU#$&Wl(x!EI&1p>Ov*!8`-O;m0kIAm*S`ffP z5E}D*5~{H`JJ=hJ9HU7R>67H&#PnAA9NOD9z56Epuj&2DG3WI5N|GPJ^uE~NFquzp zjQWj49$^T2Tdo;k0Sb=qvT)ZbQ)^# zv*uD{u0eM(kmd^MoY|!Ug`lT`seSG@?20@8+s(sCgBLjs(#bog`lEl);D>MM84ryH zz3%q+B=7I10mx-=&ICW1Pin~Yi5;PIJvi+=Bdyu4wS)z7ka7Dr`=lYp3jEa@U&P-u zqr1-DaQz!f^}sZd8w8cM^4_g$qmoOa+*K@s+;o-dVX%pH&`F|S66Ca(Xm6|`1nc~? zI0y_)C{)zg^;;1%XEL+u9vX*4jOvrklBZdh9@w+oAl(S`G;1#Mk9*2b3dskjQ^dg0 zbespR$7?i|W|8%ph|Dl~AHw12bhzlAlE825F#udmMEgJ1B6K`Bf?h6NhB9tjv`rX+9yeL^9f6f+Aw3pfS~ji_^J_MGRII#R8*8L% zS=Ed2R27UyqDEmFArcFMO2rv#QQIhQT*uYXNPp~IQkpD$#U zfisOOq|9>g`JcWvn7&5y)!xs2-Fz6aU&4+=mj}orfHuUij!u>ldZw5^}v&C0+_X4*7>A3Hl*l;x;jnR*c`&H(4qRGCWVn*4G) zoWNIoBswQUY-3S0ZHuLU#R>{F`bT56>K0A4u@!nCV(3KUVjIJqL*&+&7)_P2q<0qn zF$#sRMv+&4t#HRi*J!#GTXPZjgJebmf!L3&K)@PIP-HB<;jK*^zU5{xT z6HU3X)V&{ckD$jdK5V7%6-IVEu?yO%p{(|bnNG&>o0g6igAaE0S1|uGMU2RrG-y(A zSh~ikwk=M+02m)f8-7CPYcHGW-8i|A5DI$W1@4DAq*ZZpBTBsxZTQ?-${Z(WbLEDT zffqD4PEMd%(FPu-ulAamrpCz#Hi6@K9}eT18SPPC9L%4FM;p9Q0B;d^=5^?QGHb*Y ztS@zlHu&$8aCNP#e^p2QfNBwW#WcPUO%KP=fM_tUnOgca8l!1!4E4tIA7)%2&@cTY zsN=7g+qTpxo_tdcYa#rC1YC2CE)sc}`b>U;O$z32)(XaV6E zn9qr^ree+oL)8==)A&|2JKV3f#Z15XDUnpwUk)Nml!5yqX|p4Q&kl12JL$^>H6?=` z^<~c_^9oIVFtD2+<%q=Z1Mh3oe?kVmQp6rLP@VHdRt8lRu{R7956A!t-u<>5p0)f4 z@!Zw#%dLxcgdyXM!(J~VV^apKjkL?D-p$glrbIf2%#!?9@(L-roKAbeHWfCh?9HQg z3gF?31&)Rm=+D_ny(9G^q8(i{IRY=5U~149dw-OsOD!w^A7$SI7iE?8|IEK zar{RE{+m?F5?U%jqBQ>$jDRl8fD0|O(Qa+q4l_;mmO}K$;o+riw|Dbp+g6k#wY&b@9M8m8QrK0qJ!6W%#Z1L+?_3AIVIBAexd)ZgVg3|^IENX@?A1w8 z?*eRf53mo+4tP8S)TymRCC6sDP3q(-%cFIzvz$X!XQ2v!-OGlvYvzk_YY+tDFVJS^ z;pfJt;u)muS$pfx4E9h<>Adn)0%)Xd&irG4RC0PTN63p znrt;foxH;g&80^gI@Hjk6V^#_gl}Zx^j?JW!Uf_uN+S1k@4T|02B z>ESK2>ushrNhY+a7V8(k1y+{sIBZ~z8O3Gn@ko`^W%Nnku3>fb`!DBz*JKn&4mhh^ zbC}cSp4nuby?RBH)wG5K$b?^PO-98!e4}D0Gl{MRGh}VtN zc^L;@+b&OLQx*W#KNIR;mukpBL^_~2smQP(qAGEbg%GI~V~lMA6she}gr}^VR-dN_ za!N zN%+upu+;#1PM+zelaDBn6eA|jJK~zjssvYh>~N7bU(~6dF&h2&1z)uh1eb#MkYNp5 zGU7Vj_RRx1kgDAi`$WSUQ;zsD;^fk-)Q3##tcEqp7&djJE&=hpp$Y;)M1(2WI-n-M zKnE8i5BRlfHV!|qQNM<@%yuDg);IN@9D@7MMs-Cu=CIxp_Fs4RiTX7W6!J-0oOH}4 zv!zF1r9h$VZpl%2EXcyywBTYIN+Yx41}SAOyIf#dvt2g+hR1PyDq8id99CPx=HHFp z_@oi=m1qGF7iW{=>6g06 z13r8Plv?(?;XcufjSjTOyhcmdOXsDM8Jd*aXSv|1LfV7`9tC*@kAe&x8|DCp0Wa6{ zc(pul0FBq%%uqi>AHGwFC8Kv*<+b5J$22x)829{4#}H$EA&eo(gVe0NH(A~CK0?i8 zcXE>z+V_x-qxsg6$bSa}_LeTlp2OdCUC=KytjkVl=z}s5lJ`>ug3mfq5AY>6Y?K-{ z{;pu-69pT8Uw|0QzPyn&8`l?X{O^K6F`)q$5OnRC%@)EWWj4ZFw|dAr@8_`2YrSP6 zKF+yesP^ZXtuyf5dTKd7Bt1TcZoJnPlRN%|dIv#!d3GR<@1hGIcYK%Rp z0T|ohv+5gs7O}yXZEEo4nHwV6_Y_F%M=%w+rvTeXeV){S*=~Jm74e^m{JGgc&q;WW zlTotuG5|)l-BU0e^x+d84gN<8;Apz>w*_r8R{Pf#z#-J%RDgC{3pW0tVB=E-5$VAK z8SS#A%jzX)cw3){K`+E_+N&MVP&m)vcY#Q=ivL z!6{q6EJyx?oAL2$6tA~EQ2^)LCkpg^BHmLIFkn;QCi_G|sI@4TLs`S?AZ=s4fZar{ zXPsB`3eML@h+^V>1Wf941@{!HHyQR{4YI}5AX`VEQA})zw9W-knd>HX47~f)KT=vJ zyT`S@3NT^NK(53F88xlbhkuRGd?K&XD!(shqds1jgu0%@JoSkHHvA+TkWFoQerqR2 zNgW#V!_BK*C#bRTvhOu%<}FR4mb4f2dLi7bssF;6p!`AW8cbe*HDvHDhgL@Xdi3m-o%wUvQ~{p|S<5};TEw|)i};y< z14b`TU(;HB70MJf?PMCk(RBDF{eH&uLetI}N%|{uuf0dBH?A`-479!k{Ace>FJ_-k zce<9y2SHyD!8`{zzjj3ldu_T;(ywK2PKQ6%+42fkrYee*%Yh70TMUiyD>*{ z)VmkwNagkJeC3j`NfZ8u7WIU;KO27aS@6U&(%sAPHP`AsCZEg56V|$JZHPRmudBqB zFZF4NX#8yboB%R>n}#@1{b=66v{v_Dtr};yHmF3CG6o zss|t6;6%->#qnv*H3;9{C*H9-BKL;3U?+# zJIxu!McCnKE*qMh1_!cNH0=k6)gRG&EB1+jl&50^Y(qO-L zUj%#_^&cIBxq>SmS6LV#*!>l2>y`&ZC-cm`1=?0fpLP0Ky<2!;O}dW5v}N-+ME{YY{55mmNr@5VVv&eHsq2 zt}KxUz$6!__Q{T@ld1|fWC~Az2JOeQwp8`>)bb3wMuXVl7}{r3qs>uW2c}*$9)ff{ z9K8{)yeGVM7W`jXdsg_xS=(+G!fjdXcT-()tZf!uNcFp{0Ip_V8-9Ii8$NI4r*(AP zre7N_Lk!#?gkaScj3OeFM%qKC#cNgTvrFO92cVLrX^wRJYIlmuw5?rW*JUZ@X&(ZV zo4^WWl{+h7)E6(7;?IG<^3@(tJJ^+}HS65Zkz?SvSuCPyD_F}A#?U8p-EU_rrn9CQ zD9nxRVMb45(zxw|BAnzsOIiz!h^L&dCW1OqVy2py!Aq!b(&!E1d-FGHQUWDuqDiXd zI|&w4Ie!KFbDld|3mL`XDxqJko~eVnOFkI+pN}9p(*~X1**lM2t5L4uKRweFK#I~Q zb-p)`P1Pvr-y60&JL(%>H=*;5c`PEdso-#1*@@Jy#(7FI3#W3cy{_NRbL+bN^Vlnw zu&I}HE?V6r!NTtAP%88=eW_hr=CRgGDrDmdw&)V3xun8Lx4?ZCIG-*a6~|CnGkrY0*5L zi!=CxRwi5<=4M815<4?96)c9NPy%|s0wzqgQ!A9? z7fu5Buhx~A;Q*^#j}4p6T?%D&`132-^7Xj2&4N=-T3;f|S?_R}1I)Y>p{*hg zTrn&xb>Mo8%(qES)BC!SpFEmCY;0+27~emo6e)nIqr#* zftr-|dThL#X@39rPT72@&6k*F1gBpSgoE3hwdnus}AyC}iww4(I|BJBo<9!!UV!zEBW?vgP?gfI3P2+4fwa z#P)uBCJ1>WZ*!r~+FqE|4F^lBafj7@vK;a+cCLQx4Ov-14 zJ4AS2v=_23^&RQp6Hd0X%MI|DVEKl|V?#r{We~_w>xqnilDO zOT?x{2Hz6Byh!U?Vk%`<3za@2g8MWg*2Vj=tXNNzM}x%6Wv0g7@h^ejme^D0oXTg> ztV>LW@dA<=_2Kk6bYM3RR?kT*cpZG>#HB6Wj`b?Z7MopSKRJh^YrsneD+=@jhjYU2>N1_)PkyY9xdP!aZw*mbV~`aDXed(sg<*l7brZ8>8g z!U*5%IBa<%M%vXdkCnkv|5bLMCEMP)vycT1xJ?o3$P?Ffm7S#;S-?;k43>7L*ja}` zY>gMbuo&5k2#HzR*-^;;Xo&BImHICBIPL{RM&P9~I4Cw0!1}aLEVXNb)Q7!=3?j%r z5q?B$Epl}=>*~)6?)WDC79n4Ed}NPud~?&TSA~<$pnRZ|@-H%Mz3#e`n+VSfQG$9% z$(I|@D}*y)jpEk%>6_TR3*L>1y{i?s-j8?VFL-xaA1!yYxHS*&hV`hED*Q;_&c31_ zR=~ZOQugSb0Dc;KKbB>izJ3@N+Yjv<+Hb&Jm-~gHj?3E}=n$YEzu%2>=xn=gH$m&D zfo-5tF>s=``+38NT=S-3>zrAeSbeP48vXLEv(b}ZA%X4I1P8^RLWPxFDj#Hf4Yodz zCk;!&^sDJuc3TZBLL)+kzo;2tAC3e}L+01MYxrFcbwduY4XdG!BD` zf^7ICr#;BA!|g34Tmh}R68IDWR>=}8Z0t#44t?j5Lgo;B!}cSyXlG;fv>sCh)~kbEvtG}(>l)FN zp)$aXg1o0A{bYNnD`x^L1}kj-H9uj+ne@=C+O+LCcIGoAxm@ZA&~`jm|9u7%pUI1 z)#sIBC0)VxjFd*+hgs&8_O>fw-*=7Og~j*qx0OU!@&%HV%0MgN4v#NoPoV8!q5p%z zwiLVHVs8=m7H*{tMlW=2H?z%=7BR)HE-xtg{D?&np>=gX%xBORt*2jWF^lXDEv>|# zX$c*xw3tZd)CNGP{FCkSuEri6dr?c}a4%7nwrzW%|BXT_HAWi|GclK$cBa#@1T8Dl zut&61Yo9>xy9KIsyFj%j2vqAN1pU#3ryy>V(6|=+VVt~2w;a0+CJ1_MOcChtq?Uu& z1IN)6(PZW9@tSFhSg&A7!^IN1Z|qHa#fXpG%iJq-)7?_;EVntg!Y$@z91e$Wl=o7} zjJ@uhi~+gl1r@`NB;_EicdqU=A)Otrod)9snPMpd>(H6rD ze$UBga4F5ezw768-p@-e=x0jCz@r0Homw1)(c_Fg6g6WGB`FFghH%9^$SI!tcs6e_ z8#FN>zY~gE{vArc@a>W%H~|rKQnEb&M`)e&G1iI>OvP)3I;k6fd+_%j{kCU7fm>?5Pj5u#@jUXN~XPhlzWPzYjmGrfl@hph8^tSJMu`z z-mLvuABJWP28^CK;Dn(g4%4)7GbVjZagn;P9nP%%?MMEu=x#W2u+oyYHPO7umuIyH z8hf;Wp)YTSJ+KqMb?@YW)9`8nZC3kC;kY|X-i2KscB0reizT-1vP#z_SrJ*X+B5dH zSkvuR<3RZ2vjf08OB$~){O}oiJ6cF$D{;7p*dTUrG}K`D)-y$=TdwR%z7&p7T}+2? zk6pJ4Y>d!l7I5ihmqyqUVLGAG5$L#Lq&s78-C5n<`8(aZEs^#B6|5hw@g~2DOqBn_ z2=YU6MQ+^*`*$EtpPsvZv7+ZczAf6v)c+uF4%B%>!4+w_<~qIp%JzW%>UOAQz)pI` z;Ft&dyTrcz#{XQQPkJ6^S79;5Z>rp4o(da9K17ZJBnPUlQ6A-c5_~|o8So9JqC6q0%iyy zDF2G=KFMxp{aW@L0fMw>w{xzOC%&vz!u{e4g?n@jc`p<)oqM5-{C%Rst_iJb=@EU> zO}sP#*`E)F^c~5Ux5&P6r5yuGlC3WkHeCw58C(CY=#GOikpywMFMun}PpUj*5>*B6 z^@YMnnHKDl`lMIhYeb`>($rR92M2XI)*qjv8O^<1vc#^aRZemVzPYERm(Nz@>T4E zArzTR>5ZSK4j}aurS2SZhLTynR*A2q_N8n);@gBr&a%Y_#+GmIIyNTkGevv0&bksg z7TL>IU>UM48tPy0EPGVrfXc|!b-SM3GXyW5pK6E=ZPc*9SqFARMCQSe?vmJjcZDCp z^}!IoQ16nl;WNhX)l0Qj@>&txW}b#k)Zjiq_Q2WjavghJEw*NCIM3vhuCi0!OrCey z*(k62r*jba^uoz@FuYwqva`p|vFp!<$LU&naI^(BLNDMb>CXZ}4+Z{=#XM&eM>7&s z{G7B!=+f$S$92RJvJ=CNI8@R{Qk2{P;jlW5ccw-=?aN!tS?oQ->=A*bz}#u2JsD6~ zZ(w&10tyuZtB32(Fcm|N=*G3M(`;u?4!7MzXq+X#(- z5C!A&de0c#fT-)3-hMs1@23TNPgoL3EO_bHmJz^U+*GhO3Fw*3?v8!hTgr$&bFfR5#kK-VQAd-@a`98x>* zU^044Ee{Mu@$S;$@S&lunIgOQRCwP|*X1Jn)v0j*5Y>6xDb^J&_t_;>=d-BObw_|b zF~n{<6@GFElhM_sN32EE*p+Bt|A+uVx^6Y#mgoSz+oNauBV0J?`a;k8dA7;8ohhOm zpx1+X_6kqC)WF&!3NNBD;8J#~ZoYy2KBBxx`TnM7GEZA+UhimK>26|T=K!{viA=?k{<(lw{T zw+}WSgx$-?wn!wi`Bm<&qnapR*yRxzz5 zz`K|xW0MKpW^Fl?*_}NI=?DI2AQ3Y(?QIFzEhRy=n1wXdo-?cJahjF|Yr!+OD`Ndy z^^Y9hB=_WRk^}jhuoa<$#JkX@Wekmn@F&i)FF31nJq<38-iDV%XmeX3TW8tj{>ybj zM!@DMx^gskDcySa1Q;AtTc*h^(cIYhQ|t^b8!XI|~!N zcbWfI`+)6Md%ph`yT95_O4R}8uSD;6eu0({xfDcx6%~Ru{~k*0pltr&ESV$IE#u`G$mzzy|9S4Qa9q@wW9HQDNaZ>XoU*?T6f5K100y zt1LPJk%O&w0-x#d0%dfEs+_*@n6)E+4*Ih1Q9+0Wc#GZk7wFD(M_?ve+|nJf++%lE z5`2}f*(3z(k<3D9F1R;};A4Z)3U=pI+Wu4}bCZ=1)-3SjAyO$gm3;wrI28p=Lg?C- zo*foJENxwhj#L`uGqjnbB=R?5IoO)=k_c9)gI7;SOllo(;)=Xfn(N4+F5&qZ?HxXGXI2*Pk=G%=LX>m|?if$J ztqntwEeV2>imSL2X?Ud)OUSJ}qr{{8QQ!<41NdPS>O;8uTIZg`{wKke0Kjmt0Qkn% zMSxFpcaWWxz#orh9Ro$p{Ryt=fO`@MQ_A}S=9cu6W2so*O6~h+E zb?kiWqq7y<_KcwHk5%uU0)G}yJVI2u#jO2c)PlCQi8PqWuw~&`T|XS;nN;5Es*9iaG+L;LP%;8$3 zRa{iDp3)_z9XS(Z*Q;-olN6F31d% z(K(Z#z;tvHf6Dw&xrAe6=GP)tK{BB>Z8dXf9CNHm0!>V4-0;A@f&E8@5f{`%-YX+P z51<^K>0x&^HJVP1&Y(sUqmA}m4%5bo?D0u7^Kjx^r#^_b4U#~(8|>(&Ey>no19E-V zJ^yfBysaM3*MTq?g&;Pp&q|@gw8?W#Lc>2Ipmv}92+CHd$Sz1a%acS*v^F6w(4+(GGXBtCEjhG9f9)HRcgJNk*H%piZ!Bqkk`xlu%7zphs z5y@x;(KL75Cd!jkKwXExym_#b^oV>>nPaKy&*Y1LiWmRX1a0fAW1wnH6=1JUsuNyE zelRnlf(rgWJtO^?kckkOv?KjSj1u|VQq_$008JiHGd%BtlmoEGd@v?I04D$dB=_#gVxC+8tn`zGm$c zY(B$zGXlIpUriKIsz(G3{OPCi$>NjGI4f}=15EOvI^dSGeB0vW@Uc0_gE{!LY2f;S zuzd35v+_YBW}HY$f)L8UWYt5Hr*~T&whdaL>F~b8+MVlhH?(a8ZGJ3tAM$`G;Yr35Kp&-C7eU>u zHr{CoKW&M&JX39XhHbtjiJF|BjSiqmYB|Vgki9>SLyLD1H21=);_BfU zs|ki5O~F(>g{n$AQrNPw<)~)-Xf^dmj+@^H4kQZ7G?4a0VF*=WrG&lEkYIvYAM)8ljl9pEiP5sjp+rnOafJvA?5sNxI1~D| zrH2RvQoe~8T}N}Qw-`NQj-}e@hT#XM(l!owbtXV&IXU93Mvs}cupIF=quaRce=z9P zHuyd)9!qtY1gQMY3!_-6oRWit)QMowOczb{Saqr+W5Y+rc8q145nCJ^5H_BFvxuNU z9*#oy&=}6K{V*DhQS0`P4L>rrV+<=w_KZ=dPhF=80)dCGNcDmvohMFW#q)U8ff8Gr zB>4HFBxFEDIW_0?>e8JbW24TdT_KOQP|yb~_pfGGfFwj0yf6DcJNqyh z^M?!(o)s_;*`rfRBomz%V=OR&!9p~LD%w>*47J~lFU;o!A_6#Ubd02qJW*(U5o^|| zbU4a`?4ION7CZ>jE|!$hjzvRGiBi$WXV3!2N1DaNXY7AZp1CzR7n9|Rd)&$t8AB59tn8KPO3f_~C%6=q=! zo-Ao_62%z5T#8n(_c_Ydt>%}u`Dn*;8}^t4!Bd5e2Vv$N+<3=RJT2l$K^ypG5b zUT}?z;zs*!ZL>h{$kzE86tQl}z!UsCwbNl>oTC3;fNZ$R(>m)MP$W79T4mYVXNBZxY%w}g^VDU9hc zCH%zU7)J`eSGrANk%Zvt4&uIGGV58O;(KQ3Pdq5)B^`T{p`@dD>?x(K@vY_>h!)tQZIgB;f?}U+m0mcji zA;?C6_*l4)0l5gtz?l(-!Bh+(5X&7ZX!RVod2SUEft{07L=-u<0;q5X322E6dV_1NM`5_Sfm4@v1ZquJ~LMp(^YJ62l`2*nA*7 zdB$+oD~bIvfmm)t;-|hRgFSkpAjvZaEO*-ttFbK6Z*yBdJpo{rOGN5JNHjLrRM zC>)ng1#}*0>8XHhK~_Q*poM^CJ8rydr8^fXIHJUP;Sc6HmQwc-E|4FefZ%l{a7Dww z^u&4b?;yltPM;>?Yb?|USWw^)v1lY5pmzU2lN(a%T2WnJJi-(JA$VmdL`(@vqFOR7 zgrW?iqiDqFFU2QT1&@mx6I*W~gm;fyvF#^-3q{`3)xTXYv6Qq5n;-JM&uS4kP9%At z5lf~HsT=bRt7&6~U?=9Ub}usq&l5DtgjE6Ha4<>i#5k9oFEG8(9N>nx7rcCLoLgHL zGNK_W2dV@PSsoc>#zl6GfOTig-0ehdq;QyPA=r?B`MqYE#<{f0f2$L*wFPIzuV`Se zn$U7ytP0?o4=r5-L{}umltXe}@7e$|CLv>EUNTU?fX*l5TslSvC!x+%0c&^uC!Vq7 z1q>?&PaI@7!naN4aElpx4OA|^yvbn9dCn*Tme@={P#6`HBqy<3PEpflcpF|KL+VAcs>tSg(SF-DmTk{ z>8s^;E^c`iZyDAKUma)Xj*%cYZ?>#}g3hcoI%93HUkE|qgV+98%06hc(P~w_wn@3)C%PgM28O%b`Q4##Hl5qlsZ2p zF-|b49_%K>XR}*-CLk7pi-P#al?%Bk4x{@k?0iHvl0Db|GZMb?9h@^L3=6*K{;vd) zjV2|tKSo^U3$SxI*xaW|GkKDbGvw*c{7@|wPm!faBdHw;KqrUw9qSvH>qV7r#;`MjP%#@k@x|=tuwjvV zoIxiv#8JdEKp9L*A6$H7YqQWG^ex@W5oBoYz6jw&mLY^R!R8)pVW5;i2!IYHFcFgh zc(e+BFJ$DKGNF~KN%}silR)awSt4#U9SGJ&Wr+jjPccNoB8gLR=xsx|!w|*A34HKz zY_n1-W_>NOsZ)Od0TT!T5ete)<8KV%I`E&-E&4{p`leg#X%)>A5$IT70sbC=mWyZy z@>n@TnBbAbq8*aJ6CFm63C~{=|Eq4rYbNqOBv2|bU45#(QYqFV9HiP(U^Nu(0VJ{bs6|10~f+Rz0bO)T6YMsX>puZU%m0+>gMj^A{=byX{(&>8`V~U zRX`Qb_|RCY11E^TdPmM)Q+@KeDo%Wp!%s~p#$*GxcqA#OC_#|>NG6qcfs<}}yX*dPDue;#NTSx!(>M3pa>iG=7ZXb~Xeqg%V~KmqVPZp7qvCmQ+kE4B zrI0hDbSt`kpWVxQ2g(c#WeS;@ymLl2C{#Jz zz(tz92{5D})iU8u6^OTybA(kEq;YhiZ$c1e)zafdI07<>Ga(9R&YSpB8-80`MC%c{ z)EU>g({TUTj0$z8lSE+HD2ihF^($9!3^Z{yYjb}~w`#1WaYuE5mhW{;ByjbQkM#?M zp^lC9jvB?`^rRVSAQ0fP0f}5O`oMn?VGEvD@tXK?Kvcs^Mk{J{&*Su)j=?o<(glzR zlmZJ(9xN>77 zC~>9_MvwE@JENNl^#>;gIA?4o0tHt3gNu2{zr?vy>O$a+i(rl6BrcT1dn1}x8!(E^ zJ=b4coC0z>nY&sx$dQOS~svQ1UYkSs6}v>UxtJE3do35XaL z2=Pk7Hm&=M^IIRfAG(xNS`bl)Y2XJfj)h1s@tiKk6SZ30@R1b zJREDo0#geMOf3wzcKak8$KPhhL3g8gn_b&D_jbEBn)6Pc6SkW9pa@0CiBtPu*l|+c zDE`8(X`Fi}Y?7P%qq|G|wmAqKx9tH)c8kVkMV1F`4}r1u%mB9FoEj8oP@IWVjx%M& zD@wMl2InWSROBnKa8?E3!J!;b@BD&$ELb`ZES~93HC(8OyT9CHc%fCi&=*j4I;#TT zZf%;_a`0@+zBiH|KDV`~!T6ww>1o5hXQHm$WD z60H&D{!dp6!j>!Fp8D-0I~NGrx}-?<#_Fu@qV4yXx5T|YHCX?x&SkZ=T?VJeYHQ2E ztijFGx;^I*h`=-0*r!YLWj|F7<)N(I+g;|ZngyuJW!!Wbo)iioP2Yag30*{kHjAr_V%240>m^(6*sk zwrs4HrKhUpyr-*W>-uUryS2J?dxB!wQtZ*Dlah4)@79}H&g z-ja*jT=dMl9>nOkTt{8wPxio;Fjy@v#i8wNs|w3nf&(DwDK)>CB95P zU`eB&TbAQ}r95Iuvl^dj?8p6SRzyiT`RpHq)*?QC)Psm4?H%l5ebxS5)j=F7lifq8 z4>mm~vvyy<5P@F>4-RiY%H$q0(^=4e@);0&tY}%ax!*x?y0sl8DPjOt}`xNqMY1eu4yvRBXDGp zghe28m&1Ww)o5sSw)=B zazm`(OSrPrnvRwKpWnHr$cIS&=EQqsx7fOK0@x^;HqRn|0%x1jmz znjPgeaF6;npK;)NQoUg;&4(1^t$Pm=B z7<@#&z;43VT!Agb7jDML#g|Q}m+q>`hxQ7FJ2Y1`2>&ktg*$8d#Jg&=uxh)jMiT&T zXYHp)!CzYAvp8x33_ss%&x3~8KjNS_sn16 z=e9lWm3sCfPDO60!8LfcjVZzgH@?OTZRIsKKlHe(@RcAmS?{WWM6AOJMb!SH!`xPi zR}hC+%-^R9E`EM}N7ZiI9%9n{GFZ?2^k>R@v?dy{wf~P0*JWQ!;yBhp1nb@=)g=3pO8kUh6q) z-<&(&b3}c9zTSP%URJylb-`JyW)QdIX+2{%Hyu7OBYnnM2RB15Ht9z1S7d^AZ;fh#b}x{-?H;UjZx3uu-iyONT~Gt<5PQgg zlO}0VO(>zI2Oe^OqzI4tAnyUR%xsOubu!p?LrqJ!AM6kvgruxyKi9av;#pXO4wBqOYjayd4 zrptzQZ5#ytU{RDzEi@=Ep_2phJM0=mtXdq`-dE$lAM*wPkP?{Bzef}!*86IR)B+Y? z1al7HNUsN9LHHmJ$4A_!#nO@$Me;ZDzLq|=R$GMox>su}idN(V+|#_tEq&;%iNsL7 zaMR7om(W#^&KfW}}&c$o- z4YRFrE_7M8M(bpd(jR~8`nmG^GWMQO?wZ-~z;~+>;XnPr$SP7hEm=l_MZV{B<1t;% zS=UkcYK50a5He4vBjlv*aw!NbmL}-VM9`g(nQxsFg)~L)v)oie!Wax;6EMd(@;Icc zat;StyRmw=+493xad1YU(>QjW5xo3`^r9CEDp-Wk;>M0y(QU*a=ou6w9aJJhR)GZl zA|liho8Rr=k+Cbt9w%* z>TC|p(w%>G=JbHU>j8HNYg$;wfZcNc)qgi2F82^SL27&;gkFHaMLGZ|fF1?eqS>2p ze)hD~IGo!1-*71ZfT<#h*OWDCvBj}D-SeZyypkFO9TeFc0__r{Sqpc;_*p*CfyakV zrx{&2(1xUwbg2{4BT`8X94wv#Z)fKSY9|DR>J*^@&LgN*MbLs8NFUo~+!B5dHDj(d zQ0&?ou_eWN0ZCsc?1)lb0+W&Ytg#f;u$i!h;tD}v|M$@z6d4QQ16mlg5U^AbEWe;8 zB9_$f8b68hMIW6)9q1d}?_zbNsy(w4Rafg!`zoQYEeF@33qA;N>#$hlePHuItrG;l zUdWa?&xRw?F+_xsj5NrB`E*2cu%#R9H5j^(gyl&zk0LsxDY#jD5!i@D1R+XWTod4e zaw87d1@|vO{)TNCL}#af&bmscM?57_Pyl(rGv*vO*5z}QC5c`K<2)0#CMuf~OPGKG zq5@fh?oVft1caVMpf8FG5zT2tG^7Vd%AH)hhkjUuNVdBslI_CZ-8C%bJ9hfJOu~Om z@Mu*~Zk=?^k0zpnV%y4^6}YeRyUL0dU@)44|4SHB@pe%_Fo0y2Nw>G*Q{i|9^sslG ztTS_llLs1*kAom!2znw@dU&Gb*!uKlEP6=m9HH`A#fS{x6Rj&CKtVU#4^{jqts9*% z1w>3m7qzq`f26igY^fD!ZwlS9tetqL!R6OKU+&wJWE=VAtfx2O^_&~(w(JsH9-6+%}vu1H1d~ZZP78+jm42>l|bUZqi<=5M-r6Np1 z-jPpd;0}jJYJGX@YMaHTTA$Qh3s5<$jFoVo#t+vU*3x1b4{v6#tBq+zop{+V{kA^Dd0^Vc29 z=T%^-4S^z(E%LXbJ;-d%O8KB;1x)W@Uhy~dmFaOE90VefL?e)II;F)&^wi$A4mKme zd!Qx`Ma7-y6>9WZe_z`#K7pb(7Z*}+`L1yC2f5jJDq=ht-rO_ z|5UC2>01AN1^)XBf^F+-$;}}gBIv4Y3pj$oH}gGJ4WCAg4a2hF{&C~*YIjlN@ErHe zjl&b%iyMb?+}Cpe!RoaLZDBe%!=N%(&`S_=)k>J4?ht~y%dD?exuAPqjY#(uIFv`I znM()Xtf#xL(s1R4iDE%&-K0qSFT{V-1c!PA#1^5rd0Mfk6w)Pk8F~IyCpsIoM} z$1IY-2L=%%q)A_W%6kjVEa2yPKdKKl3-H(tKxhD2+A+9uBIY>WfM zPqsiMR@)M2?hPekBLwTnwLFTkt+kc|6#l4CSCP3P2l4t^&dK<|tg&rcOeN+O=xl(I zV=`?a=6YL0!6#|}s!G@hQ4T)&IQD+JHk1kDic!0%=!hlu+mo(I9vsMiE_6MI^?PC) zNg;?GgA&SH5LY(Twlx>{H`cbb6!@R1m8JEyq03u(8uK>R3htSFT1@I*{tW-!NFw^{D@xbf`+BOj(E{svQ-1rK~95gJj zS!ZGGj#guGbMKQH#?rI-6lX!+ke7p#4zL$BCg5sTGQvI zyAUYkI0896R|}1mG0^#36lPsLRvgt*JM~>%R`?@#S`kkWjMpdz{NV)H%hygg*dGOA z^`hxW+jznO%UvCN7@IO!kC_o8ViO*hw|s8yGinz4u0~uvUU9P9(zVlyP};QJlErDo zKKw8$OZeM#xJl#fn|Mp>S7JAxkcZfx@%~c&-sDc}>bJ6IX|=%~+<;Kn*J9)lku!y^ zx2&vLfaZ6hd=8hKqTH{cxoZA6r>|qaJE6}wYa!g|*c_o_HuQLX#`J}OM|MId-L$ib z#e$o@d2w*lS9v@IL{dOJ1w>LnJOxBjKwAcir|@dzr7K2yGWrlnp>O`%Zo{jQbx8|h z;-QDqa4cF_teoV}q(EG(oC<{CP-4iPT9>%w$RM&Aa?|Uy9qD+v;(Y}`vmAWk#eD_f5E=>)fP%%1VAkM|mvK&vST@ue*|j5OpkAaG8=b79 z$DCEjm2oa&+fa)m6#vU!|8rjd^IrcJum3f#f4di<0K93C&x>0EtSP~U2-w18zL7Yw zO#r9XNd^#?xpbaKS!&fRlfaE(ukpbc;h*xoYNC@EDmoW^QOjpTWboy|BL3Al<nY2~>-D-9G)9uVOEaup-YJ%DuP3|lT#|R525&S- z8iORcACq<13}*c`FDFn9k%-P)){X{X*;RyVejSQmhs@)US%-rDtzIA6@}VUkl6^?_ zA-N3f+Gq_Yb>1|r1P2@~H_30p)pC>EyUDRhX)j{WX)yH;%j-)Rm$m#Kk6^ivN3NY_O@Mw6mvowvfqC;p$o$!&jtJIQ;RF%rm;F}gFi=;}W{|>4JqSP9_8^~&Wqd9c%J3-d^}&IkZo@Yv^Vv)2V+nt@Q#8y3VOQrYP`^)rIEC4_ik$I^~U66dsdKL(JuYqtV0H9w5H$@fNN6dis7H<^T6cXw@u$AqIPvZ^c_G3=L zct9_=#T%O2FK)pvu+h@aomSAz5zo`&K^{=$J6sY>T?1Rf)u`#RHG)LA`1*y zd{)R^zHG={>!9r+F&s7VqfiLCBxiFA7f3U(nj%du)i7190hXL|vGXD!Sxrdd38<15 zCZssj8(np%JcZ}{+{A|h^GFN5;@ys|W0c1FWC1nHc;!R3ReelR_OZXHkCtc|UiyN9 zpbo4_%>tL3@4fi7`U2JvL`7J&`g5xK6M@u<)dZMdTR}89kbT(%Pzb3uA|F9EZ-k|f zbO@bNCEFGk#KXW(SVvs21@4nDec|Z*V)<%v1=OP@O{2p+wc-5ISc7=WxY?FvfFKmAk%xsR!&w5A(BP zb#8*j(H0h#vCXC`HeYQ6ks?Vx_dz~C-x|#|#)pIK^Ycvg&|LF*7TIP0TW_@gzBd?$ zc{}t&n~dNQ5@Nu*iupx8bj|-yXZ{zsX#Raq%~yMw#mccTHUbGQ=m$o?&e0hpm{UlU>4HS+S z*M~^iLH3owwhnJDE+0X8DxRwBc=-~g^JS~@I)eXk;H2C9K)jM-g5MpYvs^wHqw$gR zGxvX^DsAX3rj&Qq7@QV~S){>W4hTco3Qh-0PsQcz7K9`Cl~@9~u$Y}N5R*^T$B6D5 z1Q>aMbn{J$?{-n_W7okq5QqyQMn&8u)LFt;o#$#>2FYYoz)QK(JZS)Qf>1Y6KG)bU z=?>Yh#V?mBCej*%aF#*lamY+lVZ@YuMWjc0@i#H_d6L(Qo8?rDaNk5tQ4{hx-Jyna z-)Ov-qv}|VfH!9o5DSI8M+X{vFQFK&^q)->*rPC;qZTs`8QFgr(tZp+9_}L=0lx2?Bm50U|d+Ngz99D{<2{ zjD~xG$!834!h(H*Hz}N?k$VXZ5Xh!gAFML6C-mW28p!f!z3~`MPjA#9!h(FGZb~n# z3HTX9&QDOrHswa0YdvNJzuczA{y61}DkYn@3qC;Ig87yXu)}(Cbn+&~CQo#?s*{LQ zv*>L6jUVTIe8HUd!rG6|Y2x|03tx((m)JxCKt=3RoddNhTVu1>5*_!_D6qy-n++Jy zagFgFkkO+$kWnkC+peQG*p|yiAu^p-H_f%lDmQ^H zveO!;@;JE%fT;P{%Njm+$Jt*siW2QC0_{>~(R)~;K1!zuD`{e$$Jie$tP? ze4YgmZL!}gbi{Z5`d0R1I1S^6$0$>#8>No)&c<8Wbx8g10-KNPU`~{no*fFm2g-SLiv15AY_DU9)h~2d5R;EepNa*aol?^Ab#VH-Q zM&)PhXaajVi9MKt4Cy~(hZ8!II*;DU4koatk~$JQANv`5JE3EI=b@jmHxoKiI@kP+ z{WXF201CQK6PX`DlyvNNZO4Sp>>9Q)p<`laaSdxt=$P7BUBiBx&|&F3T@8r?wXeL5 zJ($pu+&Shpc3%Q|6l9@&%VaR2o=?5rvq)eAcEkUdt52%ZY;l~H0 z__d@t!FTi0FC)|cjYcD^lFDLP1*bz5Uch(+!1$lvomDOj_b76~Q*}W^7n9(?bAns3 zsoQygBbUyVo@;VRxn|cy$nSLg^{^j?WjJm%2xJZC^^=AL0_>;caX_fW`XWxFa_m~5 zF;^UOY)<5;ag$%glXAJ2$J5*F_el`sI=pzRv2=K6qYRzlJc`p3EZKR*1Tz{s4(CYc zgBD18K~{7ZK`{zKWqyDbE6z|-i3NR>BHWhnI{ppZ!O{{7O{5`uLItlQ+anlWQF9L+ zW;7#Ax&y~mq7DkpbsNi_I8Vd6rQ=<`lCHt7<`IilMBc4%IF&DOv;^+2iKI=L_)-d- zfi_HNBdmcTbMz(dej9y89utZnclb~7{g5D`0s2(}UnrfKRULYEnVB62PGYSf-oOx+ z5|k&`@LoXc!zm#A_|^4^_zbZoE@+=(Be0j_VFF_k0#tFN3oVi&K4-6c2Ash3iy`Z$ zHXTIJE{)jbZG>ov1GD`Kf&^%+yz8YEn=#5MLAmU(mz2cKaC zU4Mf%GwiiHfPTDxo}=iM@+@xaw#lpTw-P-tpyl21VM)Uj0Q`O<+znvJ-_N&Kw1TcC zaTnJ`W8ff)VmMD<2_Nt~;b)@`!q#-B-qx}R+jBO$^LTt^W8b)NH*VP!uz*+LZza4F zk!5tu=2F%ZAO54j?xP$RzCl-Z#fKYl%h(URc`IJ|1#_W~i!|ya>C`DRV0MsbRHrNs zQ`XoQul$rP0md%UWPV1XG@i7hXakEw<%UubHhVx<1H0Oc1JX>hu@V8UDJ2QLm~O7b zK7e20b#ZF4CkalD3CKmsk?^nMFk>=w95N6Q0=AsJ-7Dw4;RW=JQQ$>Q9&r0KrZ>7K zbnHj*9AzlF0=7mG``%RSg+Ibxn2o*gYV3vAU?02@`{3f}f_WF14PKlhvg$EE7j8vD zg7QgM_b-*iuFrp|n7R_~LWtMQyVRUAGDO~2c62@XOQg2_vXu3jqQvyZ7*Qa6m<-d| z(X|-$kH!>!6t7GL*Agdd5!pk+$<{r406aU8@5M8L5g zv4{Dp3|W+~q1c=RtN3H=FG6!~F`I!Mg|)Slz%=Pm@i}jcxET@zUo&x_?CQP;YTE7% zr68134~*2xopo`jm@o4$TY6)58;YE*USQI$tK>IDs_Jpz0dvkK8j zrz}PI=Rl{*@aPa<#eNp|Ct$$;of}fgCrZQ!`L!@kHwfW&6ZXVOu=3tJL^>Ue=~2Ve~jCg7q|B0bgE0Dy1l2g*(mXbK9Dr3z_z{Tl*>~ z&FEyxq$H4`pk(W#)Lxwv_XT}=6_JHw*`T?m{(;A4wedy-RNyON2-lL!t0LK)(10q4$_R=uQ!%tMr0(i@}WcHdan#eet*ifc7;s zK^l*6AqXHTPdK9g-)jnQjt5ra^wND*=X)@Tj&8uj`*R~I5QPIxyI>i{#T)*MQI9a0 zeDQCav|6WkBJzm^(6Q7o~zY9JSV3*{xx&ii9e0H;SzgOKwCbS$>8##_3TV}MZ z>xK5v^^Sa&7!dY+JX@u2+vm*@_hS!6kBGvEQBA{_JbVqrH}Ng6SjOJcR2d97zysfpX&{lTfbE9bK^r4Cs1w;`=}rXx$NPMQMWW9U?gv!;fLKb~$hw&HpP* z{#z5P2>(GP&;OD=gHC`aztNF z=2r8b^ndPEZyKSCMh-&AduSg5EQ)5_i|GxteGUXa=vD2jYM;ang%VkL##sKQ`muws~eKtZDs&lfI%c?>7ZH_bfU4OK+1N zmkC%q*0C!P+GkU{{7LL`0l6QVigimO;g+~S$M0FP8Al!w@hfk54b`bJ%bzT{FzZs= zI-~NGTCs%c4##!mw|BI)hnL6U44#@BgVa4dbz?iu5yIKA7nJ>_xQ_1jj;Gth>9N!l z*lTw5vGs8d=81DU*xhkqeH=oCA@f5#^Pk$~Uc^d+YgqgG^I>SipO~Vf1pZUAX+h$z<@`R=!W~M$y+QG2M8q-QM?PzCHt4)&~v=B|<|GU?o0j-|*egEI}UEg(m*9*g5 z=XI~O?sc!V?sczwuPs+W!7`je6)MhlmJWq9E(&2)YYd@ge-jAbjXOV^4kh8Esl#?O z8bS_9O~+&Q<7J5}OIzjgBI5>KiZyF3Ua@VU3IOBC+$2PdB`seJu%=UXq8 z!~_mLRw4+;d5HG(k)y9rbSOo$I4=NMvhbSb-0YQrypp_iPXH(%uGsQ*iIfpibGk(8 z7veo6^$MXJ+5VMsP1FRh@o6=5&pBM_b{yAa(Qnl$yxbplaK~vsT`P~$cj2N-WlWqe zG1tk*Xku>hC7e6ac&3jGq#FUD&gj1u`u7JOJ_$8P%k;VxRP={xAZ2DYREpmMt`Cu~ z?ps!~D4aM+E7T0rSOye38#QVqsbxvN4wD9I@K;oEeQfsR_QqriGPcAZXZh;QX8eb9#=mZ()j%+Ck;HWPzi*)Yf z+u68=CFtFj;Ac@z@TrJnw#KC_7Kzc8?~wgOAa=iqv%1C{7W;*`FX__G><13+Y&41} z>?r&{?A#}CJE1T(=5vJ9BjgOaPz3>JrD!{G1~o*X3y3RNGygm9qQ~wdZ3- zqu2~m+BcQp7Dd}Tb1qG{9CFl>WO75+ZxWN{*OVkOW;v2%uY#@t>ataDQy)&C){m;uF zwUnwIWD|iLWI+!z`ou6hRYG-?z7=HH?+Mq!UeFHvjL;5yrwqHZ4Eq%Lm~d#&3&7B; zEEPdT5tw}0IQD;H!EC!l$d>LEXu6d;3w2e}V?qs_b6I(<;!hQNf z*EW?%FDh#Qu}+Diq#a5*RhK3oF1=Xg8?0=419uFDIdrB7V3qr(p^fFN$74B&zIDkFTvy@{l-&oK198Fms0M@0HhVMUqLMT8D_yR zN@S>Wu7`Sopr%ND32MdUuOKd+=kC<<7CBKl98t4C_joxVwB|Fczh9L26TP_liwpSh zrjI`s)hJ}usH1B9z{}NmEX#}1y(r!LP9(9flPb6peg`cnl|lAvr9D_uGvyCkGeK;yd|sd5xmuaX?=RxYo|jANwuHSdX?gGjo$?EN)-og8fAW%96LQZpSl7s_bh~y+t zIXqi}JN?yANxfX+{UzaTY-W@dZ!7AmQN1mSn#(0pvEusr`NkisGXQ@08tHAcyg(viqkC>?^T3d_Ck$k=d6kE;tcqLyZUuMei$*GMHQ%ni->LW}fDbK|h)>6y4yXHRp^tT{95 zHm*8daaIv_kf`Ac&i`PR<&cP4g2@U+x8Sp1{8B~TsxVm6t6X;2fgSFF!CIgW_^?zq zzKMrs%V-mUem}mL2vObRCQ*K)&IYNC1kDz_2nY@hw{=4+mBz}khdvhvj5)B2KXv+# zhd*C+u<7KEIkRd`mW&dj5w=`yf}G?uJPvmHHSrfPLE@41vyr* zYs7t-(c*&_D=z)vH%}0Qv;?HTqnE2oAiZ*rM2SH+K{ES zVN1dMMlE~!PTW#K-~NkUrn&u)c+0YgNJ-n}Fuv*YPe@4yFT2okSRAx0DX9rusm3i< zM&e^X;iR#ITSS(_gR5LBO%-xPoj|F`gHP1m+e#iNw^c+&FM|$bC3GN}JLyP`uoMb% zOCjBjthtQEsDILj_MoRB{=}6|tkrhLal+{Bp4VA4pr;s?& zsgfc@|5W9rp{w+*BQF^flRYYFw%{M1I32om8SwNM{38=}aQsW@AC#B|N3zo2C(-Ir z@9i#)Q2Haa(kE(!zAQk>w@BLs=mJ*q;^h zCGYRf3W<{54`#5kRQ|pUR)osm6?Mf29|WrDTcYQTRH^zq(1Hjg zZC6wuC?yTqE}rmp6U2s6w`#hyQJneL3}I4?xcm~1T>X6|rvf@o$hhuS_`_NLPG>^VGNzYz(R*b7D|e4PLdW*~+P{Z~8$|nE zJaO@p<*zH2f5PD;`v^jsuL%)3oAj|b>xeWur1q84l|36u4~Yj#IaJp7{{YfM1nFB` zkqJ`>@?HEMQtMKD7ZA(c&pz+#7r$%wf9<=T3I+@Q ziEUIMDgC1u6--xx9B5dml^_SAf=>m1S8esMWrLOOZ(81RAI5Xse~PI|#(8kJ(ZnMj zEvhPsxcx;H6XzU@qqT4$E=KDdA%rDHxdu~YUzM|u)Klf`E_G2kJ4@jzCp6JtDNQ|n zq_IwDyh~_YB2cn71R2I8e6wnT1tI$ml;JCg_%xz(sPu{89O(7!N66=b6JNzHmEIJb zowLdDmEcsTp2nB9gzUz_LgR1-%o6}M48T|=)(EJ?qXH`N5Hd;+3c*Tz(%4&Q{88EX zD~(5KQXt=ri6O256flRf%%m*#wk%&XHbZEpY;0gz!U9?PB=W8vlx1XF!tWa2Q#L-L zY+S9B931Z4h2G&lj+Z8>=6F*T_~>q`65l-YrqWkUSEZ^~q>518J6gf&s+1WWSwzi^3|F4braj8aJ z0*7)(?P+z33GXM4^au!=Fy?c)gXf_FbG-f&XPj0%X62X8sjv+RXO$w89hP?Rl`Y@`uSuR;tWWC0;D4n0%xR=P?zLh|i?ZzREdH>UbYkgvMx| zObt&F1^m!eLsE@Q%Qw}CS6hTLy;F@8Gmpn9;rETdDqfyf0l885@tnp;elG;ySWg19 zJ(<2VCs%q*8)Xk?lzk(1kncNhU}kq_Mlv&mKbd;^XyYutakZkcO2KZ+WkX{ET75H1 z60;IRnr0v7i)LnTCBnKP%o({361Vp`rkBUzP-DRKEi{@wtUL=ctS%i+6G%Es=B=hPpZ3Qgq$)S>jX*JdE-yFV-WFO~nQ zag(C)B-i*QuH0qx1Dfdp+U~-Vv-bVac(ktIbZnOQh)fqWQG~-gho})fbQVz@|8(i8J zAGq+;%(*!1n{M;I(|n>AK8kXA7Sd;V-|;p#d(~Z3DJiMYNT17KtZVL~cHzS*`#A3O z?=$fcJQ?L|^^z;p_aeICBIu_H-LM?9t717kTm^i%ljl%{JL=+R4J`v+j^HXUb4kvq zOTLB*&C8MGt8ns{d?$Wz^}&2=wPEB)Gg{|ja8Jjb3Q)28+9@tS6n6TnW|~`Y8BJ5F z8gIo&hSt`MkkjW6r$R2?>}yI5t#B(Yf$Pm8-RgU|xpQX86p0hv%G0g)D&H8@G6k^~ z@5Lrv=L%1x_p9YTkqW!olAUJp9wL7T%|ItxvXObEJ_M<~UrQ@n;d6EZ2`A`ij?;(w z6oRY2@k|JAyIL+N{1;BNPnZ=M>WbFX5TEx%7P>)&Z>KQh^lx*$?^vhX2)Tl{7x>Q` zz*F|TcsdIy6#AAfJzUTP<9E+q`>ubL#+kZs=GQEy5b$#tuWv~5ECPyY5z%5SeUo({NZ_&Tp z7h3~-F?xMN*Ma-P2Vz7_$0urR3FmNQCaJvkvof&Zr^{qE{B#-E@Ka@Y1Ehl3aBt+Sp04 zng`VQl#y76OEXVCfcKoM72IHT!dbk*aGpV{)zTqB7~- zd0dk%hs*_xHt_uz*eQV^rW!-w0LdJHgzN3(d^ZKk*0_6$bt59BFv=8#+0*+Dk`D;P zM!9=4kU!p!cX%Eay9RSN-cR-DPA7E2_4Rr0es$pRsRzrs2Y%cYxPBFZeT%XYUMldd z1X3EJgG1S`Vz<+&kJRoc#|d2w9@k`HbLbQNKYH)wmrvr{ z7O$SaQQT4P3H9oQ8^vAah(4_LpRL(Z?gflhvqkW>;dpK5^s0{&ns9^vZ{A53t5@Yc zUUd_|=VXJX-yd4daX4X$z}e%7OM#re@jZ8zyL*i93E2MXo#k70l&?StNzeE(2lgub z6DI(^J8l9JxciRp`R{ViL6*3oW@mYz1(di;&8{{tP6;V5k6U;}M&ARf22dqtWe;6} zm)VEXjo(A*%I~33JqL5mjjq;*#gEGvb_CDRLGQOwh&zIKd8r#m7Ir+yMsEYqi+#A{ z<9*DM^)0SHX5t*OZ0IULW?-lYpN!PeL8Rg>)4xG#)besQ?uhdC_jdNqR(pG4NYU%` z$h3S4=hg&J->ssYu0_uBPMV;a>kcQhOVl-=gYO@J&-cg}ZuZsgMt9bgQ@tJ%t6+Z& zdt>=S;wHGO$_e=o!#{K)-bQtIm!4>KiWKiZ{qlMY!mz`a(4?yJnvLbS1n?@p21=gY z=-s+<>BFne{ur?v%cXa&I=fOXH5Cyk(f?s~AmPgz4tm5Vox^^WmhVrzA4(KW5NZgX8&*Z` zEl)V7#mBk6Iq{A1bza<4UhyF}3D;UyOx|0r1m3vFJ>@Op-f}FD&zJAF+>eid9;q4) zz!*E|F&dv^-u5i!5gx7RN7Z{AN}3Ez3wfi+fg>Baq@=u2ww)DN4B7 zuo16CkMNG;D{(O%K54DSm1=HrNAl^5e)gGdZ!}+tOK9-5p*4>^ERML>`$iSmCa&s7 z7}Z>*bTd~wX+*W65?>~&9XA3mD4rf(^$X(QYHo8yjtGVglU+xiAKh{=Cd_qNnE1d! zoN4h(=u_(W?3xNQK-7_c<6HN?^u(vp&bAJi<3F`4;cO;et{l^p*x42C{pG}W-sj)K zvFl-q^x?I}<&!y+VoA6F&D|e*;{+N$Seg z-vpOn!s&DU$DA}?@b{lCB?!niQ+h^OUzQ^c5q$NcQi>K1iRY&A-k}d0q@zOhxoJnd zAM97)?g#IC#;V>EOCu@!CFPN-vlB`qUEL}s|1u3i`>N4Uf~1T}|C>h+PX2A$(B+d9 zQ2X|JqNGU93C)efR?qJSZ;SssA9E{wSz?x$d00GUpv$;UGc&|=&TvTlbsD#PXv?&# zHSZX_kw*KVBg0G{WyLWb_f&vQhD%W~`CJ-K z`C22xP2#>Vp{f(=3|%eds_uk$(ikx)4v9ZaQ{Y-UsErsDo-oM%r9phFD4K`}c@Fz<5XLEd zwvsc|oH8gx-c)lMmSAe$7@&?{rg2pX=&Fjzzk+5$P+(OI2Ei;T-8^h3`z%L!UkTh8(&T-(phu z>enlzeo%#qR!_G{^A&S2KC;k}-}l6!MvlZQsEt>+naeM=y2I$DcelC~wA-vcf?H(6 z(DqXXdK-WFrNM4L5wgO67N^!?VrdCZu6&jsyxb6|Ie_IG)w+|`at%+Z(sJlZx8mqFTTmk zzMrlJi@Rg)-+n_K_Y3lg6S1$t^+eFUZV6WB>Vp?|N#C@(RkvPrHJJ^DD{Abt#(YjS z2!X8RqW3HR1?YY7-V0_z4VHcIhLLK#m#p?>c`xG%8=4^wu;~Fa*dKF!6EPJmQEoXm z4Oe!JtA5;+80o|@(yEiRT6ouPQQ$%#jE9r0mweIC4x>rT(`9)i?D}j@+R$2$j~%aW zg_@CxbEnGm;F&`4jCk*Etv>|?rdFtRnWUmt=**Zf=Idgmw_DuZFbY#ScX<7$oMdYS ziAm|L)M=@$zUVi5t~1p2exBWL>HEVr!~3J?og+LrM|^Nj$b)nEm2-rHbHr8yt{orn z5_jUv#m{5Co68U>sAoUvd*pxn--r>0Tz784h!GlN(URPP{5;M4;=;n*qC8DOevu<0 zjB8JjoSUa{mE^nUFPf;~u8T>}ce(P576xK9^B3hhbLYDq&g&8d;TL%d=Q*63+yzLW zxdwbNKG(U>Q|Ksi|20KQZqZF{&4PSXE@?r2fkVUDmKC{kmrm4Z>{?s8W>)cHcYbk^ zYqrK!>~YR_XlBI}&%47h-#r_yf_#@7btLCfr(?nFh_KPQF{53Ywm)sb;zhah9Pa%2 znqsHM#vqKEU!3RAxEu>vg^Hbd4kutB>-@HC8y_20?mSg;#_LisKv$kz*&Bg%kA{cXJ|m?MKPnN1hb;ZeAnWFT-=en zDBq=7ht0EiF_OE2RK$?zx}NHaT`{AJ@xK^P zz9xf>2aNGN$3%_G4HTh>m^PQDWOVTohZ97C23s(UHKyFfj3|xC=_r2jb;YMFa?HPz zHS_vm0tn9hJhTQ>vDjJc1|^^)3Q;CN+;ts@wiaY0Pen`TV~DvlMa6DSk;6f~M>xbp zbf-M(+<%|95Gcr9NaZcixIFXc!@Iy!5TwRsDAcnQe{Gqm$52NX<_e924Jf!`+JY!8 z@|48Ij4p}ClRz0M54xiW6+!t!m*(MNM5S}g^DG411;rCJrTLS9K+u0_-XxY^p0lZG1NDA>C!*KDaVc$I>-s<{5+W%Xh5BwufKJ+&3 z+CFAj8GYQ)_~m)&>5KJ=YH8-h#+xrl8!p!0BTDHP8wX!V)Pft!Dd7c;FEdMKzvkj= zjhR^wUQ9S3d72))D18SRYql?O6gFm~@lMv3!v(kV^HThDgy(lD3Js_z>`QjKxG7rQTx0Q0}!dtE6ge7z0P9bftwH zIQ+TL;!D(&C?_5OYxtT*i90yX?}lRdd3^PbLn6 zzG{M68m-0#x<}$5cb6Uh^U`9q^bStCq&{l+ZbeGy&L6@Xg$EcSx#SOlhDv z$KXG9h;PN~6wt`Dv}KHAfATxF{Fh zBYCR!{4^gFo0_NnQ{VMg#Ja}enm2r7=&+toA``EV!xULaNGrK<)d$S*)&WCT>Tyel zKC1T0G_|ks>d%mBU7m*FhF7VT_}CtU76E0ym4FT$?L?xJKZD0MaPDE)Zi5boUC^>j z-pN;{Dc?huNK_y~8gv2o`dyiZTTe~C#;1PvUZidLmGj;cv@!qfyb`ui`tiK-o#n49 zsmx5t&CP8-dx4aCReS2FOsEhb?GEXIU{WNbYAYhq;KL&ic`qt2Is4o? z84c)$bCF1MMl?2#P%6H9Ve6FvzQ(V9IwY2vaY0Rs^z0RB?bS&T91e%-vvZKNih24? zQsOHo6_dX-+=`DhPrNEU+aftyr2DS;PvGO7TUv0LbSCGtNw;04gg9dR(l8Q=1zoQC zznA84(kf1Ri=(ztrQSqqyzVGjs`25k5MfCFP|THHXt@=Uu8@bLFHiGc^q-P9@cyEuxU0Np(G0GcUhVe2o8jVU9LyeM#Gr5s}e9lI|pQv zSm>u;ye$oT4bqR7@TT+}XBZMxr6Ah%O*8a5v7LmGMurh@AYVn9R;hr435tf?M9RC| zFpMMWF1t+hyBG*zxf*~79nxij;wfF?<%XM)E={r{T^hs~4QT3(WMU{#g1(m!az446KZuoi%g=n_h)ZQ5&7j}0pYfE{e}o~%>gRh;*$h63T< z=+6uzqu)1-^ez94TdCt$+J#yE@S67xaMyeY6CWG;*zi#FhX!Z{VL_>wjFLRf(dv4Q zS}Ob*MM-mi#%{lHydM(Hl|A1#c#$3#nLc!~Dw6s;N_l)`&(93Fo>k@j?2sA)Ct9cd z4U`N5jtR`m>d&hBleiK!_6k6o*Uo!QROL?IlV}gs*1v&DSQ+`D;l{Ti&4dj0oB=oF zzi+5)DZ33{x)7vin%$vW{l5&57PtDp#UhT+b-Zs-&-GP*fp@Y!H?${?-!%X$R%eP% zOmg=C)qP>$e0X_C%4@~DLY`x2Ecw>8O51S9?JWPR1IXKlBK`XqIIt?xwpR46FV@>H zc9n@wIEUADV@0;HpxH5X30p}M6 z`T|J0YF}?AAyNBeL82&Sv`UAXwlo?V9_uO9;A3(M8WqzNjh{81!fTN~^~`PRIqyo( z`JH;@b?N2k*=te1Uimlmx?@DIJ4g2_SkkL-U9TdscX4>{#Z!9UHLbVP(%Y5Y+da3p zC$IOCg}qDidoL~MU3ypVDgAoMBFoKUgJfu&(OUnqD6Kzt$+s_xgQ%BgFASQw&GdTF zHpM;-*SJSfr)X?a>`USspH@gOo+E~D5i&GBqo{+zhC*7~l5n>62ar2u^`5N$!63E# zp126SmCN0=@ebUX*6fUCOUX)oIA$2W+1Yu25_j=TAS|re*LbT!+T0=?{yj0*6CoK| z_Hh-`L_ccE=1!moOIzTtKhOO?-mXVw{Zy120x2e zH5xC0QEwd74E1Kr$pNY;`W+h0?nIeam?ZslC2^8x2rf@<@UZ!Iz;6i$z^JVKVI^^j z<-a$SvEY#3{Gko^Fz3|^C;`;8@uIIm&%Kt;WlGOnk$(8i9U)n-%&Bah4)OL5{||Hg z3+h`~lU}?ct+>)Kk;67&P~u2;U#a0Ycc}FG@6MYsMf8BCg!iikE8*Hd3Z6_U{K}ly zw18^6B0WJ+ulxb1x**i30My&BAQ3);ashJ%1j>;Yn|*^v&`+UK2=*D)8+f3hKY;C49<<s1!_PWWs(;`IH%zZ zBsdCg$Q^kILuw6^Jj&ZrS0IQ%4tlcW{WkN;MFw~J1eD4QqzG1F71wfH-9#Nqnv=M8-{t6Vd?`B8xm3?*EHaBo_N?8hddu zWLZVa0-XZ!3mSJFlt68eV4ka!ASUT6E2Y)iX0yo5T zXK7no+rw_>!_1t(DOy`8#qEFq^=sZ$%)6Wlm%^!Va-71!{0{gX3I}&G-Nb9U97}&h zF)TXF+}f(@elq~?ZJ_P;{eFXG+e5)*s~ZC zcP6hk=N3A+^jvhVhB;ZJOEVO5GA1i`0RYLNJ*Xl}U}q99=Cm>~Um$qdVyZzV3A{Nw z^JFYo;BvUH^916v^7A0ZvMtJA;O3I^-5OhdsRNSK{Dr6&5lK?}k5x_2v3<{r(izpX<*>bFKJmX$2sK zAlCGI6u;m5J>TyDbCFN}ea`F}#7X^X;g(ZI^k4Irlmq)yj+%ZE{d@Jl0@vK=)M=BZ zB~N=i`XTmvJeq#wmR;>`IsT#O&!RtIzt7+z_jAma-5&(PX8;lX4>X*94foGV~aa+I9}D-a16i=iM59!fz`$UrG6e+8^0JQ_Uz zuSauB)IX>j)SJ|gNBpPXrvDgoeU4obX_31kV!P3gT-P`K7Zh z>ZK@Mmk+wgFk-u1Vy@v`$v>BwK4u2vW4rB&XkZY?)!5k-RTnj>%h9&{=b38|%ahH_ zSN@VeSj+3%^1shVOl3R6VaCadMwemJ1dl)xV&jPESOi{>j%)|BDL;4u%yC~$YMJ!Y zq{7KPCTC2p(f%91isZ~>eKJTEf0@y_Pz2<-g6NXyis+Tm|B9}P-WpvOZ3@3Vyd=CV zd}a7!;ZKD(gnt(Pb@=b$LPU7P;D}ozv_13@_K2bgJ~FFE|HzS%8>6x#?~D9rzc05c0JJbcvrq#pKf1u z9@8zWo3mR@x0kzZ=y9p@scx6Lb?!d0dstL*_XXYW?fzKz`tDzKZ|;6$k9#8?jo91c zXpirDT<+1m=lGtvJ0KZ9&z=C_aaV382dW={-f`seV^|8M&D2Rp6UC0-y8d-^t1OX>$j!f>;1mzccI_V z{#pH(^k3WmmHuD#ztBH2dPHA%= zkA%UFiE%(no)Gz12cZRy1#TQcwgbUB2$rGkAfHZt=p4?$@u47<{DK0u|(?kp-UDQa&UU^%ecxyyrtO1N=M=?Q>BW*NQM=YaigZ%d)Wy{I@(t}5RtU2jjz z&}r^;ETcuA<2yMW3sEVwg(?akooa&Db`%7%q%b{(!rVI@I52kRGtOu+W4w^uH9xli z%mJa6(*{)`(0qmp+KbUxAjs?F7C0TbdCPDbzkr<~ zyEQmSMGZqdI8Q8IfR2!>f}=%D25!P~fIe6c&`y9451vt@huOI!C?~j0;KPF&{iAlO&O`nEe@)3P|E{}0i+lT1I~pG&O#~_Y;3UOXIHStU0jAthpdJ! zO=szH5<@{I9kSdAgvj6EYwj- z0Q)bx3&_aOg{4Pt*4emZ=n@463~g&|`qXs2*-m;0ZU^bwpnFhNAR`ajNjRh@1tX9? z2$Xi)^U+^`6wu2FG&DHDu(NI^nJ98&)Izp0BVFH?7$nOX{;XLM=Jj$lPUBs0m1xCw}#WTsrr!KMi329L?U8q zpWfTi#pzfFGQm;+^K8v73v6vQxo${v=6N7E3QoWvGti?vShy4$ zqX$g-nE8nUu_1**TW~ze3MUTD__*=6(3%#UOM@a8kVR0Fgov$u>1dy)+A2a@U#6Kx zm`6qPv6XZb6?+z9S_*CJC0ZTY7Miwcl;%`<1&3GwN^5xz5Nsal-LYvjphO06*Gwoj z;0h}W*aA}4THq`$)C2}v8_}6)#v*(MvbE0&#&*>-=y?@s=8;NEAtYi<(nSg?L9`PJ zgYJOP>lz&*Ow&wfi?U;?V-y7JG7-Y{V>KYFfU+B-%wQd9V>n+tM6hCVj6xLn0ftct`#v?(lVSi`{FU|EEcTl-WAf(^`Zfw+7J z#3qa}ae3x}`2#8C(X3mTPwdFwrRF;oGf_=D^tKSxIJhdd72P(e21A0Qha;(wj9d@| zt#(eZbm@#fgSZGXnZ!p?tQiC^FMz}!$c;py!G;Hm0MY`3iFh&nQl>2@FC@i``U)IN zF@Y_iscPObO&o>|paj`lNWm9+NY;kD=>ZKtd2(r+EHrFzIhM|6>T2k9Ow3EL3NY~x zmfk#!{=gaw*lv<4F$g61p_;d?=X@ArK(S7-2+jmmROoqOpg`pn%Oc2>Eo@-fp@TZV zoqcsdE2EGDoQV76=lVv{FawAO=3bwPor*yC!S+-BJHHd=bGnU;X)M8bD~wHl=X z(dA>0u~0K5SS&}`7^e&V$N?S}L>X*RuyZiGV~!<3Cc}~kO078SVA{8VNghNHq>CWu z#l&#(;_d{Fu`Hm0?Obw-jbj49KXQ(av?Wlh8FQme#Wrxgg0T zbxTrzBqGMdjoB3dQ63{5I{s)+5ajjR7A~4*3Nh{GVTyB?KrJ|+lNzKiHW#9kJVnGN z{h0ecn#YTgmx|a(7rh#?hK1AAA%L0ag?ajpZO$t@0HFt zqqap9Jr<~Ma3N=U=rV=4a~Gnm?QSzB7djfl>Lj;~(-9ksvYDbRoz%F2U&hS_mKv38ia`?x1-9zIePEj9v;o-%Ef#It$6OrbIXL;W zgE}g>V1m-*8C~uzZ0^_^gZXv=ICOXWrrE__eh6#>MvP!b8hDR`8xc4aC1=|)BWDcA zY`Ead8aRsp$G~Nj2Adw$?wL$A0TkO2dKFIcm@qnbHnk(;kgA5zS=qh z00t9~!H|n{HLFYL8e-rQE(uBfm z@(pYl}Wgr{!$;oj|cOsP5h zN?w`a_?I6|p4g{!{*aXT1G^^md;iAI6Miy2l5=arfvnG-x^LT-7sj0(HEwK%ZTGP| zM}4*V*!yn@Uv4`|-;buhYDE&WIqofGz?HNyM0ROjY3M>O;kCE>K0G*S(+i77ZvXe2 zPa2ax+V)RJ-?L+S^5I7#x9zU(bEa0;E8J80 zfM?0uX~u77PkM9qt=>(KSvRcJtm3V=9~|PiVc@g(o~Wr^V_Kz(wa>KZaTLOHN^~wR z$PNhw{ZOBRBt)Fb(1{glqKVS`9c_{%F_P(F{jD=I3K6+EY?s1SvU3bjg9S5ye9ii!!96Dnizdkpr3 zN)9h6K9F)de(QDb>6-AnJta)eqJ`qQ5<*DY=(^y)I9Ghkh06TpFnfiPDTH z=LW@ytQh;y z*d1eckKHr&Mf~c=HjI6H?7L&%7`t}tBV(VatgYNr`FiE?%C9SD-FL@*%kEoy--`Qe z%jYbAb@{R7=a=8TJb(H6v zgkiO5wHc3L^^E~n(rOL&_=@jV{Jf%hg<@sc%5EzkUqQe8$EmLQk59$(J)Zq|CS-(K z_4d#>924@3&|O5C@;rkckUbhqMIbK?PVeNxyWeem`j@9KKCRr|dAn@(-5#@j>~_oc8QXKV&)uH4 zJ%9U0&%|$k=9w+e)IIacGj9dVIF4IHv=^FTO%08Yi(3?tWTV}IXYs^{(DaPVP+fLR z5(&)$K3j|~TXrUA$JlHUp|%;xp>R^DEzLyEu@RvuCZn9lCa2fxbfGp&Ofn_18zVTw zU<>AE%ix^Bi(tD3-!pjS;Kv8A8(cehcblJl9LMUQ&5nr^BJTmhWN%u`*px*Pp+>Vk zG$9@iV*f(*OY_|pnO)V`>^cgI(PQWQpJU^MsC)PTTn0i{>>?<5QOyQ_O#Gslw*0{; z+f0gLaqYl^k?r|{)x8evHF>Wo`rP14Xs0SJE?yBAm!OP~8ygxIKc-WB{LP)>6UO1W zC4St^W8-capD>0SrMOu!2|q3lzs2}PaZ#AcuKPXuQnRM(z!zV7J#a*QXgtK*}f=GO?x!zmyB- z%T-*cWri&+lnbSf)}yDdX&(z?L2?hWeE)TQ{x->1HBeW!dY4*v7t z6YN(7Q}L$wW(50ngGsBvwLdl2{tJctR1+lsh$K6X59XqQ3NDE$dCV1JmcgCA*zJ^^ z6*oPI6MuQz5J6(-i1x@(9haq<639vX+FT)TnL-nUMDDxGgTUaEDH~{!5emHj2K2{d z7z{SOJ&>&pOdv7l5V=eLuX1H&SapmLhFza+_(*Qi>=;PS|56&10aIvQMMMxKn4{X= zZSfqX(&-J?CKP6lCj_=-3?>miy+^^Nnlh3h;u21kD<-z5!6g|Vpa1C6N8HDDEwmT` zjdp#kE2!Ldj~v|=^aCK;?A9468rExMU?zZH4hO1Jh8;8UxSM|PGT-7^PD2=?mcWINH*(oBE-pSUK8+jp zw(ac$Z|A(DUa4NW^Kj_fXIA{U;`bGWZ?&w5TKV*whYt-uvh&E%ce@>q^4;=L?y*}x zO8y}3{hv>qK5jpu**j|Q_PU4mtlhJ9&vSbY?3uLJzelyV>)xq*oA>mpyRCM4ZPwoT zdyDs0>c5Zrj(_@>S+4Rb$_cwjK>Eb5!=DwSU zZyvR|dh^!J+c#S`@7i3q`S9i=o8QClgUz38{(SS-n~SQQ)fcOmRF_uYQ+;3c1J!?2 zw^pyJez^Lv>NV9rR##PTs#ex)saDq52h=oFzfs+^ z`SNB}b^q#{tIgHpY9_MZ04%QnT=oimR$U1Y+1Uc48IEeHf^E5ZTOwrcyZ&EjpsKi zo)n+F_sM@eS^DHRRo_>gt2$qGvFb{dVuQG$(}t)GJvQ91VZesL8-{O)-7sdu_zjab zByULFVA?Q!L*|BA8*bm=*l@>&LmQ54IKJVd4Zm*qeZ!>#gfE z*O#r|y}`b5=EkZG4{Y#mcx1!s4bkfdtyitTy6)!niuDuLA6|EMUD>)v*DYS_UHjYG z=CxPWa_fY3A?w1|MXh^l?a{Tz*M7Km+u9v#Z(MWJnvrWpuSs7seNFKi*P2JytX}i- znpfAnzUEClZ?AcG&51Q1t@)JsUS%;~!uJtE-(B;~ns3)MuK9A!xi!Dy_wAbBk$&sy z?W=dKu3P>5>V2zUS$$yj!PRfAKDzq&>JL|cvHI$2#TwO`UTgc}HvqqGYiGao!v4Bf zk{Tww{%+lnx{2E!efpm}p22<7<=)eZ7(dp-Q4sE=kHTXy96ck|wS?ojBFrbDrB{!m-6wg0wdTSsi${?r#w zz3^1yQ_5{o+s1FzZ_V1eZ|j>|qqmOS`o>f5Jtb`IvUU1X?x*})hSe^p{b%io+K+2L zuRT@!ZLNOWZ#B-{CA%lBwXC(T9lLJ)y4%)mUAJdl-FSd=Zi?Te+q~_)miLAn-?i=it>I7A>>jl~etox^&NZECzBq0^F|le&Rr&7a zySMFrboD)}Ggs%Vw!GN&*#XZ6TRw-iebH_z)w!EemIv@qgFMY!`fnSttzhf2t=pek zgBE>(HZ?s}T=(eH&+Pc;jv&7E+jecs-r4-3>LuJ_$7NS^0Rugi%dF@MdjV&v=yi>~ zh_hFa8f?(MBj69(MM&Ql@z>h@1OC6-|C91e6}?$`vV8~OlRs!vIe&#Km;cxB|GvBh zf%g1oTW%lWh1y9rmGk%Z|D?R@@%v|d|KIrsac7m+Kh^Nl^E{qc@O*`b(wxWBghvzx zabbc2n|#Q6xX#=Fm|%t!N`)E$ojVU;0hQcx?m>kAi`&fND;3KX4vuLW(bsMe?~*(SXL0`ELGqA+dU^6}kjQ<}m8aMm1?lp^RAlLy8PCiFW+tmyZoNUa zjj|0Oa<*g!(+oCI7?Lr=uCg2LCcOv@+U+LZXiyprdOY!X67VFej0Pkn(?}-32u6cB zS%iUbbwDpmFl*EGDt)%yY8EXsl1;`G!K$~|l}4*Yz>|XH)ErpUn6N-DlQCH&-3e4t zw)6ozK42#V?Bq~69wi1{#-IxTL*!U2-#XELd> z(u^j(keXr7;C0EoE{oUcc-?efXW?}QUT0TgW5s7!VWlW-$;nEsS*HZbl-USNNw)|@ zpMqU)vn#P@SL$skO6>Xs+9D~jOU9F;1i=VIc1nD93R|NT8<{$0+L)unGpE2m>fiMF#w!Vig${rNL%b84|M7rVWRvWBPdNLy;$z}AY-gGMf+iftiwdraDrUY#YYB7Q!yjif&B7ATijCz%2}T*nrd0*wd=m z+JX^lOC}>rh1mlGjm#{}GB$x+s^p9rW}S+yf`Zm+F$pOqJIKa}E`mK?V!Oz$7ONzO4PB5P{-P+ zV|do7s3VwZ&|$H&rD*OJ?3k-Q37W1ik zOhcl4@{0@@O-ijbRUnlKQC3(|X-&pdvl?T@V$#kOq4ST)5H-{3O<)gndh*%q+LURk zlnl_MT8F`ku#g!6huWaEk~3sRz#-@}^;kS%P%xHnqdi@KCtV40P~kBeL}uz`D_*t| zWGgv@#bK=tIE(=Y7FsonGGpB)AjB!iE?SOd7p=wuE!Ut^geoEbR#~+=W46iyRl0G4 zC4M}<0hcg-oLL}KWr4;EoG?`ubH?~vSh8Cv4#t@Aw}fDLgX^=}!ps>#Czc-YBl2su zVme;Ky*WMvvCJXpkqU8Ssn|_s0!4_^XBe&1Y^tdZk;Gc68D_l9D_Zp_koBq21&nhe38g@MFQFI}kQl(lmW>}O6 z2pIxtn$4J_R}D$Ag5ers!UUooV$L8R+2mIZL0L9&2>MrNqd@Y8P$CLY4I#dYg2@hH zaKM4c4nPTIAv53-hS)PwL?ncz8iLE}7%;L?y4}QlWQ#-49CHelz#O4Nh~7Z(k2sjr0^}l|QauC{ESO4hhz_h^nur#eXQZo!SW>{o4oNneRYUCH7(0Pv zt@arfqF^;f9N8+%Sk~JxRmrw2Ef_4!?rLxejL|ZhGj(DXAi#oQvZRVK%P(6PX^aDx zEuA{>a&;Jb&xH4`F+jpFqoJ;BtS}*_phwlz0oiB>2w|GRq)kQF*~tze&W+R!C6H%N!W(DOh>f;sje>oh&yqticrEyd^Y%ukm2~EHjKcl~tFH={n0w zCgu{YEsUXnO)KHdIm666s#rD#V=)GWSQ>p~SeTh2knWj^3vaJLX77#ORR0|u%n5Y4D!iMGYqY)0a-MDXyiQ4niFm#Jd2nF+qvq>eRVeKhOT zv9^G1XSNv2CJ!-|O^0GEYmF+F5mPM9ZXz?Mgv18szR;ipK}bv#h}{$VNJJ*|n;5G# zS<CQyK=WAmSoJQEB79gL`SWP&QJ;CDb8sH-s(LnW}Ol;Mitn$j`9rt8x) ztTTD7U4=z5ejJ%&5`ulAMl3-HvFf$D46|t_1|a6+po2nj60Fr_S&aaX2^-8ORhZR0 z)T|G5Q0Ah`l53mrXZ9+Kg1a zXip(aZI{m~!CPzXiWEh%La#6>Yzl)SQ=wBPTc;_3UL`JqP+G9##PYAiRDs8W$EY-= zWGFK-4N5Dvi+1=e)2Au5CbKftZc(PESd?fDZ95eys${Lrh6Mev^y!GkFwF$1STR#$-ND)`rf9MCu!>lDV5w*Vw#u9M%88Ye z+P3yeywSn7_x3+8$k(mb^6DH|-vMbxN?=Ww7kJg*EFCl|Xc=jnq$_7Dbu%oA*vhiX z;gvCp!Ajbs5mU!wZNRdcX2iA<=fdh4=4s$m%zqvWs_AT8SeR*Grk#e1%9e&+ZO1$n z%s4)RMMDy{td1k6lnGO&MD%q!RgxqcB*7qQ2CBmAr}Jh#Z?f|yJ)dglQ}vZ2D@Rq1 zs2mNc2KMzNa!9iZlv7AErlu)P8CjxyLaGFlBcLs|%2}1eu?ewBJ1o@6{Wa74*?Y(|7ZeqoKnlYnOo zp0P?D{5oqqo&-E&@Z5}N9G+X0cKGc`V@H@BVRq{+yf&Lp$>w$0d~!B#v+&6l-e%-= zMjm~Tf^M+!Iva1W@u{}|Del{_u9!l30YL`EfM8>pWt~2q_MNh&m8}%n(#w`jwhXeB z%B-n!%Bgb7sdAF3a+0Z(grrbR?1Y7#37UdJrZ&M6le2ah9T@1qKnDgoFz~+~1N^mr zifcUqcSuqQ)M=AK*q;yrotVI1hyp=~`j3Ah9O6T&|KlHn_#bose-!b*o&Y)!(1C#t z40K?i0|Olx=)gb+20Ad%fq@PTbYP$Z105LXz(5BEIxx_Ifes9GV4wp79T@1qKnDgo zFwlX44h(c)paTOP80f%22L?JY(1C#t40K?i0|Olx=)gb+20Ad%fq@PTbYP$Z105LX Lz`*}MG4Ou?bokxb literal 0 HcmV?d00001 diff --git a/tasm/TLINK.EXE b/tasm/TLINK.EXE new file mode 100644 index 0000000000000000000000000000000000000000..44fbddcbcd7bb75a8a9c11f1d367c324a87a3e95 GIT binary patch literal 53414 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSIZE 0x10000 // size of conventional memory + +int main(int argc, char** argv) { + + struct stat s; + int ret = stat(argv[1], &s); + if(ret) exit(!!printf("invalid file!\n")); + + int kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC); + + assert((ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY) ^ ioctl(kvm, KVM_GET_API_VERSION, NULL)) == 13); + + int vmfd = ioctl(kvm, KVM_CREATE_VM, (unsigned long)0), + vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0), + codefd = open(argv[1], O_RDONLY); // load boot sector from file + + uint8_t* mem = mmap(NULL, MSIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); // allocate conventional memory for vm + + mz* mzbuf = malloc(s.st_size); + read(codefd, mzbuf, s.st_size); + close(codefd); + + mz_start ms; + uint32_t mzsz = loadmz(mzbuf, mem, 0x40, &ms); + + struct kvm_userspace_memory_region memmap[2] = { + { + .guest_phys_addr = 0, + .memory_size = 0xA0000, + .userspace_addr = (uint64_t)mem, + }, + /*{ // implied map + .guest_phys_addr = 0xA0000, + .memory_size = 0x20000, + .userspace_addr = (uint64_t)mem, + },*/ + { + .guest_phys_addr = 0xC0000, + .memory_size = 0x40000, + .userspace_addr = (uint64_t)mem + 0xC0000, + }, + }; + + for(int i = 0; i < 2; i++) { + memmap[i].slot = i; // id of memory mapping + ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, memmap[i]); + } + + struct kvm_sregs sregs; + struct kvm_run* run; + size_t run_size = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL); // size of struct is. determined at runtime for some reason? + run = mmap(NULL, run_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0); + + ioctl(vcpufd, KVM_GET_SREGS, &sregs); + + sregs.cs.base = ms.cs; + sregs.ss.base = ms.ss; + + sregs.cs.selector = 0; // probably protected mode related? + sregs.ss.selector = 0; + + ioctl(vcpufd, KVM_SET_SREGS, &sregs); + + struct kvm_regs regs = { + .rip = ms.ip, + .rsp = ms.sp, + .rflags = 0x2, + }; + + ioctl(vcpufd, KVM_SET_REGS, ®s); + + while(1) { + ret = ioctl(vcpufd, KVM_RUN, NULL); + if(ret == -1) exit(!!printf("kvm error\n")); + switch (run->exit_reason) { + case KVM_EXIT_HLT: + exit(!printf("got instruction `hlt`, exiting\n")); + break; + case KVM_EXIT_IO: + + break; + default: + exit(printf("vmexit\n")); + break; + } + } +}