Merge branch 'tildearrow:master' into spectrum
This commit is contained in:
commit
2c5ca6026e
11 changed files with 160 additions and 36 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
long p=loopStart;
|
||||
for (int i=0; i<17; i++) {
|
||||
if (p>=len) {
|
||||
|
|
|
|||
|
|
@ -682,6 +682,11 @@ bool DivCSPlayer::init() {
|
|||
chan[i].readPos=chan[i].startPos;
|
||||
}
|
||||
}
|
||||
|
||||
// read stack sizes
|
||||
for (unsigned int i=0; i<fileChans; i++) {
|
||||
chan[i].callStackSize=stream.readC();
|
||||
}
|
||||
|
||||
// initialize state
|
||||
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||
|
|
|
|||
|
|
@ -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<DIV_MAX_CSTRACE; i++) {
|
||||
trace[i]=0;
|
||||
|
|
|
|||
|
|
@ -377,6 +377,10 @@ void DivPlatformMMC5::forceIns() {
|
|||
for (int i=0; i<3; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].prevFreq=65535;
|
||||
if (i<2) {
|
||||
// TODO: implement envelope mode
|
||||
rWrite(0x5000+i*4,(0x30)|(chan[i].active?chan[i].outVol:0)|((chan[i].duty&3)<<6));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -429,6 +433,10 @@ void DivPlatformMMC5::reset() {
|
|||
|
||||
rWrite(0x5015,0x03);
|
||||
rWrite(0x5010,0x00);
|
||||
|
||||
for (int i=0; i<2; i++) {
|
||||
rWrite(0x5000+i*4,(0x30)|0|((chan[i].duty&3)<<6));
|
||||
}
|
||||
}
|
||||
|
||||
bool DivPlatformMMC5::keyOffAffectsArp(int ch) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@
|
|||
#define PCM_CHECK(ch) ((chipType==4) && (ch>=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; i<sampleCount; i++) {
|
||||
sampleLoaded[i]=false;
|
||||
}
|
||||
sampleCount=maxSample;
|
||||
}
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
|
|
@ -3335,7 +3344,7 @@ void DivPlatformOPL::renderSamples(int sysID) {
|
|||
// instrument table
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
DivSample* s=parent->song.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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; i<chans; i++) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d",i);
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
for (int i=0; i<chans; i++) {
|
||||
DivCSChannelState* state=cs->getChanState(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; i<bufSize; i++) {
|
||||
float cellAlpha=(float)(fadeTime-(((short)(csTick&0xffff))-(short)accessTS[i]))/fadeTime;
|
||||
if (cellAlpha>0.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; i<e->getTotalChannelCount(); 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; i<cs->getFileChans(); i++) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%d",cs->getChanState(i)->callStackSize);
|
||||
}
|
||||
ImGui::Text("ticks: %u",cs->getCurTick());
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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<FurnaceCVEnemyVortex>(finalX,finalY);
|
||||
createObject<FurnaceCVFurBallMedium>(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<FurnaceCVEnemyVortex>(finalX,finalY);
|
||||
createObject<FurnaceCVFurBallMedium>(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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue