#include #include #include #define _USE_MATH_DEFINES #include #include #include "syntrax.h" #include "file.h" #include "resampler.h" static void reset(Player *p) { int i, j; if (p->overlapBuff){ memset(p->overlapBuff, 0, SE_OVERLAP * 2 *2 + 2); } if (p->delayBufferL && p->delayBufferR){ memset(p->delayBufferL, 0, 65536 *2); memset(p->delayBufferR, 0, 65536 *2); } if (p->tuneChannels){ for (i = 0; i < SE_MAXCHANS; i++) { TuneChannel *tc = &p->tuneChannels[i]; Voice *v = &p->voices[i]; tc->EQMIWERPIF = 0; tc->LJHG = 0; tc->insNum = -1; tc->HFRLJCG = 0; tc->ACKCWV = 0; tc->ELPHLDR = 0; tc->TVORFCC = 0; tc->freq = 0; tc->BNWIGU = 0; tc->UHYDBDDI = 0; tc->XESAWSO = 0; tc->JOEEPJCI = 0; tc->fmDelay = 0; tc->sampleBuffer = NULL; tc->smpLoopEnd = 0; //tc->smpLength = 0; tc->sampPos = 0; tc->EYRXAB = 0; tc->volume = 0; tc->panning = 0; tc->VNVJPDIWAJQ = 0; tc->smpLoopStart = 0; tc->hasLoop = 0; tc->hasBidiLoop = 0; tc->isPlayingBackward = 0; tc->hasLooped = 0; v->waveBuff = p->silentBuffer; for (j = 0; j < 4; j++) { VoiceEffect *ve = &tc->effects[j]; ve->QOMCBTRPXF = 0; ve->TIPUANVVR = 0; ve->MFATTMREMVP = 0; ve->MDTMBBIQHRQ = 0; ve->RKF = 0; ve->DQVLFV = 0; ve->ILHG = 0; ve->YLKJB = 0; ve->VMBNMTNBQU = 0; ve->ABJGHAUY = 0; ve->SPYK = 0; } memset(&tc->synthBuffers, 0, 0x100 * SE_MAXCHANS *2 + 2); } } } static int generateTables(Player *p) { int i, j; p->dynamorphTable = (int16_t *) malloc(0x100 *2); if (!p->dynamorphTable) return -1; for (i = 0; i < 0x0100; i++ ) { p->dynamorphTable[i] = (sin(((M_PI * i) / 128)) * 32760); } //debug Asscilloscope says 0xF8 to 0x61FFB //we probably don't have uint24_t at our disposal //uint32_t it is, then p->freqTable = (uint32_t *) malloc(SE_NROFFINETUNESTEPS * 128 *4); if (!p->freqTable) return -1; for (i = 0; i < SE_NROFFINETUNESTEPS; i++) { double x; for (j = 0; j < 128; j++) { x = (((j + 3) * 16) - i); x = (x / 192); x = pow(2, x); x = (x * 220) + 0.5; p->freqTable[i* 128 + j] = (int)(x); } } return 0; } void playerDestroy(Player *p) { int i; if (p) { if (p->dynamorphTable) free(p->dynamorphTable); if (p->freqTable) free(p->freqTable); if (p->silentBuffer) free(p->silentBuffer); if (p->overlapBuff) free(p->overlapBuff); if (p->delayBufferL) free(p->delayBufferL); if (p->delayBufferR) free(p->delayBufferR); if (p->tuneChannels) free(p->tuneChannels); if (p->voices) { for (i = 0; i < SE_MAXCHANS; i++) { resampler_destroy(p->voices[i].resampler[0]); resampler_destroy(p->voices[i].resampler[1]); } free(p->voices); } if (p->instruments) free(p->instruments); free(p); } } Player * playerCreate(int SAMPLEFREQUENCY) { int i, j; Player* p; srand(time(NULL)); p = (Player *) calloc(1, sizeof(Player)); if (!p) return NULL; p->bufflen = BUFFERLENGTH; if (generateTables(p) < 0) goto FAIL; p->SAMPLEFREQUENCY = SAMPLEFREQUENCY; p->overlapPos = 0; p->silentBuffer = malloc(0x0100 *2); if (!p->silentBuffer) goto FAIL; memset(p->silentBuffer, 0, 0x0100 *2); p->ISWLKT = 0; p->posCoarse = 0; p->posFine = 0; p->bkpDelayPos = 0; p->DONGS = 0; p->AMYGPFQCHSW = 0; p->selectedSubsong = 0; p->PQV = 0; p->someCounter = 0; p->WDTECTE = 0; p->sePmSong = SE_PM_SONG; p->AMVM = 0x0100; p->channelNumber = 0; p->delayPos = 0; p->otherSamplesPerBeat = 2200; p->samplesPerBeat = 2200; p->overlapBuff = malloc(SE_OVERLAP * 2 *2 + 2); if (!p->overlapBuff) goto FAIL; p->delayBufferL = malloc(65536 *2); if (!p->delayBufferL) goto FAIL; p->delayBufferR = malloc(65536 *2); if (!p->delayBufferR) goto FAIL; p->tuneChannels = malloc(SE_MAXCHANS *sizeof(TuneChannel)); if (!p->tuneChannels) goto FAIL; p->voices = malloc(SE_MAXCHANS *sizeof(Voice)); if (!p->voices) goto FAIL; for (i = 0; i < SE_MAXCHANS; i++) { Voice *v = &p->voices[i]; memset(v, 0, sizeof(Voice)); v->resampler[0] = resampler_create(); v->resampler[1] = resampler_create(); if (!v->resampler[0] || !v->resampler[1]) goto FAIL; } reset(p); return p; FAIL: playerDestroy(p); return NULL; } static void instrEffect(Player *p, int chanNum) { //TODO: minimize all the vars //too many of them int i, j; int _local3; int destWave; int16_t *destBuff; int pos; int srcWave1; int _local10; int srcWave2; int16_t *srcBuff1; int16_t *srcBuff2; double _local16; double _local17; double _local18; int oscWave; int16_t *oscBuff; int _local21; int _local22; int _local23; int _local25; int _local26; int _local27; int var1; int var2; double _local30; double _local31; int _local32; int _local33; int _local34; int _local35; int _local36; int _local37; int _local38; int _local39; int _local40; int _local43; int butt, ron, pat, buf2, buf1; TuneChannel *tc = &p->tuneChannels[chanNum]; const Instrument *ins = &p->instruments[tc->insNum]; for (i = 0; i < 4; i++ ) { const InstrumentEffect *ie = &ins->effects[i]; VoiceEffect *ve = &tc->effects[i]; ve->MFATTMREMVP = (ve->MFATTMREMVP + ie->oscSpeed); ve->MFATTMREMVP = (ve->MFATTMREMVP & 0xFF); switch (ie->effectType) { //NONE case 0: break; //NEGATE case 1: destWave = ie->destWave; _local3 = ie->fxSpeed; pos = ve->QOMCBTRPXF; destBuff = tc->synthBuffers[destWave]; for (j = 0; j < _local3; j++ ) { pos++; pos = (pos & 0xFF); destBuff[pos] = (0 - destBuff[pos]); } ve->QOMCBTRPXF = pos; break; //SWEEP case 2: destWave = ie->destWave; _local3 = ie->fxSpeed; destBuff = tc->synthBuffers[destWave]; for (pos = 0, j = 0; j < 0x0100; j++ ) { destBuff[j] = (destBuff[j] + pos); destBuff[j] = (destBuff[j] + 0x8000); destBuff[j] = (destBuff[j] & 0xFFFF); destBuff[j] = (destBuff[j] - 0x8000); pos = (pos + _local3); } break; //AVERAGER case 3: destWave = ie->destWave; srcWave1 = ie->srcWave1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; _local3 = ie->fxSpeed; pos = 0; if (_local3 > 12){ _local3 = 12; } for (_local10 = 0; _local10 < _local3; _local10++ ) { destBuff[0] = ((srcBuff1[0xFF] + srcBuff1[1]) >> 1); for (j = 1; j < 0xFF; j++ ) { destBuff[j] = ((srcBuff1[j - 1] + srcBuff1[j + 1]) >> 1); } destBuff[0xFF] = ((srcBuff1[254] + srcBuff1[0]) >> 1); } break; //WAVEMIX case 4: destWave = ie->destWave; srcWave1 = ie->srcWave1; srcWave2 = ie->srcWave2; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; srcBuff2 = tc->synthBuffers[srcWave2]; _local3 = ie->fxSpeed; ve->QOMCBTRPXF = (ve->QOMCBTRPXF + _local3); ve->QOMCBTRPXF = (ve->QOMCBTRPXF & 0xFF); pos = ve->QOMCBTRPXF; for (j = 0; j < 0x0100; j++ ) { destBuff[j] = ((srcBuff1[j] + srcBuff2[pos]) >> 1); pos++; pos = (pos & 0xFF); } break; //FILTER case 5: destWave = ie->destWave; srcWave1 = ie->srcWave1; srcWave2 = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; srcBuff2 = srcWave2 >= 0 ? tc->synthBuffers[srcWave2] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ _local16 = (double)((ie->variable1 * 20)); _local17 = (double)((ie->variable2 * 16)); } else { if (ie->oscSelect){ _local16 = (double)((ie->variable1 * 20)); _local17 = ((double)((srcBuff2[pos] + 0x8000)) / 16); } else { _local16 = ((double)((srcBuff2[pos] + 0x8000)) / 13); _local17 = (double)((ie->variable2 * 16)); } } ve->DQVLFV = exp((-((2 * M_PI)) * (_local17 / 22000))); ve->RKF = (((-4 * ve->DQVLFV) / (1 + ve->DQVLFV)) * cos(((2 * M_PI) * (_local16 / 22000)))); ve->MDTMBBIQHRQ = ((1 - ve->DQVLFV) * sqrt((1 - ((ve->RKF * ve->RKF) / (4 * ve->DQVLFV))))); for (j = 0; j < 0x0100; j++) { _local18 = (((ve->MDTMBBIQHRQ * ((double)(srcBuff1[j]) / 0x8000)) - (ve->RKF * ve->ILHG)) - (ve->DQVLFV * ve->YLKJB)); ve->YLKJB = ve->ILHG; ve->ILHG = _local18; if (_local18 > 0.9999){ _local18 = 0.9999; } if (_local18 < -0.9999){ _local18 = -0.9999; } destBuff[j] = (_local18 * 0x8000); } break; //FILTWHISTLE case 6: destWave = ie->destWave; srcWave1 = ie->srcWave1; srcWave2 = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; srcBuff2 = srcWave2 >= 0 ? tc->synthBuffers[srcWave2] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ _local16 = (double)((ie->variable1 * 20)); _local17 = (double)((ie->variable2 * 16)); } else { if (ie->oscSelect){ _local16 = (double)((ie->variable1 * 20)); _local17 = ((double)((srcBuff2[pos] + 0x8000)) / 16); } else { _local16 = ((double)((srcBuff2[pos] + 0x8000)) / 13); _local17 = (double)((ie->variable2 * 16)); } } ve->DQVLFV = exp((-((2 * M_PI)) * (_local17 / 22000))); ve->RKF = (((-4 * ve->DQVLFV) / (1 + ve->DQVLFV)) * cos(((2 * M_PI) * (_local16 / 22000)))); ve->MDTMBBIQHRQ = ((1 - ve->DQVLFV) * sqrt((1 - ((ve->RKF * ve->RKF) / (4 * ve->DQVLFV))))); ve->DQVLFV = (ve->DQVLFV * 1.2); for (j = 0; j < 0x0100; j++ ) { _local18 = (((ve->MDTMBBIQHRQ * ((double)(srcBuff1[j]) / 0x8000)) - (ve->RKF * ve->ILHG)) - (ve->DQVLFV * ve->YLKJB)); ve->YLKJB = ve->ILHG; ve->ILHG = _local18; if (_local18 > 0.9999){ _local18 = 0.9999; } if (_local18 < -0.9999){ _local18 = -0.9999; } destBuff[j] = (_local18 * 0x8000); } break; //MORPH case 7: destWave = ie->destWave; srcWave1 = ie->srcWave1; srcWave2 = ie->srcWave2; oscWave = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; srcBuff2 = tc->synthBuffers[srcWave2]; oscBuff = oscWave >= 0 ? tc->synthBuffers[oscWave] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ _local21 = ie->variable1; } else { if (ie->oscSelect){ _local21 = ie->variable1; } else { _local21 = ((oscBuff[pos] + 0x8000) / 0x0100); } } _local22 = (0xFF - _local21); for (j = 0; j < 0x0100; j++) { _local23 = (((srcBuff1[j] * _local21) / 0x0100) + ((srcBuff2[j] * _local22) / 0x0100)); destBuff[j] = _local23; } break; //DYNAMORPH case 8: destWave = ie->destWave; srcWave1 = ie->srcWave1; srcWave2 = ie->srcWave2; oscWave = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; srcBuff2 = tc->synthBuffers[srcWave2]; oscBuff = oscWave >= 0 ? tc->synthBuffers[oscWave] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ _local25 = ie->variable1; } else { if (ie->oscSelect){ _local25 = ie->variable1; } else { _local25 = ((oscBuff[pos] + 0x8000) / 0x0100); } } for (j = 0; j < 0x0100; j++) { _local21 = ((p->dynamorphTable[_local25] >> 8) + 128); _local22 = (0xFF - _local21); _local23 = (((srcBuff1[j] * _local21) / 0x0100) + ((srcBuff2[j] * _local22) / 0x0100)); destBuff[j] = _local23; _local25++; _local25 = (_local25 & 0xFF); } break; //DISTORTION case 9: destWave = ie->destWave; srcWave1 = ie->srcWave1; oscWave = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; oscBuff = oscWave >= 0 ? tc->synthBuffers[oscWave] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ _local21 = ie->variable1; } else { if (ie->oscSelect){ _local21 = ie->variable1; } else { _local21 = ((oscBuff[pos] + 0x8000) / 0x0100); } } for (j = 0; j < 0x0100; j++) { _local23 = ((srcBuff1[j] * _local21) / 16); _local23 = (_local23 + 0x8000); if (_local23 < 0){ _local23 = -(_local23); } _local23 = (_local23 % 131072); if (_local23 > 0xFFFF){ _local23 = (131071 - _local23); } _local23 = (_local23 & 0xFFFF); _local23 = (_local23 - 0x8000); destBuff[j] = _local23; } break; //SCROLL LEFT case 10: destWave = ie->destWave; destBuff = tc->synthBuffers[destWave]; _local10 = destBuff[0]; for (j = 0; j < 0xFF; j++) { destBuff[j] = destBuff[j + 1]; } destBuff[0xFF] = _local10; break; //UPSAMPLE case 11: pos = ve->QOMCBTRPXF; if (pos != 0){ ve->QOMCBTRPXF--; break; } ve->QOMCBTRPXF = ie->variable1; destWave = ie->destWave; destBuff = tc->synthBuffers[destWave]; for (j = 0; j < 128; j++) { destBuff[j] = destBuff[j * 2]; } for (j = 0; j < 128; j++) { destBuff[j + 128] = destBuff[j]; } break; //CLIPPER case 12: destWave = ie->destWave; srcWave1 = ie->srcWave1; oscWave = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; oscBuff = oscWave >= 0 ? tc->synthBuffers[oscWave] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ _local21 = ie->variable1; } else { if (ie->oscSelect){ _local21 = ie->variable1; } else { _local21 = ((oscBuff[pos] + 0x8000) / 0x0100); } } for (j = 0; j < 0x0100; j++) { _local23 = ((srcBuff1[j] * _local21) / 16); if (_local23 < -32767){ _local23 = -32767; } if (_local23 > 32767){ _local23 = 32767; } destBuff[j] = _local23; } break; //LOWPASS case 13: destWave = ie->destWave; srcWave1 = ie->srcWave1; srcWave2 = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; srcBuff2 = srcWave2 >= 0 ? tc->synthBuffers[srcWave2] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ var1 = ie->variable1; var2 = ie->variable2; var1 = var1 * 16; } else { if (ie->oscSelect){ var1 = ie->variable1; var2 = ((srcBuff2[pos] + 0x8000) >> 8); var1 = (var1 * 16); } else { //_local28 = ((_local14->data[_local7] + 0x8000) / 16); var1 = ((srcBuff2[pos] + 0x8000) >> 4); var2 = ie->variable2; } } _local30 = (var1 - 920); _local31 = (228 + var1); _local26 = (int)(((2 * M_PI) * _local31)); _local27 = (707 + ((1000 * var2) / 128)); _local36 = ve->ABJGHAUY; _local37 = ve->SPYK; _local38 = ve->VMBNMTNBQU; _local40 = 8; for (j = 0; j < 0x0100; j++) { _local32 = ((_local26 * _local40) / 100); _local39 = srcBuff1[j]; _local33 = ((((_local36 * 1000) / _local27) - _local37) + _local39); _local34 = (_local36 - ((_local32 * (_local38 / 100)) / 100)); _local35 = (_local37 - ((_local32 * (_local36 / 100)) / 100)); _local38 = _local33; _local36 = _local34; _local37 = _local35; _local3 = _local37; if (_local3 > 32767){ _local3 = 32767; } if (_local3 < -32767){ _local3 = -32767; } destBuff[j] = _local3; } ve->ABJGHAUY = _local36; ve->SPYK = _local37; ve->VMBNMTNBQU = _local38; break; //HIGHPASS case 14: destWave = ie->destWave; srcWave1 = ie->srcWave1; srcWave2 = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; srcBuff2 = srcWave2 >= 0 ? tc->synthBuffers[srcWave2] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ var1 = ie->variable1; var2 = ie->variable2; var1 = (var1 * 32); } else { if (ie->oscSelect) { var1 = ie->variable1; var2 = ((srcBuff2[pos] + 0x8000) >> 8); var1 = (var1 * 32); } else { //checked with IDA against windows ver. of Syntrax(v1.03) //It's possible that the effect has changed along the way(v2.xx) //same for lowpass //_local28 = ((_local14->data[_local7] + 0x8000) / 16); var1 = ((srcBuff2[pos] + 0x8000) >> 3); var2 = ie->variable2; } } _local30 = (var1 - 920); _local31 = (228 + var1); _local26 = (int)(((2 * M_PI) * _local31)); _local27 = (707 + ((1000 * var2) / 128)); _local36 = ve->ABJGHAUY; _local37 = ve->SPYK; _local38 = ve->VMBNMTNBQU; _local40 = 8; for (j = 0; j < 0x0100; j++) { _local32 = ((_local26 * _local40) / 100); _local39 = srcBuff1[j]; _local33 = ((((_local36 * 1000) / _local27) - _local37) + _local39); _local34 = (_local36 - ((_local32 * (_local38 / 100)) / 100)); _local35 = (_local37 - ((_local32 * (_local36 / 100)) / 100)); _local38 = _local33; _local36 = _local34; _local37 = _local35; _local3 = _local38; if (_local3 > 32767){ _local3 = 32767; } if (_local3 < -32767){ _local3 = -32767; } destBuff[j] = _local3; } ve->ABJGHAUY = _local36; ve->SPYK = _local37; ve->VMBNMTNBQU = _local38; break; //BANDPASS case 15: destWave = ie->destWave; srcWave1 = ie->srcWave1; srcWave2 = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; srcBuff2 = srcWave2 >= 0 ? tc->synthBuffers[srcWave2] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ var1 = ie->variable1; var2 = ie->variable2; var1 = var1 * 16; } else { if (ie->oscSelect){ var1 = ie->variable1; var2 = ((srcBuff2[pos] + 0x8000) >> 8); var1 = var1 * 16; } else { var1 = ((srcBuff2[pos] + 0x8000) / 16); var2 = ie->variable2; } } _local30 = (var1 - 920); _local31 = (228 + var1); _local26 = (int)(((2 * M_PI) * _local31)); _local27 = (707 + ((1000 * var2) / 128)); _local36 = ve->ABJGHAUY; _local37 = ve->SPYK; _local38 = ve->VMBNMTNBQU; _local40 = 8; for (j = 0; j < 0x0100; j++) { _local32 = ((_local26 * _local40) / 100); _local39 = srcBuff1[j]; _local33 = ((((_local36 * 1000) / _local27) - _local37) + _local39); _local34 = (_local36 - ((_local32 * (_local38 / 100)) / 100)); _local35 = (_local37 - ((_local32 * (_local36 / 100)) / 100)); _local38 = _local33; _local36 = _local34; _local37 = _local35; _local3 = _local36; if (_local3 > 32767){ _local3 = 32767; } if (_local3 < -32767){ _local3 = -32767; } destBuff[j] = _local3; } ve->ABJGHAUY = _local36; ve->SPYK = _local37; ve->VMBNMTNBQU = _local38; break; //METALNOISE case 16: destWave = ie->destWave; destBuff = tc->synthBuffers[destWave]; for (j = 0; j < 0x0100; j++ ) { //Something very bad happens here //I think it's fixed now. destBuff[j] = (int)(((double)(rand()) / (double)(RAND_MAX)) * 65530 - 0x8000); } break; //SQUASH case 17: destWave = ie->destWave; srcWave1 = ie->srcWave1; oscWave = ie->oscWave - 1; destBuff = tc->synthBuffers[destWave]; srcBuff1 = tc->synthBuffers[srcWave1]; oscBuff = oscWave >= 0 ? tc->synthBuffers[oscWave] : NULL; pos = ve->MFATTMREMVP; if (ie->oscWave == 0){ var1 = ie->variable1; var2 = ie->variable2; } else { if (ie->oscSelect){ var1 = ie->variable1; var2 = ((oscBuff[pos] + 0x8000) >> 8); } else { var1 = ((oscBuff[pos] + 0x8000) >> 8); var2 = ie->variable2; } } var2 = (var2 << 8); var1 = (var1 + var2); _local22 = 0; for (j = 0; j < 0x0100; j++ ) { //Hex Rays decompiler is lovely tool. //butt = (butt & 0xFFFF0000) | (_local22 & 0x0000FFFF); butt = _local22 & 0xFFFF; _local22 += var1; //ron = (ron & 0xFFFFFF00) | ( butt & 0x000000FF); ron = butt & 0xFF; butt >>= 8; buf1 = srcBuff1[butt]; //overflow warning buf2 = srcBuff1[butt + 1]; pat = (255 - ron) * buf1; destBuff[j] = (ron * buf2 >> 8) + (pat >> 8); } break; } } } static void channelSomethingElse(Player *p, int chanNum) { int _local3; int _local4; int _local5; int _local6; TuneChannel *tc = &p->tuneChannels[chanNum]; const Instrument *ins = &p->instruments[tc->insNum]; if (ins->amWave == 0){ _local3 = 0; } else { tc->HFRLJCG = (tc->HFRLJCG + ins->amSpeed); if (tc->HFRLJCG >= 0x0100){ tc->HFRLJCG = (tc->HFRLJCG - 0x0100); tc->HFRLJCG = (tc->HFRLJCG + ins->amLoopPoint); if (tc->HFRLJCG >= 0x0100){ tc->HFRLJCG = ins->amLoopPoint; } } _local3 = tc->synthBuffers[ins->amWave - 1][tc->HFRLJCG]; _local3 = (_local3 + 0x8000); _local3 = (_local3 / 6); _local3 = -(_local3); if (_local3 < -10000){ _local3 = -10000; } } _local3 = (_local3 + 10000); _local3 = (_local3 * ins->masterVolume); _local3 = (_local3 >> 8); _local3 = (_local3 * p->AMVM); _local3 = (_local3 >> 8); _local3 = (_local3 - 10000); tc->volume = _local3; if (ins->panWave == 0){ _local5 = 0; } else { tc->ELPHLDR = (tc->ELPHLDR + ins->panSpeed); if (tc->ELPHLDR >= 0x0100){ tc->ELPHLDR = (tc->ELPHLDR - 0x0100); tc->ELPHLDR = (tc->ELPHLDR + ins->panLoopPoint); if (tc->ELPHLDR >= 0x0100){ tc->ELPHLDR = ins->panLoopPoint; } } _local5 = tc->synthBuffers[ins->panWave - 1][tc->ELPHLDR]; _local5 = (_local5 >> 7); } tc->panning = _local5; _local6 = 0; _local6 = p->arpTable[(ins->arpIndex * 16) + tc->ACKCWV]; tc->ACKCWV++; tc->ACKCWV = (tc->ACKCWV & 15); _local4 = p->freqTable[ins->finetune*128 + (_local6 + tc->TVORFCC)]; if (tc->fmDelay){ tc->fmDelay--; } else { if (ins->fmWave != 0){ tc->JOEEPJCI = (tc->JOEEPJCI + ins->fmSpeed); if (tc->JOEEPJCI >= 0x0100){ tc->JOEEPJCI = (tc->JOEEPJCI - 0x0100); tc->JOEEPJCI = (tc->JOEEPJCI + ins->fmLoopPoint); if (tc->JOEEPJCI >= 0x0100){ tc->JOEEPJCI = ins->fmLoopPoint; } } _local4 = _local4 - tc->synthBuffers[ins->fmWave - 1][tc->JOEEPJCI]; } } _local4 = (_local4 + tc->BNWIGU); tc->freq = _local4; if (tc->XESAWSO != 0){ if (tc->XESAWSO > 0){ if (tc->BNWIGU < tc->UHYDBDDI){ tc->BNWIGU = (tc->BNWIGU + tc->XESAWSO); if (tc->BNWIGU > tc->UHYDBDDI){ tc->BNWIGU = tc->UHYDBDDI; } } } else { if (tc->BNWIGU > tc->UHYDBDDI){ tc->BNWIGU = (tc->BNWIGU + tc->XESAWSO); if (tc->BNWIGU < tc->UHYDBDDI){ tc->BNWIGU = tc->UHYDBDDI; } } } } } void playInstrument(Player *p, int chanNum, int instrNum, int note) //note: 1-112 { int j; int i; TuneChannel *tc; Voice *v; const Instrument *ins; if (instrNum > p->synSong->h.instrNum){ return; } if ((((p->tuneChannels[chanNum].insNum == -1)) && ((instrNum == 0)))){ return; } tc = &p->tuneChannels[chanNum]; v = &p->voices[chanNum]; tc->ACKCWV = 0; tc->HFRLJCG = 0; tc->ELPHLDR = 0; tc->JOEEPJCI = 0; tc->TVORFCC = note; tc->freq = 0; tc->VNVJPDIWAJQ = note; tc->BNWIGU = 0; tc->UHYDBDDI = 0; tc->XESAWSO = 0; p->m_LastNotes[chanNum] = note; if (instrNum != 0) { ins = &p->instruments[instrNum - 1]; if (ins->shareSmpDataFromInstr == 0){ tc->sampleBuffer = p->samples[instrNum - 1]; } else { tc->sampleBuffer = p->samples[ins->shareSmpDataFromInstr - 1]; } tc->sampPos = ins->smpStartPoint; tc->smpLoopStart = ins->smpLoopPoint; tc->smpLoopEnd = ins->smpEndPoint; tc->hasLoop = ins->hasLoop; tc->hasBidiLoop = ins->hasBidiLoop; tc->hasLooped = 0; tc->isPlayingBackward = 0; tc->EYRXAB = -1; tc->fmDelay = ins->fmDelay; for (i = 0; i < 16; i++) { if (ins->m_ResetWave[i]){ //ins->synthBuffers[i].copyTo(tc.synthBuffers[i]); memcpy(&tc->synthBuffers[i], &ins->synthBuffers[i], 0x100 *2); } } tc->insNum = instrNum - 1; resampler_clear(v->resampler[0]); v->last_delta = 0; } ins = &p->instruments[tc->insNum]; for (j = 0; j < 4; j++) { if (ins->effects[j].effectType != 0){ if (ins->effects[j].resetEffect) { VoiceEffect *ve = &tc->effects[j]; ve->MFATTMREMVP = 0; ve->QOMCBTRPXF = 0; ve->TIPUANVVR = 0; ve->YLKJB = 0; ve->ILHG = 0; ve->VMBNMTNBQU = 0; ve->ABJGHAUY = 0; ve->SPYK = 0; } } } } static void patEffect(Player *p, int note, int command, int dest, int spd, int chanNum) { TuneChannel *tc = &p->tuneChannels[chanNum]; Instrument *ins = &p->instruments[tc->insNum]; int off; double tempo; if (tc->insNum == -1) return; switch (command) { //NONE case 0: default: return; //PITCHBEND case 1: if (tc->VNVJPDIWAJQ){ off = p->freqTable[ins->finetune*128 + tc->VNVJPDIWAJQ]; tc->TVORFCC = tc->VNVJPDIWAJQ; } else { off = p->freqTable[ins->finetune*128 + note]; } tc->BNWIGU = 0; tc->UHYDBDDI = (p->freqTable[ins->finetune*128 + dest] - off); tc->XESAWSO = (spd * 20); tc->VNVJPDIWAJQ = dest; break; //CHNG WAVEFORM case 2: if (dest > 15){ dest = 15; } ins->waveform = dest; break; //CHNG WAVELENGTH case 3: if (dest > 192){ dest = 0x0100; } else { if (dest > 96){ dest = 128; } else { if (dest > 48){ dest = 64; } else { dest = 32; } } } ins->wavelength = dest; break; //CHNG MASTER VOL case 4: ins->masterVolume = dest; break; //CHNG AMWAVE case 5: if (dest > 15){ dest = 15; } ins->amWave = dest; break; //CHNG AMSPD case 6: ins->amSpeed = dest; break; //CHNG AMLPPOINT case 7: ins->amLoopPoint = dest; break; //CHNG FINETUNE case 8: if (dest > 15){ dest = 15; } ins->finetune = dest; break; //CHNG FMWAVE case 9: if (dest > 15){ dest = 15; } ins->fmWave = dest; break; //CHNG FMSPD case 10: ins->fmSpeed = dest; break; //CHNG FMLPPOINT case 11: ins->fmLoopPoint = dest; break; //CHNG FMDELAY case 12: ins->fmDelay = dest; break; //CHNG ARPEGGIO case 13: if (dest > 15){ dest = 15; } ins->arpIndex = dest; break; //CHNG EFF#1 DESTWAVE case 14: if (dest > 15){ dest = 15; } ins->effects[0].destWave = dest; break; //CHNG EFF#1 SRCWAVE1 case 15: if (dest > 15){ dest = 15; } ins->effects[0].srcWave1 = dest; break; //CHNG EFF#1 SRCWAVE2 case 16: if (dest > 15){ dest = 15; } ins->effects[0].srcWave2 = dest; break; //CHNG EFF#1 OSCWAVE case 17: if (dest > 15){ dest = 15; } ins->effects[0].oscWave = dest; break; //CHNG EFF#1 VARIABLE1 case 18: ins->effects[0].variable1 = dest; break; //CHNG EFF#1 VARIABLE2 case 19: ins->effects[0].variable2 = dest; break; //CHNG EFF#1 FXSPEED case 20: ins->effects[0].fxSpeed = dest; break; //CHNG EFF#1 OSCSPEED case 21: ins->effects[0].oscSpeed = dest; break; //CHNG EFF#1 OSCSELECT case 22: if (dest > 1){ dest = 1; } ins->effects[0].oscSelect = dest; break; //CHNG EFF#1 TYPE case 23: if (dest >= SE_NROFEFFECTS){ dest = (SE_NROFEFFECTS - 1); } ins->effects[0].effectType = dest; break; //CHNG EFF#1 RESETEFFECT case 24: if (dest > 1){ dest = 1; } ins->effects[0].resetEffect = dest; break; //CHNG EFF#2 DESTWAVE case 25: if (dest > 15){ dest = 15; } ins->effects[1].destWave = dest; break; //CHNG EFF#2 SRCWAVE1 case 26: if (dest > 15){ dest = 15; } ins->effects[1].srcWave1 = dest; break; //CHNG EFF#2 SRCWAVE2 case 27: if (dest > 15){ dest = 15; } //Good god! SrcEffect2 is left unplugged. I could guess what it was. //Luckly, I'm saved by one of the later effects. ins->effects[1].srcWave2 = dest; break; //CHNG EFF#2 OSCWAVE case 28: if (dest > 15){ dest = 15; } ins->effects[1].oscWave = dest; break; //CHNG EFF#2 VARIABLE1 case 29: ins->effects[1].variable1 = dest; break; //CHNG EFF#2 VARIABLE2 case 30: ins->effects[1].variable2 = dest; break; //CHNG EFF#2 FXSPEED case 31: ins->effects[1].fxSpeed = dest; break; //CHNG EFF#2 OSCSPEED case 32: ins->effects[1].oscSpeed = dest; break; //CHNG EFF#2 OSCSELECT case 33: if (dest > 1){ dest = 1; } ins->effects[1].oscSelect = dest; break; //CHNG EFF#2 TYPE case 34: if (dest >= SE_NROFEFFECTS){ dest = (SE_NROFEFFECTS - 1); } ins->effects[1].effectType = dest; break; //CHNG EFF#2 RESETEFFECT case 35: if (dest > 1){ dest = 1; } ins->effects[1].resetEffect = dest; break; //CHNG EFF#3 DESTWAVE case 36: if (dest > 15){ dest = 15; } ins->effects[2].destWave = dest; break; //CHNG EFF#3 SRCWAVE1 case 37: if (dest > 15){ dest = 15; } ins->effects[2].srcWave1 = dest; break; //CHNG EFF#3 SRCWAVE2 case 38: if (dest > 15){ dest = 15; } ins->effects[2].srcWave2 = dest; break; //CHNG EFF#3 OSCWAVE case 39: if (dest > 15){ dest = 15; } ins->effects[2].oscWave = dest; break; //CHNG EFF#3 VARIABLE1 case 40: ins->effects[2].variable1 = dest; break; //CHNG EFF#3 VARIABLE2 case 41: ins->effects[2].variable2 = dest; break; //CHNG EFF#3 FXSPEED case 42: ins->effects[2].fxSpeed = dest; break; //CHNG EFF#3 OSCSPEED case 43: ins->effects[2].oscSpeed = dest; break; //CHNG EFF#3 OSCSELECT case 44: if (dest > 1){ dest = 1; } ins->effects[2].oscSelect = dest; break; //CHNG EFF#3 TYPE case 45: if (dest >= SE_NROFEFFECTS){ dest = (SE_NROFEFFECTS - 1); } ins->effects[2].effectType = dest; break; //CHNG EFF#3 RESETEFFECT case 46: if (dest > 1){ dest = 1; } ins->effects[2].resetEffect = dest; break; //CHNG EFF#4 DESTWAVE case 47: if (dest > 15){ dest = 15; } ins->effects[3].destWave = dest; break; //CHNG EFF#4 SRCWAVE1 case 48: if (dest > 15){ dest = 15; } ins->effects[3].srcWave1 = dest; break; //CHNG EFF#4 SRCWAVE2 case 49: if (dest > 15){ dest = 15; } ins->effects[3].srcWave2 = dest; break; //CHNG EFF#4 OSCWAVE case 50: if (dest > 15){ dest = 15; } ins->effects[3].oscWave = dest; break; //CHNG EFF#4 VARIABLE1 case 51: ins->effects[3].variable1 = dest; break; //CHNG EFF#4 VARIABLE2 case 52: ins->effects[3].variable2 = dest; break; //CHNG EFF#4 FXSPEED case 53: ins->effects[3].fxSpeed = dest; break; //CHNG EFF#4 OSCSPEED case 54: ins->effects[3].oscSpeed = dest; break; //CHNG EFF#4 OSCSELECT case 55: if (dest > 1){ dest = 1; } ins->effects[3].oscSelect = dest; break; //CHNG EFF#4 TYPE case 56: if (dest >= SE_NROFEFFECTS){ dest = (SE_NROFEFFECTS - 1); } ins->effects[3].effectType = dest; break; //CHNG EFF#4 RESETEFFECT case 57: if (dest > 1){ dest = 1; } ins->effects[3].resetEffect = dest; break; //CHNG RESET WAVE #1 case 58: if (dest > 1){ dest = 1; } ins->m_ResetWave[0] = dest; break; //CHNG RESET WAVE #2 case 59: if (dest > 1){ dest = 1; } ins->m_ResetWave[1] = dest; break; //CHNG RESET WAVE #3 case 60: if (dest > 1){ dest = 1; } ins->m_ResetWave[2] = dest; break; //CHNG RESET WAVE #4 case 61: if (dest > 1){ dest = 1; } ins->m_ResetWave[3] = dest; break; //CHNG RESET WAVE #5 case 62: if (dest > 1){ dest = 1; } ins->m_ResetWave[4] = dest; break; //CHNG RESET WAVE #6 case 63: if (dest > 1){ dest = 1; } ins->m_ResetWave[5] = dest; break; //CHNG RESET WAVE #7 case 64: if (dest > 1){ dest = 1; } ins->m_ResetWave[6] = dest; break; //CHNG RESET WAVE #8 case 65: if (dest > 1){ dest = 1; } ins->m_ResetWave[7] = dest; break; //CHNG RESET WAVE #9 case 66: if (dest > 1){ dest = 1; } ins->m_ResetWave[8] = dest; break; //CHNG RESET WAVE #10 case 67: if (dest > 1){ dest = 1; } ins->m_ResetWave[9] = dest; break; //CHNG RESET WAVE #11 case 68: if (dest > 1){ dest = 1; } ins->m_ResetWave[10] = dest; break; //CHNG RESET WAVE #12 case 69: if (dest > 1){ dest = 1; } ins->m_ResetWave[11] = dest; break; //CHNG RESET WAVE #13 case 70: if (dest > 1){ dest = 1; } ins->m_ResetWave[12] = dest; break; //CHNG RESET WAVE #14 case 71: if (dest > 1){ dest = 1; } ins->m_ResetWave[13] = dest; break; //CHNG RESET WAVE #15 case 72: if (dest > 1){ dest = 1; } ins->m_ResetWave[14] = dest; break; //CHNG RESET WAVE #16 case 73: if (dest > 1){ dest = 1; } ins->m_ResetWave[15] = dest; break; //CHNG BPM case 74: if (dest <= 10){ dest = 10; } if (dest > 220){ dest = 220; } p->curSubsong.tempo = dest; tempo = (double)(p->curSubsong.tempo); tempo = (tempo / 60); tempo = (tempo * 32); p->samplesPerBeat = (int)(44100 / tempo); break; //CHNG GROOVE case 75: if (dest > 3){ dest = 3; } p->curSubsong.groove = dest; break; //FIRE EXTERNAL EVENT case 76: //this effect is for controlling external code //like animation and whatnot //similar to how 8xx is used in Travolta's 'testlast' .mod //do take note of audio latency when dealing with this. //This is called UserEvent in ocx player doc, I think break; } } static void channelSomething(Player *p, int chanNum) { int _local2; int _local3; int note; int dest; int contrScript; int spd; if (!p->PQV) return; if (p->someCounter != p->WDTECTE) return; if (p->sePmSong == SE_PM_PATTERN){ if (chanNum > 0) return; _local2 = p->AMYGPFQCHSW; _local3 = p->ISWLKT; } else { if (p->curSubsong.mutedChans[chanNum] == 1) return; _local3 = p->tuneChannels[chanNum].LJHG; _local2 = p->curSubsong.orders[chanNum][p->tuneChannels[chanNum].EQMIWERPIF].patIndex; } note = p->rows[(_local2 * 64) + _local3].note; if (note != 0) { playInstrument(p, chanNum, p->rows[(_local2 * 64) + _local3].instr, note); } contrScript = p->rows[(_local2 * 64) + _local3].command; dest = p->rows[(_local2 * 64) + _local3].dest; spd = p->rows[(_local2 * 64) + _local3].spd; patEffect(p, note, contrScript, dest, spd, chanNum); } static void ABH(Player *p) { int i, j0, j1; int _local2; Order *_local3; int _local4; bool _local5; int _local6; Order *_local9; int _local10; int _local11; if (!p->PQV) return; p->someCounter--; if (p->someCounter == 0){ if (p->sePmSong == SE_PM_PATTERN){ if (!(p->ISWLKT & 1)){ p->WDTECTE = (8 - p->curSubsong.groove); } else { p->WDTECTE = (8 + p->curSubsong.groove); } } else { if (!(p->posFine & 1)){ p->WDTECTE = (8 - p->curSubsong.groove); } else { p->WDTECTE = (8 + p->curSubsong.groove); } } p->someCounter = p->WDTECTE; if (p->sePmSong == SE_PM_PATTERN){ p->ISWLKT++; p->ISWLKT = (p->ISWLKT % p->DONGS); } else { for (i = 0; i < p->channelNumber; i++) { TuneChannel *tc = &p->tuneChannels[i]; tc->LJHG++; _local3 = p->curSubsong.orders[i]; _local4 = tc->EQMIWERPIF; if (_local4 == -1){ _local4 = 0; } _local2 = _local3[_local4].patLen; if ((((tc->LJHG == _local2)) || ((tc->EQMIWERPIF == -1)))){ tc->LJHG = 0; tc->EQMIWERPIF++; p->curSubsong.mutedChans[i] = p->mutedChans[i]; } } p->posFine++; if (p->posFine == 64){ p->posFine = 0; p->posCoarse++; } if ((((p->posCoarse == p->curSubsong.endPosCoarse)) && ((p->posFine == p->curSubsong.endPosFine)))){ if (p->curSubsong.isLooping){ _local5 = false; for (j0 = 0; j0 < SE_MAXCHANS; j0++) { _local6 = 0; _local11 = 0; _local9 = p->curSubsong.orders[j0]; _local10 = ((p->curSubsong.loopPosCoarse * 64) + p->curSubsong.loopPosFine); for (j1 = 0; j1 < 0x0100; j1++) { if (_local6 > _local10){ if (j1 != _local10){ j1--; } break; } _local11 = _local6; _local6 = (_local6 + _local9[j1].patLen); } if (j1 == 0x0100){ p->PQV = 0; _local5 = true; break; } _local10 = (_local10 - _local11); _local10 = (_local10 & 63); p->tuneChannels[j0].EQMIWERPIF = j1; p->tuneChannels[j0].LJHG = _local10; } if (_local5 == false){ p->posCoarse = p->curSubsong.loopPosCoarse; p->posFine = p->curSubsong.loopPosFine; p->loopCount++; } } else { p->PQV = 0; p->sePmSong = SE_PM_SONG; p->posCoarse = p->curSubsong.startPosCoarse; p->posFine = p->curSubsong.startPosFine; } } } } } void advanceTick(Player *p) { int i; ABH(p); for (i = 0; i < p->channelNumber; i++) { channelSomething(p, i); if (p->tuneChannels[i].insNum != -1) { channelSomethingElse(p, i); instrEffect(p, i); } } } void mixChunk(Player *p, int16_t *outBuff, uint playbackBufferSize) { int i, j; uint sampleNum; int amp, smp, pos; int32_t audioMainR, audioMainL; int32_t audioDelayR, audioDelayL; uint otherDelayTime; Voice *v; TuneChannel *tc; int insNum; //We just don't know! uint dword_6632774C = 0; if ( p->channelNumber > 0 ) { while ( playbackBufferSize > 0 ) { if ( p->otherSamplesPerBeat >= playbackBufferSize ) { p->otherSamplesPerBeat = p->otherSamplesPerBeat - playbackBufferSize; sampleNum = playbackBufferSize; } else { sampleNum = p->otherSamplesPerBeat; p->otherSamplesPerBeat = p->samplesPerBeat * p->SAMPLEFREQUENCY / 44100; } playbackBufferSize -= sampleNum; for (i=0; i < p->channelNumber; ++i ) { v = &p->voices[i]; tc = &p->tuneChannels[i]; insNum = tc->insNum; if ( insNum == -1 ) { v->waveBuff = p->silentBuffer; v->isSample = 0; } else if ( !tc->sampleBuffer ) { int waveNum = p->instruments[insNum].waveform; v->wavelength = (p->instruments[insNum].wavelength) - 1; v->waveBuff = tc->synthBuffers[waveNum]; v->isSample = 0; } else { v->waveBuff = tc->sampleBuffer; v->sampPos = tc->sampPos; v->smpLoopStart = tc->smpLoopStart; v->smpLoopEnd = tc->smpLoopEnd; v->hasLoop = tc->hasLoop; v->hasBidiLoop = tc->hasBidiLoop; v->isPlayingBackward = tc->isPlayingBackward; v->hasLooped = tc->hasLooped; v->isSample = 1; } if ( tc->freq < 10 ) tc->freq = 10; v->gain = (tc->volume + 10000) / 39; v->delta = (tc->freq << 8) / p->SAMPLEFREQUENCY; if (v->delta != v->last_delta && outBuff ) { double fdelta = (double)v->delta * (1.0 / (double)0x100); v->last_delta = v->delta; resampler_set_rate(v->resampler[0], fdelta); } if ( v->gain > 0x100 ) v->gain = 0x100; if ( tc->panning ) { if ( tc->panning <= 0 ) { v->gainRight = 0x100; v->gainLeft = 0x100 + tc->panning; } else { v->gainLeft = 0x100; v->gainRight = 0x100 - tc->panning; } } else { v->gainRight = 0x100; v->gainLeft = 0x100; } if ( dword_6632774C ) { //v->gainDelay = word_6632B9F4[i]; } else { v->gainDelay = p->curSubsong.chanDelayAmt[i]; } v->gainRight = (v->gain * v->gainRight) >> 8; v->gainLeft = (v->gain * v->gainLeft) >> 8; v->gainDelayRight = (v->gainDelay * v->gainRight) >> 8; v->gainDelayLeft = (v->gainDelay * v->gainLeft) >> 8; } if ( dword_6632774C ) { //amp = word_6632B964; //otherDelayTime = word_6632BB24; } else { amp = p->curSubsong.amplification; otherDelayTime = p->curSubsong.delayTime / (44100 / p->SAMPLEFREQUENCY); } if ( outBuff ) { if ( sampleNum > 0 ) { for(i = 0; i < sampleNum; i++) { audioMainR = 0; audioMainL = 0; audioDelayR = 0; audioDelayL = 0; if ( p->channelNumber > 0 ) { for (j = 0; j < p->channelNumber; ++j) { v = &p->voices[j]; if ( v->isSample == 1 ) { if ( v->sampPos != -1 || resampler_get_avail(v->resampler[0]) ) { //interpolation sample_t s; while ( v->sampPos != -1 && resampler_get_min_fill(v->resampler[0]) ) { s = v->waveBuff[v->sampPos]; resampler_write_sample(v->resampler[0], s); if ( v->isPlayingBackward ) { v->sampPos--; if ( v->sampPos <= v->smpLoopStart ) { v->isPlayingBackward = 0; v->sampPos++; } } else { v->sampPos++; if ( v->sampPos >= v->smpLoopEnd ) { if ( v->hasLoop ) { v->hasLooped = 1; if ( v->hasBidiLoop ) { v->isPlayingBackward = 1; v->sampPos--; } else { v->sampPos += v->smpLoopStart - v->smpLoopEnd; } } else { v->sampPos = -1; } } } } //smp = intp->interpSamp(v); resampler_read_sample(v->resampler[0], &s); smp = s; audioMainR += (smp * v->gainRight) >> 8; audioMainL += (smp * v->gainLeft) >> 8; audioDelayR += (smp * v->gainDelayRight) >> 8; audioDelayL += (smp * v->gainDelayLeft) >> 8; } } else { //interpolation //smp = intp->interpSynt(v); sample_t s; while ( resampler_get_min_fill(v->resampler[0]) ) { s = v->waveBuff[v->synthPos]; resampler_write_sample(v->resampler[0], s); v->synthPos++; v->synthPos &= v->wavelength; } resampler_read_sample(v->resampler[0], &s); smp = s; audioMainR += (smp * v->gainRight) >> 8; audioMainL += (smp * v->gainLeft) >> 8; audioDelayR += (smp * v->gainDelayRight) >> 8; audioDelayL += (smp * v->gainDelayLeft) >> 8; } } } audioMainL = (p->delayBufferL[p->delayPos] + audioMainL / p->channelNumber) / 2; audioMainR = (p->delayBufferR[p->delayPos] + audioMainR / p->channelNumber) / 2; audioMainR = audioMainR * amp / 100; audioMainL = audioMainL * amp / 100; //clip audio if ( audioMainR < -32760 ) audioMainR = -32760; if ( audioMainR > 32760 ) audioMainR = 32760; if ( audioMainL < -32760 ) audioMainL = -32760; if ( audioMainL > 32760 ) audioMainL = 32760; //interleaved buffer if ( p->overlapPos < SE_OVERLAP ) { audioMainR = p->overlapPos * audioMainR / 100; audioMainR += (SE_OVERLAP - p->overlapPos) * p->overlapBuff[p->overlapPos*2] / 100; audioMainL = p->overlapPos * audioMainL / 100; audioMainL += (SE_OVERLAP - p->overlapPos) * p->overlapBuff[p->overlapPos*2+1] / 100; ++p->overlapPos; } //output *outBuff++ = audioMainR; *outBuff++ = audioMainL; p->delayBufferL[p->delayPos] = (((audioDelayL / p->channelNumber) + p->delayBufferL[p->delayPos]) / 2); p->delayBufferR[p->delayPos] = (((audioDelayR / p->channelNumber) + p->delayBufferR[p->delayPos]) / 2); p->delayPos = ++p->delayPos % otherDelayTime; } } } if ( p->channelNumber > 0 ) { for (i = 0; i < p->channelNumber; ++i) { v = &p->voices[i]; tc = &p->tuneChannels[i]; if ( v->isSample ) { tc->sampPos = v->sampPos; tc->isPlayingBackward = v->isPlayingBackward; tc->hasLooped = v->hasLooped; } } } if ( p->otherSamplesPerBeat == (p->samplesPerBeat * p->SAMPLEFREQUENCY) / 44100 ) { p->bkpDelayPos = p->delayPos; for (i = 0; i < p->channelNumber; i++) { p->voices[i].bkpSynthPos = p->voices[i].synthPos; resampler_dup_inplace(p->voices[i].resampler[1], p->voices[i].resampler[0]); } p->overlapPos = 0; if ( outBuff ) { for (i = 0; i < SE_OVERLAP; i++) { audioMainR = 0; audioMainL = 0; audioDelayR = 0; audioDelayL = 0; if ( p->channelNumber > 0 ) { for (j = 0; j < p->channelNumber; j++) { v = &p->voices[j]; if ( v->isSample == 1 ) { if ( v->sampPos != -1 || resampler_get_avail(v->resampler[1]) ) { //interpolation //smp = intp->interpSamp(v); sample_t s; while ( v->sampPos != -1 && resampler_get_min_fill(v->resampler[1]) ) { s = v->waveBuff[v->sampPos]; resampler_write_sample(v->resampler[1], s); if ( v->isPlayingBackward ) { v->sampPos--; if ( v->sampPos <= v->smpLoopStart ) { v->isPlayingBackward = 0; v->sampPos++; } } else { v->sampPos++; if ( v->sampPos >= v->smpLoopEnd ) { if ( v->hasLoop ) { v->hasLooped = 1; if ( v->hasBidiLoop ) { v->isPlayingBackward = 1; v->sampPos--; } else { v->sampPos += v->smpLoopStart - v->smpLoopEnd; } } else { v->sampPos = -1; } } } } resampler_read_sample(v->resampler[1], &s); smp = s; audioMainR += (smp * v->gainRight) >> 8; audioMainL += (smp * v->gainLeft) >> 8; audioDelayR += (smp * v->gainDelayRight) >> 8; audioDelayL += (smp * v->gainDelayLeft) >> 8; } } else { //interpolation //smp = intp->interpSynt(v); sample_t s; while ( resampler_get_min_fill(v->resampler[1]) ) { s = v->waveBuff[v->synthPos]; resampler_write_sample(v->resampler[1], s); v->synthPos++; v->synthPos &= v->wavelength; } resampler_read_sample(v->resampler[1], &s); smp = s; audioMainR += (smp * v->gainRight) >> 8; audioMainL += (smp * v->gainLeft) >> 8; audioDelayR += (smp * v->gainDelayRight) >> 8; audioDelayL += (smp * v->gainDelayLeft) >> 8; } } } audioMainL = (p->delayBufferL[p->delayPos] + audioMainL / p->channelNumber) / 2; audioMainR = (p->delayBufferR[p->delayPos] + audioMainR / p->channelNumber) / 2; audioMainR = audioMainR * amp / 100; audioMainL = audioMainL * amp / 100; //clip audio if ( audioMainR < -32760 ) audioMainR = -32760; if ( audioMainR > 32760 ) audioMainR = 32760; if ( audioMainL < -32760 ) audioMainL = -32760; if ( audioMainL > 32760 ) audioMainL = 32760; p->overlapBuff[i * 2] = audioMainR; p->overlapBuff[i*2+1] = audioMainL; p->delayPos = ++p->delayPos % otherDelayTime; } } p->delayPos = p->bkpDelayPos; for (i = 0; i < p->channelNumber; i++) p->voices[i].synthPos = p->voices[i].bkpSynthPos; //dword_66327200 = 2 * sampleNum; advanceTick(p); } } return; } memset(outBuff, 0, playbackBufferSize * 2 *2); } /*void newSong(void) { var _local1:int; var i:int; var j:int; var _local4:Order; var _local6:Vector.; var _local7:Row; reset(); AMYGPFQCHSW = 1; selectedSubsong = 0; WDTECTE = 8; AMVM = 0x100; synSong.h.subsongNum = 1; synSong.h.version = 3457; subsongs = new Vector.(); subsongs.push(new Subsong()); var subs0:Subsong = subsongs[0]; curSubsong = subsongs[selectedSubsong]; subs0.tempo = 120; subs0.groove = 0; subs0.startPosCoarse = 0; subs0.startPosFine = 0; subs0.loopPosCoarse = 0; subs0.loopPosFine = 0; subs0.endPosCoarse = 1; subs0.endPosFine = 0; subs0.channelNumber = 4; subs0.delayTime = 0x8000; subs0.amplification = 400; subs0.chanDelayAmt = new Vector.(SE_MAXCHANS, true); subs0.m_Name = "Empty"; subs0.mutedChans = new Vector.(SE_MAXCHANS, true); subs0.orders = Tools.malloc_2DVector(Order, SE_MAXCHANS, 0x0100, true, true); for (i = 0; i < SE_MAXCHANS; i++) { _local6 = subs0.orders[i]; for (j = 0; j < 0x0100; j++) { _local6[j].patIndex = 0; _local6[j].patLen = 0; } } synSong.h.patNum = 2; synSong.rows = Tools.malloc_1DVector(Row, 64 * synSong.h.patNum); for (i = 0; i < (64 * synSong.h.patNum); i++) { rows[i].dest = 0; rows[i].note = 0; rows[i].instr = 0; rows[i].command = 0; rows[i].spd = 0; } patternNames = new Vector.(); patternNames.push("Empty"); patternNames.push("Pat1"); synSong.h.instrNum = 1; synSong.instruments = new Vector.(); synSong.instruments.push(new Instrument()); mutedChans = new Vector.(SE_MAXCHANS, true); }*/ static void AAUCAPQW(Player *p) { //What is this even for? p->PQV = 0; p->sePmSong = SE_PM_SONG; if (p->subsongs){ p->posCoarse = p->curSubsong.startPosCoarse; p->posFine = p->curSubsong.startPosFine; } } #if 0 static void IMXFLSSMB(Player *p, int _arg1) { p->PQV = 1; p->AMYGPFQCHSW = _arg1; p->ISWLKT = 63; p->someCounter = 1; p->sePmSong = SE_PM_PATTERN; p->WDTECTE = p->subsongs[0].tempo - p->subsongs[0].groove; } #endif void initSubsong(Player *p, int num) { int _local2; int i, j; Order *_local5; bool _local6; int _local7; int _local8; double tempo; //reset instruments memcpy(p->instruments, p->synSong->instruments, p->synSong->h.instrNum * sizeof(Instrument)); p->loopCount = 0; if (num >= p->synSong->h.subsongNum) return; p->selectedSubsong = num; p->curSubsong = p->subsongs[p->selectedSubsong]; p->channelNumber = p->curSubsong.channelNumber; reset(p); _local6 = false; for (i = 0; i < SE_MAXCHANS; i++) { p->m_LastNotes[i] = 0; _local2 = 0; _local8 = 0; _local5 = p->curSubsong.orders[i]; _local7 = (((p->curSubsong.startPosCoarse * 64) + p->curSubsong.startPosFine) - 1); for (j = 0; j < 0x0100; j++) { if (_local2 >= _local7){ if (j != _local7){ j--; } break; } _local8 = _local2; _local2 = (_local2 + _local5[j].patLen); } if (j == 0x0100){ _local6 = true; break; } _local7 = (_local7 - _local8); _local7 = (_local7 & 63); p->tuneChannels[i].EQMIWERPIF = j; p->tuneChannels[i].LJHG = _local7; p->curSubsong.mutedChans[i] = p->mutedChans[i]; } if (_local6 == false){ p->someCounter = 1; p->sePmSong = SE_PM_SONG; p->PQV = 1; p->WDTECTE = (8 + p->curSubsong.groove); if (p->curSubsong.tempo){ tempo = (double)(p->curSubsong.tempo); tempo = (tempo / 60); tempo = (tempo * 32); p->samplesPerBeat = (int)((44100 / tempo)); p->otherSamplesPerBeat = p->samplesPerBeat; } if (p->curSubsong.startPosFine == 0){ p->posCoarse = p->curSubsong.startPosCoarse - 1; } else { p->posCoarse = p->curSubsong.startPosCoarse; } p->posFine = p->curSubsong.startPosFine - 1; p->posFine = p->posFine & 63; } } int loadSong(Player *p, const Song *synSong) { int i; void *ptr; AAUCAPQW(p); reset(p); //clearSongData(); p->synSong = synSong; //pass things locally //not much purpouse here //nor in AS3 //why did I do it p->rows = synSong->rows; p->patternNames = (const char **) synSong->patternNames; ptr = realloc(p->instruments, synSong->h.instrNum * sizeof(Instrument)); if (!ptr) return -1; p->instruments = (Instrument *) ptr; p->subsongs = synSong->subsongs; p->arpTable = synSong->arpTable; p->samples = (const int16_t **) synSong->samples; //Do we really need to? //What would Syntrax do? for (i = 0; i < SE_MAXCHANS; i++) { p->mutedChans[i] = synSong->subsongs[0].mutedChans[i]; } initSubsong(p, 0); return 0; } bool playerGetSongEnded(Player *p) { return p->PQV == 0; } uint playerGetLoopCount(Player *p) { return p->loopCount; } void playerGetInfo(Player *p, syntrax_info *info) { int i, j; info->coarse = p->posCoarse; info->fine = p->posFine; info->subsongName = p->curSubsong.m_Name; info->selectedSubs = p->selectedSubsong; info->totalSubs = p->synSong->h.subsongNum; for (i = 0, j = 0; i < p->channelNumber; i++) { Voice *v = &p->voices[i]; if (v->waveBuff != p->silentBuffer) { if (v->isSample) { if (v->sampPos != -1) j++; } else j++; } } info->channelsPlaying = j; }