home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 15
/
CD_ASCQ_15_070894.iso
/
vrac
/
mikmod43.zip
/
MODPLAY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-30
|
16KB
|
768 lines
#include <dos.h>
#include <stdlib.h>
#include "mytypes.h"
#include "modload.h"
#include "modplay.h"
MODFILE *pf; // <- this modfile is being played
UBYTE *patptr; // pointer to the current pattern (first row)
UBYTE *rowptr; // pointer to the current row
UWORD reppos; // patternloop position
UWORD repcnt; // times to loop
UWORD patpos; // current row
UWORD sngpos; // current song position
UWORD sngspd; // current songspeed
UWORD vbtick; // tick counter
UWORD patbrk; // patternbreak position
UBYTE patdly; // patterndelay counter
UBYTE jstbrk; // breakflag
int forbid; // forbidflag
/*
Set forbid to 1 when you want to modify any of the sngpos, patpos etc.
variables and clear it when you're done. This prevents getting strange
results due to intermediate interrupts.
*/
AUDTMP mp_audio[8]; // max eight channels
UBYTE mp_bpm; // beats-per-minute speed
UBYTE mp_mainvol=80; // main volume 0%-100%
int mp_extspdflag=1; // extended speed flag, default enabled
void (*PlayRout)(int chn,AUDTMP *aud,MODFILE *mf)=NULL;
UBYTE VibratoTable[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
};
UWORD npertab[16][60]={
// -> Tuning 0
1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906,
856,808,762,720,678,640,604,570,538,508,480,453,
428,404,381,360,339,320,302,285,269,254,240,226,
214,202,190,180,170,160,151,143,135,127,120,113,
107,101,95,90,85,80,75,71,67,63,60,56,
// -> Tuning 1
1700,1604,1514,1430,1348,1274,1202,1134,1070,1010,954,900,
850,802,757,715,674,637,601,567,535,505,477,450,
425,401,379,357,337,318,300,284,268,253,239,225,
213,201,189,179,169,159,150,142,134,126,119,113,
106,100,94,89,84,79,75,71,67,63,59,56,
// -> Tuning 2
1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,894,
844,796,752,709,670,632,597,563,532,502,474,447,
422,398,376,355,335,316,298,282,266,251,237,224,
211,199,188,177,167,158,149,141,133,125,118,112,
105,99,94,88,83,79,74,70,66,62,59,56,
// -> Tuning 3
1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,888,
838,791,746,704,665,628,592,559,528,498,470,444,
419,395,373,352,332,314,296,280,264,249,235,222,
209,198,187,176,166,157,148,140,132,125,118,111,
104,99,93,88,83,78,74,70,66,62,59,55,
// -> Tuning 4
1664,1570,1482,1398,1320,1246,1176,1110,1048,990,934,882,
832,785,741,699,660,623,588,555,524,495,467,441,
416,392,370,350,330,312,294,278,262,247,233,220,
208,196,185,175,165,156,147,139,131,124,117,110,
104,98,92,87,82,78,73,69,65,62,58,55,
// -> Tuning 5
1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,874,
826,779,736,694,655,619,584,551,520,491,463,437,
413,390,368,347,328,309,292,276,260,245,232,219,
206,195,184,174,164,155,146,138,130,123,116,109,
103,97,92,87,82,77,73,69,65,61,58,54,
// -> Tuning 6
1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,868,
820,774,730,689,651,614,580,547,516,487,460,434,
410,387,365,345,325,307,290,274,258,244,230,217,
205,193,183,172,163,154,145,137,129,122,115,109,
102,96,91,86,81,77,72,68,64,61,57,54,
// -> Tuning 7
1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,862,
814,768,725,684,646,610,575,543,513,484,457,431,
407,384,363,342,323,305,288,272,256,242,228,216,
204,192,181,171,161,152,144,136,128,121,114,108,
102,96,90,85,80,76,72,68,64,60,57,54,
// -> Tuning -8
1814,1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,
907,856,808,762,720,678,640,604,570,538,508,480,
453,428,404,381,360,339,320,302,285,269,254,240,
226,214,202,190,180,170,160,151,143,135,127,120,
113,107,101,95,90,85,80,75,71,67,63,60,
// -> Tuning -7
1800,1700,1604,1514,1430,1350,1272,1202,1134,1070,1010,954,
900,850,802,757,715,675,636,601,567,535,505,477,
450,425,401,379,357,337,318,300,284,268,253,238,
225,212,200,189,179,169,159,150,142,134,126,119,
112,106,100,94,89,84,79,75,71,67,63,59,
// -> Tuning -6
1788,1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,
894,844,796,752,709,670,632,597,563,532,502,474,
447,422,398,376,355,335,316,298,282,266,251,237,
223,211,199,188,177,167,158,149,141,133,125,118,
111,105,99,94,88,83,79,74,70,66,62,59,
// -> Tuning -5
1774,1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,
887,838,791,746,704,665,628,592,559,528,498,470,
444,419,395,373,352,332,314,296,280,264,249,235,
222,209,198,187,176,166,157,148,140,132,125,118,
111,104,99,93,88,83,78,74,70,66,62,59,
// -> Tuning -4
1762,1664,1570,1482,1398,1320,1246,1176,1110,1048,988,934,
881,832,785,741,699,660,623,588,555,524,494,467,
441,416,392,370,350,330,312,294,278,262,247,233,
220,208,196,185,175,165,156,147,139,131,123,117,
110,104,98,92,87,82,78,73,69,65,61,58,
// -> Tuning -3
1750,1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,
875,826,779,736,694,655,619,584,551,520,491,463,
437,413,390,368,347,328,309,292,276,260,245,232,
219,206,195,184,174,164,155,146,138,130,123,116,
109,103,97,92,87,82,77,73,69,65,61,58,
// -> Tuning -2
1736,1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,
868,820,774,730,689,651,614,580,547,516,487,460,
434,410,387,365,345,325,307,290,274,258,244,230,
217,205,193,183,172,163,154,145,137,129,122,115,
108,102,96,91,86,81,77,72,68,64,61,57,
// -> Tuning -1
1724,1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,
862,814,768,725,684,646,610,575,543,513,484,457,
431,407,384,363,342,323,305,288,272,256,242,228,
216,203,192,181,171,161,152,144,136,128,121,114,
108,101,96,90,85,80,76,72,68,64,60,57
};
void GetPatPtr(void)
{
patpos=0;
patptr=pf->patterns[pf->positions[sngpos]];
}
void NewPatPtr(void)
{
sngpos++;
if(sngpos==pf->songlength) sngpos=0;
GetPatPtr();
}
void DoEEffects(AUDTMP *a)
{
UBYTE eff,dat,nib;
eff=a->eff;
dat=a->dat;
nib=dat&0xf;
switch(dat>>4){
case 0x0: // filter toggle, not supported
break;
case 0x1: // fineslide up
a->tmpperiod-=nib;
eff=dat=0; // only once
break;
case 0x2: // fineslide dn
a->tmpperiod+=nib;
eff=dat=0; // only once
break;
case 0x3: // glissando ctrl
a->glissando=nib;
break;
case 0x4: // set vibrato waveform
a->wavecontrol&=0xf0;
a->wavecontrol|=nib;
break;
case 0x5: // set finetune
a->finetune=nib;
a->tmpperiod=npertab[nib][a->note];
eff=dat=0;
break;
case 0x6: // set patternloop
/* hmm.. this one is a real kludge. But now it
works. */
if(nib){ // set reppos or repcnt ?
/* set repcnt, so check if repcnt already is set,
which means we are already looping */
if(repcnt>0)
repcnt--; // already looping, decrease counter
else
repcnt=nib; // not yet looping, so set repcnt
if(repcnt) // jump to reppos if repcnt>0
patpos=reppos;
}
else{
reppos=patpos-1; // set reppos
}
eff=dat=0;
break;
case 0x7: // set tremolo waveform
a->wavecontrol&=0x0f;
a->wavecontrol|=nib<<4;
break;
case 0x8: // not used
break;
case 0x9: // retrig note
/* only retrigger if
data nibble > 0 */
if(nib>0){
if(a->retrig==0){
/* when retrig counter reaches 0,
reset counter and restart the sample */
a->kick=1;
a->retrig=nib;
}
a->retrig--; // countdown
}
break;
case 0xa: // fine volume slide up
a->tmpvolume+=nib;
if(a->tmpvolume>64) a->tmpvolume=64;
eff=dat=0;
break;
case 0xb: // fine volume slide dn
a->tmpvolume-=nib;
if(a->tmpvolume<0) a->tmpvolume=0;
eff=dat=0; // only once
break;
case 0xc: // cut note
/* When vbtick reaches the cut-note value,
turn the volume to zero ( Just like
on the amiga) */
if(vbtick>=nib){
a->tmpvolume=0; // just turn the volume down
eff=dat=0;
}
break;
case 0xd: // note delay
/* delay the start of the
sample until vbtick>=nib */
if(vbtick>=nib){
a->kick=1;
eff=dat=0;
}
else a->kick=0;
break;
case 0xe: // pattern delay
patdly=nib;
eff=dat=0;
break;
case 0xf: // invert loop, not supported
break;
}
a->eff=eff;
a->dat=dat;
}
void DoVibrato(AUDTMP *a)
{
UBYTE q;
UWORD temp;
q=(a->vibpos>>2)&0x1f;
switch(a->wavecontrol&3){
case 0: // sine
temp=VibratoTable[q];
break;
case 1: // ramp down
q<<=3;
if(a->vibpos<0) q=255-q;
temp=q;
break;
case 2: // square wave
temp=255;
break;
}
temp*=a->vibdepth;
temp>>=7;
if(a->vibpos>=0)
a->period=a->tmpperiod+temp;
else
a->period=a->tmpperiod-temp;
if(vbtick) a->vibpos+=a->vibspd; // do not update when vbtick==0
}
void DoTremolo(AUDTMP *a)
{
UBYTE q;
UWORD temp;
q=(a->trmpos>>2)&0x1f;
switch((a->wavecontrol>>4)&3){
case 0: // sine
temp=VibratoTable[q];
break;
case 1: // ramp down
q<<=3;
if(a->trmpos<0) q=255-q;
temp=q;
break;
case 2: // square wave
temp=255;
break;
}
temp*=a->trmdepth;
temp>>=6;
if(a->trmpos>=0){
a->volume=a->tmpvolume+temp;
if(a->volume>64) a->volume=64;
}
else{
a->volume=a->tmpvolume-temp;
if(a->volume<0) a->volume=0;
}
if(vbtick) a->trmpos+=a->trmspd; // do not update when vbtick==0
}
void DoVolSlide(AUDTMP *a)
{
if(!vbtick) return; // do not update when vbtick==0
a->tmpvolume+=(a->dat>>4); // volume slide
a->tmpvolume-=(a->dat&0xf);
if(a->tmpvolume<0) a->tmpvolume=0;
if(a->tmpvolume>64) a->tmpvolume=64;
}
void DoToneSlide(AUDTMP *a)
{
int dist,t;
if(!vbtick){ // do not update when vbtick==0
a->period=a->tmpperiod;
return;
}
/* We have to slide a->tmpperiod towards a->wantedperiod, so
compute the difference between those two values */
dist=a->tmpperiod-a->wantedperiod;
if( dist==0 || // if they are equal
a->portspeed>abs(dist) ){ // or if portamentospeed is too big
a->tmpperiod=a->wantedperiod; // make tmpperiod equal tperiod
}
else if(dist>0){ // dist>0 ?
a->tmpperiod-=a->portspeed; // then slide up
}
else
a->tmpperiod+=a->portspeed; // dist<0 -> slide down
if(a->glissando){
/* If glissando is on, find the nearest
halfnote to a->tmpperiod */
for(t=0;t<60;t++){
if(a->tmpperiod>=npertab[a->finetune][t]) break;
}
a->period=npertab[a->finetune][t];
}
else
a->period=a->tmpperiod;
}
void DoEffect(AUDTMP *a)
{
UBYTE eff,dat,note;
WORD temp,hi,lo,arp=0;
eff=a->eff;
dat=a->dat;
note=a->note;
switch(eff){
case 0x0: // arpeggio
if(dat!=0){
switch(vbtick%3){
case 1:
note+=(dat>>4); break;
case 2:
note+=(dat&0xf); break;
}
a->period=npertab[a->finetune&0xf][note];
arp=1; // <-- v0.42 bugfix
}
break;
case 0x1: // portamento up
if(vbtick) a->tmpperiod-=dat;
break;
case 0x2: // portamento dn
if(vbtick) a->tmpperiod+=dat;
break;
case 0x3: // toneportamento (toneslide)
if(dat!=0) a->portspeed=dat;
DoToneSlide(a);
break;
case 0x4: // vibrato
if(dat&0x0f) a->vibdepth=dat&0xf;
if(dat&0xf0) a->vibspd=(dat&0xf0)>>2;
dat=0;
DoVibrato(a);
break;
case 0x5: // tone+volume slide
DoToneSlide(a);
DoVolSlide(a);
break;
case 0x6: // vibrato + volslide
DoVibrato(a);
DoVolSlide(a);
break;
case 0x7: // tremolo
if(dat&0x0f) a->trmdepth=dat&0xf;
if(dat&0xf0) a->trmspd=(dat&0xf0)>>2;
dat=0;
DoTremolo(a);
break;
case 0x8: // unused
break;
case 0x9: // set sampleoffset
a->start=(ULONG)dat<<8;
if(a->start>a->size) a->start=a->size;
eff=dat=0;
break;
case 0xa: // volume slide
DoVolSlide(a);
break;
case 0xb: // position jump
sngpos=dat;
if(sngpos>=pf->songlength) sngpos=0;
GetPatPtr();
eff=dat=0;
break;
case 0xc: // set volume
a->tmpvolume=dat;
if(a->tmpvolume>64) a->tmpvolume=64;
else if(a->tmpvolume<0) a->tmpvolume=0;
eff=dat=0;
break;
case 0xd: // patternbreak
if(!jstbrk){ // ignore when jstbrk==true
hi=(dat&0xf0)>>4;
lo=(dat&0xf);
patbrk=(hi*10)+lo+1;
if(patbrk>64) patbrk=64; // <- v0.42 fix
}
eff=dat=0;
break;
case 0xe: // extended effects
DoEEffects(a);
eff=a->eff;
dat=a->dat;
break;
case 0xf: // set speed
if(mp_extspdflag && dat>=0x20){
mp_bpm=dat;
}
else{
sngspd=dat;
}
eff=dat=0;
break;
}
a->eff=eff;
a->dat=dat;
// Effects 0,3,4,5,6 set period themselves
if( !arp && (eff<0x3 || eff>0x6) ) a->period=a->tmpperiod;
// Effect 7 sets volume itself
if(eff!=0x7) a->volume=a->tmpvolume;
}
void PlayNote(UBYTE *p,AUDTMP *aud)
{
UWORD period;
UBYTE inst,note;
inst=((p[0]&0xc0)>>2)|((p[1]&0xf0)>>4);
note=p[0]&0x3f;
aud->eff=p[1]&0xf;
aud->dat=p[2];
if(inst!=0){ // instrument change ?
inst--; // yes, so put all instrument values into aud
aud->sample=inst;
aud->handle=pf->samples[inst].handle;
aud->tmpvolume=pf->samples[inst].volume;
aud->size=pf->samples[inst].length;
aud->finetune=pf->samples[inst].finetune;
aud->retrig=0;
}
else inst=aud->sample; // no inst change, so use last instrument
// enable loop if neccesary
if(pf->samples[inst].replen>2){
aud->size=pf->samples[inst].reppos+pf->samples[inst].replen;
aud->loop=pf->samples[inst].reppos;
}
else aud->loop=pf->samples[inst].length;
if(note!=0){
note--;
aud->note=note;
period=npertab[pf->samples[inst].finetune&0xf][note];
aud->wantedperiod=period;
if(aud->eff!=0x3 && aud->eff!=0x5){
aud->tmpperiod=period;
aud->kick=1;
aud->start=0;
}
// retrig tremolo and vibrato waves ?
if(!(aud->wavecontrol&0x80)) aud->trmpos=0;
if(!(aud->wavecontrol&0x08)) aud->vibpos=0;
}
}
void MP_HandleTick(void)
{
int t;
if(forbid) return; // don't go any further when forbid is true
if(++vbtick>=sngspd){
// pattern delay active ? -> wait patdly*sngspd ticks
if(patdly){
patdly--;
}
else{
/* Do we have to get a new patternpointer ?
(when patpos reaches 64 or when
a patternbreak is active) */
if( patpos==64 || patbrk ){
NewPatPtr(); // yes, get new pattern pointer
if(patbrk){ // if patternbreak, set new patpos
patpos=patbrk-1;
jstbrk=1;
/* By making jstbrk true, patternbreak
commands on this row will be ignored */
}
else patpos=0;
}
rowptr=&patptr[3*patpos*pf->numchn];
for(t=0;t<pf->numchn;t++){
PlayNote(&rowptr[t*3],&mp_audio[t]);
}
patpos++;
patbrk=0;
}
vbtick=0;
}
else jstbrk=0;
for(t=0;t<pf->numchn;t++){
DoEffect(&mp_audio[t]);
}
for(t=0;t<pf->numchn;t++){
if(PlayRout!=NULL) PlayRout(t,&mp_audio[t],pf);
}
}
void MP_Init(MODFILE *m)
{
int t;
pf=m;
reppos=0;
repcnt=0;
sngpos=0;
sngspd=6;
vbtick=5;
patbrk=0;
patdly=0;
mp_bpm=125;
forbid=0;
/* Make sure the player doesn't start with garbage: */
for(t=0;t<pf->numchn;t++){
mp_audio[t].kick=0;
mp_audio[t].tmpvolume=0;
mp_audio[t].retrig=0;
mp_audio[t].wavecontrol=0;
mp_audio[t].glissando=0;
}
GetPatPtr();
}
void MP_RegisterPlayer(void (*Player)(int chn,AUDTMP *aud,MODFILE *mf))
{
PlayRout=Player;
}
void MP_ExtSpd(int yesno)
{
mp_extspdflag=yesno;
}
void MP_MainVol(UBYTE volume)
{
mp_mainvol=(volume>100) ? 100 : volume;
}
void MP_NextPosition(void)
{
forbid=1;
sngpos=(sngpos>=(pf->songlength-1)) ? 0 : sngpos+1;
GetPatPtr();
vbtick=sngspd;
forbid=0;
}
void MP_PrevPosition(void)
{
forbid=1;
sngpos=(sngpos==0) ? pf->songlength-1 : sngpos-1;
GetPatPtr();
vbtick=sngspd;
forbid=0;
}