diff --git a/Frameworks/Syntrax-c/Syntrax-c/file.c b/Frameworks/Syntrax-c/Syntrax-c/file.c deleted file mode 100644 index b09547889..000000000 --- a/Frameworks/Syntrax-c/Syntrax-c/file.c +++ /dev/null @@ -1,400 +0,0 @@ -#include -#include -#include -#include - -#include "file.h" - -size_t filesize; - -Song* File_loadSong(const char *path) -{ - Song *synSong; - FILE *f; - uint8_t *buffer; - size_t size; - - if (!(f = fopen(path, "rb"))) return NULL; - - fseek(f, 0, SEEK_END); - size = ftell(f); - fseek(f, 0, SEEK_SET); - - if (!(buffer = (uint8_t *) malloc(size))) { - fclose(f); - return NULL; - } - - if (fread(buffer, 1, size, f) != size) { - free(buffer); - fclose(f); - return NULL; - } - - fclose(f); - - synSong = File_loadSongMem(buffer, size); - - free(buffer); - - return synSong; -} - -uint16_t get_le16(const void *p) -{ - return (((const uint8_t*)p)[0]) + - (((const uint8_t*)p)[1]) * 0x100; -} - -uint32_t get_le32(const void *p) -{ - return (((const uint8_t*)p)[0]) + - (((const uint8_t*)p)[1]) * 0x100 + - (((const uint8_t*)p)[2]) * 0x10000 + - (((const uint8_t*)p)[3]) * 0x1000000; -} - -static long File_readHeader(SongHeader *h, const uint8_t *buffer, size_t size) -{ - if (size < 52) return -1; - - h->version = get_le16(buffer); - h->UNK00 = get_le16(buffer + 2); - h->patNum = get_le32(buffer + 4); - h->subsongNum = get_le32(buffer + 8); - h->instrNum = get_le32(buffer + 12); - h->UNK01 = get_le32(buffer + 16); - h->UNK02 = get_le16(buffer + 20); - h->UNK03 = get_le16(buffer + 22); - h->UNK04 = get_le16(buffer + 24); - h->UNK05 = get_le16(buffer + 26); - h->UNK06 = get_le16(buffer + 28); - h->UNK07 = get_le16(buffer + 30); - h->UNK08 = get_le16(buffer + 32); - h->UNK09 = get_le16(buffer + 34); - h->UNK0A = get_le16(buffer + 36); - h->UNK0B = get_le16(buffer + 38); - h->UNK0C = get_le16(buffer + 40); - h->UNK0D = get_le16(buffer + 42); - h->UNK0E = get_le16(buffer + 44); - h->UNK0F = get_le16(buffer + 46); - h->UNK10 = get_le16(buffer + 48); - h->UNK11 = get_le16(buffer + 50); - - return 52; -} - -static long File_readSubSong(Subsong *subSong, const uint8_t *buffer, size_t size) -{ - int i, j; - - if (size < 16564) return -1; - - for (i = 0; i < 16; i++) - subSong->UNK00[i] = get_le32(buffer + i * 4); - - for (i = 0; i < SE_MAXCHANS; i++) - subSong->mutedChans[i] = buffer[64 + i]; - - subSong->tempo = get_le32(buffer + 80); - subSong->groove = get_le32(buffer + 84); - subSong->startPosCoarse = get_le32(buffer + 88); - subSong->startPosFine = get_le32(buffer + 92); - subSong->endPosCoarse = get_le32(buffer + 96); - subSong->endPosFine = get_le32(buffer + 100); - subSong->loopPosCoarse = get_le32(buffer + 104); - subSong->loopPosFine = get_le32(buffer + 108); - subSong->isLooping = get_le16(buffer + 112); - - memcpy(subSong->m_Name, buffer + 114, 32); - subSong->m_Name[32] = '\0'; - - subSong->channelNumber = get_le16(buffer + 146); - subSong->delayTime = get_le16(buffer + 148); - - for (i = 0; i < SE_MAXCHANS; i++) - subSong->chanDelayAmt[i] = buffer[150 + i]; - - subSong->amplification = get_le16(buffer + 166); - - subSong->UNK01 = get_le16(buffer + 168); - subSong->UNK02 = get_le16(buffer + 170); - subSong->UNK03 = get_le16(buffer + 172); - subSong->UNK04 = get_le16(buffer + 174); - subSong->UNK05 = get_le16(buffer + 176); - subSong->UNK06 = get_le16(buffer + 178); - - for (i = 0; i < SE_MAXCHANS; i++) { - for (j = 0; j < 0x100; j++) { - subSong->orders[i][j].patIndex = get_le16(buffer + 180 + i * 1024 + j * 4); - subSong->orders[i][j].patLen = get_le16(buffer + 180 + i * 1024 + j * 4 + 2); - } - } - - return 16564; -} - -long File_readRow(Row *r, const uint8_t *buffer, size_t size) -{ - if (size < 5) return -1; - - r->note = buffer[0]; - r->dest = buffer[1]; - r->instr = buffer[2]; - r->spd = buffer[3]; - r->command = buffer[4]; - - return 5; -} - -static long File_readInstrumentEffect(InstrumentEffect *effect, const uint8_t *buffer, size_t size) -{ - if (size < 40) return -1; - - effect->destWave = get_le32(buffer); - effect->srcWave1 = get_le32(buffer + 4); - effect->srcWave2 = get_le32(buffer + 8); - effect->oscWave = get_le32(buffer + 12); - effect->variable1 = get_le32(buffer + 16); - effect->variable2 = get_le32(buffer + 20); - effect->fxSpeed = get_le32(buffer + 24); - effect->oscSpeed = get_le32(buffer + 28); - effect->effectType = get_le32(buffer + 32); - effect->oscSelect = buffer[36]; - effect->resetEffect = buffer[37]; - effect->UNK00 = get_le16(buffer + 38); - - return 40; -} - -static long File_readInstrument(Instrument *instr, const uint8_t *buffer, size_t size) -{ - int i, j; - long sizeRead; - - if (size < 8712) return -1; - - instr->version = get_le16(buffer); - - memcpy(instr->name, buffer + 2, 32); - instr->name[32] = '\0'; - - instr->waveform = get_le16(buffer + 34); - instr->wavelength = get_le16(buffer + 36); - instr->masterVolume = get_le16(buffer + 38); - instr->amWave = get_le16(buffer + 40); - instr->amSpeed = get_le16(buffer + 42); - instr->amLoopPoint = get_le16(buffer + 44); - instr->finetune = get_le16(buffer + 46); - instr->fmWave = get_le16(buffer + 48); - instr->fmSpeed = get_le16(buffer + 50); - instr->fmLoopPoint = get_le16(buffer + 52); - instr->fmDelay = get_le16(buffer + 54); - instr->arpIndex = get_le16(buffer + 56); - - for (i = 0; i < SE_MAXCHANS; i++) - instr->m_ResetWave[i] = buffer[58 + i]; - - instr->panWave = get_le16(buffer + 74); - instr->panSpeed = get_le16(buffer + 76); - instr->panLoopPoint = get_le16(buffer + 78); - instr->UNK00 = get_le16(buffer + 80); - instr->UNK01 = get_le16(buffer + 82); - instr->UNK02 = get_le16(buffer + 84); - instr->UNK03 = get_le16(buffer + 86); - instr->UNK04 = get_le16(buffer + 88); - instr->UNK05 = get_le16(buffer + 90); - - buffer += 92; size -= 92; - - for (i = 0; i < 4; i++) { - sizeRead = File_readInstrumentEffect(&instr->effects[i], buffer, size); - if (sizeRead < 0) return -1; - buffer += sizeRead; size -= sizeRead; - } - - memcpy(instr->smpFullImportPath, buffer, 192); - instr->smpFullImportPath[192] = '\0'; - - buffer += 192; size -= 192; - - instr->UNK06 = get_le32(buffer); - instr->UNK07 = get_le32(buffer + 4); - instr->UNK08 = get_le32(buffer + 8); - instr->UNK09 = get_le32(buffer + 12); - instr->UNK0A = get_le32(buffer + 16); - instr->UNK0B = get_le32(buffer + 20); - instr->UNK0C = get_le32(buffer + 24); - instr->UNK0D = get_le32(buffer + 28); - instr->UNK0E = get_le32(buffer + 32); - instr->UNK0F = get_le32(buffer + 36); - instr->UNK10 = get_le32(buffer + 40); - instr->UNK11 = get_le32(buffer + 44); - instr->UNK12 = get_le16(buffer + 48); - - buffer += 50; size -= 50; - - instr->shareSmpDataFromInstr = get_le16(buffer); - instr->hasLoop = get_le16(buffer + 2); - instr->hasBidiLoop = get_le16(buffer + 4); - - buffer += 6; size -= 6; - - instr->smpStartPoint = get_le32(buffer); - instr->smpLoopPoint = get_le32(buffer + 4); - instr->smpEndPoint = get_le32(buffer + 8); - instr->hasSample = get_le32(buffer + 12); - instr->smpLength = get_le32(buffer + 16); - - buffer += 20; size -= 20; - - for (i = 0; i < SE_MAXCHANS; i++) { - for (j = 0; j < 0x100; j++) { - instr->synthBuffers[i][j] = get_le16(buffer + i * 512 + j * 2); - } - } - - return 8712; -} - -Song* File_loadSongMem(const uint8_t *buffer, size_t size) -{ - int i, j/*, k*/; - int songVer; - /*Subsong *subs; - Order *orderCol; - Order *order; - Row *row;*/ - Instrument *instr; - Song *synSong; - long sizeRead; - - synSong = (Song *) calloc(1, sizeof(Song)); - if (!synSong) return NULL; - - /* - //unused vars - int8_t _local5[] = [0, 0, 0, 0, 0, 0]; - bool _local2 = false; - int _local7 = 0; - bool _local8 = true; - */ - - sizeRead = File_readHeader(&synSong->h, buffer, size); - if (sizeRead < 0) goto FAIL; - buffer += sizeRead; size -= sizeRead; - - songVer = synSong->h.version; - if ((songVer >= 3456) && (songVer <= 3457)){ - if (synSong->h.subsongNum > 0){ - synSong->subsongs = (Subsong *) malloc(synSong->h.subsongNum *sizeof(Subsong)); - if (!synSong->subsongs) goto FAIL; - - for (i = 0; i < synSong->h.subsongNum; i++) { - sizeRead = File_readSubSong(synSong->subsongs + i, buffer, size); - if (sizeRead < 0) goto FAIL; - buffer += sizeRead; size -= sizeRead; - } - - synSong->rows = (Row *) malloc(synSong->h.patNum * 64 *sizeof(Row)); - if (!synSong->rows) goto FAIL; - - for (i = 0, j = synSong->h.patNum * 64; i < j; i++) { - sizeRead = File_readRow(synSong->rows + i, buffer, size); - if (sizeRead < 0) goto FAIL; - buffer += sizeRead; size -= sizeRead; - } - - synSong->patNameSizes = (uint32_t *) malloc(synSong->h.patNum * sizeof(uint32_t)); - if (!synSong->patNameSizes) goto FAIL; - synSong->patternNames = calloc(sizeof(char *), synSong->h.patNum); - if (!synSong->patternNames) goto FAIL; - - for (i = 0; i < synSong->h.patNum; i++) { - if (size < 4) goto FAIL; - j = synSong->patNameSizes[i] = get_le32(buffer); - buffer += 4; size -= 4; - - if (size < j) goto FAIL; - - synSong->patternNames[i] = malloc(j + sizeof(char)); - if (!synSong->patternNames[i]) goto FAIL; - - memcpy(synSong->patternNames[i], buffer, j); - synSong->patternNames[i][j] = '\0'; - - buffer += j; size -= j; - } - - synSong->instruments = malloc(synSong->h.instrNum * sizeof(Instrument)); - if (!synSong->instruments) goto FAIL; - synSong->samples = calloc(sizeof(int16_t *), synSong->h.instrNum); - if (!synSong->samples) goto FAIL; - - for (i = 0; i < synSong->h.instrNum; i++) { - instr = &synSong->instruments[i]; - sizeRead = File_readInstrument(instr, buffer, size); - if (sizeRead < 0) goto FAIL; - buffer += sizeRead; size -= sizeRead; - - if (songVer == 3456){ - instr->shareSmpDataFromInstr = 0; - instr->hasLoop = 0; - instr->hasBidiLoop = 0; - instr->smpStartPoint = 0; - instr->smpLoopPoint = 0; - instr->smpEndPoint = 0; - if (instr->hasSample){ - instr->smpStartPoint = 0; - instr->smpEndPoint = (instr->smpLength / 2); - instr->smpLoopPoint = 0; - } - } - if (instr->hasSample){ - //instr->smpLength is in bytes, I think - if (size < instr->smpLength) goto FAIL; - synSong->samples[i] = malloc(instr->smpLength); - if (!synSong->samples[i]) goto FAIL; - memcpy(synSong->samples[i], buffer, instr->smpLength); - buffer += instr->smpLength; size -= instr->smpLength; - } else { - synSong->samples[i] = NULL; - } - - } - memcpy(synSong->arpTable, buffer, 0x100); - buffer += 0x100; size -= 0x100; - } else goto FAIL; - } else goto FAIL; - - return synSong; - -FAIL: - File_freeSong(synSong); - return NULL; -} - -void File_freeSong(Song *synSong) -{ - int i; - - if (synSong) { - if (synSong->subsongs) free(synSong->subsongs); - if (synSong->rows) free(synSong->rows); - if (synSong->patNameSizes) free(synSong->patNameSizes); - if (synSong->patternNames) { - for (i = 0; i < synSong->h.patNum; i++) { - if (synSong->patternNames[i]) free(synSong->patternNames[i]); - } - free(synSong->patternNames); - } - if (synSong->instruments) free(synSong->instruments); - if (synSong->samples) { - for (i = 0; i < synSong->h.instrNum; i++) { - if (synSong->samples[i]) free(synSong->samples[i]); - } - free(synSong->samples); - } - free(synSong); - } -} diff --git a/Frameworks/Syntrax-c/Syntrax-c/file.h b/Frameworks/Syntrax-c/Syntrax-c/file.h deleted file mode 100644 index de84ba622..000000000 --- a/Frameworks/Syntrax-c/Syntrax-c/file.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FILE_H -#define FILE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -Song* File_loadSong(const char *path); -Song* File_loadSongMem(const uint8_t *buffer, size_t size); - -void File_freeSong(Song *synSong); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Frameworks/Syntrax-c/Syntrax-c/ioutil.h b/Frameworks/Syntrax-c/Syntrax-c/ioutil.h new file mode 100644 index 000000000..85812d4a6 --- /dev/null +++ b/Frameworks/Syntrax-c/Syntrax-c/ioutil.h @@ -0,0 +1,6 @@ +enum loadErr { + ERR_OK, + ERR_MALLOC, + ERR_BADSONG, + ERR_FILEIO +}; \ No newline at end of file diff --git a/Frameworks/Syntrax-c/Syntrax-c/jaytrax.c b/Frameworks/Syntrax-c/Syntrax-c/jaytrax.c new file mode 100644 index 000000000..300327c24 --- /dev/null +++ b/Frameworks/Syntrax-c/Syntrax-c/jaytrax.c @@ -0,0 +1,1779 @@ +#include +#include +#include +#include +#include +#include +#include "jaytrax.h" +#include "mixcore.h" + +#ifndef M_PI +#define M_PI (3.14159265359) +#endif + +int32_t frequencyTable[SE_NROFFINETUNESTEPS][128]; +int16_t sineTab[256]; +uint8_t isStaticInit = 0; + +//void SoundEngine::DeAllocate() + +static void handleEffects(JT1Player* SELF, int32_t channr) { + int32_t f; + for (f=0; fvoices[channr]; + ins = SELF->song->instruments[vc->instrument]; + fx = &ins->fx[f]; + vfx = &vc->fx[f]; + + // increase oscilator + s = (int16_t) fx->oscspd; + vfx->osccnt += s; + vfx->osccnt &= 255; + + switch (fx->effecttype) { + case 0: //none + break; + case 1: { //negate + int32_t dest; + int16_t *dw; + int16_t i,s,c; + dest = fx->dsteffect; + s = (int16_t)fx->effectspd; + c = (int16_t)vfx->fxcnt1; + dw = &vc->waves[256*dest]; + for (i=0; ifxcnt1 = (int32_t)c; + } + break; + case 2: { // warp + int32_t dest; + int16_t *dw; + int16_t i,s,c; + dest = fx->dsteffect; + s = (int16_t) fx->effectspd; + dw = &vc->waves[256*dest]; + c = 0; + for (i=0; i<256; i++) { + dw[i] += c; + c+=s; + } + } + break; + case 3: { // Filter + int32_t dest, src; + int16_t *dw, *sw; + int16_t i, s, t; + dest = fx->dsteffect; + src = fx->srceffect1; + dw = &vc->waves[256*dest]; + sw = &vc->waves[256*src]; + s = (int16_t) fx->effectspd; + if(s>12) s=12; //not more than 12 times...it slowes down too much + for (t=0; t>1; + for (i=1; i<255; i++) { + dw[i] = (sw[i-1] +sw[i+1])>>1; + } + dw[255] = (sw[254] +sw[0])>>1; + } + } + break; + case 4: { // Wavemix + int32_t dest, src1, src2; + int16_t *dw, *sw1, *sw2; + int16_t i, s, c; + dest = fx->dsteffect; + src1 = fx->srceffect1; + src2 = fx->srceffect2; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + sw2 = &vc->waves[256*src2]; + s = (int16_t) fx->effectspd; + vfx->fxcnt1 += s; + vfx->fxcnt1 &= 255; + c = (int16_t)vfx->fxcnt1; + for (i=0; i<256; i++) { + dw[i] = (sw1[i] +sw2[c])>>1; + c++; + c&=255; + } + } + break; + case 5: { // Resonance + int32_t dest, src1, src2; + int16_t *dw, *sw1, *sw2; + int16_t i, c; + dest = fx->dsteffect; + src1 = fx->srceffect1; + src2 = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + sw2 = &vc->waves[256*src2]; + + c = (int16_t)vfx->osccnt; + + // init + double centerFreq, bandwidth; + if(fx->osceffect==0) { + centerFreq = (double)(fx->effectvar1*20); + bandwidth = (double)(fx->effectvar2*16); + } else { + if(fx->oscflg) { + centerFreq = (double)(fx->effectvar1*20); + bandwidth = (double)(sw2[c]+32768)/16; + } else { + centerFreq = (double)(sw2[c]+32768)/13; + bandwidth = (double)(fx->effectvar2*16); + } + } + + vfx->b2 = exp(-(2 * M_PI) * (bandwidth / 22000)); + vfx->b1 = (-4.0 * vfx->b2) / (1.0 + vfx->b2) * cos(2 * M_PI * (centerFreq / 22000)); + vfx->a0 = (1.0 - vfx->b2) * sqrt(1.0 - (vfx->b1 * vfx->b1) / (4.0 * vfx->b2)); + + for (i=0; i<256; i++) { + double o; + o = vfx->a0 * ((double)(sw1[i])/32768) - vfx->b1 * vfx->y1 - vfx->b2 * vfx->y2; + + vfx->y2 = vfx->y1; + vfx->y1 = o; + if(o>.9999)o=.9999; + if(o<-.9999)o=-.9999; + dw[i] = (int16_t)(o*32768); + } + } + break; + case 6: { // Reso Whistle + int32_t dest,src1,src2; + int16_t *dw,*sw1,*sw2; + int16_t i,c; + dest = fx->dsteffect; + src1 = fx->srceffect1; + src2 = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + sw2 = &vc->waves[256*src2]; + + c = (int16_t)vfx->osccnt; + + // init + double centerFreq, bandwidth; + + if(fx->osceffect==0) { + centerFreq = (double)(fx->effectvar1*20); + bandwidth = (double)(fx->effectvar2*16); + } else { + if(fx->oscflg) { + centerFreq = (double)(fx->effectvar1*20); + bandwidth = (double)(sw2[c]+32768)/16; + } else { + centerFreq = (double)(sw2[c]+32768)/13; + bandwidth = (double)(fx->effectvar2*16); + } + } + + vfx->b2 = exp(-(2 * M_PI) * (bandwidth / 22000)); + vfx->b1 = (-4.0 * vfx->b2) / (1.0 + vfx->b2) * cos(2 * M_PI * (centerFreq / 22000)); + vfx->a0 = (1.0 - vfx->b2) * sqrt(1.0 - (vfx->b1 * vfx->b1) / (4.0 * vfx->b2)); + + vfx->b2*=1.2; // do the reso whistle + for (i=0; i<256; i++) { + double o; + o = vfx->a0 * ((double)(sw1[i])/32768) - vfx->b1 * vfx->y1 - vfx->b2 * vfx->y2; + + vfx->y2 = vfx->y1; + vfx->y1 = o; + if(o>.9999)o=.9999; + if(o<-.9999)o=-.9999; + dw[i] = (int16_t)(o*32768); + } + } + break; + case 7: { // Morphing + int32_t dest,src1,src2,osc; + int16_t *dw,*sw1,*sw2,*ow; + int16_t i,c; + dest = fx->dsteffect; + src1 = fx->srceffect1; + src2 = fx->srceffect2; + osc = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + sw2 = &vc->waves[256*src2]; + ow = &vc->waves[256*osc]; + + c = (int16_t)vfx->osccnt; + + // init + int16_t m1,m2; + if(fx->osceffect==0) { + m1 = fx->effectvar1; + } else { + if(fx->oscflg) { + m1 = fx->effectvar1; + } else { + m1 = (ow[c]+32768)/256; + } + } + + m2 = 255-m1; + for (i=0; i<256; i++) { + int32_t a; + a=(((int32_t)sw1[i]*m1)/256)+(((int32_t)sw2[i]*m2)/256); + dw[i] = (int16_t)(a); + } + } + break; + case 8: { // Dyna-Morphing + int32_t dest,src1,src2,osc; + int16_t *dw,*sw1,*sw2,*ow,*si; + int16_t i,c; + si = &sineTab[0]; + dest = fx->dsteffect; + src1 = fx->srceffect1; + src2 = fx->srceffect2; + osc = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + sw2 = &vc->waves[256*src2]; + ow = &vc->waves[256*osc]; + + c = (int16_t)vfx->osccnt; + + // init + int16_t m1,m2,sc; //sc is sincnt + if(fx->osceffect==0) { + sc = fx->effectvar1; + } else { + if(fx->oscflg) + { + sc = fx->effectvar1; + } + else + { + sc = (ow[c]+32768)/256; + } + } + + for (i=0; i<256; i++) { + int32_t a; + m1=(si[sc]>>8)+128; + m2 = 255-m1; + a=(((int32_t)sw1[i]*m1)/256)+(((int32_t)sw2[i]*m2)/256); + dw[i] = (int16_t)(a); + sc++; + sc&=255; + } + } + break; + case 9: { // Distortion + int32_t dest,src1,osc; + int16_t *dw,*sw1,*ow; + int16_t i,c; + dest = fx->dsteffect; + src1 = fx->srceffect1; + osc = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + ow = &vc->waves[256*osc]; + + c = (int16_t)vfx->osccnt; + + // init + int16_t m1; + if(fx->osceffect==0) { + m1 = fx->effectvar1; + } else { + if(fx->oscflg) { + m1 = fx->effectvar1; + } else { + m1 = (ow[c]+32768)/256; + } + } + + for (i=0; i<256; i++) { + int32_t a; + a=((int32_t)sw1[i]*m1)/16; + a+=32768; + if(a<0)a=-a; + a%=131072; + if(a>65535) a = 131071-a; + a-=32768; + dw[i] = (int16_t)(a); + } + } + break; + case 10: { // Scroll left + + int32_t dest; + int16_t *dw; + int16_t i,t; + dest = fx->dsteffect; + dw = &vc->waves[256*dest]; + + t=dw[0]; + for (i=0; i<255; i++) { + dw[i] = dw[i+1]; + } + dw[255]=t; + } + break; + case 11: { // Upsample + + int32_t dest; + int16_t *dw; + int16_t i,c; + c = (int16_t)vfx->fxcnt1; + if(c != 0) { // timeout ended? + vfx->fxcnt1--; + break; + } + vfx->fxcnt1 = fx->effectvar1; + dest = fx->dsteffect; + dw = &vc->waves[256*dest]; + + for (i=0; i<128; i++) { + dw[i]=dw[i*2]; + } + memcpy(&dw[128], &dw[0], 256); + } + break; + case 12: { // Clipper + int32_t dest,src1,osc; + int16_t *dw,*sw1,*ow; + int16_t i,c; + dest = fx->dsteffect; + src1 = fx->srceffect1; + osc = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + ow = &vc->waves[256*osc]; + + c = (int16_t)vfx->osccnt; + + // init + int16_t m1; + if(fx->osceffect==0) { + m1 = fx->effectvar1; + } else { + if(fx->oscflg) { + m1 = fx->effectvar1; + } else { + m1 = (ow[c]+32768)/256; + } + } + + for (i=0; i<256; i++) { + int32_t a; + a=((int32_t)sw1[i]*m1)/16; + if(a<-32767)a=-32767; + if(a>32767)a=32767; + dw[i] = (int16_t)(a); + } + } + break; + case 13: { // bandpass + int32_t dest,src1,src2; + int16_t *dw,*sw1,*sw2; + int16_t i,c; + int32_t _2_pi_w0; + int32_t _1000_Q; + + dest = fx->dsteffect; + src1 = fx->srceffect1; + src2 = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + sw2 = &vc->waves[256*src2]; + + c = (int16_t)vfx->osccnt; + + // init + int32_t freq,reso; + if(fx->osceffect==0) { + freq = fx->effectvar1; + reso = fx->effectvar2; + freq*=16; //(freq 0 - 16000hz) + } else { + if(fx->oscflg) { + freq = fx->effectvar1; + reso = (sw2[c]+32768)>>8; + freq*=16; //(freq 0 - 16000hz) + } else { + freq = (sw2[c]+32768)/16; + reso = fx->effectvar2; + } + } + //calc freq; + //double x = freq - 920.0; + //double w0 = 228 + 3900/2*(1 + tanh(_copysign(pow(fabs(x), 0.85)/95, x))); + double w0 = 228+freq; + _2_pi_w0 = (int32_t)(2*M_PI*w0); + + //calc Q + _1000_Q = 707 + 1000*reso/128; + + int32_t _2_pi_w0_delta_t; + int32_t Vhp_next; + int32_t Vbp_next; + int32_t Vlp_next; + int32_t Vbp; + int32_t Vlp; + int32_t Vhp; + int32_t Vi; + int32_t s; + int32_t delta_t; + + Vbp = vfx->Vbp; + Vlp = vfx->Vlp; + Vhp = vfx->Vhp; + delta_t=8; + + // now let's throw our waveform through the resonator! + for (i=0; i<256; i++) { + // delta_t is converted to seconds given a 1MHz clock by dividing + // with 1 000 000. This is done in three operations to avoid integer + // multiplication overflow. + _2_pi_w0_delta_t = _2_pi_w0*delta_t/100; + + // Calculate filter outputs. + Vi=sw1[i]; + Vhp_next = Vbp*1000/_1000_Q - Vlp + Vi; + Vbp_next = Vbp - _2_pi_w0_delta_t*(Vhp/100)/100; + Vlp_next = Vlp - _2_pi_w0_delta_t*(Vbp/100)/100; + Vhp = Vhp_next; + Vbp = Vbp_next; + Vlp = Vlp_next; + + s = Vlp; + if(s>32767)s=32767; + if(s<-32767)s=-32767; + + dw[i] = (int16_t)(s); + } + vfx->Vbp = Vbp; + vfx->Vlp = Vlp; + vfx->Vhp = Vhp; + } + break; + case 14: { // highpass + int32_t dest,src1,src2; + int16_t *dw,*sw1,*sw2; + int16_t i,c; + int32_t _2_pi_w0; + int32_t _1000_Q; + + dest = fx->dsteffect; + src1 = fx->srceffect1; + src2 = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + sw2 = &vc->waves[256*src2]; + + c = (int16_t)vfx->osccnt; + + // init + int32_t freq, reso; + if(fx->osceffect==0) { + freq = fx->effectvar1; + reso = fx->effectvar2; + freq*=32; //(freq 0 - 16000hz) + } else { + if(fx->oscflg) { + freq = fx->effectvar1; + reso = (sw2[c]+32768)>>8; + freq*=32; //(freq 0 - 16000hz) + } else { + freq = (sw2[c]+32768)/8; + reso = fx->effectvar2; + } + } + //calc freq; + //double x = freq - 920.0; + //double w0 = 228 + 3900/2*(1 + tanh(_copysign(pow(fabs(x), 0.85)/95, x))); + double w0 = 228+freq; + _2_pi_w0 = (int32_t)(2*M_PI*w0); + + //calc Q + _1000_Q = 707 + 1000*reso/128; + + int32_t _2_pi_w0_delta_t; + int32_t Vhp_next; + int32_t Vbp_next; + int32_t Vlp_next; + int32_t Vbp; + int32_t Vlp; + int32_t Vhp; + int32_t Vi; + int32_t s; + int32_t delta_t; + + Vbp = vfx->Vbp; + Vlp = vfx->Vlp; + Vhp = vfx->Vhp; + delta_t=8; + + // now let's throw our waveform through the resonator! + for (i=0; i<256; i++) { + // delta_t is converted to seconds given a 1MHz clock by dividing + // with 1 000 000. This is done in three operations to avoid integer + // multiplication overflow. + _2_pi_w0_delta_t = _2_pi_w0*delta_t/100; + + // Calculate filter outputs. + Vi=sw1[i]; + Vhp_next = Vbp*1000/_1000_Q - Vlp + Vi; + Vbp_next = Vbp - _2_pi_w0_delta_t*(Vhp/100)/100; + Vlp_next = Vlp - _2_pi_w0_delta_t*(Vbp/100)/100; + Vhp = Vhp_next; + Vbp = Vbp_next; + Vlp = Vlp_next; + + s = Vhp; + if(s>32767)s=32767; + if(s<-32767)s=-32767; + + dw[i] = (int16_t)(s); + } + vfx->Vbp = Vbp; + vfx->Vlp = Vlp; + vfx->Vhp = Vhp; + } + break; + case 15: { // bandpass + int32_t dest,src1,src2; + int16_t *dw,*sw1,*sw2; + int16_t i,c; + int32_t _2_pi_w0; + int32_t _1000_Q; + + dest = fx->dsteffect; + src1 = fx->srceffect1; + src2 = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + sw2 = &vc->waves[256*src2]; + + c = (int16_t)vfx->osccnt; + + // init + + int32_t freq,reso; + if(fx->osceffect==0) { + freq = fx->effectvar1; + reso = fx->effectvar2; + freq*=16; //(freq 0 - 16000hz) + } else { + if(fx->oscflg) { + freq = fx->effectvar1; + reso = (sw2[c]+32768)>>8; + freq*=16; //(freq 0 - 16000hz) + } else { + freq = (sw2[c]+32768)/16; + reso = fx->effectvar2; + } + } + //calc freq; + //double x = freq - 920.0; + //double w0 = 228 + 3900/2*(1 + tanh(_copysign(pow(fabs(x), 0.85)/95, x))); + double w0 = 228+freq; + _2_pi_w0 = (int32_t)(2*M_PI*w0); + + //calc Q + _1000_Q = 707 + 1000*reso/128; + + int32_t _2_pi_w0_delta_t; + int32_t Vhp_next; + int32_t Vbp_next; + int32_t Vlp_next; + int32_t Vbp; + int32_t Vlp; + int32_t Vhp; + int32_t Vi; + int32_t s; + int32_t delta_t; + + Vbp = vfx->Vbp; + Vlp = vfx->Vlp; + Vhp = vfx->Vhp; + delta_t=8; + + // now let's throw our waveform through the resonator! + for (i=0; i<256; i++) { + // delta_t is converted to seconds given a 1MHz clock by dividing + // with 1 000 000. This is done in three operations to avoid integer + // multiplication overflow. + _2_pi_w0_delta_t = _2_pi_w0*delta_t/100; + + // Calculate filter outputs. + Vi=sw1[i]; + Vhp_next = Vbp*1000/_1000_Q - Vlp + Vi; + Vbp_next = Vbp - _2_pi_w0_delta_t*(Vhp/100)/100; + Vlp_next = Vlp - _2_pi_w0_delta_t*(Vbp/100)/100; + Vhp = Vhp_next; + Vbp = Vbp_next; + Vlp = Vlp_next; + + s = Vbp; + if(s>32767)s=32767; + if(s<-32767)s=-32767; + + dw[i] = (int16_t)(s); + } + vfx->Vbp = Vbp; + vfx->Vlp = Vlp; + vfx->Vhp = Vhp; + } + break; + case 16: { // Noise + + int32_t dest; + int16_t *dw; + int16_t i; + dest = fx->dsteffect; + dw = &vc->waves[256*dest]; + + for (i=0; i<256; i++) { + //TODO: LCG or twin LSFR noise + dw[i]=(rand()*2)-32768; + } + } + break; + case 17: { // Squash + int32_t dest,src1,osc; + int16_t *dw,*sw1,*ow; + int16_t i,c; + dest = fx->dsteffect; + src1 = fx->srceffect1; + osc = fx->osceffect-1; + dw = &vc->waves[256*dest]; + sw1 = &vc->waves[256*src1]; + ow = &vc->waves[256*osc]; + + c = (int16_t)vfx->osccnt; + + // init + uint16_t m1a, m1b, m2; + if(fx->osceffect==0) { + m1a = fx->effectvar1; + m1b = fx->effectvar2; + } else { + if(fx->oscflg) { + m1a = fx->effectvar1; + m1b = (ow[c]+32768)/256; + } else { + m1a = (ow[c]+32768)/256; + m1b = fx->effectvar2; + } + } + + m1b<<=8; + m1a+=m1b; //m1 is now the counter for the squash + m2=0; //m2 is the actual counter which is 256 times too large (fixed point) + for (i=0; i<256; i++) { + int32_t a,b; + b=sw1[m2>>8]; + a=sw1[(m2>>8)+1]; + a*=(m2&255); + b*=(255-(m2&255)); + a=(a>>8)+(b>>8); + dw[i] = a; + m2+=m1a; + } + } + break; + } + } +} + +static void handleInstrument(JT1Player* SELF, int32_t channr) { + JT1Voice* vc; JT1Inst* ins; + int32_t vol, freq, pan; + + vc = &SELF->voices[channr]; + ins = SELF->song->instruments[vc->instrument]; + + //vol + if (ins->amwave == 0) { //volume wave? + vol = 0; + } else { + vc->volcnt += ins->amspd; + if (vc->volcnt >= 256) { + vc->volcnt -= 256; + vc->volcnt += ins->amlooppoint; + if(vc->volcnt >= 256) { + vc->volcnt = ins->amlooppoint; + } + } + + vol = vc->waves[(256*(ins->amwave-1))+vc->volcnt]; + vol = vol+32768; + vol /= 6; + vol = -vol; //10930; + if (vol <-10000) vol = -10000; + } + + //last but not least, the master volume + vol += 10000; + vol *= ins->mastervol; + vol >>=8; + vol *= SELF->masterVolume; //and the replayers master master volume + vol >>=8; + vol -= 10000; + vc->curvol = vol; + //if(vc->buf) vc->buf->SetVolume(vol); + + //update panning + if(ins->panwave == 0) { //panning wave? + pan = 0; + } else { + vc->pancnt += ins->panspd; + if (vc->pancnt >= 256) { + vc->pancnt -= 256; + vc->pancnt += ins->panlooppoint; + if(vc->pancnt >= 256) { + vc->pancnt = ins->panlooppoint; + } + } + + pan = vc->waves[(256*(ins->panwave-1))+vc->pancnt]; + pan >>=7; + } + //if(vc->buf) vc->buf->SetPan(pan); + vc->curpan = pan; + + //update freq + int32_t k; + k = 0; + k = SELF->song->arpTable[(ins->arpeggio*16)+vc->arpcnt]; + vc->arpcnt++; + vc->arpcnt&=15; + + freq = frequencyTable[ins->finetune][k+vc->curnote]; + + if(vc->freqdel) { + vc->freqdel--; + } else { + if(ins->fmwave != 0) { //frequency wave? + vc->freqcnt += ins->fmspd; + if (vc->freqcnt >= 256) { + vc->freqcnt -= 256; + vc->freqcnt += ins->fmlooppoint; + if(vc->freqcnt >= 256) { + vc->freqcnt = ins->fmlooppoint; + } + } + freq -= vc->waves[(256*(ins->fmwave-1))+vc->freqcnt]; + } + } + freq += vc->bendadd; + vc->curfreq = freq; + + //update pitchbend + + if(vc->bendspd != 0) { + if(vc->bendspd >0) { + if(vc->bendadd < vc->destfreq) { + vc->bendadd += vc->bendspd; + if(vc->bendadd > vc->destfreq) { + vc->bendadd = vc->destfreq; + } + } + } else { + if(vc->bendadd > vc->destfreq) { + vc->bendadd += vc->bendspd; + if(vc->bendadd < vc->destfreq) { + vc->bendadd = vc->destfreq; + } + } + } + } +} + +static void playInstrument(JT1Player* SELF, int32_t channr, int32_t instNum, int32_t note) { + JT1Voice* vc; JT1Inst* ins; + int32_t f; + + // instruments init + if(instNum > SELF->song->nrofinst) return; // not allowed! + vc = &SELF->voices[channr]; + if(vc->instrument == -1 && instNum == 0) return; //geen instrument 0 op een gemute channel...er was namelijk geen previous instrument + ins = SELF->song->instruments[instNum-1]; + + vc->arpcnt = 0; + vc->volcnt = 0; + vc->pancnt = 0; + vc->freqcnt = 0; + vc->curnote = note; + vc->curfreq = 0; + vc->bendtonote = note; + vc->bendadd = 0; + vc->destfreq = 0; + vc->bendspd = 0; + + if(instNum) { // do not copy if 0 + int32_t i; + + //TODO: check sample usage + if(!ins->sharing) { // no sample sharing + vc->sampledata = SELF->song->samples[instNum-1]; + } else { + vc->sampledata = SELF->song->samples[ins->sharing-1]; + } + vc->samplepos = ins->startpoint<<8; + vc->looppoint = ins->looppoint<<8; + vc->endpoint = ins->endpoint<<8; + vc->loopflg = ins->loopflg; + vc->bidirecflg = ins->bidirecflg; + + vc->freqdel = ins->fmdelay; + for (i=0; iresetwave[i]) memcpy(&vc->waves[i*256], &ins->waves[i*256], 256 * sizeof(int16_t)); + } + vc->instrument = instNum-1; + } + + // effects init + for (f=0; fsong->instruments[vc->instrument]->fx[f]; + vfx = &vc->fx[f]; + if (fx->effecttype && fx->reseteffect) { + vfx->osccnt = 0; + vfx->fxcnt1 = 0; + vfx->fxcnt2 = 0; + vfx->y2 = 0; + vfx->y1 = 0; + vfx->Vhp = 0; + vfx->Vbp = 0; + vfx->Vlp = 0; + } + } +} + +static void handleSong(JT1Player* SELF) { + int16_t i; + int32_t step; + + if (!SELF->playFlg) return; + if (SELF->pauseFlg) return; + + SELF->patternDelay--; + if (SELF->patternDelay==0) { + step = SELF->playMode == SE_PM_SONG ? SELF->playStep : SELF->patternOffset; + + if ((step&1) == 0) { // change the groove + SELF->playSpeed = 8 - SELF->subsong->groove; + } else { + SELF->playSpeed = 8 + SELF->subsong->groove; + } + SELF->patternDelay = SELF->playSpeed; + + if (SELF->playMode == SE_PM_PATTERN) { + SELF->patternOffset++; + SELF->patternOffset %= SELF->patternLength; + } else { + for (i=0; i < SELF->subsong->nrofchans; i++) { + JT1Voice* vc = &SELF->voices[i]; + + vc->patpos++; + //the ==-1 part is that the song counter always is 1 before the start...so if the song starts at the beginning, the pos is -1 + if (vc->patpos == SELF->subsong->orders[i][vc->songpos].patlen || vc->songpos == -1) { + vc->patpos = 0; + vc->songpos++; + } + } + + SELF->playStep++; + if (SELF->playStep==64) { + SELF->playStep=0; + SELF->playPosition++; + } + + //has endpos been reached? + if (SELF->playPosition == SELF->subsong->endpos && SELF->playStep == SELF->subsong->endstep) { + if (SELF->subsong->songloop) { //does song loop? + int32_t maat, pos, t; + uint8_t isSkipLoop = 0; + + // now me must reset all the playpointers to the loop positions + for (t=0; tsubsong->orders[t]; + JT1Voice* vc = &SELF->voices[t]; + int32_t endpos; + int32_t lastmaat; + + maat = 0; + pos = 0; + lastmaat=0; + + endpos = (SELF->subsong->looppos * 64) + SELF->subsong->loopstep; + while (pos<256) { + if (maat > endpos) { + if (pos != endpos) pos--; + break; + } + lastmaat=maat; + maat+=orders[pos].patlen; + pos++; + } + //oops! starting position too far! + if (pos == 256) { //!WARN: >= 256? + SELF->playFlg = 0; + isSkipLoop = 1; + break; + } + + endpos -= lastmaat; + endpos &= 63; + + vc->songpos = pos; + vc->patpos = endpos; + } + + if (!isSkipLoop) { + SELF->playPosition = SELF->subsong->looppos; + SELF->playStep = SELF->subsong->loopstep; + } + + SELF->loopCnt ++; + } else { // stop song + SELF->playFlg = 0; + SELF->pauseFlg = 0; + SELF->playMode = SE_PM_SONG; + SELF->playPosition = SELF->subsong->songpos; + SELF->playStep = SELF->subsong->songstep; + } + } + } + } +} + +static void handleScript(JT1Player* SELF, int32_t f,int32_t s, int32_t d, int32_t p, int32_t channr) { //note, script,dstnote,param,channr + JT1Voice* vc; JT1Inst* ins; + int32_t a; + + vc = &SELF->voices[channr]; + if(vc->instrument==-1) return; //no change + ins = SELF->song->instruments[vc->instrument]; + + switch(s) { + default: + case 0: + return; + case 1: //pitch bend + if (vc->bendtonote) { //hebben we al eens gebend? + a = frequencyTable[ins->finetune][vc->bendtonote]; // begin frequentie + vc->curnote = vc->bendtonote; + } else { + a = frequencyTable[ins->finetune][f]; // begin freqeuntie + } + vc->bendadd = 0; + vc->destfreq = frequencyTable[ins->finetune][d] - a; + vc->bendspd = p*20; + vc->bendtonote = d; + break; + case 2: //waveform + if (d>15) d = 15; + ins->waveform = d; + break; + case 3: //wavelength + d = (d>192 ? 256 : (d>96 ? 128 : (d>48 ? 64 : 32))); + ins->wavelength = d; + break; + case 4: //mastervol + ins->mastervol = d; + break; + case 5: //amwaveform + if (d>15) d = 15; + ins->amwave = d; + break; + case 6: //amspd + ins->amspd = d; + break; + case 7: //amlooppoint + ins->amlooppoint = d; + break; + case 8: //finetune + if (d>15) d = 15; + ins->finetune = d; + break; + case 9: //fmwaveform + if (d>15) d = 15; + ins->fmwave = d; + break; + case 10: //fmspd + ins->fmspd = d; + break; + case 11: //fmlooppoint + ins->fmlooppoint = d; + break; + case 12: //fmdelay + ins->fmdelay = d; + break; + case 13: //arpeggio + if (d>15) d = 15; + ins->arpeggio = d; + break; + + case 14: //fx 0 fxdstwave + if (d>15) d = 15; + ins->fx[0].dsteffect = d; + break; + case 15: //fx 0 fxsrcwave1 + if (d>15) d = 15; + ins->fx[0].srceffect1 = d; + break; + case 16: //fx 0 fxsrcwave2 + if (d>15) d = 15; + ins->fx[0].srceffect2 = d; + break; + case 17: //fx 0 fxoscwave + if (d>15) d = 15; + ins->fx[0].osceffect = d; + break; + case 18: //fx 0 effectvar1 + ins->fx[0].effectvar1 = d; + break; + case 19: //fx 0 effectvar2 + ins->fx[0].effectvar2 = d; + break; + case 20: //fx 0 effectspd + ins->fx[0].effectspd = d; + break; + case 21: //fx 0 oscspd + ins->fx[0].oscspd = d; + break; + case 22: //fx 0 oscflg + if (d>1) d=1; + ins->fx[0].oscflg = d; + break; + case 23: //fx 0 effecttype + if (d>=SE_NROFEFFECTS) d=SE_NROFEFFECTS-1; + ins->fx[0].effecttype = d; + break; + case 24: //fx 0 reseteffect + if (d>1) d=1; + ins->fx[0].reseteffect = d; + break; + + case 25: //fx 1 fxdstwave + if (d>15) d = 15; + ins->fx[1].dsteffect = d; + break; + case 26: //fx 1 fxsrcwave1 + if (d>15) d = 15; + ins->fx[1].srceffect1 = d; + break; + case 27: //fx 1 fxsrcwave2 + if (d>15) d = 15; + ins->fx[1].srceffect2 = d; + break; + case 28: //fx 1 fxoscwave + if (d>15) d = 15; + ins->fx[1].osceffect = d; + break; + case 29: //fx 1 effectvar1 + ins->fx[1].effectvar1 = d; + break; + case 30: //fx 1 effectvar2 + ins->fx[1].effectvar2 = d; + break; + case 31: //fx 1 effectspd + ins->fx[1].effectspd = d; + break; + case 32: //fx 1 oscspd + ins->fx[1].oscspd = d; + break; + case 33: //fx 1 oscflg + if (d>1) d=1; + ins->fx[1].oscflg = d; + break; + case 34: //fx 1 effecttype + if (d>=SE_NROFEFFECTS) d=SE_NROFEFFECTS-1; + ins->fx[1].effecttype = d; + break; + case 35: //fx 1 reseteffect + if (d>1) d=1; + ins->fx[1].reseteffect = d; + break; + + case 36: //fx 2 fxdstwave + if (d>15) d = 15; + ins->fx[2].dsteffect = d; + break; + case 37: //fx 2 fxsrcwave1 + if (d>15) d = 15; + ins->fx[2].srceffect1 = d; + break; + case 38: //fx 2 fxsrcwave2 + if (d>15) d = 15; + ins->fx[2].srceffect2 = d; + break; + case 39: //fx 2 fxoscwave + if (d>15) d = 15; + ins->fx[2].osceffect = d; + break; + case 40: //fx 2 effectvar1 + ins->fx[2].effectvar1 = d; + break; + case 41: //fx 2 effectvar2 + ins->fx[2].effectvar2 = d; + break; + case 42: //fx 2 effectspd + ins->fx[2].effectspd = d; + break; + case 43: //fx 2 oscspd + ins->fx[2].oscspd = d; + break; + case 44: //fx 2 oscflg + if (d>1) d=1; + ins->fx[2].oscflg = d; + break; + case 45: //fx 2 effecttype + if (d>=SE_NROFEFFECTS) d=SE_NROFEFFECTS-1; + ins->fx[2].effecttype = d; + break; + case 46: //fx 2 reseteffect + if (d>1) d=1; + ins->fx[2].reseteffect = d; + break; + + case 47: //fx 3 fxdstwave + if (d>15) d = 15; + ins->fx[3].dsteffect = d; + break; + case 48: //fx 3 fxsrcwave1 + if (d>15) d = 15; + ins->fx[3].srceffect1 = d; + break; + case 49: //fx 3 fxsrcwave2 + if (d>15) d = 15; + ins->fx[3].srceffect2 = d; + break; + case 50: //fx 3 fxoscwave + if (d>15) d = 15; + ins->fx[3].osceffect = d; + break; + case 51: //fx 3 effectvar1 + ins->fx[3].effectvar1 = d; + break; + case 52: //fx 3 effectvar2 + ins->fx[3].effectvar2 = d; + break; + case 53: //fx 3 effectspd + ins->fx[3].effectspd = d; + break; + case 54: //fx 3 oscspd + ins->fx[3].oscspd = d; + break; + case 55: //fx 3 oscflg + if (d>1) d=1; + ins->fx[3].oscflg = d; + break; + case 56: //fx 3 effecttype + if (d>=SE_NROFEFFECTS) d=SE_NROFEFFECTS-1; + ins->fx[3].effecttype = d; + break; + case 57: //fx 3 reseteffect + if (d>1) d=1; + ins->fx[3].reseteffect = d; + break; + + case 58: //resetwave 00 + if (d>1) d=1; + ins->resetwave[0] = d; + break; + case 59: //resetwave 01 + if (d>1) d=1; + ins->resetwave[1] = d; + break; + case 60: //resetwave 02 + if (d>1) d=1; + ins->resetwave[2] = d; + break; + case 61: //resetwave 03 + if (d>1) d=1; + ins->resetwave[3] = d; + break; + case 62: //resetwave 04 + if (d>1) d=1; + ins->resetwave[4] = d; + break; + case 63: //resetwave 05 + if (d>1) d=1; + ins->resetwave[5] = d; + break; + case 64: //resetwave 06 + if (d>1) d=1; + ins->resetwave[6] = d; + break; + case 65: //resetwave 07 + if (d>1) d=1; + ins->resetwave[7] = d; + break; + case 66: //resetwave 08 + if (d>1) d=1; + ins->resetwave[8] = d; + break; + case 67: //resetwave 09 + if (d>1) d=1; + ins->resetwave[9] = d; + break; + case 68: //resetwave 10 + if (d>1) d=1; + ins->resetwave[10] = d; + break; + case 69: //resetwave 11 + if (d>1) d=1; + ins->resetwave[11] = d; + break; + case 70: //resetwave 12 + if (d>1) d=1; + ins->resetwave[12] = d; + break; + case 71: //resetwave 13 + if (d>1) d=1; + ins->resetwave[13] = d; + break; + case 72: //resetwave 14 + if (d>1) d=1; + ins->resetwave[14] = d; + break; + case 73: //resetwave 15 + if (d>1) d=1; + ins->resetwave[15] = d; + break; + + case 74: //Change bpm + if (d<=10) d=10; + if (d>220) d=220; + SELF->subsong->songspd = d; + + float t; + t = (float)SELF->subsong->songspd; //bpm + t /=60.0; //bps + t *=32.0; + SELF->timeSpd = (int32_t)(44100.0/t); + break; + case 75: //Change Groove + if (d>3) d=3; + SELF->subsong->groove = d; + break; + case 76: //Fire External Event + //TODO: add this effect + break; + } +} + +static void handlePattern(JT1Player* SELF, int32_t channr) { + JT1Voice* vc; JT1Row* row; + int32_t pat,off; + int32_t f,d,s,p; + + if (SELF->pauseFlg) return; + if (!SELF->playFlg) return; + if (SELF->patternDelay != SELF->playSpeed) return; + + vc = &SELF->voices[channr]; + + if (SELF->playMode == SE_PM_PATTERN) { + if (channr > 0) return; // just play channel 0 + pat = SELF->currentPattern; + off = SELF->patternOffset; + } else { + if (SELF->subsong->mute[channr]) return; + off = vc->patpos; + pat = SELF->subsong->orders[channr][vc->songpos].patnr; + } + + row = &SELF->song->patterns[(pat*64)+off]; + //init instrument + f = row->srcnote; + if (f) playInstrument(SELF, channr, row->inst, f); + + //handle special effects + s = row->script; + d = row->dstnote; + p = row->param; + handleScript(SELF, f, s, d, p, channr); +} + +static void advanceSong(JT1Player* SELF) { + handleSong(SELF); + for (int i=0; i < SELF->subsong->nrofchans; i++) { + handlePattern(SELF, i); + if(SELF->voices[i].instrument != -1) {// mute? + handleInstrument(SELF, i); //do volume and pitch things + handleEffects(SELF, i); //do instrument effects + } + } +} + +static void PlayPattern(JT1Player* SELF, int PatternNr) { + SELF->playFlg = 1; + SELF->currentPattern = PatternNr; + SELF->patternOffset = 63; + SELF->patternDelay = 1; + SELF->playMode = SE_PM_PATTERN; + SELF->playSpeed = SELF->song->subsongs[0]->songspd - SELF->song->subsongs[0]->groove; +} + +static void clearSoundBuffers(JT1Player* SELF) { + int32_t i,j; + + // clear delaybuffers + memset(SELF->overlapBuffer, 0, WANTEDOVERLAP*2*sizeof(int16_t)); + memset(SELF->leftDelayBuffer, 0, 65536*sizeof(int16_t)); + memset(SELF->rightDelayBuffer, 0, 65536*sizeof(int16_t)); + + //initialize channel data + for (i=0;ivoices[i]; + + vc->songpos = 0; + vc->patpos = 0; + vc->instrument = -1; + vc->volcnt = 0; + vc->arpcnt = 0; + vc->pancnt = 0; + vc->curnote = 0; + vc->curfreq = 0; + vc->bendadd = 0; + vc->destfreq = 0; + vc->bendspd = 0; + vc->freqcnt = 0; + vc->freqdel = 0; + vc->sampledata = NULL; + vc->endpoint = 0; + vc->synthPos = 0; + vc->samplepos = 0; + vc->curvol = 0; + vc->curpan = 0; + vc->bendtonote = 0; + vc->looppoint = 0; + vc->loopflg = 0; + vc->bidirecflg = 0; + + vc->wavePtr = NULL; + vc->waveLength = 0; + vc->freqOffset = 0; + vc->gainMainL = 0; + vc->gainMainR = 0; + vc->gainEchoL = 0; + vc->gainEchoR = 0; + + for(j=0;j<4;j++) { + JT1VoiceEffect* vfx = &vc->fx[j]; + + vfx->fxcnt1 = 0; + vfx->fxcnt2 = 0; + vfx->osccnt = 0; + vfx->a0 = 0; + vfx->b1 = 0; + vfx->b2 = 0; + vfx->y1 = 0; + vfx->y2 = 0; + vfx->Vhp = 0; + vfx->Vbp = 0; + vfx->Vlp = 0; + } + memset(vc->waves, 0, 4096*sizeof(int16_t)); + } +} + +//---------------------API + +int jaytrax_loadSong(JT1Player* SELF, JT1Song* sng) { + SELF->song = sng; + jaytrax_changeSubsong(SELF, 0); + return 1; +} + +// This function ensures that the play routine is called properly and everything is initialized in a good way +void jaytrax_changeSubsong(JT1Player* SELF, int subsongnr) { + int maat, pos, t; + JT1Order* order; + + if (subsongnr > SELF->song->nrofsongs) return; + SELF->subsongNr = subsongnr; + SELF->subsong = SELF->song->subsongs[subsongnr]; + clearSoundBuffers(SELF); + + for(t=0; t < SE_NROFCHANS; t++) { + JT1Voice* vc; + int endpos, lastmaat; + + vc = &SELF->voices[t]; + + maat = pos = lastmaat = 0; + order = SELF->subsong->orders[t]; + endpos = (SELF->subsong->songpos * 64) + SELF->subsong->songstep - 1; //minus 1 because we immediately start with the new note + while (pos<256) { + if (maat >= endpos) { + if(pos != endpos) pos--; + break; + } + lastmaat=maat; + maat+=order[pos].patlen; + pos++; + } + //oops! starting position too far! + if (pos == 256) return; //!WARN: >= 256? + + endpos-=lastmaat; + //endpos-=maat; + endpos &=63; + + vc->songpos = pos; + vc->patpos = endpos; + } + + SELF->patternDelay = 1; + SELF->playFlg = 1; + SELF->pauseFlg = 0; + SELF->loopCnt = 0; + SELF->playSpeed = 8 + SELF->subsong->groove; + //SELF->playSpeed = 8; + + if (SELF->subsong->songspd != 0) { + float t; + t = (float)SELF->subsong->songspd; //bpm + t /= 60.0; //bps + t *= 32.0; + SELF->timeCnt = SELF->timeSpd = (int)(44100.0/t); + } + + if(SELF->subsong->songstep == 0) { + SELF->playPosition = SELF->subsong->songpos - 1; + } else { + SELF->playPosition = SELF->subsong->songpos; + } + SELF->playStep = SELF->subsong->songstep - 1; + SELF->playStep &= 63; +} + +void jaytrax_stopSong(JT1Player* SELF) { + SELF->playFlg = 0; + SELF->pauseFlg = 0; + SELF->playMode = SE_PM_SONG; + if(SELF->song) { + SELF->playPosition = SELF->subsong->songpos; + SELF->playStep = SELF->subsong->songstep; + } +} + +void jaytrax_pauseSong(JT1Player* SELF) { + SELF->pauseFlg = 1; +} + +void jaytrax_continueSong(JT1Player* SELF) { + SELF->pauseFlg = 0; +} + +JT1Player* jaytrax_init(void) { + JT1Player* SELF = calloc(1, sizeof(JT1Player)); + //lazy static init + if (!isStaticInit) { + int32_t i, j; + double f,y; + //freq and finetune table + y=2; + for (j=0;joverlapCnt = 0; + + SELF->playPosition = 0; // waar is de song nu? + SELF->playStep = 0; + SELF->subsongNr = 0; + SELF->playFlg = 0; + SELF->pauseFlg = 0; + SELF->loopCnt = 0; + + SELF->patternDelay = 0; + SELF->playSpeed = 0; + SELF->masterVolume = 256; + SELF->playMode = SE_PM_SONG; + jaymix_setInterp(&SELF->itp, ITP_CUBIC); + SELF->song = NULL; + SELF->subsong = NULL; + + //initialize rendering counters and speed + SELF->timeCnt = 2200; + SELF->timeSpd = 2200; + + clearSoundBuffers(SELF); + SELF->delayCnt=0; + return SELF; +} + +void jaytrax_free(JT1Player* SELF) { + free(SELF); +} + +void jaytrax_setInterpolation(JT1Player* SELF, uint8_t id) { + jaymix_setInterp(&SELF->itp, id); +} + +void jaytrax_renderChunk(JT1Player* SELF, int16_t* outbuf, int32_t nrofsamples, int32_t frequency) { + int16_t ic, is; + int32_t r; + int16_t amplification; // amount to amplify afterwards + uint16_t echodelaytime; //delaytime for echo (differs for MIDI or songplayback) + int16_t chanNr; + // we calc nrofsamples samples in blocks of 'timeCnt' big (de songspd) + + r = 0; + echodelaytime = amplification = 0; + while (nrofsamples > 0) { + int32_t availOvlap, frameLen; + int16_t nos; + + frameLen = (SELF->timeSpd * frequency) / 44100; + availOvlap = MIN(WANTEDOVERLAP, frameLen); + if (SELF->timeCnttimeCnt; //Complete block + SELF->timeCnt = frameLen; + } else { + nos = nrofsamples; //Last piece + SELF->timeCnt = SELF->timeCnt - nos; + } + nrofsamples-=nos; + + if (!outbuf) { + //times two for stereo + r += (nos*2); + } else { + if (!SELF->song || !SELF->subsong || SELF->subsong->nrofchans == 0) { + for(is=0; is < nos; is++) { //clean renderbuffer + outbuf[r++] = 0; + outbuf[r++] = 0; + } + } else { + chanNr = SELF->subsong->nrofchans; + + //preparation of wave pointers and freq offset + for(ic=0; ic < chanNr; ic++) { + JT1Voice* vc; + int16_t instnr; + int16_t volMain, volEcho; + + vc = &SELF->voices[ic]; + instnr = vc->instrument; + if (instnr == -1) { // mute? + vc->wavePtr = NULL; + } else { + if(vc->sampledata) { + vc->wavePtr = (int16_t*)vc->sampledata; + } else { + JT1Inst* inst = SELF->song->instruments[instnr]; + vc->wavePtr = &vc->waves[256*inst->waveform]; + vc->waveLength = ((inst->wavelength-1)<<8)+255; //fixed point 8 bit (last 8 bits should be set) + } + } + + //calculate frequency + if (vc->curfreq < 10) vc->curfreq = 10; + vc->freqOffset = (256*vc->curfreq)/frequency * (vc->freqOffset<0 ? -1 : 1); + + if (vc->curpan == 0) { //panning? + vc->gainMainL = 256; //center + vc->gainMainR = 256; + } else { + if (vc->curpan > 0) { + vc->gainMainL = 256-(vc->curpan); + vc->gainMainR = 256; + } else { + vc->gainMainL = 256; + vc->gainMainR = 256+(vc->curpan); + } + } + + //gains + volMain = (vc->curvol+10000)/39; + if (volMain > 256) volMain = 256; + volEcho = SELF->subsong->delayamount[ic]; + + //premultiply volumes + vc->gainMainL = (vc->gainMainL * volMain)>>8; + vc->gainMainR = (vc->gainMainR * volMain)>>8; + vc->gainEchoL = (vc->gainMainL * volEcho)>>8; + vc->gainEchoR = (vc->gainMainR * volEcho)>>8; + } + amplification = SELF->subsong->amplification; + echodelaytime = SELF->subsong->delaytime; + + //main render + while (nos > 0) { + int16_t morenos = MIN(nos, MIXBUF_LEN); + int16_t* overBuf = &SELF->overlapBuffer[0]; + int16_t* delLBuf = &SELF->leftDelayBuffer[0]; + int16_t* delRBuf = &SELF->rightDelayBuffer[0]; + int32_t* tempBuf = &SELF->tempBuf[0]; + + + jaymix_mixCore(SELF, morenos); + + for(is=0; is < morenos; is++) { + int32_t lsample, rsample, echosamplel, echosampler; + int32_t off = MIXBUF_NR * is; + int32_t ocnt = SELF->overlapCnt; + int32_t delcnt = SELF->delayCnt; + + lsample = tempBuf[off + BUF_MAINL]; + rsample = tempBuf[off + BUF_MAINR]; + echosamplel = tempBuf[off + BUF_ECHOL]; + echosampler = tempBuf[off + BUF_ECHOR]; + + lsample = ((lsample / chanNr) + delLBuf[delcnt]) / 2; + lsample *= amplification; + lsample /= 100; + CLAMP(lsample, -32760, 32760); + + rsample = ((rsample / chanNr) + delRBuf[delcnt]) / 2; + rsample *= amplification; + rsample /= 100; + CLAMP(rsample, -32760, 32760); + + //interpolate from overlap buffer + if(ocnt < availOvlap) { + int32_t lovlapsamp, rovlapsamp; + lovlapsamp = overBuf[ocnt*2+0]; + rovlapsamp = overBuf[ocnt*2+1]; + lsample = ((lsample * (ocnt)) / availOvlap) + ((lovlapsamp * (availOvlap - ocnt)) / availOvlap); + rsample = ((rsample * (ocnt)) / availOvlap) + ((rovlapsamp * (availOvlap - ocnt)) / availOvlap); + SELF->overlapCnt++; + } + + outbuf[r++] = lsample; + outbuf[r++] = rsample; + + delLBuf[delcnt] = ((echosamplel / chanNr) + delLBuf[delcnt]) / 2; + delRBuf[delcnt] = ((echosampler / chanNr) + delRBuf[delcnt]) / 2; + SELF->delayCnt++; + SELF->delayCnt %= echodelaytime / (44100 / frequency); + } + + nos -= morenos; + } + } + } + + if(SELF->timeCnt == frameLen) { + int32_t tempdelaycnt; + struct { + int32_t synthPos; + int32_t sampPos; + int32_t freqOffset; + } temp[SE_NROFCHANS]; + + tempdelaycnt = SELF->delayCnt; + for(ic=0; ic < SE_NROFCHANS; ic++) { + JT1Voice* vc = &SELF->voices[ic]; + + temp[ic].synthPos = vc->synthPos; + temp[ic].sampPos = vc->samplepos; + temp[ic].freqOffset = vc->freqOffset; + } + + if (outbuf && SELF->song && SELF->subsong && SELF->subsong->nrofchans != 0) { + int16_t nos2 = availOvlap; + chanNr = SELF->subsong->nrofchans; + + //render to overlap buffer + assert(availOvlap - SELF->overlapCnt == 0); + while (nos2 > 0) { + int16_t morenos = MIN(nos2, MIXBUF_LEN); + int16_t* overBuf = &SELF->overlapBuffer[0]; + int16_t* delLBuf = &SELF->leftDelayBuffer[0]; + int16_t* delRBuf = &SELF->rightDelayBuffer[0]; + int32_t* tempBuf = &SELF->tempBuf[0]; + + + jaymix_mixCore(SELF, morenos); + + for(is=0; is < morenos; is++) { + int32_t lsample, rsample; + int32_t off = MIXBUF_NR * is; + int32_t ocnt = SELF->overlapCnt; + int32_t delcnt = SELF->delayCnt; + + lsample = tempBuf[off + BUF_MAINL]; + rsample = tempBuf[off + BUF_MAINR]; + + lsample = ((lsample / chanNr) + delLBuf[delcnt]) / 2; + lsample *= amplification; + lsample /= 100; + CLAMP(lsample, -32760, 32760); + + rsample = ((rsample / chanNr) + delRBuf[delcnt]) / 2; + rsample *= amplification; + rsample /= 100; + CLAMP(rsample, -32760, 32760); + + overBuf[(availOvlap - ocnt)*2+0] = lsample; + overBuf[(availOvlap - ocnt)*2+1] = rsample; + + SELF->delayCnt++; + SELF->delayCnt %= echodelaytime / (44100 / frequency); + SELF->overlapCnt--; + } + nos2 -= morenos; + } + assert(SELF->overlapCnt == 0); + } + + SELF->delayCnt = tempdelaycnt; + + for(ic=0; ic < SE_NROFCHANS; ic++) { + JT1Voice* vc = &SELF->voices[ic]; + + vc->synthPos = temp[ic].synthPos; + vc->samplepos = temp[ic].sampPos; + vc->freqOffset = temp[ic].freqOffset; + } + + //Update song pointers + advanceSong(SELF); + } + } +} + +int32_t jaytrax_getLength(JT1Player* SELF, int subsongnr, int loopCnt, int frequency) { + int32_t length = 0; + int32_t lengthMax = frequency * 60 * 30; + int32_t frameLen; + jaytrax_changeSubsong(SELF, subsongnr); + while (SELF->playFlg && SELF->loopCnt < loopCnt && length < lengthMax) { + frameLen = (SELF->timeSpd * frequency) / 44100; + advanceSong(SELF); + length += frameLen; + } + return length < lengthMax ? length : -1; +} diff --git a/Frameworks/Syntrax-c/Syntrax-c/jaytrax.h b/Frameworks/Syntrax-c/Syntrax-c/jaytrax.h new file mode 100644 index 000000000..9418d751b --- /dev/null +++ b/Frameworks/Syntrax-c/Syntrax-c/jaytrax.h @@ -0,0 +1,264 @@ +#ifndef JAYTRAX_H +#define JAYTRAX_H + +#define WANTEDOVERLAP (15) //wanted declick overlap length(in samples). Will be smaller than a song tick. +#define MIXBUF_LEN (512) //temporary mixing buffer length +#define SAMPSPOOLSIZE (0xFFF) //buffer for unrolling samples + +enum INTERP_LIST { + ITP_NONE, + ITP_NEAREST, + ITP_LINEAR, + ITP_QUADRATIC, + ITP_CUBIC, + //ITP_BLEP, + INTERP_COUNT +}; + +enum SE_BUFTYPE { + BUF_MAINL, + BUF_MAINR, + BUF_ECHOL, + BUF_ECHOR, + MIXBUF_NR +}; + +enum SE_PLAYMODE { + SE_PM_SONG = 0, + SE_PM_PATTERN +}; + +//in case of changing any of the below +//please change jxs loader to account for changes +#define SE_ORDERS_SUBSONG (256) +#define SE_ROWS_PAT (64) +#define SE_EFF_INST (4) +#define SE_WAVES_INST (16) +#define SE_SAMPS_WAVE (256) +#define SE_ARPS_SONG (16) +#define SE_STEPS_ARP (16) +#define SE_NAMELEN (32) + +#define SE_NROFCHANS (16) // number of chans replayer can take +#define SE_NROFFINETUNESTEPS (16) // number of finetune scales +#define SE_NROFEFFECTS (18) // number of available wave effects + +typedef struct JT1Order JT1Order; +struct JT1Order { + int16_t patnr; // welk pattern spelen... + int16_t patlen; // 0/16/32/48 +}; + +typedef struct JT1Row JT1Row; +struct JT1Row { + uint8_t srcnote; + uint8_t dstnote; + uint8_t inst; + int8_t param; + uint8_t script; +}; + +typedef struct JT1Subsong JT1Subsong; +struct JT1Subsong { + uint8_t mute[SE_NROFCHANS]; // which channels are muted? (1=muted) + int32_t songspd; // delay tussen de pattern-stepjes + int32_t groove; // groove value... 0=nothing, 1 = swing, 2=shuffle + int32_t songpos; // waar start song? (welke maat?) + int32_t songstep; // welke patternpos offset? (1/64 van maat) + int32_t endpos; // waar stopt song? (welke maat?) + int32_t endstep; // welke patternpos offset? (1/64 van maat) + int32_t looppos; // waar looped song? (welke maat?) + int32_t loopstep; // welke patternpos offset? (1/64 van maat) + int16_t songloop; // if true, the song loops inbetween looppos and endpos + char name[SE_NAMELEN]; // name of subsong + int16_t nrofchans; //nr of channels used + uint16_t delaytime; // the delaytime (for the echo effect) + uint8_t delayamount[SE_NROFCHANS]; // amount per channel for the echo-effect + int16_t amplification; //extra amplification factor (20 to 1000) + JT1Order orders[SE_NROFCHANS][SE_ORDERS_SUBSONG]; +}; + +typedef struct JT1Effect JT1Effect; +struct JT1Effect { + int32_t dsteffect; + int32_t srceffect1; + int32_t srceffect2; + int32_t osceffect; + int32_t effectvar1; + int32_t effectvar2; + int32_t effectspd; + int32_t oscspd; + int32_t effecttype; + int8_t oscflg; + int8_t reseteffect; +}; + +// inst is the structure which has the entire instrument definition. +typedef struct JT1Inst JT1Inst; +struct JT1Inst { + int16_t mugiversion; + char instname[SE_NAMELEN]; + int16_t waveform; + int16_t wavelength; + int16_t mastervol; + int16_t amwave; + int16_t amspd; + int16_t amlooppoint; + int16_t finetune; + int16_t fmwave; + int16_t fmspd; + int16_t fmlooppoint; + int16_t fmdelay; + int16_t arpeggio; + int8_t resetwave[SE_WAVES_INST]; + int16_t panwave; + int16_t panspd; + int16_t panlooppoint; + JT1Effect fx[SE_EFF_INST]; + char samplename[SE_NAMELEN]; + //ugly. Move samples into their own spot + int16_t sharing; // sample sharing! sharing contains instr nr of shared sanpledata (0=no sharing) + int16_t loopflg; //does the sample loop or play one/shot? (0=1shot) + int16_t bidirecflg; // does the sample loop birdirectional? (0=no) + int32_t startpoint; + int32_t looppoint; + int32_t endpoint; + uint8_t hasSampData; // pointer naar de sample (mag 0 zijn) + int32_t samplelength; // length of sample + int16_t waves[SE_WAVES_INST * SE_SAMPS_WAVE]; +}; + +typedef struct JT1Song JT1Song; +struct JT1Song { + int16_t mugiversion;//version of mugician this song was saved with + int32_t nrofpats; //aantal patterns beschikbaar + int32_t nrofsongs; //aantal beschikbare subsongs + int32_t nrofinst; //aantal gebruikte instruments + + JT1Subsong** subsongs; + JT1Row* patterns; + char** patNames; + JT1Inst** instruments; + uint8_t** samples; + int8_t arpTable[SE_ARPS_SONG * SE_STEPS_ARP]; + +}; + +//---------------------internal structs + +// Chanfx is an internal structure which keeps track of the current effect parameters per active channel +typedef struct JT1VoiceEffect JT1VoiceEffect; +struct JT1VoiceEffect { + int fxcnt1; + int fxcnt2; + int osccnt; + double a0; + double b1; + double b2; + double y1; + double y2; + int Vhp; + int Vbp; + int Vlp; +}; + +// chandat is an internal structure which keeps track of the current instruemnts current variables per active channel +typedef struct JT1Voice JT1Voice; +struct JT1Voice { + int32_t songpos; + int32_t patpos; + int32_t instrument; + int32_t volcnt; + int32_t pancnt; + int32_t arpcnt; + int32_t curnote; + int32_t curfreq; + int32_t curvol; + int32_t curpan; + int32_t bendadd; // for the pitchbend + int32_t destfreq; // ... + int32_t bendspd; // ... + int32_t bendtonote; + int32_t freqcnt; + int32_t freqdel; + uint8_t* sampledata; + int32_t looppoint; + int32_t endpoint; + uint8_t loopflg; + uint8_t bidirecflg; + int32_t synthPos; + int32_t samplepos; + + //immediate render vars + int16_t* wavePtr; + int32_t waveLength; + int32_t freqOffset; + int16_t gainMainL; + int16_t gainMainR; + int16_t gainEchoL; + int16_t gainEchoR; + + JT1VoiceEffect fx[SE_WAVES_INST]; + int16_t waves[SE_WAVES_INST * SE_SAMPS_WAVE]; +}; + +typedef struct Interpolator Interpolator; +struct Interpolator { + uint8_t id; + int16_t numTaps; + int32_t (*fItp) (int16_t* buf, int32_t pos, int32_t sizeMask); + char name[32]; +}; + +typedef struct JT1Player JT1Player; +struct JT1Player { + JT1Song* song; + JT1Subsong* subsong; + JT1Voice voices[SE_NROFCHANS]; + int32_t subsongNr; + int16_t timeCnt; // Samplecounter which stores the njumber of samples before the next songparams are calculated (is reinited with timeSpd) + int16_t timeSpd; // Sample accurate counter which indicates every how many samples the song should progress 1 tick. Is dependant on rendering frequency and BPM + uint8_t playFlg; // 0 if playback is stopped, 1 if song is being played + uint8_t pauseFlg; // 0 if playback is not paused, 1 if playback is paused + int32_t playSpeed; // Actual delay in between notes + int32_t patternDelay; // Current delay in between notes (resets with playSpeed) + int32_t playPosition; // Current position in song (coarse) + int32_t playStep; // Current position in song (fine) + int32_t masterVolume; // Mastervolume of the replayer (256=max - 0=min) + int16_t leftDelayBuffer[65536]; // buffer to simulate an echo on the left stereo channel + int16_t rightDelayBuffer[65536]; // buffer to simulate an echo on the right stereo channel + int16_t overlapBuffer[WANTEDOVERLAP*2]; // Buffer which stores overlap between waveforms to avoid clicks + int16_t overlapCnt; // Used to store how much overlap we have already rendered + uint16_t delayCnt; // Internal counter used for delay + int32_t tempBuf[MIXBUF_LEN * MIXBUF_NR]; + Interpolator* itp; + + int32_t playMode; // in which mode is the replayer? Song or patternmode? + int32_t currentPattern; // Which pattern are we currently playing (In pattern play mode) + int32_t patternLength; // Current length of a pattern (in pattern play mode) + int32_t patternOffset; // Current play offset in the pattern (used for display) + + int32_t loopCnt; // If song is meant to loop, the number of times the song has looped +}; + +//---------------------API + +#ifdef __cplusplus +extern "C" { +#endif + +int jaytrax_loadSong(JT1Player* SELF, JT1Song* sng); +void jaytrax_changeSubsong(JT1Player* SELF, int subsongnr); +void jaytrax_stopSong(JT1Player* SELF); +void jaytrax_pauseSong(JT1Player* SELF); +void jaytrax_continueSong(JT1Player* SELF); +void jaytrax_setInterpolation(JT1Player* SELF, uint8_t id); +JT1Player* jaytrax_init(void); +void jaytrax_free(JT1Player* SELF); +void jaytrax_renderChunk(JT1Player* SELF, int16_t* renderbuf, int32_t nrofsamples, int32_t frequency); +int32_t jaytrax_getLength(JT1Player* SELF, int subsongnr, int loopCnt, int frequency); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Frameworks/Syntrax-c/Syntrax-c/jxs.c b/Frameworks/Syntrax-c/Syntrax-c/jxs.c new file mode 100644 index 000000000..c69c83736 --- /dev/null +++ b/Frameworks/Syntrax-c/Syntrax-c/jxs.c @@ -0,0 +1,359 @@ +#include +#include +#include +#include +#include "jaytrax.h" +#include "jxs.h" +#include "ioutil.h" + +struct memdata +{ + const uint8_t* data; + size_t remain; + int error; +}; + +void memread(void* buf, size_t size, size_t count, void* _data) +{ + struct memdata* data = (struct memdata*)_data; + size_t unread = 0; + size *= count; + if (size > data->remain) + { + unread = size - data->remain; + size = data->remain; + data->error = 1; + } + memcpy(buf, data->data, size); + data->data += size; + data->remain -= size; + if (unread) + memset(((uint8_t*)buf) + size, 0, unread); +} + +int memerror(void* _data) +{ + struct memdata* data = (struct memdata*)_data; + return data->error; +} + +void fileread(void* buf, size_t size, size_t count, void* _file) +{ + FILE* file = (FILE*)_file; + fread(buf, size, count, file); +} + +int fileerror(void* _file) +{ + FILE* file = (FILE*)_file; + return ferror(file); +} + +typedef void (*thereader)(void*, size_t, size_t, void*); +typedef int (*theerror)(void*); + +//---------------------JXS3457 + +static int struct_readHeader(JT1Song* dest, thereader reader, theerror iferror, void* fin) { + + f_JT1Header t; + + reader(&t, sizeof(f_JT1Header), 1, fin); + dest->mugiversion = t.mugiversion; + dest->nrofpats = t.nrofpats; + dest->nrofsongs = t.nrofsongs; + dest->nrofinst = t.nrofinst; + return iferror(fin); +} + +static int struct_readSubsong(JT1Subsong* dest, size_t len, thereader reader, theerror iferror, void* fin) { + uint32_t i, j, k; + f_JT1Subsong t; + + for (i=0; i < len; i++) { + reader(&t, sizeof(f_JT1Subsong), 1, fin); + for (j=0; j < J3457_CHANS_SUBSONG; j++) dest[i].mute[j] = t.mute[j]; + dest[i].songspd = t.songspd; + dest[i].groove = t.groove; + dest[i].songpos = t.songpos; + dest[i].songstep = t.songstep; + dest[i].endpos = t.endpos; + dest[i].endstep = t.endstep; + dest[i].looppos = t.looppos; + dest[i].loopstep = t.loopstep; + dest[i].songloop = t.songloop; + memcpy(&dest[i].name, &t.name, 32); + dest[i].nrofchans = t.nrofchans; + dest[i].delaytime = t.delaytime; + for (j=0; j < J3457_CHANS_SUBSONG; j++) { + dest[i].delayamount[j] = t.delayamount[j]; + } + dest[i].amplification = t.amplification; + for (j=0; j < J3457_CHANS_SUBSONG; j++) { + for (k=0; k < J3457_ORDERS_SUBSONG; k++) { + dest[i].orders[j][k].patnr = t.orders[j][k].patnr; + dest[i].orders[j][k].patlen = t.orders[j][k].patlen; + } + } + } + return iferror(fin); +} + +static int struct_readPat(JT1Row* dest, size_t len, thereader reader, theerror iferror, void* fin) { + uint32_t i, j; + f_JT1Row t[J3457_ROWS_PAT]; + + for (i=0; i < len; i++) { + reader(&t, sizeof(f_JT1Row)*J3457_ROWS_PAT, 1, fin); + for (j=0; j < J3457_ROWS_PAT; j++) { + uint32_t off = i*J3457_ROWS_PAT + j; + dest[off].srcnote = t[j].srcnote; + dest[off].dstnote = t[j].dstnote; + dest[off].inst = t[j].inst; + dest[off].param = t[j].param; + dest[off].script = t[j].script; + } + } + return iferror(fin); +} + +static int struct_readInst(JT1Inst* dest, size_t len, thereader reader, theerror iferror, void* fin) { + uint32_t i, j; + f_JT1Inst t; + for (i=0; i < len; i++) { + reader(&t, sizeof(f_JT1Inst), 1, fin); + dest[i].mugiversion = t.mugiversion; + memcpy(&dest[i].instname, &t.instname, 32); + dest[i].waveform = t.waveform; + dest[i].wavelength = t.wavelength; + dest[i].mastervol = t.mastervol; + dest[i].amwave = t.amwave; + dest[i].amspd = t.amspd; + dest[i].amlooppoint = t.amlooppoint; + dest[i].finetune = t.finetune; + dest[i].fmwave = t.fmwave; + dest[i].fmspd = t.fmspd; + dest[i].fmlooppoint = t.fmlooppoint; + dest[i].fmdelay = t.fmdelay; + dest[i].arpeggio = t.arpeggio; + for (j=0; j < J3457_WAVES_INST; j++) { + dest[i].resetwave[j] = t.resetwave[j]; + } + dest[i].panwave = t.panwave; + dest[i].panspd = t.panspd; + dest[i].panlooppoint = t.panlooppoint; + for (j=0; j < J3457_EFF_INST; j++) { + dest[i].fx[j].dsteffect = t.fx[j].dsteffect; + dest[i].fx[j].srceffect1 = t.fx[j].srceffect1; + dest[i].fx[j].srceffect2 = t.fx[j].srceffect2; + dest[i].fx[j].osceffect = t.fx[j].osceffect; + dest[i].fx[j].effectvar1 = t.fx[j].effectvar1; + dest[i].fx[j].effectvar2 = t.fx[j].effectvar2; + dest[i].fx[j].effectspd = t.fx[j].effectspd; + dest[i].fx[j].oscspd = t.fx[j].oscspd; + dest[i].fx[j].effecttype = t.fx[j].effecttype; + dest[i].fx[j].oscflg = t.fx[j].oscflg; + dest[i].fx[j].reseteffect = t.fx[j].reseteffect; + } + memcpy(&dest[i].samplename, &t.samplename, 192); + //exFnameFromPath(&dest[i].samplename, &t.samplename, SE_NAMELEN); + dest[i].sharing = t.sharing; + dest[i].loopflg = t.loopflg; + dest[i].bidirecflg = t.bidirecflg; + dest[i].startpoint = t.startpoint; + dest[i].looppoint = t.looppoint; + dest[i].endpoint = t.endpoint; + dest[i].hasSampData = t.hasSampData ? 1 : 0; //this was a sampdata pointer in original jaytrax + dest[i].samplelength = t.samplelength; + //memcpy(&dest[i].waves, &t.waves, J3457_WAVES_INST * J3457_SAMPS_WAVE * sizeof(int16_t)); + reader(&dest->waves, 2, J3457_WAVES_INST * J3457_SAMPS_WAVE, fin); + } + return iferror(fin); +} + +//---------------------JXS3458 + +/* Soon! */ + +//--------------------- + +static int jxsfile_readSongCb(thereader reader, theerror iferror, void* fin, JT1Song** sngOut) { +#define FAIL(x) {error=(x); goto _ERR;} + JT1Song* song; + int i; + int error; + + //song + if((song = (JT1Song*)calloc(1, sizeof(JT1Song)))) { + int version; + + if (struct_readHeader(song, reader, iferror, fin)) FAIL(ERR_BADSONG); + //version magic + version = song->mugiversion; + if (version >= 3456 && version <= 3457) { + int nrSubsongs = song->nrofsongs; + int nrPats = song->nrofpats; + int nrRows = J3457_ROWS_PAT * nrPats; + int nrInst = song->nrofinst; + + //subsongs + if ((song->subsongs = (JT1Subsong**)calloc(nrSubsongs, sizeof(JT1Subsong*)))) { + for (i=0; i < nrSubsongs; i++) { + if ((song->subsongs[i] = (JT1Subsong*)calloc(1, sizeof(JT1Subsong)))) { + if (struct_readSubsong(song->subsongs[i], 1, reader, iferror, fin)) FAIL(ERR_BADSONG); + } else FAIL(ERR_MALLOC); + } + } else FAIL(ERR_MALLOC); + + //patterns + if ((song->patterns = (JT1Row*)calloc(nrRows, sizeof(JT1Row)))) { + if (struct_readPat(song->patterns, nrPats, reader, iferror, fin)) FAIL(ERR_BADSONG); + } else FAIL(ERR_MALLOC); + + //pattern names. Length includes \0 + if ((song->patNames = (char**)calloc(nrPats, sizeof(char*)))) { + for (i=0; i < nrPats; i++) { + int32_t nameLen = 0; + + reader(&nameLen, 4, 1, fin); + if ((song->patNames[i] = (char*)calloc(nameLen, sizeof(char)))) { + reader(song->patNames[i], nameLen, 1, fin); + } else FAIL(ERR_MALLOC); + } + + if (iferror(fin)) FAIL(ERR_BADSONG); + } else FAIL(ERR_MALLOC); + + //instruments + if ((song->instruments = (JT1Inst**)calloc(nrInst, sizeof(JT1Inst*)))) { + if (!(song->samples = (uint8_t**)calloc(nrInst, sizeof(uint8_t*)))) FAIL(ERR_MALLOC); + for (i=0; i < nrInst; i++) { + if ((song->instruments[i] = (JT1Inst*)calloc(1, sizeof(JT1Inst)))) { + JT1Inst* inst = song->instruments[i]; + if (struct_readInst(inst, 1, reader, iferror, fin)) FAIL(ERR_BADSONG); + + //patch old instrument to new + if (version == 3456) { + inst->sharing = 0; + inst->loopflg = 0; + inst->bidirecflg = 0; + inst->startpoint = 0; + inst->looppoint = 0; + inst->endpoint = 0; + //silly place to put a pointer + if (inst->hasSampData) { + inst->startpoint=0; + inst->endpoint=(inst->samplelength/2); + inst->looppoint=0; + } + } + + //sample data + if (inst->hasSampData) { + //inst->samplelength is in bytes, not samples + if(!(song->samples[i] = (uint8_t*)calloc(inst->samplelength, sizeof(uint8_t)))) FAIL(ERR_MALLOC); + reader(song->samples[i], 1, inst->samplelength, fin); + if (iferror(fin)) FAIL(ERR_BADSONG); + } else { + song->samples[i] = NULL; + } + } else FAIL(ERR_MALLOC); + } + } else FAIL(ERR_MALLOC); + + //arpeggio table + reader(&song->arpTable, J3457_STEPS_ARP, J3457_ARPS_SONG, fin); + + if (iferror(fin)) FAIL(ERR_BADSONG); + } else if (version == 3458) { + //Soon enough! + FAIL(ERR_BADSONG); + } else FAIL(ERR_BADSONG); + } else FAIL(ERR_MALLOC); + + *sngOut = song; + return ERR_OK; + #undef FAIL + _ERR: + jxsfile_freeSong(song); + *sngOut = NULL; + return error; +} + +int jxsfile_readSong(const char* path, JT1Song** sngOut) { + char buf[BUFSIZ]; + FILE *fin; + int error; + + if (!(fin = fopen(path, "rb"))) return ERR_FILEIO; + setbuf(fin, buf); + + error = jxsfile_readSongCb(fileread, fileerror, fin, sngOut); + + fclose(fin); + return error; + + _ERR: + if (fin) fclose(fin); + return error; +} + +int jxsfile_readSongMem(const uint8_t* data, size_t size, JT1Song** sngOut) { + struct memdata fin; + fin.data = data; + fin.remain = size; + fin.error = 0; + + return jxsfile_readSongCb(memread, memerror, &fin, sngOut); +} + +void jxsfile_freeSong(JT1Song* song) { + if (song) { + int i; + int nrSubsongs = song->nrofsongs; + int nrPats = song->nrofpats; + int nrInst = song->nrofinst; + + if (song->subsongs) { + + for (i=0; i < nrSubsongs; i++) { + if (song->subsongs[i]) + free(song->subsongs[i]); + } + + free(song->subsongs); + } + + if (song->patterns) { + free(song->patterns); + } + + if (song->patNames) { + for (i=0; i < nrPats; i++) { + if (song->patNames[i]) + free(song->patNames[i]); + } + + free(song->patNames); + } + + if (song->instruments && song->samples) { + for (i=0; i < nrInst; i++) { + if (song->instruments[i]) + free(song->instruments[i]); + if (song->samples[i]) + free(song->samples[i]); + } + } + + if (song->samples) { + free(song->samples); + } + + if (song->instruments) { + free(song->instruments); + } + + free(song); + } +} diff --git a/Frameworks/Syntrax-c/Syntrax-c/jxs.h b/Frameworks/Syntrax-c/Syntrax-c/jxs.h new file mode 100644 index 000000000..e16cb62ea --- /dev/null +++ b/Frameworks/Syntrax-c/Syntrax-c/jxs.h @@ -0,0 +1,168 @@ +#ifndef JXS_H +#define JXS_H +#include +#include "jaytrax.h" + +#define J3457_CHANS_SUBSONG (16) +#define J3457_ORDERS_SUBSONG (256) +#define J3457_ROWS_PAT (64) +#define J3457_EFF_INST (4) +#define J3457_WAVES_INST (16) +#define J3457_SAMPS_WAVE (256) +#define J3457_ARPS_SONG (16) +#define J3457_STEPS_ARP (16) + +typedef struct f_JT1Order f_JT1Order; +struct f_JT1Order { + int16_t patnr; // welk pattern spelen... + int16_t patlen; // 0/16/32/48 +} __attribute__((__packed__)); + +typedef struct f_JT1Row f_JT1Row; +struct f_JT1Row { + uint8_t srcnote; + uint8_t dstnote; + uint8_t inst; + int8_t param; + uint8_t script; +} __attribute__((__packed__)); + +typedef struct f_JT1Header f_JT1Header; +struct f_JT1Header { + int16_t mugiversion;//version of mugician this song was saved with + int16_t PAD00; + int32_t nrofpats; //aantal patterns beschikbaar + int32_t nrofsongs; //aantal beschikbare subsongs + int32_t nrofinst; //aantal gebruikte instruments + int32_t PAD01; + int16_t PAD02; + int16_t PAD03; + int16_t PAD04; + int16_t PAD05; + int16_t PAD06; + int16_t PAD07; + int16_t PAD08; + int16_t PAD09; + int16_t PAD0A; + int16_t PAD0B; + int16_t PAD0C; + int16_t PAD0D; + int16_t PAD0E; + int16_t PAD0F; + int16_t PAD10; + int16_t PAD11; +} __attribute__((__packed__)); + +typedef struct f_JT1Subsong f_JT1Subsong; +struct f_JT1Subsong { + int32_t PAD00[J3457_CHANS_SUBSONG]; + uint8_t mute[J3457_CHANS_SUBSONG]; // which channels are muted? (1=muted) + int32_t songspd; // delay tussen de pattern-stepjes + int32_t groove; // groove value... 0=nothing, 1 = swing, 2=shuffle + int32_t songpos; // waar start song? (welke maat?) + int32_t songstep; // welke patternpos offset? (1/64 van maat) + int32_t endpos; // waar stopt song? (welke maat?) + int32_t endstep; // welke patternpos offset? (1/64 van maat) + int32_t looppos; // waar looped song? (welke maat?) + int32_t loopstep; // welke patternpos offset? (1/64 van maat) + int16_t songloop; // if true, the song loops inbetween looppos and endpos + char name[32]; // name of subsong + int16_t nrofchans; //nr of channels used + uint16_t delaytime; // the delaytime (for the echo effect) + uint8_t delayamount[J3457_CHANS_SUBSONG]; // amount per channel for the echo-effect + int16_t amplification; //extra amplification factor (20 to 1000) + int16_t PAD01; + int16_t PAD02; + int16_t PAD03; + int16_t PAD04; + int16_t PAD05; + int16_t PAD06; + f_JT1Order orders[J3457_CHANS_SUBSONG][J3457_ORDERS_SUBSONG]; +} __attribute__((__packed__)); + +typedef struct f_JT1Effect f_JT1Effect; +struct f_JT1Effect { + int32_t dsteffect; + int32_t srceffect1; + int32_t srceffect2; + int32_t osceffect; + int32_t effectvar1; + int32_t effectvar2; + int32_t effectspd; + int32_t oscspd; + int32_t effecttype; + int8_t oscflg; + int8_t reseteffect; + int16_t PAD00; +} __attribute__((__packed__)); + +// inst is the structure which has the entire instrument definition. +typedef struct f_JT1Inst f_JT1Inst; +struct f_JT1Inst { + int16_t mugiversion; + char instname[32]; + int16_t waveform; + int16_t wavelength; + int16_t mastervol; + int16_t amwave; + int16_t amspd; + int16_t amlooppoint; + int16_t finetune; + int16_t fmwave; + int16_t fmspd; + int16_t fmlooppoint; + int16_t fmdelay; + int16_t arpeggio; + int8_t resetwave[J3457_WAVES_INST]; + int16_t panwave; + int16_t panspd; + int16_t panlooppoint; + int16_t PAD00; + int16_t PAD01; + int16_t PAD02; + int16_t PAD03; + int16_t PAD04; + int16_t PAD05; + f_JT1Effect fx[J3457_EFF_INST]; + char samplename[192]; // path naar de gebruikte sample (was _MAX_PATH lang... is nu getruncate naar 192)(in de toekomst nog kleiner?) + int32_t PAD06; + int32_t PAD07; + int32_t PAD08; + int32_t PAD09; + int32_t PAD0A; + int32_t PAD0B; + int32_t PAD0C; + int32_t PAD0D; + int32_t PAD0E; + int32_t PAD0F; + int32_t PAD10; + int32_t PAD11; + int16_t PAD12; + int16_t sharing; // sample sharing! sharing contains instr nr of shared sanpledata (0=no sharing) + int16_t loopflg; //does the sample loop or play one/shot? (0=1shot) + int16_t bidirecflg; // does the sample loop birdirectional? (0=no) + int32_t startpoint; + int32_t looppoint; + int32_t endpoint; + int32_t hasSampData; // pointer naar de sample (mag 0 zijn) + int32_t samplelength; // length of sample + //int16_t waves[J3457_WAVES_INST * J3457_SAMPS_WAVE]; +} __attribute__((__packed__)); + +//---------------------JXS3458 + + +//--------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +int jxsfile_readSong(const char* path, JT1Song** sngOut); +int jxsfile_readSongMem(const uint8_t* data, size_t size, JT1Song** sngOut); +void jxsfile_freeSong(JT1Song* song); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Frameworks/Syntrax-c/Syntrax-c/mixcore.c b/Frameworks/Syntrax-c/Syntrax-c/mixcore.c new file mode 100644 index 000000000..3b325daa5 --- /dev/null +++ b/Frameworks/Syntrax-c/Syntrax-c/mixcore.c @@ -0,0 +1,212 @@ +#include +#include +#include +#include "mixcore.h" +#include "jaytrax.h" + +// ITP_[number of taps]_[input sample width]_[fractional precision]_[readable name] +#define ITP_T02_S16_I08_LINEAR(P, F) (P[0]+(((P[1]-P[0])*F) >> 8)) +#define ITP_T03_S16_I15_QUADRA(P, F) (((((((((P[0] + P[2]) >> 1) - P[1]) * F) >> 16) + P[1]) - ((P[2] + P[0] + (P[0] << 1)) >> 2)) * F) >> 14) + P[0] +#define ITP_T04_SXX_F01_CUBIC(P, F) (P[1] + 0.5 * F*(P[2] - P[0] + F*(2.0 * P[0] - 5.0 * P[1] + 4.0 * P[2] - P[3] + F * (3.0 * (P[1] - P[2]) + P[3] - P[0])))) + + +//---------------------interpolators +#define GET_PT(x) buf[((pos + ((x)<<8)) & sizeMask)>>8] + +static int32_t itpNone(int16_t* buf, int32_t pos, int32_t sizeMask) { + return 0;(void)buf;(void)pos;(void)sizeMask; +} + +static int32_t itpNearest(int16_t* buf, int32_t pos, int32_t sizeMask) { + return GET_PT(0); +} + +static int32_t itpLinear(int16_t* buf, int32_t pos, int32_t sizeMask) { + int32_t p[2]; + int32_t frac = pos & 0xFF; + + p[0] = GET_PT(0); + p[1] = GET_PT(1); + + return ITP_T02_S16_I08_LINEAR(p, frac); +} + +static int32_t itpQuad(int16_t* buf, int32_t pos, int32_t sizeMask) { + int32_t p[3]; + int32_t frac = (pos & 0xFF)<<7; + + p[0] = GET_PT(0); + p[1] = GET_PT(1); + p[2] = GET_PT(2); + + return ITP_T03_S16_I15_QUADRA(p, frac); +} + +static int32_t itpCubic(int16_t* buf, int32_t pos, int32_t sizeMask) { + int32_t p[4]; + float frac = (float)(pos & 0xFF)/256; + + p[0] = GET_PT(0); + p[1] = GET_PT(1); + p[2] = GET_PT(2); + p[3] = GET_PT(3); + + return ITP_T04_SXX_F01_CUBIC(p, frac); +} + +Interpolator interps[INTERP_COUNT] = { + {ITP_NONE, 0, &itpNone, "None"}, + {ITP_NEAREST, 1, &itpNearest, "Nearest"}, + {ITP_LINEAR, 2, &itpLinear, "Linear"}, + {ITP_QUADRATIC, 3, &itpQuad, "Quadratic"}, + {ITP_CUBIC, 4, &itpCubic, "Cubic"}, + //{ITP_BLEP, -1, &mixSynthNearest, &mixSampNearest, "BLEP"} //BLEP needs variable amount of taps +}; + +static void smpCpyFrw(int16_t* destination, const int16_t* source, int32_t num) { + memcpy(destination, source, num * sizeof(int16_t)); +} + +static void smpCpyRev(int16_t* destination, const int16_t* source, int32_t num) { + for (int i=0; i < num; i++) { + destination[i] = source[num-1 - i]; + } +} + +//---------------------API + +uint8_t jaymix_setInterp(Interpolator** out, uint8_t id) { + for (int8_t i=0; itempBuf[0]; + int32_t chanNr = SELF->subsong->nrofchans; + + + assert(numSamples <= MIXBUF_LEN); + memset(&outBuf[0], 0, numSamples * MIXBUF_NR * sizeof(int32_t)); + + + for (ic=0; ic < chanNr; ic++) { + JT1Voice* vc = &SELF->voices[ic]; + int32_t (*fItp) (int16_t* buf, int pos, int sizeMask); + int32_t loopLen = vc->endpoint - vc->looppoint; + + doneSmp = 0; + if (vc->sampledata) { + + if (!vc->wavePtr) continue; + if (vc->samplepos < 0) continue; + fItp = SELF->itp->fItp; + + while (doneSmp < numSamples) { + int16_t tapArr[32] = {0}; + int32_t tapPos = vc->samplepos>>8; + uint8_t tapDir = 0; + + //slow, but better than nothing + //also, not centered + for (int i=0; i < SELF->itp->numTaps; i++) { + tapArr[i] = vc->wavePtr[tapPos]; + + if (tapDir) { //backwards + tapPos--; + + if (tapPos < (vc->looppoint>>8)) { + tapPos += 2; + tapDir = 0; + } + } else { //forwards + tapPos++; + + if (tapPos >= (vc->endpoint>>8)) { + if (vc->loopflg) { //has loop + if(vc->bidirecflg) { //bidi + tapPos -= 2; + tapDir = 1; + } else { //straight + tapPos -= (loopLen>>8); + } + } else { //oneshot + break; + } + } + } + } + + tempBuf[doneSmp++] = fItp(tapArr, vc->samplepos&0xFF, 0xFFFFFFFF); //vc->wavePtr[vc->samplepos>>8]; + vc->samplepos += vc->freqOffset; + + + + if (vc->freqOffset < 0) { //backwards + if (vc->samplepos < vc->looppoint) { + vc->freqOffset *= -1; + vc->samplepos += vc->freqOffset; + } + } else { //forwards + if (vc->samplepos >= vc->endpoint) { + if (vc->loopflg) { //has loop + if(vc->bidirecflg) { //bidi + vc->freqOffset *= -1; + vc->samplepos += vc->freqOffset; + } else { //straight + vc->samplepos -= loopLen; + } + } else { //oneshot + vc->samplepos = -1; + break; + } + } + } + } + } else { //synth render + int32_t nos; + + if (!vc->wavePtr) { + //original replayer plays through an empty wave + vc->synthPos += vc->freqOffset * numSamples; + vc->synthPos &= vc->waveLength; + continue; + } + fItp = SELF->itp->fItp; + + //loop unroll optimization + nos = numSamples; + if (nos&1) { + tempBuf[doneSmp++] = fItp(vc->wavePtr, vc->synthPos, vc->waveLength); + vc->synthPos += vc->freqOffset; + vc->synthPos &= vc->waveLength; + nos--; + } + for(is=0; is < nos; is+=2) { + tempBuf[doneSmp++] = fItp(vc->wavePtr, vc->synthPos, vc->waveLength); + vc->synthPos += vc->freqOffset; + vc->synthPos &= vc->waveLength; + tempBuf[doneSmp++] = fItp(vc->wavePtr, vc->synthPos, vc->waveLength); + vc->synthPos += vc->freqOffset; + vc->synthPos &= vc->waveLength; + } + } + + for(is=0; is < doneSmp; is++) { + int32_t samp, off; + + samp = tempBuf[is]; + off = is * MIXBUF_NR; + outBuf[off + BUF_MAINL] += (samp * vc->gainMainL)>>8; + outBuf[off + BUF_MAINR] += (samp * vc->gainMainR)>>8; + outBuf[off + BUF_ECHOL] += (samp * vc->gainEchoL)>>8; + outBuf[off + BUF_ECHOR] += (samp * vc->gainEchoR)>>8; + } + } +} \ No newline at end of file diff --git a/Frameworks/Syntrax-c/Syntrax-c/mixcore.h b/Frameworks/Syntrax-c/Syntrax-c/mixcore.h new file mode 100644 index 000000000..912927f66 --- /dev/null +++ b/Frameworks/Syntrax-c/Syntrax-c/mixcore.h @@ -0,0 +1,15 @@ +#ifndef MIXCORE_H +#define MIXCORE_H +#include +#include "jaytrax.h" + +#define CLAMP(x, low, high) (x = ((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +//#define CLAMP16(x) if ((int16_t)(x) != x) x = 0x7FFF ^ (x >> 31) //fast 32 -> 16 bit clamp +#define CLAMP16(x) (int16_t)(x) != x ? 0x7FFF ^ (x >> 31) : x //fast 32 -> 16 bit clamp +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define CHKPOS(VC) ((VC->samplepos >= 0) && ((VC->curdirecflg && ((VC->samplepos & 0xFFFFFF00) >= VC->looppoint)) || ((VC->samplepos & 0xFFFFFF00) < VC->endpoint))) + +void jaymix_mixCore(JT1Player* SELF, int32_t numSamples); +uint8_t jaymix_setInterp(Interpolator** out, uint8_t id); + +#endif \ No newline at end of file diff --git a/Frameworks/Syntrax-c/Syntrax-c/resampler.c b/Frameworks/Syntrax-c/Syntrax-c/resampler.c deleted file mode 100644 index 9d99cc78c..000000000 --- a/Frameworks/Syntrax-c/Syntrax-c/resampler.c +++ /dev/null @@ -1,367 +0,0 @@ -#include "resampler.h" - -#include -#include -#include - -/* Copyright (C) 2004-2008 Shay Green. - Copyright (C) 2021 Christopher Snowhill. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#undef PI -#define PI 3.1415926535897932384626433832795029 - -enum { imp_scale = 0x7FFF }; -typedef int16_t imp_t; -typedef int32_t imp_off_t; /* for max_res of 512 and impulse width of 32, end offsets must be 32 bits */ - -#if RESAMPLER_BITS == 16 -typedef int32_t intermediate_t; -#elif RESAMPLER_BITS == 32 -typedef int64_t intermediate_t; -#endif - -static void gen_sinc( double rolloff, int width, double offset, double spacing, double scale, - int count, imp_t* out ) -{ - double angle; - - double const maxh = 256; - double const step = PI / maxh * spacing; - double const to_w = maxh * 2 / width; - double const pow_a_n = pow( rolloff, maxh ); - scale /= maxh * 2; - angle = (count / 2 - 1 + offset) * -step; - - while ( count-- ) - { - double w; - *out++ = 0; - w = angle * to_w; - if ( fabs( w ) < PI ) - { - double rolloff_cos_a = rolloff * cos( angle ); - double num = 1 - rolloff_cos_a - - pow_a_n * cos( maxh * angle ) + - pow_a_n * rolloff * cos( (maxh - 1) * angle ); - double den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; - double sinc = scale * num / den - scale; - - out [-1] = (imp_t) (cos( w ) * sinc + sinc); - } - angle += step; - } -} - -enum { width = 32 }; -enum { max_res = 512 }; -enum { min_width = (width < 4 ? 4 : width) }; -enum { adj_width = min_width / 4 * 4 + 2 }; -enum { write_offset = adj_width }; - -enum { buffer_size = 128 }; - -typedef struct _resampler -{ - int width_; - int rate_; - int inptr; - int infilled; - int outptr; - int outfilled; - - int latency; - - imp_t const* imp; - imp_t impulses [max_res * (adj_width + 2 * (sizeof(imp_off_t) / sizeof(imp_t)))]; - sample_t buffer_in[buffer_size * 2]; - sample_t buffer_out[buffer_size]; -} resampler; - -void * resampler_create() -{ - resampler *r = (resampler *) malloc(sizeof(resampler)); - if (r) resampler_clear(r); - return r; -} - -void * resampler_dup(const void *_r) -{ - void *_t = (resampler *) malloc(sizeof(resampler)); - if (_t) resampler_dup_inplace(_t, _r); - return _t; -} - -void resampler_dup_inplace(void *_t, const void *_r) -{ - const resampler *r = (const resampler *)_r; - resampler *t = (resampler *)_t; - if (r && t) - { - memcpy(t, r, sizeof(resampler)); - t->imp = t->impulses + (r->imp - r->impulses); - } - else if (t) - { - resampler_clear(t); - } -} - -void resampler_destroy(void *r) -{ - free(r); -} - -void resampler_clear(void *_r) -{ - resampler * r = (resampler *)_r; - r->width_ = adj_width; - r->inptr = 0; - r->infilled = 0; - r->outptr = 0; - r->outfilled = 0; - r->latency = 0; - r->imp = r->impulses; - - resampler_set_rate(r, 1.0); -} - -void resampler_set_rate( void *_r, double new_factor ) -{ - int step; //const - double filter; //const - double fraction, pos; - int n; - - resampler *rs = (resampler *)_r; - imp_t* out; - - double const rolloff = 0.999; - double const gain = 1.0; - - /* determine number of sub-phases that yield lowest error */ - double ratio_ = 0.0; - int res = -1; - { - double least_error = 2; - double pos = 0; - int r; - for ( r = 1; r <= max_res; r++ ) - { - double nearest, error; - pos += new_factor; - nearest = floor( pos + 0.5 ); - error = fabs( pos - nearest ); - if ( error < least_error ) - { - res = r; - ratio_ = nearest / res; - least_error = error; - } - } - } - rs->rate_ = ratio_; - - /* how much of input is used for each output sample */ - step = (int) floor( ratio_ ); - fraction = fmod( ratio_, 1.0 ); - - filter = (ratio_ < 1.0) ? 1.0 : 1.0 / ratio_; - pos = 0.0; - /*int input_per_cycle = 0;*/ - out = rs->impulses; - - for ( n = res; --n >= 0; ) - { - int cur_step; - - gen_sinc( rolloff, (int) (rs->width_ * filter + 1) & ~1, pos, filter, - (double)(imp_scale * gain * filter), (int) rs->width_, out ); - out += rs->width_; - - cur_step = step; - pos += fraction; - if ( pos >= 0.9999999 ) - { - pos -= 1.0; - cur_step += 1; - } - - ((imp_off_t*)out)[0] = (cur_step - rs->width_ + 2) * sizeof (sample_t); - ((imp_off_t*)out)[1] = 2 * sizeof (imp_t) + 2 * sizeof (imp_off_t); - out += 2 * (sizeof(imp_off_t) / sizeof(imp_t)); - /*input_per_cycle += cur_step;*/ - } - /* last offset moves back to beginning of impulses*/ - ((imp_off_t*)out) [-1] -= (char*) out - (char*) rs->impulses; - - rs->imp = rs->impulses; -} - -int resampler_get_free(void *_r) -{ - resampler *r = (resampler *)_r; - return buffer_size - r->infilled; -} - -int resampler_get_min_fill(void *_r) -{ - resampler *r = (resampler *)_r; - const int min_needed = write_offset + 1; - const int latency = r->latency ? 0 : adj_width; - int min_free = min_needed - r->infilled - latency; - return min_free < 0 ? 0 : min_free; -} - -void resampler_write_sample(void *_r, sample_t s) -{ - resampler *r = (resampler *)_r; - - if (!r->latency) - { - int i; - for ( i = 0; i < adj_width / 2; ++i) - { - r->buffer_in[r->inptr] = 0; - r->buffer_in[buffer_size + r->inptr] = 0; - r->inptr = (r->inptr + 1) % (buffer_size); - r->infilled += 1; - } - r->latency = 1; - } - - if (r->infilled < buffer_size) - { - r->buffer_in[r->inptr] = s; - r->buffer_in[buffer_size + r->inptr + 0] = s; - r->inptr = (r->inptr + 1) % (buffer_size); - r->infilled += 1; - } -} - -#if defined(_MSC_VER) || defined(__GNUC__) -#define restrict __restrict -#endif - -static const sample_t * resampler_inner_loop( resampler *r, sample_t** out_, - sample_t const* out_end, sample_t const in [], int in_size ) -{ - in_size -= write_offset; - if ( in_size > 0 ) - { - sample_t* restrict out = *out_; - sample_t const* const in_end = in + in_size; - imp_t const* imp = r->imp; - - do - { - int n; - /* accumulate in extended precision*/ - int pt = imp [0]; - intermediate_t s = (intermediate_t)pt * (intermediate_t)(in [0]); - if ( out >= out_end ) - break; - for ( n = (adj_width - 2) / 2; n; --n ) - { - pt = imp [1]; - s += (intermediate_t)pt * (intermediate_t)(in [1]); - - /* pre-increment more efficient on some RISC processors*/ - imp += 2; - pt = imp [0]; - s += (intermediate_t)pt * (intermediate_t)(in [2]); - in += 2; - } - pt = imp [1]; - s += (intermediate_t)pt * (intermediate_t)(in [1]); - - /* these two "samples" after the end of the impulse give the - * proper offsets to the next input sample and next impulse */ - in = (sample_t const*) ((char const*) in + ((imp_off_t*)(&imp [2]))[0]); /* some negative value */ - imp = (imp_t const*) ((char const*) imp + ((imp_off_t*)(&imp [2]))[1]); /* small positive or large negative */ - - out [0] = (sample_t) (s >> 15); - out += 1; - } - while ( in < in_end ); - - r->imp = imp; - *out_ = out; - } - return in; -} - -#undef restrict - -static int resampler_wrapper( resampler *r, sample_t out [], int* out_size, - sample_t const in [], int in_size ) -{ - sample_t* out_ = out; - long result = resampler_inner_loop( r, &out_, out + *out_size, in, in_size ) - in; - - *out_size = (int)(out_ - out); - return (int) result; -} - -static void resampler_fill( resampler *r ) -{ - while (!r->outfilled && r->infilled) - { - int inread; - - int writepos = ( r->outptr + r->outfilled ) % (buffer_size); - int writesize = (buffer_size) - writepos; - if ( writesize > ( buffer_size - r->outfilled ) ) - writesize = buffer_size - r->outfilled; - inread = resampler_wrapper(r, &r->buffer_out[writepos], &writesize, &r->buffer_in[buffer_size + r->inptr - r->infilled], r->infilled); - r->infilled -= inread; - r->outfilled += writesize; - if (!inread) - break; - } -} - -int resampler_get_avail(void *_r) -{ - resampler *r = (resampler *)_r; - if (r->outfilled < 1 && r->infilled >= r->width_) - resampler_fill( r ); - return r->outfilled; -} - -static void resampler_read_sample_internal( resampler *r, sample_t *s, int advance ) -{ - if (r->outfilled < 1) - resampler_fill( r ); - if (r->outfilled < 1) - { - *s = 0; - return; - } - *s = r->buffer_out[r->outptr]; - if (advance) - { - r->outptr = (r->outptr + 1) % (buffer_size); - r->outfilled -= 1; - } -} - -void resampler_read_sample( void *_r, sample_t *s ) -{ - resampler *r = (resampler *)_r; - resampler_read_sample_internal(r, s, 1); -} - -void resampler_peek_sample( void *_r, sample_t *s ) -{ - resampler *r = (resampler *)_r; - resampler_read_sample_internal(r, s, 0); -} diff --git a/Frameworks/Syntrax-c/Syntrax-c/resampler.h b/Frameworks/Syntrax-c/Syntrax-c/resampler.h deleted file mode 100644 index b0dab77b7..000000000 --- a/Frameworks/Syntrax-c/Syntrax-c/resampler.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _RESAMPLER_H_ -#define _RESAMPLER_H_ - -/* Copyright (C) 2004-2008 Shay Green. - Copyright (C) 2021 Christopher Snowhill. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#define RESAMPLER_BITS 32 -#define RESAMPLER_DECORATE syntrax - -#ifdef RESAMPLER_DECORATE -#undef PASTE -#undef EVALUATE -#define PASTE(a,b) a ## b -#define EVALUATE(a,b) PASTE(a,b) -#define resampler_create EVALUATE(RESAMPLER_DECORATE,_resampler_create) -#define resampler_dup EVALUATE(RESAMPLER_DECORATE,_resampler_dup) -#define resampler_dup_inplace EVALUATE(RESAMPLER_DECORATE,_resampler_dup_inplace) -#define resampler_destroy EVALUATE(RESAMPLER_DECORATE,_resampler_destroy) -#define resampler_clear EVALUATE(RESAMPLER_DECORATE,_resampler_clear) -#define resampler_set_rate EVALUATE(RESAMPLER_DECORATE,_resampler_set_rate) -#define resampler_get_free EVALUATE(RESAMPLER_DECORATE,_resampler_get_free) -#define resampler_get_min_fill EVALUATE(RESAMPLER_DECORATE,_resampler_get_min_fill) -#define resampler_write_sample EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample) -#define resampler_get_avail EVALUATE(RESAMPLER_DECORATE,_resampler_get_avail) -#define resampler_read_sample EVALUATE(RESAMPLER_DECORATE,_resampler_read_sample) -#define resampler_peek_sample EVALUATE(RESAMPLER_DECORATE,_resampler_peek_sample) -#endif - -#include - -#if RESAMPLER_BITS == 16 -typedef int16_t sample_t; -#elif RESAMPLER_BITS == 32 -typedef int32_t sample_t; -#else -#error Choose a bit depth! -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -void * resampler_create(void); -void * resampler_dup(const void *); -void resampler_dup_inplace(void *, const void *); -void resampler_destroy(void *); - -void resampler_clear(void *); - -void resampler_set_rate( void *, double new_factor ); - -int resampler_get_free(void *); -int resampler_get_min_fill(void *); - -void resampler_write_sample(void *, sample_t s); - -int resampler_get_avail(void *); - -void resampler_read_sample( void *, sample_t *s ); -void resampler_peek_sample( void *, sample_t *s ); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Frameworks/Syntrax-c/Syntrax-c/syntrax.c b/Frameworks/Syntrax-c/Syntrax-c/syntrax.c deleted file mode 100644 index daec8b4b3..000000000 --- a/Frameworks/Syntrax-c/Syntrax-c/syntrax.c +++ /dev/null @@ -1,2355 +0,0 @@ -#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; - - Player* p; - - srand((unsigned int) 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 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 == 0xFF)))){ - 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; - 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; -} diff --git a/Frameworks/Syntrax-c/Syntrax-c/syntrax.h b/Frameworks/Syntrax-c/Syntrax-c/syntrax.h deleted file mode 100644 index 24f0b2268..000000000 --- a/Frameworks/Syntrax-c/Syntrax-c/syntrax.h +++ /dev/null @@ -1,363 +0,0 @@ -#ifndef SYNTRAX_H -#define SYNTRAX_H - -#include -#include - -//----------------------------typedefs------------------------- -#ifndef NULL -#define NULL 0 -#endif -typedef unsigned uint; - -//----------------------------defines-------------------------- -#define SE_NROFEFFECTS 18 -#define SE_MAXCHANS 16 -#define SE_NROFFINETUNESTEPS 16 - -#define SE_OVERLAP 100 - -#define BUFFERLENGTH 4096 -#define CHANNELS 2 -#define BITRATE 16 -#define RESAMPLE_POINTS 4 - -//some constants for controlling stuff -//I've no idea what the abreviations stand for -#define SE_PM_SONG 0 -#define SE_PM_PATTERN 1 - - -//---------------------------structures------------------------ -//player structs -//don't pack these -typedef struct -{ - int wavelength; - int gainDelay; - int delta; - int freq; - int isSample; - int isPlayingBackward; - int smpLoopEnd; - int PPMXBYLQ; //unused - int gain; - const int16_t *waveBuff; - int hasBidiLoop; - int synthPos; - int gainRight; - int smpLoopStart; - int bkpSynthPos; - int sampPos; - int gainLeft; - int hasLoop; - int smpLength; - int gainDelayRight; - int gainDelayLeft; - int hasLooped; - void * resampler[2]; - int last_delta; -} Voice; - -typedef struct -{ - int VMBNMTNBQU; - int TIPUANVVR; - double MDTMBBIQHRQ; - double YLKJB; - double DQVLFV; - int MFATTMREMVP; - double ILHG; - double RKF; - int SPYK; - int QOMCBTRPXF; - int ABJGHAUY; -} VoiceEffect; - -typedef struct -{ - int JOEEPJCI; - int BNWIGU; - int isPlayingBackward; - int ELPHLDR; - int panning; - int TVORFCC; - int EYRXAB; //rather unused - int UHYDBDDI; - int XESAWSO; - int hasBidiLoop; - int fmDelay; - int volume; - int ACKCWV; - int sampPos; - int insNum; - uint8_t EQMIWERPIF; - int freq; - int HFRLJCG; - int VNVJPDIWAJQ; - int hasLoop; - int LJHG; - const int16_t *sampleBuffer; - //SQUASH effect overflows into next buffer - //SE_MAXCHANS * 0x100 + 1 must be allocated - int16_t synthBuffers[SE_MAXCHANS][0x100]; - int16_t OVERFLOW_DUMMY; - int smpLoopStart; - int smpLoopEnd; - int hasLooped; - VoiceEffect effects[4]; -} TuneChannel; - - -//data structs - -typedef struct -{ - uint32_t destWave; - uint32_t srcWave1; - uint32_t srcWave2; - uint32_t oscWave; - uint32_t variable1; - uint32_t variable2; - uint32_t fxSpeed; - uint32_t oscSpeed; - uint32_t effectType; - int8_t oscSelect; - int8_t resetEffect; - int16_t UNK00; -} InstrumentEffect; - -typedef struct -{ - int16_t version; - char name[33]; - int16_t waveform; - int16_t wavelength; - int16_t masterVolume; - int16_t amWave; - int16_t amSpeed; - int16_t amLoopPoint; - int16_t finetune; - int16_t fmWave; - int16_t fmSpeed; - int16_t fmLoopPoint; - int16_t fmDelay; - int16_t arpIndex; - uint8_t m_ResetWave[SE_MAXCHANS]; - int16_t panWave; - int16_t panSpeed; - int16_t panLoopPoint; - int16_t UNK00; - int16_t UNK01; - int16_t UNK02; - int16_t UNK03; - int16_t UNK04; - int16_t UNK05; - InstrumentEffect effects[4]; - //why do we even need to store a full path? - //only filename appears to be used. - char smpFullImportPath[193]; - uint32_t UNK06; - uint32_t UNK07; - uint32_t UNK08; - uint32_t UNK09; - uint32_t UNK0A; - uint32_t UNK0B; - uint32_t UNK0C; - uint32_t UNK0D; - uint32_t UNK0E; - uint32_t UNK0F; - uint32_t UNK10; - uint32_t UNK11; - int16_t UNK12; - int16_t shareSmpDataFromInstr; //0 is off - int16_t hasLoop; - int16_t hasBidiLoop; - uint32_t smpStartPoint; - uint32_t smpLoopPoint; - uint32_t smpEndPoint; - uint32_t hasSample; - uint32_t smpLength; - int16_t synthBuffers[SE_MAXCHANS][0x100]; -} Instrument; - -typedef struct -{ - uint8_t note; - uint8_t dest; - uint8_t instr; - int8_t spd; - uint8_t command; -} Row; - -typedef struct -{ - uint16_t patIndex; //0 means empty - uint16_t patLen; -} Order; - -typedef struct -{ - uint32_t UNK00[16]; - //UNK00 is used for something. No idea what. - //There is a sequence to the data in it. - //zeroing it out with hex editor doesn't seem to break stuff with Jaytrax - //it could as well be uninitialized memory - uint8_t mutedChans[SE_MAXCHANS]; - uint32_t tempo; - uint32_t groove; - uint32_t startPosCoarse; - uint32_t startPosFine; - uint32_t endPosCoarse; - uint32_t endPosFine; - uint32_t loopPosCoarse; - uint32_t loopPosFine; - int16_t isLooping; - char m_Name[33]; - int16_t channelNumber; - uint16_t delayTime; - uint8_t chanDelayAmt[SE_MAXCHANS]; - int16_t amplification; - int16_t UNK01; - int16_t UNK02; - int16_t UNK03; - int16_t UNK04; - int16_t UNK05; - int16_t UNK06; - //if my eyes don't deceive me, this actually happens - //waste of space - Order orders[SE_MAXCHANS][0x100]; -} Subsong; - -typedef struct -{ - uint16_t version; - uint16_t UNK00; - uint32_t patNum; - uint32_t subsongNum; - uint32_t instrNum; - uint32_t UNK01; - int16_t UNK02; - int16_t UNK03; - int16_t UNK04; - int16_t UNK05; - int16_t UNK06; - int16_t UNK07; - int16_t UNK08; - int16_t UNK09; - int16_t UNK0A; - int16_t UNK0B; - int16_t UNK0C; - int16_t UNK0D; - int16_t UNK0E; - int16_t UNK0F; - int16_t UNK10; - int16_t UNK11; -} SongHeader; - - -typedef struct -{ - SongHeader h; - int8_t arpTable[0x100]; - - Row *rows; - //we don't know what maximum pat name length should be - //in fact this is probably a buffer overflow target in Syntrax(app crashed on too long name, from UI); - uint32_t *patNameSizes; - char **patternNames; - Instrument *instruments; - Subsong *subsongs; - int16_t **samples; -} Song; - - -typedef struct Player -{ - int16_t *silentBuffer; - uint8_t m_LastNotes[SE_MAXCHANS]; - - uint32_t *freqTable; - int16_t *dynamorphTable; - - const Song *synSong; - TuneChannel *tuneChannels; - Voice *voices; - - int SAMPLEFREQUENCY; - - int samplesPerBeat; - int otherSamplesPerBeat; - int someCounter; - int channelNumber; - int sePmSong; - int16_t *overlapBuff; - int16_t *delayBufferR; - int16_t *delayBufferL; - - int bkpDelayPos; - int delayPos; - int gainPos; - int overlapPos; - - int ISWLKT; - int WDTECTE; - int PQV; - int AMVM; - int DONGS; - uint8_t posCoarse; - int AMYGPFQCHSW; - int posFine; - int8_t mutedChans[SE_MAXCHANS]; - - int selectedSubsong; - Subsong curSubsong; - - //local pointers to song structures - const Row *rows; - const char ** patternNames; - Instrument *instruments; - const Subsong *subsongs; - const int8_t *arpTable; - const int16_t **samples; - - uint bufflen; - - uint loopCount; -} Player; - - -//---------------------------prototypes------------------------ -#ifdef __cplusplus -extern "C" { -#endif - -Player * playerCreate(int sampleFrequency); -void playerDestroy(Player *); - -int loadSong(Player *, const Song *); -void initSubsong(Player *, int num); - -void mixChunk(Player *, int16_t *outBuff, uint playbackBufferSize); - -void playInstrument(Player *, int chanNum, int instrNum, int note); //could be handy dandy - -bool playerGetSongEnded(Player *); -uint playerGetLoopCount(Player *); - -typedef struct _stmi -{ - unsigned char coarse; - unsigned char fine; - unsigned char channelsPlaying; - const char *subsongName; - int selectedSubs; - int totalSubs; -} syntrax_info; - -void playerGetInfo(Player *, syntrax_info *); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/Frameworks/Syntrax-c/Syntrax_c.xcodeproj/project.pbxproj b/Frameworks/Syntrax-c/Syntrax_c.xcodeproj/project.pbxproj index 7ea88d9ff..e65153acf 100644 --- a/Frameworks/Syntrax-c/Syntrax_c.xcodeproj/project.pbxproj +++ b/Frameworks/Syntrax-c/Syntrax_c.xcodeproj/project.pbxproj @@ -7,23 +7,25 @@ objects = { /* Begin PBXBuildFile section */ - 83EEAB071C965247002761C5 /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = 83EEAB011C965247002761C5 /* file.c */; }; - 83EEAB081C965247002761C5 /* file.h in Headers */ = {isa = PBXBuildFile; fileRef = 83EEAB021C965247002761C5 /* file.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 83EEAB091C965247002761C5 /* resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 83EEAB031C965247002761C5 /* resampler.c */; }; - 83EEAB0A1C965247002761C5 /* resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 83EEAB041C965247002761C5 /* resampler.h */; }; - 83EEAB0B1C965247002761C5 /* syntrax.c in Sources */ = {isa = PBXBuildFile; fileRef = 83EEAB051C965247002761C5 /* syntrax.c */; }; - 83EEAB0C1C965247002761C5 /* syntrax.h in Headers */ = {isa = PBXBuildFile; fileRef = 83EEAB061C965247002761C5 /* syntrax.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8398BF3D2769D28A0048F38A /* jaytrax.c in Sources */ = {isa = PBXBuildFile; fileRef = 8398BF3C2769D26D0048F38A /* jaytrax.c */; }; + 8398BF3E2769D28D0048F38A /* jxs.c in Sources */ = {isa = PBXBuildFile; fileRef = 8398BF372769D26D0048F38A /* jxs.c */; }; + 8398BF3F2769D2950048F38A /* mixcore.c in Sources */ = {isa = PBXBuildFile; fileRef = 8398BF392769D26D0048F38A /* mixcore.c */; }; + 8398BF402769D2EE0048F38A /* mixcore.h in Headers */ = {isa = PBXBuildFile; fileRef = 8398BF362769D26D0048F38A /* mixcore.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 8398BF412769D2F50048F38A /* ioutil.h in Headers */ = {isa = PBXBuildFile; fileRef = 8398BF3A2769D26D0048F38A /* ioutil.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8398BF422769D2F80048F38A /* jaytrax.h in Headers */ = {isa = PBXBuildFile; fileRef = 8398BF382769D26D0048F38A /* jaytrax.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8398BF432769D2FD0048F38A /* jxs.h in Headers */ = {isa = PBXBuildFile; fileRef = 8398BF3B2769D26D0048F38A /* jxs.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 832FF31B1C96511E0076D662 /* Syntrax_c.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Syntrax_c.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 832FF3201C96511E0076D662 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 83EEAB011C965247002761C5 /* file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = file.c; sourceTree = ""; }; - 83EEAB021C965247002761C5 /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file.h; sourceTree = ""; }; - 83EEAB031C965247002761C5 /* resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resampler.c; sourceTree = ""; }; - 83EEAB041C965247002761C5 /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = ""; }; - 83EEAB051C965247002761C5 /* syntrax.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = syntrax.c; sourceTree = ""; }; - 83EEAB061C965247002761C5 /* syntrax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = syntrax.h; sourceTree = ""; }; + 8398BF362769D26D0048F38A /* mixcore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mixcore.h; sourceTree = ""; }; + 8398BF372769D26D0048F38A /* jxs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = jxs.c; sourceTree = ""; }; + 8398BF382769D26D0048F38A /* jaytrax.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = jaytrax.h; sourceTree = ""; }; + 8398BF392769D26D0048F38A /* mixcore.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mixcore.c; sourceTree = ""; }; + 8398BF3A2769D26D0048F38A /* ioutil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ioutil.h; sourceTree = ""; }; + 8398BF3B2769D26D0048F38A /* jxs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = jxs.h; sourceTree = ""; }; + 8398BF3C2769D26D0048F38A /* jaytrax.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = jaytrax.c; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -56,12 +58,13 @@ 832FF31D1C96511E0076D662 /* Syntrax-c */ = { isa = PBXGroup; children = ( - 83EEAB011C965247002761C5 /* file.c */, - 83EEAB021C965247002761C5 /* file.h */, - 83EEAB031C965247002761C5 /* resampler.c */, - 83EEAB041C965247002761C5 /* resampler.h */, - 83EEAB051C965247002761C5 /* syntrax.c */, - 83EEAB061C965247002761C5 /* syntrax.h */, + 8398BF3A2769D26D0048F38A /* ioutil.h */, + 8398BF3C2769D26D0048F38A /* jaytrax.c */, + 8398BF382769D26D0048F38A /* jaytrax.h */, + 8398BF372769D26D0048F38A /* jxs.c */, + 8398BF3B2769D26D0048F38A /* jxs.h */, + 8398BF392769D26D0048F38A /* mixcore.c */, + 8398BF362769D26D0048F38A /* mixcore.h */, 832FF3201C96511E0076D662 /* Info.plist */, ); path = "Syntrax-c"; @@ -74,9 +77,10 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 83EEAB0C1C965247002761C5 /* syntrax.h in Headers */, - 83EEAB081C965247002761C5 /* file.h in Headers */, - 83EEAB0A1C965247002761C5 /* resampler.h in Headers */, + 8398BF412769D2F50048F38A /* ioutil.h in Headers */, + 8398BF422769D2F80048F38A /* jaytrax.h in Headers */, + 8398BF432769D2FD0048F38A /* jxs.h in Headers */, + 8398BF402769D2EE0048F38A /* mixcore.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -149,9 +153,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 83EEAB071C965247002761C5 /* file.c in Sources */, - 83EEAB0B1C965247002761C5 /* syntrax.c in Sources */, - 83EEAB091C965247002761C5 /* resampler.c in Sources */, + 8398BF3D2769D28A0048F38A /* jaytrax.c in Sources */, + 8398BF3E2769D28D0048F38A /* jxs.c in Sources */, + 8398BF3F2769D2950048F38A /* mixcore.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Plugins/Syntrax/Syntrax/jxsContainer.m b/Plugins/Syntrax/Syntrax/jxsContainer.m index aaac18890..5092c59de 100755 --- a/Plugins/Syntrax/Syntrax/jxsContainer.m +++ b/Plugins/Syntrax/Syntrax/jxsContainer.m @@ -6,8 +6,8 @@ // Copyright 2016 __NoWork, Inc__. All rights reserved. // -#import -#import +#import +#import #import "jxsContainer.h" #import "jxsDecoder.h" @@ -54,8 +54,8 @@ void * data = malloc(size); [source read:data amount:size]; - Song * synSong = File_loadSongMem(data, size); - if (!synSong) + JT1Song * synSong; + if (jxsfile_readSongMem(data, size, &synSong)) { ALog(@"Open failed for file: %@", [url absoluteString]); free(data); @@ -64,33 +64,13 @@ free(data); - Player * synPlayer = playerCreate(44100); - if (!synPlayer) - { - ALog(@"Failed to create Syntrax-c player for file: %@", [url absoluteString]); - File_freeSong(synSong); - return nil; - } - - if (loadSong(synPlayer, synSong) < 0) - { - ALog(@"Load failed for file: %@", [url absoluteString]); - playerDestroy(synPlayer); - File_freeSong(synSong); - return nil; - } + int i; + int subsongs = synSong->nrofsongs; + jxsfile_freeSong(synSong); + NSMutableArray *tracks = [NSMutableArray array]; - syntrax_info info; - - playerGetInfo(synPlayer, &info); - - playerDestroy(synPlayer); - File_freeSong(synSong); - - int i; - int subsongs = info.totalSubs; if ( subsongs ) { for (i = 0; i < subsongs; i++) { diff --git a/Plugins/Syntrax/Syntrax/jxsDecoder.h b/Plugins/Syntrax/Syntrax/jxsDecoder.h index de98db2be..6141555a1 100755 --- a/Plugins/Syntrax/Syntrax/jxsDecoder.h +++ b/Plugins/Syntrax/Syntrax/jxsDecoder.h @@ -8,14 +8,14 @@ #import -#import -#import +#import +#import #import "Plugin.h" @interface jxsDecoder : NSObject { - Song *synSong; - Player *synPlayer; + JT1Song *synSong; + JT1Player *synPlayer; int track_num; long framesLength; diff --git a/Plugins/Syntrax/Syntrax/jxsDecoder.m b/Plugins/Syntrax/Syntrax/jxsDecoder.m index 2df92938b..9b517f2cf 100755 --- a/Plugins/Syntrax/Syntrax/jxsDecoder.m +++ b/Plugins/Syntrax/Syntrax/jxsDecoder.m @@ -14,50 +14,6 @@ @implementation jxsDecoder -BOOL probe_length( Song * synSong, unsigned long * intro_length, unsigned long * loop_length, unsigned int subsong ) -{ - Player * synPlayer = playerCreate(44100); - - if (loadSong(synPlayer, synSong) < 0) - return NO; - - initSubsong(synPlayer, subsong); - - unsigned long length_total = 0; - unsigned long length_saved; - - const long length_safety = 44100 * 60 * 30; - - while ( !playerGetSongEnded(synPlayer) && playerGetLoopCount(synPlayer) < 1 && length_total < length_safety ) - { - mixChunk(synPlayer, NULL, 512); - length_total += 512; - } - - if ( !playerGetSongEnded(synPlayer) && playerGetLoopCount(synPlayer) < 1 ) - { - *loop_length = 0; - *intro_length = 44100 * 60 * 3; - playerDestroy(synPlayer); - return YES; - } - - length_saved = length_total; - - while ( !playerGetSongEnded(synPlayer) && playerGetLoopCount(synPlayer) < 2 ) - { - mixChunk(synPlayer, NULL, 512); - length_total += 512; - } - - playerDestroy(synPlayer); - - *loop_length = length_total - length_saved; - *intro_length = length_saved - *loop_length; - - return YES; -} - - (id)init { self = [super init]; @@ -81,20 +37,23 @@ BOOL probe_length( Song * synSong, unsigned long * intro_length, unsigned long * track_num = 0; else track_num = [[[s url] fragment] intValue]; - - synSong = File_loadSongMem(data, size); - if (!synSong) + + if (jxsfile_readSongMem(data, size, &synSong)) return NO; free(data); - - unsigned long intro_length, loop_length; - - if ( !probe_length(synSong, &intro_length, &loop_length, track_num) ) + + synPlayer = jaytrax_init(); + if (!synPlayer) return NO; - framesLength = intro_length + loop_length * 2; - totalFrames = framesLength + 44100 * 8; + if (!jaytrax_loadSong(synPlayer, synSong)) + return NO; + + framesLength = jaytrax_getLength(synPlayer, track_num, 2, 44100); + totalFrames = framesLength + ((synPlayer->playFlg) ? 44100 * 8 : 0); + + framesRead = 0; [self willChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"]; @@ -104,14 +63,24 @@ BOOL probe_length( Song * synSong, unsigned long * intro_length, unsigned long * - (BOOL)decoderInitialize { - synPlayer = playerCreate(44100); - if (!synPlayer) - return NO; + jaytrax_changeSubsong(synPlayer, track_num); + + uint8_t interp = ITP_CUBIC; + NSString * resampling = [[NSUserDefaults standardUserDefaults] stringForKey:@"resampling"]; + if ([resampling isEqualToString:@"zoh"]) + interp = ITP_NEAREST; + else if ([resampling isEqualToString:@"blep"]) + interp = ITP_NEAREST; + else if ([resampling isEqualToString:@"linear"]) + interp = ITP_LINEAR; + else if ([resampling isEqualToString:@"blam"]) + interp = ITP_LINEAR; + else if ([resampling isEqualToString:@"cubic"]) + interp = ITP_CUBIC; + else if ([resampling isEqualToString:@"sinc"]) + interp = ITP_CUBIC; - if (loadSong(synPlayer, synSong) < 0) - return NO; - - initSubsong(synPlayer, track_num); + jaytrax_setInterpolation(synPlayer, interp); framesRead = 0; @@ -120,11 +89,12 @@ BOOL probe_length( Song * synSong, unsigned long * intro_length, unsigned long * - (void)decoderShutdown { - if ( synPlayer ) + if (synPlayer) { - playerDestroy(synPlayer); - synPlayer = NULL; + jaytrax_stopSong(synPlayer); } + + framesRead = 0; } - (NSDictionary *)properties @@ -146,18 +116,18 @@ BOOL probe_length( Song * synSong, unsigned long * intro_length, unsigned long * { BOOL repeat_one = IsRepeatOneSet(); - if ( synPlayer && playerGetSongEnded(synPlayer) ) - return 0; - if ( !repeat_one && framesRead >= totalFrames ) return 0; - if ( !synPlayer ) + if ( !framesRead ) { if ( ![self decoderInitialize] ) return 0; } + if ( synPlayer && !synPlayer->playFlg ) + return 0; + int total = 0; while ( total < frames ) { int framesToRender = 512; @@ -168,7 +138,7 @@ BOOL probe_length( Song * synSong, unsigned long * intro_length, unsigned long * int16_t * sampleBuf = ( int16_t * ) buf + total * 2; - mixChunk(synPlayer, sampleBuf, framesToRender); + jaytrax_renderChunk(synPlayer, sampleBuf, framesToRender, 44100); if ( !repeat_one && framesRead + framesToRender > framesLength ) { long fadeStart = ( framesLength > framesRead ) ? framesLength : framesRead; @@ -190,8 +160,8 @@ BOOL probe_length( Song * synSong, unsigned long * intro_length, unsigned long * total += framesToRender; framesRead += framesToRender; - - if ( playerGetSongEnded(synPlayer) ) + + if ( !synPlayer->playFlg ) break; } @@ -212,7 +182,7 @@ BOOL probe_length( Song * synSong, unsigned long * intro_length, unsigned long * int frames_todo = INT_MAX; if ( frames_todo > frame - framesRead ) frames_todo = (int)( frame - framesRead ); - mixChunk(synPlayer, NULL, frames_todo); + jaytrax_renderChunk(synPlayer, NULL, frames_todo, 44100); framesRead += frames_todo; } @@ -224,10 +194,16 @@ BOOL probe_length( Song * synSong, unsigned long * intro_length, unsigned long * - (void)close { [self decoderShutdown]; + + if (synPlayer) + { + jaytrax_free(synPlayer); + synPlayer = NULL; + } if (synSong) { - File_freeSong(synSong); + jxsfile_freeSong(synSong); synSong = NULL; } } diff --git a/Plugins/Syntrax/Syntrax/jxsMetadataReader.m b/Plugins/Syntrax/Syntrax/jxsMetadataReader.m index 219487ef7..e5ece459a 100644 --- a/Plugins/Syntrax/Syntrax/jxsMetadataReader.m +++ b/Plugins/Syntrax/Syntrax/jxsMetadataReader.m @@ -9,8 +9,8 @@ #import "jxsMetadataReader.h" #import "jxsDecoder.h" -#import -#import +#import +#import #import "Logging.h" @@ -49,8 +49,8 @@ void * data = malloc(size); [source read:data amount:size]; - Song * synSong = File_loadSongMem(data, size); - if (!synSong) + JT1Song* synSong; + if (jxsfile_readSongMem(data, size, &synSong)) { ALog(@"Open failed for file: %@", [url absoluteString]); free(data); @@ -59,19 +59,19 @@ free(data); - Player * synPlayer = playerCreate(44100); + JT1Player * synPlayer = jaytrax_init(); if (!synPlayer) { ALog(@"Failed to create player for file: %@", [url absoluteString]); - File_freeSong(synSong); + jxsfile_freeSong(synSong); return nil; } - if (loadSong(synPlayer, synSong) < 0) + if (!jaytrax_loadSong(synPlayer, synSong)) { ALog(@"Load failed for file: %@", [url absoluteString]); - playerDestroy(synPlayer); - File_freeSong(synSong); + jaytrax_free(synPlayer); + jxsfile_freeSong(synSong); return nil; } @@ -81,16 +81,13 @@ else track_num = [[url fragment] intValue]; - initSubsong(synPlayer, track_num); - - syntrax_info info; - playerGetInfo(synPlayer, &info); - - playerDestroy(synPlayer); - File_freeSong(synSong); + jaytrax_changeSubsong(synPlayer, track_num); //Some titles are all spaces?! - NSString *title = [[NSString stringWithUTF8String: info.subsongName] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + NSString *title = [[NSString stringWithUTF8String: synPlayer->subsong->name] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + + jaytrax_free(synPlayer); + jxsfile_freeSong(synSong); if (title == nil) { title = @"";