/* Name: MPLAYER.C Description: The actual modplaying routines Portability: All systems - all compilers */ package audio.jmikmod.MikMod.MPlayer; import java.io.*; import audio.jmikmod.MikMod.*; public class clMPlayer { public clMain m_; /* Envelope flags: */ public static final int EF_ON = 1; public static final int EF_SUSTAIN = 2; public static final int EF_LOOP = 4; public float speed_constant; public boolean quit; public int pause_flag; public boolean play_current; public int ui_result; public UNIMOD pf; /* <- this modfile is being played */ public short reppos; /* patternloop position */ public short repcnt; /* times to loop */ public short vbtick; /* tick counter */ public short patbrk; /* position where to start a new pattern */ public short patdly; /* patterndelay counter */ public short patdly2; /* patterndelay counter */ public short numrow; /* number of rows on current pattern */ public short posjmp; /* flag to indicate a position jump is needed... changed since 1.00: now also indicates the direction the position has to jump to: 0: Don't do anything 1: Jump back 1 position 2: Restart on current position 3: Jump forward 1 position */ public boolean forbid; /* forbidflag */ protected int isfirst; /* Set forbid to 1 when you want to modify any of the mp_sngpos, mp_patpos etc. variables and clear it when you're done. This prevents getting strange results due to intermediate interrupts. */ public AUDTMP mp_audio[]; //[32]; /* max 32 channels */ public short mp_bpm; /* beats-per-minute speed */ public short mp_patpos; /* current row number (0-255) */ public short mp_sngpos; /* current song position */ public short mp_sngspd; /* current songspeed */ public short mp_channel; /* channel it's working on */ public boolean mp_extspd; /* extended speed flag, default enabled */ public boolean mp_panning; /* panning flag, default enabled */ public boolean mp_loop; /* loop module ? */ public short mp_volume; /* song volume (0-100) (or user volume) */ protected byte globalvolume; /* global volume */ protected short globalslide; public AUDTMP a; /* current AUDTMP it's working on */ public float old_bpm; //extern float speed_constant; //extern int m_.quiet; //extern curmod m_.cur_mod; static short [] toshortarray(int [] intarray) { short shortarray[] = new short[intarray.length]; int i; for(i=0;i<intarray.length;i++) shortarray[i] = (short)intarray[i]; return shortarray; } protected static final short mytab[] = { // 12 (short)(1712*16),(short)(1616*16),(short)(1524*16),(short)(1440*16),(short)(1356*16),(short)(1280*16), (short)(1208*16),(short)(1140*16),(short)(1076*16),(short)(1016*16),(short)(960*16),(short)(907*16) }; protected short 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 };*/ /* linear periods to frequency translation table: */ protected static final int lintab[]={ //768 16726,16741,16756,16771,16786,16801,16816,16832,16847,16862,16877,16892,16908,16923,16938,16953, 16969,16984,16999,17015,17030,17046,17061,17076,17092,17107,17123,17138,17154,17169,17185,17200, 17216,17231,17247,17262,17278,17293,17309,17325,17340,17356,17372,17387,17403,17419,17435,17450, 17466,17482,17498,17513,17529,17545,17561,17577,17593,17608,17624,17640,17656,17672,17688,17704, 17720,17736,17752,17768,17784,17800,17816,17832,17848,17865,17881,17897,17913,17929,17945,17962, 17978,17994,18010,18027,18043,18059,18075,18092,18108,18124,18141,18157,18174,18190,18206,18223, 18239,18256,18272,18289,18305,18322,18338,18355,18372,18388,18405,18421,18438,18455,18471,18488, 18505,18521,18538,18555,18572,18588,18605,18622,18639,18656,18672,18689,18706,18723,18740,18757, 18774,18791,18808,18825,18842,18859,18876,18893,18910,18927,18944,18961,18978,18995,19013,19030, 19047,19064,19081,19099,19116,19133,19150,19168,19185,19202,19220,19237,19254,19272,19289,19306, 19324,19341,19359,19376,19394,19411,19429,19446,19464,19482,19499,19517,19534,19552,19570,19587, 19605,19623,19640,19658,19676,19694,19711,19729,19747,19765,19783,19801,19819,19836,19854,19872, 19890,19908,19926,19944,19962,19980,19998,20016,20034,20052,20071,20089,20107,20125,20143,20161, 20179,20198,20216,20234,20252,20271,20289,20307,20326,20344,20362,20381,20399,20418,20436,20455, 20473,20492,20510,20529,20547,20566,20584,20603,20621,20640,20659,20677,20696,20715,20733,20752, 20771,20790,20808,20827,20846,20865,20884,20902,20921,20940,20959,20978,20997,21016,21035,21054, 21073,21092,21111,21130,21149,21168,21187,21206,21226,21245,21264,21283,21302,21322,21341,21360, 21379,21399,21418,21437,21457,21476,21496,21515,21534,21554,21573,21593,21612,21632,21651,21671, 21690,21710,21730,21749,21769,21789,21808,21828,21848,21867,21887,21907,21927,21946,21966,21986, 22006,22026,22046,22066,22086,22105,22125,22145,22165,22185,22205,22226,22246,22266,22286,22306, 22326,22346,22366,22387,22407,22427,22447,22468,22488,22508,22528,22549,22569,22590,22610,22630, 22651,22671,22692,22712,22733,22753,22774,22794,22815,22836,22856,22877,22897,22918,22939,22960, 22980,23001,23022,23043,23063,23084,23105,23126,23147,23168,23189,23210,23230,23251,23272,23293, 23315,23336,23357,23378,23399,23420,23441,23462,23483,23505,23526,23547,23568,23590,23611,23632, 23654,23675,23696,23718,23739,23761,23782,23804,23825,23847,23868,23890,23911,23933,23954,23976, 23998,24019,24041,24063,24084,24106,24128,24150,24172,24193,24215,24237,24259,24281,24303,24325, 24347,24369,24391,24413,24435,24457,24479,24501,24523,24545,24567,24590,24612,24634,24656,24679, 24701,24723,24746,24768,24790,24813,24835,24857,24880,24902,24925,24947,24970,24992,25015,25038, 25060,25083,25105,25128,25151,25174,25196,25219,25242,25265,25287,25310,25333,25356,25379,25402, 25425,25448,25471,25494,25517,25540,25563,25586,25609,25632,25655,25678,25702,25725,25748,25771, 25795,25818,25841,25864,25888,25911,25935,25958,25981,26005,26028,26052,26075,26099,26123,26146, 26170,26193,26217,26241,26264,26288,26312,26336,26359,26383,26407,26431,26455,26479,26502,26526, 26550,26574,26598,26622,26646,26670,26695,26719,26743,26767,26791,26815,26839,26864,26888,26912, 26937,26961,26985,27010,27034,27058,27083,27107,27132,27156,27181,27205,27230,27254,27279,27304, 27328,27353,27378,27402,27427,27452,27477,27502,27526,27551,27576,27601,27626,27651,27676,27701, 27726,27751,27776,27801,27826,27851,27876,27902,27927,27952,27977,28003,28028,28053,28078,28104, 28129,28155,28180,28205,28231,28256,28282,28307,28333,28359,28384,28410,28435,28461,28487,28513, 28538,28564,28590,28616,28642,28667,28693,28719,28745,28771,28797,28823,28849,28875,28901,28927, 28953,28980,29006,29032,29058,29084,29111,29137,29163,29190,29216,29242,29269,29295,29322,29348, 29375,29401,29428,29454,29481,29507,29534,29561,29587,29614,29641,29668,29694,29721,29748,29775, 29802,29829,29856,29883,29910,29937,29964,29991,30018,30045,30072,30099,30126,30154,30181,30208, 30235,30263,30290,30317,30345,30372,30400,30427,30454,30482,30509,30537,30565,30592,30620,30647, 30675,30703,30731,30758,30786,30814,30842,30870,30897,30925,30953,30981,31009,31037,31065,31093, 31121,31149,31178,31206,31234,31262,31290,31319,31347,31375,31403,31432,31460,31489,31517,31546, 31574,31602,31631,31660,31688,31717,31745,31774,31803,31832,31860,31889,31918,31947,31975,32004, 32033,32062,32091,32120,32149,32178,32207,32236,32265,32295,32324,32353,32382,32411,32441,32470, 32499,32529,32558,32587,32617,32646,32676,32705,32735,32764,32794,32823,32853,32883,32912,32942, 32972,33002,33031,33061,33091,33121,33151,33181,33211,33241,33271,33301,33331,33361,33391,33421 }; protected static final int LOGFAC=2*16; protected static final short logtab[] = { (short)(LOGFAC*907),(short)(LOGFAC*900),(short)(LOGFAC*894),(short)(LOGFAC*887),(short)(LOGFAC*881),(short)(LOGFAC*875),(short)(LOGFAC*868),(short)(LOGFAC*862), (short)(LOGFAC*856),(short)(LOGFAC*850),(short)(LOGFAC*844),(short)(LOGFAC*838),(short)(LOGFAC*832),(short)(LOGFAC*826),(short)(LOGFAC*820),(short)(LOGFAC*814), (short)(LOGFAC*808),(short)(LOGFAC*802),(short)(LOGFAC*796),(short)(LOGFAC*791),(short)(LOGFAC*785),(short)(LOGFAC*779),(short)(LOGFAC*774),(short)(LOGFAC*768), (short)(LOGFAC*762),(short)(LOGFAC*757),(short)(LOGFAC*752),(short)(LOGFAC*746),(short)(LOGFAC*741),(short)(LOGFAC*736),(short)(LOGFAC*730),(short)(LOGFAC*725), (short)(LOGFAC*720),(short)(LOGFAC*715),(short)(LOGFAC*709),(short)(LOGFAC*704),(short)(LOGFAC*699),(short)(LOGFAC*694),(short)(LOGFAC*689),(short)(LOGFAC*684), (short)(LOGFAC*678),(short)(LOGFAC*675),(short)(LOGFAC*670),(short)(LOGFAC*665),(short)(LOGFAC*660),(short)(LOGFAC*655),(short)(LOGFAC*651),(short)(LOGFAC*646), (short)(LOGFAC*640),(short)(LOGFAC*636),(short)(LOGFAC*632),(short)(LOGFAC*628),(short)(LOGFAC*623),(short)(LOGFAC*619),(short)(LOGFAC*614),(short)(LOGFAC*610), (short)(LOGFAC*604),(short)(LOGFAC*601),(short)(LOGFAC*597),(short)(LOGFAC*592),(short)(LOGFAC*588),(short)(LOGFAC*584),(short)(LOGFAC*580),(short)(LOGFAC*575), (short)(LOGFAC*570),(short)(LOGFAC*567),(short)(LOGFAC*563),(short)(LOGFAC*559),(short)(LOGFAC*555),(short)(LOGFAC*551),(short)(LOGFAC*547),(short)(LOGFAC*543), (short)(LOGFAC*538),(short)(LOGFAC*535),(short)(LOGFAC*532),(short)(LOGFAC*528),(short)(LOGFAC*524),(short)(LOGFAC*520),(short)(LOGFAC*516),(short)(LOGFAC*513), (short)(LOGFAC*508),(short)(LOGFAC*505),(short)(LOGFAC*502),(short)(LOGFAC*498),(short)(LOGFAC*494),(short)(LOGFAC*491),(short)(LOGFAC*487),(short)(LOGFAC*484), (short)(LOGFAC*480),(short)(LOGFAC*477),(short)(LOGFAC*474),(short)(LOGFAC*470),(short)(LOGFAC*467),(short)(LOGFAC*463),(short)(LOGFAC*460),(short)(LOGFAC*457), (short)(LOGFAC*453),(short)(LOGFAC*450),(short)(LOGFAC*447),(short)(LOGFAC*443),(short)(LOGFAC*440),(short)(LOGFAC*437),(short)(LOGFAC*434),(short)(LOGFAC*431) }; ; /*={ LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862, LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814, LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768, LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725, LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684, LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646, LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610, LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575, LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543, LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513, LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484, LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457, LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431 };*/ public clMPlayer(clMain theMain) { /*{ int mytab_i[] = { // 12 1712*16,1616*16,1524*16,1440*16,1356*16,1280*16, 1208*16,1140*16,1076*16,1016*16,960*16,907*16 }; mytab=toshortarray(mytab_i); }*/ { int vbi[] = { //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 }; VibratoTable=toshortarray(vbi); } /*{ int lti[] = { LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862, LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814, LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768, LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725, LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684, LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646, LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610, LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575, LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543, LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513, LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484, LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457, LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431 }; logtab = toshortarray(lti); }*/ m_ = theMain; mp_extspd = true; mp_panning = true; mp_loop = false; mp_volume = 100; isfirst = 0; globalvolume = 64; globalslide = 0; { mp_audio = new AUDTMP[32]; int i; for(i=0;i<32;i++) mp_audio[i] = new AUDTMP(); } //memset(mp_audio, 0, sizeof(mp_audio)); { int i; for(i=0;i<32;i++) { mp_audio[i].fadevol = mp_audio[i].start = mp_audio[i].period = mp_audio[i].c2spd = mp_audio[i].tmpperiod = mp_audio[i].wantedperiod = mp_audio[i].slidespeed = mp_audio[i].portspeed = mp_audio[i].soffset = 0; mp_audio[i].volume = mp_audio[i].transpose = mp_audio[i].retrig = mp_audio[i].tmpvolume = mp_audio[i].vibpos = mp_audio[i].trmpos = ((byte)0); mp_audio[i].sample = mp_audio[i].handle = mp_audio[i].panning = mp_audio[i].pansspd = mp_audio[i].note = mp_audio[i].ownper = mp_audio[i].ownvol = mp_audio[i].s3mtremor = mp_audio[i].s3mtronof = mp_audio[i].s3mvolslide = mp_audio[i].s3mrtgspeed = mp_audio[i].s3mrtgslide = mp_audio[i].glissando = mp_audio[i].wavecontrol = mp_audio[i].vibspd = mp_audio[i].vibdepth = mp_audio[i].trmspd = mp_audio[i].trmdepth = ((short)0); mp_audio[i].keyon = mp_audio[i].kick = false; mp_audio[i].i = null; mp_audio[i].s = null; mp_audio[i].row = null; mp_audio[i].venv.flg = mp_audio[i].venv.pts = mp_audio[i].venv.sus = mp_audio[i].venv.beg = mp_audio[i].venv.end = mp_audio[i].venv.p = mp_audio[i].venv.a = mp_audio[i].venv.b; mp_audio[i].venv.env = null; mp_audio[i].penv.flg = mp_audio[i].penv.pts = mp_audio[i].penv.sus = mp_audio[i].penv.beg = mp_audio[i].penv.end = mp_audio[i].penv.p = mp_audio[i].penv.a = mp_audio[i].penv.b; mp_audio[i].penv.env = null; } } } public static short Interpolate(short p,short p1,short p2,short v1,short v2) { short dp,dv,di; if(p1==p2) return v1; dv=(short)(v2-v1); dp=(short)(p2-p1); di=(short)(p-p1); return (short)(v1 + ((int)(di*dv) / dp)); } public static int getlinearperiod(short note,int fine) { return((10*12*16*4)-((int)note*16*4)-(fine/2)+64); } public static int getlogperiod(short note,int fine) { short n,o; int p1,p2,i; n=(short)(note%12); o=(short)(note/12); i=(n<<3)+(fine>>4); /* n*8 + fine/16 */ p1=logtab[i]; p2=logtab[i+1]; return(Interpolate((short)(fine/16),(short)0,(short)15,(short)p1,(short)p2)>>o); } public static int getoldperiod(short note, int c2spd) { short n,o; int period; if(c2spd == 0) return 4242; /* <- prevent divide overflow.. (42 eheh) */ n=(short)(note%12); o=(short)(note/12); period=(short)(((8363L*mytab[n]) >> o )/c2spd); return period; } public int GetPeriod(short note,int c2spd) { if((pf.flags&audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UF_XMPERIODS) != 0){ return ((pf.flags&audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UF_LINEAR) != 0) ? getlinearperiod(note,c2spd) : getlogperiod(note,c2spd); } return(getoldperiod(note,c2spd)); } public void DoEEffects(short dat) { short nib; dat &= 0xFF; nib=(short)(dat&0xf); switch(dat>>4){ case 0x0: /* filter toggle, not supported */ break; case 0x1: /* fineslide up */ if(vbtick == 0) a.tmpperiod-=(nib<<2); break; case 0x2: /* fineslide dn */ if(vbtick == 0) a.tmpperiod+=(nib<<2); 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.c2spd=finetune[nib]; */ /* a.tmpperiod=GetPeriod(a.note,pf.samples[a.sample].transpose,a.c2spd); */ break; case 0x6: /* set patternloop */ if(vbtick != 0) break; /* hmm.. this one is a real kludge. But now it works. */ if(nib != 0){ /* 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 != 0) /* jump to reppos if repcnt>0 */ mp_patpos=reppos; } else{ reppos=(short)(mp_patpos-1); /* set reppos */ } break; case 0x7: /* set tremolo waveform */ a.wavecontrol&=0x0f; a.wavecontrol|=nib<<4; break; case 0x8: /* set panning */ if(mp_panning){ nib<<=4; a.panning=nib; pf.panning[mp_channel]=nib; } 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=true; a.retrig=(byte)nib; } a.retrig--; /* countdown */ } break; case 0xa: /* fine volume slide up */ if(vbtick != 0) break; a.tmpvolume+=nib; if(a.tmpvolume>64) a.tmpvolume=64; break; case 0xb: /* fine volume slide dn */ if(vbtick != 0) break; a.tmpvolume-=nib; if(a.tmpvolume<0) a.tmpvolume=0; 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 */ } break; case 0xd: /* note delay */ /* delay the start of the sample until vbtick==nib */ if(vbtick==nib){ a.kick=true; } else a.kick=false; break; case 0xe: /* pattern delay */ if(vbtick != (short)0) break; if(patdly2 == (short)0) patdly=(short)(nib+1); /* only once (when vbtick=0) */ break; case 0xf: /* invert loop, not supported */ break; } } public void DoVibrato() { short q; int temp=0; q=(short)((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=(short)(255-q); temp=q; break; case 2: /* square wave */ temp=255; break; } temp*=a.vibdepth; temp>>=7; temp<<=2; if(a.vibpos>=0) a.period=a.tmpperiod+temp; else a.period=a.tmpperiod-temp; if(vbtick != 0) a.vibpos+=a.vibspd; /* do not update when vbtick==0 */ } public void DoTremolo() { short q; int temp=0; q=(short)((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=(short)(255-q); temp=q; break; case 2: /* square wave */ temp=255; break; } temp*=a.trmdepth; temp>>=6; if(a.trmpos>=0){ a.volume=(byte)(a.tmpvolume+temp); if(a.volume>64) a.volume=64; } else{ a.volume=(byte)(a.tmpvolume-temp); if(a.volume<0) a.volume=0; } if(vbtick != 0) a.trmpos+=a.trmspd; /* do not update when vbtick==0 */ } public void DoVolSlide(short dat) { dat &= 0xFF; if(vbtick == 0) return; /* do not update when vbtick==0 */ a.tmpvolume+=dat>>4; /* volume slide */ a.tmpvolume-=dat&0xf; if(a.tmpvolume<0) a.tmpvolume=0; if(a.tmpvolume>64) a.tmpvolume=64; } public void DoS3MVolSlide(short inf) { short lo,hi; inf &= 0xFF; if(inf != 0){ a.s3mvolslide=inf; } inf=a.s3mvolslide; lo=(short)(inf&0xf); hi=(short)(inf>>4); if(hi==0){ a.tmpvolume-=lo; } else if(lo==0){ a.tmpvolume+=hi; } else if(hi==0xf){ if(vbtick == 0) a.tmpvolume-=lo; } else if(lo==0xf){ if(vbtick == 0) a.tmpvolume+=hi; } if(a.tmpvolume<0) a.tmpvolume=0; if(a.tmpvolume>64) a.tmpvolume=64; } public void DoXMVolSlide(short inf) { short lo,hi; inf &= 0xFF; if(inf!=0){ a.s3mvolslide=inf; } inf=a.s3mvolslide; if(vbtick == 0) return; lo=(short)(inf&0xf); hi=(short)(inf>>4); if(hi==0) a.tmpvolume-=lo; else a.tmpvolume+=hi; if(a.tmpvolume<0) a.tmpvolume=0; else if(a.tmpvolume>64) a.tmpvolume=64; } public void DoXMGlobalSlide(short inf) { short lo,hi; inf &= 0xFF; if(inf != 0){ globalslide=inf; } inf=globalslide; if(vbtick==0) return; lo=(short)(inf&0xf); hi=(short)(inf>>4); if(hi==0) globalvolume-=lo; else globalvolume+=hi; if(globalvolume<0) globalvolume=0; else if(globalvolume>64) globalvolume=64; } public void DoXMPanSlide(short inf) { short lo,hi; short pan; inf &= 0xFF; if(inf!=0) a.pansspd=inf; else inf=a.pansspd; if(vbtick==0) return; lo=(short)(inf&0xf); hi=(short)(inf>>4); /* slide right has absolute priority: */ if(hi != 0) lo=0; pan=a.panning; pan-=lo; pan+=hi; if(pan<0) pan=0; if(pan>255) pan=255; a.panning=pan; } public void DoS3MSlideDn(short inf) { short hi,lo; inf &= 0xFF; if(inf!=0) a.slidespeed=inf; else inf=(short)(a.slidespeed); hi=(short)(inf>>4); lo=(short)(inf&0xf); if(hi==0xf){ if(vbtick==0) a.tmpperiod+=(int)lo<<2; } else if(hi==0xe){ if(vbtick==0) a.tmpperiod+=lo; } else{ if(vbtick!=0) a.tmpperiod+=(int)inf<<2; } } public void DoS3MSlideUp(short inf) { short hi,lo; inf &= 0xFF; if(inf!=0) a.slidespeed=inf; else inf=(short)(a.slidespeed); hi=(short)(inf>>4); lo=(short)(inf&0xf); if(hi==0xf){ if(vbtick==0) a.tmpperiod-=(int)lo<<2; } else if(hi==0xe){ if(vbtick==0) a.tmpperiod-=lo; } else{ if(vbtick != 0) a.tmpperiod-=(int)inf<<2; } } public void DoS3MTremor(short inf) { short on,off; inf &= 0xFF; if(inf!=0) a.s3mtronof=inf; else inf=a.s3mtronof; if(vbtick==0) return; on=(short)((inf>>4)+1); off=(short)((inf&0xf)+1); a.s3mtremor%=(on+off); a.volume=(a.s3mtremor < on ) ? a.tmpvolume:0; a.s3mtremor++; } public void DoS3MRetrig(short inf) { short hi,lo; inf &= 0xFF; hi=(short)(inf>>4); lo=(short)(inf&0xf); if(lo != 0){ a.s3mrtgslide=hi; a.s3mrtgspeed=lo; } if(hi != 0){ a.s3mrtgslide=hi; } /* only retrigger if lo nibble > 0 */ if(a.s3mrtgspeed>0){ if(a.retrig==0){ /* when retrig counter reaches 0, reset counter and restart the sample */ a.kick=true; a.retrig=(byte)a.s3mrtgspeed; if(vbtick!=0){ /* don't slide on first retrig */ switch(a.s3mrtgslide){ case 1: case 2: case 3: case 4: case 5: a.tmpvolume-=(1<<(a.s3mrtgslide-1)); break; case 6: a.tmpvolume=(byte)((2*a.tmpvolume)/3); break; case 7: a.tmpvolume=(byte)(a.tmpvolume>>1); break; case 9: case 0xa: case 0xb: case 0xc: case 0xd: a.tmpvolume+=(1<<(a.s3mrtgslide-9)); break; case 0xe: a.tmpvolume=(byte)((3*a.tmpvolume)/2); break; case 0xf: a.tmpvolume=(byte)(a.tmpvolume<<1); break; } if(a.tmpvolume<0) a.tmpvolume=0; if(a.tmpvolume>64) a.tmpvolume=64; } } a.retrig--; /* countdown */ } } public void DoS3MSpeed(short speed) { speed &= 0xFF; if((vbtick != 0) || (patdly2 != 0)) return; if(speed!=0){ /* <- v0.44 bugfix */ mp_sngspd=speed; vbtick=0; } } public void DoS3MTempo(short tempo) { tempo &= 0xFF; if((vbtick!=0) || (patdly2!=0)) return; old_bpm=tempo; mp_bpm=(short) rint(old_bpm*speed_constant); } public void DoToneSlide() { int dist,t; if(vbtick==0){ a.tmpperiod=a.period; return; } /* We have to slide a.period towards a.wantedperiod, so compute the difference between those two values */ dist=a.period-a.wantedperiod; if( dist==0 || /* if they are equal */ a.portspeed>Math.abs(dist) ){ /* or if portamentospeed is too big */ a.period=a.wantedperiod; /* make tmpperiod equal tperiod */ } else if(dist>0){ /* dist>0 ? */ a.period-=a.portspeed; /* then slide up */ } else a.period+=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.tmpperiod=a.period; } public void DoPTEffect0(short dat) { short note; dat &= 0xFF; note=a.note; if(dat!=0){ switch(vbtick%3){ case 1: note+=(dat>>4); break; case 2: note+=(dat&0xf); break; } a.period=GetPeriod((short)(note+a.transpose),a.c2spd); a.ownper=1; } } public void PlayNote() { int period; short inst,c; short note; if(a.row==null) return; m_.MUniTrk.UniSetRow(a.row, a.row_pos); while((c=m_.MUniTrk.UniGetByte()) != 0){ switch(c){ case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_NOTE: note=m_.MUniTrk.UniGetByte(); if(note==96){ /* key off ? */ a.keyon=false; if((a.i != null) && ((a.i.volflg & EF_ON) == 0)){ a.tmpvolume=0; } } else{ a.note=note; period=GetPeriod((short)(note+a.transpose),a.c2spd); a.wantedperiod=period; a.tmpperiod=period; a.kick=true; a.start=0; /* retrig tremolo and vibrato waves ? */ if((a.wavecontrol&0x80) == 0) a.trmpos=0; if((a.wavecontrol&0x08) == 0) a.vibpos=0; } break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_INSTRUMENT: inst=m_.MUniTrk.UniGetByte(); if(inst>=pf.numins) break; /* <- safety valve */ a.sample=inst; // i=&pf.instruments[inst]; a.i=pf.instruments[inst]; if(pf.instruments[inst].samplenumber[a.note] >= pf.instruments[inst].numsmp) break; //s=&i.samples[i.samplenumber[a.note]]; a.s=pf.instruments[inst].samples[pf.instruments[inst].samplenumber[a.note]]; /* channel or instrument determined panning ? */ if((pf.instruments[inst].samples[pf.instruments[inst].samplenumber[a.note]].flags & (m_.MDriver.SF_OWNPAN)) != 0){ a.panning=pf.instruments[inst].samples[pf.instruments[inst].samplenumber[a.note]].panning; } else{ a.panning=pf.panning[mp_channel]; } a.transpose=pf.instruments[inst].samples[pf.instruments[inst].samplenumber[a.note]].transpose; a.handle=pf.instruments[inst].samples[pf.instruments[inst].samplenumber[a.note]].handle; a.tmpvolume=(byte)(pf.instruments[inst].samples[pf.instruments[inst].samplenumber[a.note]].volume); a.volume=(byte)(pf.instruments[inst].samples[pf.instruments[inst].samplenumber[a.note]].volume); a.c2spd=pf.instruments[inst].samples[pf.instruments[inst].samplenumber[a.note]].c2spd; a.retrig=0; a.s3mtremor=0; period=GetPeriod((short)(a.note+a.transpose),(short)a.c2spd); a.wantedperiod=period; a.tmpperiod=period; break; default: m_.MUniTrk.UniSkipOpcode(c); break; } } } public void PlayEffects() { short c,dat; if(a.row==null) return; m_.MUniTrk.UniSetRow(a.row, a.row_pos); a.ownper=0; a.ownvol=0; while((c=m_.MUniTrk.UniGetByte()) != 0){ switch(c){ case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_NOTE: case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_INSTRUMENT: m_.MUniTrk.UniSkipOpcode(c); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT0: DoPTEffect0(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT1: dat=m_.MUniTrk.UniGetByte(); if(dat!=0) a.slidespeed=(int)dat<<2; if(vbtick != 0) a.tmpperiod-=a.slidespeed; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT2: dat=m_.MUniTrk.UniGetByte(); if(dat!=0) a.slidespeed=(int)dat<<2; if(vbtick != 0) a.tmpperiod+=a.slidespeed; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT3: dat=m_.MUniTrk.UniGetByte(); a.kick=false; /* temp XM fix */ if(dat!=0){ a.portspeed=dat; a.portspeed<<=2; } DoToneSlide(); a.ownper=1; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT4: dat=m_.MUniTrk.UniGetByte(); if((dat&0x0f) != 0) a.vibdepth=(short)(dat&0xf); if((dat&0xf0) != 0) a.vibspd=(short)((dat&0xf0)>>2); DoVibrato(); a.ownper=1; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT5: dat=m_.MUniTrk.UniGetByte(); a.kick=false; DoToneSlide(); DoVolSlide(dat); a.ownper=1; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT6: dat=m_.MUniTrk.UniGetByte(); DoVibrato(); DoVolSlide(dat); a.ownper=1; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT7: dat=m_.MUniTrk.UniGetByte(); if((dat&0x0f) != 0) a.trmdepth=(short)(dat&0xf); if((dat&0xf0) != 0) a.trmspd=(short)((dat&0xf0)>>2); DoTremolo(); a.ownvol=1; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT8: dat=m_.MUniTrk.UniGetByte(); if(mp_panning){ a.panning=dat; pf.panning[mp_channel]=dat; } break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECT9: dat=m_.MUniTrk.UniGetByte(); if(dat != 0) a.soffset=(int)dat<<8; /* <- 0.43 fix.. */ a.start=a.soffset; if(a.start>a.s.length) a.start=a.s.length; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECTA: DoVolSlide(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECTB: dat=m_.MUniTrk.UniGetByte(); if(patdly2 != 0) break; if(dat<mp_sngpos) break; /* avoid eternal looping */ patbrk=0; mp_sngpos=(short)(dat-1); posjmp=3; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECTC: dat=m_.MUniTrk.UniGetByte(); if(vbtick != 0) break; if(dat>64) dat=64; a.tmpvolume=(byte)dat; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECTD: dat=m_.MUniTrk.UniGetByte(); if(patdly2 != 0) break; { int hi=(dat&0xf0)>>4; int lo=(dat&0xf); patbrk=(short)((hi*10)+lo); } if(patbrk>64) patbrk=64; /* <- v0.42 fix */ posjmp=3; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECTE: DoEEffects(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_PTEFFECTF: dat=m_.MUniTrk.UniGetByte(); if((vbtick != 0) || (patdly2 != 0)) break; if(mp_extspd && dat>=0x20){ old_bpm=dat; mp_bpm=(short) rint(old_bpm*speed_constant); } else{ if(dat != 0){ /* <- v0.44 bugfix */ mp_sngspd=dat; vbtick=0; } } break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_S3MEFFECTD: DoS3MVolSlide(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_S3MEFFECTE: DoS3MSlideDn(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_S3MEFFECTF: DoS3MSlideUp(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_S3MEFFECTI: DoS3MTremor(m_.MUniTrk.UniGetByte()); a.ownvol=1; break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_S3MEFFECTQ: DoS3MRetrig(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_S3MEFFECTA: DoS3MSpeed(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_S3MEFFECTT: DoS3MTempo(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_XMEFFECTA: DoXMVolSlide(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_XMEFFECTG: globalvolume=(byte)m_.MUniTrk.UniGetByte(); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_XMEFFECTH: DoXMGlobalSlide(m_.MUniTrk.UniGetByte()); break; case audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UNI_XMEFFECTP: DoXMPanSlide(m_.MUniTrk.UniGetByte()); break; default: m_.MUniTrk.UniSkipOpcode(c); break; } } if(a.ownper == 0){ a.period=a.tmpperiod; } if(a.ownvol == 0){ a.volume=a.tmpvolume; } } public static short InterpolateEnv(short p,ENVPT a,ENVPT b) { return(Interpolate(p,a.pos,b.pos,a.val,b.val)); } public static short DoPan(short envpan,short pan) { return (short)(pan + (((envpan-128)*(128-Math.abs(pan-128)))/128)); } public static short DoVol(int a,short b,short c) { a*=b; a*=c; return (short)(a>>23); } public static void StartEnvelope(ENVPR t,short flg,short pts,short sus,short beg,short end,ENVPT p[]) { flg &= 0xFF; pts &= 0xFF; sus &= 0xFF; beg &= 0xFF; end &= 0xFF; t.flg=flg; t.pts=pts; t.sus=sus; t.beg=beg; t.end=end; t.env=p; t.p=0; t.a=0; t.b=1; } public static short ProcessEnvelope(ENVPR t,short v,boolean keyon) { if((t.flg & EF_ON) != 0){ /* panning active? . copy variables */ short a,b; int p; a=t.a; b=t.b; p=t.p; /* compute the envelope value between points a and b */ v=InterpolateEnv((short)p,t.env[a],t.env[b]); /* Should we sustain? (sustain flag on, key-on, point a is the sustain point, and the pointer is exactly on point a) */ if(((t.flg & EF_SUSTAIN) != 0) && keyon && a==t.sus && p==t.env[a].pos){ /* do nothing */ } else{ /* don't sustain, so increase pointer. */ p++; /* pointer reached point b? */ if(p >= t.env[b].pos){ /* shift points a and b */ a=b; b++; if((t.flg & EF_LOOP) != 0){ if(b > t.end){ a=t.beg; b=(short)(a+1); p=t.env[a].pos; } } else{ if(b >= t.pts){ b--; p--; } } } } t.a=a; t.b=b; t.p=(short)p; } return v; } /* int GetFreq2(int period) { float frequency; frequency=8363.0*pow(2,((6*12*16*4.0)-period)/(12*16*4.0)); return(floor(frequency)); } */ public static int GetFreq2(int period) { int okt; int frequency; period=7680-period; okt=period/768; frequency=lintab[period%768]; frequency<<=2; return(frequency>>(7-okt)); } public void MP_HandleTick() { int tmpvol; // extern char current_file[1024]; int z,t,tr,ui_result; //extern int play_current; // extern int current_pattern; //extern int count_pattern, count_song; boolean reinit_audio=false; pause_flag=-128; if(isfirst != 0){ /* don't handle the very first ticks, this allows the other hardware to settle down so we don't lose any starting notes */ isfirst--; return; } if(forbid) return; /* don't go any further when forbid is true */ if(MP_Ready()) return; if(++vbtick>=mp_sngspd){ mp_patpos++; vbtick=0; if(patdly != 0){ patdly2=patdly; patdly=0; } if(patdly2 != 0){ /* patterndelay active */ if((--patdly2) != 0){ mp_patpos--; /* so turn back mp_patpos by 1 */ } } /* Do we have to get a new patternpointer ? (when mp_patpos reaches 64 or when a patternbreak is active). Also check for 256 - if mod is broken it will continue forever otherwise */ if( mp_patpos == numrow || mp_patpos > 255 ) posjmp=3; if( posjmp != 0){ mp_patpos=patbrk; mp_sngpos+=(posjmp-2); patbrk=posjmp=0; if(mp_sngpos>=pf.numpos){ /* if(true) return;*/ if(!mp_loop) return; mp_sngpos=pf.reppos; } if(mp_sngpos<0) mp_sngpos=(short)(pf.numpos-1); } if(patdly2==0){ for(t=0;t<pf.numchn;t++){ tr=pf.patterns[(pf.positions[mp_sngpos]*pf.numchn)+t]; numrow=(short)(pf.pattrows[pf.positions[mp_sngpos]]); mp_channel=(short)t; a=mp_audio[t]; //a.row = (tr<pf.numtrk) ? MikMod.MUniTrk.clMUniTrk.UniFindRow(pf.tracks[tr],mp_patpos) : ((short*)null); if (tr<pf.numtrk) { a.row = pf.tracks[tr]; a.row_pos = m_.MUniTrk.UniFindRow(pf.tracks[tr],mp_patpos); } else a.row = null; PlayNote(); } do /* run through once, repeat if paused */ { if(pause_flag==127) m_.usleep(1000); /* don't need to eat cpu time! */ m_.UI.count_pattern++; m_.UI.count_song++; if(m_.quiet) ui_result = 9999; /* don't match any case */ else ui_result=m_.UI.get_ui(); /* volume=0 already by default if paused, so don't need to fiddle with it... */ switch(ui_result) { case audio.jmikmod.MikMod.UI.myUI.UI_DELETE_MARKED: /*if(!m_.cur_mod.deleted) break; if(!unlink(m_.cur_mod.filename)) m_.cur_mod.deleted=2; else m_.cur_mod.deleted=3; m_.Display.update_file_display(); m_.Display.display_all(); */ /* FALL THROUGH */ case audio.jmikmod.MikMod.UI.myUI.UI_NEXT_SONG: m_.MDriver.MD_PatternChange(); m_.MPlayer.play_current=false; break; case audio.jmikmod.MikMod.UI.myUI.UI_PREVIOUS_SONG: /* if halfway through mod restart it, if beginning jump to the previous one */ if ((m_.UI.count_song < audio.jmikmod.MikMod.UI.myUI.SMALL_DELAY) && (m_.optind>1) ) { m_.optind-=2; m_.MPlayer.play_current=false; } else { mp_sngpos=1; MP_PrevPosition(); } m_.UI.count_song=0; m_.MDriver.MD_PatternChange(); break; case audio.jmikmod.MikMod.UI.myUI.UI_QUIT: m_.MDriver.MD_PatternChange(); quit=true; break; case audio.jmikmod.MikMod.UI.myUI.UI_JUMP_TO_NEXT_PATTERN: m_.MDriver.MD_PatternChange(); MP_NextPosition(); break; case audio.jmikmod.MikMod.UI.myUI.UI_JUMP_TO_PREV_PATTERN: m_.MDriver.MD_PatternChange(); if (m_.UI.count_pattern < audio.jmikmod.MikMod.UI.myUI.SMALL_DELAY) /* near start of pattern? */ MP_PrevPosition(); else MP_RestartPosition(); m_.UI.count_pattern=0; break; case audio.jmikmod.MikMod.UI.myUI.UI_PAUSE: pause_flag=~pause_flag; if(pause_flag==127) { if(m_.md_type != 0) m_.MDriver.MD_Mute(); else m_.MDriver.MD_Exit(); /* temp. free the sound driver */ m_.Display.display_version(); m_.Display.display_pausebanner(); } else { if(m_.md_type != 0) { m_.MDriver.MD_UnMute(); m_.Display.display_all(); } else /* need to re-init. the sound driver before leaving pause mode */ { if(!m_.MDriver.MD_Init()){ m_.Display.display_driver_error(m_.mmIO.myerr); m_.Display.display_pausebanner(); pause_flag=~pause_flag; } else m_.Display.display_all(); } } break; case audio.jmikmod.MikMod.UI.myUI.UI_SPEED_UP: if ((old_bpm*(speed_constant+0.05))<=255) speed_constant+=0.05; break; case audio.jmikmod.MikMod.UI.myUI.UI_SLOW_DOWN: if ((old_bpm*(speed_constant-0.05))>10) speed_constant-=0.05; break; case audio.jmikmod.MikMod.UI.myUI.UI_NORMAL_SPEED: speed_constant=(float)1.0; break; case audio.jmikmod.MikMod.UI.myUI.UI_VOL_UP: if(mp_volume<250) mp_volume+=5; break; case audio.jmikmod.MikMod.UI.myUI.UI_VOL_DOWN: if(mp_volume>5) mp_volume-=5; break; case audio.jmikmod.MikMod.UI.myUI.UI_NORMAL_VOL: mp_volume=100; break; case audio.jmikmod.MikMod.UI.myUI.UI_MARK_DELETED: if(!m_.cur_mod.deleted) m_.cur_mod.deleted=true; else if (m_.cur_mod.deleted==true) m_.cur_mod.deleted=false; m_.Display.update_file_display(); m_.Display.display_all(); break; case audio.jmikmod.MikMod.UI.myUI.UI_SELECT_STEREO: m_.MDriver.md_mode |= m_.DMODE_STEREO; reinit_audio=true; break; case audio.jmikmod.MikMod.UI.myUI.UI_SELECT_MONO: m_.MDriver.md_mode &= ~m_.DMODE_STEREO; reinit_audio=true; break; case audio.jmikmod.MikMod.UI.myUI.UI_SELECT_INTERP: m_.MDriver.md_mode |= m_.DMODE_INTERP; reinit_audio=true; break; case audio.jmikmod.MikMod.UI.myUI.UI_SELECT_NONINTERP: m_.MDriver.md_mode &= ~m_.DMODE_INTERP; reinit_audio=true; break; case audio.jmikmod.MikMod.UI.myUI.UI_SELECT_8BIT: m_.MDriver.md_mode &= ~m_.DMODE_16BITS; reinit_audio=true; break; case audio.jmikmod.MikMod.UI.myUI.UI_SELECT_16BIT: m_.MDriver.md_mode |= m_.DMODE_16BITS; reinit_audio=true; break; default: break; } if ((old_bpm*speed_constant)>255) mp_bpm=255; else mp_bpm=(short) rint(old_bpm*speed_constant); if (reinit_audio){ reinit_audio=false; m_.MDriver.MD_Exit(); m_.MDriver.MD_Init(); } } while(pause_flag==127); } } /* Update effects */ for(t=0;t<pf.numchn;t++){ mp_channel=(short)t; a=mp_audio[t]; PlayEffects(); } for(t=0;t<pf.numchn;t++){ //INSTRUMENT *i; //SAMPLE *s; short envpan,envvol; a=mp_audio[t]; //i=a.i; //s=a.s; if(a.i==null || a.s==null) continue; if(a.period<40) a.period=40; if(a.period>8000) a.period=8000; if(a.kick){ m_.MDriver.MD_VoicePlay((short)t,a.handle,a.start,a.s.length,a.s.loopstart,a.s.loopend,a.s.flags); a.kick=false; a.keyon=true; a.fadevol=32768; StartEnvelope(a.venv,a.i.volflg,a.i.volpts,a.i.volsus,a.i.volbeg,a.i.volend,a.i.volenv); StartEnvelope(a.penv,a.i.panflg,a.i.panpts,a.i.pansus,a.i.panbeg,a.i.panend,a.i.panenv); } envvol=ProcessEnvelope(a.venv,(short)256,a.keyon); envpan=ProcessEnvelope(a.penv,(short)128,a.keyon); tmpvol=a.fadevol; /* max 32768 */ tmpvol*=envvol; /* * max 256 */ tmpvol*=a.volume; /* * max 64 */ tmpvol/=16384; /* tmpvol/(256*64) => tmpvol is max 32768 */ tmpvol*=globalvolume; /* * max 64 */ tmpvol*=mp_volume; /* * max 100 */ tmpvol/=3276800; /* tmpvol/(64*100*512) => tmpvol is max 64 */ m_.MDriver.MD_VoiceSetVolume((short)t,(short)tmpvol); // m_.MDriver.MD_VoiceSetVolume(t,tmpvol&0xFF); if((a.s.flags& (m_.MDriver.SF_OWNPAN)) != 0){ m_.MDriver.MD_VoiceSetPanning((short)t,DoPan(envpan,a.panning)); // m_.MDriver.MD_VoiceSetPanning(t,DoPan(envpan,a.panning) & 0xFF); } else{ m_.MDriver.MD_VoiceSetPanning((short)t,a.panning); // m_.MDriver.MD_VoiceSetPanning(t,(a.panning) & 0xFF); } if((pf.flags & audio.jmikmod.MikMod.MUniTrk.clMUniTrk.UF_LINEAR) != 0) m_.MDriver.MD_VoiceSetFrequency((short)t,GetFreq2(a.period)); else m_.MDriver.MD_VoiceSetFrequency((short)t,(3579546<<2)/a.period); /* if key-off, start substracting fadeoutspeed from fadevol: */ if(!a.keyon){ if(a.fadevol>=a.i.volfade) a.fadevol-=a.i.volfade; else a.fadevol=0; } } } public void MP_Init(UNIMOD m) { int t; pf=m; reppos=0; repcnt=0; mp_sngpos=0; mp_sngspd=m.initspeed; vbtick=mp_sngspd; patdly=0; patdly2=0; mp_bpm=m.inittempo; old_bpm=mp_bpm; m_.cur_mod.deleted=false; forbid=false; mp_patpos=0; posjmp=2; /* <- make sure the player fetches the first note */ patbrk=0; isfirst=2; /* delay start by 2 ticks */ globalvolume=64; /* reset global volume */ /* Make sure the player doesn't start with garbage: */ for(t=0;t<pf.numchn;t++){ mp_audio[t].kick=false; mp_audio[t].tmpvolume=0; mp_audio[t].retrig=0; mp_audio[t].wavecontrol=0; mp_audio[t].glissando=0; mp_audio[t].soffset=0; } } public boolean MP_Ready() { return(mp_sngpos>=pf.numpos); } public void MP_NextPosition() { forbid=true; posjmp=3; patbrk=0; vbtick=mp_sngspd; forbid=false; } public void MP_PrevPosition() { forbid=true; posjmp=1; patbrk=0; vbtick=mp_sngspd; forbid=false; } public void MP_RestartPosition() { forbid=true; posjmp=2; patbrk=0; vbtick=mp_sngspd; forbid=false; } public void MP_SetPosition(short pos) { /* avoid infinitely-looping mods */ /* if(pos>=pf.numpos) pos=pf.numpos; forbid=true; posjmp=2; patbrk=0; mp_sngpos=pos; vbtick=mp_sngspd; forbid=false;*/ } public static double rint (double x) { if (x-(int)x < 0.5) return (double)(int)x; else return (double)((int)x+1); } }