home *** CD-ROM | disk | FTP | other *** search
- #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;
- }
-