MOD-Player [C++, RealMode]
SBOUT.H
int InitBlaster (int,int,int);
void DeinitBlaster (void);
void SetBlasterRate (unsigned int);
void PlayBlaster (long,unsigned int);
void StopBlaster (void);
void SetBlasterHandler (void far*);
MOD.H
typedef struct Module
{unsigned int ChannelNumber;
unsigned int PatternsToPlay;
unsigned char PatternArragement[128];
unsigned char *PatternData[128];
unsigned char *SampleData[31];
unsigned int SampleLength[31];
unsigned int SampleLoopStart[31];
unsigned int SampleLoopLength[31];
unsigned char SampleVolume[31];
int sampleFineTune[31];
};
typedef struct MODsample
{char Name[22];
unsigned int Length;
unsigned char Finetune;
unsigned char Volume;
unsigned int LoopStart;
unsigned int LoopLength;
};
typedef struct MODheader
{char Name[20];
MODsample Samples[31];
unsigned char OrderLen;
unsigned char Dummy;
unsigned char Order[128];
unsigned long Sign;
};
unsigned int xchg( unsigned int data)
{return ((data>8));
}
unsigned int freqTable[296]=
{907, 900, 894, 887, 881, 875, 868, 862, 856,
850, 844, 838, 832, 826, 820, 814, 808,
802, 796, 791, 785, 779, 774, 768, 762,
757, 752, 746, 741, 736, 730, 725, 720,
715, 709, 704, 699, 694, 689, 684, 678,
675, 670, 665, 660, 655, 651, 646, 640,
636, 632, 628, 623, 619, 614, 610, 604,
601, 597, 592, 588, 584, 580, 575, 570,
567, 563, 559, 555, 551, 547, 543, 538,
535, 532, 528, 524, 520, 516, 513, 508,
505, 502, 498, 494, 491, 487, 484, 480,
477, 474, 470, 467, 463, 460, 457, 453,
450, 447, 444, 441, 437, 434, 431, 428,
425, 422, 419, 416, 413, 410, 407, 404,
401, 398, 395, 392, 390, 387, 384, 381,
379, 376, 373, 370, 368, 365, 363, 360,
357, 355, 352, 350, 347, 345, 342, 339,
337, 335, 332, 330, 328, 325, 323, 320,
318, 316, 314, 312, 309, 307, 305, 302,
300, 298, 296, 294, 292, 290, 288, 285,
284, 282, 280, 278, 276, 274, 272, 269,
268, 266, 264, 262, 260, 258, 256, 254,
253, 251, 249, 247, 245, 244, 242, 240,
238, 237, 235, 233, 232, 230, 228, 226,
225, 223, 222, 220, 219, 217, 216, 214,
212, 211, 209, 208, 206, 205, 203, 202,
200, 199, 198, 196, 195, 193, 192, 190,
189, 188, 187, 185, 184, 183, 181, 180,
179, 177, 176, 175, 174, 172, 171, 170,
169, 167, 166, 165, 164, 163, 161, 160,
159, 158, 157, 156, 155, 154, 152, 151,
150, 149, 148, 147, 146, 145, 144, 143,
142, 141, 140, 139, 138, 137, 136, 135,
134, 133, 132, 131, 130, 129, 128, 127,
126, 125, 125, 123, 123, 122, 121, 120,
119, 118, 118, 117, 116, 115, 114, 113,
113, 112, 111, 110, 109, 109, 108
};
int sineTable[32]=
{ 0, 24, 49, 74, 97, 120, 141, 161,
180, 197, 212, 224, 235, 244, 250, 253,
255, 253, 250, 244, 235, 224, 212, 197,
180, 161, 141, 120, 97, 74, 49, 24
};
SB_LO.CPP
#include
int sb_base_port;
int sb_irq_num;
int sb_dma_chan;
int dma_maskport;
int dma_clrport;
int dma_modeport;
int dma_addrport;
int dma_pageport;
int dma_countport;
//unsigned char dma_page;
//unsigned int dma_offset;
//unsigned int dma_size;
void (*user_handler) (void);
void interrupt (*oldvector)(...);
void dsp_write (unsigned char value)
{
while (inportb(sb_base_port+0xC)&0x80);
outportb(sb_base_port+0xC,value);
}
unsigned char dsp_read (void)
{
while (!(inportb(sb_base_port+0xE)&0x80));
return (inportb(sb_base_port+0xA));
}
int dsp_reset (void)
{
int i;
outportb(sb_base_port+6,1);
outportb(sb_base_port+6,0);
i=100;
while ((dsp_read()!=0xAA)&&i--);
return i;
}
void interrupt sb_handler (...)
{
//dsp_read ();
user_handler ();
inportb(sb_base_port+0xE);
outportb (0x20,0x20);
}
int InitBlaster (int sb_port,int sb_irq,int sb_dma)
{
sb_base_port=sb_port;
sb_irq_num=sb_irq;
sb_dma_chan=sb_dma;
dma_maskport=0xA;
dma_clrport=0xC;
dma_modeport=0xB;
dma_addrport=sb_dma_chan*2;
dma_countport=sb_dma_chan*2+1;
switch (sb_dma_chan)
{
case 0:dma_pageport=0x87;break;
case 1:dma_pageport=0x83;break;
case 3:dma_pageport=0x82;break;
}
if (dsp_reset())
{
oldvector=getvect(sb_irq_num+8);
setvect(sb_irq_num+8,sb_handler);
outportb(0x21,inportb(0x21)&~(1>8)&0xFF));
outportb (dma_pageport,((addr>>16)&0xFF));
outportb (dma_countport,((size)&0xFF));
outportb (dma_countport,(((size)>>8)&0xFF));
outportb (dma_maskport,1);
dsp_write (0x14);
dsp_write ((size&0xFF));
dsp_write (((size>>8)&0xFF));
//dsp_write (0x48);
//dsp_write ((size&0xFF));
//dsp_write (((size>>8)&0xFF));
//dsp_write (0x1C);
}
void StopBlaster (void)
{
dsp_write (0xDA);
}
MODPLAY.CPP
#include
#include
#include
#include
#include "mod.h"
#include "sbout.h"
//#pragma inline .386
#define MOD_4CH 0x2E4B2E4D
#define MOD_6CH 0x4E484336
#define MOD_8CH 0x4E484338
#define CH_active 0x0001
#define CH_looped 0x0002
#define NONE 0xFF
#define ARPEGGIO 0x00
#define PORTA_UP 0x01
#define PORTA_DOWN 0x02
#define PORTA_TO_NOTE 0x03
#define CUT_NOTE 0x04
#define VOLUME_SLIDE 0x05
#define VIBRATO 0x06
#define PORTA_VOLUME_SLIDE 0x07
#define VIBRATO_VOLUME_SLIDE 0x08
#define TREMOLO 0x09
#define RETRIG_NOTE 0x0A
#define mixBuffSize 0x80
#define mixFreq 44100
typedef struct channelInfo
{unsigned char sample;
unsigned char *sampleData;
int sampleVolume;
unsigned long sampleLength;
unsigned long sampleLoopStart;
unsigned long sampleLoopLength;
unsigned long samplePosition;
unsigned long sampleIncrement;
unsigned int sampleNote;
unsigned int sampleFreq;
unsigned int flags;
int effect;
int effectCounter;
int effectParam;
unsigned int portaSpeed;
unsigned int freqToPortaTo;
unsigned int vibratoSpeed;
unsigned int vibratoDepth;
unsigned int vibratoNegative;
unsigned int vibratoIndex;
unsigned int tremoloSpeed;
unsigned int tremoloDepth;
unsigned int tremoloNegative;
unsigned int tremoloIndex;
};
channelInfo ci[8];
unsigned int channels;
unsigned char bpm;
unsigned char tempo;
unsigned int mixRate;
unsigned int speed;
unsigned long magic;
unsigned int currientRow;
unsigned int currientPattern;
unsigned int tickCount;
unsigned int oneTick;
unsigned int needToJump;
unsigned int rowToJumpTo;
unsigned int patternToJumpTo;
int volumeTable[65][256];
unsigned char outputTable[2048];
unsigned int startOutput;
unsigned char *mixBuff[2];
unsigned long mixBuffAddr[2];
unsigned char flipFlag;
Module *mod;
Module *MODloadModule( char *name)
{Module *mod;
FILE *in;
MODheader header;
int i,j,r,d,totalch;
unsigned char *note;
unsigned int sampleNum,periodFreq,effectNum,effectParam,temp;
if ((mod=new Module)==NULL) return 0;
if ((in=fopen( name, "rb"))==NULL) return 0;
if ((fread( &header, 1, sizeof(header), in))!=sizeof( header)) return 0;
if (header.Sign==MOD_4CH) mod->ChannelNumber=totalch=4;
else if (header.Sign==MOD_6CH) mod->ChannelNumber=totalch=6;
else if (header.Sign==MOD_8CH) mod->ChannelNumber=totalch=8;
else return 0;
mod->PatternsToPlay=header.OrderLen;
for (i=0;iSampleLength[i]=xchg( header.Samples[i].Length)*2;
mod->SampleLoopStart[i]=xchg( header.Samples[i].LoopStart)*2;
mod->SampleLoopLength[i]=xchg( header.Samples[i].LoopLength)*2;
mod->SampleVolume[i]=header.Samples[i].Volume;
mod->sampleFineTune[i]=header.Samples[i].Finetune;
if (mod->sampleFineTune[i]>7)
mod->sampleFineTune[i]-=16;
}
for (i=j=0;iPatternArragement[i]=header.Order[i];
if (header.Order[i]>j)
j=header.Order[i];
}
j++;
for (i=0;iPatternData[i]=new unsigned char[64*4*totalch];
fread( mod->PatternData[i], 1, 64*4*totalch, in);
}
for (i=0;iPatternData[i];
for (r=0;r>4);
periodFreq=(((unsigned int)note[0]&0x0F)freqTable[d*8]-2)&&(periodFreq=freqTable[d*8])
{temp=d*8;
break;
}
}
*/
periodFreq=temp;
note[0]=sampleNum;
note[1]=(effectNum>8);
note[2]=periodFreq&0xFF;
note[3]=effectParam;
}
}
for (i=0;iSampleLength[i])
{mod->SampleData[i]=new unsigned char[mod->SampleLength[i]];
fread( mod->SampleData[i], 1, mod->SampleLength[i], in);
for (j=0;jSampleLength[i];j++)
mod->SampleData[i][j]^=0x80;
if (mod->SampleLoopLength[i]>2)
{if (mod->SampleLoopStart[i]+mod->SampleLoopLength[i] > mod->SampleLength[i])
{if (mod->SampleLoopLength[i] > mod->SampleLength[i])
{mod->SampleLoopLength[i]=mod->SampleLength[i]-3;
mod->SampleLoopStart[i]=3;
}
else
{mod->SampleLoopStart[i]-=mod->SampleLoopLength[i]+mod->SampleLoopStart[i]-mod->SampleLength[i];
}
}
}
}
}
fclose( in);
return mod;
}
void MODinit( unsigned int freq, unsigned int ch)
{int i,j;
bpm=125;
tempo=6;
mixRate=freq;
speed=(double)mixRate/(((24.0*bpm)/tempo)/60.0);
oneTick=speed/tempo;
magic=(3579545.25/(double)mixRate)*65536.0;
currientRow=0;
currientPattern=0;
needToJump=0;
tickCount=1;
startOutput=ch*128;
channels=ch;
for (i=0;ieffectParam>>4);
y=(ch->effectParam&0xF);
switch (ch->effect)
{case ARPEGGIO:
if (ch->effectCounter==1)
ch->sampleFreq=freqTable[ch->sampleNote+(x*8)+mod->sampleFineTune[ch->sample]];
else if (ch->effectCounter==2)
ch->sampleFreq=freqTable[ch->sampleNote+(y*8)+mod->sampleFineTune[ch->sample]];
else
ch->sampleFreq=freqTable[ch->sampleNote+mod->sampleFineTune[ch->sample]];
if (ch->sampleFreq!=0)
ch->sampleIncrement=magic/ch->sampleFreq;
ch->effectCounter++;
if (ch->effectCounter>2)
ch->effectCounter=0;
break;
case PORTA_UP:
if (ch->effectCounter)
ch->effectCounter--;
else
{ch->sampleFreq-=ch->effectParam;
if (ch->sampleFreqsampleFreq=113;
ch->sampleIncrement=magic/ch->sampleFreq;
}
break;
case PORTA_DOWN:
if (ch->effectCounter)
ch->effectCounter--;
else
{ch->sampleFreq+=ch->effectParam;
if (ch->sampleFreq>856)
ch->sampleFreq=856;
ch->sampleIncrement=magic/ch->sampleFreq;
}
break;
case PORTA_TO_NOTE:
case PORTA_VOLUME_SLIDE:
if (ch->sampleFreqfreqToPortaTo)
{ch->sampleFreq+=ch->portaSpeed;
if (ch->sampleFreq>ch->freqToPortaTo)
ch->sampleFreq=ch->freqToPortaTo;
}
else if (ch->sampleFreq>ch->freqToPortaTo)
{ch->sampleFreq-=ch->portaSpeed;
if (ch->sampleFreqfreqToPortaTo)
ch->sampleFreq=ch->freqToPortaTo;
}
ch->sampleIncrement=magic/ch->sampleFreq;
if (ch->effect==PORTA_VOLUME_SLIDE)
goto doVolume;
break;
case VIBRATO:
case VIBRATO_VOLUME_SLIDE:
t=(ch->vibratoDepth*sineTable[ch->vibratoIndex])>>7;
if (ch->vibratoNegative)
ch->sampleFreq+=t;
else
ch->sampleFreq-=t;
ch->sampleIncrement=magic/ch->sampleFreq;
ch->vibratoIndex+=ch->vibratoSpeed;
if (ch->vibratoIndex>31)
{ch->vibratoIndex-=32;
ch->vibratoNegative^=1;
}
if (ch->effect==VIBRATO_VOLUME_SLIDE)
goto doVolume;
break;
case TREMOLO:
t=(ch->tremoloDepth*sineTable[ch->tremoloIndex])>>6;
if (ch->tremoloNegative)
{ch->sampleVolume-=t;
if (ch->sampleVolumesampleVolume=0;
}
else
{ch->sampleVolume+=t;
if (ch->sampleVolume>0x40)
ch->sampleVolume=0x40;
}
ch->tremoloIndex+=ch->tremoloSpeed;
if (ch->tremoloIndex>31)
{ch->tremoloIndex-=32;
ch->tremoloNegative^=1;
}
break;
case VOLUME_SLIDE:
doVolume:
if (ch->effectCounter)
ch->effectCounter--;
else
{ch->sampleVolume=ch->sampleVolume+x-y;
if (ch->sampleVolumesampleVolume=0;
else if (ch->sampleVolume>64)
ch->sampleVolume=64;
}
break;
}
}
}
void UpdateRow( void)
{int sample,note,effectNum,effectParam;
int i;
unsigned char *noteptr;
unsigned int temp;
channelInfo *ch;
/*if (needToJump)
{if (needToJump==1)
{currientPattern=patternToJumpTo;
}
if (needToJump==2)
{currientPattern=patternToJumpTo;
currientRow=rowToJumpTo;
}
needToJump=0;
}*/
noteptr=(unsigned char*)(mod->PatternData[mod->PatternArragement[currientPattern]]+
currientRow*4*channels);
needToJump=0;
for (i=0,ch=ci;i>4);
note=(((unsigned int)(noteptr[1]&0x0F))effectParam=noteptr[3];
if ((sample)&&(effectNum!=3)&&(effectNum!=5))
{ch->effect=NONE;
ch->flags=0;
sample--;
ch->sample=sample;
ch->sampleData=mod->SampleData[sample];
ch->sampleLength=((unsigned long)mod->SampleLength[sample]samplePosition=0;
ch->sampleVolume=mod->SampleVolume[sample];
if (mod->SampleLoopLength[sample]>2)
{ch->flags|=CH_looped;
ch->sampleLoopStart=((unsigned long)mod->SampleLoopStart[sample]sampleLoopLength=((unsigned long)mod->SampleLoopLength[sample]flags|=CH_active;
}
if ((note!=0x0FFF)&&(effectNum!=3)&&(effectNum!=5))
{ch->effect=NONE;
ch->sampleNote=note;
ch->sampleFreq=freqTable[mod->sampleFineTune[ch->sample]+note];
ch->sampleIncrement=magic/ch->sampleFreq;
ch->vibratoNegative=0;
ch->vibratoIndex=0;
ch->tremoloNegative=0;
ch->tremoloIndex=0;
ch->flags|=CH_active;
}
switch (effectNum)
{case 0x00: //arpeggio
if ((ch->effect==NONE)&&(ch->effectParam!=0))
{ch->effect=ARPEGGIO;
ch->effectCounter=0;
}
break;
case 0x01: //porta up
ch->effect=PORTA_UP;
ch->effectCounter=1;
break;
case 0x02: //porta down
ch->effect=PORTA_DOWN;
ch->effectCounter=1;
break;
case 0x03: //porta_to_note
ch->effect=PORTA_TO_NOTE;
if (ch->effectParam)
ch->portaSpeed=ch->effectParam;
if (note!=0x0FFF)
ch->freqToPortaTo=freqTable[mod->sampleFineTune[ch->sample]+note];
break;
case 0x04: //vibrato
ch->effect=VIBRATO;
if (ch->effectParam)
{ch->vibratoSpeed=(ch->effectParam>>4);
ch->vibratoDepth=(ch->effectParam&0x0F);
}
break;
case 0x05: //porta + volume slide
ch->effect=PORTA_VOLUME_SLIDE;
break;
case 0x06:
ch->effect=VIBRATO_VOLUME_SLIDE;
break;
case 0x07:
ch->effect=TREMOLO;
if (ch->effectParam)
{ch->tremoloSpeed=(ch->effectParam>>4);
ch->tremoloDepth=(ch->effectParam&0x0F);
}
break;
case 0x09: //sample offset
ch->samplePosition=((unsigned long)ch->effectParameffect=VOLUME_SLIDE;
ch->effectCounter=1;
break;
case 0x0B:
//needToJump=1;
//patternToJumpTo=ch->effectParam;
currientRow=63;
currientPattern=ch->effectParam-1;
break;
case 0xC:
ch->sampleVolume=(ch->effectParam>64)?64:ch->effectParam;
break;
case 0xD:
/*if (needToJump!=1) patternToJumpTo=currientPattern+1;
needToJump=2;
temp=((ch->effectParam>>4)*10)+(ch->effectParam&0x0F);
rowToJumpTo=(tempeffectParam>>4)*10)+(ch->effectParam&0x0F)-1;
currientPattern++;
}
break;
case 0xE:
switch (ch->effectParam>>4)
{case 0x01:
ch->sampleFreq-=(ch->effectParam&0x0F);
ch->sampleIncrement=magic/ch->sampleFreq;
break;
case 0x02:
ch->sampleFreq+=(ch->effectParam&0x0F);
ch->sampleIncrement=magic/ch->sampleFreq;
break;
case 0x05:
mod->sampleFineTune[sample]=ch->effectParam&0x0F;
if (mod->sampleFineTune[sample]>7)
mod->sampleFineTune[sample]-=16;
break;
case 0xA:
ch->sampleVolume+=(ch->effectParam&0x0F);
if (ch->sampleVolume>0x40)
ch->sampleVolume=0x40;
break;
case 0xB:
ch->sampleVolume-=(ch->effectParam&0x0F);
if (ch->sampleVolumesampleVolume=0;
break;
}
break;
case 0xF:
if (ch->effectParameffectParam;
else bpm=ch->effectParam;
speed=(double)mixRate/(((24.0*bpm)/tempo)/60.0);
oneTick=speed/tempo;
break;
default:
ch->effect=NONE;
break;
}
}
currientRow++;
if (currientRow==64)
{currientRow=0;
currientPattern++;
if (currientPattern>mod->PatternsToPlay) currientPattern=0;
}
}
/*void UpdateNoLoop( Channel *ch)
{asm push es
asm push di
asm push eax
asm push ebx
asm push ecx
asm les di,[bp+6]
asm mov eax,dword ptr es:[di+16]
asm mov ecx,dword ptr es:[di+20]
asm add eax,ecx
asm mov ebx,dword ptr es:[di+4]
asm cmp eax,ebx
asm jb l1:
asm mov word ptr es:[di+23],0
asm jmp l2:
l1:
asm add dword ptr es:[di+16],ecx
l2:
asm pop ecx
asm pop ebx
asm pop eax
asm pop di
asm pop es
}
void UpdateLooped( Channel *ch)
{asm push es
asm push di
asm push eax
asm push ebx
asm push ecx
asm les di,[bp+6]
asm mov eax,dword ptr es:[di+16]
asm mov ecx,dword ptr es:[di+20]
asm add eax,ecx
asm mov ebx,dword ptr es:[di+8]
asm add ebx,dword ptr es:[di+12]
asm cmp eax,ebx
asm jb looped1
asm mov ecx,dword ptr es:[di+8]
asm mov dword ptr es:[di+16],ecx
asm jmp looped2
looped1:
asm add dword ptr es:[di+16],ecx
looped2:
asm pop ecx
asm pop ebx
asm pop eax
asm pop di
asm pop es
} */
void Mix8bitMono( int MixLength, char *buffer)
{channelInfo *chptr;
int MixCount;
int i,j;
int output;
MixCount=MixLength;
while (MixCount)
{chptr=ci;
output=startOutput;
oneTick--;
if (oneTick==0)
{BitTrack();
oneTick=speed/tempo;
}
tickCount--;
if (tickCount==0)
{UpdateRow();
tickCount=speed;
}
for (i=0;iflags&CH_active)
{output+=volumeTable[chptr->sampleVolume][chptr->sampleData[(chptr->samplePosition>>16)]];
if (chptr->flags&CH_looped)
{if ((chptr->samplePosition+chptr->sampleIncrement) sampleLoopStart+chptr->sampleLoopLength))
{chptr->samplePosition+=chptr->sampleIncrement;
}
else
{chptr->samplePosition=chptr->sampleLoopStart;
}
//UpdateLooped( chptr);
}
else
{if ((chptr->samplePosition+chptr->sampleIncrement) sampleLength)
{chptr->samplePosition+=chptr->sampleIncrement;
}
else
{chptr->flags=0;
}
//UpdateNoLoop( chptr);
}
}
}
*(buffer++)=outputTable[output];
MixCount--;
}
}
void MyHandler( void)
{PlayBlaster( mixBuffAddr[!flipFlag], mixBuffSize);
//MixBuffer(MixBuf[!flag],MixBuffSize);
flipFlag=!flipFlag;
}
void main (int,char *argv[])
{
int i;
if ((mod=MODloadModule( argv[1]))==0) return;
MODinit( mixFreq, mod->ChannelNumber);
InitBlaster( 0x220, 5, 1);
SetBlasterRate( mixFreq);
SetBlasterHandler( (void far*)MyHandler);
mixBuff[0]=new unsigned char[mixBuffSize];
mixBuff[1]=new unsigned char[mixBuffSize];
mixBuffAddr[0]=FP_SEG( mixBuff[0])*16L+FP_OFF( mixBuff[0]);
mixBuffAddr[1]=FP_SEG( mixBuff[1])*16L+FP_OFF( mixBuff[1]);
Mix8bitMono( mixBuffSize, mixBuff[0]);
Mix8bitMono( mixBuffSize, mixBuff[1]);
flipFlag=i=0;
PlayBlaster( mixBuffAddr[0], mixBuffSize);
while (!kbhit())
{if (i!=flipFlag)
{Mix8bitMono( mixBuffSize, mixBuff[i]);
i=flipFlag;
}
}
getch();
StopBlaster();
DeinitBlaster();
}