diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index fce9f783..ea609a3d 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -245,6 +245,22 @@ const unsigned char q1_reg_map[Q1V_REG_COUNT][16] = { {0x06,0x0e,0x16,0x1e,0x26,0x2e,0x36,0x3e,0x46,0x4e,0x56,0x5e,0x66,0x6e,0x76,0x7e}, }; +const unsigned char q1a_start_map[3]={ + 0xca, 0xce, 0xd2 +}; + +const unsigned char q1a_end_map[3]={ + 0xcb, 0xcf, 0xd3 +}; + +const unsigned char q1a_bank_map[3]={ + 0xcc, 0xd0, 0xd4 +}; + +const unsigned char q1a_vol_map[3]={ + 0xcd, 0xd1, 0xd5 +}; + const char** DivPlatformQSound::getRegisterSheet() { return regCheatSheetQSound; } @@ -265,7 +281,7 @@ void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t l } void DivPlatformQSound::tick(bool sysTick) { - for (int i=0; i<16; i++) { + for (int i=0; i<19; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { if (chan[i].isNewQSound) { @@ -277,7 +293,11 @@ void DivPlatformQSound::tick(bool sysTick) { } // Check if enabled and write volume if (chan[i].active) { - rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol); + if (i<16) { + rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol); + } else { + rWrite(q1a_vol_map[i-16],chan[i].resVol); + } } } uint16_t qsound_bank = 0; @@ -286,8 +306,13 @@ void DivPlatformQSound::tick(bool sysTick) { uint16_t qsound_end = 0; if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].sample); - qsound_bank = 0x8000 | (offPCM[chan[i].sample] >> 16); - qsound_addr = offPCM[chan[i].sample] & 0xffff; + if (i<16) { + qsound_bank = 0x8000 | (offPCM[chan[i].sample] >> 16); + qsound_addr = offPCM[chan[i].sample] & 0xffff; + } else { + qsound_bank = 0x8000 | (offBS[chan[i].sample] >> 16); + qsound_addr = offBS[chan[i].sample] & 0xffff; + } int loopStart=s->loopStart; int length = s->loopEnd; @@ -295,10 +320,18 @@ void DivPlatformQSound::tick(bool sysTick) { length = 65536 - 16; } if (loopStart == -1 || loopStart >= length) { - qsound_end = offPCM[chan[i].sample] + length + 15; + if (i<16) { + qsound_end = offPCM[chan[i].sample] + length + 15; + } else { + qsound_end = offBS[chan[i].sample] + length + 15; + } qsound_loop = 15; } else { - qsound_end = offPCM[chan[i].sample] + length; + if (i<16) { + qsound_end = offPCM[chan[i].sample] + length; + } else { + qsound_end = offBS[chan[i].sample] + length; + } qsound_loop = length - loopStart; } } @@ -310,7 +343,9 @@ void DivPlatformQSound::tick(bool sysTick) { } if (chan[i].isNewQSound && chan[i].std.duty.had) { chan[i].echo=CLAMP(chan[i].std.duty.val,0,32767); - immWrite(Q1_ECHO+i,chan[i].echo&0x7fff); + if (i<16) { + immWrite(Q1_ECHO+i,chan[i].echo&0x7fff); + } } if (chan[i].isNewQSound && chan[i].std.ex1.had) { immWrite(Q1_ECHO_FEEDBACK,chan[i].std.ex1.val&0x3fff); @@ -355,11 +390,17 @@ void DivPlatformQSound::tick(bool sysTick) { chan[i].freq=off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,440.0,4096.0); if (chan[i].freq>0xefff) chan[i].freq=0xefff; if (chan[i].keyOn) { - rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank); - rWrite(q1_reg_map[Q1V_END][i], qsound_end); - rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop); - rWrite(q1_reg_map[Q1V_START][i], qsound_addr); - rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000); + if (i<16) { + rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank); + rWrite(q1_reg_map[Q1V_END][i], qsound_end); + rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop); + rWrite(q1_reg_map[Q1V_START][i], qsound_addr); + rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000); + } else { + rWrite(q1a_bank_map[i-16], qsound_bank); + rWrite(q1a_end_map[i-16], qsound_end); + rWrite(q1a_start_map[i-16], qsound_addr); + } //logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); // Write sample address. Enable volume if (!chan[i].std.vol.had) { @@ -368,16 +409,26 @@ void DivPlatformQSound::tick(bool sysTick) { } else { chan[i].resVol=chan[i].vol<<4; } - rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol); + if (i<16) { + rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol); + } else { + rWrite(q1a_vol_map[i-16],chan[i].resVol); + } } } if (chan[i].keyOff) { // Disable volume - rWrite(q1_reg_map[Q1V_VOL][i],0); - rWrite(q1_reg_map[Q1V_FREQ][i],0); + if (i<16) { + rWrite(q1_reg_map[Q1V_VOL][i],0); + rWrite(q1_reg_map[Q1V_FREQ][i],0); + } else { + rWrite(q1a_vol_map[i-16],0); + } } else if (chan[i].active) { //logV("ch %d frequency set to %04x, off=%f, note=%d, %04x!",i,chan[i].freq,off,chan[i].note,QS_NOTE_FREQUENCY(chan[i].note)); - rWrite(q1_reg_map[Q1V_FREQ][i],chan[i].freq); + if (i<16) { + rWrite(q1_reg_map[Q1V_FREQ][i],chan[i].freq); + } } if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; @@ -441,8 +492,12 @@ int DivPlatformQSound::dispatch(DivCommand c) { } else { chan[c.chan].resVol=chan[c.chan].outVol<<4; } - if (chan[c.chan].active && c.chan<16) { - rWrite(q1_reg_map[Q1V_VOL][c.chan],chan[c.chan].resVol); + if (chan[c.chan].active) { + if (c.chan<16) { + rWrite(q1_reg_map[Q1V_VOL][c.chan],chan[c.chan].resVol); + } else { + rWrite(q1a_vol_map[c.chan-16],chan[c.chan].resVol); + } } } } @@ -459,6 +514,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { break; case DIV_CMD_QSOUND_ECHO_LEVEL: chan[c.chan].echo=c.value<<7; + if (c.chan>=16) break; immWrite(Q1_ECHO+c.chan,chan[c.chan].echo&0x7fff); break; case DIV_CMD_QSOUND_ECHO_FEEDBACK: @@ -532,7 +588,8 @@ void DivPlatformQSound::muteChannel(int ch, bool mute) { } void DivPlatformQSound::forceIns() { - for (int i=0; i<4; i++) { + // TODO: what? + for (int i=0; i<19; i++) { chan[i].insChanged=true; chan[i].freqChanged=true; chan[i].sample=-1; @@ -552,7 +609,7 @@ DivDispatchOscBuffer* DivPlatformQSound::getOscBuffer(int ch) { } void DivPlatformQSound::reset() { - for (int i=0; i<16; i++) { + for (int i=0; i<19; i++) { chan[i]=DivPlatformQSound::Channel(); chan[i].std.setEngine(parent); } @@ -582,8 +639,7 @@ void DivPlatformQSound::notifyInsChange(int ins) { } void DivPlatformQSound::notifyWaveChange(int wave) { - // TODO when wavetables are added - // TODO they probably won't be added unless the samples reside in RAM + // yeah won't add wavetables } void DivPlatformQSound::notifyInsDeletion(void* ins) { @@ -633,27 +689,32 @@ int DivPlatformQSound::getRegisterPoolDepth() { } const void* DivPlatformQSound::getSampleMem(int index) { - return index == 0 ? sampleMem : NULL; + return (index == 0 || index == 1) ? sampleMem : NULL; } size_t DivPlatformQSound::getSampleMemCapacity(int index) { - return index == 0 ? 16777216 : 0; + return (index == 0 || index == 1) ? 16777216 : 0; } size_t DivPlatformQSound::getSampleMemUsage(int index) { - return index == 0 ? sampleMemLen : 0; + return index == 0 ? sampleMemLen : index == 1 ? sampleMemLenBS : 0; } bool DivPlatformQSound::isSampleLoaded(int index, int sample) { - if (index!=0) return false; + if (index<0 || index>1) return false; if (sample<0 || sample>255) return false; + if (index==1) return sampleLoadedBS[sample]; return sampleLoaded[sample]; } -// TODO: ADPCM... come on... +const char* DivPlatformQSound::getSampleMemName(int index) { + return index == 0 ? "PCM" : index == 1 ? "ADPCM" : NULL; +} + void DivPlatformQSound::renderSamples(int sysID) { memset(sampleMem,0,getSampleMemCapacity()); memset(sampleLoaded,0,256*sizeof(bool)); + memset(sampleLoadedBS,0,256*sizeof(bool)); size_t memPos=0; for (int i=0; isong.sampleLen; i++) { @@ -689,6 +750,40 @@ void DivPlatformQSound::renderSamples(int sysID) { memPos+=length+16; } sampleMemLen=memPos+256; + + for (int i=0; isong.sampleLen; i++) { + DivSample* s=parent->song.sample[i]; + if (!s->renderOn[1][sysID]) { + offBS[i]=0; + continue; + } + + int length=s->lengthQSoundA; + if (length>65536-16) { + length=65536-16; + } + if ((memPos&0xff0000)!=((memPos+length)&0xff0000)) { + memPos=(memPos+0xffff)&0xff0000; + } + if (memPos>=getSampleMemCapacity()) { + logW("out of QSound ADPCM memory for sample %d!",i); + break; + } + if (memPos+length>=getSampleMemCapacity()) { + for (unsigned int i=0; idataQSoundA[i]; + } + logW("out of QSound ADPCM memory for sample %d!",i); + } else { + for (int i=0; idataQSoundA[i]; + } + sampleLoaded[i]=true; + } + offBS[i]=memPos^0x8000; + memPos+=length+16; + } + sampleMemLenBS=memPos+256; } int DivPlatformQSound::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { @@ -706,6 +801,7 @@ int DivPlatformQSound::init(DivEngine* p, int channels, int sugRate, const DivCo rate = qsound_start(&chip, chipClock); sampleMem=new unsigned char[getSampleMemCapacity()]; sampleMemLen=0; + sampleMemLenBS=0; chip.rom_data=sampleMem; chip.rom_mask=0xffffff; reset(); diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index 1f911a83..d141d591 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -69,7 +69,9 @@ class DivPlatformQSound: public DivDispatch { unsigned char* sampleMem; size_t sampleMemLen; + size_t sampleMemLenBS; bool sampleLoaded[256]; + bool sampleLoadedBS[256]; struct qsound_chip chip; unsigned short regPool[512]; @@ -102,6 +104,7 @@ class DivPlatformQSound: public DivDispatch { void poke(std::vector& wlist); const char** getRegisterSheet(); const void* getSampleMem(int index = 0); + const char* getSampleMemName(int index=0); size_t getSampleMemCapacity(int index = 0); size_t getSampleMemUsage(int index = 0); bool isSampleLoaded(int index, int sample);