furnace/src/engine/export/amigaValidation.cpp

215 lines
5.8 KiB
C++
Raw Normal View History

2023-03-13 15:17:05 -04:00
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2023 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "amigaValidation.h"
#include "../engine.h"
2023-03-13 21:01:01 -04:00
#include "../platform/amiga.h"
2023-03-13 15:17:05 -04:00
2023-03-16 02:44:35 -04:00
struct WaveEntry {
unsigned int pos;
short width;
signed char data[256];
WaveEntry():
pos(0),
width(32) {
memset(data,0,256);
}
};
2023-03-13 15:17:05 -04:00
std::vector<DivROMExportOutput> DivExportAmigaValidation::go(DivEngine* e) {
2023-03-13 21:01:01 -04:00
std::vector<DivROMExportOutput> ret;
2023-03-16 02:44:35 -04:00
std::vector<WaveEntry> waves;
unsigned int wavesDataPtr=0;
WaveEntry curWaveState[4];
2023-03-13 21:01:01 -04:00
DivPlatformAmiga* amiga=(DivPlatformAmiga*)e->getDispatch(0);
2023-03-13 15:17:05 -04:00
2023-03-13 21:01:01 -04:00
e->stop();
e->repeatPattern=false;
e->setOrder(0);
EXTERN_BUSY_BEGIN_SOFT;
// determine loop point
int loopOrder=0;
int loopRow=0;
int loopEnd=0;
e->walkSong(loopOrder,loopRow,loopEnd);
e->curOrder=0;
e->freelance=false;
e->playing=false;
e->extValuePresent=false;
e->remainingLoops=-1;
// play the song ourselves
bool done=false;
// sample.bin
SafeWriter* sample=new SafeWriter;
sample->init();
for (int i=0; i<256; i++) {
sample->writeI(0);
}
sample->write(&((const unsigned char*)amiga->getSampleMem(0))[0x400],amiga->getSampleMemUsage(0)-0x400);
if (sample->tell()&1) sample->writeC(0);
// seq.bin
SafeWriter* seq=new SafeWriter;
seq->init();
amiga->toggleRegisterDump(true);
// write song data
e->playSub(false);
size_t songTick=0;
size_t lastTick=0;
//bool writeLoop=false;
2023-03-13 21:01:01 -04:00
int loopPos=-1;
for (int i=0; i<e->chans; i++) {
e->chan[i].wentThroughNote=false;
e->chan[i].goneThroughNote=false;
}
while (!done) {
if (loopPos==-1) {
if (loopOrder==e->curOrder && loopRow==e->curRow && e->ticks==1) {
//writeLoop=true;
2023-03-13 21:01:01 -04:00
}
}
if (e->nextTick(false,true)) {
done=true;
amiga->getRegisterWrites().clear();
2023-03-16 02:44:35 -04:00
if (lastTick!=songTick) {
int delta=songTick-lastTick;
if (delta==1) {
seq->writeC(0xf1);
} else if (delta<256) {
seq->writeC(0xf2);
seq->writeC(delta-1);
} else if (delta<32768) {
seq->writeC(0xf3);
seq->writeS_BE(delta-1);
}
lastTick=songTick;
}
2023-03-13 21:01:01 -04:00
break;
}
2023-03-16 02:44:35 -04:00
// check wavetable changes
for (int i=0; i<4; i++) {
if (amiga->chan[i].useWave) {
if ((amiga->chan[i].audLen*2)!=curWaveState[i].width || memcmp(curWaveState[i].data,&(((signed char*)amiga->getSampleMem())[i<<8]),amiga->chan[i].audLen*2)!=0) {
curWaveState[i].width=amiga->chan[i].audLen*2;
memcpy(curWaveState[i].data,&(((signed char*)amiga->getSampleMem())[i<<8]),amiga->chan[i].audLen*2);
int waveNum=-1;
for (size_t j=0; j<waves.size(); j++) {
if (waves[j].width!=curWaveState[i].width) continue;
if (memcmp(waves[j].data,curWaveState[i].data,curWaveState[i].width)==0) {
waveNum=j;
break;
}
}
if (waveNum==-1) {
// write new wavetable
waveNum=(int)waves.size();
curWaveState[i].pos=wavesDataPtr;
waves.push_back(curWaveState[i]);
wavesDataPtr+=curWaveState[i].width;
}
seq->writeC((i<<4)|1);
seq->writeC(waves[waveNum].pos>>16);
seq->writeC(waves[waveNum].pos>>8);
seq->writeC(waves[waveNum].pos);
seq->writeS_BE(waves[waveNum].width);
}
}
}
2023-03-13 21:01:01 -04:00
// get register writes
std::vector<DivRegWrite>& writes=amiga->getRegisterWrites();
for (DivRegWrite& j: writes) {
if (lastTick!=songTick) {
int delta=songTick-lastTick;
if (delta==1) {
seq->writeC(0xf1);
} else if (delta<256) {
seq->writeC(0xf2);
seq->writeC(delta-1);
} else if (delta<32768) {
2023-03-13 21:01:01 -04:00
seq->writeC(0xf3);
seq->writeS_BE(delta-1);
2023-03-13 21:01:01 -04:00
}
lastTick=songTick;
}
if (j.addr>=0x200) { // direct loc/len change
if (j.addr&4) { // len
seq->writeS_BE(j.val);
} else { // loc
seq->writeC((j.addr&3)<<4);
seq->writeC(j.val>>16);
seq->writeC(j.val>>8);
seq->writeC(j.val);
}
} else if (j.addr<0xa0) {
// don't write INTENA
if ((j.addr&15)!=10) {
seq->writeC(0xf0|(j.addr&15));
seq->writeS_BE(j.val);
}
} else if ((j.addr&15)!=0 && (j.addr&15)!=2 && (j.addr&15)!=4) {
seq->writeC(j.addr-0xa0);
if ((j.addr&15)==8) {
seq->writeC(j.val);
} else {
seq->writeS_BE(j.val);
}
}
}
writes.clear();
songTick++;
}
// end of song
seq->writeC(0xff);
amiga->toggleRegisterDump(false);
e->remainingLoops=-1;
e->playing=false;
e->freelance=false;
e->extValuePresent=false;
EXTERN_BUSY_END;
2023-03-16 02:44:35 -04:00
// wave.bin
SafeWriter* wave=new SafeWriter;
wave->init();
for (WaveEntry& i: waves) {
wave->write(i.data,i.width);
}
2023-03-13 21:01:01 -04:00
// finish
ret.push_back(DivROMExportOutput("sample.bin",sample));
ret.push_back(DivROMExportOutput("wave.bin",wave));
ret.push_back(DivROMExportOutput("seq.bin",seq));
return ret;
2023-03-13 15:17:05 -04:00
}