Merge branch 'master' of https://github.com/tildearrow/furnace into ym2610b
# Conflicts: # src/engine/engine.cpp # src/engine/platform/ym2610Interface.cpp
This commit is contained in:
		
						commit
						d831a522a4
					
				|  | @ -25,6 +25,8 @@ furthermore, an `or reserved` indicates this field is always present, but is res | |||
| 
 | ||||
| the format versions are: | ||||
| 
 | ||||
| - 59: Furnace dev59 | ||||
| - 58: Furnace dev58 | ||||
| - 57: Furnace dev57 | ||||
| 
 | ||||
| - 53: Furnace 0.5.7 | ||||
|  | @ -202,6 +204,8 @@ size | description | |||
|  S?? | channel short names | ||||
|      | - same as above | ||||
|  STR | song comment | ||||
|   4f | master volume, 1.0f=100% (>=59) | ||||
|      | this is 2.0f for modules before 59 | ||||
| 
 | ||||
| # instrument | ||||
| 
 | ||||
|  |  | |||
|  | @ -444,46 +444,67 @@ void DivEngine::renderSamples() { | |||
|   sPreview.sample=-1; | ||||
|   sPreview.pos=0; | ||||
| 
 | ||||
|   // step 1: render samples
 | ||||
|   for (int i=0; i<song.sampleLen; i++) { | ||||
|     song.sample[i]->render(); | ||||
|   } | ||||
| 
 | ||||
|   /*
 | ||||
|   // step 3: allocate ADPCM samples
 | ||||
|   if (adpcmMem==NULL) adpcmMem=new unsigned char[16777216]; | ||||
|   // step 2: allocate ADPCM-A samples
 | ||||
|   if (adpcmAMem==NULL) adpcmAMem=new unsigned char[16777216]; | ||||
| 
 | ||||
|   size_t memPos=0; | ||||
|   for (int i=0; i<song.sampleLen; i++) { | ||||
|     DivSample* s=song.sample[i]; | ||||
|     if ((memPos&0xf00000)!=((memPos+s->adpcmRendLength)&0xf00000)) { | ||||
|     int paddedLen=(s->lengthA+255)&(~0xff); | ||||
|     if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) { | ||||
|       memPos=(memPos+0xfffff)&0xf00000; | ||||
|     } | ||||
|     if (memPos>=16777216) { | ||||
|       logW("out of ADPCM memory for sample %d!\n",i); | ||||
|       break; | ||||
|     } | ||||
|     if (memPos+s->adpcmRendLength>=16777216) { | ||||
|       memcpy(adpcmMem+memPos,s->adpcmRendData,16777216-memPos); | ||||
|     if (memPos+paddedLen>=16777216) { | ||||
|       memcpy(adpcmAMem+memPos,s->dataA,16777216-memPos); | ||||
|       logW("out of ADPCM memory for sample %d!\n",i); | ||||
|     } else { | ||||
|       memcpy(adpcmMem+memPos,s->adpcmRendData,s->adpcmRendLength); | ||||
|       memcpy(adpcmAMem+memPos,s->dataA,paddedLen); | ||||
|     } | ||||
|     s->rendOff=memPos; | ||||
|     memPos+=s->adpcmRendLength; | ||||
|     s->offA=memPos; | ||||
|     memPos+=paddedLen; | ||||
|   } | ||||
|   adpcmMemLen=memPos+256; | ||||
|   adpcmAMemLen=memPos+256; | ||||
| 
 | ||||
|   // step 4: allocate qsound pcm samples
 | ||||
|   if (qsoundMem==NULL) qsoundMem=new unsigned char[16777216]; | ||||
| 
 | ||||
|   memset(qsoundMem, 0, 16777216); | ||||
|   // step 3: allocate ADPCM-B samples
 | ||||
|   if (adpcmBMem==NULL) adpcmBMem=new unsigned char[16777216]; | ||||
| 
 | ||||
|   memPos=0; | ||||
|   for (int i=0; i<song.sampleLen; i++) { | ||||
|     DivSample* s=song.sample[i]; | ||||
|     int length = s->rendLength; | ||||
|     if (length > 65536-16) { | ||||
|       length = 65536-16; | ||||
|     int paddedLen=(s->lengthB+255)&(~0xff); | ||||
|     if (memPos>=16777216) { | ||||
|       logW("out of ADPCM-B memory for sample %d!\n",i); | ||||
|       break; | ||||
|     } | ||||
|     if (memPos+paddedLen>=16777216) { | ||||
|       memcpy(adpcmBMem+memPos,s->dataB,16777216-memPos); | ||||
|       logW("out of ADPCM-B memory for sample %d!\n",i); | ||||
|     } else { | ||||
|       memcpy(adpcmBMem+memPos,s->dataB,paddedLen); | ||||
|     } | ||||
|     s->offB=memPos; | ||||
|     memPos+=paddedLen; | ||||
|   } | ||||
|   adpcmBMemLen=memPos+256; | ||||
| 
 | ||||
|   // step 4: allocate qsound pcm samples
 | ||||
|   if (qsoundMem==NULL) qsoundMem=new unsigned char[16777216]; | ||||
| 
 | ||||
|   memPos=0; | ||||
|   for (int i=0; i<song.sampleLen; i++) { | ||||
|     DivSample* s=song.sample[i]; | ||||
|     int length=s->length8; | ||||
|     if (length>65536-16) { | ||||
|       length=65536-16; | ||||
|     } | ||||
|     if ((memPos&0xff0000)!=((memPos+length)&0xff0000)) { | ||||
|       memPos=(memPos+0xffff)&0xff0000; | ||||
|  | @ -494,41 +515,18 @@ void DivEngine::renderSamples() { | |||
|     } | ||||
|     if (memPos+length>=16777216) { | ||||
|       for (unsigned int i=0; i<16777216-(memPos+length); i++) { | ||||
|         qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0); | ||||
|         qsoundMem[(memPos+i)^0x8000]=s->data8[i]; | ||||
|       } | ||||
|       logW("out of QSound PCM memory for sample %d!\n",i); | ||||
|     } else { | ||||
|       for (int i=0; i<length; i++) { | ||||
|         qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0); | ||||
|         qsoundMem[(memPos+i)^0x8000]=s->data8[i]; | ||||
|       } | ||||
|     } | ||||
|     s->rendOffQsound=memPos ^ 0x8000; | ||||
|     s->offQSound=memPos^0x8000; | ||||
|     memPos+=length+16; | ||||
|   } | ||||
|   qsoundMemLen=memPos+256; | ||||
| 
 | ||||
|   // step 5: allocate ADPCM-B samples
 | ||||
|   if (adpcmBMem==NULL) adpcmBMem=new unsigned char[16777216]; | ||||
| 
 | ||||
|   memPos=0; | ||||
|   for (int i=0; i<song.sampleLen; i++) { | ||||
|     DivSample* s=song.sample[i]; | ||||
|     if (memPos>=16777216) { | ||||
|       logW("out of ADPCM-B memory for sample %d!\n",i); | ||||
|       break; | ||||
|     } | ||||
|     if (memPos+s->adpcmBRendLength>=16777216) { | ||||
|       memcpy(adpcmBMem+memPos,s->adpcmBRendData,16777216-memPos); | ||||
|       logW("out of ADPCM-B memory for sample %d!\n",i); | ||||
|     } else { | ||||
|       memcpy(adpcmBMem+memPos,s->adpcmBRendData,s->adpcmBRendLength); | ||||
|     } | ||||
|     s->rendOff=memPos; | ||||
|     memPos+=s->adpcmBRendLength; | ||||
|   } | ||||
|   adpcmBMemLen=memPos+256; | ||||
| 
 | ||||
|   */ | ||||
| } | ||||
| 
 | ||||
| void DivEngine::createNew() { | ||||
|  |  | |||
|  | @ -37,8 +37,8 @@ | |||
|     warnings+=(String("\n")+x); \ | ||||
|   } | ||||
| 
 | ||||
| #define DIV_VERSION "dev58" | ||||
| #define DIV_ENGINE_VERSION 58 | ||||
| #define DIV_VERSION "dev59" | ||||
| #define DIV_ENGINE_VERSION 59 | ||||
| 
 | ||||
| enum DivStatusView { | ||||
|   DIV_STATUS_NOTHING=0, | ||||
|  | @ -621,12 +621,16 @@ class DivEngine { | |||
|     // terminate the engine.
 | ||||
|     bool quit(); | ||||
| 
 | ||||
|     unsigned char* adpcmMem; | ||||
|     size_t adpcmMemLen; | ||||
|     unsigned char* adpcmAMem; | ||||
|     size_t adpcmAMemLen; | ||||
|     unsigned char* adpcmBMem; | ||||
|     size_t adpcmBMemLen; | ||||
|     unsigned char* qsoundMem; | ||||
|     size_t qsoundMemLen; | ||||
|     unsigned char* qsoundAMem; | ||||
|     size_t qsoundAMemLen; | ||||
|     unsigned char* dpcmMem; | ||||
|     size_t dpcmMemLen; | ||||
| 
 | ||||
|     DivEngine(): | ||||
|       output(NULL), | ||||
|  | @ -680,11 +684,15 @@ class DivEngine { | |||
|       totalProcessed(0), | ||||
|       oscBuf{NULL,NULL}, | ||||
|       oscSize(1), | ||||
|       adpcmMem(NULL), | ||||
|       adpcmMemLen(0), | ||||
|       adpcmAMem(NULL), | ||||
|       adpcmAMemLen(0), | ||||
|       adpcmBMem(NULL), | ||||
|       adpcmBMemLen(0), | ||||
|       qsoundMem(NULL), | ||||
|       qsoundMemLen(0) {} | ||||
|       qsoundMemLen(0), | ||||
|       qsoundAMem(NULL), | ||||
|       qsoundAMemLen(0), | ||||
|       dpcmMem(NULL), | ||||
|       dpcmMemLen(0) {} | ||||
| }; | ||||
| #endif | ||||
|  |  | |||
|  | @ -845,7 +845,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { | |||
|     if (tchans>DIV_MAX_CHANS) tchans=DIV_MAX_CHANS; | ||||
| 
 | ||||
|     // system volume
 | ||||
|     for (int i=0; i<32; i++) ds.systemVol[i]=reader.readC(); | ||||
|     for (int i=0; i<32; i++) { | ||||
|       ds.systemVol[i]=reader.readC(); | ||||
|       if (ds.version<59 && ds.system[i]==DIV_SYSTEM_NES) { | ||||
|         ds.systemVol[i]/=4; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // system panning
 | ||||
|     for (int i=0; i<32; i++) ds.systemPan[i]=reader.readC(); | ||||
|  | @ -1003,6 +1008,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { | |||
|       ds.notes=reader.readString(); | ||||
|     } | ||||
| 
 | ||||
|     if (ds.version>=59) { | ||||
|       ds.masterVol=reader.readF(); | ||||
|     } else { | ||||
|       ds.masterVol=2.0f; | ||||
|     } | ||||
| 
 | ||||
|     // read instruments
 | ||||
|     for (int i=0; i<ds.insLen; i++) { | ||||
|       DivInstrument* ins=new DivInstrument; | ||||
|  | @ -1448,6 +1459,8 @@ SafeWriter* DivEngine::saveFur() { | |||
| 
 | ||||
|   w->writeString(song.notes,false); | ||||
| 
 | ||||
|   w->writeF(song.masterVol); | ||||
| 
 | ||||
|   /// INSTRUMENT
 | ||||
|   for (int i=0; i<song.insLen; i++) { | ||||
|     DivInstrument* ins=song.ins[i]; | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ | |||
| #define WRITE_CONTROL(ch,v) rWrite(0x25+(ch<<3),(v)) | ||||
| #define WRITE_OTHER(ch,v) rWrite(0x27+(ch<<3),(v)) | ||||
| #define WRITE_ATTEN(ch,v) rWrite((0x40+ch),(v)) | ||||
| #define WRITE_STEREO(v) rWrite(0x50,(v)) | ||||
| 
 | ||||
| #define CHIP_DIVIDER 64 | ||||
| 
 | ||||
|  | @ -88,9 +89,9 @@ const char* regCheatSheetLynx[]={ | |||
| 
 | ||||
| const char** DivPlatformLynx::getRegisterSheet() { | ||||
|   return regCheatSheetLynx; | ||||
| } | ||||
| 
 | ||||
| const char* DivPlatformLynx::getEffectName(unsigned char effect) { | ||||
| } | ||||
| 
 | ||||
| const char* DivPlatformLynx::getEffectName(unsigned char effect) { | ||||
|   switch (effect) | ||||
|   { | ||||
|   case 0x30: case 0x31: case 0x32: case 0x33: | ||||
|  | @ -197,7 +198,8 @@ int DivPlatformLynx::dispatch(DivCommand c) { | |||
|       } | ||||
|       break; | ||||
|     case DIV_CMD_PANNING: | ||||
|       WRITE_ATTEN(c.chan, c.value); | ||||
|       chan[c.chan].pan=((c.value&0x0f)<<4)|((c.value&0xf0)>>4); | ||||
|       WRITE_ATTEN(c.chan,chan[c.chan].pan); | ||||
|       break; | ||||
|     case DIV_CMD_GET_VOLUME: | ||||
|       if (chan[c.chan].std.hasVol) { | ||||
|  | @ -261,6 +263,10 @@ void DivPlatformLynx::muteChannel(int ch, bool mute) { | |||
|   if (chan[ch].active) WRITE_VOLUME(ch,(isMuted[ch]?0:(chan[ch].outVol&127))); | ||||
| } | ||||
| 
 | ||||
| bool DivPlatformLynx::isStereo() { | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| void DivPlatformLynx::forceIns() { | ||||
|   for (int i=0; i<4; i++) { | ||||
|     if (chan[i].active) { | ||||
|  | @ -272,16 +278,16 @@ void DivPlatformLynx::forceIns() { | |||
| 
 | ||||
| void* DivPlatformLynx::getChanState(int ch) { | ||||
|   return &chan[ch]; | ||||
| } | ||||
| 
 | ||||
| unsigned char* DivPlatformLynx::getRegisterPool() | ||||
| { | ||||
|   return const_cast<unsigned char*>( mikey->getRegisterPool() ); | ||||
| } | ||||
| 
 | ||||
| int DivPlatformLynx::getRegisterPoolSize() | ||||
| { | ||||
|   return 4*8+4; | ||||
| } | ||||
| 
 | ||||
| unsigned char* DivPlatformLynx::getRegisterPool() | ||||
| { | ||||
|   return const_cast<unsigned char*>( mikey->getRegisterPool() ); | ||||
| } | ||||
| 
 | ||||
| int DivPlatformLynx::getRegisterPoolSize() | ||||
| { | ||||
|   return 4*8+4; | ||||
| } | ||||
| 
 | ||||
| void DivPlatformLynx::reset() { | ||||
|  | @ -294,6 +300,7 @@ void DivPlatformLynx::reset() { | |||
|   if (dumpWrites) { | ||||
|     addWrite(0xffffffff,0); | ||||
|   } | ||||
|   WRITE_STEREO(0); | ||||
| } | ||||
| 
 | ||||
| bool DivPlatformLynx::keyOffAffectsArp(int ch) { | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ class DivPlatformLynx: public DivDispatch { | |||
|     MikeyFreqDiv fd; | ||||
|     MikeyDuty duty; | ||||
|     int baseFreq, pitch, note, actualNote, lfsr; | ||||
|     unsigned char ins; | ||||
|     unsigned char ins, pan; | ||||
|     bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; | ||||
|     signed char vol, outVol; | ||||
|     Channel(): | ||||
|  | @ -58,6 +58,7 @@ class DivPlatformLynx: public DivDispatch { | |||
|       actualNote(0), | ||||
|       lfsr(-1), | ||||
|       ins(-1), | ||||
|       pan(0xff), | ||||
|       active(false), | ||||
|       insChanged(true), | ||||
|       freqChanged(false), | ||||
|  | @ -81,6 +82,7 @@ class DivPlatformLynx: public DivDispatch { | |||
|     void forceIns(); | ||||
|     void tick(); | ||||
|     void muteChannel(int ch, bool mute); | ||||
|     bool isStereo(); | ||||
|     bool keyOffAffectsArp(int ch); | ||||
|     bool keyOffAffectsPorta(int ch); | ||||
|     //int getPortaFloor(int ch);
 | ||||
|  |  | |||
|  | @ -99,7 +99,10 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) | |||
|     if (nes->apu.clocked) { | ||||
|       nes->apu.clocked=false; | ||||
|     } | ||||
|     bufL[i]=(pulse_output(nes)+tnd_output(nes))*30; | ||||
|     int sample=(pulse_output(nes)+tnd_output(nes)-128)<<7; | ||||
|     if (sample>32767) sample=32767; | ||||
|     if (sample<-32768) sample=-32768; | ||||
|     bufL[i]=sample; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -301,7 +301,9 @@ void DivPlatformSMS::poke(std::vector<DivRegWrite>& wlist) { | |||
| } | ||||
| 
 | ||||
| void DivPlatformSMS::setFlags(unsigned int flags) { | ||||
|   if ((flags&3)==2) { | ||||
|   if ((flags&3)==3) { | ||||
|     chipClock=COLOR_NTSC/2.0; | ||||
|   } else if ((flags&3)==2) { | ||||
|     chipClock=4000000; | ||||
|   } else if ((flags&3)==1) { | ||||
|     chipClock=COLOR_PAL*4.0/5.0; | ||||
|  |  | |||
|  | @ -22,12 +22,20 @@ | |||
| #include "../engine.h" | ||||
| 
 | ||||
| uint8_t DivYM2610Interface::ymfm_external_read(ymfm::access_class type, uint32_t address) { | ||||
|   //printf("wants to read from %x\n",address);
 | ||||
|   if (type!=ymfm::ACCESS_ADPCM_A) return /*s->dataB[address&0xffffff];*/0; | ||||
|   return parent->adpcmMem[address&0xffffff];/*s->dataA[address&0xffffff]*/ | ||||
|   /*if (12*sampleBank+(address>>16)>=parent->song.sampleLen) return 0;
 | ||||
|   return parent->song.sample[12*sampleBank+(address>>16)]->adpcmRendData[(address&0xffff)];*/ | ||||
|   switch (type) { | ||||
|     case ymfm::ACCESS_ADPCM_A: | ||||
|       if (parent->adpcmAMem==NULL) return 0; | ||||
|       if ((address&0xffffff)>=parent->adpcmAMemLen) return 0; | ||||
|       return parent->adpcmAMem[address&0xffffff]; | ||||
|     case ymfm::ACCESS_ADPCM_B: | ||||
|       if (parent->adpcmBMem==NULL) return 0; | ||||
|       if ((address&0xffffff)>=parent->adpcmBMemLen) return 0; | ||||
|       return parent->adpcmBMem[address&0xffffff]; | ||||
|     default: | ||||
|       return 0; | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| void DivYM2610Interface::ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data) { | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -237,7 +237,7 @@ void DivPlatformYM2610B::tick() { | |||
|    | ||||
|   // FM
 | ||||
|   for (int i=0; i<6; i++) { | ||||
|     if (i==1 && extMode) continue; | ||||
|     if (i==2 && extMode) continue; | ||||
|     chan[i].std.next(); | ||||
| 
 | ||||
|     if (chan[i].std.hadVol) { | ||||
|  | @ -366,7 +366,7 @@ void DivPlatformYM2610B::tick() { | |||
|   } | ||||
| 
 | ||||
|   for (int i=0; i<6; i++) { | ||||
|     if (i==1 && extMode) continue; | ||||
|     if (i==2 && extMode) continue; | ||||
|     if (chan[i].freqChanged) { | ||||
|       chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq)); | ||||
|       if (chan[i].freq>262143) chan[i].freq=262143; | ||||
|  |  | |||
|  | @ -1314,17 +1314,17 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi | |||
|   } | ||||
| 
 | ||||
|   for (int i=0; i<song.systemLen; i++) { | ||||
|     float volL=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127-(int)song.systemPan[i])/127.0f); | ||||
|     float volR=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127+(int)song.systemPan[i])/127.0f); | ||||
|     float volL=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127-(int)song.systemPan[i])/127.0f)*song.masterVol; | ||||
|     float volR=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127+(int)song.systemPan[i])/127.0f)*song.masterVol; | ||||
|     if (disCont[i].dispatch->isStereo()) { | ||||
|       for (size_t j=0; j<size; j++) { | ||||
|         out[0][j]+=((float)disCont[i].bbOut[0][j]/16384.0)*volL; | ||||
|         out[1][j]+=((float)disCont[i].bbOut[1][j]/16384.0)*volR; | ||||
|         out[0][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volL; | ||||
|         out[1][j]+=((float)disCont[i].bbOut[1][j]/32768.0)*volR; | ||||
|       } | ||||
|     } else { | ||||
|       for (size_t j=0; j<size; j++) { | ||||
|         out[0][j]+=((float)disCont[i].bbOut[0][j]/16384.0)*volL; | ||||
|         out[1][j]+=((float)disCont[i].bbOut[0][j]/16384.0)*volR; | ||||
|         out[0][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volL; | ||||
|         out[1][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volR; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -73,6 +73,7 @@ bool DivSample::save(const char* path) { | |||
|   return true; | ||||
| } | ||||
| 
 | ||||
| // 16-bit memory is padded to 512, to make things easier for ADPCM-A/B.
 | ||||
| bool DivSample::initInternal(unsigned char d, int count) { | ||||
|   switch (d) { | ||||
|     case 0: // 1-bit
 | ||||
|  | @ -96,14 +97,14 @@ bool DivSample::initInternal(unsigned char d, int count) { | |||
|     case 5: // ADPCM-A
 | ||||
|       if (dataA!=NULL) delete[] dataA; | ||||
|       lengthA=(count+1)/2; | ||||
|       dataA=new unsigned char[lengthA]; | ||||
|       memset(dataA,0,lengthA); | ||||
|       dataA=new unsigned char[(lengthA+255)&(~0xff)]; | ||||
|       memset(dataA,0,(lengthA+255)&(~0xff)); | ||||
|       break; | ||||
|     case 6: // ADPCM-B
 | ||||
|       if (dataB!=NULL) delete[] dataB; | ||||
|       lengthB=(count+1)/2; | ||||
|       dataB=new unsigned char[lengthB]; | ||||
|       memset(dataB,0,lengthB); | ||||
|       dataB=new unsigned char[(lengthB+255)&(~0xff)]; | ||||
|       memset(dataB,0,(lengthB+255)&(~0xff)); | ||||
|       break; | ||||
|     case 7: // X68000 ADPCM
 | ||||
|       if (dataX68!=NULL) delete[] dataX68; | ||||
|  | @ -132,8 +133,8 @@ bool DivSample::initInternal(unsigned char d, int count) { | |||
|     case 16: // 16-bit
 | ||||
|       if (data16!=NULL) delete[] data16; | ||||
|       length16=count*2; | ||||
|       data16=new short[count]; | ||||
|       memset(data16,0,count*sizeof(short)); | ||||
|       data16=new short[(count+511)&(~0x1ff)]; | ||||
|       memset(data16,0,((count+511)&(~0x1ff))*sizeof(short)); | ||||
|       break; | ||||
|     default: | ||||
|       return false; | ||||
|  | @ -223,13 +224,14 @@ void DivSample::render() { | |||
|     if (!initInternal(4,samples)) return; | ||||
|     bs_encode(data16,dataQSoundA,samples); | ||||
|   } | ||||
|   // TODO: pad to 256.
 | ||||
|   if (depth!=5) { // ADPCM-A
 | ||||
|     if (!initInternal(5,samples)) return; | ||||
|     yma_encode(data16,dataA,samples); | ||||
|     yma_encode(data16,dataA,(samples+511)&(~0x1ff)); | ||||
|   } | ||||
|   if (depth!=6) { // ADPCM-B
 | ||||
|     if (!initInternal(6,samples)) return; | ||||
|     ymb_encode(data16,dataB,samples); | ||||
|     ymb_encode(data16,dataB,(samples+511)&(~0x1ff)); | ||||
|   } | ||||
|   if (depth!=7) { // X68000 ADPCM
 | ||||
|     if (!initInternal(7,samples)) return; | ||||
|  |  | |||
|  | @ -242,6 +242,7 @@ struct DivSong { | |||
|   bool pal; | ||||
|   bool customTempo; | ||||
|   int hz, patLen, ordersLen, insLen, waveLen, sampleLen; | ||||
|   float masterVol; | ||||
|   float tuning; | ||||
| 
 | ||||
|   // compatibility flags
 | ||||
|  | @ -309,6 +310,7 @@ struct DivSong { | |||
|     insLen(0), | ||||
|     waveLen(0), | ||||
|     sampleLen(0), | ||||
|     masterVol(1.0f), | ||||
|     tuning(440.0f), | ||||
|     limitSlides(false), | ||||
|     linearPitch(true), | ||||
|  |  | |||
|  | @ -938,14 +938,24 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) { | |||
|     delete[] pcmMem; | ||||
|   } | ||||
| 
 | ||||
|   if (writeADPCM && adpcmMemLen>0) { | ||||
|   if (writeADPCM && adpcmAMemLen>0) { | ||||
|     w->writeC(0x67); | ||||
|     w->writeC(0x66); | ||||
|     w->writeC(0x82); | ||||
|     w->writeI(adpcmMemLen+8); | ||||
|     w->writeI(adpcmMemLen); | ||||
|     w->writeI(adpcmAMemLen+8); | ||||
|     w->writeI(adpcmAMemLen); | ||||
|     w->writeI(0); | ||||
|     w->write(adpcmMem,adpcmMemLen); | ||||
|     w->write(adpcmAMem,adpcmAMemLen); | ||||
|   } | ||||
| 
 | ||||
|   if (writeADPCM && adpcmBMemLen>0) { | ||||
|     w->writeC(0x67); | ||||
|     w->writeC(0x66); | ||||
|     w->writeC(0x83); | ||||
|     w->writeI(adpcmBMemLen+8); | ||||
|     w->writeI(adpcmBMemLen); | ||||
|     w->writeI(0); | ||||
|     w->write(adpcmBMem,adpcmBMemLen); | ||||
|   } | ||||
| 
 | ||||
|   if (writeQSound && qsoundMemLen>0) { | ||||
|  |  | |||
|  | @ -1345,6 +1345,10 @@ void FurnaceGUI::drawMixer() { | |||
|   ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); | ||||
|   if (ImGui::Begin("Mixer",&mixerOpen,settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking)) { | ||||
|     char id[32]; | ||||
|     if (ImGui::SliderFloat("Master Volume",&e->song.masterVol,0,3,"%.2fx")) { | ||||
|       if (e->song.masterVol<0) e->song.masterVol=0; | ||||
|       if (e->song.masterVol>3) e->song.masterVol=3; | ||||
|     } | ||||
|     for (int i=0; i<e->song.systemLen; i++) { | ||||
|       snprintf(id,31,"MixS%d",i); | ||||
|       bool doInvert=e->song.systemVol[i]&128; | ||||
|  | @ -1898,12 +1902,12 @@ void FurnaceGUI::drawStats() { | |||
|   } | ||||
|   if (!statsOpen) return; | ||||
|   if (ImGui::Begin("Statistics",&statsOpen)) { | ||||
|     String adpcmUsage=fmt::sprintf("%d/16384KB",e->adpcmMemLen/1024); | ||||
|     String adpcmAUsage=fmt::sprintf("%d/16384KB",e->adpcmAMemLen/1024); | ||||
|     String adpcmBUsage=fmt::sprintf("%d/16384KB",e->adpcmBMemLen/1024); | ||||
|     String qsoundUsage=fmt::sprintf("%d/16384KB",e->qsoundMemLen/1024); | ||||
|     ImGui::Text("ADPCM-A"); | ||||
|     ImGui::SameLine(); | ||||
|     ImGui::ProgressBar(((float)e->adpcmMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmUsage.c_str()); | ||||
|     ImGui::ProgressBar(((float)e->adpcmAMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmAUsage.c_str()); | ||||
|     ImGui::Text("ADPCM-B"); | ||||
|     ImGui::SameLine(); | ||||
|     ImGui::ProgressBar(((float)e->adpcmBMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmBUsage.c_str()); | ||||
|  | @ -4542,6 +4546,10 @@ bool FurnaceGUI::loop() { | |||
|                   e->setSysFlags(i,(flags&(~3))|2,restart); | ||||
|                   updateWindowTitle(); | ||||
|                 } | ||||
|                 if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&3)==3)) { | ||||
|                   e->setSysFlags(i,(flags&(~3))|3,restart); | ||||
|                   updateWindowTitle(); | ||||
|                 } | ||||
|                 ImGui::Text("Chip type:"); | ||||
|                 if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) { | ||||
|                   e->setSysFlags(i,(flags&(~12))|0,restart); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 cam900
						cam900