home *** CD-ROM | disk | FTP | other *** search
/ CD-X 1 / cdx_01.iso / demodisc / basq / dualmodp / dmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-16  |  61.4 KB  |  1,890 lines

  1. // ************************************************************************
  2. // *
  3. // *    File        : DMP.C
  4. // *
  5. // *    Description : Dual Module player that uses DSMI
  6. // *
  7. // *    Copyright (C) 1992,1994 Otto Chrons
  8. // *
  9. // ************************************************************************
  10. /*
  11.         Revision history of DMP.C
  12.  
  13.         2.33    16.4.93
  14.                 First recorded version.
  15.         2.40    6.5.93
  16.                 Support for S3M format.
  17.                 DMP can now also display more channels and instruments.
  18.                 Support for 669 format also.
  19.         2.41    8.5.93
  20.                 Fixed the blinking bug after DOS shell
  21.                 9.5.93
  22.                 Added amplifying control via mcpOpenChannel (option -a)
  23.                 S3M loader if now more compatible
  24.         2.42    10.5.93
  25.                 S3M loader had troubles with non-used instruments.
  26.                 Same problem in 669 loader
  27.                 Filter on/off key for SB Pro
  28.                 Tempo keys, channel keys
  29.         2.43    11.5.93
  30.                 Left/right/middle,channel selection
  31.                 No more channel orders
  32.                 Real volumebars
  33.         2.44    12.5.93
  34.                 PC internal speaker support
  35.                 DAC works now with QEMM
  36.         2.45    15.5.93
  37.                 Full panning
  38.                 Support for MDA (0xB000 screen)
  39.         2.46    15.5.93
  40.                 Corrected the bug with all frequency commands...
  41.                 Aria sound card support
  42.         2.50    25.5.93
  43.                 Autocalibration
  44.                 EMS support
  45.         2.51    27.5.93
  46.                 EMS corrections
  47.                 New Quality mode
  48.                 Many bug fixes
  49.         2.52    8.6.93
  50.                 Some bug fixes.. don't know what :)
  51.         2.53    20.6.93
  52.                 WSS support
  53.                 Bugfixes with pause and SB
  54.                 Virtual DMA services support
  55.         2.54    27.6.93
  56.                 Bug in VDS detection
  57.                 WSS didn't work, now fixed
  58.         2.55    11.7.93
  59.                 Bugs with SB16 fixed (hopefully).
  60.         2.60    8.8.93
  61.                 GUS support, sort of
  62.         2.62    29.8.93
  63.                 GUS works now pretty well.
  64.                 Corrected a small bug in 669 loader
  65.         2.65    18.9.93
  66.                 Surround sound for MCP
  67.                 GUS bugs fixed...
  68.         2.66    26.9.93
  69.                 GUS DMA bugs fixed.. reset bugs, volume ramps, pause/resume
  70.         2.67    2.10.93
  71.                 GUS IRQ bugs.
  72.                 New SB16 detection.
  73.         2.68    3.10.93
  74.                 Portamento bug fixed
  75.                 Stereo DACs
  76.         2.69    Stereo DACs are now stereo! :)
  77.                 GUS reset bugs fixed
  78.         2.70    669 loader tempo bug fixed
  79.                 GUS reset bugs...
  80.         2.71    GUS reset bugs again.. :(
  81.                 -W is immediate DOS shell
  82.                 GUS is now timed propely
  83.                 Samples are now loaded without DMA to the GUS
  84.                 (optimized routine)
  85.         2.72    7.11.93
  86.                 Fixed a bug in CDI's CDIDEVICE
  87.                 S3M last instrument bug fixed
  88.         2.74    20.11.93
  89.                 All calls use 32-bit parameters in DSMI
  90.                 28.11.93
  91.                 GUS,AMP,Timer Service and CDI use new Cstyle macros,
  92.                 not TASM language MODELs
  93.                 Had to skip 2.73 because of a fake 2.73b
  94.         2.75    Changes in source for DSMI/32
  95.                 New reset routine for GUS
  96.                 Bug in S3M loader fixed
  97.                 Support for 32 channels
  98.         2.76    DMP.INI support
  99.                 Archiver support
  100.                 MTM loader bug fixes
  101.         2.77    Fixed a tiny bug in GUS heap (uninitialized pointer)
  102.                 New volume table for GUS, less clicks
  103.                 Mono screen support via DMP.INI
  104.                 Real volume bars for GUS
  105.         2.78    Fixed a stack bug in AMPLAYER (CMDinstrument)
  106.                 Fixed plain instrument handling to MOD and MTM loaders
  107.                 Fixed a bug with archive expansion
  108.         2.79    FAR loader
  109.                 MCPLAYER now uses macro library
  110.                 Fixed the CmdLine bug in DMP.INI
  111.         2.80    GUS bugs fixed
  112.                 50/25-row switch
  113.         2.81    S3M volume slide bug fixed
  114.                 Pitch bending bug fixed
  115.                 VGA hardware palette option
  116.                 Channel ID chars option
  117.         2.82    Rewritten mixing routines are 25% faster on 486
  118.                 PAS DMA bugs fixed (hopefully)
  119.         2.83    Internal DMA routines rewritten
  120.                 SB 2.0 44kHz support
  121.                 AudioTrix Pro support
  122.                 Fixed the amplifying bug
  123.                 Another S3M volume slide bug fixed
  124.         2.85    SB16 initRate bug fixed (no ENTERPROC...)
  125.                 ampSetMasterVolume added
  126.                 Corrupted modules are now loaded
  127.         2.86    Quality mode bug fixed
  128.                 Quiet mode, errorlevel support (68)
  129.                 Fixed MTM loader bug
  130.         2.87    DMA bug with PAS cards (DMA was not stopped)
  131.                 GUS samples are downloaded with DMA
  132.                 GUS player bugs fixed
  133.         2.88    GUS DMA works now
  134.                 MTM & FAR loaders fixed
  135.         2.89    Module loaders now compatible with DSMI/32
  136.                 New detection routines for SB family
  137.                 Fixed a bug in WSS exit routine
  138.                 Optional non-DMA transfer mode for GUS
  139.         2.90    Fixed S3M loader and FAR loader.
  140.                 AMF now supports >64 row patterns (FARandole)
  141.                 GUS now uses regular timer. Some bug fixes.
  142.                 Optimized mixing routines for 16-bit cards
  143.         2.91    Memory optimizations
  144. */
  145.  
  146.  
  147. #include <io.h>
  148. #include <fcntl.h>
  149. #include <dos.h>
  150. #include <stdio.h>
  151. #include <dir.h>
  152. #include <stdlib.h>
  153. #include <string.h>
  154. #include <bios.h>
  155. #include <ctype.h>
  156. #include <timeb.h>
  157. #include <alloc.h>
  158. #include <conio.h>
  159. #include <process.h>
  160. #include <time.h>
  161.  
  162. #include "mcp.h"
  163. #include "gus.h"
  164. #include "gushm.h"
  165. #include "cdi.h"
  166. #include "sdi_dac.h"
  167. #include "sdi_sb.h"
  168. #include "sdi_sb16.h"
  169. #include "sdi_aria.h"
  170. #include "sdi_pas.h"
  171. #include "sdi_wss.h"
  172. #include "detpas.h"
  173. #include "detaria.h"
  174. #include "detsb.h"
  175. #include "detgus.h"
  176. #include "amp.h"
  177. #include "mixer.h"
  178. #include "fastext.h"
  179. #include "timeserv.h"
  180. #include "dvcalls.h"
  181. #include "vds.h"
  182. #include "ini.h"
  183. #include "queue.h"
  184.  
  185. #ifdef _USE_EMS
  186. #include "emhm.h"
  187. #endif
  188.  
  189. char    DMP_VERSION[5] = "2.91";
  190.  
  191. extern uchar quietMode;
  192. extern ushort eventDiff;
  193.  
  194. #define V_REAL 1
  195. #define V_NORMAL 0
  196.  
  197. typedef struct {
  198.     char    fileName[MAXPATH];
  199.     uchar   deleteIt;
  200. } FileListItem;
  201.  
  202. typedef struct {
  203.     char    ext[5];
  204.     char    cmd[128];
  205. } Unpacker;
  206.  
  207. typedef struct {
  208.     ushort   r,g,b;
  209. } RGB;
  210.  
  211. int getCPUType();
  212. long timer();
  213.  
  214. long            startTime;
  215. volatile long   *timer2 = (long *)0x0000046C;
  216. uchar           lines, oldStereo, volumeBar = V_REAL;
  217. ushort          rate = 21000, multitasking = 0, cCount, thisChan = 0,
  218.                 isEMS = 0, vdsOK = 0, scrSize = 0, mono = 0, verLow1 = 9;
  219. DDS             dds;
  220. SOUNDCARD       scard;
  221.  
  222. int             fileCount = 0, verLow2 = 1,looping = 1, helpScr = 0,
  223.                 volume = 64, loadOpt = LM_IML, unpCount = 0,verHigh = 2;
  224. Queue           *fileList;
  225. MODULE          *module;
  226. char            instrUsed[127];
  227. char            *tempDir = ".\\", *defaultDir = NULL;
  228. Unpacker        unp[10];
  229. char            *defaultExtensions = "MOD STM NST AMF S3M 669 MTM FAR";
  230. char            channelID[33] = "123456789ABCDEFGHIJKLMNOPQRSTUVW";
  231.  
  232. #define VGACOLORCOUNT 16
  233.  
  234. int             setVGAColors = 0;
  235.  
  236. char            *vgaColorNames[VGACOLORCOUNT] = {
  237. "BLACK",
  238. "BLUE",
  239. "GREEN",
  240. "CYAN",
  241. "RED",
  242. "MAGENTA",
  243. "BROWN",
  244. "LIGHTGRAY",
  245. "DARKGRAY",
  246. "LIGHTBLUE",
  247. "LIGHTGREEN",
  248. "LIGHTCYAN",
  249. "LIGHTRED",
  250. "LIGHTMAGENTA",
  251. "YELLOW",
  252. "WHITE"};
  253.  
  254. RGB             vgaColors[VGACOLORCOUNT];
  255. int             colorPointers[VGACOLORCOUNT];
  256.  
  257. #define COLORCOUNT 17
  258. enum {          C_HEADER, C_INFO1, C_INFO2, C_3D1, C_3D2, C_3D3, C_TRACK,
  259.                 C_BAR1, C_BAR2, C_BAR3, C_INSTR1, C_INSTR2, C_INSTR3,
  260.                 C_CONTACT1, C_CONTACT2, C_HELP1, C_HELP2 };
  261. ushort          colors[COLORCOUNT] = {
  262.                 0x4F,0x17,0x1E,0x7F,0x8F,0x78,0x78,0x7A,0x7E,
  263.                 0x7C,0x1E,0x1A,0x1D,0x07,0x0A,0x5F,0x5E };
  264.  
  265. ushort          monoColors[COLORCOUNT] = {
  266.                 0x7F,0x07,0x0F,0x7F,0x8F,0x78,0x78,0x7F,0x7F,
  267.                 0x7F,0x07,0x09,0x0F,0x07,0x0F,0x70,0x7F };
  268.  
  269. char            *colorNames[COLORCOUNT] = {
  270. "Header",
  271. "Info1",
  272. "Info2",
  273. "3D1",
  274. "3D2",
  275. "3D3",
  276. "Track",
  277. "VolumeBar1",
  278. "VolumeBar2",
  279. "VolumeBar3",
  280. "Instr1",
  281. "Instr2",
  282. "Instr3",
  283. "Contact1",
  284. "Contact2",
  285. "Help1",
  286. "Help2"};
  287.  
  288. char            *helpText[] = {
  289. " Command line options :                   │ Keys :",
  290. " ─────────────────────────────────────────┼────────────────────────────────────",
  291. "   ~-?~, ~-h~     This help screen            │ ~P~           Pause/resume module",
  292. "   ~-s~xxxx     Sampling rate (4000-44100)  │ ~1~-~9~,~0~       Turn track on/off",
  293. "   ~-8~         Force 8-bit mode            │ ~D~           Shell to DOS",
  294. "   ~-p~xxx      Use port xxx (42 = PC spkr) │ ~N~           Next module",
  295. "   ~-i~x        Use interrupt x             │ ~F1~-~F10~,~+~,~-~  Set volume",
  296. "   ~-d~x        DMA channel x               │ ~Left~/~Right~  Go to next/prev pattern",
  297. "   ~-l~         No looping                  │ ~S~,~F~         Stereo/filter on/off",
  298. "   ~-a~xx       Amplify by xx (norm=31)     │ ~[~,~]~,~{~,~}~     Adjust speed/tempo",
  299. "   ~-c~x        Sound device x              │ ~, .~         Panning left/right",
  300. "              ~1~=SB, ~2~=SB Pro, ~3~=PAS+      │ ~L~,~M~,~R~,~U~     Left/mid/right/surround",
  301. "              ~4~=PAS16, ~5~=SB16, ~6~=DAC      │ ~Up~/~down~     Select next/prev channel",
  302. "              ~7~=Aria, ~8~=WSS/AudioTrix Pro │ ~V~           Real/fake volume bars",
  303. "              ~9~=GUS, ~10~=Spkr,             │ ~H~           This help screen",
  304. "              ~11,12~=Stereo DAC            │ ~Z~           Screen size (25/50)",
  305. "   ~-m~         Mono mode (PAS,SB16)        │",
  306. "   ~-q~         Quality mode (8-bit cards)  │ ~ESC~         Exit",
  307. "   ~-t~xxxx     Buffer = xxxx               └────────────────────────────────────",
  308. "   ~-o~         Scramble module order         ~-w~[command] Immediate DOS shell",
  309. "   ~-e~         Disable extended tempos       ~-g~          Non-DMA download (GUS)",
  310. "   ~-b~         Disable EMS usage             ~-n~xx        Set default panning",
  311. "   ~-zxx~       Screen size 25/50             ~-x~          Quiet screen mode  ",
  312. 0 },
  313.                 *contactText[] = {
  314. "",
  315. "                         Thank you for using ~DMP~",
  316. "",
  317. "  DMP is ~cardware~, which means that if you like the program, you ~must~",
  318. "  send me a ~postcard~. I want you to do this so that I can see how much DMP",
  319. "  is actually used around the world. Send your postcard to following address.",
  320. "  Please don't send e-mail as a substitute for a real post card!",
  321. "",
  322. "  To contact the author of ~DMP~, use following methods:",
  323. "",
  324. "  By mail:                    Internet:",
  325. "  ~Otto Chrons                 otto.chrons@cc.tut.fi",
  326. "  ~Vaajakatu 5 K 199",
  327. "  ~FIN-33720 TAMPERE",
  328. "  ~FINLAND",
  329. "",
  330. "  Read ~README~ for information on ~DSMI~ Programming Interface!!",
  331. "",0 };
  332.  
  333. void setTextmode(int mode)
  334. {
  335.     if(!quietMode) textmode(mode);
  336. }
  337.  
  338. long timer(void)
  339. {
  340.     struct timeb curtime;
  341.  
  342.     ftime(&curtime);
  343.     return curtime.time;
  344. }
  345.  
  346. int realVolume(int track)
  347. {
  348.     int         t,orgvol;
  349.     long        ave,vol;
  350.     char huge   *hsample;
  351.     char far    *sample;
  352.     static char buf[128];
  353.  
  354.     if( (orgvol = cdiGetVolume(track)) == 0 ||
  355.         !(cdiGetChannelStatus(track) & CH_PLAYING)) return 0;
  356.     if( scard.ID == ID_GUS )
  357.     {
  358.         ave = (long)cdiGetInstrument(track);
  359.         ave += cdiGetPosition(track);
  360.         for( t = 0; t < 80; t++ )
  361.         {
  362.             buf[t] = (char)(gusPeek(ave++))^(char)0x80;
  363.         }
  364.         sample = buf;
  365.     }
  366.     else
  367.     {
  368.         hsample = (char huge *)cdiGetInstrument(track);
  369.         hsample += cdiGetPosition(track);
  370.         sample = (char far *)hsample;
  371.     }
  372.     vol = 0;
  373.     for( t = 0; t < 80; t++ )
  374.     {
  375.         vol += abs(sample[t]^(char)0x80);
  376.     }
  377.     vol = vol*orgvol/8000;
  378.     if( vol > 64 ) vol = 64;
  379.     return vol;
  380. }
  381.  
  382. void setBlink(int toggle)
  383. {
  384.     if( quietMode ) return;
  385.     asm mov     ax,1003h
  386.     asm mov     bx,toggle
  387.     asm int     10h
  388. }
  389.  
  390. void resetMixer(void)
  391. {
  392.     mixerSet( MIX_STEREO, oldStereo );
  393. }
  394.  
  395. void drawHeader(void)
  396. {
  397.     ushort      buf[80];
  398.     char        str[80];
  399.  
  400.     sprintf(str,"Dual Module Player version %s (C) 1992,1994 Otto Chrons. All Rights Reserved.",DMP_VERSION);
  401.     moveChar(buf,0,' ',colors[C_HEADER],80);
  402.     moveStr(buf,1,str,colors[C_HEADER]);
  403.     writeBuf(buf,0,0,80);
  404. }
  405.  
  406. void drawScreen(void)
  407. {
  408.     ushort      t, buf[80];
  409.  
  410.     drawHeader();
  411.     moveChar(buf,0,' ',0x07,80);
  412.     for( t = 1; t < lines; t++ ) writeBuf(buf,0,t,80);
  413. }
  414.  
  415. void drawContact(void)
  416. {
  417.     ushort      t, buf[80];
  418.  
  419.     moveChar(buf,0,' ',0x07,80);
  420.     for( t = 1; t < lines; t++ ) writeBuf(buf,0,t,80);
  421.     for( t = 0; contactText[t] != 0; t++)
  422.         writeCStr(contactText[t],0,t+1,colors[C_CONTACT1],colors[C_CONTACT2],80);
  423. }
  424.  
  425. void showHelp(int line)
  426. {
  427.     int         t;
  428.  
  429.     for( t = 0; helpText[t] != 0; t++, line++)
  430.         writeCStr(helpText[t],0,line,colors[C_HELP1],colors[C_HELP2],80);
  431. }
  432.  
  433. void drawTracks(void)
  434. {
  435.     static ushort       trackTime[32] = {65535,65535,65535,65535,65535,65535,65535,65535,
  436.                                          65535,65535,65535,65535,65535,65535,65535,65535,
  437.                                          65535,65535,65535,65535,65535,65535,65535,65535,
  438.                                          65535,65535,65535,65535,65535,65535,65535,65535};
  439.     static int          barSize[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
  440.                                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, oldRow = 255;
  441.     static long         oldTimer;
  442.     static char         *notes[12] = {"C-","C#","D-","D#","E-","F-","F#","G-","G#","A-","A#","B-"},
  443.                         *cmds[] = {"","","VOLUME SLIDE","","","","PORTA TO NOTE",
  444.                                    "TREMOR","ARPEGGIO","VIBRATO","TONE+VOL",
  445.                                    "VIBRATO+VOL","","","","RETRIG","SAMPLE OFFSET",
  446.                                    "FINE VOLUME","","DELAY NOTE","NOTE CUT","","","PAN"},
  447.                         *modes[] = {"DOS","DesqView","Windows","Covox"},
  448.                         noteTrack[33];
  449.     int                 t,trck,i,s,a,x,y,cnt;
  450.     TRACKDATA           *trackdata;
  451.     TRACKDATA           tracks[32];
  452.     ushort              buf[160],attr,ins;
  453.     char                str[80], *strptr;
  454.     uchar               note;
  455.  
  456.     if( *timer2 == oldTimer ) return;
  457.     drawHeader();
  458.     moveChar(buf,0,' ',colors[C_INFO1],80);
  459.     sprintf(str,"Song: ~%s~",module->name);
  460.     moveCStr(buf,1,str,colors[C_INFO1],colors[C_INFO2]);
  461.     sprintf(str,"File size: ~%uK~",module->filesize/1024);
  462.     moveCStr(buf,30,str,colors[C_INFO1],colors[C_INFO2]);
  463.     sprintf(str,"Memory used: ~%uK~",module->size/1024);
  464.     moveCStr(buf,46,str,colors[C_INFO1],colors[C_INFO2]);
  465.     strptr = modes[multitasking];
  466.     if( !multitasking && isEMS ) strptr = "DOS/EMS";
  467.     sprintf(str,"Mode: ~%s~",strptr);
  468.     moveCStr(buf,64,str,colors[C_INFO1],colors[C_INFO2]);
  469.     writeBuf(buf,0,1,80);
  470.     moveChar(buf,0,' ',colors[C_INFO1],80);
  471.     sprintf(str,"Pattern: ~%d~/~%d~",ampGetPattern(),module->patternCount-1);
  472.     moveCStr(buf,1,str,colors[C_INFO1],colors[C_INFO2]);
  473.     sprintf(str,"Row: ~%02X~",oldRow = ampGetRow());
  474.     moveCStr(buf,18,str,colors[C_INFO1],colors[C_INFO2]);
  475.     sprintf(str,"Volume: ~%u~",volume);
  476.     moveCStr(buf,39,str,colors[C_INFO1],colors[C_INFO2]);
  477.     sprintf(str,"Rate: ~%u~",rate);
  478.     moveCStr(buf,50,str,colors[C_INFO1],colors[C_INFO2]);
  479.     sprintf(str,"Tempo: ~%u~/~%u~",ampGetTempo() & 255,ampGetTempo()>>8);
  480.     moveCStr(buf,63,str,colors[C_INFO1],colors[C_INFO2]);
  481.     if( ampGetModuleStatus() & MD_PAUSED ) strcpy(str,"Time: ~PAUSED~");
  482.     else
  483.     {
  484.         a = (timer() - startTime);
  485.         sprintf(str,"Time: ~%u:%02u~",a/60,a%60);
  486.     }
  487.     moveCStr(buf,26,str,colors[C_INFO1],colors[C_INFO2]);
  488.     writeBuf(buf,0,2,80);
  489.     oldTimer = *timer2;
  490.     for( t = 0; t < cCount; t++)
  491.     {
  492.         if( barSize[t] > 18 ) barSize[t]--;
  493.         else barSize[t] -= 2;
  494.         if( barSize[t] < 0 ) barSize[t] = 0;
  495.     }
  496.     for( t = 0; t < cCount; t++)
  497.     {
  498.         trck = t;
  499.         trackdata = ampGetTrackData( trck );
  500.         memcpy(&tracks[t],trackdata,sizeof(TRACKDATA));
  501.         moveChar(buf,0,' ',colors[C_TRACK],80);
  502.         note = trackdata->note;
  503.         moveStr(buf,0,"▌                      ▐     ▐    ▐                ▐",colors[C_TRACK]);
  504.         putAttr(buf,0,colors[C_3D1]);
  505.         putAttr(buf,23,colors[C_3D2]);
  506.         putAttr(buf,29,colors[C_3D2]);
  507.         putAttr(buf,34,colors[C_3D2]);
  508.         putAttr(buf,51,colors[C_3D2]);
  509.         putAttr(buf,79,colors[C_3D3]);
  510.         putChar(buf,79,'▐');
  511.         if( t == thisChan )
  512.         {
  513.             putChar(buf,0,'»');
  514.             putAttr(buf,0,colors[C_TRACK]);
  515.         }
  516.         moveChar(buf,53,'■',colors[C_3D3],20);
  517.         if( !(trackdata->status & TR_MUTED) )
  518.         {
  519.             if( note > 0 )
  520.             {
  521.                 strncpy(str,module->instruments[trackdata->instrument].name,22);
  522.                 str[22] = 0;
  523.                 moveStr(buf,1,str,colors[C_TRACK]);
  524.             }
  525.             str[0] = 0;
  526.             if( note > 0 )
  527.                 sprintf(str,"%2s%u",notes[note % 12],note/12 - ((module->type == MOD_S3M) ? 1 : 3));
  528.             moveStr(buf,25,str,colors[C_TRACK]);
  529.             sprintf(str,"%u",trackdata->volume);
  530.             if( note > 0 ) moveStr(buf,31,str,colors[C_TRACK]);
  531.             switch( trackdata->command )
  532.             {
  533.                 case cmdBender :
  534.                     strptr = (trackdata->cmdvalue > 127) ? "PORTA UP" : "PORTA DOWN";
  535.                     break;
  536.                 case cmdFinetune :
  537.                     strptr = (trackdata->cmdvalue > 127) ? "FINE PORTA UP" : "FINE PORTA DOWN";
  538.                     break;
  539.                 case cmdExtraFineBender:
  540.                     strptr = (trackdata->cmdvalue > 127) ? "EXTRA FINE UP" : "EXTRA FINE DOWN";
  541.                     break;
  542.                 default :
  543.                     strptr = cmds[trackdata->command & 0x7F];
  544.                     break;
  545.             }
  546.             moveStr(buf,36,strptr,colors[C_TRACK]);
  547.             if( trackdata->playtime < trackTime[trck] )
  548.                 barSize[t] = 20*trackdata->volume/64;
  549.             if(volumeBar) barSize[t] = realVolume(t)*20/64;
  550.             for( i = 0; i < barSize[t]; i++)
  551.             {
  552.                 attr = ( i < 13 ) ? colors[C_BAR1] : ( i < 18 ) ? colors[C_BAR2] : colors[C_BAR3];
  553.                 putAttr(buf,53+i,attr);
  554.             }
  555.         }
  556.         else moveStr(buf,60," MUTE ",colors[C_TRACK]);
  557.         switch( trackdata->panning )
  558.         {
  559.             case PAN_LEFT :
  560.                 strptr = " LEFT";
  561.                 break;
  562.             case PAN_RIGHT :
  563.                 strptr = "RIGHT";
  564.                 break;
  565.             case PAN_MIDDLE :
  566.                 strptr = " MID ";
  567.                 break;
  568.             case PAN_SURROUND :
  569.                 strptr = "SURND";
  570.                 break;
  571.             default :
  572.                 sprintf(str,"%d",trackdata->panning);
  573.                 strptr = str;
  574.                 break;
  575.         }
  576.         moveStr(buf,74,strptr,colors[C_TRACK]);
  577.         if( trackdata->playtime > 0 ) trackTime[trck] = trackdata->playtime;
  578.         writeBuf(buf,0,3+t,80);
  579.     }
  580.     for( t = 0; t < (module->instrumentCount+1)/2*2; t++)
  581.     {
  582.         a = 0; cnt = cCount;
  583.         memset(noteTrack,' ',cnt);
  584.         noteTrack[cnt] = 0;
  585.         if( t < module->instrumentCount )
  586.             for( i = cnt-1; i >= 0; i--)
  587.             {
  588.                 s = i;
  589.                 if( tracks[s].instrument == t && !(tracks[s].status & TR_MUTED) && (tracks[s].note > 0))
  590.                 {
  591.                     a++;
  592.                     noteTrack[--cnt] = channelID[s];
  593.                 }
  594.             }
  595.         ins = (module->instrumentCount+1)/2;
  596.         attr = (a == 0) ? colors[C_INSTR1] : colors[C_INSTR2];
  597.         if( a != 0 ) instrUsed[t] = '\x7';
  598.         x = (t < ins) ? 0 : 40;
  599.         y = (t < ins) ? t : t-ins;
  600.         y += 3+cCount;
  601.         moveChar(buf,0,' ',colors[C_INSTR1],40);
  602.         if( t < module->instrumentCount )
  603.         {
  604.             moveStr(buf,8-cCount,noteTrack,colors[C_INSTR3]);
  605.             putChar(buf,9,instrUsed[t]);
  606.             moveStr(buf,10,module->instruments[t].name,attr);
  607.             if( t < ins ) putChar(buf,39,'│');
  608.         }
  609.         writeBuf(buf,x,y,40);
  610.     }
  611.     moveChar(buf,0,' ',colors[C_INSTR1],80);
  612.     for( t = 3+ins+cCount; t < 50; t++) writeBuf(buf,0,t,80);
  613. }
  614.  
  615. void errorexit(const char *str)
  616. {
  617.     drawContact();
  618.     writeStr(str,0,1,0x1C,80);
  619.     cursorxy(0,24);
  620.     setBlink(1);
  621.     exit(1);
  622. }
  623.  
  624. int loader(char *name)
  625. {
  626.     char        *strptr, str[80], ch;
  627.     long        wait1;
  628.  
  629.     if((module = ampLoadModule(name,loadOpt)) == NULL)
  630.     {
  631.         switch(moduleError)
  632.         {
  633.             case -1 :
  634.                 strptr = " Not enough memory to load %s";
  635.                 break;
  636.             case -2 :
  637.                 strptr = " File error loading %s";
  638.                 break;
  639.             case -3 :
  640.                 strptr = " %s is not a valid module file";
  641.                 break;
  642.             default :
  643.                 strptr = " Couldn't load module %s";
  644.                 break;
  645.         }
  646.         sprintf(str,strptr,name);
  647.         drawScreen();
  648.         writeStr(str,0,2,0x1C,80);
  649.         writeStr("Press <ENTER> to continue, <ESC> to quit",0,3,0x1C,80);
  650.         do {
  651.             ch = bioskey(0);
  652.         } while( ch != 13 && ch != 27 );
  653.         drawScreen();
  654.         if( ch == 27 ) errorexit(str);
  655.     }
  656.     if( moduleError == MERR_CORRUPT )
  657.     {
  658.         wait1 = *timer2;
  659.         writeStr("Module is corrupted. Play anyway?",0,2,0x1C,80);
  660.         while( *timer2 < wait1 + 18 && bioskey(1) == 0 );
  661.         if(bioskey(1))
  662.         {
  663.             ch = toupper(bioskey(0));
  664.             if( ch == 27 ) errorexit("Corrupted module");
  665.             if( ch != 'N' ) moduleError = MERR_NONE;
  666.         } else moduleError = MERR_NONE;
  667.     }
  668.     return moduleError;
  669. }
  670.  
  671. char *searchAll(const char *name)
  672. {
  673.     struct ffblk ff;
  674.     char        drive[MAXDRIVE],path[MAXDIR],file[MAXFILE],ext[MAXEXT];
  675.     static char fName[MAXPATH],buffer[MAXPATH];
  676.  
  677.     fnsplit(name,drive,path,file,ext);
  678.     fnsplit(_argv[0],drive,path,buffer,buffer);
  679.     fnmerge(fName,drive,path,file,ext);
  680.     if( findfirst(fName,&ff,0) != 0 )
  681.     {
  682.         return searchpath(name);
  683.     }
  684.     else return fName;
  685. }
  686.  
  687. int addExtension(char *name)
  688. {
  689.     struct ffblk ff;
  690.     char        drive[MAXDRIVE],path[MAXDIR],file[MAXFILE],ext[MAXEXT];
  691.     char        fName[MAXPATH],buffer[MAXPATH];
  692.     int         a;
  693.     char        *extPtr = defaultExtensions;
  694.  
  695.     strcpy(fName,name);
  696.     a = findfirst(fName,&ff,0);
  697.     if( a != 0 )
  698.     {
  699.         a = fnsplit(fName,drive,path,file,ext);
  700.         if( (a & EXTENSION) == 0 )
  701.         {
  702.             ext[0] = '.';
  703.             do {
  704.                 a = 1; ext[1] = ext[2] = ext[3] = 0;
  705.                 while(*extPtr!=0 && *extPtr!=' ' && a < 4) ext[a++] = *extPtr++;
  706.                 if(*extPtr) extPtr++;
  707.                 ext[a] = 0;
  708.                 fnmerge(fName,drive,path,file,ext);
  709.                 if( findfirst(fName,&ff,0) == 0) break;
  710.             } while( ext[1] );
  711.             if( !ext[1] ) return -1;
  712.         }
  713.         else return -1;
  714.     }
  715.     _fullpath(buffer,fName,255);
  716.     strcpy(name,buffer);
  717.     return 0;
  718. }
  719.  
  720. void appendFileList(const char* name)
  721. {
  722.     char        drive[MAXDRIVE],path[MAXDIR],file[MAXFILE],ext[MAXEXT];
  723.     char        fileName[255];
  724.     struct ffblk ffblk;
  725.     int         error;
  726.     FileListItem    *item;
  727.  
  728.     if( strchr( name,'*' ) != NULL || strchr( name,'?' ) != NULL )
  729.     {
  730.         fnsplit( name,drive,path,file,ext );
  731.         error = findfirst( name,&ffblk,0 );
  732.         while( !error )
  733.         {
  734.             fnsplit( ffblk.ff_name,NULL,NULL,file,ext );
  735.             fnmerge( fileName,drive,path,file,ext );
  736.             addExtension( fileName );
  737.             item = malloc(sizeof(FileListItem));
  738.             strupr( fileName );
  739.             strcpy( item->fileName,fileName );
  740.             item->deleteIt = 0;
  741.             InsertQueueBottom(fileList, item);
  742.             error = findnext(&ffblk);
  743.             fileCount++;
  744.         }
  745.     }
  746.     else
  747.     {
  748.         strcpy(fileName,name);
  749.         if(addExtension(fileName) == 0)
  750.         {
  751.             item = malloc(sizeof(FileListItem));
  752.             strupr( fileName );
  753.             strcpy( item->fileName,fileName );
  754.             item->deleteIt = 0;
  755.             InsertQueueBottom(fileList, item);
  756.             fileCount++;
  757.         }
  758.     }
  759. }
  760.  
  761. void quit(int err)
  762. {
  763.     setTextmode(mono ? MONO : scrSize == 25 ? C80 : C4350);
  764.     drawScreen();
  765.     drawContact();
  766.     cursorxy(0,23);
  767.     setBlink(1);
  768.     if( vdsOK == 2 )
  769.     {
  770.         vdsEnableDMATranslation(scard.dmaChannel);
  771.         vdsUnlockDMA(&dds);
  772.     }
  773.     if(heapcheck() == _HEAPCORRUPT )
  774.     {
  775.         puts("Heap is corrupted!\n");
  776.         exit(-1);
  777.     }
  778.     exit(err);
  779. }
  780.  
  781. void beginCritical(void)
  782. {
  783.     if( multitasking == 1 )
  784.     {
  785.         dvBeginCritical();
  786.     }
  787.     else
  788.     {
  789.         asm     mov     ax,1681h
  790.         asm     int     2Fh
  791.     }
  792. }
  793.  
  794. void endCritical(void)
  795. {
  796.     if( multitasking == 1 )
  797.     {
  798.         dvEndCritical();
  799.     }
  800.     else
  801.     {
  802.         asm     mov     ax,1682h
  803.         asm     int     2Fh
  804.     }
  805. }
  806.  
  807. void releaseSlice(void)
  808. {
  809.     if( multitasking == 1 )
  810.     {
  811.         dvPause();
  812.     }
  813. }
  814.  
  815. int getWindowsVersion(void)
  816. {
  817.     uchar       RAL;
  818.     ushort      RAX;
  819.  
  820.     asm mov     ax,1600h
  821.     asm int     2Fh
  822.     asm mov     RAX,ax
  823.     asm mov     RAL,al
  824.     switch( RAL )
  825.     {
  826.         case 0x00 :
  827.         case 0x80 :
  828.             break;
  829.         case 0x01 :
  830.         case 0xFF :
  831.             return 2;
  832.         default :
  833.             return RAX;
  834.     }
  835.     if(getenv("windir")) return 1;
  836.     return 0;
  837. }
  838.  
  839. void update(void)
  840. {
  841.  
  842.     if( multitasking == 0 ) return;
  843.     beginCritical();
  844.     ampPoll();
  845.     endCritical();
  846. }
  847.  
  848. Queue *ReadDir(const char *dir)
  849. {
  850.     char            drive[MAXDRIVE],path[MAXDIR],path1[MAXDIR],file[MAXFILE],ext[MAXEXT];
  851.     char            fileName[MAXDIR];
  852.     Queue           *q;
  853.     struct ffblk    ff;
  854.     int             error;
  855.     FileListItem    *item;
  856.  
  857.     q = CreateQueue();
  858.     strcpy(path1,dir);
  859.     fnsplit( path1,drive,path,file,ext );
  860.     strcat(path1,"*.*");
  861.     error = findfirst( path1,&ff,0 );
  862.     while( !error )
  863.     {
  864.         fnsplit( ff.ff_name,NULL,NULL,file,ext );
  865.         fnmerge( fileName,drive,path,file,ext );
  866.         item = calloc(1,sizeof(FileListItem));
  867.         strupr( fileName );
  868.         strcpy( item->fileName,fileName );
  869.         InsertQueueBottom(q,item);
  870.         error = findnext(&ff);
  871.     }
  872.     return q;
  873. }
  874.  
  875. int DiffDir(Queue *q1, Queue *q2)
  876. {
  877.     FileListItem    *item;
  878.     int             success = 0;
  879.  
  880.     item = GetQueueItem(q2);
  881.     while( item )
  882.     {
  883.         if( !SearchQueueItem(q1,item,sizeof(FileListItem)))
  884.         {
  885.             item->deleteIt = 1;
  886.             InsertQueueTop(fileList,item);
  887.             success = 1;
  888.         }
  889.         else free(item);
  890.         item = GetQueueItem(q2);
  891.     }
  892.     DestroyQueue(q1);
  893.     DestroyQueue(q2);
  894.     return success;
  895. }
  896.  
  897. void AddUnpacker(const char *ext, const char *cmd)
  898. {
  899.     if( unpCount == 10 ) return;
  900.     strncpy(unp[unpCount].ext,ext,5);
  901.     unp[unpCount].ext[4] = 0;
  902.     strncpy(unp[unpCount].cmd,cmd,128);
  903.     unp[unpCount].cmd[127] = 0;
  904.     unpCount++;
  905. }
  906.  
  907. FileListItem *GetNextFile(void)
  908. {
  909.     FileListItem    *fileItem;
  910.     int             t;
  911.     Queue           *dir1,*dir2;
  912.     char            cmdline[128];
  913.  
  914.     fileItem = GetQueueItem( fileList );
  915.     if( fileItem == NULL ) quit(0);
  916.     for( t = 0; t < unpCount; t++ )
  917.         if(strstr(fileItem->fileName,unp[t].ext))
  918.         {
  919.             dir1 = ReadDir(tempDir);
  920.             sprintf(cmdline,unp[t].cmd,fileItem->fileName,tempDir);
  921.             cursorxy(0,1);
  922.             setBlink(1);
  923.             system(cmdline);
  924.             setBlink(0);
  925.             dir2 = ReadDir(tempDir);
  926.             if(DiffDir(dir1,dir2) && looping )
  927.             {
  928.                 InsertQueueBottom( fileList, fileItem );
  929.             }
  930.             return GetNextFile();
  931.         }
  932.     if( looping && !fileItem->deleteIt )
  933.     {
  934.         InsertQueueBottom( fileList, fileItem );
  935.     }
  936.     return fileItem;
  937. }
  938.  
  939. #pragma option -2-
  940.  
  941. void check386(void)
  942. {
  943.     if(!(getCPUType() & 2))
  944.     {
  945.         puts("This program requires atleast a 386 processor.");
  946.         exit(-1);
  947.     }
  948. }
  949.  
  950. #pragma option -3
  951.  
  952. #pragma startup check386
  953.  
  954. int getColorPointer(int color)
  955. {
  956.     int pointer;
  957.  
  958.     inp(0x3DA);
  959.     outp(0x3C0,color);
  960.     pointer = inp(0x3C1);
  961.     inp(0x3DA);
  962.     outp(0x3C0,0x20);
  963.     return pointer;
  964. }
  965.  
  966. void getRGB(int color, RGB *rgb)
  967. {
  968.     _ES = FP_SEG(rgb);
  969.     _DI = FP_OFF(rgb);
  970.     asm {
  971.         mov     dx,3C7h
  972.         mov     ax,color
  973.         out     dx,al
  974.         mov     dx,3C9h
  975.         sub     ax,ax
  976.         in      al,dx
  977.         mov     [es:di],ax
  978.         in      al,dx
  979.         mov     [es:di+2],ax
  980.         in      al,dx
  981.         mov     [es:di+4],ax
  982.     }
  983. }
  984.  
  985. void setRGB(int color, RGB *rgb)
  986. {
  987.     _ES = FP_SEG(rgb);
  988.     _DI = FP_OFF(rgb);
  989.     asm {
  990.         mov     dx,3C8h
  991.         mov     ax,color
  992.         out     dx,al
  993.         mov     dx,3C9h
  994.         mov     ax,[es:di]
  995.         out     dx,al
  996.         mov     ax,[es:di+2]
  997.         out     dx,al
  998.         mov     ax,[es:di+4]
  999.         out     dx,al
  1000.     }
  1001. }
  1002.  
  1003. void updatePalette(void)
  1004. {
  1005.     int t;
  1006.  
  1007.     if(setVGAColors == 0) return;
  1008.     for( t = 0; t < VGACOLORCOUNT; t++ )
  1009.         setRGB(colorPointers[t],&vgaColors[t]);
  1010. }
  1011.  
  1012. int main(int argc, char *argv[])
  1013. {
  1014.     int         t,i,b,key,stereo,filter = 1,ishelp = 0,
  1015.                 sDevice = 0, doMono = 0, dmach = 16, amp = 0, bit8 = 0,
  1016.                 emsOK = 1, defpan = 64, dosshell = 0, gusDMA = 1;
  1017.     char        ch, str[80], *strptr, fileName[MAXPATH], drive[MAXDRIVE];
  1018.     char        szName[10], szExt[5],*dmpenv = NULL,*dmpini,shellstr[80] = "";
  1019.     ushort      port = 0, intnum = 0, scramble = 0, a, bufsize = 0;
  1020.     ushort      voltable[32];
  1021.     long        tempTime, tempSeg;
  1022.     FILE        *f;
  1023.     MCPSTRUCT   mcpstrc;
  1024.     void        *temp;
  1025.     SDI_INIT    sdi;
  1026.     ConfigFile  iniFile;
  1027.     ConfigItemData  *itemData;
  1028.     FileListItem    *fileItem;
  1029.     QueueItem   *i1,*i2;
  1030.     ConfigClass *unpack;
  1031.     ConfigItem  *cItem;
  1032.  
  1033.     temp = farmalloc(100000);
  1034.     malloc(2000);
  1035.     farfree(temp);
  1036.     tempTime = 0;
  1037.     setBlink(0);
  1038.     randomize();
  1039.     lines = 50;
  1040.     sprintf(DMP_VERSION,"%d.%d%d",verHigh,verLow1,verLow2);
  1041.     if(initFastext() == 7)
  1042.     {
  1043.         mono = 1;
  1044.         memcpy(colors,monoColors,sizeof(colors));
  1045.     }
  1046.     dmpini = searchAll("DMP.INI");
  1047.     if( dmpini && ReadConfig(dmpini,&iniFile) == 0 )
  1048.     {
  1049.         if(SelectConfigClass("StartUp",&iniFile))
  1050.         {
  1051.             itemData = GetConfigItem("DefaultExt",T_STR,&iniFile);
  1052.             if( itemData != NULL  && itemData->i_str[0])
  1053.             {
  1054.                 defaultExtensions = itemData->i_str;
  1055.             }
  1056.             itemData = GetConfigItem("Cmdline",T_STR,&iniFile);
  1057.             if( itemData != NULL && itemData->i_str[0] )
  1058.             {
  1059.                 dmpenv = itemData->i_str;
  1060.             }
  1061.             itemData = GetConfigItem("DefaultDir",T_STR,&iniFile);
  1062.             if( itemData != NULL  && itemData->i_str[0] )
  1063.             {
  1064.                 defaultDir = itemData->i_str;
  1065.             }
  1066.             itemData = GetConfigItem("ChannelID",T_STR,&iniFile);
  1067.             if( itemData != NULL  && itemData->i_str[0] )
  1068.             {
  1069.                 for( a = 0; a < 32 && itemData->i_str[a] != 0; a++ )
  1070.                     channelID[a] = itemData->i_str[a];
  1071.             }
  1072.         }
  1073.         if(SelectConfigClass((mono) ? "MonoColors" : "Colors",&iniFile))
  1074.         {
  1075.             for( t = 0 ; t < COLORCOUNT; t++ )
  1076.             {
  1077.                 itemData = GetConfigItem(colorNames[t],T_LONG,&iniFile);
  1078.                 if( itemData != NULL )
  1079.                 {
  1080.                     a = itemData->i_long;
  1081.                     if( a != 0 ) colors[t] = a;
  1082.                 }
  1083.             }
  1084.         }
  1085.         if(SelectConfigClass("Unpack",&iniFile))
  1086.         {
  1087.             itemData = GetConfigItem("TempDir",T_STR,&iniFile);
  1088.             if( itemData != NULL )
  1089.             {
  1090.                 tempDir = itemData->i_str;
  1091.             }
  1092.             unpack = GetConfigClass("Unpack",&iniFile);
  1093.             cItem = unpack->firstItem;
  1094.             while( cItem )
  1095.             {
  1096.                 if( cItem->name[0] == '.' )
  1097.                 {
  1098.                     AddUnpacker(cItem->name,cItem->data);
  1099.                 }
  1100.                 cItem = cItem->nextItem;
  1101.             }
  1102.         }
  1103.         if(SelectConfigClass("VGAColors",&iniFile))
  1104.         {
  1105.             setVGAColors = 1;
  1106.             scrSize = (peekb(0x40,0x84) < 25) ? 25 : 50;
  1107.             setTextmode(mono ? MONO : scrSize == 25 ? C80 : C4350);        // Load default palette
  1108.             for( t = 0; t < VGACOLORCOUNT; t++ )
  1109.                 colorPointers[t] = getColorPointer(t);
  1110.             for( t = 0; t < VGACOLORCOUNT; t++ )
  1111.                 getRGB(colorPointers[t],&vgaColors[t]);
  1112.             for( t = 0; t < VGACOLORCOUNT; t++ )
  1113.             {
  1114.                 itemData = GetConfigItem(vgaColorNames[t],T_STR,&iniFile);
  1115.                 if( itemData != NULL )
  1116.                 {
  1117.                     sscanf(itemData->i_str,"%x %x %x",&vgaColors[t].r,&vgaColors[t].g,&vgaColors[t].b);
  1118.                 }
  1119.             }
  1120.         }
  1121.     }
  1122.     if( argc < 2 )
  1123.     {
  1124.         drawScreen();
  1125.         writeStr(" Syntax :    DMP modulename [options] [modulename] [@listfile] [options]",0,1,0x1F,80);
  1126.         writeStr("",0,2,0x1F,80);
  1127.         writeStr(" Use -H for more information",0,3,0x1F,80);
  1128.         cursorxy(0,4);
  1129.         exit(0);
  1130.     }
  1131.     mcpstrc.options = 0;
  1132.     fileList = CreateQueue();
  1133.     if(dmpenv == NULL) dmpenv = getenv("DMP");
  1134.     if( defaultDir )
  1135.     {
  1136.         fnsplit(defaultDir,drive,NULL,NULL,NULL);
  1137.         if(drive[0]) setdisk(toupper(drive[0])-'A');
  1138.         chdir(defaultDir);
  1139.     }
  1140.     if( dmpenv != NULL )
  1141.     {
  1142.         for( i = 0; dmpenv[i] != 0; i++ )
  1143.         {
  1144.             if( isspace(dmpenv[i]) ) continue;
  1145.             if( dmpenv[i] == '/' || dmpenv[i] == '-' )
  1146.             switch(toupper(dmpenv[i+1]))
  1147.             {
  1148.                 case 'S' :
  1149.                     sscanf(&dmpenv[i+2],"%u",&a);
  1150.                     if( a >= 4 && a <= 64 ) a = rate = a*1000;
  1151.                     if( a < 4000 ) rate = 4000;
  1152.                     else rate = a;
  1153.                     break;
  1154.                 case 'O' :
  1155.                     scramble = 1;
  1156.                     break;
  1157.                 case 'I' :
  1158.                     sscanf(&dmpenv[i+2],"%u",&intnum);
  1159.                     break;
  1160.                 case 'P' :
  1161.                     sscanf(&dmpenv[i+2],"%x",&port);
  1162.                     break;
  1163.                 case 'C' :
  1164.                     sscanf(&dmpenv[i+2],"%u",&a);
  1165.                     if( a > 0 && a < 13 ) sDevice = a;
  1166.                     break;
  1167.                 case 'L' :
  1168.                     looping = 0;
  1169.                     break;
  1170.                 case 'Q' :
  1171.                     mcpstrc.options |= MCP_QUALITY;
  1172.                     break;
  1173.                 case 'M' :
  1174.                     doMono = 1;
  1175.                     break;
  1176.                 case 'D' :
  1177.                     sscanf(&dmpenv[i+2],"%u",&dmach);
  1178.                     break;
  1179.                 case 'T' :
  1180.                     sscanf(&dmpenv[i+2],"%u",&bufsize);
  1181.                     if( bufsize > 32000 ) bufsize = 32000;
  1182.                     break;
  1183.                 case 'E' :
  1184.                     loadOpt |= LM_OLDTEMPO;
  1185.                     break;
  1186.                 case 'A' :
  1187.                     sscanf(&dmpenv[i+2],"%u",&);
  1188.                     if( amp > 64 ) amp = 64;
  1189.                     break;
  1190.                 case '8' :                      // Use 8-bit sound
  1191.                     bit8 = 1;
  1192.                     break;
  1193.                 case 'B' :
  1194.                     emsOK = 0;
  1195.                     break;
  1196.                 case 'N' :
  1197.                     sscanf(&dmpenv[i+2],"%u",&defpan);
  1198.                     if( defpan != 100 && defpan > 63 ) defpan = 64;
  1199.                     break;
  1200.                 case 'Z' :
  1201.                     sscanf(&dmpenv[i+2],"%u",&scrSize);
  1202.                     break;
  1203.                 case 'G' :
  1204.                     gusDMA = 0;
  1205.                     break;
  1206.             }
  1207.         }
  1208.     }
  1209.     for( t = 1; t < argc; t++)
  1210.     {
  1211.         strptr = argv[t];
  1212.         if( strptr[0] == '/' || strptr[0] == '-' )
  1213.         {
  1214.             switch(toupper(strptr[1]))
  1215.             {
  1216.                 case 'S' :
  1217.                     sscanf(&strptr[2],"%u",&a);
  1218.                     if( a >= 4 && a <= 64 ) a = rate = a*1000;
  1219.                     if( a < 4000 ) rate = 4000;
  1220.                     else rate = a;
  1221.                     break;
  1222.                 case 'H' :
  1223.                 case '?' :
  1224.                     ishelp = 1;
  1225.                     break;
  1226.                 case 'O' :
  1227.                     scramble = 1;
  1228.                     break;
  1229.                 case 'I' :
  1230.                     sscanf(&strptr[2],"%u",&intnum);
  1231.                     break;
  1232.                 case 'P' :
  1233.                     sscanf(&strptr[2],"%x",&port);
  1234.                     break;
  1235.                 case 'C' :
  1236.                     sscanf(&strptr[2],"%u",&a);
  1237.                     if( a > 0 && a < 13 ) sDevice = a;
  1238.                     break;
  1239.                 case 'L' :
  1240.                     looping = 0;
  1241.                     break;
  1242.                 case 'Q' :
  1243.                     mcpstrc.options |= MCP_QUALITY;
  1244.                     break;
  1245.                 case 'M' :
  1246.                     doMono = 1;
  1247.                     break;
  1248.                 case 'D' :
  1249.                     sscanf(&strptr[2],"%u",&dmach);
  1250.                     break;
  1251.                 case 'T' :
  1252.                     sscanf(&strptr[2],"%u",&bufsize);
  1253.                     if( bufsize > 32000 ) bufsize = 32000;
  1254.                     break;
  1255.                 case 'E' :
  1256.                     loadOpt |= LM_OLDTEMPO;
  1257.                     break;
  1258.                 case 'A' :
  1259.                     sscanf(&strptr[2],"%u",&);
  1260.                     if( amp > 64 ) amp = 64;
  1261.                     break;
  1262.                 case '8' :
  1263.                     bit8 = 1;                   // Use 8-bit sound
  1264.                     break;
  1265.                 case 'B' :
  1266.                     emsOK = 0;
  1267.                     break;
  1268.                 case 'N' :
  1269.                     sscanf(&strptr[2],"%u",&defpan);
  1270.                     if( defpan != 100 && defpan > 63 ) defpan = 64;
  1271.                     break;
  1272.                 case 'W' :
  1273.                     sscanf(&strptr[2],"%s",&shellstr);
  1274.                     dosshell = 1;
  1275.                     break;
  1276.                 case 'Z' :
  1277.                     sscanf(&strptr[2],"%u",&scrSize);
  1278.                     break;
  1279.                 case 'X' :
  1280.                     quietMode = 1;
  1281.                     break;
  1282.                 case 'G' :
  1283.                     gusDMA = 0;
  1284.                     break;
  1285.             }
  1286.         }
  1287.         else if( strptr[0] == '@' )
  1288.         {
  1289.             if((f = fopen(&strptr[1],"rt")) != NULL)
  1290.             {
  1291.                 do {
  1292.                     a = fscanf(f,"%s",fileName);
  1293.                     if( a == 1 ) appendFileList( fileName );
  1294.                 } while( a == 1 );
  1295.                 fclose(f);
  1296.             }
  1297.         }
  1298.         else appendFileList( strptr );
  1299.     }
  1300. #ifdef _USE_EMS
  1301.     if( emsOK ) isEMS = (emsInit(128,1024) == 0);
  1302. #endif
  1303.     drawScreen();
  1304.     updatePalette();
  1305.     cursorxy(0,1);
  1306.     if( fileCount > 1 && scramble )
  1307.     {
  1308.         for(i = 0; i < fileCount; i++)
  1309.         {
  1310.             b = random(fileCount);
  1311.             if( i != b )
  1312.             {
  1313.                 for( a = 0,i1 = fileList->firstItem; a < i; a++,i1 = i1->next );
  1314.                 for( a = 0,i2 = fileList->firstItem; a < b; a++,i2 = i2->next );
  1315.                 temp = i1->data;
  1316.                 i1->data = i2->data;
  1317.                 i2->data = temp;
  1318.             }
  1319.         }
  1320.     }
  1321.     if( ishelp )
  1322.     {
  1323.         showHelp(1);
  1324.         cursorxy(0,23);
  1325.         exit(0);
  1326.     }
  1327.     if( scrSize == 25 || scrSize == 50 )
  1328.     {
  1329.         setTextmode(mono ? MONO : scrSize == 25 ? C80 : C4350);
  1330.         updatePalette();
  1331.         setBlink(0);
  1332.     }
  1333.     scrSize = (peekb(0x40,0x84) < 25) ? 25 : 50;
  1334.     if( fileCount == 0 )
  1335.     {
  1336.         writeStr(" Syntax :    DMP [options] modulename [modulename] [@listfile] [options]",0,1,0x1F,80);
  1337.         cursorxy(0,2);
  1338.         exit(0);
  1339.     }
  1340.     if( !multitasking )
  1341.     {
  1342.         tsInit();               // init Timer Service
  1343.         atexit(tsClose);
  1344.     }
  1345.     if( intnum != 0 || port != 0 || dmach != 16 || sDevice == 10 || sDevice == 11 || sDevice == 12)
  1346.     {
  1347.         memset(&scard,0,sizeof(SOUNDCARD));
  1348.         scard.dmaChannel = (dmach != 16 ) ? dmach : 1;
  1349.         scard.sampleSize = 1;
  1350.         scard.minRate = 4000;
  1351.         scard.maxRate = 22050;
  1352.         if( intnum == 0 ) intnum = 7;
  1353.         switch(sDevice)
  1354.         {
  1355.             case 1 :
  1356.                 scard.ID = ID_SB;
  1357.                 break;
  1358.             case 2 :
  1359.                 scard.ID = ID_SBPRO;
  1360.                 break;
  1361.             case 3 :
  1362.                 scard.ID = ID_PASPLUS;
  1363.                 scard.stereo = (doMono == 1) ? 0 : 1;
  1364.                 if( intnum==0 ) intnum = 7;
  1365.                 if( port==0 ) port = 0x388;
  1366.                 scard.maxRate = 44100;
  1367.                 break;
  1368.             case 4 :
  1369.                 scard.ID = ID_PAS16;
  1370.                 scard.sampleSize = (bit8) ? 1 : 2;
  1371.                 scard.stereo = (doMono == 1) ? 0 : 1;
  1372.                 if( intnum==0 ) intnum = 7;
  1373.                 if( port==0 ) port = 0x388;
  1374.                 scard.maxRate = 44100;
  1375.                 break;
  1376.             case 5 :
  1377.                 scard.ID = ID_SB16;
  1378.                 scard.sampleSize = (bit8) ? 1 : 2;
  1379.                 scard.stereo = (doMono == 1) ? 0 : 1;
  1380.                 if( intnum==0 ) intnum = 5;
  1381.                 scard.maxRate = 44100;
  1382.                 break;
  1383.             case 6 :
  1384.                 scard.ID = ID_DAC;
  1385.                 scard.sampleSize = 1;
  1386.                 scard.stereo = 0;
  1387.                 scard.dmaChannel = 0;
  1388.                 if( port == 0 ) port = 0x378;
  1389.                 scard.maxRate = 60000;
  1390.                 break;
  1391.             case 7 :
  1392.                 scard.ID = ID_ARIA;
  1393.                 scard.sampleSize = (bit8) ? 1 : 2;
  1394.                 scard.stereo = 1;
  1395.                 if( port == 0 ) port = 0x290;
  1396.                 scard.maxRate = 44100;
  1397.                 break;
  1398.             case 8 :
  1399.                 scard.ID = ID_WSS;
  1400.                 scard.sampleSize = (bit8) ? 1 : 2;
  1401.                 scard.stereo = 1;
  1402.                 if( port == 0 ) port = 0x530;
  1403.                 scard.maxRate = 44100;
  1404.                 break;
  1405.             case 9 :
  1406.                 detectGUS(&scard);
  1407.                 scard.ID = ID_GUS;
  1408.                 scard.sampleSize = 0;
  1409.                 if( port == 0 ) port = 0x220;
  1410.                 scard.stereo = 1;
  1411.                 scard.extraField[2] = gusDMA;
  1412.                 break;
  1413.             case 10 :
  1414.                 scard.ID = ID_DAC;
  1415.                 scard.sampleSize = 1;
  1416.                 scard.stereo = 0;
  1417.                 scard.dmaChannel = 0;
  1418.                 port = 0x42;
  1419.                 scard.maxRate = 44100;
  1420.                 break;
  1421.             case 11 :
  1422.                 scard.ID = ID_DAC;
  1423.                 scard.sampleSize = 1;
  1424.                 scard.stereo = 1;
  1425.                 scard.dmaChannel = 1;
  1426.                 scard.maxRate = 60000;
  1427.                 break;
  1428.             case 12 :
  1429.                 scard.ID = ID_DAC;
  1430.                 scard.sampleSize = 1;
  1431.                 scard.stereo = 1;
  1432.                 scard.dmaChannel = 2;
  1433.                 if( port == 0 ) port = 0x378;
  1434.                 scard.maxRate = 60000;
  1435.                 break;
  1436.             default :
  1437.                 errorexit("You have to specify card type with -c parameter!");
  1438.                 break;
  1439.         }
  1440.         scard.ioPort = port;
  1441.         scard.dmaIRQ = intnum;
  1442.         switch( scard.ID )
  1443.         {
  1444.             case ID_SB :
  1445.                 sdi = SDI_SB;
  1446.                 break;
  1447.             case ID_SBPRO :
  1448.                 sdi = SDI_SBPro;
  1449.                 if(doMono) scard.stereo = 0;
  1450.                 break;
  1451.             case ID_PAS :
  1452.             case ID_PASPLUS :
  1453.             case ID_PAS16 :
  1454.                 sdi = SDI_PAS;
  1455.                 if(doMono) scard.stereo = 0;
  1456.                 break;
  1457.             case ID_SB16 :
  1458.                 sdi = SDI_SB16;
  1459.                 if(doMono) scard.stereo = 0;
  1460.                 break;
  1461.             case ID_ARIA :
  1462.                 sdi = SDI_ARIA;
  1463.                 if(doMono) scard.stereo = 0;
  1464.                 break;
  1465.             case ID_WSS :
  1466.                 sdi = SDI_WSS;
  1467.                 if(doMono) scard.stereo = 0;
  1468.                 break;
  1469.             case ID_DAC :
  1470.                 sdi = SDI_DAC;
  1471.                 break;
  1472.             case ID_GUS :
  1473.                 break;
  1474.             default :
  1475.                 errorexit("Invalid Sound Device Interface");
  1476.                 break;
  1477.         }
  1478.         if( scard.ID != ID_GUS )
  1479.             if(mcpInitSoundDevice(sdi,&scard)) errorexit("Unable to use the sound card");
  1480.     }
  1481.     else
  1482.     {
  1483.         if( sDevice == 0 || sDevice == 9 ) a = detectGUS(&scard);
  1484.         if( a != 0 && (sDevice == 0 || sDevice == 3 || sDevice == 4) ) a = detectPAS(&scard);
  1485.         if( a != 0 && (sDevice == 0 || sDevice == 7) ) a = detectAria(&scard);
  1486.         if( a != 0 && (sDevice == 0 || sDevice == 1) ) a = detectSB(&scard);
  1487.         if( a == 0 )
  1488.         {
  1489.             sprintf(str,"%s has been detected at %Xh using IRQ %d on DMA channel %d",\
  1490.                 scard.name,scard.ioPort,scard.dmaIRQ,scard.dmaChannel);
  1491.             writeStr(str,0,1,0x1E,80);
  1492.             sprintf(str,"version is %d.%02d",scard.version>>8,scard.version&255);
  1493.             writeStr(str,0,2,0x1E,80);
  1494.             delay(500);
  1495.             switch( scard.ID )
  1496.             {
  1497.                 case ID_SB :
  1498.                     sdi = SDI_SB;
  1499.                     break;
  1500.                 case ID_SBPRO :
  1501.                     sdi = SDI_SBPro;
  1502.                     if(doMono) scard.stereo = 0;
  1503.                     break;
  1504.                 case ID_PAS :
  1505.                 case ID_PASPLUS :
  1506.                 case ID_PAS16 :
  1507.                     sdi = SDI_PAS;
  1508.                     scard.sampleSize = (bit8) ? 1 : 2;
  1509.                     if(doMono) scard.stereo = 0;
  1510.                     break;
  1511.                 case ID_SB16 :
  1512.                     scard.sampleSize = (bit8) ? 1 : 2;
  1513.                     sdi = SDI_SB16;
  1514.                     if(doMono) scard.stereo = 0;
  1515.                     break;
  1516.                 case ID_ARIA :
  1517.                     scard.sampleSize = (bit8) ? 1 : 2;
  1518.                     sdi = SDI_ARIA;
  1519.                     if(doMono) scard.stereo = 0;
  1520.                     break;
  1521.                 case ID_GUS :
  1522.                     scard.extraField[2] = gusDMA;
  1523.                     break;
  1524.                 default :
  1525.                     errorexit("Invalid Sound Device Interface");
  1526.                     break;
  1527.             }
  1528.             if(scard.ID != ID_GUS) mcpInitSoundDevice(sdi,&scard);
  1529.         }
  1530.         else errorexit("Couldn't find sound card");
  1531.     }
  1532.     if((a = getDVVersion()) != 0)
  1533.     {
  1534.         printf("Detected DesqView %d.%02d\n",a/256,a & 255);
  1535.         puts("DesqView support enabled.");
  1536.         multitasking = 1;
  1537.     }
  1538.     else if((a = getWindowsVersion()) != 0)
  1539.     {
  1540.         if( a == 1 ) puts("Detected MS Windows 3.xx in Standard or Real mode");
  1541.         else if( a == 2 ) puts("Detected MS Windows/386 2.xx");
  1542.         else printf("Detected MS Windows %d.%02d in Enhanced mode\n",a & 255,a/256);
  1543.         if( a > 1 )
  1544.         {
  1545.             puts("MS Windows support enabled");
  1546.             multitasking = 2;
  1547.         }
  1548.     }
  1549.     vdsOK = vdsInit() == 0;
  1550.     if(scard.ID == ID_SBPRO)
  1551.     {
  1552.         mixerInit(MIX_SBPRO, scard.ioPort);
  1553.         stereo = 1;
  1554.         mixerSet(MIX_FILTEROUT, filter = 0);
  1555.         atexit(resetMixer);
  1556.     }
  1557.     if( scard.ID != ID_GUS )
  1558.     {
  1559.         a = MCP_TABLESIZE;
  1560.         mcpstrc.reqSize = 0;
  1561.         if( bufsize == 0 )
  1562.         {
  1563.             bufsize = (2800*(int)scard.sampleSize<<(int)scard.stereo)*(long)rate/22000l;
  1564.             mcpstrc.reqSize = 0;
  1565.             if( multitasking )
  1566.             {
  1567.                 bufsize = 16384;
  1568.                 mcpstrc.reqSize = 0;
  1569.             }
  1570.         }
  1571.         if( mcpstrc.options & MCP_QUALITY ) a += MCP_QUALITYSIZE;
  1572.         if((temp = malloc(a+bufsize)) == NULL) errorexit("Not enough memory");
  1573.         tempSeg = ((long)(FP_SEG(temp))*0x10+FP_OFF(temp)+0x10)/0x10;
  1574.         if( getCPUType() & 4 ) mcpstrc.options |= MCP_486;
  1575.         mcpstrc.bufferSeg = tempSeg;
  1576.         if( vdsOK && scard.ID != ID_DAC )
  1577.         {
  1578.             dds.size = bufsize;
  1579.             dds.segment = tempSeg;
  1580.             dds.offset = 0;
  1581.             if(vdsLockDMA(&dds)==0)
  1582.             {
  1583.                 mcpstrc.bufferPhysical = dds.address;
  1584. //                vdsDisableDMATranslation(scard.dmaChannel);
  1585.                 vdsOK = 2;
  1586.             }
  1587.             else mcpstrc.bufferPhysical = (ulong)tempSeg<<4;
  1588.         }
  1589.         else mcpstrc.bufferPhysical = (ulong)tempSeg<<4;
  1590.         mcpstrc.bufferSize = bufsize;
  1591.         mcpstrc.samplingRate = rate;
  1592.         if(mcpInit(&mcpstrc)) errorexit(" Couldn't initialize MultiChannelPlayer");
  1593.         atexit(mcpClose);
  1594.         cdiInit();
  1595.         cdiRegister(&CDI_MCP,0,31);
  1596.     }
  1597.     else
  1598.     {
  1599.         gusInit(&scard);
  1600.         atexit(gusClose);
  1601.         gushmInit();
  1602.         cdiInit();
  1603.         cdiRegister(&CDI_GUS,0,31);
  1604.         tsAddRoutine(gusInterrupt,GUS_TIMER);
  1605.     }
  1606.     if(ampInit(0)) errorexit(" Couldn't initialize AdvancedModulePlayer");
  1607.     atexit(ampClose);
  1608.     if( !multitasking )
  1609.     {
  1610.         tsAddRoutine(ampInterrupt,AMP_TIMER);
  1611. //      mcpCalibrateInit(11932,100);            // 100 times a sec
  1612. //      tsAddRoutine(mcpCalibrate,11932);
  1613.         if( scard.ID == ID_DAC ) setDACTimer(tsGetTimerRate());
  1614.     }
  1615.     if( scard.ID != ID_GUS )
  1616.     {
  1617.         mcpStartVoice();                // Start voice output
  1618.         rate = mcpGetSamplingRate();
  1619.     }
  1620.     else
  1621.     {
  1622.         gusStartVoice();
  1623.         rate = gusGetSamplingRate();
  1624.     }
  1625.     drawScreen();
  1626.     cursorxy(0,lines+1);
  1627.     startTime = timer();
  1628.     ch = 0; module = NULL;
  1629.     do
  1630.     {
  1631.         if( fileList->firstItem->next && ampGetPattern() == module->patternCount - 1 )
  1632.             ampSetMasterVolume(-1,(ampGetRow() < 64 ) ? volume-ampGetRow()*volume/64 : 0);
  1633.         if( (ampGetModuleStatus() & MD_PLAYING) == 0 )
  1634.         {
  1635.             do
  1636.             {
  1637.                 drawScreen();
  1638.                 mcpClearBuffer();
  1639.                 ampFreeModule(module);
  1640.                 if(heapcheck() == _HEAPCORRUPT )
  1641.                 {
  1642.                     puts("Heap is corrupted!\n");
  1643.                     exit(-1);
  1644.                 }
  1645.                 fileItem = GetNextFile();
  1646.                 fnsplit(fileItem->fileName,NULL,NULL,szName,szExt);
  1647.                 sprintf(str,"Loading %s%s . . .",szName,szExt);
  1648.                 writeStr(str,0,1,0x1F,80);
  1649.                 cursorxy(0,2);
  1650.                 if(heapcheck() == _HEAPCORRUPT )
  1651.                 {
  1652.                     puts("Heap is corrupted!\n");
  1653.                     exit(-1);
  1654.                 }
  1655.                 b = loader(fileItem->fileName);
  1656.                 if( fileItem->deleteIt )
  1657.                 {
  1658.                     remove(fileItem->fileName);
  1659.                     free(fileItem);
  1660.                 }
  1661.                 if(heapcheck() == _HEAPCORRUPT )
  1662.                 {
  1663.                     puts("Heap is corrupted!\n");
  1664.                     exit(-1);
  1665.                 }
  1666.                 memset(instrUsed,' ',31);
  1667.                 cursorxy(0,lines+1);
  1668.             } while( b < MERR_NONE );
  1669.             if( b == MERR_NONE )
  1670.             {
  1671.                 startTime = timer();
  1672.                 ampSetMasterVolume(-1,volume);
  1673.                 cCount = module->channelCount;
  1674.                 if( amp )
  1675.                 {
  1676.                     for( i = 0; i < 32; i++ ) voltable[i] = i*amp/32+1;
  1677.                     cdiSetupChannels(0,cCount,voltable);
  1678.                 }
  1679.                 else cdiSetupChannels(0,cCount,0);
  1680.                 thisChan = 0;
  1681.                 ampPlayModule(module,(fileCount == 1 && looping == 1) ? PM_LOOP : 0);
  1682.                 if( defpan != 64 )
  1683.                 {
  1684.                     for( i = 0; i < module->channelCount; i++ )
  1685.                     {
  1686.                         if( defpan == 100 ) a = defpan;
  1687.                         else
  1688.                         {
  1689.                             b = module->channelPanning[i];
  1690.                             if( b == PAN_MIDDLE ) a = PAN_MIDDLE;
  1691.                             else if( b > PAN_MIDDLE ) a = defpan;
  1692.                             else a = -defpan;
  1693.                         }
  1694.                         ampSetPanning(i,a);
  1695.                     }
  1696.                 }
  1697.                 if( scard.ID != ID_GUS )
  1698.                 {
  1699.                     rate = mcpGetSamplingRate();
  1700.                 }
  1701.                 else
  1702.                 {
  1703.                     rate = gusGetSamplingRate();
  1704.                 }
  1705.             }
  1706.             while(bioskey(1)) bioskey(0);       // Empty the keyboard buffer
  1707.             }
  1708.         drawTracks();
  1709.         update();
  1710.         releaseSlice();
  1711.         if( dosshell )
  1712.         {
  1713.             if( !multitasking )
  1714.             {
  1715.                 drawScreen();
  1716.                 writeStr("Type EXIT to return to DMP . . .",0,1,0x1F,80);
  1717.                 cursorxy(0,2);
  1718.                 setBlink(1);
  1719.                 if( shellstr[0] == 0 ) a = spawnlp(P_WAIT,getenv("COMSPEC"),NULL,NULL);
  1720.                 else a = spawnlp(P_WAIT,getenv("COMSPEC"),"","/C",shellstr,NULL);
  1721.                 if( a == 68 ) quit(68);         // Errorlevel == 68?
  1722.                 setTextmode(mono ? MONO : scrSize == 25 ? C80 : C4350);
  1723.                 updatePalette();
  1724.                 shellstr[0] = 0;                // Erase string
  1725.                 setBlink(0);
  1726.                 drawScreen();
  1727.                 cursorxy(0,lines+1);
  1728.             }
  1729.             dosshell = 0;
  1730.         }
  1731.         if( bioskey(1) )
  1732.         {
  1733.             key = bioskey(0);
  1734.             ch = toupper(key);
  1735.             if( ampGetModuleStatus() & MD_PAUSED )
  1736.             {
  1737.                 ampResumeModule();
  1738.                 mcpResumeVoice();
  1739.                 startTime += timer() - tempTime;
  1740.                 while(bioskey(1)) bioskey(0);   // Empty the keyboard buffer
  1741.             }
  1742.             else
  1743.             {
  1744.                 switch( ch )
  1745.                 {
  1746.                     case 0 :
  1747.                         a = key>>8;
  1748.                         if( a >= 0x3B && a <= 0x44 )
  1749.                             ampSetMasterVolume(-1, volume = (a - 0x3A)*64/10 );
  1750.                         switch(a)
  1751.                         {
  1752.                             case 0x4B :
  1753.                                 ampBreakPattern(-1);
  1754.                                 ampSetMasterVolume(-1, volume );
  1755.                                 break;
  1756.                             case 0x4D :
  1757.                                 ampBreakPattern(1);
  1758.                                 break;
  1759.                             case 0x48 :
  1760.                                 if( thisChan ) thisChan--;
  1761.                                 break;
  1762.                             case 0x50 :
  1763.                                 if( thisChan < module->channelCount-1 )
  1764.                                     thisChan++;
  1765.                                 break;
  1766.                         }
  1767.                         break;
  1768.                     case '+':
  1769.                         volume +=2 ;
  1770.                     case '-' :
  1771.                         volume--;
  1772.                         if( volume < 0 ) volume = 0;
  1773.                         if( volume > 64 ) volume = 64;
  1774.                         ampSetMasterVolume(-1, volume );
  1775.                         break;
  1776.                     case 'P' :
  1777.                         if( !(ampGetModuleStatus() & MD_PAUSED) )
  1778.                         {
  1779.                             ampPauseModule();
  1780.                             mcpPauseVoice();
  1781.                             tempTime = timer();
  1782.                         }
  1783.                         break;
  1784.                     case 'D' :
  1785.                         if( multitasking ) break;
  1786.                         drawScreen();
  1787.                         writeStr("Type EXIT to return to DMP . . .",0,1,0x1F,80);
  1788.                         cursorxy(0,2);
  1789.                         setBlink(1);
  1790.                         system("");
  1791.                         setTextmode(mono ? MONO : scrSize == 25 ? C80 : C4350);
  1792.                         updatePalette();
  1793.                         setBlink(0);
  1794.                         drawScreen();
  1795.                         cursorxy(0,lines+1);
  1796.                         break;
  1797.                     case 'H' :
  1798.                         showHelp(1);
  1799.                         while(!bioskey(1))
  1800.                         {
  1801.                             update();
  1802.                             releaseSlice();
  1803.                         }
  1804.                         while(bioskey(1)) bioskey(0);           // Read keys
  1805.                         break;
  1806.                     case 'N' :
  1807.                         ampStopModule();
  1808.                         break;
  1809.                     case 'S' :
  1810.                         if( scard.ID != ID_SBPRO ) break;
  1811.                         stereo = 1-stereo;
  1812.                         mixerSet(MIX_STEREO,stereo);
  1813.                         break;
  1814.                     case 'F' :
  1815.                         if( scard.ID != ID_SBPRO ) break;
  1816.                         filter = 1-filter;
  1817.                         mixerSet(MIX_FILTEROUT,filter);
  1818.                         break;
  1819.                     case '[' :
  1820.                         a = ampGetTempo();
  1821.                         if( (a & 0xFF) > 1 ) ampSetTempo(a-1);
  1822.                         break;
  1823.                     case ']' :
  1824.                         a = ampGetTempo();
  1825.                         if( (a & 0xFF) < 32 ) ampSetTempo(a+1);
  1826.                         break;
  1827.                     case '{' :
  1828.                         a = ampGetTempo();
  1829.                         if( (a & 0xFF00) > 32*256 ) ampSetTempo(a-256);
  1830.                         break;
  1831.                     case '}' :
  1832.                         a = ampGetTempo();
  1833.                         if( (ushort)(a & 0xFF00) < 255u*256 ) ampSetTempo(a+256);
  1834.                         break;
  1835.                     case 'M' :
  1836.                         ampSetPanning(thisChan,PAN_MIDDLE);
  1837.                         break;
  1838.                     case 'L' :
  1839.                         ampSetPanning(thisChan,PAN_LEFT);
  1840.                         break;
  1841.                     case 'R' :
  1842.                         ampSetPanning(thisChan,PAN_RIGHT);
  1843.                         break;
  1844.                     case 'U' :
  1845.                         ampSetPanning(thisChan,PAN_SURROUND);
  1846.                         break;
  1847.                     case 'V' :
  1848.                         volumeBar ^= 1;
  1849.                         break;
  1850.                     case '0' :
  1851.                         if( ampGetTrackStatus(thisChan) & TR_MUTED ) ampUnmuteTrack( thisChan );
  1852.                         else ampMuteTrack( thisChan );
  1853.                         break;
  1854.                     case ',' :
  1855.                         b = ampGetTrackData( thisChan )->panning;
  1856.                         if( b == PAN_SURROUND ) break;
  1857.                         if( b >= PAN_LEFT + 3 ) ampSetPanning(thisChan,b-3);
  1858.                         break;
  1859.                     case '.' :
  1860.                         b = ampGetTrackData( thisChan )->panning;
  1861.                         if( b == PAN_SURROUND ) break;
  1862.                         if( b <= PAN_RIGHT - 3 ) ampSetPanning(thisChan,b+3);
  1863.                         break;
  1864.                     case 'Z' :
  1865.                         scrSize = (peekb(0x40,0x84) < 25) ? 50 : 25;
  1866.                         setTextmode(mono ? MONO : scrSize == 25 ? C80 : C4350);
  1867.                         updatePalette();
  1868.                         setBlink(0);
  1869.                         drawScreen();
  1870.                         cursorxy(0,lines+1);
  1871.                         break;
  1872.                     case 'A' :
  1873.                         cursorxy(0,0);
  1874.                         printf("%x %x",inp(0x246),inp(0xA1));
  1875.                         getch();
  1876.                         break;
  1877.                 }
  1878.                 if( ch >= '1' && ch <= module->channelCount+'0' && ch <= '9' )
  1879.                 {
  1880.                     a = ch - '1';
  1881.                     if( ampGetTrackStatus(a) & TR_MUTED ) ampUnmuteTrack( a );
  1882.                     else ampMuteTrack( a );
  1883.                 }
  1884.             }
  1885.         }
  1886.     } while ( ch != 27 );
  1887.     quit(1);
  1888.     return 0;
  1889. }
  1890.