XM import: all the code
This commit is contained in:
		
							parent
							
								
									ec4131a872
								
							
						
					
					
						commit
						36e6899eff
					
				| 
						 | 
					@ -24,11 +24,28 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
 | 
				
			||||||
  bool success=false;
 | 
					  bool success=false;
 | 
				
			||||||
  char magic[32];
 | 
					  char magic[32];
 | 
				
			||||||
  unsigned char sampleVol[256][256];
 | 
					  unsigned char sampleVol[256][256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unsigned short patLen[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool doesPitchSlide[128];
 | 
				
			||||||
 | 
					  bool doesVibrato[128];
 | 
				
			||||||
 | 
					  bool doesPanning[128];
 | 
				
			||||||
 | 
					  bool doesVolSlide[128];
 | 
				
			||||||
 | 
					  bool doesArp[128];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SafeReader reader=SafeReader(file,len);
 | 
					  SafeReader reader=SafeReader(file,len);
 | 
				
			||||||
  warnings="";
 | 
					  warnings="";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  memset(sampleVol,0,256*256);
 | 
					  memset(sampleVol,0,256*256);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  memset(patLen,0,256*sizeof(unsigned short));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  memset(doesPitchSlide,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					  memset(doesVibrato,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					  memset(doesPanning,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					  memset(doesVolSlide,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					  memset(doesArp,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    DivSong ds;
 | 
					    DivSong ds;
 | 
				
			||||||
    ds.version=DIV_VERSION_XM;
 | 
					    ds.version=DIV_VERSION_XM;
 | 
				
			||||||
| 
						 | 
					@ -81,6 +98,13 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
 | 
				
			||||||
    double bpm=(unsigned short)reader.readS();
 | 
					    double bpm=(unsigned short)reader.readS();
 | 
				
			||||||
    ds.subsong[0]->hz=(double)bpm/2.5;
 | 
					    ds.subsong[0]->hz=(double)bpm/2.5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ds.insLen<0 || ds.insLen>256) {
 | 
				
			||||||
 | 
					      logE("invalid instrument count!");
 | 
				
			||||||
 | 
					      lastError="invalid instrument count";
 | 
				
			||||||
 | 
					      delete[] file;
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    logV("channels: %d",totalChans);
 | 
					    logV("channels: %d",totalChans);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (totalChans>127) {
 | 
					    if (totalChans>127) {
 | 
				
			||||||
| 
						 | 
					@ -107,17 +131,18 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ds.systemLen=(totalChans+31)>>5;
 | 
					    ds.systemLen=(totalChans+31)>>5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    logV("seeking to %x...",headerSeek);
 | 
					    size_t patBegin=headerSeek;
 | 
				
			||||||
 | 
					    logV("seeking to %x...",patBegin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!reader.seek(headerSeek,SEEK_SET)) {
 | 
					    if (!reader.seek(patBegin,SEEK_SET)) {
 | 
				
			||||||
      logE("premature end of file!");
 | 
					      logE("premature end of file!");
 | 
				
			||||||
      lastError="incomplete file";
 | 
					      lastError="incomplete file";
 | 
				
			||||||
      delete[] file;
 | 
					      delete[] file;
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // read patterns
 | 
					    // scan pattern data for effect use
 | 
				
			||||||
    logD("reading patterns...");
 | 
					    logD("scanning patterns...");
 | 
				
			||||||
    for (unsigned short i=0; i<patCount; i++) {
 | 
					    for (unsigned short i=0; i<patCount; i++) {
 | 
				
			||||||
      logV("pattern %d",i);
 | 
					      logV("pattern %d",i);
 | 
				
			||||||
      headerSeek=reader.tell();
 | 
					      headerSeek=reader.tell();
 | 
				
			||||||
| 
						 | 
					@ -135,6 +160,238 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
 | 
				
			||||||
      unsigned short totalRows=reader.readS();
 | 
					      unsigned short totalRows=reader.readS();
 | 
				
			||||||
      logV("total rows: %d",totalRows);
 | 
					      logV("total rows: %d",totalRows);
 | 
				
			||||||
      if (totalRows>ds.subsong[0]->patLen) ds.subsong[0]->patLen=totalRows;
 | 
					      if (totalRows>ds.subsong[0]->patLen) ds.subsong[0]->patLen=totalRows;
 | 
				
			||||||
 | 
					      patLen[i]=totalRows;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (totalRows>256) {
 | 
				
			||||||
 | 
					        logE("too many rows! %d",totalRows);
 | 
				
			||||||
 | 
					        lastError="too many rows";
 | 
				
			||||||
 | 
					        delete[] file;
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      unsigned int packedSeek=headerSeek+(unsigned short)reader.readS();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      logV("seeking to %x...",headerSeek);
 | 
				
			||||||
 | 
					      if (!reader.seek(headerSeek,SEEK_SET)) {
 | 
				
			||||||
 | 
					        logE("premature end of file!");
 | 
				
			||||||
 | 
					        lastError="incomplete file";
 | 
				
			||||||
 | 
					        delete[] file;
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // read data
 | 
				
			||||||
 | 
					      for (int j=0; j<totalRows; j++) {
 | 
				
			||||||
 | 
					        for (int k=0; k<totalChans; k++) {
 | 
				
			||||||
 | 
					          unsigned char note=reader.readC();
 | 
				
			||||||
 | 
					          unsigned char vol=0;
 | 
				
			||||||
 | 
					          unsigned char effect=0;
 | 
				
			||||||
 | 
					          unsigned char effectVal=0;
 | 
				
			||||||
 | 
					          bool hasNote=false;
 | 
				
			||||||
 | 
					          bool hasIns=false;
 | 
				
			||||||
 | 
					          bool hasVol=false;
 | 
				
			||||||
 | 
					          bool hasEffect=false;
 | 
				
			||||||
 | 
					          bool hasEffectVal=false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (note&0x80) { // packed
 | 
				
			||||||
 | 
					            hasNote=note&1;
 | 
				
			||||||
 | 
					            hasIns=note&2;
 | 
				
			||||||
 | 
					            hasVol=note&4;
 | 
				
			||||||
 | 
					            hasEffect=note&8;
 | 
				
			||||||
 | 
					            hasEffectVal=note&16;
 | 
				
			||||||
 | 
					            if (hasNote) {
 | 
				
			||||||
 | 
					              note=reader.readC();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          } else { // unpacked
 | 
				
			||||||
 | 
					            hasNote=true;
 | 
				
			||||||
 | 
					            hasIns=true;
 | 
				
			||||||
 | 
					            hasVol=true;
 | 
				
			||||||
 | 
					            hasEffect=true;
 | 
				
			||||||
 | 
					            hasEffectVal=true;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (hasIns) {
 | 
				
			||||||
 | 
					            reader.readC();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (hasVol) {
 | 
				
			||||||
 | 
					            vol=reader.readC();
 | 
				
			||||||
 | 
					            switch (vol>>4) {
 | 
				
			||||||
 | 
					              case 0x6: // vol slide down
 | 
				
			||||||
 | 
					                doesVolSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x7: // vol slide up
 | 
				
			||||||
 | 
					                doesVolSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x8: // vol slide down (fine)
 | 
				
			||||||
 | 
					                doesVolSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x9: // vol slide up (fine)
 | 
				
			||||||
 | 
					                doesVolSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xa: // vibrato speed
 | 
				
			||||||
 | 
					                doesVibrato[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xb: // vibrato depth
 | 
				
			||||||
 | 
					                doesVibrato[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xc: // panning
 | 
				
			||||||
 | 
					                doesPanning[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xd: // pan slide left
 | 
				
			||||||
 | 
					                doesPanning[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xe: // pan slide right
 | 
				
			||||||
 | 
					                doesPanning[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xf: // porta
 | 
				
			||||||
 | 
					                doesPitchSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (hasEffect) {
 | 
				
			||||||
 | 
					            effect=reader.readC();
 | 
				
			||||||
 | 
					            switch (effect) {
 | 
				
			||||||
 | 
					              case 0:
 | 
				
			||||||
 | 
					                doesArp[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 1:
 | 
				
			||||||
 | 
					                doesPitchSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 2:
 | 
				
			||||||
 | 
					                doesPitchSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 3:
 | 
				
			||||||
 | 
					                doesPitchSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 4:
 | 
				
			||||||
 | 
					                doesVibrato[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 5:
 | 
				
			||||||
 | 
					                doesPitchSlide[k]=true;
 | 
				
			||||||
 | 
					                doesVolSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 6:
 | 
				
			||||||
 | 
					                doesVibrato[k]=true;
 | 
				
			||||||
 | 
					                doesVolSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 8:
 | 
				
			||||||
 | 
					                doesPanning[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xe:
 | 
				
			||||||
 | 
					                doesPanning[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x19: // P
 | 
				
			||||||
 | 
					                doesPanning[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x21: // X
 | 
				
			||||||
 | 
					                doesPitchSlide[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (hasEffectVal) {
 | 
				
			||||||
 | 
					            effectVal=reader.readC();
 | 
				
			||||||
 | 
					            if (effect==0xe) {
 | 
				
			||||||
 | 
					              switch (effectVal>>4) {
 | 
				
			||||||
 | 
					                case 1:
 | 
				
			||||||
 | 
					                  doesPitchSlide[k]=true;
 | 
				
			||||||
 | 
					                  break;
 | 
				
			||||||
 | 
					                case 2:
 | 
				
			||||||
 | 
					                  doesPitchSlide[k]=true;
 | 
				
			||||||
 | 
					                  break;
 | 
				
			||||||
 | 
					                case 0xa:
 | 
				
			||||||
 | 
					                  doesVolSlide[k]=true;
 | 
				
			||||||
 | 
					                  break;
 | 
				
			||||||
 | 
					                case 0xb:
 | 
				
			||||||
 | 
					                  doesVolSlide[k]=true;
 | 
				
			||||||
 | 
					                  break;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      logV("seeking to %x...",packedSeek);
 | 
				
			||||||
 | 
					      if (!reader.seek(packedSeek,SEEK_SET)) {
 | 
				
			||||||
 | 
					        logE("premature end of file!");
 | 
				
			||||||
 | 
					        lastError="incomplete file";
 | 
				
			||||||
 | 
					        delete[] file;
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!reader.seek(patBegin,SEEK_SET)) {
 | 
				
			||||||
 | 
					      logE("premature end of file!");
 | 
				
			||||||
 | 
					      lastError="incomplete file";
 | 
				
			||||||
 | 
					      delete[] file;
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // read patterns
 | 
				
			||||||
 | 
					    logD("reading patterns...");
 | 
				
			||||||
 | 
					    for (unsigned short i=0; i<patCount; i++) {
 | 
				
			||||||
 | 
					      unsigned char effectCol[128];
 | 
				
			||||||
 | 
					      unsigned char vibStatus[128];
 | 
				
			||||||
 | 
					      bool vibStatusChanged[128];
 | 
				
			||||||
 | 
					      bool vibing[128];
 | 
				
			||||||
 | 
					      bool vibingOld[128];
 | 
				
			||||||
 | 
					      unsigned char volSlideStatus[128];
 | 
				
			||||||
 | 
					      bool volSlideStatusChanged[128];
 | 
				
			||||||
 | 
					      bool volSliding[128];
 | 
				
			||||||
 | 
					      bool volSlidingOld[128];
 | 
				
			||||||
 | 
					      unsigned char portaStatus[128];
 | 
				
			||||||
 | 
					      bool portaStatusChanged[128];
 | 
				
			||||||
 | 
					      bool porting[128];
 | 
				
			||||||
 | 
					      bool portingOld[128];
 | 
				
			||||||
 | 
					      unsigned char portaType[128];
 | 
				
			||||||
 | 
					      unsigned char arpStatus[128];
 | 
				
			||||||
 | 
					      bool arpStatusChanged[128];
 | 
				
			||||||
 | 
					      bool arping[128];
 | 
				
			||||||
 | 
					      bool arpingOld[128];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      bool mustCommitInitial=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      memset(effectCol,4,128);
 | 
				
			||||||
 | 
					      memset(vibStatus,0,128);
 | 
				
			||||||
 | 
					      memset(vibStatusChanged,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(vibing,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(vibingOld,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(volSlideStatus,0,128);
 | 
				
			||||||
 | 
					      memset(volSlideStatusChanged,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(volSliding,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(volSlidingOld,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(portaStatus,0,128);
 | 
				
			||||||
 | 
					      memset(portaStatusChanged,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(porting,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(portingOld,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(portaType,0,128);
 | 
				
			||||||
 | 
					      memset(arpStatus,0,128);
 | 
				
			||||||
 | 
					      memset(arpStatusChanged,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(arping,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					      memset(arpingOld,0,128*sizeof(bool));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      logV("pattern %d",i);
 | 
				
			||||||
 | 
					      headerSeek=reader.tell();
 | 
				
			||||||
 | 
					      headerSeek+=reader.readI();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      unsigned char packType=reader.readC();
 | 
				
			||||||
 | 
					      if (packType!=0) {
 | 
				
			||||||
 | 
					        logE("unknown packing type %d!",packType);
 | 
				
			||||||
 | 
					        lastError="unknown packing type";
 | 
				
			||||||
 | 
					        ds.unload();
 | 
				
			||||||
 | 
					        delete[] file;
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      unsigned short totalRows=reader.readS();
 | 
				
			||||||
 | 
					      logV("total rows: %d",totalRows);
 | 
				
			||||||
 | 
					      if (totalRows>ds.subsong[0]->patLen) ds.subsong[0]->patLen=totalRows;
 | 
				
			||||||
 | 
					      patLen[i]=totalRows;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (totalRows>256) {
 | 
				
			||||||
 | 
					        logE("too many rows! %d",totalRows);
 | 
				
			||||||
 | 
					        lastError="too many rows";
 | 
				
			||||||
 | 
					        delete[] file;
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      unsigned int packedSeek=headerSeek+(unsigned short)reader.readS();
 | 
					      unsigned int packedSeek=headerSeek+(unsigned short)reader.readS();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -198,15 +455,240 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          if (hasVol) {
 | 
					          if (hasVol) {
 | 
				
			||||||
            vol=reader.readC();
 | 
					            vol=reader.readC();
 | 
				
			||||||
            p->data[j][3]=vol;
 | 
					            if (vol>=0x10 && vol<=0x50) {
 | 
				
			||||||
 | 
					              p->data[j][3]=vol-0x10;
 | 
				
			||||||
 | 
					            } else { // effects in volume column
 | 
				
			||||||
 | 
					              // TODO
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (vol==0) {
 | 
				
			||||||
 | 
					            if (hasNote && hasIns && note<96 && ins>0) {
 | 
				
			||||||
 | 
					              // TODO: default volume
 | 
				
			||||||
 | 
					              p->data[j][3]=0x40;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          if (hasEffect) {
 | 
					          if (hasEffect) {
 | 
				
			||||||
            effect=reader.readC();
 | 
					            effect=reader.readC();
 | 
				
			||||||
            p->data[j][4]=effect;
 | 
					 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          if (hasEffectVal) {
 | 
					          if (hasEffectVal) {
 | 
				
			||||||
            effectVal=reader.readC();
 | 
					            effectVal=reader.readC();
 | 
				
			||||||
            p->data[j][5]=effectVal;
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (hasEffect) {
 | 
				
			||||||
 | 
					            switch (effect) {
 | 
				
			||||||
 | 
					              case 0: // arp
 | 
				
			||||||
 | 
					                if (effectVal!=0) {
 | 
				
			||||||
 | 
					                  arpStatus[k]=effectVal;
 | 
				
			||||||
 | 
					                  arpStatusChanged[k]=true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                arping[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 1: // pitch up
 | 
				
			||||||
 | 
					                if (effectVal!=0) {
 | 
				
			||||||
 | 
					                  portaStatus[k]=effectVal;
 | 
				
			||||||
 | 
					                  portaStatusChanged[k]=true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                portaType[k]=1;
 | 
				
			||||||
 | 
					                porting[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 2: // pitch down
 | 
				
			||||||
 | 
					                if (effectVal!=0) {
 | 
				
			||||||
 | 
					                  portaStatus[k]=effectVal;
 | 
				
			||||||
 | 
					                  portaStatusChanged[k]=true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                portaType[k]=2;
 | 
				
			||||||
 | 
					                porting[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 3: // porta
 | 
				
			||||||
 | 
					                if (effectVal!=0) {
 | 
				
			||||||
 | 
					                  portaStatus[k]=effectVal;
 | 
				
			||||||
 | 
					                  portaStatusChanged[k]=true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                portaType[k]=3;
 | 
				
			||||||
 | 
					                porting[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 4: // vibrato
 | 
				
			||||||
 | 
					                if (effectVal!=0) {
 | 
				
			||||||
 | 
					                  vibStatus[k]=effectVal;
 | 
				
			||||||
 | 
					                  vibStatusChanged[k]=true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                vibing[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 5: // vol slide + porta
 | 
				
			||||||
 | 
					                if (effectVal!=0) {
 | 
				
			||||||
 | 
					                  volSlideStatus[k]=effectVal;
 | 
				
			||||||
 | 
					                  volSlideStatusChanged[k]=true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                volSliding[k]=true;
 | 
				
			||||||
 | 
					                porting[k]=true;
 | 
				
			||||||
 | 
					                portaType[k]=3;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 6: // vol slide + vibrato
 | 
				
			||||||
 | 
					                if (effectVal!=0) {
 | 
				
			||||||
 | 
					                  volSlideStatus[k]=effectVal;
 | 
				
			||||||
 | 
					                  volSlideStatusChanged[k]=true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                volSliding[k]=true;
 | 
				
			||||||
 | 
					                vibing[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 7: // tremolo
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 8: // panning
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=0x80;
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=effectVal;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 9: // offset
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=0x91;
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=effectVal;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xa: // vol slide
 | 
				
			||||||
 | 
					                if (effectVal!=0) {
 | 
				
			||||||
 | 
					                  volSlideStatus[k]=effectVal;
 | 
				
			||||||
 | 
					                  volSlideStatusChanged[k]=true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (hasIns) {
 | 
				
			||||||
 | 
					                  volSlideStatusChanged[k]=true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                volSliding[k]=true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xb: // go to order
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=0x0b;
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=effectVal;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xc: // set volume
 | 
				
			||||||
 | 
					                p->data[j][3]=effectVal;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xd: // next order
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=0x0d;
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=effectVal;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xe: // special...
 | 
				
			||||||
 | 
					                // TODO: implement the rest
 | 
				
			||||||
 | 
					                switch (effectVal>>4) {
 | 
				
			||||||
 | 
					                  case 0xc:
 | 
				
			||||||
 | 
					                    p->data[j][effectCol[k]++]=0xec;
 | 
				
			||||||
 | 
					                    p->data[j][effectCol[k]++]=effectVal&15;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                  case 0xd:
 | 
				
			||||||
 | 
					                    p->data[j][effectCol[k]++]=0xed;
 | 
				
			||||||
 | 
					                    p->data[j][effectCol[k]++]=effectVal&15;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x10: // G: global volume (!)
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0xf: // speed/tempp
 | 
				
			||||||
 | 
					                if (effectVal>=0x20) {
 | 
				
			||||||
 | 
					                  p->data[j][effectCol[k]++]=0xf0;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                  p->data[j][effectCol[k]++]=0x0f;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=effectVal;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x11: // H: global volume slide (!)
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x14: // K: key off
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=0xe7;
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=effectVal;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x15: // L: set envelope position (!)
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x19: // P: pan slide
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x1b: // R: retrigger
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=0x0c;
 | 
				
			||||||
 | 
					                p->data[j][effectCol[k]++]=effectVal;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x1d: // T: tremor (!)
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 0x21: // X: extra fine volume
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // commit effects
 | 
				
			||||||
 | 
					        for (int k=0; k<totalChans; k++) {
 | 
				
			||||||
 | 
					          DivPattern* p=ds.subsong[0]->pat[k].getPattern(i,true);
 | 
				
			||||||
 | 
					          if (vibing[k]!=vibingOld[k] || vibStatusChanged[k]) {
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0x04;
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=vibing[k]?vibStatus[k]:0;
 | 
				
			||||||
 | 
					            doesVibrato[k]=true;
 | 
				
			||||||
 | 
					          } else if (doesVibrato[k] && mustCommitInitial) {
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0x04;
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (volSliding[k]!=volSlidingOld[k] || volSlideStatusChanged[k]) {
 | 
				
			||||||
 | 
					            if (volSlideStatus[k]>=0xf1 && volSliding[k]) {
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=0xf9;
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=volSlideStatus[k]&15;
 | 
				
			||||||
 | 
					              volSliding[k]=false;
 | 
				
			||||||
 | 
					            } else if ((volSlideStatus[k]&15)==15 && volSlideStatus[k]>=0x10 && volSliding[k]) {
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=0xf8;
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=volSlideStatus[k]>>4;
 | 
				
			||||||
 | 
					              volSliding[k]=false;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=0xfa;
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=volSliding[k]?volSlideStatus[k]:0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            doesVolSlide[k]=true;
 | 
				
			||||||
 | 
					          } else if (doesVolSlide[k] && mustCommitInitial) {
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0xfa;
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (porting[k]!=portingOld[k] || portaStatusChanged[k]) {
 | 
				
			||||||
 | 
					            if (portaStatus[k]>=0xe0 && portaType[k]!=3 && porting[k]) {
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=portaType[k]|0xf0;
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=(portaStatus[k]&15)*((portaStatus[k]>=0xf0)?1:1);
 | 
				
			||||||
 | 
					              porting[k]=false;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=portaType[k];
 | 
				
			||||||
 | 
					              p->data[j][effectCol[k]++]=porting[k]?portaStatus[k]:0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            doesPitchSlide[k]=true;
 | 
				
			||||||
 | 
					          } else if (doesPitchSlide[k] && mustCommitInitial) {
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0x01;
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (arping[k]!=arpingOld[k] || arpStatusChanged[k]) {
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0x00;
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=arping[k]?arpStatus[k]:0;
 | 
				
			||||||
 | 
					            doesArp[k]=true;
 | 
				
			||||||
 | 
					          } else if (doesArp[k] && mustCommitInitial) {
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0x00;
 | 
				
			||||||
 | 
					            p->data[j][effectCol[k]++]=0;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if ((effectCol[k]>>1)-2>ds.subsong[0]->pat[k].effectCols) {
 | 
				
			||||||
 | 
					            ds.subsong[0]->pat[k].effectCols=(effectCol[k]>>1)-1;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        memset(effectCol,4,64);
 | 
				
			||||||
 | 
					        memcpy(vibingOld,vibing,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memcpy(volSlidingOld,volSliding,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memcpy(portingOld,porting,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memcpy(arpingOld,arping,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memset(vibStatusChanged,0,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memset(volSlideStatusChanged,0,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memset(portaStatusChanged,0,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memset(arpStatusChanged,0,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memset(vibing,0,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memset(volSliding,0,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memset(porting,0,64*sizeof(bool));
 | 
				
			||||||
 | 
					        memset(arping,0,64*sizeof(bool));
 | 
				
			||||||
 | 
					        mustCommitInitial=false;
 | 
				
			||||||
 | 
					        if (j==totalRows-1) {
 | 
				
			||||||
 | 
					          // place end of pattern marker
 | 
				
			||||||
 | 
					          DivPattern* p=ds.subsong[0]->pat[0].getPattern(i,true);
 | 
				
			||||||
 | 
					          p->data[j][effectCol[0]++]=0x0d;
 | 
				
			||||||
 | 
					          p->data[j][effectCol[0]++]=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if ((effectCol[0]>>1)-2>ds.subsong[0]->pat[0].effectCols) {
 | 
				
			||||||
 | 
					            ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)-1;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -233,7 +715,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
 | 
				
			||||||
      logV("the freaking thing ends at %x",headerSeek);
 | 
					      logV("the freaking thing ends at %x",headerSeek);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ins->name=reader.readStringLatin1(22);
 | 
					      ins->name=reader.readStringLatin1(22);
 | 
				
			||||||
      ins->type=DIV_INS_AMIGA;
 | 
					      ins->type=DIV_INS_ES5506;
 | 
				
			||||||
      ins->amiga.useNoteMap=true;
 | 
					      ins->amiga.useNoteMap=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      unsigned char insType=reader.readC();
 | 
					      unsigned char insType=reader.readC();
 | 
				
			||||||
| 
						 | 
					@ -397,6 +879,13 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ds.sampleLen=ds.sample.size();
 | 
					    ds.sampleLen=ds.sample.size();
 | 
				
			||||||
 | 
					    if (ds.sampleLen>256) {
 | 
				
			||||||
 | 
					      logE("too many samples!");
 | 
				
			||||||
 | 
					      lastError="too many samples";
 | 
				
			||||||
 | 
					      ds.unload();
 | 
				
			||||||
 | 
					      delete[] file;
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // find subsongs
 | 
					    // find subsongs
 | 
				
			||||||
    ds.findSubSongs(totalChans);
 | 
					    ds.findSubSongs(totalChans);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue