/* play.c - DSIK Module Player v1.02 Copyright 1993,94 Carlos Hasan */ #include #include #include #include #include "sound.h" /* Keyboard constants */ #define kbEsc 0x001B #define kbSpace 0x0020 #define kbPlus 0x002B #define kbMinus 0x002D #define kbLeft 0x4B00 #define kbRight 0x4D00 /* VGA 80x50 textmode constants */ #define VideoSeg 0xB800 #define VideoWidth 80 #define VideoHeight 50 /* VGA 8x8 Fonts */ char Fonts[8*13] = { 0x00,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0x00, 0x00,0xee,0xee,0xee,0xee,0xee,0xee,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, 0xff,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xff, 0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff, 0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff, 0x00,0x1c,0x3a,0x3e,0x3e,0x1c,0x00,0x00 }; /* VGA RGB Palette */ char Palette[3*16] = { 00,00,00, 06,10,22, 12,20,43, 20,32,63, 48,00,00, 00,44,00, 56,40,38, 63,63,63, 63,63,63, 63,63,63, 63,63,63, 00,50,63, 63,63,63, 63,63,63, 63,63,63, 50,50,63 }; typedef word TFrame[9]; TFrame frame1 = { 0x2388,0x028a,0x208a,0x2189,0x2383,0x2182,0x2385,0x2184,0x2100 }; TFrame frame2 = { 0x2289,0x2288,0x2287,0x2186,0x2382,0x2183,0x2384,0x2185,0x2100 }; TFrame frame3 = { 0x2187,0x2288,0x2287,0x2286,0x2182,0x2383,0x2184,0x2385,0x0f00 }; TFrame frame4 = { 0x128b,0x128a,0x218a,0x218b,0x2383,0x2182,0x2385,0x2184,0x2100 }; /* Lowlevel VGA 80x50 TextMode routines */ void SetTextMode(void) { asm { mov ax,0x0003 int 0x10 } } void SetTweakedMode(void) { asm { push ax push bx push dx mov ax,0x0003 /* set 80x25x16 textmode */ int 0x10 mov ax,0x1112 /* set ROM 8x8 charset */ mov bl,0x00 /* in the block zero */ int 0x10 mov dx,0x3C4 /* sync reset while */ mov ax,0x0100 /* setting misc output */ out dx,ax mov dx,0x3C2 /* select the dot clock and */ mov al,0x63 /* Horiz scanning rate */ out dx,al mov dx,0x3C4 /* select 8/9 dot clock */ mov ax,0x0101 out dx,ax mov dx,0x3C4 /* undo reset */ mov ax,0x0300 /* (restart sequencer) */ out dx,ax mov dx,0x3D4 /* hide cursor */ mov ax,0x100A out dx,ax mov al,0x0B out dx,ax pop dx pop bx pop ax } } void SetTextFont(void *FontData, word First, word Count) { asm { push ax push bx push cx push dx push bp push es mov ax,0x1100 /* load charset with reset */ mov bx,0x0800 mov cx,[Count] mov dx,[First] les bp,[FontData] int 0x10 pop es pop bp pop dx pop cx pop bx pop ax } } void SetPalette(void *Palette, word Count) { static byte Index[16] = { 0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63 }; asm { push ax push cx push dx push si push di push ds push es lea di,[Index] les si,[Palette] mov cx,[Count] mov dx,3c8h } L0: asm { mov al,[di] out dx,al inc dx mov al,es:[si] out dx,al mov al,es:[si+1] out dx,al mov al,es:[si+2] out dx,al dec dx add si,3 inc di loop L0 pop es pop ds pop di pop si pop dx pop cx pop ax } } void DrawChar(int X, int Y, char C, byte Color, word Count) { asm { push di push es mov ax,[Y] mov dx,VideoWidth mul dx add ax,[X] add ax,ax mov di,ax mov ax,VideoSeg mov es,ax mov ah,[Color] mov al,[C] mov cx,[Count] cld rep stosw pop es pop di } } void DrawText(int X, int Y, char *Text, byte Color, word Max) { asm { push si push di push ds push es mov ax,[Y] mov dx,VideoWidth mul dx add ax,[X] add ax,ax mov di,ax mov ax,VideoSeg mov es,ax mov ah,[Color] mov cx,[Max] lds si,[Text] } L0: asm { mov al,[ds:si] test al,al je L1 mov [es:di],ax add di,2 inc si dec cx jg L0 } L1: asm { mov al,20h test cx,cx jle L3 } L2: asm { mov [es:di],ax add di,2 loop L2 } L3: asm { pop es pop ds pop di pop si } } void DrawNum(int X, int Y, word Num, byte Color) { asm { push si push di push es mov ax,[Y] mov dx,VideoWidth mul dx add ax,[X] add ax,ax mov di,ax mov ax,VideoSeg mov es,ax mov bh,[Color] mov ax,[Num] aam or al,30h mov bl,al mov [es:di+4],bx mov al,ah aam or al,30h mov bl,al mov [es:di+2],bx mov al,ah aam or al,30h mov bl,al mov [es:di],bx pop es pop di pop si } } void DrawNum2(int X, int Y, word Num, byte Color) { asm { push si push di push es mov ax,[Y] mov dx,VideoWidth mul dx add ax,[X] add ax,ax mov di,ax mov ax,VideoSeg mov es,ax mov bh,[Color] mov ax,[Num] aam or al,30h mov bl,al mov [es:di+2],bx mov al,ah aam or al,30h mov bl,al mov [es:di],bx pop es pop di pop si } } void DrawNote(int X, int Y, word Note) { static char Notes[3*13] = "ùùùC-?C#?D-?D#?E-?F-?F#?G-?G#?A-?A#?B-?"; asm { push si push di push es mov ax,[Y] mov dx,VideoWidth mul dx add ax,[X] add ax,ax mov di,ax mov ax,VideoSeg mov es,ax mov cx,3 lea si,[Notes] mov ax,[Note] dec ax jl L0 xor dx,dx mov bx,12 div bx add si,dx add dx,dx add si,dx add si,3 or al,30h mov [ds:si+2],al } L0: asm { mov al,[ds:si] mov [es:di],al add di,2 inc si loop L0 pop es pop di pop si } } void DrawFrame(int XLeft, int YTop, int XRight, int YBottom, TFrame *Frame) { asm { push si push di push ds push es lds si,[Frame] mov ax,VideoSeg mov es,ax mov ax,[YTop] mov dx,VideoWidth mul dx add ax,[XLeft] add ax,ax mov di,ax mov bx,[XRight] sub bx,[XLeft] dec bx jl L0 mov dx,[YBottom] sub dx,[YTop] dec dx jl L0 cld push di mov ax,[si+2*0] stosw mov ax,[si+2*4] mov cx,bx rep stosw mov ax,[si+2*1] stosw pop di add di,2*VideoWidth } L1: asm { push di mov ax,[si+2*6] stosw mov ax,[si+2*8] mov cx,bx rep stosw mov ax,[si+2*7] stosw pop di add di,2*VideoWidth dec dx jne L1 mov ax,[si+2*2] stosw mov ax,[si+2*5] mov cx,bx rep stosw mov ax,[si+2*3] stosw } L0: asm { pop es pop ds pop di pop si } } void DrawMeter(int X, int Y, word Count) { asm { push di push es mov ax,VideoSeg mov es,ax mov ax,[Y] mov dx,VideoWidth mul dx add ax,[X] add ax,ax mov di,ax mov dx,[Count] cmp dx,32 jle L0 mov dx,32 } L0: asm { mov cx,dx shr cx,1 cld mov ax,0x0B81 rep stosw mov cx,dx test cx,1 je L1 inc cx mov ax,0x0B80 stosw } L1: asm { neg cx add cx,32 shr cx,1 xor ax,ax rep stosw pop es pop di } } void DrawBar(int X, int Y, word Count) { asm { push di push es mov ax,VideoSeg mov es,ax mov ax,[Y] mov dx,VideoWidth mul dx add ax,[X] add ax,ax mov di,ax mov dx,[Count] cmp dx,24 jle L0 mov dx,24 } L0: asm { mov cx,dx shr cx,1 cld mov ax,0x0681 rep stosw mov cx,dx test cx,1 je L1 inc cx mov ax,0x0680 stosw } L1: asm { mov dx,[Count] cmp dx,32 jle L2 mov dx,32 } L2: asm { mov cx,dx cmp cx,24 jle L3 sub cx,24 shr cx,1 cld mov ax,0x0481 rep stosw mov cx,dx test cx,1 je L3 inc cx mov ax,0x0480 stosw } L3: asm { neg cx add cx,32 shr cx,1 xor ax,ax rep stosw pop es pop di } } /* Lowlevel Keyboard routines */ int Keypressed(void) { asm { mov ah,01h int 16h mov ax,0 je L0 mov ax,1 } L0: return _AX; } int ReadKey(void) { asm { mov ah,00h int 16h test al,al je L0 xor ah,ah } L0: return _AX; } int main(int argc, char *argv[]) { char Path[MAXPATH],Drive[MAXDRIVE],Dir[MAXDIR],Name[MAXFILE],Ext[MAXEXT]; DSMCard Card; DSM *Module; DSMMusicInfo *Music; int Error,Volume,Key,I,J,N; printf("DSIK Module Player V1.02 Copyright 1993,94 Carlos Hasan\n"); /* Get Command Line Parameters */ if (argc <= 1) { printf("Usage: PLAY file[.dsm]\n"); return 1; } if ((fnsplit(argv[1],Drive,Dir,Name,Ext) & EXTENSION) == 0) strcpy(Ext,".DSM"); fnmerge(Path,Drive,Dir,Name,Ext); /* Sound Card configuration */ if (DSMLoadSetup(&Card)) { printf("Please run SETUP.EXE to configure.\n"); return 1; } /* Initialize the Sound System */ if (DSMInit(&Card)) { printf("Error Initializing the Sound System.\n"); return 1; } /* Load Module File */ if ((Module = DSMLoad(Path,0L)) == NULL) { switch (DSMStatus) { case ERR_NORAM: printf("Not enough system memory.\n"); break; case ERR_NODRAM: printf("Not enough card memory.\n"); break; case ERR_NOFILE: printf("File not found (%s).\n",Path); break; case ERR_FORMAT: printf("Invalid file format.\n"); break; case ERR_ACCESS: printf("File damaged.\n"); break; } DSMDone(); return 1; } /* Setup Text Screen */ SetTweakedMode(); SetPalette(&Palette,sizeof(Palette)/3); SetTextFont(&Fonts,0x80,sizeof(Fonts) >> 3); /* Draw Panel */ DrawFrame(1,0,78,49,&frame1); DrawChar(4,1,130,0x21,72); DrawChar(4,2,131,0x23,72); DrawChar(4,4,130,0x21,72); DrawChar(4,5,131,0x23,72); DrawText(5,3,"DSIK Module Player Version 1.02 Copyright (C) 1993,94 Carlos Hasan",0x2B,70); /* Draw InfoBox */ DrawChar(10,6,135,0x21,1); DrawChar(11,6,130,0x21,39); DrawChar(10,7,132,0x21,1); DrawChar(11,7,32,0x05,39); DrawChar(50,7,138,0x20,1); DrawChar(10,8,132,0x21,1); DrawChar(11,8,32,0x05,8); DrawChar(15,8,47,0x05,1); DrawChar(19,8,132,0x03,1); DrawChar(20,8,131,0x23,25); DrawChar(45,8,138,0x02,1); DrawChar(46,8,32,0x05,4); DrawChar(50,8,132,0x03,1); DrawChar(10,9,132,0x21,1); DrawChar(11,9,32,0x05,3); DrawChar(14,9,132,0x03,1); DrawChar(15,9,131,0x23,5); DrawChar(45,9,132,0x21,1); DrawChar(46,9,32,0x05,4); DrawChar(50,9,132,0x03,1); DrawChar(11,10,131,0x23,4); DrawChar(46,10,131,0x23,5); DrawFrame(59,6,76,9,&frame3); DrawText(5,7,"Song:",0x21,5); DrawText(4,8,"Order:",0x21,6); DrawText(6,9,"Row:",0x21,4); DrawText(37,9,"Pattern:",0x21,8); DrawText(53,7,"Played",0x21,6); DrawText(53,8,"Volume",0x21,6); /* Put SongName */ DrawText(12,7,Module->Song.SongName,0x05,38); N = Module->Song.NumChannels; /* Draw TrackBox */ DrawFrame(03,11,76,16+N,&frame3); DrawFrame(04,12,75,15+N,&frame4); DrawFrame(11,13,23,14+N,&frame3); DrawFrame(24,13,54,14+N,&frame3); DrawFrame(55,13,72,14+N,&frame3); DrawFrame(06,13,07,14+N,&frame2); DrawFrame(10,13,11,14+N,&frame2); for (I = 1; I <= N; I++) DrawNum2(8,13+I,I,0x21); /* Draw SamplesBox */ J = 2*(28-N); if (J > Module->Song.NumSamples) J = Module->Song.NumSamples; J = (J+1) >> 1; DrawFrame(03,17+N,76,20+N+J,&frame2); DrawFrame(04,18+N,75,19+N+J,&frame3); for (I = 0; I < J; I++) { DrawNum2(06,19+N+I,I+1,0x0f); DrawNum2(41,19+N+I,I+J+1,0x0f); if (Module->Inst[I] != NULL) DrawText(9,19+N+I,Module->Inst[I]->SampleName,0x0b,28); if (Module->Inst[I+J] != NULL) DrawText(44,19+N+I,Module->Inst[I+J]->SampleName,0x0b,28); } /* Start Playing Music */ DSMSetupVoices(Module->Song.NumChannels,Module->Song.MasterVolume); DSMPlayMusic(Module); Music = DSMGetMusicInfo(); Volume = 255; /* Setup the timer service */ #ifdef __TS_H TSInit(); TSSetRate(70); TSSetRoutine(DSMPoll); #endif Key = 0; while (Key != kbEsc) { /* Poll Music System */ #ifndef __TS_H DSMPoll(); #endif /* Update InfoBox */ if (Music->BreakFlag == PB_NONE) { DrawNum(12,8,Music->OrderPosition,0x05); DrawNum(16,8,Music->OrderLength,0x05); DrawNum2(12,9,Music->PatternRow,0x05); DrawNum(47,9,Music->PatternNumber,0x05); DrawMeter(60,7,(32*Music->OrderPosition+(Music->PatternRow >> 1)) / Music->OrderLength); DrawMeter(60,8,Volume >> 3); } /* Update TrackBox */ for (I = 0; I < N; I++) { if (Music->Tracks[I].NoteEvent & 0xFF) DrawChar(5,14+I,140,0x25,1); else DrawChar(5,14+I,140,0x21,1); DrawNote(13,14+I,Music->Tracks[I].Note); DrawNum2(17,14+I,J = Music->Tracks[I].Sample,0x0f); DrawNum2(20,14+I,Music->Tracks[I].Volume,0x0f); if (J != 0) DrawText(26,14+I,Module->Inst[J-1]->SampleName,0x0f,28); DrawBar(56,14+I,Music->Tracks[I].EQBar >> 1); } /* Dispatch Keyboard */ if (Keypressed()) { Key = ReadKey(); switch (Key) { case kbPlus: if (Volume <= 247) DSMSetMusicVolume(Volume += 8); break; case kbMinus: if (Volume >= 8) DSMSetMusicVolume(Volume -= 8); break; case kbSpace: switch (DSMGetMusicStatus()) { case PS_PLAYING: DSMStopMusic(); break; case PS_STOPPED: DSMPlayMusic(Module); break; } break; case kbLeft: Music->OrderPosition--; Music->PatternRow = 0; Music->BreakFlag = PB_JUMP; break; case kbRight: Music->OrderPosition++; Music->PatternRow = 0; Music->BreakFlag = PB_JUMP; break; } } } /* Done timer service and restore time */ #ifdef __TS_H TSDone(); TSRestoreTime(); #endif /* Stop Playing and Free Module */ DSMStopMusic(); DSMFree(Module); /* Shutdown Music System */ DSMDone(); /* Clear the Text Screen */ SetTextMode(); return 0; }