beta 1-3 .dmf loading
i did it
This commit is contained in:
		
							parent
							
								
									9e0e725802
								
							
						
					
					
						commit
						8a49522e59
					
				|  | @ -53,6 +53,10 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|   warnings=""; | ||||
|   try { | ||||
|     DivSong ds; | ||||
|     unsigned char historicColIns[DIV_MAX_CHANS]; | ||||
|     for (int i=0; i<DIV_MAX_CHANS; i++) { | ||||
|       historicColIns[i]=i; | ||||
|     } | ||||
| 
 | ||||
|     ds.nullWave.len=32; | ||||
|     for (int i=0; i<32; i++) { | ||||
|  | @ -172,7 +176,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
| 
 | ||||
|     ds.timeBase=reader.readC(); | ||||
|     ds.speed1=reader.readC(); | ||||
|     if (ds.version>0x03) { | ||||
|     if (ds.version>0x05) { | ||||
|       ds.speed2=reader.readC(); | ||||
|       ds.pal=reader.readC(); | ||||
|       ds.hz=(ds.pal)?60:50; | ||||
|  | @ -258,7 +262,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|       addWarning("Yamaha YMU759 emulation is incomplete! please migrate your song to the OPL3 system."); | ||||
|     } | ||||
| 
 | ||||
|     logI("reading pattern matrix (%d)...",ds.ordersLen); | ||||
|     logV("%x",reader.tell()); | ||||
| 
 | ||||
|     logI("reading pattern matrix (%d * %d = %d)...",ds.ordersLen,getChannelCount(ds.system[0]),ds.ordersLen*getChannelCount(ds.system[0])); | ||||
|     for (int i=0; i<getChannelCount(ds.system[0]); i++) { | ||||
|       for (int j=0; j<ds.ordersLen; j++) { | ||||
|         ds.orders.ord[i][j]=reader.readC(); | ||||
|  | @ -272,9 +278,14 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|           ds.pat[i].getPattern(j,true)->name=reader.readString((unsigned char)reader.readC()); | ||||
|         } | ||||
|       } | ||||
|       if (ds.version>0x03 && ds.version<0x06 && i<16) { | ||||
|         historicColIns[i]=reader.readC(); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (ds.version>0x03) { | ||||
|     logV("%x",reader.tell()); | ||||
| 
 | ||||
|     if (ds.version>0x05) { | ||||
|       ds.insLen=(unsigned char)reader.readC(); | ||||
|     } else { | ||||
|       ds.insLen=16; | ||||
|  | @ -282,7 +293,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|     logI("reading instruments (%d)...",ds.insLen); | ||||
|     for (int i=0; i<ds.insLen; i++) { | ||||
|       DivInstrument* ins=new DivInstrument; | ||||
|       if (ds.version>0x03) { | ||||
|       if (ds.version>0x05) { | ||||
|         ins->name=reader.readString((unsigned char)reader.readC()); | ||||
|       } | ||||
|       logD("%d name: %s",i,ins->name.c_str()); | ||||
|  | @ -319,29 +330,41 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|       } | ||||
| 
 | ||||
|       if (ins->mode) { // FM
 | ||||
|         ins->fm.alg=reader.readC(); | ||||
|         if (ds.version<0x13) { | ||||
|           reader.readC(); | ||||
|         } | ||||
|         ins->fm.fb=reader.readC(); | ||||
|         if (ds.version<0x13) { | ||||
|           reader.readC(); | ||||
|         } | ||||
|         ins->fm.fms=reader.readC(); | ||||
|         if (ds.version<0x13) { | ||||
|           reader.readC(); | ||||
|           ins->fm.ops=2+reader.readC()*2; | ||||
|           if (ds.system[0]!=DIV_SYSTEM_YMU759) ins->fm.ops=4; | ||||
|         if (ds.version>0x05) { | ||||
|           ins->fm.alg=reader.readC(); | ||||
|           if (ds.version<0x13) { | ||||
|             reader.readC(); | ||||
|           } | ||||
|           ins->fm.fb=reader.readC(); | ||||
|           if (ds.version<0x13) { | ||||
|             reader.readC(); | ||||
|           } | ||||
|           ins->fm.fms=reader.readC(); | ||||
|           if (ds.version<0x13) { | ||||
|             reader.readC(); | ||||
|             ins->fm.ops=2+reader.readC()*2; | ||||
|             if (ds.system[0]!=DIV_SYSTEM_YMU759) ins->fm.ops=4; | ||||
|           } else { | ||||
|             ins->fm.ops=4; | ||||
|           } | ||||
|           ins->fm.ams=reader.readC(); | ||||
|         } else { | ||||
|           ins->fm.ops=4; | ||||
|           ins->fm.alg=reader.readC(); | ||||
|           reader.readC(); | ||||
|           ins->fm.fb=reader.readC(); | ||||
|           reader.readC(); // apparently an index of sorts starting from 0x59?
 | ||||
|           ins->fm.fms=reader.readC(); | ||||
|           reader.readC(); // 0x59+index?
 | ||||
|           ins->fm.ops=2+reader.readC()*2; | ||||
|         } | ||||
| 
 | ||||
|         logD("ALG %d FB %d FMS %d AMS %d OPS %d",ins->fm.alg,ins->fm.fb,ins->fm.fms,ins->fm.ams,ins->fm.ops); | ||||
|         if (ins->fm.ops!=2 && ins->fm.ops!=4) { | ||||
|           logE("invalid op count %d. did we read it wrong?",ins->fm.ops); | ||||
|           lastError="file is corrupt or unreadable at operators"; | ||||
|           delete[] file; | ||||
|           return false; | ||||
|         } | ||||
|         ins->fm.ams=reader.readC(); | ||||
| 
 | ||||
|         for (int j=0; j<ins->fm.ops; j++) { | ||||
|           ins->fm.op[j].am=reader.readC(); | ||||
|  | @ -385,7 +408,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|               ins->fm.op[j].dt2=reader.readC(); | ||||
|             } | ||||
|           } | ||||
|           if (ds.version>0x03) { | ||||
|           if (ds.version>0x05) { | ||||
|             if (ds.system[0]==DIV_SYSTEM_SMS_OPLL || ds.system[0]==DIV_SYSTEM_NES_VRC7) { | ||||
|               ins->fm.op[j].ksr=reader.readC(); | ||||
|               ins->fm.op[j].vib=reader.readC(); | ||||
|  | @ -588,6 +611,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|       } | ||||
|     } | ||||
| 
 | ||||
|     logV("%x",reader.tell()); | ||||
| 
 | ||||
|     logI("reading patterns (%d channels, %d orders)...",getChannelCount(ds.system[0]),ds.ordersLen); | ||||
|     for (int i=0; i<getChannelCount(ds.system[0]); i++) { | ||||
|       DivChannelData& chan=ds.pat[i]; | ||||
|  | @ -595,7 +620,6 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|         chan.effectRows=1; | ||||
|       } else { | ||||
|         chan.effectRows=reader.readC(); | ||||
|          | ||||
|       } | ||||
|       logD("%d fx rows: %d",i,chan.effectRows); | ||||
|       if (chan.effectRows>4 || chan.effectRows<1) { | ||||
|  | @ -606,79 +630,110 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|       } | ||||
|       for (int j=0; j<ds.ordersLen; j++) { | ||||
|         DivPattern* pat=chan.getPattern(ds.orders.ord[i][j],true); | ||||
|         for (int k=0; k<ds.patLen; k++) { | ||||
|           // note
 | ||||
|           pat->data[k][0]=reader.readS(); | ||||
|           // octave
 | ||||
|           pat->data[k][1]=reader.readS(); | ||||
|           if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && pat->data[k][1]>0) { | ||||
|             // apparently it was up one octave before
 | ||||
|             pat->data[k][1]--; | ||||
|           } else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && pat->data[k][1]>0 && i>5) { | ||||
|             // ditto
 | ||||
|             pat->data[k][1]--; | ||||
|           } | ||||
|           if (ds.version<0x12) { | ||||
|             if (ds.system[0]==DIV_SYSTEM_GB && i==3 && pat->data[k][1]>0) { | ||||
|               // back then noise was 2 octaves lower
 | ||||
|               pat->data[k][1]-=2; | ||||
|         if (ds.version>0x05) { // current pattern format
 | ||||
|           for (int k=0; k<ds.patLen; k++) { | ||||
|             // note
 | ||||
|             pat->data[k][0]=reader.readS(); | ||||
|             // octave
 | ||||
|             pat->data[k][1]=reader.readS(); | ||||
|             if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && pat->data[k][1]>0) { | ||||
|               // apparently it was up one octave before
 | ||||
|               pat->data[k][1]--; | ||||
|             } else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && pat->data[k][1]>0 && i>5) { | ||||
|               // ditto
 | ||||
|               pat->data[k][1]--; | ||||
|             } | ||||
|             if (ds.version<0x12) { | ||||
|               if (ds.system[0]==DIV_SYSTEM_GB && i==3 && pat->data[k][1]>0) { | ||||
|                 // back then noise was 2 octaves lower
 | ||||
|                 pat->data[k][1]-=2; | ||||
|               } | ||||
|             } | ||||
|             if (ds.system[0]==DIV_SYSTEM_YMU759 && pat->data[k][0]!=0) { | ||||
|               // apparently YMU759 is stored 2 octaves lower
 | ||||
|               pat->data[k][1]+=2; | ||||
|             } | ||||
|             if (pat->data[k][0]==0 && pat->data[k][1]!=0) { | ||||
|               logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); | ||||
|               pat->data[k][0]=12; | ||||
|               pat->data[k][1]--; | ||||
|             } | ||||
|             // volume
 | ||||
|             pat->data[k][3]=reader.readS(); | ||||
|             if (ds.version<0x0a) { | ||||
|               // back then volume was stored as 00-ff instead of 00-7f/0-f
 | ||||
|               if (i>5) { | ||||
|                 pat->data[k][3]>>=4; | ||||
|               } else { | ||||
|                 pat->data[k][3]>>=1; | ||||
|               } | ||||
|             } | ||||
|             if (ds.version<0x12) { | ||||
|               if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->data[k][3]>0) { | ||||
|                 // volume range of GB wave channel was 0-3 rather than 0-F
 | ||||
|                 pat->data[k][3]=(pat->data[k][3]&3)*5; | ||||
|               } | ||||
|             } | ||||
|             for (int l=0; l<chan.effectRows; l++) { | ||||
|               // effect
 | ||||
|               pat->data[k][4+(l<<1)]=reader.readS(); | ||||
|               pat->data[k][5+(l<<1)]=reader.readS(); | ||||
| 
 | ||||
|               if (ds.version<0x14) { | ||||
|                 if (pat->data[k][4+(l<<1)]==0xe5 && pat->data[k][5+(l<<1)]!=-1) { | ||||
|                   pat->data[k][5+(l<<1)]=128+((pat->data[k][5+(l<<1)]-128)/4); | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|             // instrument
 | ||||
|             pat->data[k][2]=reader.readS(); | ||||
| 
 | ||||
|             // this is sad
 | ||||
|             if (ds.system[0]==DIV_SYSTEM_NES_FDS) { | ||||
|               if (i==5 && pat->data[k][2]!=-1) { | ||||
|                 if (pat->data[k][2]>=0 && pat->data[k][2]<ds.insLen) { | ||||
|                   ds.ins[pat->data[k][2]]->type=DIV_INS_FDS; | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           if (ds.system[0]==DIV_SYSTEM_YMU759 && pat->data[k][0]!=0) { | ||||
|             // apparently YMU759 is stored 2 octaves lower
 | ||||
|             pat->data[k][1]+=2; | ||||
|           } | ||||
|           if (pat->data[k][0]==0 && pat->data[k][1]!=0) { | ||||
|             logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); | ||||
|             pat->data[k][0]=12; | ||||
|             pat->data[k][1]--; | ||||
|           } | ||||
|           // volume
 | ||||
|           pat->data[k][3]=reader.readS(); | ||||
|           if (ds.version<0x0a) { | ||||
|             // back then volume was stored as 00-ff instead of 00-7f/0-f
 | ||||
|             if (i>5) { | ||||
|               pat->data[k][3]>>=4; | ||||
|             } else { | ||||
|               pat->data[k][3]>>=1; | ||||
|         } else { // historic pattern format
 | ||||
|           if (i<16) pat->data[0][2]=historicColIns[i]; | ||||
|           for (int k=0; k<ds.patLen; k++) { | ||||
|             // note
 | ||||
|             pat->data[k][0]=reader.readC(); | ||||
|             // octave
 | ||||
|             pat->data[k][1]=reader.readC(); | ||||
|             if (pat->data[k][0]!=0) { | ||||
|               // YMU759 is stored 2 octaves lower
 | ||||
|               pat->data[k][1]+=2; | ||||
|             } | ||||
|           } | ||||
|           if (ds.version<0x12) { | ||||
|             if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->data[k][3]>0) { | ||||
|               // volume range of GB wave channel was 0-3 rather than 0-F
 | ||||
|               pat->data[k][3]=(pat->data[k][3]&3)*5; | ||||
|             if (pat->data[k][0]==0 && pat->data[k][1]!=0) { | ||||
|               logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); | ||||
|               pat->data[k][0]=12; | ||||
|               pat->data[k][1]--; | ||||
|             } | ||||
|           } | ||||
|           for (int l=0; l<chan.effectRows; l++) { | ||||
|             // volume and effect
 | ||||
|             unsigned char vol=reader.readC(); | ||||
|             unsigned char fx=reader.readC(); | ||||
|             unsigned char fxVal=reader.readC(); | ||||
|             pat->data[k][3]=(vol==0x80)?-1:vol; | ||||
|             // effect
 | ||||
|             pat->data[k][4+(l<<1)]=reader.readS(); | ||||
|             pat->data[k][5+(l<<1)]=reader.readS(); | ||||
| 
 | ||||
|             if (ds.version<0x14) { | ||||
|               if (pat->data[k][4+(l<<1)]==0xe5 && pat->data[k][5+(l<<1)]!=-1) { | ||||
|                 pat->data[k][5+(l<<1)]=128+((pat->data[k][5+(l<<1)]-128)/4); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           // instrument
 | ||||
|           pat->data[k][2]=reader.readS(); | ||||
| 
 | ||||
|           // this is sad
 | ||||
|           if (ds.system[0]==DIV_SYSTEM_NES_FDS) { | ||||
|             if (i==5 && pat->data[k][2]!=-1) { | ||||
|               if (pat->data[k][2]>=0 && pat->data[k][2]<ds.insLen) { | ||||
|                 ds.ins[pat->data[k][2]]->type=DIV_INS_FDS; | ||||
|               } | ||||
|             } | ||||
|             pat->data[k][4]=(fx==0x80)?-1:fx; | ||||
|             pat->data[k][5]=(fxVal==0x80)?-1:fxVal; | ||||
|             // instrument wasn't stored back then
 | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     int ymuSampleRate=20; | ||||
| 
 | ||||
|     ds.sampleLen=(unsigned char)reader.readC(); | ||||
|     logI("reading samples (%d)...",ds.sampleLen); | ||||
|     if (ds.version<0x0b && ds.sampleLen>0) { // TODO what is this for?
 | ||||
|       reader.readC(); | ||||
|     if (ds.version<0x0b && ds.sampleLen>0) { | ||||
|       // it appears this byte stored the YMU759 sample rate
 | ||||
|       ymuSampleRate=reader.readC(); | ||||
|     } | ||||
|     for (int i=0; i<ds.sampleLen; i++) { | ||||
|       DivSample* sample=new DivSample; | ||||
|  | @ -686,6 +741,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|       int pitch=5; | ||||
|       int vol=50; | ||||
|       short* data; | ||||
|       unsigned char* adpcmData; | ||||
|       if (length<0) { | ||||
|         logE("invalid sample length %d. are we doing something wrong?",length); | ||||
|         lastError="file is corrupt or unreadable at samples"; | ||||
|  | @ -704,6 +760,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|         pitch=reader.readC(); | ||||
|         vol=reader.readC(); | ||||
|       } | ||||
|       if (ds.version<=0x05) { | ||||
|         sample->rate=ymuSampleRate*400; | ||||
|       } | ||||
|       if (ds.version>0x15) { | ||||
|         sample->depth=reader.readC(); | ||||
|         if (sample->depth!=8 && sample->depth!=16) { | ||||
|  | @ -711,43 +770,65 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { | |||
|           sample->depth=16; | ||||
|         } | ||||
|       } else { | ||||
|         sample->depth=16; | ||||
|         if (ds.version>0x05) { | ||||
|           sample->depth=16; | ||||
|         } else { | ||||
|           // it appears samples were stored as ADPCM back then
 | ||||
|           sample->depth=6; | ||||
|         } | ||||
|       } | ||||
|       if (length>0) { | ||||
|         if (ds.version<0x0b) { | ||||
|           data=new short[1+(length/2)]; | ||||
|           reader.read(data,length); | ||||
|           length/=2; | ||||
|         } else { | ||||
|           data=new short[length]; | ||||
|           reader.read(data,length*2); | ||||
|         } | ||||
| 
 | ||||
|         if (pitch!=5) { | ||||
|           logD("%d: scaling from %d...",i,pitch); | ||||
|         } | ||||
| 
 | ||||
|         // render data
 | ||||
|         if (!sample->init((double)length/samplePitches[pitch])) { | ||||
|           logE("%d: error while initializing sample!",i); | ||||
|         } | ||||
| 
 | ||||
|         unsigned int k=0; | ||||
|         float mult=(float)(vol)/50.0f; | ||||
|         for (double j=0; j<length; j+=samplePitches[pitch]) { | ||||
|           if (k>=sample->samples) { | ||||
|             break; | ||||
|           } | ||||
|           if (sample->depth==8) { | ||||
|             float next=(float)(data[(unsigned int)j]-0x80)*mult; | ||||
|             sample->data8[k++]=fmin(fmax(next,-128),127); | ||||
|         if (ds.version>0x05) { | ||||
|           if (ds.version<0x0b) { | ||||
|             data=new short[1+(length/2)]; | ||||
|             reader.read(data,length); | ||||
|             length/=2; | ||||
|           } else { | ||||
|             float next=(float)data[(unsigned int)j]*mult; | ||||
|             sample->data16[k++]=fmin(fmax(next,-32768),32767); | ||||
|             data=new short[length]; | ||||
|             reader.read(data,length*2); | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         delete[] data; | ||||
|           if (pitch!=5) { | ||||
|             logD("%d: scaling from %d...",i,pitch); | ||||
|           } | ||||
| 
 | ||||
|           // render data
 | ||||
|           if (!sample->init((double)length/samplePitches[pitch])) { | ||||
|             logE("%d: error while initializing sample!",i); | ||||
|           } | ||||
| 
 | ||||
|           unsigned int k=0; | ||||
|           float mult=(float)(vol)/50.0f; | ||||
|           for (double j=0; j<length; j+=samplePitches[pitch]) { | ||||
|             if (k>=sample->samples) { | ||||
|               break; | ||||
|             } | ||||
|             if (sample->depth==8) { | ||||
|               float next=(float)(data[(unsigned int)j]-0x80)*mult; | ||||
|               sample->data8[k++]=fmin(fmax(next,-128),127); | ||||
|             } else { | ||||
|               float next=(float)data[(unsigned int)j]*mult; | ||||
|               sample->data16[k++]=fmin(fmax(next,-32768),32767); | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           delete[] data; | ||||
|         } else { | ||||
|           // ADPCM?
 | ||||
|           // it appears to be a slightly modified version of ADPCM-B!
 | ||||
|           adpcmData=new unsigned char[length]; | ||||
|           logV("%x",reader.tell()); | ||||
|           reader.read(adpcmData,length); | ||||
|           for (int i=0; i<length; i++) { | ||||
|             adpcmData[i]=(adpcmData[i]<<4)|(adpcmData[i]>>4); | ||||
|           } | ||||
|           if (!sample->init(length*2)) { | ||||
|             logE("%d: error while initializing sample!",i); | ||||
|           } | ||||
| 
 | ||||
|           memcpy(sample->dataB,adpcmData,length); | ||||
|           delete[] adpcmData; | ||||
|         } | ||||
|       } | ||||
|       ds.sample.push_back(sample); | ||||
|     } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 tildearrow
						tildearrow