diff --git a/doc/7-systems/pokey.md b/doc/7-systems/pokey.md index 8bbb04b78..257b85d53 100644 --- a/doc/7-systems/pokey.md +++ b/doc/7-systems/pokey.md @@ -33,7 +33,7 @@ a sound and input chip developed by Atari for their 8-bit computers (Atari 400, - use for PWM effects (not automatic!). - bit 0: 15KHz mode. - `12xx`: **toggle two-tone mode.** - - when enabled, channel 2 modulates channel 1. I don't know how, but it does. + - when enabled, channel 2 modulates channel 1 in an oscillator sync-like manner. - only on ASAP core. ## info diff --git a/src/engine/brrUtils.c b/src/engine/brrUtils.c index 38073fb4b..ff62e5641 100644 --- a/src/engine/brrUtils.c +++ b/src/engine/brrUtils.c @@ -256,7 +256,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigne total+=9; } // encode loop block - if (loopStart>=0) { + if (loopStart>=0 && loopStart=len) { diff --git a/src/engine/cmdStream.cpp b/src/engine/cmdStream.cpp index f1605426e..21ed84b5c 100644 --- a/src/engine/cmdStream.cpp +++ b/src/engine/cmdStream.cpp @@ -682,6 +682,11 @@ bool DivCSPlayer::init() { chan[i].readPos=chan[i].startPos; } } + + // read stack sizes + for (unsigned int i=0; igetTotalChannelCount(); i++) { diff --git a/src/engine/cmdStream.h b/src/engine/cmdStream.h index 326134dbd..459a49d62 100644 --- a/src/engine/cmdStream.h +++ b/src/engine/cmdStream.h @@ -41,7 +41,7 @@ struct DivCSChannelState { unsigned char arp, arpStage, arpTicks; unsigned int callStack[DIV_MAX_CSSTACK]; - unsigned char callStackPos; + unsigned char callStackPos, callStackSize; unsigned int trace[DIV_MAX_CSTRACE]; unsigned char tracePos; @@ -67,6 +67,7 @@ struct DivCSChannelState { arpStage(0), arpTicks(0), callStackPos(0), + callStackSize(0), tracePos(0) { for (int i=0; i=pcmChanOffs)) #define PCM_REG(ch) (ch-pcmChanOffs) +// check if PCM in RAM (and size is <= 2MB) - 4MB uses whole sample area +#define PCM_IN_RAM (ramSize<=0x200000) + // N = invalid #define N 255 @@ -1466,7 +1469,7 @@ void DivPlatformOPL::tick(bool sysTick) { ctrl|=(chan[i].active?0x80:0)|(chan[i].damp?0x40:0)|(chan[i].lfoReset?0x20:0)|(chan[i].ch?0x10:0)|(isMuted[i]?8:(chan[i].pan&0xf)); int waveNum=chan[i].sample; if (waveNum>=0) { - if (ramSize<=0x200000) { + if (PCM_IN_RAM) { waveNum=CLAMP(waveNum,0,0x7f)|0x180; } if (chan[i].keyOn) { @@ -2941,7 +2944,7 @@ void DivPlatformOPL::reset() { if (chipType==4) { immWrite(0x105,3); // Reset wavetable header - immWrite(0x202,(ramSize<=0x200000)?0x10:0x00); + immWrite(0x202,PCM_IN_RAM?0x10:0x00); // initialize mixer volume fmMixL=7; fmMixR=7; @@ -3209,7 +3212,7 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) { pcm.setClockFrequency(chipClock); rate=chipClock/768; chipRateBase=chipClock/684; - immWrite(0x202,(ramSize<=0x200000)?0x10:0x00); + immWrite(0x202,PCM_IN_RAM?0x10:0x00); break; case 759: rate=48000; @@ -3232,7 +3235,7 @@ const void* DivPlatformOPL::getSampleMem(int index) { size_t DivPlatformOPL::getSampleMemCapacity(int index) { return (index==0 && pcmChanOffs>=0)? - ((ramSize<=0x200000)?0x200000+ramSize:ramSize): + (PCM_IN_RAM?0x200000+ramSize:ramSize): ((index==0 && adpcmChan>=0)?262144:0); } @@ -3269,10 +3272,16 @@ void DivPlatformOPL::renderSamples(int sysID) { memCompo.name="Sample Memory"; if (pcmChanOffs>=0) { // OPL4 PCM - size_t memPos=((ramSize<=0x200000)?0x200600:0x1800); - const int maxSample=(ramSize<=0x200000)?127:511; + size_t memPos=(PCM_IN_RAM?0x200600:0x1800); + const int maxSample=PCM_IN_RAM?128:512; int sampleCount=parent->song.sampleLen; - if (sampleCount>maxSample) sampleCount=maxSample; + if (sampleCount>maxSample) { + // mark the rest as unavailable + for (int i=maxSample; isong.sample[i]; if (!s->renderOn[0][sysID]) { @@ -3335,7 +3344,7 @@ void DivPlatformOPL::renderSamples(int sysID) { // instrument table for (int i=0; isong.sample[i]; - unsigned int insAddr=(i*12)+((ramSize<=0x200000)?0x200000:0); + unsigned int insAddr=(i*12)+(PCM_IN_RAM?0x200000:0); unsigned char bitDepth; int endPos=CLAMP(s->isLoopable()?s->loopEnd:(s->samples+1),1,0x10000); int loop=s->isLoopable()?CLAMP(s->loopStart,0,endPos-2):(endPos-2); @@ -3366,12 +3375,12 @@ void DivPlatformOPL::renderSamples(int sysID) { pcmMem[6+insAddr]=(~(endPos-1))&0xff; // on MultiPCM this consists of instrument params, but on OPL4 this is not used pcmMem[7+insAddr]=0; // LFO, VIB - pcmMem[8+insAddr]=(0xf << 4) | (0xf << 0); // AR, D1R + pcmMem[8+insAddr]=(0xf<<4)|(0xf<<0); // AR, D1R pcmMem[9+insAddr]=0; // DL, D2R - pcmMem[10+insAddr]=(0xf << 4) | (0xf << 0); // RC, RR + pcmMem[10+insAddr]=(0xf<<4)|(0xf<<0); // RC, RR pcmMem[11+insAddr]=0; // AM } - if (ramSize<=0x200000) { + if (PCM_IN_RAM) { memCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_RESERVED,"ROM data",0,0,0x200000)); } diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 2f7d50617..054d2bc4e 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -1479,7 +1479,8 @@ void DivSample::render(unsigned int formatMask) { } } if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_BRR)) { // BRR - int sampleCount=loop?loopEnd:samples; + int sampleCount=isLoopable()?loopEnd:samples; + if (sampleCount>(int)samples) sampleCount=samples; if (!initInternal(DIV_SAMPLE_DEPTH_BRR,sampleCount)) return; brrEncode(data16,dataBRR,sampleCount,loop?loopStart:-1,brrEmphasis,brrNoFilter); } diff --git a/src/gui/csPlayer.cpp b/src/gui/csPlayer.cpp index c84494dda..e438a4d60 100644 --- a/src/gui/csPlayer.cpp +++ b/src/gui/csPlayer.cpp @@ -525,6 +525,72 @@ void FurnaceGUI::drawCSPlayer() { ImGui::PopFont(); ImGui::EndTabItem(); } + if (ImGui::BeginTabItem(_("Data Access Visualizer"))) { + ImGui::Text("%d bytes",(int)cs->getDataLen()); + + ImGui::PushFont(patFont); + if (ImGui::BeginTable("CSHexPos",chans,ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableNextRow(); + for (int i=0; igetChanState(i); + ImGui::TableNextColumn(); + ImGui::Text("$%.4x",state->readPos); + } + ImGui::EndTable(); + } + ImGui::PopFont(); + + if (csTex==NULL || !rend->isTextureValid(csTex)) { + logD("recreating command stream data texture."); + csTex=rend->createTexture(true,256,256,false,GUI_TEXFORMAT_ABGR32); + if (csTex==NULL) { + logE("error while creating command stream data texture! %s",SDL_GetError()); + } + } + if (csTex!=NULL) { + unsigned int* dataT=NULL; + int pitch=0; + if (!rend->lockTexture(csTex,(void**)&dataT,&pitch)) { + logE("error while locking command stream data texture! %s",SDL_GetError()); + } else { + unsigned short* accessTS=cs->getDataAccess(); + unsigned int csTick=cs->getCurTick(); + const float fadeTime=64.0f; + size_t bufSize=cs->getDataLen(); + if (bufSize>65536) bufSize=65536; + + for (size_t i=0; i0.0f) { + dataT[i]=ImGui::GetColorU32(ImGuiCol_HeaderActive,cellAlpha); + } else { + dataT[i]=0; + } + } + for (size_t i=bufSize; i<65536; i++) { + dataT[i]=0; + } + + for (int i=0; igetTotalChannelCount(); i++) { + unsigned int pos=cs->getChanState(i)->readPos; + if (pos<65536) { + ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f); + ImGui::ColorConvertHSVtoRGB((float)i/(float)e->getTotalChannelCount(),0.8f,1.0f,col.x,col.y,col.z); + dataT[pos]=ImGui::GetColorU32(col); + } + } + rend->unlockTexture(csTex); + } + + ImGui::Image(rend->getTextureID(csTex),ImVec2(768.0*dpiScale,768.0*dpiScale)); + } + ImGui::EndTabItem(); + } if (ImGui::BeginTabItem(_("Stream Info"))) { ImGui::Text("%d bytes",(int)cs->getDataLen()); ImGui::Text("%u channels",cs->getFileChans()); @@ -538,6 +604,11 @@ void FurnaceGUI::drawCSPlayer() { ImGui::SameLine(); ImGui::Text("%d",cs->getFastCmds()[i]); } + ImGui::Text("stack sizes:"); + for (unsigned int i=0; igetFileChans(); i++) { + ImGui::SameLine(); + ImGui::Text("%d",cs->getChanState(i)->callStackSize); + } ImGui::Text("ticks: %u",cs->getCurTick()); ImGui::EndTabItem(); } diff --git a/src/gui/gui.h b/src/gui/gui.h index c2a4c818d..12d31de8b 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1668,6 +1668,8 @@ class FurnaceGUI { int sampleTexW, sampleTexH; bool updateSampleTex; + FurnaceGUITexture* csTex; + String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile, sysSearchQuery, newSongQuery, paletteQuery, sampleBankSearchQuery; String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport; String workingDirVGMExport, workingDirROMExport; diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 240d0c8bd..e71f7f6b1 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -2318,6 +2318,32 @@ void FurnaceGUI::drawSampleEdit() { } } } + if (displayLoopHintsNDSA) { + if (sampleZoom<0.5) { + for (int i=0; i<(int)(sampleZoom*avail.x); i++) { + if (((i+samplePos)&7)==0) { + ImVec2 p1=ImVec2(rectMin.x+((float)i/sampleZoom),rectMin.y); + ImVec2 p2=p1; + p2.y=rectMax.y; + + dl->AddLine(p1,p2,ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_LOOP_HINT])); + } + } + } + } + if (displayLoopHintsNDS8) { + if (sampleZoom<0.375) { + for (int i=0; i<(int)(sampleZoom*avail.x); i++) { + if (((i+samplePos)&3)==0) { + ImVec2 p1=ImVec2(rectMin.x+((float)i/sampleZoom),rectMin.y); + ImVec2 p2=p1; + p2.y=rectMax.y; + + dl->AddLine(p1,p2,ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_LOOP_HINT])); + } + } + } + } if (displayLoopHintsAmiga) { if (sampleZoom<0.25) { for (int i=0; i<(int)(sampleZoom*avail.x); i++) { diff --git a/src/gui/tutorial.cpp b/src/gui/tutorial.cpp index 9b238be85..e06c52f6d 100644 --- a/src/gui/tutorial.cpp +++ b/src/gui/tutorial.cpp @@ -1313,7 +1313,7 @@ void FurnaceCV::buildStage(int which) { curStage=NULL; } - if (which>19 || which==4 || which==7 || which==9 || which==11 || which==13 || which==16 || which==17) { + if (which>18 || which==4 || which==7 || which==9 || which==11 || which==13 || which==16 || which==17) { stageWidth=80; stageHeight=56; } else { @@ -1346,26 +1346,7 @@ void FurnaceCV::buildStage(int which) { memset(busy,0,28*40*sizeof(bool)); // special stages - if ((which%10)==9) { - // vortex - for (int i=0; i<20+(which>>2); i++) { - int tries=0; - while (tries<20) { - int x=rand()%(stageWidth>>1); - int y=rand()%(stageHeight>>1); - int finalX=x<<4; - int finalY=y<<4; - if (busy[y][x]) { - tries++; - continue; - } - createObject(finalX,finalY); - createObject(finalX-4,finalY-4); - busy[y][x]=true; - break; - } - } - } else if ((which%10)==19) { + if ((which%20)==19) { for (int i=0; i<20+(which>>2); i++) { int tries=0; while (tries<20) { @@ -1387,6 +1368,25 @@ void FurnaceCV::buildStage(int which) { break; } } + } else if ((which%10)==9) { + // vortex + for (int i=0; i<20+(which>>2); i++) { + int tries=0; + while (tries<20) { + int x=rand()%(stageWidth>>1); + int y=rand()%(stageHeight>>1); + int finalX=x<<4; + int finalY=y<<4; + if (busy[y][x]) { + tries++; + continue; + } + createObject(finalX,finalY); + createObject(finalX-4,finalY-4); + busy[y][x]=true; + break; + } + } } else { // large if (which>=2) for (int i=0; i<(rand()%3)+which-2; i++) { @@ -1675,6 +1675,7 @@ void FurnaceCV::render(unsigned char joyIn) { lives+=lifeBank; respawnTime=1; lifeBank=0; + score=0; gameOver=false; }