Merge branch 'tildearrow:master' into master

This commit is contained in:
BlastBrothers 2022-04-11 10:15:47 -04:00 committed by GitHub
commit 72632b9b72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
105 changed files with 3745 additions and 3039 deletions

View file

@ -44,18 +44,18 @@ bool TAMidiInRtMidi::gather() {
std::vector<String> TAMidiInRtMidi::listDevices() {
std::vector<String> ret;
logD("listing devices.\n");
logD("listing devices.");
if (port==NULL) return ret;
try {
unsigned int count=port->getPortCount();
logD("got port count.\n");
logD("got port count.");
for (unsigned int i=0; i<count; i++) {
String name=port->getPortName(i);
if (name!="") ret.push_back(name);
}
} catch (RtMidiError& e) {
logW("could not get MIDI inputs! %s\n",e.what());
logW("could not get MIDI inputs! %s",e.what());
}
return ret;
}
@ -78,10 +78,10 @@ bool TAMidiInRtMidi::openDevice(String name) {
}
}
isOpen=portOpen;
if (!portOpen) logW("could not find MIDI in device...\n");
if (!portOpen) logW("could not find MIDI in device...");
return portOpen;
} catch (RtMidiError& e) {
logW("could not open MIDI in device! %s\n",e.what());
logW("could not open MIDI in device! %s",e.what());
return false;
}
return true;
@ -93,7 +93,7 @@ bool TAMidiInRtMidi::closeDevice() {
try {
port->closePort();
} catch (RtMidiError& e) {
logW("could not close MIDI in device! %s\n",e.what());
logW("could not close MIDI in device! %s",e.what());
isOpen=false; // still
return false;
}
@ -106,7 +106,7 @@ bool TAMidiInRtMidi::init() {
try {
port=new RtMidiIn;
} catch (RtMidiError& e) {
logW("could not initialize RtMidi in! %s\n",e.what());
logW("could not initialize RtMidi in! %s",e.what());
return false;
}
return true;
@ -176,10 +176,10 @@ bool TAMidiOutRtMidi::openDevice(String name) {
}
}
isOpen=portOpen;
if (!portOpen) logW("could not find MIDI out device...\n");
if (!portOpen) logW("could not find MIDI out device...");
return portOpen;
} catch (RtMidiError& e) {
logW("could not open MIDI out device! %s\n",e.what());
logW("could not open MIDI out device! %s",e.what());
return false;
}
return true;
@ -191,7 +191,7 @@ bool TAMidiOutRtMidi::closeDevice() {
try {
port->closePort();
} catch (RtMidiError& e) {
logW("could not close MIDI out device! %s\n",e.what());
logW("could not close MIDI out device! %s",e.what());
isOpen=false; // still
return false;
}
@ -210,7 +210,7 @@ std::vector<String> TAMidiOutRtMidi::listDevices() {
if (name!="") ret.push_back(name);
}
} catch (RtMidiError& e) {
logW("could not get MIDI outputs! %s\n",e.what());
logW("could not get MIDI outputs! %s",e.what());
}
return ret;
}
@ -220,7 +220,7 @@ bool TAMidiOutRtMidi::init() {
try {
port=new RtMidiOut;
} catch (RtMidiError& e) {
logW("could not initialize RtMidi out! %s\n",e.what());
logW("could not initialize RtMidi out! %s",e.what());
return false;
}
return true;

View file

@ -75,7 +75,7 @@ std::vector<String> TAAudioSDL::listAudioDevices() {
std::vector<String> ret;
if (!audioSysStarted) {
if (SDL_Init(SDL_INIT_AUDIO)<0) {
logE("could not initialize SDL to list audio devices\n");
logE("could not initialize SDL to list audio devices");
} else {
audioSysStarted=true;
}
@ -96,12 +96,12 @@ std::vector<String> TAAudioSDL::listAudioDevices() {
bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) {
if (initialized) {
logE("audio already initialized\n");
logE("audio already initialized");
return false;
}
if (!audioSysStarted) {
if (SDL_Init(SDL_INIT_AUDIO)<0) {
logE("could not initialize SDL\n");
logE("could not initialize SDL");
return false;
}
audioSysStarted=true;
@ -119,7 +119,7 @@ bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) {
ai=SDL_OpenAudioDevice(request.deviceName.empty()?NULL:request.deviceName.c_str(),0,&ac,&ar,SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (ai==0) {
logE("could not open audio device: %s\n",SDL_GetError());
logE("could not open audio device: %s",SDL_GetError());
return false;
}

View file

@ -32,13 +32,13 @@ bool DivEngine::saveConf() {
configFile=configPath+String(CONFIG_FILE);
FILE* f=ps_fopen(configFile.c_str(),"wb");
if (f==NULL) {
logW("could not write config file! %s\n",strerror(errno));
logW("could not write config file! %s",strerror(errno));
return false;
}
for (auto& i: conf) {
String toWrite=fmt::sprintf("%s=%s\n",i.first,i.second);
if (fwrite(toWrite.c_str(),1,toWrite.size(),f)!=toWrite.size()) {
logW("could not write config file! %s\n",strerror(errno));
logW("could not write config file! %s",strerror(errno));
fclose(f);
return false;
}
@ -52,10 +52,10 @@ bool DivEngine::loadConf() {
configFile=configPath+String(CONFIG_FILE);
FILE* f=ps_fopen(configFile.c_str(),"rb");
if (f==NULL) {
logI("creating default config.\n");
logI("creating default config.");
return saveConf();
}
logI("loading config.\n");
logI("loading config.");
while (!feof(f)) {
String key="";
String value="";

View file

@ -56,6 +56,7 @@ enum DivDispatchCmds {
DIV_CMD_SAMPLE_BANK,
DIV_CMD_SAMPLE_POS,
DIV_CMD_FM_HARD_RESET,
DIV_CMD_FM_LFO,
DIV_CMD_FM_LFO_WAVE,
DIV_CMD_FM_TL,
@ -319,6 +320,18 @@ class DivDispatch {
*/
virtual int getPortaFloor(int ch);
/**
* get the required amplification level of this dispatch's output.
* @return the amplification level.
*/
virtual float getPostAmp();
/**
* check whether DC offset correction is required.
* @return truth.
*/
virtual bool getDCOffRequired();
/**
* get a description of a dispatch-specific effect.
* @param effect the effect.

View file

@ -79,6 +79,11 @@ void DivDispatchContainer::flush(size_t count) {
}
void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) {
if (dcOffCompensation && runtotal>0) {
dcOffCompensation=false;
prevSample[0]=bbIn[0][0];
if (dispatch->isStereo()) prevSample[1]=bbIn[1][0];
}
if (lowQuality) {
for (size_t i=0; i<runtotal; i++) {
temp[0]=bbIn[0][i];
@ -126,6 +131,9 @@ void DivDispatchContainer::clear() {
temp[1]=0;
prevSample[0]=0;
prevSample[1]=0;
if (dispatch->getDCOffRequired()) {
dcOffCompensation=true;
}
// run for one cycle to determine DC offset
// TODO: SAA1099 doesn't like that
/*dispatch->acquire(bbIn[0],bbIn[1],0,1);
@ -140,13 +148,13 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
bb[0]=blip_new(32768);
if (bb[0]==NULL) {
logE("not enough memory!\n");
logE("not enough memory!");
return;
}
bb[1]=blip_new(32768);
if (bb[1]==NULL) {
logE("not enough memory!\n");
logE("not enough memory!");
return;
}
@ -304,7 +312,7 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
dispatch=new DivPlatformMMC5;
break;
default:
logW("this system is not supported yet! using dummy platform.\n");
logW("this system is not supported yet! using dummy platform.");
dispatch=new DivPlatformDummy;
break;
}

View file

@ -17,9 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "dataErrors.h"
#include "song.h"
#include <functional>
#define _USE_MATH_DEFINES
#include "engine.h"
#include "instrument.h"
@ -196,7 +193,7 @@ void DivEngine::runExportThread() {
sf=sf_open(exportPath.c_str(),SFM_WRITE,&si);
if (sf==NULL) {
logE("could not open file for writing! (%s)\n",sf_strerror(NULL));
logE("could not open file for writing! (%s)",sf_strerror(NULL));
exporting=false;
return;
}
@ -210,7 +207,7 @@ void DivEngine::runExportThread() {
deinitAudioBackend();
playSub(false);
logI("rendering to file...\n");
logI("rendering to file...");
while (playing) {
nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE);
@ -219,10 +216,10 @@ void DivEngine::runExportThread() {
outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]));
}
if (totalProcessed>EXPORT_BUFSIZE) {
logE("error: total processed is bigger than export bufsize! %d>%d\n",totalProcessed,EXPORT_BUFSIZE);
logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE);
}
if (sf_writef_float(sf,outBuf[2],totalProcessed)!=(int)totalProcessed) {
logE("error: failed to write entire buffer!\n");
logE("error: failed to write entire buffer!");
break;
}
}
@ -232,7 +229,7 @@ void DivEngine::runExportThread() {
delete[] outBuf[2];
if (sf_close(sf)!=0) {
logE("could not close audio file!\n");
logE("could not close audio file!");
}
exporting=false;
@ -242,10 +239,10 @@ void DivEngine::runExportThread() {
disCont[i].setQuality(lowQuality);
}
if (!output->setRun(true)) {
logE("error while activating audio!\n");
logE("error while activating audio!");
}
}
logI("done!\n");
logI("done!");
break;
}
case DIV_EXPORT_MODE_MANY_SYS: {
@ -265,10 +262,10 @@ void DivEngine::runExportThread() {
for (int i=0; i<song.systemLen; i++) {
fname[i]=fmt::sprintf("%s_s%02d.wav",exportPath,i+1);
logI("- %s\n",fname[i].c_str());
logI("- %s",fname[i].c_str());
sf[i]=sf_open(fname[i].c_str(),SFM_WRITE,&si[i]);
if (sf[i]==NULL) {
logE("could not open file for writing! (%s)\n",sf_strerror(NULL));
logE("could not open file for writing! (%s)",sf_strerror(NULL));
for (int j=0; j<i; j++) {
sf_close(sf[i]);
}
@ -285,7 +282,7 @@ void DivEngine::runExportThread() {
deinitAudioBackend();
playSub(false);
logI("rendering to files...\n");
logI("rendering to files...");
while (playing) {
nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE);
@ -299,10 +296,10 @@ void DivEngine::runExportThread() {
}
}
if (totalProcessed>EXPORT_BUFSIZE) {
logE("error: total processed is bigger than export bufsize! (%d) %d>%d\n",i,totalProcessed,EXPORT_BUFSIZE);
logE("error: total processed is bigger than export bufsize! (%d) %d>%d",i,totalProcessed,EXPORT_BUFSIZE);
}
if (sf_writef_short(sf[i],sysBuf,totalProcessed)!=(int)totalProcessed) {
logE("error: failed to write entire buffer! (%d)\n",i);
logE("error: failed to write entire buffer! (%d)",i);
break;
}
}
@ -314,7 +311,7 @@ void DivEngine::runExportThread() {
for (int i=0; i<song.systemLen; i++) {
if (sf_close(sf[i])!=0) {
logE("could not close audio file!\n");
logE("could not close audio file!");
}
}
exporting=false;
@ -325,10 +322,10 @@ void DivEngine::runExportThread() {
disCont[i].setQuality(lowQuality);
}
if (!output->setRun(true)) {
logE("error while activating audio!\n");
logE("error while activating audio!");
}
}
logI("done!\n");
logI("done!");
break;
}
case DIV_EXPORT_MODE_MANY_CHAN: {
@ -341,20 +338,20 @@ void DivEngine::runExportThread() {
outBuf[2]=new float[EXPORT_BUFSIZE*2];
int loopCount=remainingLoops;
logI("rendering to files...\n");
logI("rendering to files...");
for (int i=0; i<chans; i++) {
SNDFILE* sf;
SF_INFO si;
String fname=fmt::sprintf("%s_c%02d.wav",exportPath,i+1);
logI("- %s\n",fname.c_str());
logI("- %s",fname.c_str());
si.samplerate=got.rate;
si.channels=2;
si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
sf=sf_open(fname.c_str(),SFM_WRITE,&si);
if (sf==NULL) {
logE("could not open file for writing! (%s)\n",sf_strerror(NULL));
logE("could not open file for writing! (%s)",sf_strerror(NULL));
break;
}
@ -377,16 +374,16 @@ void DivEngine::runExportThread() {
outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j]));
}
if (totalProcessed>EXPORT_BUFSIZE) {
logE("error: total processed is bigger than export bufsize! %d>%d\n",totalProcessed,EXPORT_BUFSIZE);
logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE);
}
if (sf_writef_float(sf,outBuf[2],totalProcessed)!=(int)totalProcessed) {
logE("error: failed to write entire buffer!\n");
logE("error: failed to write entire buffer!");
break;
}
}
if (sf_close(sf)!=0) {
logE("could not close audio file!\n");
logE("could not close audio file!");
}
}
exporting=false;
@ -408,10 +405,10 @@ void DivEngine::runExportThread() {
disCont[i].setQuality(lowQuality);
}
if (!output->setRun(true)) {
logE("error while activating audio!\n");
logE("error while activating audio!");
}
}
logI("done!\n");
logI("done!");
break;
}
}
@ -482,12 +479,12 @@ void DivEngine::renderSamples() {
memPos=(memPos+0xfffff)&0xf00000;
}
if (memPos>=16777216) {
logW("out of ADPCM-A memory for sample %d!\n",i);
logW("out of ADPCM-A memory for sample %d!",i);
break;
}
if (memPos+paddedLen>=16777216) {
memcpy(adpcmAMem+memPos,s->dataA,16777216-memPos);
logW("out of ADPCM-A memory for sample %d!\n",i);
logW("out of ADPCM-A memory for sample %d!",i);
} else {
memcpy(adpcmAMem+memPos,s->dataA,paddedLen);
}
@ -507,12 +504,12 @@ void DivEngine::renderSamples() {
memPos=(memPos+0xfffff)&0xf00000;
}
if (memPos>=16777216) {
logW("out of ADPCM-B memory for sample %d!\n",i);
logW("out of ADPCM-B memory for sample %d!",i);
break;
}
if (memPos+paddedLen>=16777216) {
memcpy(adpcmBMem+memPos,s->dataB,16777216-memPos);
logW("out of ADPCM-B memory for sample %d!\n",i);
logW("out of ADPCM-B memory for sample %d!",i);
} else {
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
}
@ -536,14 +533,14 @@ void DivEngine::renderSamples() {
memPos=(memPos+0xffff)&0xff0000;
}
if (memPos>=16777216) {
logW("out of QSound PCM memory for sample %d!\n",i);
logW("out of QSound PCM memory for sample %d!",i);
break;
}
if (memPos+length>=16777216) {
for (unsigned int i=0; i<16777216-(memPos+length); i++) {
qsoundMem[(memPos+i)^0x8000]=s->data8[i];
}
logW("out of QSound PCM memory for sample %d!\n",i);
logW("out of QSound PCM memory for sample %d!",i);
} else {
for (int i=0; i<length; i++) {
qsoundMem[(memPos+i)^0x8000]=s->data8[i];
@ -570,12 +567,12 @@ void DivEngine::renderSamples() {
memPos=(memPos+0x1ffff)&0xfe0000;
}
if (memPos>=1048576) {
logW("out of X1-010 memory for sample %d!\n",i);
logW("out of X1-010 memory for sample %d!",i);
break;
}
if (memPos+paddedLen>=1048576) {
memcpy(x1_010Mem+memPos,s->data8,1048576-memPos);
logW("out of X1-010 memory for sample %d!\n",i);
logW("out of X1-010 memory for sample %d!",i);
} else {
memcpy(x1_010Mem+memPos,s->data8,paddedLen);
}
@ -767,6 +764,7 @@ void DivEngine::getCommandStream(std::vector<DivCommand>& where) {
}
void DivEngine::playSub(bool preserveDrift, int goalRow) {
std::chrono::high_resolution_clock::time_point timeStart=std::chrono::high_resolution_clock::now();
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false);
reset();
if (preserveDrift && curOrder==0) return;
@ -825,6 +823,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
}
skipping=false;
cmdStream.clear();
std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now();
logV("playSub() took %dµs",std::chrono::duration_cast<std::chrono::microseconds>(timeEnd-timeStart).count());
}
/*
@ -873,6 +873,11 @@ void DivEngine::play() {
for (int i=0; i<DIV_MAX_CHANS; i++) {
keyHit[i]=false;
}
if (output) if (!skipping && output->midiOut!=NULL) {
int pos=totalTicksR/6;
output->midiOut->send(TAMidiMessage(TA_MIDI_POSITION,(pos>>7)&0x7f,pos&0x7f));
output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_PLAY,0,0));
}
BUSY_END;
}
@ -918,6 +923,14 @@ void DivEngine::stop() {
for (int i=0; i<song.systemLen; i++) {
disCont[i].dispatch->notifyPlaybackStop();
}
if (output) if (output->midiOut!=NULL) {
output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_STOP,0,0));
for (int i=0; i<chans; i++) {
if (chan[i].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(i&15),chan[i].curMidiNote,0));
}
}
}
BUSY_END;
}
@ -1281,7 +1294,7 @@ void DivEngine::delInstrument(int index) {
song.ins.erase(song.ins.begin()+index);
song.insLen=song.ins.size();
for (int i=0; i<chans; i++) {
for (int j=0; j<128; j++) {
for (int j=0; j<256; j++) {
if (song.pat[i].data[j]==NULL) continue;
for (int k=0; k<song.patLen; k++) {
if (song.pat[i].data[j]->data[k][2]>index) {
@ -1333,7 +1346,7 @@ bool DivEngine::addWaveFromFile(const char* path) {
}
buf=new unsigned char[len];
if (fread(buf,1,len,f)!=(size_t)len) {
logW("did not read entire wavetable file buffer!\n");
logW("did not read entire wavetable file buffer!");
delete[] buf;
return false;
}
@ -1373,22 +1386,22 @@ bool DivEngine::addWaveFromFile(const char* path) {
wave->max=(unsigned char)reader.readC();
if (wave->max==255) { // new wavetable format
unsigned char waveVersion=reader.readC();
logI("reading modern .dmw...\n");
logD("wave version %d\n",waveVersion);
logI("reading modern .dmw...");
logD("wave version %d",waveVersion);
wave->max=reader.readC();
for (int i=0; i<len; i++) {
wave->data[i]=reader.readI();
}
} else if (reader.size()==(size_t)(len+5)) {
// read as .dmw
logI("reading .dmw...\n");
logI("reading .dmw...");
if (len>256) len=256;
for (int i=0; i<len; i++) {
wave->data[i]=(unsigned char)reader.readC();
}
} else {
// read as binary
logI("reading binary...\n");
logI("reading binary...");
len=reader.size();
if (len>256) len=256;
reader.seek(0,SEEK_SET);
@ -1401,7 +1414,7 @@ bool DivEngine::addWaveFromFile(const char* path) {
} catch (EndOfFileException& e) {
// read as binary
len=reader.size();
logI("reading binary for being too small...\n");
logI("reading binary for being too small...");
if (len>256) len=256;
reader.seek(0,SEEK_SET);
for (int i=0; i<len; i++) {
@ -1475,7 +1488,7 @@ int DivEngine::addSampleFromFile(const char* path) {
}
short* buf=new short[si.channels*si.frames];
if (sf_readf_short(f,buf,si.frames)!=si.frames) {
logW("sample read size mismatch!\n");
logW("sample read size mismatch!");
}
DivSample* sample=new DivSample;
int sampleCount=(int)song.sample.size();
@ -1556,7 +1569,7 @@ void DivEngine::delSample(int index) {
void DivEngine::addOrder(bool duplicate, bool where) {
unsigned char order[DIV_MAX_CHANS];
if (song.ordersLen>=0x7e) return;
if (song.ordersLen>=0xff) return;
BUSY_BEGIN_SOFT;
if (duplicate) {
for (int i=0; i<DIV_MAX_CHANS; i++) {
@ -1569,7 +1582,7 @@ void DivEngine::addOrder(bool duplicate, bool where) {
for (int j=0; j<song.ordersLen; j++) {
used[song.orders.ord[i][j]]=true;
}
order[i]=0x7e;
order[i]=0xff;
for (int j=0; j<256; j++) {
if (!used[j]) {
order[i]=j;
@ -1605,23 +1618,23 @@ void DivEngine::addOrder(bool duplicate, bool where) {
void DivEngine::deepCloneOrder(bool where) {
unsigned char order[DIV_MAX_CHANS];
if (song.ordersLen>=0x7e) return;
if (song.ordersLen>=0xff) return;
warnings="";
BUSY_BEGIN_SOFT;
for (int i=0; i<chans; i++) {
bool didNotFind=true;
logD("channel %d\n",i);
logD("channel %d",i);
order[i]=song.orders.ord[i][curOrder];
// find free slot
for (int j=0; j<128; j++) {
logD("finding free slot in %d...\n",j);
for (int j=0; j<256; j++) {
logD("finding free slot in %d...",j);
if (song.pat[i].data[j]==NULL) {
int origOrd=order[i];
order[i]=j;
DivPattern* oldPat=song.pat[i].getPattern(origOrd,false);
DivPattern* pat=song.pat[i].getPattern(j,true);
memcpy(pat->data,oldPat->data,256*32*sizeof(short));
logD("found at %d\n",j);
logD("found at %d",j);
didNotFind=false;
break;
}
@ -1715,7 +1728,7 @@ void DivEngine::moveOrderDown() {
void DivEngine::exchangeIns(int one, int two) {
for (int i=0; i<chans; i++) {
for (int j=0; j<128; j++) {
for (int j=0; j<256; j++) {
if (song.pat[i].data[j]==NULL) continue;
for (int k=0; k<song.patLen; k++) {
if (song.pat[i].data[j]->data[k][2]==one) {
@ -1940,7 +1953,7 @@ bool DivEngine::switchMaster() {
disCont[i].setQuality(lowQuality);
}
if (!output->setRun(true)) {
logE("error while activating audio!\n");
logE("error while activating audio!");
return false;
}
} else {
@ -2058,9 +2071,9 @@ void DivEngine::quitDispatch() {
#define CHECK_CONFIG_DIR_MAC() \
configPath+="/Library/Application Support/Furnace"; \
if (stat(configPath.c_str(),&st)<0) { \
logI("creating config dir...\n"); \
logI("creating config dir..."); \
if (mkdir(configPath.c_str(),0755)<0) { \
logW("could not make config dir! (%s)\n",strerror(errno)); \
logW("could not make config dir! (%s)",strerror(errno)); \
configPath="."; \
} \
}
@ -2068,18 +2081,18 @@ void DivEngine::quitDispatch() {
#define CHECK_CONFIG_DIR() \
configPath+="/.config"; \
if (stat(configPath.c_str(),&st)<0) { \
logI("creating user config dir...\n"); \
logI("creating user config dir..."); \
if (mkdir(configPath.c_str(),0755)<0) { \
logW("could not make user config dir! (%s)\n",strerror(errno)); \
logW("could not make user config dir! (%s)",strerror(errno)); \
configPath="."; \
} \
} \
if (configPath!=".") { \
configPath+="/furnace"; \
if (stat(configPath.c_str(),&st)<0) { \
logI("creating config dir...\n"); \
logI("creating config dir..."); \
if (mkdir(configPath.c_str(),0755)<0) { \
logW("could not make config dir! (%s)\n",strerror(errno)); \
logW("could not make config dir! (%s)",strerror(errno)); \
configPath="."; \
} \
} \
@ -2101,7 +2114,7 @@ bool DivEngine::initAudioBackend() {
switch (audioEngine) {
case DIV_AUDIO_JACK:
#ifndef HAVE_JACK
logE("Furnace was not compiled with JACK support!\n");
logE("Furnace was not compiled with JACK support!");
setConf("audioEngine","SDL");
saveConf();
output=new TAAudioSDL;
@ -2116,7 +2129,7 @@ bool DivEngine::initAudioBackend() {
output=new TAAudio;
break;
default:
logE("invalid audio engine!\n");
logE("invalid audio engine!");
return false;
}
@ -2134,7 +2147,7 @@ bool DivEngine::initAudioBackend() {
output->setCallback(process,this);
if (!output->init(want,got)) {
logE("error while initializing audio!\n");
logE("error while initializing audio!");
delete output;
output=NULL;
audioEngine=DIV_AUDIO_NULL;
@ -2145,15 +2158,15 @@ bool DivEngine::initAudioBackend() {
midiIns=output->midiIn->listDevices();
midiOuts=output->midiOut->listDevices();
} else {
logW("error while initializing MIDI!\n");
logW("error while initializing MIDI!");
}
if (output->midiIn) {
String inName=getConfString("midiInDevice","");
if (!inName.empty()) {
// try opening device
logI("opening MIDI input.\n");
logI("opening MIDI input.");
if (!output->midiIn->openDevice(inName)) {
logW("could not open MIDI input device!\n");
logW("could not open MIDI input device!");
}
}
}
@ -2161,9 +2174,9 @@ bool DivEngine::initAudioBackend() {
String outName=getConfString("midiOutDevice","");
if (!outName.empty()) {
// try opening device
logI("opening MIDI output.\n");
logI("opening MIDI output.");
if (!output->midiOut->openDevice(outName)) {
logW("could not open MIDI output device!\n");
logW("could not open MIDI output device!");
}
}
}
@ -2175,13 +2188,13 @@ bool DivEngine::deinitAudioBackend() {
if (output!=NULL) {
if (output->midiIn) {
if (output->midiIn->isDeviceOpen()) {
logI("closing MIDI input.\n");
logI("closing MIDI input.");
output->midiIn->closeDevice();
}
}
if (output->midiOut) {
if (output->midiOut->isDeviceOpen()) {
logI("closing MIDI output.\n");
logI("closing MIDI output.");
output->midiOut->closeDevice();
}
}
@ -2209,7 +2222,7 @@ bool DivEngine::init() {
int uid=getuid();
struct passwd* entry=getpwuid(uid);
if (entry==NULL) {
logW("unable to determine config directory! (%s)\n",strerror(errno));
logW("unable to determine config directory! (%s)",strerror(errno));
configPath=".";
} else {
configPath=entry->pw_dir;
@ -2228,21 +2241,21 @@ bool DivEngine::init() {
#endif
}
#endif
logD("config path: %s\n",configPath.c_str());
logD("config path: %s",configPath.c_str());
loadConf();
// init the rest of engine
bool haveAudio=false;
if (!initAudioBackend()) {
logE("no audio output available!\n");
logE("no audio output available!");
} else {
haveAudio=true;
}
samp_bb=blip_new(32768);
if (samp_bb==NULL) {
logE("not enough memory!\n");
logE("not enough memory!");
return false;
}
@ -2277,7 +2290,7 @@ bool DivEngine::init() {
return false;
} else {
if (!output->setRun(true)) {
logE("error while activating!\n");
logE("error while activating!");
return false;
}
}
@ -2287,7 +2300,7 @@ bool DivEngine::init() {
bool DivEngine::quit() {
deinitAudioBackend();
quitDispatch();
logI("saving config.\n");
logI("saving config.");
saveConf();
active=false;
delete[] oscBuf[0];

View file

@ -42,8 +42,8 @@
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
#define BUSY_END isBusy.unlock(); softLocked=false;
#define DIV_VERSION "dev79"
#define DIV_ENGINE_VERSION 79
#define DIV_VERSION "dev81"
#define DIV_ENGINE_VERSION 81
// for imports
#define DIV_VERSION_MOD 0xff01
@ -86,7 +86,8 @@ struct DivChannelState {
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp;
int midiNote, curMidiNote;
int midiNote, curMidiNote, midiPitch;
bool midiAftertouch;
DivChannelState():
note(-1),
@ -130,7 +131,9 @@ struct DivChannelState {
noteOnInhibit(false),
resetArp(false),
midiNote(-1),
curMidiNote(-1) {}
curMidiNote(-1),
midiPitch(-1),
midiAftertouch(false) {}
};
struct DivNoteEvent {
@ -151,7 +154,7 @@ struct DivDispatchContainer {
int temp[2], prevSample[2];
short* bbIn[2];
short* bbOut[2];
bool lowQuality;
bool lowQuality, dcOffCompensation;
void setRates(double gotRate);
void setQuality(bool lowQual);
@ -169,7 +172,8 @@ struct DivDispatchContainer {
prevSample{0,0},
bbIn{NULL,NULL},
bbOut{NULL,NULL},
lowQuality(false) {}
lowQuality(false),
dcOffCompensation(false) {}
};
class DivEngine {
@ -295,6 +299,7 @@ class DivEngine {
bool keyHit[DIV_MAX_CHANS];
float* oscBuf[2];
float oscSize;
int oscReadPos, oscWritePos;
void runExportThread();
void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size);
@ -769,6 +774,8 @@ class DivEngine {
totalProcessed(0),
oscBuf{NULL,NULL},
oscSize(1),
oscReadPos(0),
oscWritePos(0),
adpcmAMem(NULL),
adpcmAMemLen(0),
adpcmBMem(NULL),

File diff suppressed because it is too large Load diff

View file

@ -41,10 +41,10 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
try {
reader.seek(0,SEEK_SET);
version=reader.readC();
logD(".dmp version %d\n",version);
logD(".dmp version %d",version);
} catch (EndOfFileException& e) {
lastError="premature end of file";
logE("premature end of file!\n");
logE("premature end of file!");
delete ins;
return;
}
@ -64,38 +64,38 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
switch (sys) {
case 1: // YMU759
ins->type=DIV_INS_FM;
logD("instrument type is YMU759\n");
logD("instrument type is YMU759");
break;
case 2: // Genesis
ins->type=DIV_INS_FM;
logD("instrument type is Genesis\n");
logD("instrument type is Genesis");
break;
case 3: // SMS
ins->type=DIV_INS_STD;
logD("instrument type is SMS\n");
logD("instrument type is SMS");
break;
case 4: // Game Boy
ins->type=DIV_INS_GB;
logD("instrument type is Game Boy\n");
logD("instrument type is Game Boy");
break;
case 5: // PC Engine
ins->type=DIV_INS_PCE;
logD("instrument type is PC Engine\n");
logD("instrument type is PC Engine");
break;
case 6: // NES
ins->type=DIV_INS_STD;
logD("instrument type is NES\n");
logD("instrument type is NES");
break;
case 7: case 0x17: // C64
ins->type=DIV_INS_C64;
logD("instrument type is C64\n");
logD("instrument type is C64");
break;
case 8: // Arcade
ins->type=DIV_INS_FM;
logD("instrument type is Arcade\n");
logD("instrument type is Arcade");
break;
default:
logD("instrument type is unknown\n");
logD("instrument type is unknown");
lastError="unknown instrument type!";
delete ins;
return;
@ -103,7 +103,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
}
} catch (EndOfFileException& e) {
lastError="premature end of file";
logE("premature end of file!\n");
logE("premature end of file!");
delete ins;
return;
}
@ -113,7 +113,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
bool mode=true;
if (version>1) {
mode=reader.readC();
logD("instrument mode is %d\n",mode);
logD("instrument mode is %d",mode);
if (mode==0) {
if (version<11) {
ins->type=DIV_INS_STD;
@ -126,7 +126,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
}
if (mode) { // FM
logD("reading FM data...\n");
logD("reading FM data...");
if (version<10) {
if (version>1) {
// bullcrap! no way to determine the instrument type other than a vague FM/STD!
@ -151,7 +151,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
if (sys!=1) ins->fm.ams=reader.readC();
for (int j=0; j<ins->fm.ops; j++) {
logD("OP%d is at %d\n",j,reader.tell());
logD("OP%d is at %d",j,reader.tell());
ins->fm.op[j].mult=reader.readC();
ins->fm.op[j].tl=reader.readC();
ins->fm.op[j].ar=reader.readC();
@ -179,81 +179,81 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
}
}
} else { // STD
logD("reading STD data...\n");
logD("reading STD data...");
if (ins->type!=DIV_INS_GB) {
ins->std.volMacroLen=reader.readC();
ins->std.volMacro.len=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.volMacroLen; i++) {
ins->std.volMacro[i]=reader.readI();
for (int i=0; i<ins->std.volMacro.len; i++) {
ins->std.volMacro.val[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.volMacroLen; i++) {
ins->std.volMacro[i]=reader.readC();
for (int i=0; i<ins->std.volMacro.len; i++) {
ins->std.volMacro.val[i]=reader.readC();
}
}
if (version<11) for (int i=0; i<ins->std.volMacroLen; i++) {
if (ins->std.volMacro[i]>15 && ins->type==DIV_INS_STD) ins->type=DIV_INS_PCE;
if (version<11) for (int i=0; i<ins->std.volMacro.len; i++) {
if (ins->std.volMacro.val[i]>15 && ins->type==DIV_INS_STD) ins->type=DIV_INS_PCE;
}
if (ins->std.volMacroLen>0) {
ins->std.volMacroOpen=true;
ins->std.volMacroLoop=reader.readC();
if (ins->std.volMacro.len>0) {
ins->std.volMacro.open=true;
ins->std.volMacro.loop=reader.readC();
} else {
ins->std.volMacroOpen=false;
ins->std.volMacro.open=false;
}
}
ins->std.arpMacroLen=reader.readC();
ins->std.arpMacro.len=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.arpMacroLen; i++) {
ins->std.arpMacro[i]=reader.readI();
for (int i=0; i<ins->std.arpMacro.len; i++) {
ins->std.arpMacro.val[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.arpMacroLen; i++) {
ins->std.arpMacro[i]=reader.readC();
for (int i=0; i<ins->std.arpMacro.len; i++) {
ins->std.arpMacro.val[i]=reader.readC();
}
}
if (ins->std.arpMacroLen>0) {
ins->std.arpMacroOpen=true;
ins->std.arpMacroLoop=reader.readC();
if (ins->std.arpMacro.len>0) {
ins->std.arpMacro.open=true;
ins->std.arpMacro.loop=reader.readC();
} else {
ins->std.arpMacroOpen=false;
ins->std.arpMacro.open=false;
}
if (version>8) { // TODO: when?
ins->std.arpMacroMode=reader.readC();
ins->std.arpMacro.mode=reader.readC();
}
ins->std.dutyMacroLen=reader.readC();
ins->std.dutyMacro.len=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.dutyMacroLen; i++) {
ins->std.dutyMacro[i]=reader.readI();
for (int i=0; i<ins->std.dutyMacro.len; i++) {
ins->std.dutyMacro.val[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.dutyMacroLen; i++) {
ins->std.dutyMacro[i]=reader.readC();
for (int i=0; i<ins->std.dutyMacro.len; i++) {
ins->std.dutyMacro.val[i]=reader.readC();
}
}
if (ins->std.dutyMacroLen>0) {
ins->std.dutyMacroOpen=true;
ins->std.dutyMacroLoop=reader.readC();
if (ins->std.dutyMacro.len>0) {
ins->std.dutyMacro.open=true;
ins->std.dutyMacro.loop=reader.readC();
} else {
ins->std.dutyMacroOpen=false;
ins->std.dutyMacro.open=false;
}
ins->std.waveMacroLen=reader.readC();
ins->std.waveMacro.len=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.waveMacroLen; i++) {
ins->std.waveMacro[i]=reader.readI();
for (int i=0; i<ins->std.waveMacro.len; i++) {
ins->std.waveMacro.val[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.waveMacroLen; i++) {
ins->std.waveMacro[i]=reader.readC();
for (int i=0; i<ins->std.waveMacro.len; i++) {
ins->std.waveMacro.val[i]=reader.readC();
}
}
if (ins->std.waveMacroLen>0) {
ins->std.waveMacroOpen=true;
ins->std.waveMacroLoop=reader.readC();
if (ins->std.waveMacro.len>0) {
ins->std.waveMacro.open=true;
ins->std.waveMacro.loop=reader.readC();
} else {
ins->std.waveMacroOpen=false;
ins->std.waveMacro.open=false;
}
if (ins->type==DIV_INS_C64) {
@ -295,7 +295,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
}
} catch (EndOfFileException& e) {
lastError="premature end of file";
logE("premature end of file!\n");
logE("premature end of file!");
delete ins;
return;
}
@ -330,7 +330,7 @@ void DivEngine::loadTFI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
}
} catch (EndOfFileException& e) {
lastError="premature end of file";
logE("premature end of file!\n");
logE("premature end of file!");
delete ins;
return;
}
@ -372,7 +372,7 @@ void DivEngine::loadVGI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
}
} catch (EndOfFileException& e) {
lastError="premature end of file";
logE("premature end of file!\n");
logE("premature end of file!");
delete ins;
return;
}
@ -453,7 +453,7 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector<DivInstrument*>& ret, St
};
} catch (EndOfFileException& e) {
lastError = "premature end of file";
logE("premature end of file!\n");
logE("premature end of file!");
delete ins;
return;
}
@ -623,7 +623,7 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} catch (EndOfFileException& e) {
lastError = "premature end of file";
logE("premature end of file!\n");
logE("premature end of file!");
delete ins;
return;
}
@ -640,7 +640,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} catch (EndOfFileException& e) {
lastError="premature end of file";
logE("premature end of file!\n");
logE("premature end of file!");
return;
}
}
@ -695,7 +695,7 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
}
buf=new unsigned char[len];
if (fread(buf,1,len,f)!=(size_t)len) {
logW("did not read entire instrument file buffer!\n");
logW("did not read entire instrument file buffer!");
lastError="did not read entire instrument file!";
delete[] buf;
return ret;
@ -738,7 +738,7 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
}
} catch (EndOfFileException& e) {
lastError="premature end of file";
logE("premature end of file!\n");
logE("premature end of file!");
delete ins;
delete[] buf;
return ret;

View file

@ -17,7 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stddef.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "filter.h"
@ -31,7 +30,7 @@ float* DivFilterTables::sincIntegralTable=NULL;
// licensed under same license as this program.
float* DivFilterTables::getCubicTable() {
if (cubicTable==NULL) {
logD("initializing cubic spline table.\n");
logD("initializing cubic spline table.");
cubicTable=new float[4096];
for (int i=0; i<1024; i++) {
@ -47,7 +46,7 @@ float* DivFilterTables::getCubicTable() {
float* DivFilterTables:: getSincTable() {
if (sincTable==NULL) {
logD("initializing sinc table.\n");
logD("initializing sinc table.");
sincTable=new float[65536];
sincTable[0]=1.0f;
@ -67,7 +66,7 @@ float* DivFilterTables:: getSincTable() {
float* DivFilterTables::getSincIntegralTable() {
if (sincIntegralTable==NULL) {
logD("initializing sinc integral table.\n");
logD("initializing sinc integral table.");
sincIntegralTable=new float[65536];
sincIntegralTable[0]=-0.5f;
@ -85,4 +84,4 @@ float* DivFilterTables::getSincIntegralTable() {
}
}
return sincIntegralTable;
}
}

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,7 @@
// NOTICE!
// before adding new instrument types to this struct, please ask me first.
// absolutely zero support granted to conflicting formats.
enum DivInstrumentType {
enum DivInstrumentType: unsigned short {
DIV_INS_STD=0,
DIV_INS_FM=1,
DIV_INS_GB=2,
@ -77,9 +77,11 @@ struct DivInstrumentFM {
bool fixedDrums;
unsigned short kickFreq, snareHatFreq, tomTopFreq;
struct Operator {
bool enable;
unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ
Operator():
enable(true),
am(0),
ar(0),
dr(0),
@ -151,248 +153,97 @@ struct DivInstrumentFM {
};
// this is getting out of hand
struct DivInstrumentMacro {
String name;
int val[256];
unsigned int mode;
bool open;
unsigned char len;
signed char loop;
signed char rel;
DivInstrumentMacro(String n, bool initOpen=false):
name(n),
mode(0),
open(initOpen),
len(0),
loop(-1),
rel(-1) {
memset(val,0,256*sizeof(int));
}
};
struct DivInstrumentSTD {
int volMacro[256];
int arpMacro[256];
int dutyMacro[256];
int waveMacro[256];
int pitchMacro[256];
int ex1Macro[256];
int ex2Macro[256];
int ex3Macro[256];
int algMacro[256];
int fbMacro[256];
int fmsMacro[256];
int amsMacro[256];
int panLMacro[256];
int panRMacro[256];
int phaseResetMacro[256];
int ex4Macro[256];
int ex5Macro[256];
int ex6Macro[256];
int ex7Macro[256];
int ex8Macro[256];
DivInstrumentMacro volMacro;
DivInstrumentMacro arpMacro;
DivInstrumentMacro dutyMacro;
DivInstrumentMacro waveMacro;
DivInstrumentMacro pitchMacro;
DivInstrumentMacro ex1Macro;
DivInstrumentMacro ex2Macro;
DivInstrumentMacro ex3Macro;
DivInstrumentMacro algMacro;
DivInstrumentMacro fbMacro;
DivInstrumentMacro fmsMacro;
DivInstrumentMacro amsMacro;
DivInstrumentMacro panLMacro;
DivInstrumentMacro panRMacro;
DivInstrumentMacro phaseResetMacro;
DivInstrumentMacro ex4Macro;
DivInstrumentMacro ex5Macro;
DivInstrumentMacro ex6Macro;
DivInstrumentMacro ex7Macro;
DivInstrumentMacro ex8Macro;
bool arpMacroMode;
unsigned char volMacroHeight, dutyMacroHeight, waveMacroHeight;
bool volMacroOpen, arpMacroOpen, dutyMacroOpen, waveMacroOpen;
bool pitchMacroOpen, ex1MacroOpen, ex2MacroOpen, ex3MacroOpen;
bool algMacroOpen, fbMacroOpen, fmsMacroOpen, amsMacroOpen;
bool panLMacroOpen, panRMacroOpen, phaseResetMacroOpen, ex4MacroOpen;
bool ex5MacroOpen, ex6MacroOpen, ex7MacroOpen, ex8MacroOpen;
unsigned char volMacroLen, arpMacroLen, dutyMacroLen, waveMacroLen;
unsigned char pitchMacroLen, ex1MacroLen, ex2MacroLen, ex3MacroLen;
unsigned char algMacroLen, fbMacroLen, fmsMacroLen, amsMacroLen;
unsigned char panLMacroLen, panRMacroLen, phaseResetMacroLen, ex4MacroLen;
unsigned char ex5MacroLen, ex6MacroLen, ex7MacroLen, ex8MacroLen;
signed char volMacroLoop, arpMacroLoop, dutyMacroLoop, waveMacroLoop;
signed char pitchMacroLoop, ex1MacroLoop, ex2MacroLoop, ex3MacroLoop;
signed char algMacroLoop, fbMacroLoop, fmsMacroLoop, amsMacroLoop;
signed char panLMacroLoop, panRMacroLoop, phaseResetMacroLoop, ex4MacroLoop;
signed char ex5MacroLoop, ex6MacroLoop, ex7MacroLoop, ex8MacroLoop;
signed char volMacroRel, arpMacroRel, dutyMacroRel, waveMacroRel;
signed char pitchMacroRel, ex1MacroRel, ex2MacroRel, ex3MacroRel;
signed char algMacroRel, fbMacroRel, fmsMacroRel, amsMacroRel;
signed char panLMacroRel, panRMacroRel, phaseResetMacroRel, ex4MacroRel;
signed char ex5MacroRel, ex6MacroRel, ex7MacroRel, ex8MacroRel;
struct OpMacro {
// ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
unsigned char amMacro[256];
unsigned char arMacro[256];
unsigned char drMacro[256];
unsigned char multMacro[256];
unsigned char rrMacro[256];
unsigned char slMacro[256];
unsigned char tlMacro[256];
unsigned char dt2Macro[256];
unsigned char rsMacro[256];
unsigned char dtMacro[256];
unsigned char d2rMacro[256];
unsigned char ssgMacro[256];
unsigned char damMacro[256];
unsigned char dvbMacro[256];
unsigned char egtMacro[256];
unsigned char kslMacro[256];
unsigned char susMacro[256];
unsigned char vibMacro[256];
unsigned char wsMacro[256];
unsigned char ksrMacro[256];
bool amMacroOpen, arMacroOpen, drMacroOpen, multMacroOpen;
bool rrMacroOpen, slMacroOpen, tlMacroOpen, dt2MacroOpen;
bool rsMacroOpen, dtMacroOpen, d2rMacroOpen, ssgMacroOpen;
bool damMacroOpen, dvbMacroOpen, egtMacroOpen, kslMacroOpen;
bool susMacroOpen, vibMacroOpen, wsMacroOpen, ksrMacroOpen;
unsigned char amMacroLen, arMacroLen, drMacroLen, multMacroLen;
unsigned char rrMacroLen, slMacroLen, tlMacroLen, dt2MacroLen;
unsigned char rsMacroLen, dtMacroLen, d2rMacroLen, ssgMacroLen;
unsigned char damMacroLen, dvbMacroLen, egtMacroLen, kslMacroLen;
unsigned char susMacroLen, vibMacroLen, wsMacroLen, ksrMacroLen;
signed char amMacroLoop, arMacroLoop, drMacroLoop, multMacroLoop;
signed char rrMacroLoop, slMacroLoop, tlMacroLoop, dt2MacroLoop;
signed char rsMacroLoop, dtMacroLoop, d2rMacroLoop, ssgMacroLoop;
signed char damMacroLoop, dvbMacroLoop, egtMacroLoop, kslMacroLoop;
signed char susMacroLoop, vibMacroLoop, wsMacroLoop, ksrMacroLoop;
signed char amMacroRel, arMacroRel, drMacroRel, multMacroRel;
signed char rrMacroRel, slMacroRel, tlMacroRel, dt2MacroRel;
signed char rsMacroRel, dtMacroRel, d2rMacroRel, ssgMacroRel;
signed char damMacroRel, dvbMacroRel, egtMacroRel, kslMacroRel;
signed char susMacroRel, vibMacroRel, wsMacroRel, ksrMacroRel;
DivInstrumentMacro amMacro;
DivInstrumentMacro arMacro;
DivInstrumentMacro drMacro;
DivInstrumentMacro multMacro;
DivInstrumentMacro rrMacro;
DivInstrumentMacro slMacro;
DivInstrumentMacro tlMacro;
DivInstrumentMacro dt2Macro;
DivInstrumentMacro rsMacro;
DivInstrumentMacro dtMacro;
DivInstrumentMacro d2rMacro;
DivInstrumentMacro ssgMacro;
DivInstrumentMacro damMacro;
DivInstrumentMacro dvbMacro;
DivInstrumentMacro egtMacro;
DivInstrumentMacro kslMacro;
DivInstrumentMacro susMacro;
DivInstrumentMacro vibMacro;
DivInstrumentMacro wsMacro;
DivInstrumentMacro ksrMacro;
OpMacro():
amMacroOpen(false), arMacroOpen(false), drMacroOpen(false), multMacroOpen(false),
rrMacroOpen(false), slMacroOpen(false), tlMacroOpen(true), dt2MacroOpen(false),
rsMacroOpen(false), dtMacroOpen(false), d2rMacroOpen(false), ssgMacroOpen(false),
damMacroOpen(false), dvbMacroOpen(false), egtMacroOpen(false), kslMacroOpen(false),
susMacroOpen(false), vibMacroOpen(false), wsMacroOpen(false), ksrMacroOpen(false),
amMacroLen(0), arMacroLen(0), drMacroLen(0), multMacroLen(0),
rrMacroLen(0), slMacroLen(0), tlMacroLen(0), dt2MacroLen(0),
rsMacroLen(0), dtMacroLen(0), d2rMacroLen(0), ssgMacroLen(0),
damMacroLen(0), dvbMacroLen(0), egtMacroLen(0), kslMacroLen(0),
susMacroLen(0), vibMacroLen(0), wsMacroLen(0), ksrMacroLen(0),
amMacroLoop(-1), arMacroLoop(-1), drMacroLoop(-1), multMacroLoop(-1),
rrMacroLoop(-1), slMacroLoop(-1), tlMacroLoop(-1), dt2MacroLoop(-1),
rsMacroLoop(-1), dtMacroLoop(-1), d2rMacroLoop(-1), ssgMacroLoop(-1),
damMacroLoop(-1), dvbMacroLoop(-1), egtMacroLoop(-1), kslMacroLoop(-1),
susMacroLoop(-1), vibMacroLoop(-1), wsMacroLoop(-1), ksrMacroLoop(-1),
amMacroRel(-1), arMacroRel(-1), drMacroRel(-1), multMacroRel(-1),
rrMacroRel(-1), slMacroRel(-1), tlMacroRel(-1), dt2MacroRel(-1),
rsMacroRel(-1), dtMacroRel(-1), d2rMacroRel(-1), ssgMacroRel(-1),
damMacroRel(-1), dvbMacroRel(-1), egtMacroRel(-1), kslMacroRel(-1),
susMacroRel(-1), vibMacroRel(-1), wsMacroRel(-1), ksrMacroRel(-1) {
memset(amMacro,0,256);
memset(arMacro,0,256);
memset(drMacro,0,256);
memset(multMacro,0,256);
memset(rrMacro,0,256);
memset(slMacro,0,256);
memset(tlMacro,0,256);
memset(dt2Macro,0,256);
memset(rsMacro,0,256);
memset(dtMacro,0,256);
memset(d2rMacro,0,256);
memset(ssgMacro,0,256);
memset(damMacro,0,256);
memset(dvbMacro,0,256);
memset(egtMacro,0,256);
memset(kslMacro,0,256);
memset(susMacro,0,256);
memset(vibMacro,0,256);
memset(wsMacro,0,256);
memset(ksrMacro,0,256);
}
amMacro("am"), arMacro("ar"), drMacro("dr"), multMacro("mult"),
rrMacro("rr"), slMacro("sl"), tlMacro("tl",true), dt2Macro("dt2"),
rsMacro("rs"), dtMacro("dt"), d2rMacro("d2r"), ssgMacro("ssg"),
damMacro("dam"), dvbMacro("dvb"), egtMacro("egt"), kslMacro("ksl"),
susMacro("sus"), vibMacro("vib"), wsMacro("ws"), ksrMacro("ksr") {}
} opMacros[4];
DivInstrumentSTD():
arpMacroMode(false),
volMacroHeight(15),
dutyMacroHeight(3),
waveMacroHeight(63),
volMacroOpen(true),
arpMacroOpen(false),
dutyMacroOpen(false),
waveMacroOpen(false),
pitchMacroOpen(false),
ex1MacroOpen(false),
ex2MacroOpen(false),
ex3MacroOpen(false),
algMacroOpen(false),
fbMacroOpen(false),
fmsMacroOpen(false),
amsMacroOpen(false),
panLMacroOpen(false),
panRMacroOpen(false),
phaseResetMacroOpen(false),
ex4MacroOpen(false),
ex5MacroOpen(false),
ex6MacroOpen(false),
ex7MacroOpen(false),
ex8MacroOpen(false),
volMacroLen(0),
arpMacroLen(0),
dutyMacroLen(0),
waveMacroLen(0),
pitchMacroLen(0),
ex1MacroLen(0),
ex2MacroLen(0),
ex3MacroLen(0),
algMacroLen(0),
fbMacroLen(0),
fmsMacroLen(0),
amsMacroLen(0),
panLMacroLen(0),
panRMacroLen(0),
phaseResetMacroLen(0),
ex4MacroLen(0),
ex5MacroLen(0),
ex6MacroLen(0),
ex7MacroLen(0),
ex8MacroLen(0),
volMacroLoop(-1),
arpMacroLoop(-1),
dutyMacroLoop(-1),
waveMacroLoop(-1),
pitchMacroLoop(-1),
ex1MacroLoop(-1),
ex2MacroLoop(-1),
ex3MacroLoop(-1),
algMacroLoop(-1),
fbMacroLoop(-1),
fmsMacroLoop(-1),
amsMacroLoop(-1),
panLMacroLoop(-1),
panRMacroLoop(-1),
phaseResetMacroLoop(-1),
ex4MacroLoop(-1),
ex5MacroLoop(-1),
ex6MacroLoop(-1),
ex7MacroLoop(-1),
ex8MacroLoop(-1),
volMacroRel(-1),
arpMacroRel(-1),
dutyMacroRel(-1),
waveMacroRel(-1),
pitchMacroRel(-1),
ex1MacroRel(-1),
ex2MacroRel(-1),
ex3MacroRel(-1),
algMacroRel(-1),
fbMacroRel(-1),
fmsMacroRel(-1),
amsMacroRel(-1),
panLMacroRel(-1),
panRMacroRel(-1),
phaseResetMacroRel(-1),
ex4MacroRel(-1),
ex5MacroRel(-1),
ex6MacroRel(-1),
ex7MacroRel(-1),
ex8MacroRel(-1) {
memset(volMacro,0,256*sizeof(int));
memset(arpMacro,0,256*sizeof(int));
memset(dutyMacro,0,256*sizeof(int));
memset(waveMacro,0,256*sizeof(int));
memset(pitchMacro,0,256*sizeof(int));
memset(ex1Macro,0,256*sizeof(int));
memset(ex2Macro,0,256*sizeof(int));
memset(ex3Macro,0,256*sizeof(int));
memset(algMacro,0,256*sizeof(int));
memset(fbMacro,0,256*sizeof(int));
memset(fmsMacro,0,256*sizeof(int));
memset(amsMacro,0,256*sizeof(int));
memset(panLMacro,0,256*sizeof(int));
memset(panRMacro,0,256*sizeof(int));
memset(phaseResetMacro,0,256*sizeof(int));
memset(ex4Macro,0,256*sizeof(int));
memset(ex5Macro,0,256*sizeof(int));
memset(ex6Macro,0,256*sizeof(int));
memset(ex7Macro,0,256*sizeof(int));
memset(ex8Macro,0,256*sizeof(int));
}
volMacro("vol",true),
arpMacro("arp"),
dutyMacro("duty"),
waveMacro("wave"),
pitchMacro("pitch"),
ex1Macro("ex1"),
ex2Macro("ex2"),
ex3Macro("ex3"),
algMacro("alg"),
fbMacro("fb"),
fmsMacro("fms"),
amsMacro("ams"),
panLMacro("panL"),
panRMacro("panR"),
phaseResetMacro("phaseReset"),
ex4Macro("ex4"),
ex5Macro("ex5"),
ex6Macro("ex6"),
ex7Macro("ex7"),
ex8Macro("ex8") {}
};
struct DivInstrumentGB {

View file

@ -20,85 +20,41 @@
#include "macroInt.h"
#include "instrument.h"
#define doMacro(finished,had,has,val,pos,source,sourceLen,sourceLoop,sourceRel) \
if (finished) finished=false; \
if (had!=has) { \
finished=true; \
} \
had=has; \
if (has) { \
val=source[pos++]; \
if (sourceRel>=0 && pos>sourceRel && !released) { \
if (sourceLoop<sourceLen && sourceLoop>=0 && sourceLoop<sourceRel) { \
pos=sourceLoop; \
} else { \
pos--; \
} \
} \
if (pos>=sourceLen) { \
if (sourceLoop<sourceLen && sourceLoop>=0 && (sourceLoop>=sourceRel || sourceRel>=sourceLen)) { \
pos=sourceLoop; \
} else { \
has=false; \
} \
} \
void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released) {
if (finished) {
finished=false;
}
if (had!=has) {
finished=true;
}
had=has;
if (has) {
val=source.val[pos++];
if (source.rel>=0 && pos>source.rel && !released) {
if (source.loop<source.len && source.loop>=0 && source.loop<source.rel) {
pos=source.loop;
} else {
pos--;
}
}
if (pos>=source.len) {
if (source.loop<source.len && source.loop>=0 && (source.loop>=source.rel || source.rel>=source.len)) {
pos=source.loop;
} else {
has=false;
}
}
}
}
// CPU hell
void DivMacroInt::next() {
if (ins==NULL) return;
doMacro(finishedVol,hadVol,hasVol,vol,volPos,ins->std.volMacro,ins->std.volMacroLen,ins->std.volMacroLoop,ins->std.volMacroRel);
doMacro(finishedArp,hadArp,hasArp,arp,arpPos,ins->std.arpMacro,ins->std.arpMacroLen,ins->std.arpMacroLoop,ins->std.arpMacroRel);
doMacro(finishedDuty,hadDuty,hasDuty,duty,dutyPos,ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel);
doMacro(finishedWave,hadWave,hasWave,wave,wavePos,ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel);
doMacro(finishedPitch,hadPitch,hasPitch,pitch,pitchPos,ins->std.pitchMacro,ins->std.pitchMacroLen,ins->std.pitchMacroLoop,ins->std.pitchMacroRel);
doMacro(finishedEx1,hadEx1,hasEx1,ex1,ex1Pos,ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel);
doMacro(finishedEx2,hadEx2,hasEx2,ex2,ex2Pos,ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel);
doMacro(finishedEx3,hadEx3,hasEx3,ex3,ex3Pos,ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel);
doMacro(finishedAlg,hadAlg,hasAlg,alg,algPos,ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel);
doMacro(finishedFb,hadFb,hasFb,fb,fbPos,ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel);
doMacro(finishedFms,hadFms,hasFms,fms,fmsPos,ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel);
doMacro(finishedAms,hadAms,hasAms,ams,amsPos,ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel);
doMacro(finishedPanL,hadPanL,hasPanL,panL,panLPos,ins->std.panLMacro,ins->std.panLMacroLen,ins->std.panLMacroLoop,ins->std.panLMacroRel);
doMacro(finishedPanR,hadPanR,hasPanR,panR,panRPos,ins->std.panRMacro,ins->std.panRMacroLen,ins->std.panRMacroLoop,ins->std.panRMacroRel);
doMacro(finishedPhaseReset,hadPhaseReset,hasPhaseReset,phaseReset,phaseResetPos,ins->std.phaseResetMacro,ins->std.phaseResetMacroLen,ins->std.phaseResetMacroLoop,ins->std.phaseResetMacroRel);
doMacro(finishedEx4,hadEx4,hasEx4,ex4,ex4Pos,ins->std.ex4Macro,ins->std.ex4MacroLen,ins->std.ex4MacroLoop,ins->std.ex4MacroRel);
doMacro(finishedEx5,hadEx5,hasEx5,ex5,ex5Pos,ins->std.ex5Macro,ins->std.ex5MacroLen,ins->std.ex5MacroLoop,ins->std.ex5MacroRel);
doMacro(finishedEx6,hadEx6,hasEx6,ex6,ex6Pos,ins->std.ex6Macro,ins->std.ex6MacroLen,ins->std.ex6MacroLoop,ins->std.ex6MacroRel);
doMacro(finishedEx7,hadEx7,hasEx7,ex7,ex7Pos,ins->std.ex7Macro,ins->std.ex7MacroLen,ins->std.ex7MacroLoop,ins->std.ex7MacroRel);
doMacro(finishedEx8,hadEx8,hasEx8,ex8,ex8Pos,ins->std.ex8Macro,ins->std.ex8MacroLen,ins->std.ex8MacroLoop,ins->std.ex8MacroRel);
for (int i=0; i<4; i++) {
DivInstrumentSTD::OpMacro& m=ins->std.opMacros[i];
IntOp& o=op[i];
doMacro(o.finishedAm,o.hadAm,o.hasAm,o.am,o.amPos,m.amMacro,m.amMacroLen,m.amMacroLoop,m.amMacroRel);
doMacro(o.finishedAr,o.hadAr,o.hasAr,o.ar,o.arPos,m.arMacro,m.arMacroLen,m.arMacroLoop,m.arMacroRel);
doMacro(o.finishedDr,o.hadDr,o.hasDr,o.dr,o.drPos,m.drMacro,m.drMacroLen,m.drMacroLoop,m.drMacroRel);
doMacro(o.finishedMult,o.hadMult,o.hasMult,o.mult,o.multPos,m.multMacro,m.multMacroLen,m.multMacroLoop,m.multMacroRel);
doMacro(o.finishedRr,o.hadRr,o.hasRr,o.rr,o.rrPos,m.rrMacro,m.rrMacroLen,m.rrMacroLoop,m.rrMacroRel);
doMacro(o.finishedSl,o.hadSl,o.hasSl,o.sl,o.slPos,m.slMacro,m.slMacroLen,m.slMacroLoop,m.slMacroRel);
doMacro(o.finishedTl,o.hadTl,o.hasTl,o.tl,o.tlPos,m.tlMacro,m.tlMacroLen,m.tlMacroLoop,m.tlMacroRel);
doMacro(o.finishedDt2,o.hadDt2,o.hasDt2,o.dt2,o.dt2Pos,m.dt2Macro,m.dt2MacroLen,m.dt2MacroLoop,m.dt2MacroRel);
doMacro(o.finishedRs,o.hadRs,o.hasRs,o.rs,o.rsPos,m.rsMacro,m.rsMacroLen,m.rsMacroLoop,m.rsMacroRel);
doMacro(o.finishedDt,o.hadDt,o.hasDt,o.dt,o.dtPos,m.dtMacro,m.dtMacroLen,m.dtMacroLoop,m.dtMacroRel);
doMacro(o.finishedD2r,o.hadD2r,o.hasD2r,o.d2r,o.d2rPos,m.d2rMacro,m.d2rMacroLen,m.d2rMacroLoop,m.d2rMacroRel);
doMacro(o.finishedSsg,o.hadSsg,o.hasSsg,o.ssg,o.ssgPos,m.ssgMacro,m.ssgMacroLen,m.ssgMacroLoop,m.ssgMacroRel);
doMacro(o.finishedDam,o.hadDam,o.hasDam,o.dam,o.damPos,m.damMacro,m.damMacroLen,m.damMacroLoop,m.damMacroRel);
doMacro(o.finishedDvb,o.hadDvb,o.hasDvb,o.dvb,o.dvbPos,m.dvbMacro,m.dvbMacroLen,m.dvbMacroLoop,m.dvbMacroRel);
doMacro(o.finishedEgt,o.hadEgt,o.hasEgt,o.egt,o.egtPos,m.egtMacro,m.egtMacroLen,m.egtMacroLoop,m.egtMacroRel);
doMacro(o.finishedKsl,o.hadKsl,o.hasKsl,o.ksl,o.kslPos,m.kslMacro,m.kslMacroLen,m.kslMacroLoop,m.kslMacroRel);
doMacro(o.finishedSus,o.hadSus,o.hasSus,o.sus,o.susPos,m.susMacro,m.susMacroLen,m.susMacroLoop,m.susMacroRel);
doMacro(o.finishedVib,o.hadVib,o.hasVib,o.vib,o.vibPos,m.vibMacro,m.vibMacroLen,m.vibMacroLoop,m.vibMacroRel);
doMacro(o.finishedWs,o.hadWs,o.hasWs,o.ws,o.wsPos,m.wsMacro,m.wsMacroLen,m.wsMacroLoop,m.wsMacroRel);
doMacro(o.finishedKsr,o.hadKsr,o.hasKsr,o.ksr,o.ksrPos,m.ksrMacro,m.ksrMacroLen,m.ksrMacroLoop,m.ksrMacroRel);
// run macros
// TODO: potentially get rid of list to avoid allocations
for (size_t i=0; i<macroListLen; i++) {
if (macroList[i]!=NULL && macroSource[i]!=NULL) {
macroList[i]->doMacro(*macroSource[i],released);
}
}
}
@ -106,316 +62,155 @@ void DivMacroInt::release() {
released=true;
}
#define ADD_MACRO(m,s) \
macroList[macroListLen]=&m; \
macroSource[macroListLen++]=&s;
void DivMacroInt::init(DivInstrument* which) {
ins=which;
volPos=0;
arpPos=0;
dutyPos=0;
wavePos=0;
pitchPos=0;
ex1Pos=0;
ex2Pos=0;
ex3Pos=0;
algPos=0;
fbPos=0;
fmsPos=0;
amsPos=0;
panLPos=0;
panRPos=0;
phaseResetPos=0;
ex4Pos=0;
ex5Pos=0;
ex6Pos=0;
ex7Pos=0;
ex8Pos=0;
// initialize
for (size_t i=0; i<macroListLen; i++) {
if (macroList[i]!=NULL) macroList[i]->init();
}
macroListLen=0;
released=false;
hasVol=false;
hasArp=false;
hasDuty=false;
hasWave=false;
hasPitch=false;
hasEx1=false;
hasEx2=false;
hasEx3=false;
hasAlg=false;
hasFb=false;
hasFms=false;
hasAms=false;
hasPanL=false;
hasPanR=false;
hasPhaseReset=false;
hasEx4=false;
hasEx5=false;
hasEx6=false;
hasEx7=false;
hasEx8=false;
hadVol=false;
hadArp=false;
hadDuty=false;
hadWave=false;
hadPitch=false;
hadEx1=false;
hadEx2=false;
hadEx3=false;
hadAlg=false;
hadFb=false;
hadFms=false;
hadAms=false;
hadPanL=false;
hadPanR=false;
hadPhaseReset=false;
hadEx4=false;
hadEx5=false;
hadEx6=false;
hadEx7=false;
hadEx8=false;
willVol=false;
willArp=false;
willDuty=false;
willWave=false;
willPitch=false;
willEx1=false;
willEx2=false;
willEx3=false;
willAlg=false;
willFb=false;
willFms=false;
willAms=false;
willPanL=false;
willPanR=false;
willPhaseReset=false;
willEx4=false;
willEx5=false;
willEx6=false;
willEx7=false;
willEx8=false;
op[0]=IntOp();
op[1]=IntOp();
op[2]=IntOp();
op[3]=IntOp();
arpMode=false;
if (ins==NULL) return;
if (ins->std.volMacroLen>0) {
hadVol=true;
hasVol=true;
willVol=true;
// prepare common macro
if (ins->std.volMacro.len>0) {
ADD_MACRO(vol,ins->std.volMacro);
}
if (ins->std.arpMacroLen>0) {
hadArp=true;
hasArp=true;
willArp=true;
if (ins->std.arpMacro.len>0) {
ADD_MACRO(arp,ins->std.arpMacro);
}
if (ins->std.dutyMacroLen>0) {
hadDuty=true;
hasDuty=true;
willDuty=true;
if (ins->std.dutyMacro.len>0) {
ADD_MACRO(duty,ins->std.dutyMacro);
}
if (ins->std.waveMacroLen>0) {
hadWave=true;
hasWave=true;
willWave=true;
if (ins->std.waveMacro.len>0) {
ADD_MACRO(wave,ins->std.waveMacro);
}
if (ins->std.pitchMacroLen>0) {
hadPitch=true;
hasPitch=true;
willPitch=true;
if (ins->std.pitchMacro.len>0) {
ADD_MACRO(pitch,ins->std.pitchMacro);
}
if (ins->std.ex1MacroLen>0) {
hadEx1=true;
hasEx1=true;
willEx1=true;
if (ins->std.ex1Macro.len>0) {
ADD_MACRO(ex1,ins->std.ex1Macro);
}
if (ins->std.ex2MacroLen>0) {
hadEx2=true;
hasEx2=true;
willEx2=true;
if (ins->std.ex2Macro.len>0) {
ADD_MACRO(ex2,ins->std.ex2Macro);
}
if (ins->std.ex3MacroLen>0) {
hadEx3=true;
hasEx3=true;
willEx3=true;
if (ins->std.ex3Macro.len>0) {
ADD_MACRO(ex3,ins->std.ex3Macro);
}
if (ins->std.algMacroLen>0) {
hadAlg=true;
hasAlg=true;
willAlg=true;
if (ins->std.algMacro.len>0) {
ADD_MACRO(alg,ins->std.algMacro);
}
if (ins->std.fbMacroLen>0) {
hadFb=true;
hasFb=true;
willFb=true;
if (ins->std.fbMacro.len>0) {
ADD_MACRO(fb,ins->std.fbMacro);
}
if (ins->std.fmsMacroLen>0) {
hadFms=true;
hasFms=true;
willFms=true;
if (ins->std.fmsMacro.len>0) {
ADD_MACRO(fms,ins->std.fmsMacro);
}
if (ins->std.amsMacroLen>0) {
hadAms=true;
hasAms=true;
willAms=true;
if (ins->std.amsMacro.len>0) {
ADD_MACRO(ams,ins->std.amsMacro);
}
// TODO: other macros
if (ins->std.panLMacroLen>0) {
hadPanL=true;
hasPanL=true;
willPanL=true;
if (ins->std.panLMacro.len>0) {
ADD_MACRO(panL,ins->std.panLMacro);
}
if (ins->std.panRMacroLen>0) {
hadPanR=true;
hasPanR=true;
willPanR=true;
if (ins->std.panRMacro.len>0) {
ADD_MACRO(panR,ins->std.panRMacro);
}
if (ins->std.phaseResetMacroLen>0) {
hadPhaseReset=true;
hasPhaseReset=true;
willPhaseReset=true;
if (ins->std.phaseResetMacro.len>0) {
ADD_MACRO(phaseReset,ins->std.phaseResetMacro);
}
if (ins->std.ex4MacroLen>0) {
hadEx4=true;
hasEx4=true;
willEx4=true;
if (ins->std.ex4Macro.len>0) {
ADD_MACRO(ex4,ins->std.ex4Macro);
}
if (ins->std.ex5MacroLen>0) {
hadEx5=true;
hasEx5=true;
willEx5=true;
if (ins->std.ex5Macro.len>0) {
ADD_MACRO(ex5,ins->std.ex5Macro);
}
if (ins->std.ex6MacroLen>0) {
hadEx6=true;
hasEx6=true;
willEx6=true;
if (ins->std.ex6Macro.len>0) {
ADD_MACRO(ex6,ins->std.ex6Macro);
}
if (ins->std.ex7MacroLen>0) {
hadEx7=true;
hasEx7=true;
willEx7=true;
if (ins->std.ex7Macro.len>0) {
ADD_MACRO(ex7,ins->std.ex7Macro);
}
if (ins->std.ex8MacroLen>0) {
hadEx8=true;
hasEx8=true;
willEx8=true;
}
if (ins->std.arpMacroMode) {
arpMode=true;
if (ins->std.ex8Macro.len>0) {
ADD_MACRO(ex8,ins->std.ex8Macro);
}
// prepare FM operator macros
for (int i=0; i<4; i++) {
DivInstrumentSTD::OpMacro& m=ins->std.opMacros[i];
IntOp& o=op[i];
if (m.amMacroLen>0) {
o.hadAm=true;
o.hasAm=true;
o.willAm=true;
if (m.amMacro.len>0) {
ADD_MACRO(o.am,m.amMacro);
}
if (m.arMacroLen>0) {
o.hadAr=true;
o.hasAr=true;
o.willAr=true;
if (m.arMacro.len>0) {
ADD_MACRO(o.ar,m.arMacro);
}
if (m.drMacroLen>0) {
o.hadDr=true;
o.hasDr=true;
o.willDr=true;
if (m.drMacro.len>0) {
ADD_MACRO(o.dr,m.drMacro);
}
if (m.multMacroLen>0) {
o.hadMult=true;
o.hasMult=true;
o.willMult=true;
if (m.multMacro.len>0) {
ADD_MACRO(o.mult,m.multMacro);
}
if (m.rrMacroLen>0) {
o.hadRr=true;
o.hasRr=true;
o.willRr=true;
if (m.rrMacro.len>0) {
ADD_MACRO(o.rr,m.rrMacro);
}
if (m.slMacroLen>0) {
o.hadSl=true;
o.hasSl=true;
o.willSl=true;
if (m.slMacro.len>0) {
ADD_MACRO(o.sl,m.slMacro);
}
if (m.tlMacroLen>0) {
o.hadTl=true;
o.hasTl=true;
o.willTl=true;
if (m.tlMacro.len>0) {
ADD_MACRO(o.tl,m.tlMacro);
}
if (m.dt2MacroLen>0) {
o.hadDt2=true;
o.hasDt2=true;
o.willDt2=true;
if (m.dt2Macro.len>0) {
ADD_MACRO(o.dt2,m.dt2Macro);
}
if (m.rsMacroLen>0) {
o.hadRs=true;
o.hasRs=true;
o.willRs=true;
if (m.rsMacro.len>0) {
ADD_MACRO(o.rs,m.rsMacro);
}
if (m.dtMacroLen>0) {
o.hadDt=true;
o.hasDt=true;
o.willDt=true;
if (m.dtMacro.len>0) {
ADD_MACRO(o.dt,m.dtMacro);
}
if (m.d2rMacroLen>0) {
o.hadD2r=true;
o.hasD2r=true;
o.willD2r=true;
if (m.d2rMacro.len>0) {
ADD_MACRO(o.d2r,m.d2rMacro);
}
if (m.ssgMacroLen>0) {
o.hadSsg=true;
o.hasSsg=true;
o.willSsg=true;
if (m.ssgMacro.len>0) {
ADD_MACRO(o.ssg,m.ssgMacro);
}
if (m.damMacroLen>0) {
o.hadDam=true;
o.hasDam=true;
o.willDam=true;
if (m.damMacro.len>0) {
ADD_MACRO(o.dam,m.damMacro);
}
if (m.dvbMacroLen>0) {
o.hadDvb=true;
o.hasDvb=true;
o.willDvb=true;
if (m.dvbMacro.len>0) {
ADD_MACRO(o.dvb,m.dvbMacro);
}
if (m.egtMacroLen>0) {
o.hadEgt=true;
o.hasEgt=true;
o.willEgt=true;
if (m.egtMacro.len>0) {
ADD_MACRO(o.egt,m.egtMacro);
}
if (m.kslMacroLen>0) {
o.hadKsl=true;
o.hasKsl=true;
o.willKsl=true;
if (m.kslMacro.len>0) {
ADD_MACRO(o.ksl,m.kslMacro);
}
if (m.susMacroLen>0) {
o.hadSus=true;
o.hasSus=true;
o.willSus=true;
if (m.susMacro.len>0) {
ADD_MACRO(o.sus,m.susMacro);
}
if (m.vibMacroLen>0) {
o.hadVib=true;
o.hasVib=true;
o.willVib=true;
if (m.vibMacro.len>0) {
ADD_MACRO(o.vib,m.vibMacro);
}
if (m.wsMacroLen>0) {
o.hadWs=true;
o.hasWs=true;
o.willWs=true;
if (m.wsMacro.len>0) {
ADD_MACRO(o.ws,m.wsMacro);
}
if (m.ksrMacroLen>0) {
o.hadKsr=true;
o.hasKsr=true;
o.willKsr=true;
if (m.ksrMacro.len>0) {
ADD_MACRO(o.ksr,m.ksrMacro);
}
}
for (size_t i=0; i<macroListLen; i++) {
macroList[i]->prepare(*macroSource[i]);
}
}
void DivMacroInt::notifyInsDeletion(DivInstrument* which) {

View file

@ -22,125 +22,72 @@
#include "instrument.h"
struct DivMacroStruct {
int pos;
int val;
bool has, had, finished, will;
unsigned int mode;
void doMacro(DivInstrumentMacro& source, bool released);
void init() {
pos=mode=0;
has=had=will=false;
}
void prepare(DivInstrumentMacro& source) {
has=had=will=true;
mode=source.mode;
}
DivMacroStruct():
pos(0),
val(0),
has(false),
had(false),
finished(false),
will(false),
mode(0) {}
};
class DivMacroInt {
DivInstrument* ins;
int volPos, arpPos, dutyPos, wavePos, pitchPos, ex1Pos, ex2Pos, ex3Pos;
int algPos, fbPos, fmsPos, amsPos;
int panLPos, panRPos, phaseResetPos, ex4Pos, ex5Pos, ex6Pos, ex7Pos, ex8Pos;
DivMacroStruct* macroList[128];
DivInstrumentMacro* macroSource[128];
size_t macroListLen;
bool released;
public:
int vol;
int arp;
int duty, wave, pitch, ex1, ex2, ex3;
int alg, fb, fms, ams;
int panL, panR, phaseReset, ex4, ex5, ex6, ex7, ex8;
bool hasVol, hasArp, hasDuty, hasWave, hasPitch, hasEx1, hasEx2, hasEx3, hasAlg, hasFb, hasFms, hasAms;
bool hasPanL, hasPanR, hasPhaseReset, hasEx4, hasEx5, hasEx6, hasEx7, hasEx8;
bool hadVol, hadArp, hadDuty, hadWave, hadPitch, hadEx1, hadEx2, hadEx3, hadAlg, hadFb, hadFms, hadAms;
bool hadPanL, hadPanR, hadPhaseReset, hadEx4, hadEx5, hadEx6, hadEx7, hadEx8;
bool finishedVol, finishedArp, finishedDuty, finishedWave, finishedPitch, finishedEx1, finishedEx2, finishedEx3;
bool finishedAlg, finishedFb, finishedFms, finishedAms;
bool finishedPanL, finishedPanR, finishedPhaseReset, finishedEx4, finishedEx5, finishedEx6, finishedEx7, finishedEx8;
bool willVol, willArp, willDuty, willWave, willPitch, willEx1, willEx2, willEx3, willAlg, willFb, willFms, willAms;
bool willPanL, willPanR, willPhaseReset, willEx4, willEx5, willEx6, willEx7, willEx8;
bool arpMode;
// common macro
DivMacroStruct vol;
DivMacroStruct arp;
DivMacroStruct duty, wave, pitch, ex1, ex2, ex3;
DivMacroStruct alg, fb, fms, ams;
DivMacroStruct panL, panR, phaseReset, ex4, ex5, ex6, ex7, ex8;
// FM operator macro
struct IntOp {
int amPos, arPos, drPos, multPos;
int rrPos, slPos, tlPos, dt2Pos;
int rsPos, dtPos, d2rPos, ssgPos;
int damPos, dvbPos, egtPos, kslPos;
int susPos, vibPos, wsPos, ksrPos;
int am, ar, dr, mult;
int rr, sl, tl, dt2;
int rs, dt, d2r, ssg;
int dam, dvb, egt, ksl;
int sus, vib, ws, ksr;
bool hasAm, hasAr, hasDr, hasMult;
bool hasRr, hasSl, hasTl, hasDt2;
bool hasRs, hasDt, hasD2r, hasSsg;
bool hasDam, hasDvb, hasEgt, hasKsl;
bool hasSus, hasVib, hasWs, hasKsr;
bool hadAm, hadAr, hadDr, hadMult;
bool hadRr, hadSl, hadTl, hadDt2;
bool hadRs, hadDt, hadD2r, hadSsg;
bool hadDam, hadDvb, hadEgt, hadKsl;
bool hadSus, hadVib, hadWs, hadKsr;
bool finishedAm, finishedAr, finishedDr, finishedMult;
bool finishedRr, finishedSl, finishedTl, finishedDt2;
bool finishedRs, finishedDt, finishedD2r, finishedSsg;
bool finishedDam, finishedDvb, finishedEgt, finishedKsl;
bool finishedSus, finishedVib, finishedWs, finishedKsr;
bool willAm, willAr, willDr, willMult;
bool willRr, willSl, willTl, willDt2;
bool willRs, willDt, willD2r, willSsg;
bool willDam, willDvb, willEgt, willKsl;
bool willSus, willVib, willWs, willKsr;
DivMacroStruct am, ar, dr, mult;
DivMacroStruct rr, sl, tl, dt2;
DivMacroStruct rs, dt, d2r, ssg;
DivMacroStruct dam, dvb, egt, ksl;
DivMacroStruct sus, vib, ws, ksr;
IntOp():
amPos(0),
arPos(0),
drPos(0),
multPos(0),
rrPos(0),
slPos(0),
tlPos(0),
dt2Pos(0),
rsPos(0),
dtPos(0),
d2rPos(0),
ssgPos(0),
damPos(0),
dvbPos(0),
egtPos(0),
kslPos(0),
susPos(0),
vibPos(0),
wsPos(0),
ksrPos(0),
am(0),
ar(0),
dr(0),
mult(0),
rr(0),
sl(0),
tl(0),
dt2(0),
rs(0),
dt(0),
d2r(0),
ssg(0),
dam(0),
dvb(0),
egt(0),
ksl(0),
sus(0),
vib(0),
ws(0),
ksr(0),
hasAm(false), hasAr(false), hasDr(false), hasMult(false),
hasRr(false), hasSl(false), hasTl(false), hasDt2(false),
hasRs(false), hasDt(false), hasD2r(false), hasSsg(false),
hasDam(false), hasDvb(false), hasEgt(false), hasKsl(false),
hasSus(false), hasVib(false), hasWs(false), hasKsr(false),
hadAm(false), hadAr(false), hadDr(false), hadMult(false),
hadRr(false), hadSl(false), hadTl(false), hadDt2(false),
hadRs(false), hadDt(false), hadD2r(false), hadSsg(false),
hadDam(false), hadDvb(false), hadEgt(false), hadKsl(false),
hadSus(false), hadVib(false), hadWs(false), hadKsr(false),
finishedAm(false), finishedAr(false), finishedDr(false), finishedMult(false),
finishedRr(false), finishedSl(false), finishedTl(false), finishedDt2(false),
finishedRs(false), finishedDt(false), finishedD2r(false), finishedSsg(false),
finishedDam(false), finishedDvb(false), finishedEgt(false), finishedKsl(false),
finishedSus(false), finishedVib(false), finishedWs(false), finishedKsr(false),
willAm(false), willAr(false), willDr(false), willMult(false),
willRr(false), willSl(false), willTl(false), willDt2(false),
willRs(false), willDt(false), willD2r(false), willSsg(false),
willDam(false), willDvb(false), willEgt(false), willKsl(false),
willSus(false), willVib(false), willWs(false), willKsr(false) {}
am(),
ar(),
dr(),
mult(),
rr(),
sl(),
tl(),
dt2(),
rs(),
dt(),
d2r(),
ssg(),
dam(),
dvb(),
egt(),
ksl(),
sus(),
vib(),
ws(),
ksr() {}
} op[4];
/**
@ -167,128 +114,31 @@ class DivMacroInt {
DivMacroInt():
ins(NULL),
volPos(0),
arpPos(0),
dutyPos(0),
wavePos(0),
pitchPos(0),
ex1Pos(0),
ex2Pos(0),
ex3Pos(0),
algPos(0),
fbPos(0),
fmsPos(0),
amsPos(0),
panLPos(0),
panRPos(0),
phaseResetPos(0),
ex4Pos(0),
ex5Pos(0),
ex6Pos(0),
ex7Pos(0),
ex8Pos(0),
macroListLen(0),
released(false),
vol(0),
arp(0),
duty(0),
wave(0),
pitch(0),
ex1(0),
ex2(0),
ex3(0),
alg(0),
fb(0),
fms(0),
ams(0),
panL(0),
panR(0),
phaseReset(0),
ex4(0),
ex5(0),
ex6(0),
ex7(0),
ex8(0),
hasVol(false),
hasArp(false),
hasDuty(false),
hasWave(false),
hasPitch(false),
hasEx1(false),
hasEx2(false),
hasEx3(false),
hasAlg(false),
hasFb(false),
hasFms(false),
hasAms(false),
hasPanL(false),
hasPanR(false),
hasPhaseReset(false),
hasEx4(false),
hasEx5(false),
hasEx6(false),
hasEx7(false),
hasEx8(false),
hadVol(false),
hadArp(false),
hadDuty(false),
hadWave(false),
hadPitch(false),
hadEx1(false),
hadEx2(false),
hadEx3(false),
hadAlg(false),
hadFb(false),
hadFms(false),
hadAms(false),
hadPanL(false),
hadPanR(false),
hadPhaseReset(false),
hadEx4(false),
hadEx5(false),
hadEx6(false),
hadEx7(false),
hadEx8(false),
finishedVol(false),
finishedArp(false),
finishedDuty(false),
finishedWave(false),
finishedPitch(false),
finishedEx1(false),
finishedEx2(false),
finishedEx3(false),
finishedAlg(false),
finishedFb(false),
finishedFms(false),
finishedAms(false),
finishedPanL(false),
finishedPanR(false),
finishedPhaseReset(false),
finishedEx4(false),
finishedEx5(false),
finishedEx6(false),
finishedEx7(false),
finishedEx8(false),
willVol(false),
willArp(false),
willDuty(false),
willWave(false),
willPitch(false),
willEx1(false),
willEx2(false),
willEx3(false),
willAlg(false),
willFb(false),
willFms(false),
willAms(false),
willPanL(false),
willPanR(false),
willPhaseReset(false),
willEx4(false),
willEx5(false),
willEx6(false),
willEx7(false),
willEx8(false),
arpMode(false) {}
vol(),
arp(),
duty(),
wave(),
pitch(),
ex1(),
ex2(),
ex3(),
alg(),
fb(),
fms(),
ams(),
panL(),
panR(),
phaseReset(),
ex4(),
ex5(),
ex6(),
ex7(),
ex8() {
memset(macroList,0,128*sizeof(void*));
memset(macroSource,0,128*sizeof(void*));
}
};
#endif

View file

@ -21,10 +21,10 @@
#define _ORDERS_H
struct DivOrders {
unsigned char ord[DIV_MAX_CHANS][128];
unsigned char ord[DIV_MAX_CHANS][256];
DivOrders() {
memset(ord,0,DIV_MAX_CHANS*128);
memset(ord,0,DIV_MAX_CHANS*256);
}
};

View file

@ -41,7 +41,7 @@ DivPattern* DivChannelData::getPattern(int index, bool create) {
}
void DivChannelData::wipePatterns() {
for (int i=0; i<128; i++) {
for (int i=0; i<256; i++) {
if (data[i]!=NULL) {
delete data[i];
data[i]=NULL;
@ -131,5 +131,5 @@ SafeReader* DivPattern::compile(int len, int fxRows) {
DivChannelData::DivChannelData():
effectRows(1) {
memset(data,0,128*sizeof(void*));
memset(data,0,256*sizeof(void*));
}

View file

@ -49,7 +49,7 @@ struct DivChannelData {
// 3: volume
// 4-5+: effect/effect value
// do NOT access directly unless you know what you're doing!
DivPattern* data[128];
DivPattern* data[256];
/**
* get a pattern from this channel, or the empty pattern if not initialized.

View file

@ -74,6 +74,14 @@ int DivDispatch::getPortaFloor(int ch) {
return 0x00;
}
float DivDispatch::getPostAmp() {
return 1.0f;
}
bool DivDispatch::getDCOffRequired() {
return false;
}
const char* DivDispatch::getEffectName(unsigned char effect) {
return NULL;
}

View file

@ -147,8 +147,8 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
void DivPlatformAmiga::tick() {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=((chan[i].vol%65)*MIN(64,chan[i].std.vol))>>6;
if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol%65)*MIN(64,chan[i].std.vol.val))>>6;
}
double off=1.0;
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
@ -159,24 +159,24 @@ void DivPlatformAmiga::tick() {
off=8363.0/(double)s->centerRate;
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].std.arp));
if (chan[i].std.arp.mode) {
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].std.arp.val));
} else {
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note+chan[i].std.arp));
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note+chan[i].std.arp.val));
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note));
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadWave) {
if (chan[i].wave!=chan[i].std.wave) {
chan[i].wave=chan[i].std.wave;
if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave.val) {
chan[i].wave=chan[i].std.wave.val;
if (!chan[i].keyOff) chan[i].keyOn=true;
}
}
@ -252,13 +252,13 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
}
break;
case DIV_CMD_GET_VOLUME:
if (chan[c.chan].std.hasVol) {
if (chan[c.chan].std.vol.has) {
return chan[c.chan].vol;
}
return chan[c.chan].outVol;
@ -315,7 +315,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
off=8363.0/(double)s->centerRate;
}
}
chan[c.chan].baseFreq=round(off*NOTE_PERIODIC_NOROUND(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp-12):(0))));
chan[c.chan].baseFreq=round(off*NOTE_PERIODIC_NOROUND(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val-12):(0))));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -132,6 +132,9 @@ const char* DivPlatformArcade::getEffectName(unsigned char effect) {
case 0x1f:
return "1Fxx: Set PM depth (0 to 7F)";
break;
case 0x30:
return "30xx: Toggle hard envelope reset on new notes";
break;
}
return NULL;
}
@ -220,8 +223,8 @@ void DivPlatformArcade::tick() {
for (int i=0; i<8; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127;
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
@ -233,50 +236,50 @@ void DivPlatformArcade::tick() {
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp);
chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_LINEAR(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
if (chan[i].std.duty>0) {
rWrite(0x0f,0x80|(0x20-chan[i].std.duty));
if (chan[i].std.duty.had) {
if (chan[i].std.duty.val>0) {
rWrite(0x0f,0x80|(0x20-chan[i].std.duty.val));
} else {
rWrite(0x0f,0);
}
}
if (chan[i].std.hadWave) {
rWrite(0x1b,chan[i].std.wave&3);
if (chan[i].std.wave.had) {
rWrite(0x1b,chan[i].std.wave.val&3);
}
if (chan[i].std.hadEx1) {
amDepth=chan[i].std.ex1;
if (chan[i].std.ex1.had) {
amDepth=chan[i].std.ex1.val;
immWrite(0x19,amDepth);
}
if (chan[i].std.hadEx2) {
pmDepth=chan[i].std.ex2;
if (chan[i].std.ex2.had) {
pmDepth=chan[i].std.ex2.val;
immWrite(0x19,0x80|pmDepth);
}
if (chan[i].std.hadEx3) {
immWrite(0x18,chan[i].std.ex3);
if (chan[i].std.ex3.had) {
immWrite(0x18,chan[i].std.ex3.val);
}
if (chan[i].std.hadAlg) {
chan[i].state.alg=chan[i].std.alg;
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
if (isMuted[i]) {
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
} else {
@ -296,77 +299,94 @@ void DivPlatformArcade::tick() {
}
}
}
if (chan[i].std.hadFb) {
chan[i].state.fb=chan[i].std.fb;
if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb.val;
if (isMuted[i]) {
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
} else {
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|((chan[i].chVolL&1)<<6)|((chan[i].chVolR&1)<<7));
}
}
if (chan[i].std.hadFms) {
chan[i].state.fms=chan[i].std.fms;
if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms.val;
rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3));
}
if (chan[i].std.hadAms) {
chan[i].state.ams=chan[i].std.ams;
if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams.val;
rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3));
}
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) {
op.am=m.am;
if (m.am.had) {
op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadAr) {
op.ar=m.ar;
if (m.ar.had) {
op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.hadDr) {
op.dr=m.dr;
if (m.dr.had) {
op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadMult) {
op.mult=m.mult;
if (m.mult.had) {
op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadRr) {
op.rr=m.rr;
if (m.rr.had) {
op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadSl) {
op.sl=m.sl;
if (m.sl.had) {
op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadTl) {
op.tl=127-m.tl;
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
if (m.hadRs) {
op.rs=m.rs;
if (m.rs.had) {
op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.hadDt) {
op.dt=m.dt;
if (m.dt.had) {
op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadD2r) {
op.d2r=m.d2r;
if (m.d2r.had) {
op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
}
if (m.hadDt2) {
op.dt2=m.dt2;
if (m.dt2.had) {
op.dt2=m.dt2.val;
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
}
}
if (chan[i].keyOn || chan[i].keyOff) {
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
immWrite(baseAddr+ADDR_SL_RR,0x0f);
immWrite(baseAddr+ADDR_TL,0x7f);
oldWrites[baseAddr+ADDR_SL_RR]=-1;
oldWrites[baseAddr+ADDR_TL]=-1;
}
}
immWrite(0x08,i);
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
for (int k=0; k<9; k++) {
immWrite(baseAddr+ADDR_SL_RR,0x0f);
}
}
}
chan[i].keyOff=false;
}
}
@ -413,7 +433,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
}
chan[c.chan].std.init(ins);
if (!chan[c.chan].std.willVol) {
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
@ -472,7 +492,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
for (int i=0; i<4; i++) {
@ -602,6 +622,9 @@ int DivPlatformArcade::dispatch(DivCommand c) {
immWrite(0x19,0x80|pmDepth);
break;
}
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_CMD_STD_NOISE_FREQ: {
if (c.chan!=7) break;
if (c.value) {

View file

@ -39,10 +39,30 @@ class DivPlatformArcade: public DivDispatch {
int freq, baseFreq, pitch, note;
unsigned char ins;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset;
int vol, outVol;
unsigned char chVolL, chVolR;
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {}
Channel():
freqH(0),
freqL(0),
freq(0),
baseFreq(0),
pitch(0),
note(0),
ins(-1),
active(false),
insChanged(true),
freqChanged(false),
keyOn(false),
keyOff(false),
inPorta(false),
portaPause(false),
furnacePCM(false),
hardReset(false),
vol(0),
outVol(0),
chVolL(127),
chVolR(127) {}
};
Channel chan[8];
struct QueuedWrite {

View file

@ -176,8 +176,8 @@ void DivPlatformAY8910::tick() {
// PSG
for (int i=0; i<3; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15));
if (chan[i].std.vol.had) {
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
if (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) {
rWrite(0x08+i,0);
@ -187,26 +187,26 @@ void DivPlatformAY8910::tick() {
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
rWrite(0x06,31-chan[i].std.duty);
if (chan[i].std.duty.had) {
rWrite(0x06,31-chan[i].std.duty.val);
}
if (chan[i].std.hadWave) {
chan[i].psgMode=(chan[i].std.wave+1)&7;
if (chan[i].std.wave.had) {
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
if (isMuted[i]) {
rWrite(0x08+i,0);
} else if (intellivision && (chan[i].psgMode&4)) {
@ -215,19 +215,19 @@ void DivPlatformAY8910::tick() {
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
}
}
if (chan[i].std.hadEx2) {
ayEnvMode=chan[i].std.ex2;
if (chan[i].std.ex2.had) {
ayEnvMode=chan[i].std.ex2.val;
rWrite(0x0d,ayEnvMode);
}
if (chan[i].std.hadEx3) {
chan[i].autoEnvNum=chan[i].std.ex3;
if (chan[i].std.ex3.had) {
chan[i].autoEnvNum=chan[i].std.ex3.val;
chan[i].freqChanged=true;
if (!chan[i].std.willAlg) chan[i].autoEnvDen=1;
if (!chan[i].std.alg.will) chan[i].autoEnvDen=1;
}
if (chan[i].std.hadAlg) {
chan[i].autoEnvDen=chan[i].std.alg;
if (chan[i].std.alg.had) {
chan[i].autoEnvDen=chan[i].std.alg.val;
chan[i].freqChanged=true;
if (!chan[i].std.willEx3) chan[i].autoEnvNum=1;
if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true);
@ -314,7 +314,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (isMuted[c.chan]) {
@ -431,11 +431,11 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
if (c.value) { // port B
ioPortB=true;
portBVal=c.value2;
logI("AY I/O port B write: %x\n",portBVal);
logI("AY I/O port B write: %x",portBVal);
} else { // port A
ioPortA=true;
portAVal=c.value2;
logI("AY I/O port A write: %x\n",portAVal);
logI("AY I/O port A write: %x",portAVal);
}
updateOutSel(true);
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
@ -497,6 +497,10 @@ void DivPlatformAY8910::flushWrites() {
while (!writes.empty()) writes.pop();
}
bool DivPlatformAY8910::getDCOffRequired() {
return true;
}
void DivPlatformAY8910::reset() {
while (!writes.empty()) writes.pop();
ay->device_reset();

View file

@ -95,6 +95,7 @@ class DivPlatformAY8910: public DivDispatch {
void setFlags(unsigned int flags);
bool isStereo();
bool keyOffAffectsArp(int ch);
bool getDCOffRequired();
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist);

View file

@ -123,7 +123,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l
}
while (!writes.empty()) {
QueuedWrite w=writes.front();
if (bank!=(w.addr>>4)) {
if ((int)bank!=(w.addr>>4)) {
bank=w.addr>>4;
ay->address_w(0x0d);
ay->data_w(0xa0|(bank<<4)|ayEnvMode[0]);
@ -191,8 +191,8 @@ void DivPlatformAY8930::tick() {
// PSG
for (int i=0; i<3; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=MIN(31,chan[i].std.vol)-(31-(chan[i].vol&31));
if (chan[i].std.vol.had) {
chan[i].outVol=MIN(31,chan[i].std.vol.val)-(31-(chan[i].vol&31));
if (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) {
rWrite(0x08+i,0);
@ -200,55 +200,55 @@ void DivPlatformAY8930::tick() {
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
rWrite(0x06,chan[i].std.duty);
if (chan[i].std.duty.had) {
rWrite(0x06,chan[i].std.duty.val);
}
if (chan[i].std.hadWave) {
chan[i].psgMode=(chan[i].std.wave+1)&7;
if (chan[i].std.wave.had) {
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
if (isMuted[i]) {
rWrite(0x08+i,0);
} else {
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
}
}
if (chan[i].std.hadEx1) { // duty
rWrite(0x16+i,chan[i].std.ex1);
if (chan[i].std.ex1.had) { // duty
rWrite(0x16+i,chan[i].std.ex1.val);
}
if (chan[i].std.hadEx2) {
ayEnvMode[i]=chan[i].std.ex2;
if (chan[i].std.ex2.had) {
ayEnvMode[i]=chan[i].std.ex2.val;
rWrite(regMode[i],ayEnvMode[i]);
}
if (chan[i].std.hadEx3) {
chan[i].autoEnvNum=chan[i].std.ex3;
if (chan[i].std.ex3.had) {
chan[i].autoEnvNum=chan[i].std.ex3.val;
chan[i].freqChanged=true;
if (!chan[i].std.willAlg) chan[i].autoEnvDen=1;
if (!chan[i].std.alg.will) chan[i].autoEnvDen=1;
}
if (chan[i].std.hadAlg) {
chan[i].autoEnvDen=chan[i].std.alg;
if (chan[i].std.alg.had) {
chan[i].autoEnvDen=chan[i].std.alg.val;
chan[i].freqChanged=true;
if (!chan[i].std.willEx3) chan[i].autoEnvNum=1;
if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1;
}
if (chan[i].std.hadFb) {
ayNoiseAnd=chan[i].std.fb;
if (chan[i].std.fb.had) {
ayNoiseAnd=chan[i].std.fb.val;
immWrite(0x19,ayNoiseAnd);
}
if (chan[i].std.hadFms) {
ayNoiseOr=chan[i].std.fms;
if (chan[i].std.fms.had) {
ayNoiseOr=chan[i].std.fms.val;
immWrite(0x1a,ayNoiseOr);
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
@ -256,7 +256,7 @@ void DivPlatformAY8930::tick() {
if (chan[i].freq>65535) chan[i].freq=65535;
if (chan[i].keyOn) {
if (chan[i].insChanged) {
if (!chan[i].std.willEx1) immWrite(0x16+i,chan[i].duty);
if (!chan[i].std.ex1.will) immWrite(0x16+i,chan[i].duty);
chan[i].insChanged=false;
}
}
@ -336,7 +336,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (isMuted[c.chan]) {
@ -456,11 +456,11 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
if (c.value) { // port B
ioPortB=true;
portBVal=c.value2;
logI("AY I/O port B write: %x\n",portBVal);
logI("AY I/O port B write: %x",portBVal);
} else { // port A
ioPortA=true;
portAVal=c.value2;
logI("AY I/O port A write: %x\n",portAVal);
logI("AY I/O port A write: %x",portAVal);
}
updateOutSel(true);
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));

View file

@ -84,28 +84,28 @@ void DivPlatformBubSysWSG::updateWave(int ch) {
void DivPlatformBubSysWSG::tick() {
for (int i=0; i<2; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol))/15;
if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))/15;
rWrite(2+i,(chan[i].wave<<5)|chan[i].outVol);
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadWave) {
if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave;
if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave.val;
chan[i].ws.changeWave1(chan[i].wave);
if (!chan[i].keyOff) chan[i].keyOn=true;
}
@ -174,14 +174,14 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
if (chan[c.chan].active) rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].outVol);
}
}
break;
case DIV_CMD_GET_VOLUME:
if (chan[c.chan].std.hasVol) {
if (chan[c.chan].std.vol.has) {
return chan[c.chan].vol;
}
return chan[c.chan].outVol;
@ -219,7 +219,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
break;
}
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -118,50 +118,50 @@ void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len)
void DivPlatformC64::updateFilter() {
rWrite(0x15,filtCut&7);
rWrite(0x16,filtCut>>3);
rWrite(0x17,(filtRes<<4)|(chan[2].filter<<2)|(chan[1].filter<<1)|(chan[0].filter));
rWrite(0x17,(filtRes<<4)|(chan[2].filter<<2)|(chan[1].filter<<1)|(int)(chan[0].filter));
rWrite(0x18,(filtControl<<4)|vol);
}
void DivPlatformC64::tick() {
for (int i=0; i<3; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
if (chan[i].std.vol.had) {
DivInstrument* ins=parent->getIns(chan[i].ins);
if (ins->c64.volIsCutoff) {
if (ins->c64.filterIsAbs) {
filtCut=MIN(2047,chan[i].std.vol);
filtCut=MIN(2047,chan[i].std.vol.val);
} else {
filtCut-=((signed char)chan[i].std.vol-18)*7;
filtCut-=((signed char)chan[i].std.vol.val-18)*7;
if (filtCut>2047) filtCut=2047;
if (filtCut<0) filtCut=0;
}
updateFilter();
} else {
vol=MIN(15,chan[i].std.vol);
vol=MIN(15,chan[i].std.vol.val);
updateFilter();
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp);
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
if (chan[i].std.duty.had) {
DivInstrument* ins=parent->getIns(chan[i].ins);
if (ins->c64.dutyIsAbs) {
chan[i].duty=chan[i].std.duty;
chan[i].duty=chan[i].std.duty.val;
} else {
chan[i].duty-=((signed char)chan[i].std.duty-12)*4;
chan[i].duty-=((signed char)chan[i].std.duty.val-12)*4;
}
rWrite(i*7+2,chan[i].duty&0xff);
rWrite(i*7+3,chan[i].duty>>8);
@ -175,21 +175,21 @@ void DivPlatformC64::tick() {
}
}
}
if (chan[i].std.hadWave) {
chan[i].wave=chan[i].std.wave;
rWrite(i*7+4,(isMuted[i]?8:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|chan[i].active);
if (chan[i].std.wave.had) {
chan[i].wave=chan[i].std.wave.val;
rWrite(i*7+4,(isMuted[i]?8:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
}
if (chan[i].std.hadEx1) {
filtControl=chan[i].std.ex1&15;
if (chan[i].std.ex1.had) {
filtControl=chan[i].std.ex1.val&15;
updateFilter();
}
if (chan[i].std.hadEx2) {
filtRes=chan[i].std.ex2&15;
if (chan[i].std.ex2.had) {
filtRes=chan[i].std.ex2.val&15;
updateFilter();
}
if (chan[i].std.hadEx3) {
chan[i].sync=chan[i].std.ex3&1;
chan[i].ring=chan[i].std.ex3&2;
if (chan[i].std.ex3.had) {
chan[i].sync=chan[i].std.ex3.val&1;
chan[i].ring=chan[i].std.ex3.val&2;
chan[i].freqChanged=true;
}
@ -226,13 +226,13 @@ int DivPlatformC64::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacroLen>0) {
if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) {
chan[c.chan].duty=ins->c64.duty;
rWrite(c.chan*7+2,chan[c.chan].duty&0xff);
rWrite(c.chan*7+3,chan[c.chan].duty>>8);
}
if (chan[c.chan].insChanged) {
chan[c.chan].wave=(ins->c64.noiseOn<<3)|(ins->c64.pulseOn<<2)|(ins->c64.sawOn<<1)|(ins->c64.triOn);
chan[c.chan].wave=(ins->c64.noiseOn<<3)|(ins->c64.pulseOn<<2)|(ins->c64.sawOn<<1)|(int)(ins->c64.triOn);
chan[c.chan].attack=ins->c64.a;
chan[c.chan].decay=(ins->c64.s==15)?0:ins->c64.d;
chan[c.chan].sustain=ins->c64.s;
@ -245,7 +245,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
if (ins->c64.initFilter) {
filtCut=ins->c64.cut;
filtRes=ins->c64.res;
filtControl=ins->c64.lp|(ins->c64.bp<<1)|(ins->c64.hp<<2)|(ins->c64.ch3off<<3);
filtControl=(int)(ins->c64.lp)|(ins->c64.bp<<1)|(ins->c64.hp<<2)|(ins->c64.ch3off<<3);
}
updateFilter();
}
@ -279,7 +279,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
vol=chan[c.chan].outVol;
} else {
@ -330,10 +330,10 @@ int DivPlatformC64::dispatch(DivCommand c) {
break;
case DIV_CMD_WAVE:
chan[c.chan].wave=c.value;
rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active);
rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active));
break;
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;
@ -411,11 +411,11 @@ int DivPlatformC64::dispatch(DivCommand c) {
break;
case 4:
chan[c.chan].ring=c.value;
rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active);
rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active));
break;
case 5:
chan[c.chan].sync=c.value;
rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active);
rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active));
break;
case 6:
filtControl&=7;
@ -434,7 +434,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
void DivPlatformC64::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
rWrite(ch*7+4,(isMuted[ch]?8:(chan[ch].wave<<4))|(chan[ch].ring<<2)|(chan[ch].sync<<1)|chan[ch].active);
rWrite(ch*7+4,(isMuted[ch]?8:(chan[ch].wave<<4))|(chan[ch].ring<<2)|(chan[ch].sync<<1)|(int)(chan[ch].active));
}
void DivPlatformC64::forceIns() {

View file

@ -100,40 +100,40 @@ void DivPlatformFDS::updateWave() {
void DivPlatformFDS::tick() {
for (int i=0; i<1; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
if (chan[i].std.vol.had) {
// ok, why are the volumes like that?
chan[i].outVol=MIN(32,chan[i].std.vol)-(32-MIN(32,chan[i].vol));
chan[i].outVol=MIN(32,chan[i].std.vol.val)-(32-MIN(32,chan[i].vol));
if (chan[i].outVol<0) chan[i].outVol=0;
rWrite(0x4080,0x80|chan[i].outVol);
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (i==3) { // noise
if (chan[i].std.arpMode) {
chan[i].baseFreq=chan[i].std.arp;
if (chan[i].std.arp.mode) {
chan[i].baseFreq=chan[i].std.arp.val;
} else {
chan[i].baseFreq=chan[i].note+chan[i].std.arp;
chan[i].baseFreq=chan[i].note+chan[i].std.arp.val;
}
if (chan[i].baseFreq>255) chan[i].baseFreq=255;
if (chan[i].baseFreq<0) chan[i].baseFreq=0;
} else {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
}
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true;
}
}
/*
if (chan[i].std.hadDuty) {
chan[i].duty=chan[i].std.duty;
if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val;
if (i==3) {
if (parent->song.properNoiseLayout) {
chan[i].duty&=1;
@ -148,9 +148,9 @@ void DivPlatformFDS::tick() {
chan[i].freqChanged=true;
}
}*/
if (chan[i].std.hadWave) {
if (chan[i].wave!=chan[i].std.wave || ws.activeChanged()) {
chan[i].wave=chan[i].std.wave;
if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave.val || ws.activeChanged()) {
chan[i].wave=chan[i].std.wave.val;
ws.changeWave1(chan[i].wave);
//if (!chan[i].keyOff) chan[i].keyOn=true;
}
@ -161,18 +161,18 @@ void DivPlatformFDS::tick() {
if (!chan[i].keyOff) chan[i].keyOn=true;
}
}
if (chan[i].std.hadEx1) { // mod depth
chan[i].modOn=chan[i].std.ex1;
chan[i].modDepth=chan[i].std.ex1;
if (chan[i].std.ex1.had) { // mod depth
chan[i].modOn=chan[i].std.ex1.val;
chan[i].modDepth=chan[i].std.ex1.val;
rWrite(0x4084,(chan[i].modOn<<7)|0x40|chan[i].modDepth);
}
if (chan[i].std.hadEx2) { // mod speed
chan[i].modFreq=chan[i].std.ex2;
if (chan[i].std.ex2.had) { // mod speed
chan[i].modFreq=chan[i].std.ex2.val;
rWrite(0x4086,chan[i].modFreq&0xff);
rWrite(0x4087,chan[i].modFreq>>8);
}
if (chan[i].std.hadEx3) { // mod position
chan[i].modPos=chan[i].std.ex3;
if (chan[i].std.ex3.had) { // mod position
chan[i].modPos=chan[i].std.ex3.val;
rWrite(0x4087,0x80|chan[i].modFreq>>8);
rWrite(0x4085,chan[i].modPos);
rWrite(0x4087,chan[i].modFreq>>8);
@ -276,7 +276,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
rWrite(0x4080,0x80|chan[c.chan].vol);
@ -359,7 +359,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
}
case DIV_CMD_LEGATO:
if (c.chan==3) break;
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -149,45 +149,45 @@ static unsigned char noiseTable[256]={
void DivPlatformGB::tick() {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (i==3) { // noise
if (chan[i].std.arpMode) {
chan[i].baseFreq=chan[i].std.arp+24;
if (chan[i].std.arp.mode) {
chan[i].baseFreq=chan[i].std.arp.val+24;
} else {
chan[i].baseFreq=chan[i].note+chan[i].std.arp;
chan[i].baseFreq=chan[i].note+chan[i].std.arp.val;
}
if (chan[i].baseFreq>255) chan[i].baseFreq=255;
if (chan[i].baseFreq<0) chan[i].baseFreq=0;
} else {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp+24);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val+24);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
chan[i].duty=chan[i].std.duty;
if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val;
DivInstrument* ins=parent->getIns(chan[i].ins);
if (i!=2) {
rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
} else {
if (parent->song.waveDutyIsVol) {
rWrite(16+i*5+2,gbVolMap[(chan[i].std.duty&3)<<2]);
rWrite(16+i*5+2,gbVolMap[(chan[i].std.duty.val&3)<<2]);
}
}
}
if (i==2 && chan[i].std.hadWave) {
if (chan[i].wave!=chan[i].std.wave || ws.activeChanged()) {
chan[i].wave=chan[i].std.wave;
if (i==2 && chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave.val || ws.activeChanged()) {
chan[i].wave=chan[i].std.wave.val;
ws.changeWave1(chan[i].wave);
if (!chan[i].keyOff) chan[i].keyOn=true;
}
@ -359,7 +359,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
}
case DIV_CMD_LEGATO:
if (c.chan==3) break;
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -74,9 +74,9 @@ const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
case 0x1d:
return "1Dxx: Set attack of operator 4 (0 to 1F)";
break;
case 0x20:
return "20xy: Set PSG noise mode (x: preset freq/ch3 freq; y: thin pulse/noise)";
break;
case 0x30:
return "30xx: Toggle hard envelope reset on new notes";
break;
}
return NULL;
}
@ -225,8 +225,8 @@ void DivPlatformGenesis::tick() {
if (i==2 && extMode) continue;
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127;
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
@ -242,24 +242,24 @@ void DivPlatformGenesis::tick() {
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp);
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadAlg) {
chan[i].state.alg=chan[i].std.alg;
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
@ -275,48 +275,48 @@ void DivPlatformGenesis::tick() {
}
}
}
if (chan[i].std.hadFb) {
chan[i].state.fb=chan[i].std.fb;
if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
}
if (chan[i].std.hadFms) {
chan[i].state.fms=chan[i].std.fms;
if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms.val;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
if (chan[i].std.hadAms) {
chan[i].state.ams=chan[i].std.ams;
if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams.val;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) {
op.am=m.am;
if (m.am.had) {
op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadAr) {
op.ar=m.ar;
if (m.ar.had) {
op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.hadDr) {
op.dr=m.dr;
if (m.dr.had) {
op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadMult) {
op.mult=m.mult;
if (m.mult.had) {
op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadRr) {
op.rr=m.rr;
if (m.rr.had) {
op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadSl) {
op.sl=m.sl;
if (m.sl.had) {
op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadTl) {
op.tl=127-m.tl;
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isMuted[i]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
@ -327,26 +327,44 @@ void DivPlatformGenesis::tick() {
}
}
}
if (m.hadRs) {
op.rs=m.rs;
if (m.rs.had) {
op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.hadDt) {
op.dt=m.dt;
if (m.dt.had) {
op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadD2r) {
op.d2r=m.d2r;
if (m.d2r.had) {
op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
if (m.hadSsg) {
op.ssgEnv=m.ssg;
if (m.ssg.had) {
op.ssgEnv=m.ssg.val;
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
}
if (chan[i].keyOn || chan[i].keyOff) {
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
immWrite(baseAddr+ADDR_SL_RR,0x0f);
immWrite(baseAddr+ADDR_TL,0x7f);
oldWrites[baseAddr+ADDR_SL_RR]=-1;
oldWrites[baseAddr+ADDR_TL]=-1;
//rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
}
immWrite(0x28,0x00|konOffs[i]);
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
for (int k=0; k<5; k++) {
immWrite(baseAddr+ADDR_SL_RR,0x0f);
}
}
}
chan[i].keyOff=false;
}
}
@ -505,7 +523,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
}
chan[c.chan].std.init(ins);
if (!chan[c.chan].std.willVol) {
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
@ -578,7 +596,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
for (int i=0; i<4; i++) {
@ -715,9 +733,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
break;
}
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_ALWAYS_SET_VOLUME:
return 0;
break;

View file

@ -38,7 +38,7 @@ class DivPlatformGenesis: public DivDispatch {
unsigned char freqH, freqL;
int freq, baseFreq, pitch, note;
unsigned char ins;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset;
int vol, outVol;
unsigned char pan;
Channel():
@ -57,6 +57,7 @@ class DivPlatformGenesis: public DivDispatch {
portaPause(false),
furnaceDac(false),
inPorta(false),
hardReset(false),
vol(0),
pan(3) {}
};

View file

@ -148,23 +148,23 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
void DivPlatformLynx::tick() {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol))>>7;
if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7;
WRITE_VOLUME(i,(isMuted[i]?0:(chan[i].outVol&127)));
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
chan[i].actualNote=chan[i].std.arp;
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
chan[i].actualNote=chan[i].std.arp.val;
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].actualNote=chan[i].note+chan[i].std.arp;
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
chan[i].actualNote=chan[i].note+chan[i].std.arp.val;
}
chan[i].freqChanged=true;
}
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].actualNote=chan[i].note;
chan[i].freqChanged=true;
@ -178,15 +178,15 @@ void DivPlatformLynx::tick() {
chan[i].lfsr=-1;
}
chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true);
if (chan[i].std.hadDuty) {
chan[i].duty=chan[i].std.duty;
if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val;
WRITE_FEEDBACK(i, chan[i].duty.feedback);
}
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
WRITE_BACKUP( i, chan[i].fd.backup );
}
else if (chan[i].std.hadDuty) {
chan[i].duty = chan[i].std.duty;
else if (chan[i].std.duty.had) {
chan[i].duty = chan[i].std.duty.val;
WRITE_FEEDBACK(i, chan[i].duty.feedback);
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
}
@ -228,7 +228,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (chan[c.chan].active) WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
@ -239,7 +239,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
WRITE_ATTEN(c.chan,chan[c.chan].pan);
break;
case DIV_CMD_GET_VOLUME:
if (chan[c.chan].std.hasVol) {
if (chan[c.chan].std.vol.has) {
return chan[c.chan].vol;
}
return chan[c.chan].outVol;
@ -272,7 +272,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
break;
}
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
chan[c.chan].actualNote=c.value;

View file

@ -89,7 +89,6 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
if (!isMuted[2]) {
sample+=mmc5->pcm.output*2;
}
sample=(sample-128)<<6;
if (sample>32767) sample=32767;
if (sample<-32768) sample=-32768;
bufL[i]=sample;
@ -99,29 +98,29 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
void DivPlatformMMC5::tick() {
for (int i=0; i<2; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
if (chan[i].std.vol.had) {
// ok, why are the volumes like that?
chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15));
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
if (chan[i].outVol<0) chan[i].outVol=0;
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
chan[i].duty=chan[i].std.duty;
if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val;
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
@ -243,7 +242,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (chan[c.chan].active) {
@ -291,7 +290,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
}
break;
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;
@ -336,6 +335,10 @@ int DivPlatformMMC5::getRegisterPoolSize() {
return 32;
}
float DivPlatformMMC5::getPostAmp() {
return 64.0f;
}
void DivPlatformMMC5::reset() {
for (int i=0; i<3; i++) {
chan[i]=DivPlatformMMC5::Channel();

View file

@ -74,6 +74,7 @@ class DivPlatformMMC5: public DivDispatch {
void tick();
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
float getPostAmp();
void setFlags(unsigned int flags);
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);

View file

@ -203,8 +203,8 @@ void DivPlatformN163::updateWaveCh(int ch) {
void DivPlatformN163::tick() {
for (int i=0; i<=chanMax; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(MIN(15,chan[i].std.vol)*(chan[i].vol&15))/15;
if (chan[i].std.vol.had) {
chan[i].outVol=(MIN(15,chan[i].std.vol.val)*(chan[i].vol&15))/15;
if (chan[i].outVol<0) chan[i].outVol=0;
if (chan[i].outVol>15) chan[i].outVol=15;
if (chan[i].resVol!=chan[i].outVol) {
@ -214,87 +214,87 @@ void DivPlatformN163::tick() {
}
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp);
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
if (chan[i].wavePos!=chan[i].std.duty) {
chan[i].wavePos=chan[i].std.duty;
if (chan[i].std.duty.had) {
if (chan[i].wavePos!=chan[i].std.duty.val) {
chan[i].wavePos=chan[i].std.duty.val;
if (chan[i].waveMode&0x2) {
chan[i].waveUpdated=true;
}
chan[i].waveChanged=true;
}
}
if (chan[i].std.hadWave) {
if (chan[i].wave!=chan[i].std.wave) {
chan[i].wave=chan[i].std.wave;
if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave.val) {
chan[i].wave=chan[i].std.wave.val;
if (chan[i].waveMode&0x2) {
chan[i].waveUpdated=true;
}
}
}
if (chan[i].std.hadEx1) {
if (chan[i].waveLen!=(chan[i].std.ex1&0xfc)) {
chan[i].waveLen=chan[i].std.ex1&0xfc;
if (chan[i].std.ex1.had) {
if (chan[i].waveLen!=(chan[i].std.ex1.val&0xfc)) {
chan[i].waveLen=chan[i].std.ex1.val&0xfc;
if (chan[i].waveMode&0x2) {
chan[i].waveUpdated=true;
}
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadEx2) {
if ((chan[i].waveMode&0x2)!=(chan[i].std.ex2&0x2)) { // update when every waveform changed
chan[i].waveMode=(chan[i].waveMode&~0x2)|(chan[i].std.ex2&0x2);
if (chan[i].std.ex2.had) {
if ((chan[i].waveMode&0x2)!=(chan[i].std.ex2.val&0x2)) { // update when every waveform changed
chan[i].waveMode=(chan[i].waveMode&~0x2)|(chan[i].std.ex2.val&0x2);
if (chan[i].waveMode&0x2) {
chan[i].waveUpdated=true;
chan[i].waveChanged=true;
}
}
if ((chan[i].waveMode&0x1)!=(chan[i].std.ex2&0x1)) { // update waveform now
chan[i].waveMode=(chan[i].waveMode&~0x1)|(chan[i].std.ex2&0x1);
if ((chan[i].waveMode&0x1)!=(chan[i].std.ex2.val&0x1)) { // update waveform now
chan[i].waveMode=(chan[i].waveMode&~0x1)|(chan[i].std.ex2.val&0x1);
if (chan[i].waveMode&0x1) { // rising edge
chan[i].waveUpdated=true;
chan[i].waveChanged=true;
}
}
}
if (chan[i].std.hadEx3) {
if (chan[i].loadWave!=chan[i].std.ex3) {
chan[i].loadWave=chan[i].std.ex3;
if (chan[i].std.ex3.had) {
if (chan[i].loadWave!=chan[i].std.ex3.val) {
chan[i].loadWave=chan[i].std.ex3.val;
if (chan[i].loadMode&0x2) {
updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc);
}
}
}
if (chan[i].std.hadAlg) {
if (chan[i].loadPos!=chan[i].std.alg) {
chan[i].loadPos=chan[i].std.alg;
if (chan[i].std.alg.had) {
if (chan[i].loadPos!=chan[i].std.alg.val) {
chan[i].loadPos=chan[i].std.alg.val;
}
}
if (chan[i].std.hadFb) {
if (chan[i].loadLen!=(chan[i].std.fb&0xfc)) {
chan[i].loadLen=chan[i].std.fb&0xfc;
if (chan[i].std.fb.had) {
if (chan[i].loadLen!=(chan[i].std.fb.val&0xfc)) {
chan[i].loadLen=chan[i].std.fb.val&0xfc;
}
}
if (chan[i].std.hadFms) {
if ((chan[i].loadMode&0x2)!=(chan[i].std.fms&0x2)) { // load when every waveform changes
chan[i].loadMode=(chan[i].loadMode&~0x2)|(chan[i].std.fms&0x2);
if (chan[i].std.fms.had) {
if ((chan[i].loadMode&0x2)!=(chan[i].std.fms.val&0x2)) { // load when every waveform changes
chan[i].loadMode=(chan[i].loadMode&~0x2)|(chan[i].std.fms.val&0x2);
}
if ((chan[i].loadMode&0x1)!=(chan[i].std.fms&0x1)) { // load now
chan[i].loadMode=(chan[i].loadMode&~0x1)|(chan[i].std.fms&0x1);
if ((chan[i].loadMode&0x1)!=(chan[i].std.fms.val&0x1)) { // load now
chan[i].loadMode=(chan[i].loadMode&~0x1)|(chan[i].std.fms.val&0x1);
if (chan[i].loadMode&0x1) { // rising edge
updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc);
}
@ -400,7 +400,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
chan[c.chan].resVol=chan[c.chan].outVol;
} else {
@ -513,7 +513,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
}
break;
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;
@ -607,6 +607,7 @@ void DivPlatformN163::reset() {
memset(regPool,0,128);
n163.set_disable(false);
n163.set_multiplex(multiplex);
chanMax=initChanMax;
loadWave=-1;
loadPos=0;
@ -636,8 +637,10 @@ void DivPlatformN163::setFlags(unsigned int flags) {
break;
}
initChanMax=chanMax=(flags>>4)&7;
multiplex=((flags>>7)&1)?false:true; // not accurate in real hardware
chipClock=rate;
rate/=15;
n163.set_multiplex(multiplex);
rWrite(0x7f,initChanMax<<4);
}

View file

@ -75,6 +75,7 @@ class DivPlatformN163: public DivDispatch {
unsigned char chanMax;
short loadWave, loadPos, loadLen;
unsigned char loadMode;
bool multiplex;
n163_core n163;
unsigned char regPool[128];

View file

@ -80,7 +80,14 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len)
DivSample* s=parent->getSample(dacSample);
if (s->samples>0) {
if (!isMuted[4]) {
rWrite(0x4011,((unsigned char)s->data8[dacPos]+0x80)>>1);
unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1;
if (dacAntiClickOn && dacAntiClick<next) {
dacAntiClick+=8;
rWrite(0x4011,dacAntiClick);
} else {
dacAntiClickOn=false;
rWrite(0x4011,next);
}
}
if (++dacPos>=s->samples) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
@ -101,7 +108,7 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len)
if (nes->apu.clocked) {
nes->apu.clocked=false;
}
int sample=(pulse_output(nes)+tnd_output(nes)-128)<<7;
int sample=(pulse_output(nes)+tnd_output(nes));
if (sample>32767) sample=32767;
if (sample<-32768) sample=-32768;
bufL[i]=sample;
@ -136,9 +143,9 @@ static unsigned char noiseTable[253]={
void DivPlatformNES::tick() {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
if (chan[i].std.vol.had) {
// ok, why are the volumes like that?
chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15));
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
if (chan[i].outVol<0) chan[i].outVol=0;
if (i==2) { // triangle
rWrite(0x4000+i*4,(chan[i].outVol==0)?0:255);
@ -147,33 +154,33 @@ void DivPlatformNES::tick() {
rWrite(0x4000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (i==3) { // noise
if (chan[i].std.arpMode) {
chan[i].baseFreq=chan[i].std.arp;
if (chan[i].std.arp.mode) {
chan[i].baseFreq=chan[i].std.arp.val;
} else {
chan[i].baseFreq=chan[i].note+chan[i].std.arp;
chan[i].baseFreq=chan[i].note+chan[i].std.arp.val;
}
if (chan[i].baseFreq>255) chan[i].baseFreq=255;
if (chan[i].baseFreq<0) chan[i].baseFreq=0;
} else {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
chan[i].duty=chan[i].std.duty;
if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val;
if (i==3) {
if (parent->song.properNoiseLayout) {
chan[i].duty&=1;
@ -337,7 +344,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (chan[c.chan].active) {
@ -406,7 +413,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
break;
case DIV_CMD_LEGATO:
if (c.chan==3) break;
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;
@ -454,6 +461,10 @@ int DivPlatformNES::getRegisterPoolSize() {
return 32;
}
float DivPlatformNES::getPostAmp() {
return 128.0f;
}
void DivPlatformNES::reset() {
for (int i=0; i<5; i++) {
chan[i]=DivPlatformNES::Channel();
@ -476,6 +487,9 @@ void DivPlatformNES::reset() {
rWrite(0x4015,0x1f);
rWrite(0x4001,chan[0].sweep);
rWrite(0x4005,chan[1].sweep);
dacAntiClickOn=true;
dacAntiClick=0;
}
bool DivPlatformNES::keyOffAffectsArp(int ch) {

View file

@ -54,10 +54,11 @@ class DivPlatformNES: public DivDispatch {
Channel chan[5];
bool isMuted[5];
int dacPeriod, dacRate;
unsigned int dacPos;
unsigned int dacPos, dacAntiClick;
int dacSample;
unsigned char sampleBank;
unsigned char apuType;
bool dacAntiClickOn;
struct NESAPU* nes;
unsigned char regPool[128];
@ -74,6 +75,7 @@ class DivPlatformNES: public DivDispatch {
void tick();
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
float getPostAmp();
void setFlags(unsigned int flags);
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);

View file

@ -233,8 +233,8 @@ void DivPlatformOPL::tick() {
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(chan[i].vol*MIN(63,chan[i].std.vol))/63;
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(63,chan[i].std.vol.val))/63;
for (int j=0; j<ops; j++) {
unsigned char slot=slots[j][i];
if (slot==255) continue;
@ -253,30 +253,30 @@ void DivPlatformOPL::tick() {
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp);
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadAlg) {
chan[i].state.alg=chan[i].std.alg;
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
}
if (chan[i].std.hadFb) {
chan[i].state.fb=chan[i].std.fb;
if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb.val;
}
if (chan[i].std.hadAlg || chan[i].std.hadFb) {
if (chan[i].std.alg.had || chan[i].std.fb.had) {
if (isMuted[i]) {
rWrite(chanMap[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&1)|(chan[i].state.fb<<1));
if (ops==4) {
@ -296,58 +296,58 @@ void DivPlatformOPL::tick() {
unsigned short baseAddr=slotMap[slot];
DivInstrumentFM::Operator& op=chan[i].state.op[(ops==4)?orderedOpsL[j]:j];
DivMacroInt::IntOp& m=chan[i].std.op[(ops==4)?orderedOpsL[j]:j];
if (m.hadAm) {
op.am=m.am;
if (m.am.had) {
op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
}
if (m.hadVib) {
op.vib=m.vib;
if (m.vib.had) {
op.vib=m.vib.val;
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
}
if (m.hadSus) {
op.sus=m.sus;
if (m.sus.had) {
op.sus=m.sus.val;
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
}
if (m.hadKsr) {
op.ksr=m.ksr;
if (m.ksr.had) {
op.ksr=m.ksr.val;
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
}
if (m.hadMult) {
op.mult=m.mult;
if (m.mult.had) {
op.mult=m.mult.val;
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
}
if (m.hadAr) {
op.ar=m.ar;
if (m.ar.had) {
op.ar=m.ar.val;
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
}
if (m.hadDr) {
op.dr=m.dr;
if (m.dr.had) {
op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
}
if (m.hadSl) {
op.sl=m.sl;
if (m.sl.had) {
op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
}
if (m.hadRr) {
op.rr=m.rr;
if (m.rr.had) {
op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
}
if (oplType>1) {
if (m.hadWs) {
op.ws=m.ws;
if (m.ws.had) {
op.ws=m.ws.val;
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
}
}
if (m.hadTl) {
op.tl=63-m.tl;
if (m.tl.had) {
op.tl=63-m.tl.val;
}
if (m.hadKsl) {
op.ksl=m.ksl;
if (m.ksl.had) {
op.ksl=m.ksl.val;
}
if (m.hadTl || m.hadKsl) {
if (m.tl.had || m.ksl.had) {
if (isMuted[i]) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
@ -371,7 +371,7 @@ void DivPlatformOPL::tick() {
if (update4OpMask) {
update4OpMask=false;
if (oplType==3) {
unsigned char opMask=chan[0].fourOp|(chan[2].fourOp<<1)|(chan[4].fourOp<<2)|(chan[6].fourOp<<3)|(chan[8].fourOp<<4)|(chan[10].fourOp<<5);
unsigned char opMask=(int)(chan[0].fourOp)|(chan[2].fourOp<<1)|(chan[4].fourOp<<2)|(chan[6].fourOp<<3)|(chan[8].fourOp<<4)|(chan[10].fourOp<<5);
immWrite(0x104,opMask);
//printf("updating opMask to %.2x\n",opMask);
}
@ -528,7 +528,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
}
chan[c.chan].std.init(ins);
if (!chan[c.chan].std.willVol) {
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].insChanged) {
@ -620,7 +620,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
if (c.value>63) c.value=63;
}
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
@ -1067,6 +1067,11 @@ void DivPlatformOPL::setFlags(unsigned int flags) {
chipClock=COLOR_NTSC;
rate=chipClock/72;
}
if (pretendYMU) {
rate=48000;
chipClock=rate*288;
}
}
int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {

View file

@ -115,51 +115,51 @@ void DivPlatformOPLL::tick() {
for (int i=0; i<11; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol))/15;
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol.val))/15;
if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp);
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadWave && chan[i].state.opllPreset!=16) {
chan[i].state.opllPreset=chan[i].std.wave;
if (chan[i].std.wave.had && chan[i].state.opllPreset!=16) {
chan[i].state.opllPreset=chan[i].std.wave.val;
if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
}
}
if (chan[i].state.opllPreset==0) {
if (chan[i].std.hadAlg) { // SUS
chan[i].state.alg=chan[i].std.alg;
if (chan[i].std.alg.had) { // SUS
chan[i].state.alg=chan[i].std.alg.val;
chan[i].freqChanged=true;
}
if (chan[i].std.hadFb) {
chan[i].state.fb=chan[i].std.fb;
if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb.val;
rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
}
if (chan[i].std.hadFms) {
chan[i].state.fms=chan[i].std.fms;
if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms.val;
rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
}
if (chan[i].std.hadAms) {
chan[i].state.ams=chan[i].std.ams;
if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams.val;
rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
}
@ -167,32 +167,32 @@ void DivPlatformOPLL::tick() {
DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) {
op.am=m.am;
if (m.am.had) {
op.am=m.am.val;
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
}
if (m.hadAr) {
op.ar=m.ar;
if (m.ar.had) {
op.ar=m.ar.val;
rWrite(0x04+j,(op.ar<<4)|(op.dr));
}
if (m.hadDr) {
op.dr=m.dr;
if (m.dr.had) {
op.dr=m.dr.val;
rWrite(0x04+j,(op.ar<<4)|(op.dr));
}
if (m.hadMult) {
op.mult=m.mult;
if (m.mult.had) {
op.mult=m.mult.val;
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
}
if (m.hadRr) {
op.rr=m.rr;
if (m.rr.had) {
op.rr=m.rr.val;
rWrite(0x06+j,(op.sl<<4)|(op.rr));
}
if (m.hadSl) {
op.sl=m.sl;
if (m.sl.had) {
op.sl=m.sl.val;
rWrite(0x06+j,(op.sl<<4)|(op.rr));
}
if (m.hadTl) {
op.tl=((j==1)?15:63)-m.tl;
if (m.tl.had) {
op.tl=((j==1)?15:63)-m.tl.val;
if (j==1) {
if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
@ -202,24 +202,24 @@ void DivPlatformOPLL::tick() {
}
}
if (m.hadEgt) {
op.ssgEnv=(m.egt&1)?8:0;
if (m.egt.had) {
op.ssgEnv=(m.egt.val&1)?8:0;
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
}
if (m.hadKsl) {
op.ksl=m.ksl;
if (m.ksl.had) {
op.ksl=m.ksl.val;
if (j==1) {
rWrite(0x02,(chan[i].state.op[0].ksl<<6)|(chan[i].state.op[0].tl&63));
} else {
rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
}
}
if (m.hadKsr) {
op.ksr=m.ksr;
if (m.ksr.had) {
op.ksr=m.ksr.val;
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
}
if (m.hadVib) {
op.vib=m.vib;
if (m.vib.had) {
op.vib=m.vib.val;
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
}
}
@ -361,7 +361,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
}
chan[c.chan].std.init(ins);
if (!chan[c.chan].std.willVol) {
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
@ -490,7 +490,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: {
if (c.chan>=9 && !properDrums) return 0;
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (c.chan>=6 && properDrums) {
@ -620,7 +620,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
}
case DIV_CMD_FM_EXTCH:
if (!properDrumsSys) break;
if (properDrums==c.value) break;
if ((int)properDrums==c.value) break;
if (c.value) {
properDrums=true;
immWrite(0x0e,0x20);

View file

@ -149,39 +149,39 @@ static unsigned char noiseFreq[12]={
void DivPlatformPCE::tick() {
for (int i=0; i<6; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=((chan[i].vol&31)*MIN(31,chan[i].std.vol))>>5;
if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&31)*MIN(31,chan[i].std.vol.val))>>5;
if (chan[i].furnaceDac) {
// ignore for now
} else {
chWrite(i,0x04,0x80|chan[i].outVol);
}
}
if (chan[i].std.hadDuty && i>=4) {
chan[i].noise=chan[i].std.duty;
if (chan[i].std.duty.had && i>=4) {
chan[i].noise=chan[i].std.duty.val;
chan[i].freqChanged=true;
int noiseSeek=chan[i].note;
if (noiseSeek<0) noiseSeek=0;
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
// noise
int noiseSeek=chan[i].std.arp;
int noiseSeek=chan[i].std.arp.val;
if (noiseSeek<0) noiseSeek=0;
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
int noiseSeek=chan[i].note+chan[i].std.arp;
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
int noiseSeek=chan[i].note+chan[i].std.arp.val;
if (noiseSeek<0) noiseSeek=0;
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
int noiseSeek=chan[i].note;
if (noiseSeek<0) noiseSeek=0;
@ -189,9 +189,9 @@ void DivPlatformPCE::tick() {
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadWave && !chan[i].pcm) {
if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave;
if (chan[i].std.wave.had && !chan[i].pcm) {
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave.val;
chan[i].ws.changeWave1(chan[i].wave);
if (!chan[i].keyOff) chan[i].keyOn=true;
}
@ -332,14 +332,14 @@ int DivPlatformPCE::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
if (chan[c.chan].active) chWrite(c.chan,0x04,0x80|chan[c.chan].outVol);
}
}
break;
case DIV_CMD_GET_VOLUME:
if (chan[c.chan].std.hasVol) {
if (chan[c.chan].std.vol.has) {
return chan[c.chan].vol;
}
return chan[c.chan].outVol;
@ -409,7 +409,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
break;
}
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -167,21 +167,21 @@ void DivPlatformPCSpeaker::acquire(short* bufL, short* bufR, size_t start, size_
void DivPlatformPCSpeaker::tick() {
for (int i=0; i<1; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(chan[i].vol && chan[i].std.vol);
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol && chan[i].std.vol.val);
on=chan[i].outVol;
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
@ -233,7 +233,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (chan[c.chan].active) {
@ -273,7 +273,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
}
case DIV_CMD_LEGATO:
if (c.chan==3) break;
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -87,28 +87,28 @@ void DivPlatformPET::writeOutVol() {
void DivPlatformPET::tick() {
chan.std.next();
if (chan.std.hadVol) {
chan.outVol=chan.std.vol&chan.vol;
if (chan.std.vol.had) {
chan.outVol=chan.std.vol.val&chan.vol;
writeOutVol();
}
if (chan.std.hadArp) {
if (chan.std.arp.had) {
if (!chan.inPorta) {
if (chan.std.arpMode) {
chan.baseFreq=NOTE_PERIODIC(chan.std.arp);
if (chan.std.arp.mode) {
chan.baseFreq=NOTE_PERIODIC(chan.std.arp.val);
} else {
chan.baseFreq=NOTE_PERIODIC(chan.note+chan.std.arp);
chan.baseFreq=NOTE_PERIODIC(chan.note+chan.std.arp.val);
}
}
chan.freqChanged=true;
} else {
if (chan.std.arpMode && chan.std.finishedArp) {
if (chan.std.arp.mode && chan.std.arp.finished) {
chan.baseFreq=NOTE_PERIODIC(chan.note);
chan.freqChanged=true;
}
}
if (chan.std.hadWave) {
if (chan.wave!=chan.std.wave) {
chan.wave=chan.std.wave;
if (chan.std.wave.had) {
if (chan.wave!=chan.std.wave.val) {
chan.wave=chan.std.wave.val;
rWrite(10,chan.wave);
}
}
@ -118,7 +118,7 @@ void DivPlatformPET::tick() {
if (chan.freq<2) chan.freq=2;
rWrite(8,chan.freq-2);
if (chan.keyOn) {
if (!chan.std.willVol) {
if (!chan.std.vol.will) {
chan.outVol=chan.vol;
writeOutVol();
}
@ -163,7 +163,7 @@ int DivPlatformPET::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan.vol!=c.value) {
chan.vol=c.value;
if (!chan.std.hadVol) {
if (!chan.std.vol.had) {
chan.outVol=chan.vol;
writeOutVol();
}
@ -204,7 +204,7 @@ int DivPlatformPET::dispatch(DivCommand c) {
break;
}
case DIV_CMD_LEGATO:
chan.baseFreq=NOTE_PERIODIC(c.value+((chan.std.willArp && !chan.std.arpMode)?(chan.std.arp):(0)));
chan.baseFreq=NOTE_PERIODIC(c.value+((chan.std.arp.will && !chan.std.arp.mode)?(chan.std.arp.val):(0)));
chan.freqChanged=true;
chan.note=c.value;
break;

View file

@ -277,8 +277,8 @@ void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t l
void DivPlatformQSound::tick() {
for (int i=0; i<16; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol)>>6;
if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6;
// Check if enabled and write volume
if (chan[i].active) {
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 4);
@ -311,17 +311,17 @@ void DivPlatformQSound::tick() {
qsound_loop = length - s->loopStart;
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true;
}
@ -336,9 +336,9 @@ void DivPlatformQSound::tick() {
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);
//logW("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!\n",i,qsound_bank,qsound_addr,qsound_end,qsound_loop);
//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.hadVol) {
if (!chan[i].std.vol.had) {
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4);
}
}
@ -347,7 +347,7 @@ void DivPlatformQSound::tick() {
rWrite(q1_reg_map[Q1V_VOL][i], 0);
rWrite(q1_reg_map[Q1V_FREQ][i], 0);
} else if (chan[i].active) {
//logW("ch %d frequency set to %04x, off=%f, note=%d, %04x!\n",i,chan[i].freq,off,chan[i].note,QS_NOTE_FREQUENCY(chan[i].note));
//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 (chan[i].keyOn) chan[i].keyOn=false;
@ -404,7 +404,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
// Check if enabled and write volume
chan[c.chan].outVol=c.value;
if (chan[c.chan].active && c.chan < 16) {
@ -414,7 +414,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
}
break;
case DIV_CMD_GET_VOLUME:
if (chan[c.chan].std.hasVol) {
if (chan[c.chan].std.vol.has) {
return chan[c.chan].vol;
}
return chan[c.chan].outVol;
@ -477,7 +477,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
off=(double)s->centerRate/24038.0/16.0;
}
}
chan[c.chan].baseFreq=off*QS_NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp-12):(0)));
chan[c.chan].baseFreq=off*QS_NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val-12):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -135,8 +135,8 @@ inline unsigned char applyPan(unsigned char vol, unsigned char pan) {
void DivPlatformSAA1099::tick() {
for (int i=0; i<6; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15));
if (chan[i].std.vol.had) {
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
if (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) {
rWrite(i,0);
@ -144,30 +144,30 @@ void DivPlatformSAA1099::tick() {
rWrite(i,applyPan(chan[i].outVol&15,chan[i].pan));
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
saaNoise[i/3]=chan[i].std.duty&3;
if (chan[i].std.duty.had) {
saaNoise[i/3]=chan[i].std.duty.val&3;
rWrite(0x16,saaNoise[0]|(saaNoise[1]<<4));
}
if (chan[i].std.hadWave) {
chan[i].psgMode=chan[i].std.wave&3;
if (chan[i].std.wave.had) {
chan[i].psgMode=chan[i].std.wave.val&3;
}
if (chan[i].std.hadEx1) {
saaEnv[i/3]=chan[i].std.ex1;
if (chan[i].std.ex1.had) {
saaEnv[i/3]=chan[i].std.ex1.val;
rWrite(0x18+(i/3),saaEnv[i/3]);
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
@ -253,7 +253,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (isMuted[c.chan]) {
@ -414,6 +414,16 @@ void DivPlatformSAA1099::reset() {
extMode=false;
rWrite(8,255);
rWrite(9,255);
rWrite(10,255);
rWrite(11,255);
rWrite(12,255);
rWrite(13,255);
rWrite(16,0x77);
rWrite(17,0x77);
rWrite(18,0x77);
rWrite(0x1c,2);
rWrite(0x1c,1);
}

View file

@ -80,21 +80,21 @@ void DivPlatformSegaPCM::tick() {
for (int i=0; i<16; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127;
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=(chan[i].std.arp<<6);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=(chan[i].std.arp.val<<6);
} else {
chan[i].baseFreq=((chan[i].note+(signed char)chan[i].std.arp)<<6);
chan[i].baseFreq=((chan[i].note+(signed char)chan[i].std.arp.val)<<6);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=(chan[i].note<<6);
chan[i].freqChanged=true;
}
@ -214,7 +214,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
chan[c.chan].chVolL=c.value;

View file

@ -56,21 +56,21 @@ int DivPlatformSMS::acquireOne() {
void DivPlatformSMS::tick() {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15));
if (chan[i].std.vol.had) {
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
if (chan[i].outVol<0) chan[i].outVol=0;
// old formula
// ((chan[i].vol&15)*MIN(15,chan[i].std.vol))>>4;
// ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4;
rWrite(0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15))));
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
chan[i].actualNote=chan[i].std.arp;
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
chan[i].actualNote=chan[i].std.arp.val;
} else {
// TODO: check whether this weird octave boundary thing applies to other systems as well
int areYouSerious=chan[i].note+chan[i].std.arp;
int areYouSerious=chan[i].note+chan[i].std.arp.val;
while (areYouSerious>0x60) areYouSerious-=12;
chan[i].baseFreq=NOTE_PERIODIC(areYouSerious);
chan[i].actualNote=areYouSerious;
@ -78,15 +78,15 @@ void DivPlatformSMS::tick() {
chan[i].freqChanged=true;
}
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].actualNote=chan[i].note;
chan[i].freqChanged=true;
}
}
if (i==3) if (chan[i].std.hadDuty) {
snNoiseMode=chan[i].std.duty;
if (chan[i].std.duty<2) {
if (i==3) if (chan[i].std.duty.had) {
snNoiseMode=chan[i].std.duty.val;
if (chan[i].std.duty.val<2) {
chan[3].freqChanged=false;
}
updateSNMode=true;
@ -130,11 +130,11 @@ void DivPlatformSMS::tick() {
}
} else { // 3 fixed values
unsigned char value;
if (chan[3].std.hadArp) {
if (chan[3].std.arpMode) {
value=chan[3].std.arp%12;
if (chan[3].std.arp.had) {
if (chan[3].std.arp.mode) {
value=chan[3].std.arp.val%12;
} else {
value=(chan[3].note+chan[3].std.arp)%12;
value=(chan[3].note+chan[3].std.arp.val)%12;
}
} else {
value=chan[3].note%12;
@ -181,14 +181,14 @@ int DivPlatformSMS::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (chan[c.chan].active) rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
}
break;
case DIV_CMD_GET_VOLUME:
if (chan[c.chan].std.hasVol) {
if (chan[c.chan].std.vol.has) {
return chan[c.chan].vol;
}
return chan[c.chan].outVol;
@ -225,7 +225,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
updateSNMode=true;
break;
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
chan[c.chan].actualNote=c.value;

View file

@ -1120,7 +1120,7 @@ void ay8910_device::sound_stream_update(short** outputs, int outLen)
for (int chan = 0; chan < NUM_CHANNELS; chan++)
{
tone = &m_tone[chan];
m_vol_enabled[chan] = (tone->output | tone_enable(chan)) & (noise_output() | noise_enable(chan));
m_vol_enabled[chan] = (tone->output | (unsigned char)tone_enable(chan)) & (noise_output() | (unsigned char)noise_enable(chan));
}
/* update envelope */

View file

@ -58,16 +58,27 @@
Frequency formula:
Frequency: Pitch input * ((Input clock * 15 * Number of activated voices) / 65536)
There's to way for reduce N163 noises: reduce channel limit and demultiplex
- Channel limit is runtime changeable and it makes some usable effects.
- Demultiplex is used for "non-ear destroyable" emulators, but less hardware accurate. (when LPF and RF filter is not considered)
This core is support both, You can choose output behavior
*/
#include "n163.hpp"
void n163_core::tick()
{
m_out = 0;
if (m_multiplex)
m_out = 0;
// 0xe000-0xe7ff Disable sound bits (bit 6, bit 0 to 5 are CPU ROM Bank 0x8000-0x9fff select.)
if (m_disable)
{
if (!m_multiplex)
m_out = 0;
return;
}
// tick per each clock
const u32 freq = m_ram[m_voice_cycle + 0] | (u32(m_ram[m_voice_cycle + 2]) << 8) | (bitfield<u32>(m_ram[m_voice_cycle + 4], 0, 2) << 16); // 18 bit frequency
@ -88,22 +99,34 @@ void n163_core::tick()
m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8);
// update voice cycle
bool flush = m_multiplex ? true : false;
m_voice_cycle -= 0x8;
if (m_voice_cycle < (0x78 - (bitfield(m_ram[0x7f], 4, 3) << 3)))
{
if (!m_multiplex)
flush = true;
m_voice_cycle = 0x78;
}
// output 4 bit waveform and volume, multiplexed
m_out = wave * volume;
m_acc += wave * volume;
if (flush)
{
m_out = m_acc / (m_multiplex ? 1 : (bitfield(m_ram[0x7f], 4, 3) + 1));
m_acc = 0;
}
}
void n163_core::reset()
{
// reset this chip
m_disable = false;
m_multiplex = true;
std::fill(std::begin(m_ram), std::end(m_ram), 0);
m_voice_cycle = 0x78;
m_addr_latch.reset();
m_out = 0;
m_acc = 0;
}
// accessor

View file

@ -48,6 +48,7 @@ public:
// register pool
u8 reg(u8 addr) { return m_ram[addr & 0x7f]; }
void set_multiplex(bool multiplex = true) { m_multiplex = multiplex; }
private:
// Address latch
@ -73,6 +74,9 @@ private:
u8 m_voice_cycle = 0x78; // Voice cycle for processing
addr_latch_t m_addr_latch; // address latch
s16 m_out = 0; // output
// demultiplex related
bool m_multiplex = true; // multiplex flag, but less noisy = inaccurate!
s16 m_acc = 0; // accumulated output
};
#endif

View file

@ -213,7 +213,8 @@ void apu_turn_on(struct NESAPU* a, BYTE apu_type) {
a->S2.sweep.delay = 1;
a->S2.sweep.divider = 1;
a->TR.frequency = 1;
a->TR.sequencer = 0;
/* questo era 0 ma produce click nell'audio */
a->TR.sequencer = 7;
a->NS.frequency = 1;
a->NS.shift = 1;
a->DMC.frequency = 1;

View file

@ -33,7 +33,7 @@
#pragma once
#ifdef _MSC_VER
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif

View file

@ -145,31 +145,31 @@ void DivPlatformSwan::tick() {
unsigned char sndCtrl=(pcm?0x20:0)|(sweep?0x40:0)|((noise>0)?0x80:0);
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
int env=chan[i].std.vol;
if (chan[i].std.vol.had) {
int env=chan[i].std.vol.val;
if(parent->getIns(chan[i].ins)->type==DIV_INS_AMIGA) {
env=MIN(env/4,15);
}
calcAndWriteOutVol(i,env);
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadWave && !(i==1 && pcm)) {
if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave;
if (chan[i].std.wave.had && !(i==1 && pcm)) {
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave.val;
chan[i].ws.changeWave1(chan[i].wave);
}
}
@ -200,7 +200,7 @@ void DivPlatformSwan::tick() {
rWrite(i*2,rVal&0xff);
rWrite(i*2+1,rVal>>8);
if (chan[i].keyOn) {
if (!chan[i].std.willVol) {
if (!chan[i].std.vol.will) {
calcAndWriteOutVol(i,15);
}
chan[i].keyOn=false;
@ -211,8 +211,8 @@ void DivPlatformSwan::tick() {
chan[i].freqChanged=false;
}
}
if (chan[3].std.hadDuty) {
noise=chan[3].std.duty;
if (chan[3].std.duty.had) {
noise=chan[3].std.duty.val;
if (noise>0) {
rWrite(0x0e,((noise-1)&0x07)|0x18);
sndCtrl|=0x80;
@ -319,7 +319,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hadVol) {
if (!chan[c.chan].std.vol.had) {
calcAndWriteOutVol(c.chan,15);
}
}
@ -391,11 +391,11 @@ int DivPlatformSwan::dispatch(DivCommand c) {
break;
case DIV_CMD_PANNING: {
chan[c.chan].pan=c.value;
calcAndWriteOutVol(c.chan,chan[c.chan].std.willVol?chan[c.chan].std.vol:15);
calcAndWriteOutVol(c.chan,chan[c.chan].std.vol.will?chan[c.chan].std.vol.val:15);
break;
}
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -87,8 +87,8 @@ unsigned char DivPlatformTIA::dealWithFreq(unsigned char shape, int base, int pi
void DivPlatformTIA::tick() {
for (int i=0; i<2; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15));
if (chan[i].std.vol.had) {
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
if (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) {
rWrite(0x19+i,0);
@ -96,29 +96,29 @@ void DivPlatformTIA::tick() {
rWrite(0x19+i,chan[i].outVol&15);
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=0x80000000|chan[i].std.arp;
if (chan[i].std.arp.mode) {
chan[i].baseFreq=0x80000000|chan[i].std.arp.val;
} else {
chan[i].baseFreq=(chan[i].note+chan[i].std.arp)<<8;
chan[i].baseFreq=(chan[i].note+chan[i].std.arp.val)<<8;
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=chan[i].note<<8;
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadWave) {
chan[i].shape=chan[i].std.wave&15;
if (chan[i].std.wave.had) {
chan[i].shape=chan[i].std.wave.val&15;
rWrite(0x15+i,chan[i].shape);
chan[i].freqChanged=true;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
if (chan[i].insChanged) {
if (!chan[i].std.willWave) {
if (!chan[i].std.wave.will) {
chan[i].shape=4;
rWrite(0x15+i,chan[i].shape);
}
@ -179,7 +179,7 @@ int DivPlatformTIA::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (isMuted[c.chan]) {

View file

@ -137,6 +137,9 @@ const char* DivPlatformTX81Z::getEffectName(unsigned char effect) {
case 0x1f:
return "1Fxx: Set PM depth (0 to 7F)";
break;
case 0x30:
return "30xx: Toggle hard envelope reset on new notes";
break;
}
return NULL;
}
@ -184,8 +187,8 @@ void DivPlatformTX81Z::tick() {
for (int i=0; i<8; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127;
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
@ -197,50 +200,50 @@ void DivPlatformTX81Z::tick() {
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp);
chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_LINEAR(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
if (chan[i].std.duty>0) {
rWrite(0x0f,0x80|(0x20-chan[i].std.duty));
if (chan[i].std.duty.had) {
if (chan[i].std.duty.val>0) {
rWrite(0x0f,0x80|(0x20-chan[i].std.duty.val));
} else {
rWrite(0x0f,0);
}
}
if (chan[i].std.hadWave) {
rWrite(0x1b,chan[i].std.wave&3);
if (chan[i].std.wave.had) {
rWrite(0x1b,chan[i].std.wave.val&3);
}
if (chan[i].std.hadEx1) {
amDepth=chan[i].std.ex1;
if (chan[i].std.ex1.had) {
amDepth=chan[i].std.ex1.val;
immWrite(0x19,amDepth);
}
if (chan[i].std.hadEx2) {
pmDepth=chan[i].std.ex2;
if (chan[i].std.ex2.had) {
pmDepth=chan[i].std.ex2.val;
immWrite(0x19,0x80|pmDepth);
}
if (chan[i].std.hadEx3) {
immWrite(0x18,chan[i].std.ex3);
if (chan[i].std.ex3.had) {
immWrite(0x18,chan[i].std.ex3.val);
}
if (chan[i].std.hadAlg) {
chan[i].state.alg=chan[i].std.alg;
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
if (isMuted[i]) {
immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x40);
} else {
@ -260,82 +263,99 @@ void DivPlatformTX81Z::tick() {
}
}
}
if (chan[i].std.hadFb) {
chan[i].state.fb=chan[i].std.fb;
if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb.val;
if (isMuted[i]) {
immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x40);
} else {
immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|(chan[i].active?0:0x40)|(chan[i].chVolR<<7));
}
}
if (chan[i].std.hadFms) {
chan[i].state.fms=chan[i].std.fms;
if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms.val;
rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3));
}
if (chan[i].std.hadAms) {
chan[i].state.ams=chan[i].std.ams;
if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams.val;
rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3));
}
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) {
op.am=m.am;
if (m.am.had) {
op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadAr) {
op.ar=m.ar;
if (m.ar.had) {
op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6));
}
if (m.hadDr) {
op.dr=m.dr;
if (m.dr.had) {
op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadMult) {
op.mult=m.mult;
if (m.mult.had) {
op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadRr) {
op.rr=m.rr;
if (m.rr.had) {
op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadSl) {
op.sl=m.sl;
if (m.sl.had) {
op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadTl) {
op.tl=127-m.tl;
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
if (m.hadRs) {
op.rs=m.rs;
if (m.rs.had) {
op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6));
}
if (m.hadDt) {
op.dt=m.dt;
if (m.dt.had) {
op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadD2r) {
op.d2r=m.d2r;
if (m.d2r.had) {
op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
}
if (m.hadDt2) {
op.dt2=m.dt2;
if (m.dt2.had) {
op.dt2=m.dt2.val;
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
}
}
if (chan[i].keyOn || chan[i].keyOff) {
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
immWrite(baseAddr+ADDR_SL_RR,0x0f);
immWrite(baseAddr+ADDR_TL,0x7f);
oldWrites[baseAddr+ADDR_SL_RR]=-1;
oldWrites[baseAddr+ADDR_TL]=-1;
}
}
if (isMuted[i]) {
immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x00);
} else {
//if (chan[i].keyOn) immWrite(0x08,i);
immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x00|(chan[i].chVolR<<7));
}
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
for (int k=0; k<9; k++) {
immWrite(baseAddr+ADDR_SL_RR,0x0f);
}
}
}
chan[i].keyOff=false;
}
}
@ -401,7 +421,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
}
chan[c.chan].std.init(ins);
if (!chan[c.chan].std.willVol) {
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
@ -435,6 +455,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)|((chan[c.chan].chVolL&1)<<6)|((chan[c.chan].chVolR&1)<<7));
}*/
rWrite(chanOffs[c.chan]+ADDR_FMS_AMS,((chan[c.chan].state.fms&7)<<4)|(chan[c.chan].state.ams&3));
//rWrite(chanOffs[c.chan]+ADDR_FMS_AMS,0x84|((chan[c.chan].state.fms2&7)<<4)|(chan[c.chan].state.ams2&3));
}
chan[c.chan].insChanged=false;
@ -463,7 +484,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
for (int i=0; i<4; i++) {
@ -596,6 +617,9 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
immWrite(0x19,0x80|pmDepth);
break;
}
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_CMD_STD_NOISE_FREQ: {
if (c.chan!=7) break;
if (c.value) {
@ -652,6 +676,7 @@ void DivPlatformTX81Z::forceIns() {
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|((chan[i].chVolL&1)<<6)|((chan[i].chVolR&1)<<7));
}*/
rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3));
//rWrite(chanOffs[i]+ADDR_FMS_AMS,0x84|((chan[i].state.fms2&7)<<4)|(chan[i].state.ams2&3));
if (chan[i].active) {
chan[i].keyOn=true;
chan[i].freqChanged=true;

View file

@ -38,10 +38,30 @@ class DivPlatformTX81Z: public DivDispatch {
int freq, baseFreq, pitch, note;
unsigned char ins;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset;
int vol, outVol;
unsigned char chVolL, chVolR;
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {}
Channel():
freqH(0),
freqL(0),
freq(0),
baseFreq(0),
pitch(0),
note(0),
ins(-1),
active(false),
insChanged(true),
freqChanged(false),
keyOn(false),
keyOff(false),
inPorta(false),
portaPause(false),
furnacePCM(false),
hardReset(false),
vol(0),
outVol(0),
chVolL(127),
chVolR(127) {}
};
Channel chan[8];
struct QueuedWrite {

View file

@ -158,30 +158,30 @@ int DivPlatformVERA::calcNoteFreq(int ch, int note) {
void DivPlatformVERA::tick() {
for (int i=0; i<16; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=MAX(chan[i].vol+chan[i].std.vol-63,0);
if (chan[i].std.vol.had) {
chan[i].outVol=MAX(chan[i].vol+chan[i].std.vol.val-63,0);
rWriteLo(i,2,chan[i].outVol);
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=calcNoteFreq(0,chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=calcNoteFreq(0,chan[i].std.arp.val);
} else {
chan[i].baseFreq=calcNoteFreq(0,chan[i].note+chan[i].std.arp);
chan[i].baseFreq=calcNoteFreq(0,chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=calcNoteFreq(0,chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
rWriteLo(i,3,chan[i].std.duty);
if (chan[i].std.duty.had) {
rWriteLo(i,3,chan[i].std.duty.val);
}
if (chan[i].std.hadWave) {
rWriteHi(i,3,chan[i].std.wave);
if (chan[i].std.wave.had) {
rWriteHi(i,3,chan[i].std.wave.val);
}
if (chan[i].freqChanged) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8);
@ -193,21 +193,21 @@ void DivPlatformVERA::tick() {
}
// PCM
chan[16].std.next();
if (chan[16].std.hadVol) {
chan[16].outVol=MAX(chan[16].vol+MIN(chan[16].std.vol/4,15)-15,0);
if (chan[16].std.vol.had) {
chan[16].outVol=MAX(chan[16].vol+MIN(chan[16].std.vol.val/4,15)-15,0);
rWritePCMVol(chan[16].outVol&15);
}
if (chan[16].std.hadArp) {
if (chan[16].std.arp.had) {
if (!chan[16].inPorta) {
if (chan[16].std.arpMode) {
chan[16].baseFreq=calcNoteFreq(16,chan[16].std.arp);
if (chan[16].std.arp.mode) {
chan[16].baseFreq=calcNoteFreq(16,chan[16].std.arp.val);
} else {
chan[16].baseFreq=calcNoteFreq(16,chan[16].note+chan[16].std.arp);
chan[16].baseFreq=calcNoteFreq(16,chan[16].note+chan[16].std.arp.val);
}
}
chan[16].freqChanged=true;
} else {
if (chan[16].std.arpMode && chan[16].std.finishedArp) {
if (chan[16].std.arp.mode && chan[16].std.arp.finished) {
chan[16].baseFreq=calcNoteFreq(16,chan[16].note);
chan[16].freqChanged=true;
}
@ -311,7 +311,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
break;
}
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=calcNoteFreq(c.chan,c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=calcNoteFreq(c.chan,c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -94,28 +94,28 @@ void DivPlatformVIC20::writeOutVol(int ch) {
void DivPlatformVIC20::tick() {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
int env=chan[i].std.vol;
if (chan[i].std.vol.had) {
int env=chan[i].std.vol.val;
calcAndWriteOutVol(i,env);
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadWave) {
if (chan[i].wave!=chan[i].std.wave) {
chan[i].wave=chan[i].std.wave&0x0f;
if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave.val) {
chan[i].wave=chan[i].std.wave.val&0x0f;
chan[i].keyOn=true;
}
}
@ -183,7 +183,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hadVol) {
if (!chan[c.chan].std.vol.had) {
calcAndWriteOutVol(c.chan,15);
}
}
@ -223,7 +223,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
break;
}
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -140,16 +140,16 @@ void DivPlatformVRC6::tick() {
// 16 for pulse; 14 for saw
int CHIP_DIVIDER=(i==2)?14:16;
chan[i].std.next();
if (chan[i].std.hadVol) {
if (chan[i].std.vol.had) {
if (i==2) { // sawtooth
chan[i].outVol=((chan[i].vol&63)*MIN(63,chan[i].std.vol))/63;
chan[i].outVol=((chan[i].vol&63)*MIN(63,chan[i].std.vol.val))/63;
if (chan[i].outVol<0) chan[i].outVol=0;
if (chan[i].outVol>63) chan[i].outVol=63;
if (!isMuted[i]) {
chWrite(i,0,chan[i].outVol);
}
} else { // pulse
chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol))/15;
chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))/15;
if (chan[i].outVol<0) chan[i].outVol=0;
if (chan[i].outVol>15) chan[i].outVol=15;
if ((!isMuted[i]) && (!chan[i].pcm)) {
@ -157,23 +157,23 @@ void DivPlatformVRC6::tick() {
}
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
chan[i].duty=chan[i].std.duty;
if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val;
if ((!isMuted[i]) && (i!=2) && (!chan[i].pcm)) { // pulse
chWrite(i,0,(chan[i].outVol&0xf)|((chan[i].duty&7)<<4));
}
@ -310,7 +310,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (!isMuted[c.chan]) {
@ -371,7 +371,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
}
break;
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;

View file

@ -339,41 +339,41 @@ void DivPlatformX1_010::updateEnvelope(int ch) {
void DivPlatformX1_010::tick() {
for (int i=0; i<16; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
signed char macroVol=((chan[i].vol&15)*MIN(chan[i].furnacePCM?64:15,chan[i].std.vol))/(chan[i].furnacePCM?64:15);
if (chan[i].std.vol.had) {
signed char macroVol=((chan[i].vol&15)*MIN(chan[i].furnacePCM?64:15,chan[i].std.vol.val))/(chan[i].furnacePCM?64:15);
if ((!isMuted[i]) && (macroVol!=chan[i].outVol)) {
chan[i].outVol=macroVol;
chan[i].envChanged=true;
}
}
if ((!chan[i].pcm) || chan[i].furnacePCM) {
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NoteX1_010(i,chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NoteX1_010(i,chan[i].std.arp.val);
} else {
chan[i].baseFreq=NoteX1_010(i,chan[i].note+chan[i].std.arp);
chan[i].baseFreq=NoteX1_010(i,chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NoteX1_010(i,chan[i].note);
chan[i].freqChanged=true;
}
}
}
if (chan[i].std.hadWave && !chan[i].pcm) {
if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave;
if (chan[i].std.wave.had && !chan[i].pcm) {
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave.val;
if (!chan[i].pcm) {
chan[i].ws.changeWave1(chan[i].wave);
if (!chan[i].keyOff) chan[i].keyOn=true;
}
}
}
if (chan[i].std.hadEx1) {
bool nextEnable=(chan[i].std.ex1&1);
if (chan[i].std.ex1.had) {
bool nextEnable=(chan[i].std.ex1.val&1);
if (nextEnable!=(chan[i].env.flag.envEnable)) {
chan[i].env.flag.envEnable=nextEnable;
if (!chan[i].pcm) {
@ -383,42 +383,42 @@ void DivPlatformX1_010::tick() {
refreshControl(i);
}
}
bool nextOneshot=(chan[i].std.ex1&2);
bool nextOneshot=(chan[i].std.ex1.val&2);
if (nextOneshot!=(chan[i].env.flag.envOneshot)) {
chan[i].env.flag.envOneshot=nextOneshot;
if (!chan[i].pcm) {
refreshControl(i);
}
}
bool nextSplit=(chan[i].std.ex1&4);
bool nextSplit=(chan[i].std.ex1.val&4);
if (nextSplit!=(chan[i].env.flag.envSplit)) {
chan[i].env.flag.envSplit=nextSplit;
if (!isMuted[i] && !chan[i].pcm) {
chan[i].envChanged=true;
}
}
bool nextHinvR=(chan[i].std.ex1&8);
bool nextHinvR=(chan[i].std.ex1.val&8);
if (nextHinvR!=(chan[i].env.flag.envHinvR)) {
chan[i].env.flag.envHinvR=nextHinvR;
if (!isMuted[i] && !chan[i].pcm) {
chan[i].envChanged=true;
}
}
bool nextVinvR=(chan[i].std.ex1&16);
bool nextVinvR=(chan[i].std.ex1.val&16);
if (nextVinvR!=(chan[i].env.flag.envVinvR)) {
chan[i].env.flag.envVinvR=nextVinvR;
if (!isMuted[i] && !chan[i].pcm) {
chan[i].envChanged=true;
}
}
bool nextHinvL=(chan[i].std.ex1&32);
bool nextHinvL=(chan[i].std.ex1.val&32);
if (nextHinvL!=(chan[i].env.flag.envHinvL)) {
chan[i].env.flag.envHinvL=nextHinvL;
if (!isMuted[i] && !chan[i].pcm) {
chan[i].envChanged=true;
}
}
bool nextVinvL=(chan[i].std.ex1&64);
bool nextVinvL=(chan[i].std.ex1.val&64);
if (nextVinvL!=(chan[i].env.flag.envVinvL)) {
chan[i].env.flag.envVinvL=nextVinvL;
if (!isMuted[i] && !chan[i].pcm) {
@ -426,9 +426,9 @@ void DivPlatformX1_010::tick() {
}
}
}
if (chan[i].std.hadEx2) {
if (chan[i].env.shape!=chan[i].std.ex2) {
chan[i].env.shape=chan[i].std.ex2;
if (chan[i].std.ex2.had) {
if (chan[i].env.shape!=chan[i].std.ex2.val) {
chan[i].env.shape=chan[i].std.ex2.val;
if (!chan[i].pcm) {
if (chan[i].env.flag.envEnable && (!isMuted[i])) {
chan[i].envChanged=true;
@ -437,18 +437,18 @@ void DivPlatformX1_010::tick() {
}
}
}
if (chan[i].std.hadEx3) {
chan[i].autoEnvNum=chan[i].std.ex3;
if (chan[i].std.ex3.had) {
chan[i].autoEnvNum=chan[i].std.ex3.val;
if (!chan[i].pcm) {
chan[i].freqChanged=true;
if (!chan[i].std.willAlg) chan[i].autoEnvDen=1;
if (!chan[i].std.alg.will) chan[i].autoEnvDen=1;
}
}
if (chan[i].std.hadAlg) {
chan[i].autoEnvDen=chan[i].std.alg;
if (chan[i].std.alg.had) {
chan[i].autoEnvDen=chan[i].std.alg.val;
if (!chan[i].pcm) {
chan[i].freqChanged=true;
if (!chan[i].std.willEx3) chan[i].autoEnvNum=1;
if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1;
}
}
if (chan[i].active) {
@ -601,7 +601,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
if (chan[c.chan].outVol!=c.value) {
chan[c.chan].outVol=c.value;
if (!isMuted[c.chan]) {
@ -612,7 +612,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
}
break;
case DIV_CMD_GET_VOLUME:
if (chan[c.chan].std.hasVol) {
if (chan[c.chan].std.vol.has) {
return chan[c.chan].vol;
}
return chan[c.chan].outVol;
@ -685,7 +685,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
}
case DIV_CMD_LEGATO:
chan[c.chan].note=c.value;
chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note+((chan[c.chan].std.willArp&&!chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)));
chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note+((chan[c.chan].std.arp.will&&!chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
break;
case DIV_CMD_PRE_PORTA:

View file

@ -309,6 +309,9 @@ const char* DivPlatformYM2610::getEffectName(unsigned char effect) {
case 0x29:
return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)";
break;
case 0x30:
return "30xx: Toggle hard envelope reset on new notes";
break;
}
return NULL;
}
@ -376,8 +379,8 @@ void DivPlatformYM2610::tick() {
if (i==1 && extMode) continue;
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127;
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
@ -389,24 +392,24 @@ void DivPlatformYM2610::tick() {
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp);
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadAlg) {
chan[i].state.alg=chan[i].std.alg;
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
@ -422,74 +425,92 @@ void DivPlatformYM2610::tick() {
}
}
}
if (chan[i].std.hadFb) {
chan[i].state.fb=chan[i].std.fb;
if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
}
if (chan[i].std.hadFms) {
chan[i].state.fms=chan[i].std.fms;
if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms.val;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
if (chan[i].std.hadAms) {
chan[i].state.ams=chan[i].std.ams;
if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams.val;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) {
op.am=m.am;
if (m.am.had) {
op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadAr) {
op.ar=m.ar;
if (m.ar.had) {
op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.hadDr) {
op.dr=m.dr;
if (m.dr.had) {
op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadMult) {
op.mult=m.mult;
if (m.mult.had) {
op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadRr) {
op.rr=m.rr;
if (m.rr.had) {
op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadSl) {
op.sl=m.sl;
if (m.sl.had) {
op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadTl) {
op.tl=127-m.tl;
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
if (m.hadRs) {
op.rs=m.rs;
if (m.rs.had) {
op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.hadDt) {
op.dt=m.dt;
if (m.dt.had) {
op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadD2r) {
op.d2r=m.d2r;
if (m.d2r.had) {
op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
if (m.hadSsg) {
op.ssgEnv=m.ssg;
if (m.ssg.had) {
op.ssgEnv=m.ssg.val;
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
}
if (chan[i].keyOn || chan[i].keyOff) {
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
immWrite(baseAddr+ADDR_SL_RR,0x0f);
immWrite(baseAddr+ADDR_TL,0x7f);
oldWrites[baseAddr+ADDR_SL_RR]=-1;
oldWrites[baseAddr+ADDR_TL]=-1;
//rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
}
immWrite(0x28,0x00|konOffs[i]);
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
for (int k=0; k<100; k++) {
immWrite(baseAddr+ADDR_SL_RR,0x0f);
}
}
}
chan[i].keyOff=false;
}
}
@ -498,22 +519,22 @@ void DivPlatformYM2610::tick() {
if (chan[13].furnacePCM) {
chan[13].std.next();
if (chan[13].std.hadVol) {
chan[13].outVol=(chan[13].vol*MIN(64,chan[13].std.vol))/64;
if (chan[13].std.vol.had) {
chan[13].outVol=(chan[13].vol*MIN(64,chan[13].std.vol.val))/64;
immWrite(0x1b,chan[13].outVol);
}
if (chan[13].std.hadArp) {
if (chan[13].std.arp.had) {
if (!chan[13].inPorta) {
if (chan[13].std.arpMode) {
chan[13].baseFreq=NOTE_ADPCMB(chan[13].std.arp);
if (chan[13].std.arp.mode) {
chan[13].baseFreq=NOTE_ADPCMB(chan[13].std.arp.val);
} else {
chan[13].baseFreq=NOTE_ADPCMB(chan[13].note+(signed char)chan[13].std.arp);
chan[13].baseFreq=NOTE_ADPCMB(chan[13].note+(signed char)chan[13].std.arp.val);
}
}
chan[13].freqChanged=true;
} else {
if (chan[13].std.arpMode && chan[13].std.finishedArp) {
if (chan[13].std.arp.mode && chan[13].std.arp.finished) {
chan[13].baseFreq=NOTE_ADPCMB(chan[13].note);
chan[13].freqChanged=true;
}
@ -608,7 +629,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
if (skipRegisterWrites) break;
if (chan[c.chan].furnacePCM) {
chan[c.chan].std.init(ins);
if (!chan[c.chan].std.willVol) {
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
immWrite(0x1b,chan[c.chan].outVol);
}
@ -685,7 +706,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].std.init(ins);
if (c.chan<4) {
if (!chan[c.chan].std.willVol) {
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
}
@ -764,7 +785,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (c.chan>12) { // ADPCM-B
@ -930,6 +951,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
}
break;
}
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_ALWAYS_SET_VOLUME:
return 0;
break;

View file

@ -46,7 +46,7 @@ class DivPlatformYM2610: public DivDispatch {
int freq, baseFreq, pitch, note;
unsigned char ins, psgMode, autoEnvNum, autoEnvDen;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
int vol, outVol;
int sample;
unsigned char pan;
@ -70,6 +70,7 @@ class DivPlatformYM2610: public DivDispatch {
portaPause(false),
inPorta(false),
furnacePCM(false),
hardReset(false),
vol(0),
outVol(15),
sample(-1),

View file

@ -373,6 +373,9 @@ const char* DivPlatformYM2610B::getEffectName(unsigned char effect) {
case 0x29:
return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)";
break;
case 0x30:
return "30xx: Toggle hard envelope reset on new notes";
break;
}
return NULL;
}
@ -440,8 +443,8 @@ void DivPlatformYM2610B::tick() {
if (i==2 && extMode) continue;
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127;
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
@ -453,24 +456,24 @@ void DivPlatformYM2610B::tick() {
}
}
if (chan[i].std.hadArp) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp);
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp);
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadAlg) {
chan[i].state.alg=chan[i].std.alg;
if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
@ -486,74 +489,92 @@ void DivPlatformYM2610B::tick() {
}
}
}
if (chan[i].std.hadFb) {
chan[i].state.fb=chan[i].std.fb;
if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb.val;
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
}
if (chan[i].std.hadFms) {
chan[i].state.fms=chan[i].std.fms;
if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms.val;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
if (chan[i].std.hadAms) {
chan[i].state.ams=chan[i].std.ams;
if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams.val;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) {
op.am=m.am;
if (m.am.had) {
op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadAr) {
op.ar=m.ar;
if (m.ar.had) {
op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.hadDr) {
op.dr=m.dr;
if (m.dr.had) {
op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.hadMult) {
op.mult=m.mult;
if (m.mult.had) {
op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadRr) {
op.rr=m.rr;
if (m.rr.had) {
op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadSl) {
op.sl=m.sl;
if (m.sl.had) {
op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.hadTl) {
op.tl=127-m.tl;
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
if (m.hadRs) {
op.rs=m.rs;
if (m.rs.had) {
op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.hadDt) {
op.dt=m.dt;
if (m.dt.had) {
op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.hadD2r) {
op.d2r=m.d2r;
if (m.d2r.had) {
op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
if (m.hadSsg) {
op.ssgEnv=m.ssg;
if (m.ssg.had) {
op.ssgEnv=m.ssg.val;
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
}
if (chan[i].keyOn || chan[i].keyOff) {
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
immWrite(baseAddr+ADDR_SL_RR,0x0f);
immWrite(baseAddr+ADDR_TL,0x7f);
oldWrites[baseAddr+ADDR_SL_RR]=-1;
oldWrites[baseAddr+ADDR_TL]=-1;
//rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
}
immWrite(0x28,0x00|konOffs[i]);
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
for (int k=0; k<100; k++) {
immWrite(baseAddr+ADDR_SL_RR,0x0f);
}
}
}
chan[i].keyOff=false;
}
}
@ -561,22 +582,22 @@ void DivPlatformYM2610B::tick() {
if (chan[15].furnacePCM) {
chan[15].std.next();
if (chan[15].std.hadVol) {
chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol))/64;
if (chan[15].std.vol.had) {
chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol.val))/64;
immWrite(0x1b,chan[15].outVol);
}
if (chan[15].std.hadArp) {
if (chan[15].std.arp.had) {
if (!chan[15].inPorta) {
if (chan[15].std.arpMode) {
chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp);
if (chan[15].std.arp.mode) {
chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp.val);
} else {
chan[15].baseFreq=NOTE_ADPCMB(chan[15].note+(signed char)chan[15].std.arp);
chan[15].baseFreq=NOTE_ADPCMB(chan[15].note+(signed char)chan[15].std.arp.val);
}
}
chan[15].freqChanged=true;
} else {
if (chan[15].std.arpMode && chan[15].std.finishedArp) {
if (chan[15].std.arp.mode && chan[15].std.arp.finished) {
chan[15].baseFreq=NOTE_ADPCMB(chan[15].note);
chan[15].freqChanged=true;
}
@ -671,7 +692,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
if (skipRegisterWrites) break;
if (chan[c.chan].furnacePCM) {
chan[c.chan].std.init(ins);
if (!chan[c.chan].std.willVol) {
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
immWrite(0x1b,chan[c.chan].outVol);
}
@ -748,7 +769,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].std.init(ins);
if (c.chan<6) {
if (!chan[c.chan].std.willVol) {
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
}
@ -827,7 +848,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (c.chan>14) { // ADPCM-B
@ -993,6 +1014,9 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
}
break;
}
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_ALWAYS_SET_VOLUME:
return 0;
break;

View file

@ -38,7 +38,7 @@ class DivPlatformYM2610B: public DivDispatch {
int freq, baseFreq, pitch, note;
unsigned char ins, psgMode, autoEnvNum, autoEnvDen;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
int vol, outVol;
int sample;
unsigned char pan;
@ -62,6 +62,7 @@ class DivPlatformYM2610B: public DivDispatch {
portaPause(false),
inPorta(false),
furnacePCM(false),
hardReset(false),
vol(0),
outVol(15),
sample(-1),

View file

@ -17,9 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "blip_buf.h"
#include "song.h"
#include "wavetable.h"
#define _USE_MATH_DEFINES
#include "dispatch.h"
#include "engine.h"
@ -64,6 +61,7 @@ const char* cmdName[DIV_CMD_MAX]={
"SAMPLE_BANK",
"SAMPLE_POS",
"FM_HARD_RESET",
"FM_LFO",
"FM_LFO_WAVE",
"FM_TL",
@ -201,16 +199,24 @@ int DivEngine::dispatchCmd(DivCommand c) {
chan[c.chan].curMidiNote=-1;
break;
case DIV_CMD_INSTRUMENT:
output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0));
if (chan[c.chan].lastIns!=c.value) {
output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0));
}
break;
case DIV_CMD_VOLUME:
//output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x07,scaledVol));
if (chan[c.chan].curMidiNote>=0 && chan[c.chan].midiAftertouch) {
chan[c.chan].midiAftertouch=false;
output->midiOut->send(TAMidiMessage(0xa0|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
}
break;
case DIV_CMD_PITCH: {
int pitchBend=8192+(c.value<<5);
if (pitchBend<0) pitchBend=0;
if (pitchBend>16383) pitchBend=16383;
output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7));
if (pitchBend!=chan[c.chan].midiPitch) {
chan[c.chan].midiPitch=pitchBend;
output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7));
}
break;
}
default:
@ -235,6 +241,23 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
case 0x20: // SN noise mode
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal));
break;
case 0x30: // toggle hard-reset
dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal));
break;
default:
return false;
}
break;
case DIV_SYSTEM_YM2151:
case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610B:
case DIV_SYSTEM_YM2610B_EXT:
case DIV_SYSTEM_OPZ:
switch (effect) {
case 0x30: // toggle hard-reset
dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal));
break;
default:
return false;
}
@ -335,6 +358,22 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
case 0x18: // drum mode toggle
dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal));
break;
case 0x30: // toggle hard-reset
dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal));
break;
default:
return false;
}
break;
case DIV_SYSTEM_OPLL:
case DIV_SYSTEM_VRC7:
case DIV_SYSTEM_OPL:
case DIV_SYSTEM_OPL2:
case DIV_SYSTEM_OPL3:
switch (effect) {
case 0x30: // toggle hard-reset
dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal));
break;
default:
return false;
}
@ -963,6 +1002,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
// volume
if (pat->data[whatRow][3]!=-1) {
if (dispatchCmd(DivCommand(DIV_ALWAYS_SET_VOLUME,i)) || (MIN(chan[i].volMax,chan[i].volume)>>8)!=pat->data[whatRow][3]) {
if (pat->data[whatRow][0]==0 && pat->data[whatRow][1]==0) {
chan[i].midiAftertouch=true;
}
chan[i].volume=pat->data[whatRow][3]<<8;
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
}
@ -1436,6 +1478,11 @@ bool DivEngine::nextTick(bool noAccum) {
cycles++;
}
// MIDI clock
if (output) if (!skipping && output->midiOut!=NULL) {
output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0));
}
while (!pendingNotes.empty()) {
DivNoteEvent& note=pendingNotes.front();
if (note.on) {
@ -1613,7 +1660,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
if (softLocked) {
if (!isBusy.try_lock()) {
logV("audio is soft-locked (%d)\n",softLockCount++);
logV("audio is soft-locked (%d)",softLockCount++);
return;
}
} else {
@ -1665,7 +1712,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
}
}
}
logD("%.2x\n",msg.type);
logD("%.2x",msg.type);
output->midiIn->queue.pop();
}
@ -1732,8 +1779,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
if (!playing) {
if (out!=NULL) {
memcpy(oscBuf[0],out[0],size*sizeof(float));
memcpy(oscBuf[1],out[1],size*sizeof(float));
for (unsigned int i=0; i<size; i++) {
oscBuf[0][oscWritePos]=out[0][i];
oscBuf[1][oscWritePos]=out[1][i];
if (++oscWritePos>=32768) oscWritePos=0;
}
oscSize=size;
}
isBusy.unlock();
@ -1795,7 +1845,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
if (remainingLoops>0) {
remainingLoops--;
if (!remainingLoops) {
logI("end of song!\n");
logI("end of song!");
remainingLoops=-1;
playing=false;
freelance=false;
@ -1831,9 +1881,9 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
return;
}
//logD("attempts: %d\n",attempts);
//logD("attempts: %d",attempts);
if (attempts>=100) {
logE("hang detected! stopping! at %d seconds %d micro\n",totalSeconds,totalTicks);
logE("hang detected! stopping! at %d seconds %d micro",totalSeconds,totalTicks);
freelance=false;
playing=false;
extValuePresent=false;
@ -1847,6 +1897,8 @@ 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)*song.masterVol;
float volR=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127+(int)song.systemPan[i])/127.0f)*song.masterVol;
volL*=disCont[i].dispatch->getPostAmp();
volR*=disCont[i].dispatch->getPostAmp();
if (disCont[i].dispatch->isStereo()) {
for (size_t j=0; j<size; j++) {
out[0][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volL;
@ -1880,8 +1932,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
while (metroPos>=1) metroPos--;
}
memcpy(oscBuf[0],out[0],size*sizeof(float));
memcpy(oscBuf[1],out[1],size*sizeof(float));
for (unsigned int i=0; i<size; i++) {
oscBuf[0][oscWritePos]=out[0][i];
oscBuf[1][oscWritePos]=out[1][i];
if (++oscWritePos>=32768) oscWritePos=0;
}
oscSize=size;
if (forceMono) {

View file

@ -57,7 +57,7 @@ size_t SafeReader::size() {
int SafeReader::read(void* where, size_t count) {
#ifdef READ_DEBUG
logD("SR: reading %d bytes at %x\n",count,curSeek);
logD("SR: reading %d bytes at %x",count,curSeek);
#endif
if (count==0) return 0;
if (curSeek+count>len) throw EndOfFileException(this,len);
@ -68,23 +68,23 @@ int SafeReader::read(void* where, size_t count) {
signed char SafeReader::readC() {
#ifdef READ_DEBUG
logD("SR: reading char %x:\n",curSeek);
logD("SR: reading char %x:",curSeek);
#endif
if (curSeek+1>len) throw EndOfFileException(this,len);
#ifdef READ_DEBUG
logD("SR: %.2x\n",buf[curSeek]);
logD("SR: %.2x",buf[curSeek]);
#endif
return (signed char)buf[curSeek++];
}
short SafeReader::readS() {
#ifdef READ_DEBUG
logD("SR: reading short %x:\n",curSeek);
logD("SR: reading short %x:",curSeek);
#endif
if (curSeek+2>len) throw EndOfFileException(this,len);
short ret=*(short*)(&buf[curSeek]);
#ifdef READ_DEBUG
logD("SR: %.4x\n",ret);
logD("SR: %.4x",ret);
#endif
curSeek+=2;
return ret;
@ -99,13 +99,13 @@ short SafeReader::readS_BE() {
int SafeReader::readI() {
#ifdef READ_DEBUG
logD("SR: reading int %x:\n",curSeek);
logD("SR: reading int %x:",curSeek);
#endif
if (curSeek+4>len) throw EndOfFileException(this,len);
int ret=*(int*)(&buf[curSeek]);
curSeek+=4;
#ifdef READ_DEBUG
logD("SR: %.8x\n",ret);
logD("SR: %.8x",ret);
#endif
return ret;
}
@ -141,7 +141,7 @@ double SafeReader::readD() {
String SafeReader::readString(size_t stlen) {
String ret;
#ifdef READ_DEBUG
logD("SR: reading string len %d at %x\n",stlen,curSeek);
logD("SR: reading string len %d at %x",stlen,curSeek);
#endif
size_t curPos=0;
while (curPos<stlen) {

View file

@ -24,6 +24,11 @@
#include <stdint.h>
#include "../ta-utils.h"
enum Endianness {
LittleEndian=0,
BigEndian
};
class SafeReader;
struct EndOfFileException {

View file

@ -50,7 +50,7 @@ bool DivSample::save(const char* path) {
f=sf_open(path,SFM_WRITE,&si);
if (f==NULL) {
logE("could not open wave file for saving! %s\n",sf_error_number(sf_error(f)));
logE("could not open wave file for saving! %s",sf_error_number(sf_error(f)));
return false;
}
@ -822,7 +822,7 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
initInternal(h->depth,h->samples); \
samples=h->samples; \
\
if (h->length!=getCurBufLen()) logW("undo buffer length not equal to current buffer length! %d != %d\n",h->length,getCurBufLen()); \
if (h->length!=getCurBufLen()) logW("undo buffer length not equal to current buffer length! %d != %d",h->length,getCurBufLen()); \
\
void* buf=getCurBuf(); \
\

View file

@ -143,12 +143,15 @@ struct DivSong {
// - 9: v3.9
// - introduces Genesis system
// - introduces system number
// - patterns now stored in current known format
// - 7: ???
// - 5: BETA 3 (?)
// - 5: BETA 3
// - adds arpeggio tick
// - 3: BETA 2
// - 4: BETA 2
// - 3: BETA 1
// - possibly the first version that could save
// - basic format, no system number, 16 instruments, one speed, YMU759-only
// - patterns were stored in a different format (chars instead of shorts)
// - if somebody manages to find a version 2 or even 1 module, please tell me as it will be worth more than a luxury vehicle
unsigned short version;
bool isDMF;

View file

@ -415,7 +415,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
}
if (write.addr>=0xffff0000) { // Furnace special command
unsigned char streamID=streamOff+((write.addr&0xff00)>>8);
logD("writing stream command %x:%x with stream ID %d\n",write.addr,write.val,streamID);
logD("writing stream command %x:%x with stream ID %d",write.addr,write.val,streamID);
switch (write.addr&0xff) {
case 0: // play sample
if (write.val<song.sampleLen) {
@ -599,7 +599,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
}
break;
default:
logW("write not handled!\n");
logW("write not handled!");
break;
}
}
@ -620,7 +620,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
int loopRow=0;
int loopEnd=0;
walkSong(loopOrder,loopRow,loopEnd);
logI("loop point: %d %d\n",loopOrder,loopRow);
logI("loop point: %d %d",loopOrder,loopRow);
warnings="";
curOrder=0;
@ -1162,7 +1162,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
unsigned int sampleSeek=0;
for (int i=0; i<song.sampleLen; i++) {
DivSample* sample=song.sample[i];
logI("setting seek to %d\n",sampleSeek);
logI("setting seek to %d",sampleSeek);
sample->off8=sampleSeek;
sampleSeek+=sample->length8;
}
@ -1447,7 +1447,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
if (waitTime>0) {
w->writeC(0x61);
w->writeS(waitTime);
printf("wait is: %f\n",waitTime);
logV("wait is: %f",waitTime);
totalWait-=waitTime;
tickCount+=waitTime;
}
@ -1561,7 +1561,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
freelance=false;
extValuePresent=false;
logI("%d register writes total.\n",writeCount);
logI("%d register writes total.",writeCount);
BUSY_END;
return w;

View file

@ -25,6 +25,54 @@ bool DivWaveSynth::tick() {
}
updated=true;
break;
case DIV_WS_ADD:
for (int i=0; i<=state.speed; i++) {
output[pos]+=MIN(height,state.param1);
if (output[pos]>=height) output[pos]-=height;
if (++pos>=width) pos=0;
}
updated=true;
break;
case DIV_WS_SUBTRACT:
for (int i=0; i<=state.speed; i++) {
output[pos]+=MIN(height,state.param1);
if (output[pos]<0) output[pos]+=height;
if (++pos>=width) pos=0;
}
updated=true;
break;
case DIV_WS_AVERAGE:
for (int i=0; i<=state.speed; i++) {
int pos1=(pos+1>=width)?0:(pos+1);
output[pos]=(output[pos]*state.param1+output[pos1]*(256-state.param1))>>8;
if (output[pos]<0) output[pos]=0;
if (output[pos]>height) output[pos]=height;
if (++pos>=width) pos=0;
}
updated=true;
break;
case DIV_WS_PHASE:
for (int i=0; i<=state.speed; i++) {
output[pos]=wave1[(pos+stage)%width];
if (++pos>=width) {
pos=0;
if (++stage>=width) stage=0;
}
}
updated=true;
break;
case DIV_WS_WIPE:
break;
case DIV_WS_FADE:
break;
case DIV_WS_PING_PONG:
break;
case DIV_WS_OVERLAY:
break;
case DIV_WS_NEGATIVE_OVERLAY:
break;
case DIV_WS_PHASE_DUAL:
break;
}
divCounter=state.rateDivider;
}
@ -96,4 +144,4 @@ void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) {
changeWave1(state.wave1);
changeWave2(state.wave2);
}
}
}

View file

@ -75,8 +75,8 @@ class DivWaveSynth {
height(31),
first(false),
activeChangedB(false) {
memset(wave1,0,sizeof(int)*256);
memset(wave2,0,sizeof(int)*256);
memset(wave1,0,256);
memset(wave2,0,256);
memset(output,0,sizeof(int)*256);
}
};

View file

@ -73,12 +73,12 @@ bool DivWavetable::save(const char* path) {
FILE* outFile=ps_fopen(path,"wb");
if (outFile==NULL) {
logE("could not save wavetable: %s!\n",strerror(errno));
logE("could not save wavetable: %s!",strerror(errno));
w->finish();
return false;
}
if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) {
logW("did not write entire wavetable!\n");
logW("did not write entire wavetable!");
}
fclose(outFile);
w->finish();

View file

@ -33,15 +33,15 @@ String getWinConfigPath() {
configPath=path;
configPath+=L"\\furnace";
if (!PathIsDirectoryW(configPath.c_str())) {
logI("creating config dir...\n");
logI("creating config dir...");
int mkdirRet;
if ((mkdirRet=SHCreateDirectory(NULL,configPath.c_str()))!=ERROR_SUCCESS) {
logW("could not make config dir! (%.8x)\n",mkdirRet);
logW("could not make config dir! (%.8x)",mkdirRet);
configPath=L".";
}
}
} else {
logW("unable to determine config directory! (%.8x)\n",configHR);
logW("unable to determine config directory! (%.8x)",configHR);
configPath=L".";
}
return utf16To8(configPath.c_str());

View file

@ -212,6 +212,9 @@ void FurnaceGUI::doAction(int what) {
case GUI_ACTION_WINDOW_REGISTER_VIEW:
nextWindow=GUI_WINDOW_REGISTER_VIEW;
break;
case GUI_ACTION_WINDOW_LOG:
nextWindow=GUI_WINDOW_LOG;
break;
case GUI_ACTION_COLLAPSE_WINDOW:
collapseWindow=true;

View file

@ -546,8 +546,8 @@ void FurnaceGUI::doPaste(PasteMode mode) {
}
if (invalidData) {
logW("invalid clipboard data! failed at line %d char %d\n",i,charPos);
logW("%s\n",line.c_str());
logW("invalid clipboard data! failed at line %d char %d",i,charPos);
logW("%s",line.c_str());
break;
}
j++;
@ -562,6 +562,7 @@ void FurnaceGUI::doPaste(PasteMode mode) {
}
if (settings.cursorPastePos) {
cursor.y=j;
updateScroll(cursor.y);
}
makeUndo(GUI_UNDO_PATTERN_PASTE);

View file

@ -8,6 +8,7 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector<String> filter, c
if (opened) return false;
saving=false;
curPath=path;
logD("opening load file dialog with curPath %s",curPath.c_str());
if (sysDialog) {
dialogO=new pfd::open_file(header,path,filter);
} else {
@ -22,6 +23,7 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector<String> filter, c
if (opened) return false;
saving=true;
curPath=path;
logD("opening save file dialog with curPath %s",curPath.c_str());
if (sysDialog) {
dialogS=new pfd::save_file(header,path,filter);
} else {
@ -65,7 +67,9 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) {
if (dialogS!=NULL) {
if (dialogS->ready(0)) {
fileName=dialogS->result();
logD("returning %s\n",fileName.c_str());
size_t dsPos=fileName.rfind(DIR_SEPARATOR);
if (dsPos!=String::npos) curPath=fileName.substr(0,dsPos);
logD("returning %s",fileName.c_str());
return true;
}
}
@ -74,10 +78,12 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) {
if (dialogO->ready(0)) {
if (dialogO->result().empty()) {
fileName="";
logD("returning nothing\n");
logD("returning nothing");
} else {
fileName=dialogO->result()[0];
logD("returning %s\n",fileName.c_str());
size_t dsPos=fileName.rfind(DIR_SEPARATOR);
if (dsPos!=String::npos) curPath=fileName.substr(0,dsPos);
logD("returning %s",fileName.c_str());
}
return true;
}
@ -91,6 +97,12 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) {
String FurnaceGUIFileDialog::getPath() {
if (sysDialog) {
if (curPath.size()>1) {
if (curPath[curPath.size()-1]==DIR_SEPARATOR) {
curPath=curPath.substr(0,curPath.size()-1);
}
}
logD("curPath: %s",curPath.c_str());
return curPath;
} else {
return ImGuiFileDialog::Instance()->GetCurrentPath();

View file

@ -815,10 +815,10 @@ void FurnaceGUI::prepareLayout() {
}
// copy initial layout
logI("loading default layout.\n");
logI("loading default layout.");
check=ps_fopen(finalLayoutPath,"w");
if (check==NULL) {
logW("could not write default layout!\n");
logW("could not write default layout!");
return;
}
@ -1131,7 +1131,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
if (orderCursor>=0 && orderCursor<e->getTotalChannelCount()) {
int curOrder=e->getOrder();
e->lockSave([this,curOrder,num]() {
e->song.orders.ord[orderCursor][curOrder]=((e->song.orders.ord[orderCursor][curOrder]<<4)|num)&0x7f;
e->song.orders.ord[orderCursor][curOrder]=((e->song.orders.ord[orderCursor][curOrder]<<4)|num);
});
if (orderEditMode==2 || orderEditMode==3) {
curNibble=!curNibble;
@ -1539,7 +1539,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
memset(&zl,0,sizeof(z_stream));
ret=deflateInit(&zl,Z_DEFAULT_COMPRESSION);
if (ret!=Z_OK) {
logE("zlib error!\n");
logE("zlib error!");
lastError="compression error";
fclose(outFile);
w->finish();
@ -1551,7 +1551,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
zl.avail_out=131072;
zl.next_out=zbuf;
if ((ret=deflate(&zl,Z_NO_FLUSH))==Z_STREAM_ERROR) {
logE("zlib stream error!\n");
logE("zlib stream error!");
lastError="zlib stream error";
deflateEnd(&zl);
fclose(outFile);
@ -1561,7 +1561,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
size_t amount=131072-zl.avail_out;
if (amount>0) {
if (fwrite(zbuf,1,amount,outFile)!=amount) {
logE("did not write entirely: %s!\n",strerror(errno));
logE("did not write entirely: %s!",strerror(errno));
lastError=strerror(errno);
deflateEnd(&zl);
fclose(outFile);
@ -1573,7 +1573,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
zl.avail_out=131072;
zl.next_out=zbuf;
if ((ret=deflate(&zl,Z_FINISH))==Z_STREAM_ERROR) {
logE("zlib finish stream error!\n");
logE("zlib finish stream error!");
lastError="zlib finish stream error";
deflateEnd(&zl);
fclose(outFile);
@ -1582,7 +1582,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
}
if (131072-zl.avail_out>0) {
if (fwrite(zbuf,1,131072-zl.avail_out,outFile)!=(131072-zl.avail_out)) {
logE("did not write entirely: %s!\n",strerror(errno));
logE("did not write entirely: %s!",strerror(errno));
lastError=strerror(errno);
deflateEnd(&zl);
fclose(outFile);
@ -1593,7 +1593,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
deflateEnd(&zl);
#else
if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) {
logE("did not write entirely: %s!\n",strerror(errno));
logE("did not write entirely: %s!",strerror(errno));
lastError=strerror(errno);
fclose(outFile);
w->finish();
@ -1613,7 +1613,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
int FurnaceGUI::load(String path) {
if (!path.empty()) {
logI("loading module...\n");
logI("loading module...");
FILE* f=ps_fopen(path.c_str(),"rb");
if (f==NULL) {
perror("error");
@ -1635,7 +1635,7 @@ int FurnaceGUI::load(String path) {
}
if (len<1) {
if (len==0) {
logE("that file is empty!\n");
logE("that file is empty!");
lastError="file is empty";
} else {
perror("tell error");
@ -1662,7 +1662,7 @@ int FurnaceGUI::load(String path) {
fclose(f);
if (!e->load(file,(size_t)len)) {
lastError=e->getLastError();
logE("could not open file!\n");
logE("could not open file!");
return 1;
}
}
@ -2076,7 +2076,7 @@ bool FurnaceGUI::loop() {
macroLoopDragActive=false;
waveDragActive=false;
if (sampleDragActive) {
logD("stopping sample drag\n");
logD("stopping sample drag");
if (sampleDragMode) {
e->renderSamplesP();
} else {
@ -2506,6 +2506,7 @@ bool FurnaceGUI::loop() {
if (ImGui::MenuItem("oscilloscope",BIND_FOR(GUI_ACTION_WINDOW_OSCILLOSCOPE),oscOpen)) oscOpen=!oscOpen;
if (ImGui::MenuItem("volume meter",BIND_FOR(GUI_ACTION_WINDOW_VOL_METER),volMeterOpen)) volMeterOpen=!volMeterOpen;
if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen;
if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen;
if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen;
ImGui::EndMenu();
@ -2600,6 +2601,9 @@ bool FurnaceGUI::loop() {
drawInsList();
drawInsEdit();
drawMixer();
readOsc();
drawOsc();
drawVolMeter();
drawSettings();
@ -2610,6 +2614,7 @@ bool FurnaceGUI::loop() {
drawNotes();
drawChannels();
drawRegView();
drawLog();
if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen);
@ -2710,7 +2715,7 @@ bool FurnaceGUI::loop() {
}
break;
case GUI_FILE_SAVE: {
logD("saving: %s\n",copyOfName.c_str());
logD("saving: %s",copyOfName.c_str());
String lowerCase=fileName;
for (char& i: lowerCase) {
if (i>='A' && i<='Z') i+='a'-'A';
@ -2727,7 +2732,7 @@ bool FurnaceGUI::loop() {
break;
}
case GUI_FILE_SAVE_DMF_LEGACY:
logD("saving: %s\n",copyOfName.c_str());
logD("saving: %s",copyOfName.c_str());
if (save(copyOfName,24)>0) {
showError(fmt::sprintf("Error while saving file! (%s)",lastError));
}
@ -2862,7 +2867,7 @@ bool FurnaceGUI::loop() {
if (aboutOpen) drawAbout();
if (ImGui::BeginPopupModal("Rendering...",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Please wait...\n");
ImGui::Text("Please wait...");
if (ImGui::Button("Abort")) {
if (e->haltAudioFile()) {
ImGui::CloseCurrentPopup();
@ -2923,6 +2928,7 @@ bool FurnaceGUI::loop() {
break;
case GUI_WARN_RESET_COLORS:
resetColors();
applyUISettings(false);
break;
case GUI_WARN_GENERIC:
break;
@ -2944,22 +2950,22 @@ bool FurnaceGUI::loop() {
if (backupTimer<=0) {
backupTask=std::async(std::launch::async,[this]() -> bool {
if (backupPath==curFileName) {
logD("backup file open. not saving backup.\n");
logD("backup file open. not saving backup.");
return true;
}
logD("saving backup...\n");
logD("saving backup...");
SafeWriter* w=e->saveFur(true);
if (w!=NULL) {
FILE* outFile=ps_fopen(backupPath.c_str(),"wb");
if (outFile!=NULL) {
if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) {
logW("did not write backup entirely: %s!\n",strerror(errno));
logW("did not write backup entirely: %s!",strerror(errno));
w->finish();
}
fclose(outFile);
} else {
logW("could not save backup: %s!\n",strerror(errno));
logW("could not save backup: %s!",strerror(errno));
w->finish();
}
}
@ -3034,6 +3040,7 @@ bool FurnaceGUI::init() {
notesOpen=e->getConfBool("notesOpen",false);
channelsOpen=e->getConfBool("channelsOpen",false);
regViewOpen=e->getConfBool("regViewOpen",false);
logOpen=e->getConfBool("logOpen",false);
tempoView=e->getConfBool("tempoView",true);
waveHex=e->getConfBool("waveHex",false);
@ -3063,7 +3070,7 @@ bool FurnaceGUI::init() {
sdlWin=SDL_CreateWindow("Furnace",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,scrW*dpiScale,scrH*dpiScale,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI);
if (sdlWin==NULL) {
logE("could not open window! %s\n",SDL_GetError());
logE("could not open window! %s",SDL_GetError());
return false;
}
@ -3088,14 +3095,14 @@ bool FurnaceGUI::init() {
SDL_FreeSurface(icon);
free(furIcon);
} else {
logW("could not create icon!\n");
logW("could not create icon!");
}
#endif
sdlRend=SDL_CreateRenderer(sdlWin,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_TARGETTEXTURE);
if (sdlRend==NULL) {
logE("could not init renderer! %s\n",SDL_GetError());
logE("could not init renderer! %s",SDL_GetError());
return false;
}
@ -3112,14 +3119,14 @@ bool FurnaceGUI::init() {
applyUISettings();
if (!ImGui::GetIO().Fonts->Build()) {
logE("error while building font atlas!\n");
logE("error while building font atlas!");
showError("error while loading fonts! please check your settings.");
ImGui::GetIO().Fonts->Clear();
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
patFont=mainFont;
ImGui_ImplSDLRenderer_DestroyFontsTexture();
if (!ImGui::GetIO().Fonts->Build()) {
logE("error again while building font atlas!\n");
logE("error again while building font atlas!");
}
}
@ -3196,6 +3203,7 @@ bool FurnaceGUI::finish() {
e->setConf("notesOpen",notesOpen);
e->setConf("channelsOpen",channelsOpen);
e->setConf("regViewOpen",regViewOpen);
e->setConf("logOpen",logOpen);
// commit last window size
e->setConf("lastWindowWidth",scrW);
@ -3295,6 +3303,7 @@ FurnaceGUI::FurnaceGUI():
notesOpen(false),
channelsOpen(false),
regViewOpen(false),
logOpen(false),
/*
editControlsDocked(false),
ordersDocked(false),
@ -3428,7 +3437,11 @@ FurnaceGUI::FurnaceGUI():
openSampleResampleOpt(false),
openSampleAmplifyOpt(false),
openSampleSilenceOpt(false),
openSampleFilterOpt(false) {
openSampleFilterOpt(false),
oscTotal(0),
oscZoom(0.5f),
oscZoomSlider(false),
followLog(true) {
// value keys
valueKeys[SDLK_0]=0;
valueKeys[SDLK_1]=1;
@ -3469,4 +3482,5 @@ FurnaceGUI::FurnaceGUI():
memset(patChanX,0,sizeof(float)*(DIV_MAX_CHANS+1));
memset(patChanSlideY,0,sizeof(float)*(DIV_MAX_CHANS+1));
memset(lastIns,-1,sizeof(int)*DIV_MAX_CHANS);
memset(oscValues,0,sizeof(float)*512);
}

View file

@ -71,6 +71,16 @@ enum FurnaceGUIColors {
GUI_COLOR_FILE_FONT,
GUI_COLOR_FILE_OTHER,
GUI_COLOR_OSC_BG1,
GUI_COLOR_OSC_BG2,
GUI_COLOR_OSC_BG3,
GUI_COLOR_OSC_BG4,
GUI_COLOR_OSC_BORDER,
GUI_COLOR_OSC_WAVE,
GUI_COLOR_OSC_WAVE_PEAK,
GUI_COLOR_OSC_REF,
GUI_COLOR_OSC_GUIDE,
GUI_COLOR_VOLMETER_LOW,
GUI_COLOR_VOLMETER_HIGH,
GUI_COLOR_VOLMETER_PEAK,
@ -157,6 +167,12 @@ enum FurnaceGUIColors {
GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,
GUI_COLOR_PATTERN_EFFECT_MISC,
GUI_COLOR_LOGLEVEL_ERROR,
GUI_COLOR_LOGLEVEL_WARNING,
GUI_COLOR_LOGLEVEL_INFO,
GUI_COLOR_LOGLEVEL_DEBUG,
GUI_COLOR_LOGLEVEL_TRACE,
GUI_COLOR_EE_VALUE,
GUI_COLOR_PLAYBACK_STAT,
GUI_COLOR_MAX
@ -185,7 +201,8 @@ enum FurnaceGUIWindows {
GUI_WINDOW_PIANO,
GUI_WINDOW_NOTES,
GUI_WINDOW_CHANNELS,
GUI_WINDOW_REGISTER_VIEW
GUI_WINDOW_REGISTER_VIEW,
GUI_WINDOW_LOG
};
enum FurnaceGUIFileDialogs {
@ -280,6 +297,7 @@ enum FurnaceGUIActions {
GUI_ACTION_WINDOW_NOTES,
GUI_ACTION_WINDOW_CHANNELS,
GUI_ACTION_WINDOW_REGISTER_VIEW,
GUI_ACTION_WINDOW_LOG,
GUI_ACTION_COLLAPSE_WINDOW,
GUI_ACTION_CLOSE_WINDOW,
@ -761,6 +779,9 @@ class FurnaceGUI {
int titleBarSys;
int frameBorders;
int effectDeletionAltersValue;
int oscRoundedCorners;
int oscTakesEntireWindow;
int oscBorder;
unsigned int maxUndoSteps;
String mainFontPath;
String patFontPath;
@ -821,6 +842,9 @@ class FurnaceGUI {
titleBarSys(1),
frameBorders(0),
effectDeletionAltersValue(1),
oscRoundedCorners(1),
oscTakesEntireWindow(0),
oscBorder(1),
maxUndoSteps(100),
mainFontPath(""),
patFontPath(""),
@ -838,7 +862,7 @@ class FurnaceGUI {
bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen;
bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen;
bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen;
bool pianoOpen, notesOpen, channelsOpen, regViewOpen;
bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen;
/* there ought to be a better way...
bool editControlsDocked, ordersDocked, insListDocked, songInfoDocked, patternDocked, insEditDocked;
@ -952,7 +976,7 @@ class FurnaceGUI {
int oldOrdersLen;
DivOrders oldOrders;
DivPattern* oldPat[128];
DivPattern* oldPat[DIV_MAX_CHANS];
std::deque<UndoStep> undoHist;
std::deque<UndoStep> redoHist;
@ -976,9 +1000,18 @@ class FurnaceGUI {
size_t sampleClipboardLen;
bool openSampleResizeOpt, openSampleResampleOpt, openSampleAmplifyOpt, openSampleSilenceOpt, openSampleFilterOpt;
// oscilloscope
int oscTotal;
float oscValues[512];
float oscZoom;
bool oscZoomSlider;
// visualizer
float keyHit[DIV_MAX_CHANS];
int lastIns[DIV_MAX_CHANS];
// log window
bool followLog;
void drawSSGEnv(unsigned char type, const ImVec2& size);
void drawWaveform(unsigned char type, bool opz, const ImVec2& size);
@ -996,6 +1029,8 @@ class FurnaceGUI {
void updateWindowTitle();
void prepareLayout();
void readOsc();
float calcBPM(int s1, int s2, float hz);
void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache);
@ -1026,6 +1061,7 @@ class FurnaceGUI {
void drawSettings();
void drawDebug();
void drawNewSong();
void drawLog();
void parseKeybinds();
void promptKey(int which);
@ -1096,7 +1132,7 @@ class FurnaceGUI {
int load(String path);
void exportAudio(String path, DivAudioExportModes mode);
void applyUISettings();
void applyUISettings(bool updateFonts=true);
void initSystemPresets();
void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false);

View file

@ -191,6 +191,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
D("WINDOW_NOTES", "Song Comments", 0),
D("WINDOW_CHANNELS", "Channels", 0),
D("WINDOW_REGISTER_VIEW", "Register View", 0),
D("WINDOW_LOG", "Log Viewer", 0),
D("COLLAPSE_WINDOW", "Collapse/expand current window", 0),
D("CLOSE_WINDOW", "Close current window", FURKMOD_SHIFT|SDLK_ESCAPE),
@ -377,6 +378,16 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
D(GUI_COLOR_FILE_FONT,"",ImVec4(0.3f,1.0f,0.6f,1.0f)),
D(GUI_COLOR_FILE_OTHER,"",ImVec4(0.7f,0.7f,0.7f,1.0f)),
D(GUI_COLOR_OSC_BG1,"",ImVec4(0.1f,0.18f,0.3f,1.0f)),
D(GUI_COLOR_OSC_BG2,"",ImVec4(0.1f,0.18f,0.3f,1.0f)),
D(GUI_COLOR_OSC_BG3,"",ImVec4(0.05f,0.15f,0.25f,1.0f)),
D(GUI_COLOR_OSC_BG4,"",ImVec4(0.05f,0.15f,0.25f,1.0f)),
D(GUI_COLOR_OSC_BORDER,"",ImVec4(0.4f,0.6f,0.95f,1.0f)),
D(GUI_COLOR_OSC_WAVE,"",ImVec4(0.95f,0.95f,1.0f,1.0f)),
D(GUI_COLOR_OSC_WAVE_PEAK,"",ImVec4(0.95f,0.95f,1.0f,1.0f)),
D(GUI_COLOR_OSC_REF,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
D(GUI_COLOR_OSC_GUIDE,"",ImVec4(0.3,0.3f,0.3f,1.0f)),
D(GUI_COLOR_VOLMETER_LOW,"",ImVec4(0.2f,0.6f,0.2f,1.0f)),
D(GUI_COLOR_VOLMETER_HIGH,"",ImVec4(1.0f,0.9f,0.2f,1.0f)),
D(GUI_COLOR_VOLMETER_PEAK,"",ImVec4(1.0f,0.1f,0.1f,1.0f)),
@ -463,6 +474,12 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
D(GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,"",ImVec4(0.0f,1.0f,0.5f,1.0f)),
D(GUI_COLOR_PATTERN_EFFECT_MISC,"",ImVec4(0.3f,0.3f,1.0f,1.0f)),
D(GUI_COLOR_LOGLEVEL_ERROR,"",ImVec4(1.0f,0.2f,0.2f,1.0f)),
D(GUI_COLOR_LOGLEVEL_WARNING,"",ImVec4(1.0f,1.0f,0.2f,1.0f)),
D(GUI_COLOR_LOGLEVEL_INFO,"",ImVec4(0.4f,1.0f,0.4f,1.0f)),
D(GUI_COLOR_LOGLEVEL_DEBUG,"",ImVec4(0.3f,0.5f,1.0f,1.0f)),
D(GUI_COLOR_LOGLEVEL_TRACE,"",ImVec4(0.8f,0.8f,0.8f,1.0f)),
D(GUI_COLOR_EE_VALUE,"",ImVec4(0.0f,1.0f,1.0f,1.0f)),
D(GUI_COLOR_PLAYBACK_STAT,"",ImVec4(0.6f,0.6f,0.6f,1.0f)),
};

View file

@ -32,7 +32,7 @@ const char* ssgEnvTypes[8]={
};
const char* fmParamNames[3][32]={
{"Algorithm", "Feedback", "LFO > Freq", "LFO > Amp", "Attack", "Decay", "Decay 2", "Release", "Sustain", "Level", "EnvScale", "Multiplier", "Detune", "Detune 2", "SSG-EG", "AM", "AM Depth", "Vibrato Depth", "Sustained", "Sustained", "Level Scaling", "Sustain", "Vibrato", "Waveform", "Key Scale Rate", "OP2 Half Sine", "OP1 Half Sine", "EnvShift", "Reverb", "Fine", "LFO > Freq", "LFO > Amp"},
{"Algorithm", "Feedback", "LFO > Freq", "LFO > Amp", "Attack", "Decay", "Decay 2", "Release", "Sustain", "Level", "EnvScale", "Multiplier", "Detune", "Detune 2", "SSG-EG", "AM", "AM Depth", "Vibrato Depth", "Sustained", "Sustained", "Level Scaling", "Sustain", "Vibrato", "Waveform", "Key Scale Rate", "OP2 Half Sine", "OP1 Half Sine", "EnvShift", "Reverb", "Fine", "LFO2 > Freq", "LFO2 > Amp"},
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "SR", "RR", "SL", "TL", "KS", "MULT", "DT", "DT2", "SSG-EG", "AM", "AMD", "FMD", "EGT", "EGT", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"},
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "D2R", "RR", "SL", "TL", "RS", "MULT", "DT", "DT2", "SSG-EG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"}
};
@ -109,6 +109,10 @@ enum FMParams {
#define FM_NAME(x) fmParamNames[settings.fmNames][x]
#define FM_SHORT_NAME(x) fmParamShortNames[settings.fmNames][x]
const char* fmOperatorBits[5]={
"op1", "op2", "op3", "op4", NULL
};
const char* c64ShapeBits[5]={
"triangle", "saw", "pulse", "noise", NULL
};
@ -176,6 +180,16 @@ const char* dualWSEffects[7]={
"Phase (dual)",
};
const char* macroAbsoluteMode[2]={
"Relative",
"Absolute"
};
const char* macroDummyMode[2]={
"Bug",
"Bug"
};
String macroHoverNote(int id, float val) {
if (val<-60 || val>=120) return "???";
return fmt::sprintf("%d: %s",id,noteNames[(int)val+60]);
@ -924,8 +938,8 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
ImVec2 posREnd=ImLerp(rect.Min,rect.Max,ImVec2(rrPos,1.0));//release end
ImVec2 posSLineHEnd=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //sustain horizontal line end
ImVec2 posSLineVEnd=ImLerp(rect.Min,rect.Max,ImVec2(drPos,1.0)); //sustain vertical line end
ImVec2 posDecayRate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(tl/maxTl))); //Heght of the peak of AR, forever
ImVec2 posDecay2Rate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //Heght of the peak of SR, forever
ImVec2 posDecayRate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(tl/maxTl))); //Height of the peak of AR, forever
ImVec2 posDecay2Rate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //Height of the peak of SR, forever
//dl->Flags=ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex;
if (ar==0.0) { //if AR = 0, the envelope never starts
@ -963,7 +977,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
#define PARAMETER MARK_MODIFIED; e->notifyInsChange(curIns);
#define NORMAL_MACRO(macro,macroLen,macroLoop,macroRel,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,macroDispMin,bitOff,macroMode,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \
#define NORMAL_MACRO(macro,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,macroDispMin,bitOff,macroMode,macroModeMax,displayModeName,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \
ImGui::TableNextRow(); \
ImGui::TableNextColumn(); \
ImGui::Text("%s",displayName); \
@ -973,26 +987,41 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
} \
if (displayLoop) { \
ImGui::SetNextItemWidth(lenAvail); \
if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,&macroLen,&_ONE,&_THREE)) { MARK_MODIFIED \
if (macroLen>127) macroLen=127; \
if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,&macro.len,&_ONE,&_THREE)) { MARK_MODIFIED \
if (macro.len>127) macro.len=127; \
} \
if (macroMode!=NULL) { \
ImGui::Checkbox("Fixed##IMacroMode_" macroName,macroMode); \
if (macroMode) { \
String modeName; \
if (macro.mode>macroModeMax) { \
modeName="none selected"; \
} else { \
modeName=displayModeName[macro.mode]; \
} \
if (ImGui::BeginCombo("TODO: Improve##IMacroMode_" macroName,modeName.c_str())) { \
String id; \
for (unsigned int i=0; i<=macroModeMax; i++) { \
id=fmt::sprintf("%d: %s",i,displayModeName[i]); \
if (ImGui::Selectable(id.c_str(),macro.mode==i)) { PARAMETER \
macro.mode=i; \
} \
} \
ImGui::EndCombo(); \
} \
} \
} \
ImGui::TableNextColumn(); \
for (int j=0; j<256; j++) { \
if (j+macroDragScroll>=macroLen) { \
if (j+macroDragScroll>=macro.len) { \
asFloat[j]=0; \
asInt[j]=0; \
} else { \
asFloat[j]=macro[j+macroDragScroll]+macroDispMin; \
asInt[j]=macro[j+macroDragScroll]+macroDispMin+bitOff; \
asFloat[j]=macro.val[j+macroDragScroll]+macroDispMin; \
asInt[j]=macro.val[j+macroDragScroll]+macroDispMin+bitOff; \
} \
if (j+macroDragScroll>=macroLen || (j+macroDragScroll>macroRel && macroLoop<macroRel)) { \
if (j+macroDragScroll>=macro.len || (j+macroDragScroll>macro.rel && macro.loop<macro.rel)) { \
loopIndicator[j]=0; \
} else { \
loopIndicator[j]=((macroLoop!=-1 && (j+macroDragScroll)>=macroLoop))|((macroRel!=-1 && (j+macroDragScroll)==macroRel)<<1); \
loopIndicator[j]=((macro.loop!=-1 && (j+macroDragScroll)>=macro.loop))|((macro.rel!=-1 && (j+macroDragScroll)==macro.rel)<<1); \
} \
} \
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); \
@ -1000,7 +1029,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
if (bitfield) { \
PlotBitfield("##IMacro_" macroName,asInt,totalFit,0,bfVal,macroHeight,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale))); \
} else { \
PlotCustom("##IMacro_" macroName,asFloat,totalFit,macroDragScroll,NULL,macroDispMin+macroMin,macroHeight+macroDispMin,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale)),sizeof(float),macroColor,macroLen-macroDragScroll,hoverFunc,blockMode); \
PlotCustom("##IMacro_" macroName,asFloat,totalFit,macroDragScroll,NULL,macroDispMin+macroMin,macroHeight+macroDispMin,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale)),sizeof(float),macroColor,macro.len-macroDragScroll,hoverFunc,blockMode); \
} \
if (displayLoop && ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \
macroDragStart=ImGui::GetItemRectMin(); \
@ -1013,7 +1042,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
macroDragInitialValue=false; \
macroDragLen=totalFit; \
macroDragActive=true; \
macroDragTarget=macro; \
macroDragTarget=macro.val; \
macroDragChar=false; \
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \
} \
@ -1022,37 +1051,37 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
ImGui::SameLine(); \
CWVSliderInt("##IArpMacroPos",ImVec2(20.0f*dpiScale,displayHeight*dpiScale),sliderVal,sliderLow,70); \
} \
PlotCustom("##IMacroLoop_" macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),macroColor,macroLen-macroDragScroll,&macroHoverLoop); \
PlotCustom("##IMacroLoop_" macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),macroColor,macro.len-macroDragScroll,&macroHoverLoop); \
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \
macroLoopDragStart=ImGui::GetItemRectMin(); \
macroLoopDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); \
macroLoopDragLen=totalFit; \
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \
macroLoopDragTarget=&macroRel; \
macroLoopDragTarget=&macro.rel; \
} else { \
macroLoopDragTarget=&macroLoop; \
macroLoopDragTarget=&macro.loop; \
} \
macroLoopDragActive=true; \
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \
} \
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { \
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \
macroRel=-1; \
macro.rel=-1; \
} else { \
macroLoop=-1; \
macro.loop=-1; \
} \
} \
ImGui::SetNextItemWidth(availableWidth); \
if (ImGui::InputText("##IMacroMML_" macroName,&mmlStr)) { \
decodeMMLStr(mmlStr,macro,macroLen,macroLoop,macroAMin,(bitfield)?((1<<macroAMax)-1):macroAMax,macroRel); \
decodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,macroAMin,(bitfield)?((1<<(bitfield?macroAMax:0))-1):macroAMax,macro.rel); \
} \
if (!ImGui::IsItemActive()) { \
encodeMMLStr(mmlStr,macro,macroLen,macroLoop,macroRel); \
encodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,macro.rel); \
} \
} \
ImGui::PopStyleVar();
#define OP_MACRO(macro,macroLen,macroLoop,macroRel,macroHeight,op,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,mmlStr) \
#define OP_MACRO(macro,macroHeight,op,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,macroMode,macroModeMax,displayModeName,mmlStr) \
ImGui::TableNextRow(); \
ImGui::TableNextColumn(); \
ImGui::Text("%s",displayName); \
@ -1062,23 +1091,41 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
} \
if (displayLoop) { \
ImGui::SetNextItemWidth(lenAvail); \
if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,&macroLen,&_ONE,&_THREE)) { MARK_MODIFIED \
if (macroLen>127) macroLen=127; \
if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,&macro.len,&_ONE,&_THREE)) { MARK_MODIFIED \
if (macro.len>127) macro.len=127; \
} \
if (macroMode) { \
String modeName; \
if (macro.mode>macroModeMax) { \
modeName="none selected"; \
} else { \
modeName=displayModeName[macro.mode]; \
} \
if (ImGui::BeginCombo("TODO: Improve##IOPMacroMode_" macroName,modeName.c_str())) { \
String id; \
for (unsigned int i=0; i<=macroModeMax; i++) { \
id=fmt::sprintf("%d: %s",i,displayModeName[i]); \
if (ImGui::Selectable(id.c_str(),macro.mode==i)) { PARAMETER \
macro.mode=i; \
} \
} \
ImGui::EndCombo(); \
} \
} \
} \
ImGui::TableNextColumn(); \
for (int j=0; j<256; j++) { \
if (j+macroDragScroll>=macroLen) { \
if (j+macroDragScroll>=macro.len) { \
asFloat[j]=0; \
asInt[j]=0; \
} else { \
asFloat[j]=macro[j+macroDragScroll]; \
asInt[j]=macro[j+macroDragScroll]; \
asFloat[j]=macro.val[j+macroDragScroll]; \
asInt[j]=macro.val[j+macroDragScroll]; \
} \
if (j+macroDragScroll>=macroLen || (j+macroDragScroll>macroRel && macroLoop<macroRel)) { \
if (j+macroDragScroll>=macro.len || (j+macroDragScroll>macro.rel && macro.loop<macro.rel)) { \
loopIndicator[j]=0; \
} else { \
loopIndicator[j]=((macroLoop!=-1 && (j+macroDragScroll)>=macroLoop))|((macroRel!=-1 && (j+macroDragScroll)==macroRel)<<1); \
loopIndicator[j]=((macro.loop!=-1 && (j+macroDragScroll)>=macro.loop))|((macro.rel!=-1 && (j+macroDragScroll)==macro.rel)<<1); \
} \
} \
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); \
@ -1086,7 +1133,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
if (bitfield) { \
PlotBitfield("##IOPMacro_" #op macroName,asInt,totalFit,0,bfVal,macroHeight,ImVec2(availableWidth,displayLoop?(displayHeight*dpiScale):(24*dpiScale))); \
} else { \
PlotCustom("##IOPMacro_" #op macroName,asFloat,totalFit,macroDragScroll,NULL,0,macroHeight,ImVec2(availableWidth,displayLoop?(displayHeight*dpiScale):(24*dpiScale)),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macroLen-macroDragScroll); \
PlotCustom("##IOPMacro_" #op macroName,asFloat,totalFit,macroDragScroll,NULL,0,macroHeight,ImVec2(availableWidth,displayLoop?(displayHeight*dpiScale):(24*dpiScale)),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macro.len-macroDragScroll); \
} \
if (displayLoop && ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \
macroDragStart=ImGui::GetItemRectMin(); \
@ -1099,37 +1146,37 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
macroDragInitialValue=false; \
macroDragLen=totalFit; \
macroDragActive=true; \
macroDragCTarget=macro; \
macroDragChar=true; \
macroDragTarget=macro.val; \
macroDragChar=false; \
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \
} \
if (displayLoop) { \
PlotCustom("##IOPMacroLoop_" #op macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macroLen-macroDragScroll,&macroHoverLoop); \
PlotCustom("##IOPMacroLoop_" #op macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macro.len-macroDragScroll,&macroHoverLoop); \
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \
macroLoopDragStart=ImGui::GetItemRectMin(); \
macroLoopDragAreaSize=ImVec2(availableWidth,8.0f*dpiScale); \
macroLoopDragLen=totalFit; \
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \
macroLoopDragTarget=&macroRel; \
macroLoopDragTarget=&macro.rel; \
} else { \
macroLoopDragTarget=&macroLoop; \
macroLoopDragTarget=&macro.loop; \
} \
macroLoopDragActive=true; \
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \
} \
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { \
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \
macroRel=-1; \
macro.rel=-1; \
} else { \
macroLoop=-1; \
macro.loop=-1; \
} \
} \
ImGui::SetNextItemWidth(availableWidth); \
if (ImGui::InputText("##IOPMacroMML_" macroName,&mmlStr)) { \
decodeMMLStr(mmlStr,macro,macroLen,macroLoop,0,bitfield?((1<<macroHeight)-1):(macroHeight),macroRel); \
decodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,0,bitfield?((1<<(bitfield?macroHeight:0))-1):(macroHeight),macro.rel); \
} \
if (!ImGui::IsItemActive()) { \
encodeMMLStr(mmlStr,macro,macroLen,macroLoop,macroRel); \
encodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,macro.rel); \
} \
} \
ImGui::PopStyleVar();
@ -1262,7 +1309,7 @@ void FurnaceGUI::drawInsEdit() {
ImGui::Text("Type");
ImGui::TableNextColumn();
if (ins->type<0 || ins->type>=DIV_INS_MAX) ins->type=DIV_INS_FM;
if (ins->type>=DIV_INS_MAX) ins->type=DIV_INS_FM;
int insType=ins->type;
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##Type",&insType,insTypes,DIV_INS_MAX,DIV_INS_MAX)) {
@ -1804,8 +1851,6 @@ void FurnaceGUI::drawInsEdit() {
op.am=amOn;
}
ImGui::SameLine();
int maxTl=127;
if (ins->type==DIV_INS_OPLL) {
if (i==1) {
@ -1825,6 +1870,7 @@ void FurnaceGUI::drawInsEdit() {
bool susOn=op.sus; // don't you make fun of this one
unsigned char ssgEnv=op.ssgEnv&7;
if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPZ) {
ImGui::SameLine();
if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER
op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3);
}
@ -1836,6 +1882,7 @@ void FurnaceGUI::drawInsEdit() {
}
if (ins->type==DIV_INS_OPL) {
ImGui::SameLine();
if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER
op.sus=susOn;
}
@ -1953,14 +2000,16 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_DT2));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
} rightClickable
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_SSG));
if (ins->type==DIV_INS_FM) { // OPN only
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
} rightClickable
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_SSG));
}
}
if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) {
@ -1999,24 +2048,31 @@ void FurnaceGUI::drawInsEdit() {
if (ImGui::BeginTabItem("FM Macros")) {
MACRO_BEGIN(0);
if (ins->type==DIV_INS_OPLL) {
NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,1,"alg",FM_NAME(FM_SUS),32,ins->std.algMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,1,NULL,false);
NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,1,"fms",FM_NAME(FM_DC),32,ins->std.fmsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,1,NULL,false);
NORMAL_MACRO(ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel,0,1,"ams",FM_NAME(FM_DM),32,ins->std.amsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,1,NULL,false);
NORMAL_MACRO(ins->std.algMacro,0,1,"alg",FM_NAME(FM_SUS),32,ins->std.algMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,1,NULL,false);
NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
NORMAL_MACRO(ins->std.fmsMacro,0,1,"fms",FM_NAME(FM_DC),32,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,1,NULL,false);
NORMAL_MACRO(ins->std.amsMacro,0,1,"ams",FM_NAME(FM_DM),32,ins->std.amsMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,1,NULL,false);
} else {
NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false);
NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
NORMAL_MACRO(ins->std.algMacro,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false);
NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
if (ins->type!=DIV_INS_OPL) {
NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false);
NORMAL_MACRO(ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false);
if (ins->type==DIV_INS_OPZ) {
// TODO: FMS2/AMS2 macros
NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false);
NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,3,NULL,false);
} else {
NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false);
NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false);
}
}
}
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,127,"ex1","AM Depth",128,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,127,NULL,false);
NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,127,"ex2","PM Depth",128,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,127,NULL,false);
NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,255,"ex3","LFO Speed",128,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false);
NORMAL_MACRO(ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel,0,3,"wave","LFO Shape",48,ins->std.waveMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[7],0,3,&macroLFOWaves,false);
NORMAL_MACRO(ins->std.ex1Macro,0,127,"ex1","AM Depth",128,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false);
NORMAL_MACRO(ins->std.ex2Macro,0,127,"ex2","PM Depth",128,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,127,NULL,false);
NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","LFO Speed",128,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,255,NULL,false);
NORMAL_MACRO(ins->std.waveMacro,0,3,"wave","LFO Shape",48,ins->std.waveMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[9],0,3,&macroLFOWaves,false);
NORMAL_MACRO(ins->std.ex4Macro,0,4,"ex4","OpMask",128,ins->std.ex4Macro.open,true,fmOperatorBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false);
}
MACRO_END;
ImGui::EndTabItem();
@ -2041,45 +2097,45 @@ void FurnaceGUI::drawInsEdit() {
int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15;
if (ins->type==DIV_INS_OPL) {
OP_MACRO(ins->std.opMacros[ordi].tlMacro,ins->std.opMacros[ordi].tlMacroLen,ins->std.opMacros[ordi].tlMacroLoop,ins->std.opMacros[ordi].tlMacroRel,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacroOpen,false,NULL,mmlString[0]);
OP_MACRO(ins->std.opMacros[ordi].arMacro,ins->std.opMacros[ordi].arMacroLen,ins->std.opMacros[ordi].arMacroLoop,ins->std.opMacros[ordi].arMacroRel,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacroOpen,false,NULL,mmlString[1]);
OP_MACRO(ins->std.opMacros[ordi].drMacro,ins->std.opMacros[ordi].drMacroLen,ins->std.opMacros[ordi].drMacroLoop,ins->std.opMacros[ordi].drMacroRel,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacroOpen,false,NULL,mmlString[2]);
OP_MACRO(ins->std.opMacros[ordi].slMacro,ins->std.opMacros[ordi].slMacroLen,ins->std.opMacros[ordi].slMacroLoop,ins->std.opMacros[ordi].slMacroRel,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacroOpen,false,NULL,mmlString[5]);
OP_MACRO(ins->std.opMacros[ordi].rrMacro,ins->std.opMacros[ordi].rrMacroLen,ins->std.opMacros[ordi].rrMacroLoop,ins->std.opMacros[ordi].rrMacroRel,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacroOpen,false,NULL,mmlString[4]);
OP_MACRO(ins->std.opMacros[ordi].kslMacro,ins->std.opMacros[ordi].kslMacroLen,ins->std.opMacros[ordi].kslMacroLoop,ins->std.opMacros[ordi].kslMacroRel,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacroOpen,false,NULL,mmlString[6]);
OP_MACRO(ins->std.opMacros[ordi].multMacro,ins->std.opMacros[ordi].multMacroLen,ins->std.opMacros[ordi].multMacroLoop,ins->std.opMacros[ordi].multMacroRel,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacroOpen,false,NULL,mmlString[7]);
OP_MACRO(ins->std.opMacros[ordi].wsMacro,ins->std.opMacros[ordi].wsMacroLen,ins->std.opMacros[ordi].wsMacroLoop,ins->std.opMacros[ordi].wsMacroRel,7,ordi,"ws",FM_NAME(FM_WS),64,ins->std.opMacros[ordi].wsMacroOpen,false,NULL,mmlString[8]);
OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]);
OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]);
OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]);
OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]);
OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]);
OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]);
OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]);
OP_MACRO(ins->std.opMacros[ordi].wsMacro,7,ordi,"ws",FM_NAME(FM_WS),64,ins->std.opMacros[ordi].wsMacro.open,false,NULL,false,0,macroDummyMode,mmlString[8]);
OP_MACRO(ins->std.opMacros[ordi].amMacro,ins->std.opMacros[ordi].amMacroLen,ins->std.opMacros[ordi].amMacroLoop,ins->std.opMacros[ordi].amMacroRel,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacroOpen,true,NULL,mmlString[9]);
OP_MACRO(ins->std.opMacros[ordi].vibMacro,ins->std.opMacros[ordi].vibMacroLen,ins->std.opMacros[ordi].vibMacroLoop,ins->std.opMacros[ordi].vibMacroRel,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacroOpen,true,NULL,mmlString[10]);
OP_MACRO(ins->std.opMacros[ordi].ksrMacro,ins->std.opMacros[ordi].ksrMacroLen,ins->std.opMacros[ordi].ksrMacroLoop,ins->std.opMacros[ordi].ksrMacroRel,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacroOpen,true,NULL,mmlString[11]);
OP_MACRO(ins->std.opMacros[ordi].susMacro,ins->std.opMacros[ordi].susMacroLen,ins->std.opMacros[ordi].susMacroLoop,ins->std.opMacros[ordi].susMacroRel,1,ordi,"sus",FM_NAME(FM_SUS),32,ins->std.opMacros[ordi].susMacroOpen,true,NULL,mmlString[12]);
OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[9]);
OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]);
OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,0,macroDummyMode,mmlString[11]);
OP_MACRO(ins->std.opMacros[ordi].susMacro,1,ordi,"sus",FM_NAME(FM_SUS),32,ins->std.opMacros[ordi].susMacro.open,true,NULL,false,0,macroDummyMode,mmlString[12]);
} else if (ins->type==DIV_INS_OPLL) {
OP_MACRO(ins->std.opMacros[ordi].tlMacro,ins->std.opMacros[ordi].tlMacroLen,ins->std.opMacros[ordi].tlMacroLoop,ins->std.opMacros[ordi].tlMacroRel,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacroOpen,false,NULL,mmlString[0]);
OP_MACRO(ins->std.opMacros[ordi].arMacro,ins->std.opMacros[ordi].arMacroLen,ins->std.opMacros[ordi].arMacroLoop,ins->std.opMacros[ordi].arMacroRel,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacroOpen,false,NULL,mmlString[1]);
OP_MACRO(ins->std.opMacros[ordi].drMacro,ins->std.opMacros[ordi].drMacroLen,ins->std.opMacros[ordi].drMacroLoop,ins->std.opMacros[ordi].drMacroRel,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacroOpen,false,NULL,mmlString[2]);
OP_MACRO(ins->std.opMacros[ordi].slMacro,ins->std.opMacros[ordi].slMacroLen,ins->std.opMacros[ordi].slMacroLoop,ins->std.opMacros[ordi].slMacroRel,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacroOpen,false,NULL,mmlString[5]);
OP_MACRO(ins->std.opMacros[ordi].rrMacro,ins->std.opMacros[ordi].rrMacroLen,ins->std.opMacros[ordi].rrMacroLoop,ins->std.opMacros[ordi].rrMacroRel,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacroOpen,false,NULL,mmlString[4]);
OP_MACRO(ins->std.opMacros[ordi].kslMacro,ins->std.opMacros[ordi].kslMacroLen,ins->std.opMacros[ordi].kslMacroLoop,ins->std.opMacros[ordi].kslMacroRel,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacroOpen,false,NULL,mmlString[6]);
OP_MACRO(ins->std.opMacros[ordi].multMacro,ins->std.opMacros[ordi].multMacroLen,ins->std.opMacros[ordi].multMacroLoop,ins->std.opMacros[ordi].multMacroRel,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacroOpen,false,NULL,mmlString[7]);
OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]);
OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]);
OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]);
OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]);
OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]);
OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]);
OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]);
OP_MACRO(ins->std.opMacros[ordi].amMacro,ins->std.opMacros[ordi].amMacroLen,ins->std.opMacros[ordi].amMacroLoop,ins->std.opMacros[ordi].amMacroRel,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacroOpen,true,NULL,mmlString[8]);
OP_MACRO(ins->std.opMacros[ordi].vibMacro,ins->std.opMacros[ordi].vibMacroLen,ins->std.opMacros[ordi].vibMacroLoop,ins->std.opMacros[ordi].vibMacroRel,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacroOpen,true,NULL,mmlString[9]);
OP_MACRO(ins->std.opMacros[ordi].ksrMacro,ins->std.opMacros[ordi].ksrMacroLen,ins->std.opMacros[ordi].ksrMacroLoop,ins->std.opMacros[ordi].ksrMacroRel,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacroOpen,true,NULL,mmlString[10]);
OP_MACRO(ins->std.opMacros[ordi].egtMacro,ins->std.opMacros[ordi].egtMacroLen,ins->std.opMacros[ordi].egtMacroLoop,ins->std.opMacros[ordi].egtMacroRel,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacroOpen,true,NULL,mmlString[11]);
OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[8]);
OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,0,macroDummyMode,mmlString[9]);
OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]);
OP_MACRO(ins->std.opMacros[ordi].egtMacro,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacro.open,true,NULL,false,0,macroDummyMode,mmlString[11]);
} else {
OP_MACRO(ins->std.opMacros[ordi].tlMacro,ins->std.opMacros[ordi].tlMacroLen,ins->std.opMacros[ordi].tlMacroLoop,ins->std.opMacros[ordi].tlMacroRel,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacroOpen,false,NULL,mmlString[0]);
OP_MACRO(ins->std.opMacros[ordi].arMacro,ins->std.opMacros[ordi].arMacroLen,ins->std.opMacros[ordi].arMacroLoop,ins->std.opMacros[ordi].arMacroRel,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacroOpen,false,NULL,mmlString[1]);
OP_MACRO(ins->std.opMacros[ordi].drMacro,ins->std.opMacros[ordi].drMacroLen,ins->std.opMacros[ordi].drMacroLoop,ins->std.opMacros[ordi].drMacroRel,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacroOpen,false,NULL,mmlString[2]);
OP_MACRO(ins->std.opMacros[ordi].d2rMacro,ins->std.opMacros[ordi].d2rMacroLen,ins->std.opMacros[ordi].d2rMacroLoop,ins->std.opMacros[ordi].d2rMacroRel,31,ordi,"d2r",FM_NAME(FM_D2R),64,ins->std.opMacros[ordi].d2rMacroOpen,false,NULL,mmlString[3]);
OP_MACRO(ins->std.opMacros[ordi].rrMacro,ins->std.opMacros[ordi].rrMacroLen,ins->std.opMacros[ordi].rrMacroLoop,ins->std.opMacros[ordi].rrMacroRel,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacroOpen,false,NULL,mmlString[4]);
OP_MACRO(ins->std.opMacros[ordi].slMacro,ins->std.opMacros[ordi].slMacroLen,ins->std.opMacros[ordi].slMacroLoop,ins->std.opMacros[ordi].slMacroRel,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacroOpen,false,NULL,mmlString[5]);
OP_MACRO(ins->std.opMacros[ordi].rsMacro,ins->std.opMacros[ordi].rsMacroLen,ins->std.opMacros[ordi].rsMacroLoop,ins->std.opMacros[ordi].rsMacroRel,3,ordi,"rs",FM_NAME(FM_RS),32,ins->std.opMacros[ordi].rsMacroOpen,false,NULL,mmlString[6]);
OP_MACRO(ins->std.opMacros[ordi].multMacro,ins->std.opMacros[ordi].multMacroLen,ins->std.opMacros[ordi].multMacroLoop,ins->std.opMacros[ordi].multMacroRel,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacroOpen,false,NULL,mmlString[7]);
OP_MACRO(ins->std.opMacros[ordi].dtMacro,ins->std.opMacros[ordi].dtMacroLen,ins->std.opMacros[ordi].dtMacroLoop,ins->std.opMacros[ordi].dtMacroRel,7,ordi,"dt",FM_NAME(FM_DT),64,ins->std.opMacros[ordi].dtMacroOpen,false,NULL,mmlString[8]);
OP_MACRO(ins->std.opMacros[ordi].dt2Macro,ins->std.opMacros[ordi].dt2MacroLen,ins->std.opMacros[ordi].dt2MacroLoop,ins->std.opMacros[ordi].dt2MacroRel,3,ordi,"dt2",FM_NAME(FM_DT2),32,ins->std.opMacros[ordi].dt2MacroOpen,false,NULL,mmlString[9]);
OP_MACRO(ins->std.opMacros[ordi].amMacro,ins->std.opMacros[ordi].amMacroLen,ins->std.opMacros[ordi].amMacroLoop,ins->std.opMacros[ordi].amMacroRel,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacroOpen,true,NULL,mmlString[10]);
OP_MACRO(ins->std.opMacros[ordi].ssgMacro,ins->std.opMacros[ordi].ssgMacroLen,ins->std.opMacros[ordi].ssgMacroLoop,ins->std.opMacros[ordi].ssgMacroRel,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacroOpen,true,ssgEnvBits,mmlString[11]);
OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]);
OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]);
OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]);
OP_MACRO(ins->std.opMacros[ordi].d2rMacro,31,ordi,"d2r",FM_NAME(FM_D2R),64,ins->std.opMacros[ordi].d2rMacro.open,false,NULL,false,0,macroDummyMode,mmlString[3]);
OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]);
OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]);
OP_MACRO(ins->std.opMacros[ordi].rsMacro,3,ordi,"rs",FM_NAME(FM_RS),32,ins->std.opMacros[ordi].rsMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]);
OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]);
OP_MACRO(ins->std.opMacros[ordi].dtMacro,7,ordi,"dt",FM_NAME(FM_DT),64,ins->std.opMacros[ordi].dtMacro.open,false,NULL,false,0,macroDummyMode,mmlString[8]);
OP_MACRO(ins->std.opMacros[ordi].dt2Macro,3,ordi,"dt2",FM_NAME(FM_DT2),32,ins->std.opMacros[ordi].dt2Macro.open,false,NULL,false,0,macroDummyMode,mmlString[9]);
OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]);
OP_MACRO(ins->std.opMacros[ordi].ssgMacro,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacro.open,true,ssgEnvBits,false,0,macroDummyMode,mmlString[11]);
}
MACRO_END;
ImGui::PopID();
@ -2464,7 +2520,7 @@ void FurnaceGUI::drawInsEdit() {
volMax=32;
}
bool arpMode=ins->std.arpMacroMode;
bool arpMode=ins->std.arpMacro.mode;
const char* dutyLabel="Duty/Noise";
int dutyMax=3;
@ -2571,66 +2627,67 @@ void FurnaceGUI::drawInsEdit() {
if (settings.macroView==0) { // modern view
MACRO_BEGIN(28*dpiScale);
if (volMax>0) {
NORMAL_MACRO(ins->std.volMacro,ins->std.volMacroLen,ins->std.volMacroLoop,ins->std.volMacroRel,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL,false);
NORMAL_MACRO(ins->std.volMacro,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL,false);
}
NORMAL_MACRO(ins->std.arpMacro,ins->std.arpMacroLen,ins->std.arpMacroLoop,ins->std.arpMacroRel,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacroOpen,false,NULL,true,&arpMacroScroll,(arpMode?-60:-80),0,0,&ins->std.arpMacroMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-92,94,(ins->std.arpMacroMode?(&macroHoverNote):NULL),true);
NORMAL_MACRO(ins->std.arpMacro,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacro.open,false,NULL,true,&arpMacroScroll,(arpMode?-60:-80),0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-92,94,(ins->std.arpMacro.mode?(&macroHoverNote):NULL),true);
if (dutyMax>0) {
if (ins->type==DIV_INS_MIKEY) {
NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,true,mikeyFeedbackBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,true,mikeyFeedbackBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
} else if (ins->type==DIV_INS_C64) {
NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
} else {
NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
}
else {
NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
}
}
if (waveMax>0) {
NORMAL_MACRO(ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacroOpen,bitMode,waveNames,false,NULL,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),NULL,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false);
NORMAL_MACRO(ins->std.waveMacro,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacro.open,bitMode,waveNames,false,NULL,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false);
}
if (ex1Max>0) {
if (ins->type==DIV_INS_C64) {
NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1MacroOpen,true,filtModeBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1Macro.open,true,filtModeBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
} else if (ins->type==DIV_INS_SAA1099) {
NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Envelope",160,ins->std.ex1MacroOpen,true,saaEnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope",160,ins->std.ex1Macro.open,true,saaEnvBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
} else if (ins->type==DIV_INS_X1_010) {
NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Envelope Mode",160,ins->std.ex1MacroOpen,true,x1_010EnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope Mode",160,ins->std.ex1Macro.open,true,x1_010EnvBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
} else if (ins->type==DIV_INS_N163) {
NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Waveform len.",160,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Waveform len.",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
} else if (ins->type==DIV_INS_FDS) {
NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Mod Depth",160,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Mod Depth",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
} else {
NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Duty",160,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Duty",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
}
}
if (ex2Max>0) {
if (ins->type==DIV_INS_C64) {
NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Resonance",64,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",64,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
} else if (ins->type==DIV_INS_N163) {
NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Waveform update",64,ins->std.ex2MacroOpen,true,n163UpdateBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Waveform update",64,ins->std.ex2Macro.open,true,n163UpdateBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
} else if (ins->type==DIV_INS_FDS) {
NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Mod Speed",160,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Mod Speed",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
} else {
NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Envelope",ex2Bit?64:160,ins->std.ex2MacroOpen,ex2Bit,ayEnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Envelope",ex2Bit?64:160,ins->std.ex2Macro.open,ex2Bit,ayEnvBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
}
}
if (ins->type==DIV_INS_C64) {
NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,2,"ex3","Special",32,ins->std.ex3MacroOpen,true,c64SpecialBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false);
NORMAL_MACRO(ins->std.ex3Macro,0,2,"ex3","Special",32,ins->std.ex3Macro.open,true,c64SpecialBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false);
}
if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_X1_010) {
NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,15,"ex3","AutoEnv Num",96,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL,false);
NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,15,"alg","AutoEnv Den",96,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL,false);
NORMAL_MACRO(ins->std.ex3Macro,0,15,"ex3","AutoEnv Num",96,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL,false);
NORMAL_MACRO(ins->std.algMacro,0,15,"alg","AutoEnv Den",96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL,false);
}
if (ins->type==DIV_INS_AY8930) {
// oh my i am running out of macros
NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,8,"fb","Noise AND Mask",96,ins->std.fbMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL,false);
NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL,false);
NORMAL_MACRO(ins->std.fbMacro,0,8,"fb","Noise AND Mask",96,ins->std.fbMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL,false);
NORMAL_MACRO(ins->std.fmsMacro,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL,false);
}
if (ins->type==DIV_INS_N163) {
NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,255,"ex3","Waveform to Load",160,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false);
NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,255,"alg","Wave pos. to Load",160,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,255,NULL,false);
NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,252,"fb","Wave len. to Load",160,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,252,NULL,false);
NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,2,"fms","Waveform load",64,ins->std.fmsMacroOpen,true,n163UpdateBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,2,NULL,false);
NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","Waveform to Load",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false);
NORMAL_MACRO(ins->std.algMacro,0,255,"alg","Wave pos. to Load",160,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,255,NULL,false);
NORMAL_MACRO(ins->std.fbMacro,0,252,"fb","Wave len. to Load",160,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,252,NULL,false);
NORMAL_MACRO(ins->std.fmsMacro,0,2,"fms","Waveform load",64,ins->std.fmsMacro.open,true,n163UpdateBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,2,NULL,false);
}
if (ins->type==DIV_INS_FDS) {
NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,127,"ex3","Mod Position",160,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false);
NORMAL_MACRO(ins->std.ex3Macro,0,127,"ex3","Mod Position",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false);
}
MACRO_END;
@ -2646,87 +2703,87 @@ void FurnaceGUI::drawInsEdit() {
} else {
ImGui::Text("Volume Macro");
}
for (int i=0; i<ins->std.volMacroLen; i++) {
for (int i=0; i<ins->std.volMacro.len; i++) {
if (ins->type==DIV_INS_C64 && ins->c64.volIsCutoff && !ins->c64.filterIsAbs) {
asFloat[i]=ins->std.volMacro[i]-18;
asFloat[i]=ins->std.volMacro.val[i]-18;
} else {
asFloat[i]=ins->std.volMacro[i];
asFloat[i]=ins->std.volMacro.val[i];
}
loopIndicator[i]=(ins->std.volMacroLoop!=-1 && i>=ins->std.volMacroLoop);
loopIndicator[i]=(ins->std.volMacro.loop!=-1 && i>=ins->std.volMacro.loop);
}
macroDragScroll=0;
if (volMax>0) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f));
ImGui::PlotHistogram("##IVolMacro",asFloat,ins->std.volMacroLen,0,NULL,volMin,volMax,ImVec2(400.0f*dpiScale,200.0f*dpiScale));
ImGui::PlotHistogram("##IVolMacro",asFloat,ins->std.volMacro.len,0,NULL,volMin,volMax,ImVec2(400.0f*dpiScale,200.0f*dpiScale));
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin();
macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale);
macroDragMin=volMin;
macroDragMax=volMax;
macroDragLen=ins->std.volMacroLen;
macroDragLen=ins->std.volMacro.len;
macroDragActive=true;
macroDragTarget=ins->std.volMacro;
macroDragTarget=ins->std.volMacro.val;
macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
ImGui::PlotHistogram("##IVolMacroLoop",loopIndicator,ins->std.volMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
ImGui::PlotHistogram("##IVolMacro.loop",loopIndicator,ins->std.volMacro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.volMacroLen;
macroLoopDragTarget=&ins->std.volMacroLoop;
macroLoopDragLen=ins->std.volMacro.len;
macroLoopDragTarget=&ins->std.volMacro.loop;
macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.volMacroLoop=-1;
ins->std.volMacro.loop=-1;
}
ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IVolMacroL",ImGuiDataType_U8,&ins->std.volMacroLen,&_ONE,&_THREE)) {
if (ins->std.volMacroLen>127) ins->std.volMacroLen=127;
if (ImGui::InputScalar("Length##IVolMacroL",ImGuiDataType_U8,&ins->std.volMacro.len,&_ONE,&_THREE)) {
if (ins->std.volMacro.len>127) ins->std.volMacro.len=127;
}
}
// arp macro
ImGui::Separator();
ImGui::Text("Arpeggio Macro");
for (int i=0; i<ins->std.arpMacroLen; i++) {
asFloat[i]=ins->std.arpMacro[i];
loopIndicator[i]=(ins->std.arpMacroLoop!=-1 && i>=ins->std.arpMacroLoop);
for (int i=0; i<ins->std.arpMacro.len; i++) {
asFloat[i]=ins->std.arpMacro.val[i];
loopIndicator[i]=(ins->std.arpMacro.loop!=-1 && i>=ins->std.arpMacro.loop);
}
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f));
ImGui::PlotHistogram("##IArpMacro",asFloat,ins->std.arpMacroLen,0,NULL,arpMode?arpMacroScroll:(arpMacroScroll-12),arpMacroScroll+(arpMode?24:12),ImVec2(400.0f*dpiScale,200.0f*dpiScale));
ImGui::PlotHistogram("##IArpMacro",asFloat,ins->std.arpMacro.len,0,NULL,arpMode?arpMacroScroll:(arpMacroScroll-12),arpMacroScroll+(arpMode?24:12),ImVec2(400.0f*dpiScale,200.0f*dpiScale));
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin();
macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale);
macroDragMin=arpMacroScroll;
macroDragMax=arpMacroScroll+24;
macroDragLen=ins->std.arpMacroLen;
macroDragLen=ins->std.arpMacro.len;
macroDragActive=true;
macroDragTarget=ins->std.arpMacro;
macroDragTarget=ins->std.arpMacro.val;
macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
ImGui::SameLine();
CWVSliderInt("##IArpMacroPos",ImVec2(20.0f*dpiScale,200.0f*dpiScale),&arpMacroScroll,arpMode?0:-80,70);
ImGui::PlotHistogram("##IArpMacroLoop",loopIndicator,ins->std.arpMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
ImGui::PlotHistogram("##IArpMacro.loop",loopIndicator,ins->std.arpMacro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.arpMacroLen;
macroLoopDragTarget=&ins->std.arpMacroLoop;
macroLoopDragLen=ins->std.arpMacro.len;
macroLoopDragTarget=&ins->std.arpMacro.loop;
macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.arpMacroLoop=-1;
ins->std.arpMacro.loop=-1;
}
ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IArpMacroL",ImGuiDataType_U8,&ins->std.arpMacroLen,&_ONE,&_THREE)) {
if (ins->std.arpMacroLen>127) ins->std.arpMacroLen=127;
if (ImGui::InputScalar("Length##IArpMacroL",ImGuiDataType_U8,&ins->std.arpMacro.len,&_ONE,&_THREE)) {
if (ins->std.arpMacro.len>127) ins->std.arpMacro.len=127;
}
if (ImGui::Checkbox("Fixed",&arpMode)) {
ins->std.arpMacroMode=arpMode;
ins->std.arpMacro.mode=arpMode;
if (arpMode) {
if (arpMacroScroll<0) arpMacroScroll=0;
}
@ -2748,39 +2805,39 @@ void FurnaceGUI::drawInsEdit() {
ImGui::Text("Duty/Noise Mode Macro");
}
}
for (int i=0; i<ins->std.dutyMacroLen; i++) {
asFloat[i]=ins->std.dutyMacro[i]-(dutyIsRel?12:0);
loopIndicator[i]=(ins->std.dutyMacroLoop!=-1 && i>=ins->std.dutyMacroLoop);
for (int i=0; i<ins->std.dutyMacro.len; i++) {
asFloat[i]=ins->std.dutyMacro.val[i]-(dutyIsRel?12:0);
loopIndicator[i]=(ins->std.dutyMacro.loop!=-1 && i>=ins->std.dutyMacro.loop);
}
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f));
ImGui::PlotHistogram("##IDutyMacro",asFloat,ins->std.dutyMacroLen,0,NULL,dutyIsRel?-12:0,dutyMax-(dutyIsRel?12:0),ImVec2(400.0f*dpiScale,200.0f*dpiScale));
ImGui::PlotHistogram("##IDutyMacro",asFloat,ins->std.dutyMacro.len,0,NULL,dutyIsRel?-12:0,dutyMax-(dutyIsRel?12:0),ImVec2(400.0f*dpiScale,200.0f*dpiScale));
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin();
macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale);
macroDragMin=0;
macroDragMax=dutyMax;
macroDragLen=ins->std.dutyMacroLen;
macroDragLen=ins->std.dutyMacro.len;
macroDragActive=true;
macroDragTarget=ins->std.dutyMacro;
macroDragTarget=ins->std.dutyMacro.val;
macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
ImGui::PlotHistogram("##IDutyMacroLoop",loopIndicator,ins->std.dutyMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
ImGui::PlotHistogram("##IDutyMacro.loop",loopIndicator,ins->std.dutyMacro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.dutyMacroLen;
macroLoopDragTarget=&ins->std.dutyMacroLoop;
macroLoopDragLen=ins->std.dutyMacro.len;
macroLoopDragTarget=&ins->std.dutyMacro.loop;
macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.dutyMacroLoop=-1;
ins->std.dutyMacro.loop=-1;
}
ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IDutyMacroL",ImGuiDataType_U8,&ins->std.dutyMacroLen,&_ONE,&_THREE)) {
if (ins->std.dutyMacroLen>127) ins->std.dutyMacroLen=127;
if (ImGui::InputScalar("Length##IDutyMacroL",ImGuiDataType_U8,&ins->std.dutyMacro.len,&_ONE,&_THREE)) {
if (ins->std.dutyMacro.len>127) ins->std.dutyMacro.len=127;
}
}
@ -2788,24 +2845,24 @@ void FurnaceGUI::drawInsEdit() {
if (waveMax>0) {
ImGui::Separator();
ImGui::Text("Waveform Macro");
for (int i=0; i<ins->std.waveMacroLen; i++) {
asFloat[i]=ins->std.waveMacro[i];
for (int i=0; i<ins->std.waveMacro.len; i++) {
asFloat[i]=ins->std.waveMacro.val[i];
if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930) {
asInt[i]=ins->std.waveMacro[i]+1;
asInt[i]=ins->std.waveMacro.val[i]+1;
} else {
asInt[i]=ins->std.waveMacro[i];
asInt[i]=ins->std.waveMacro.val[i];
}
loopIndicator[i]=(ins->std.waveMacroLoop!=-1 && i>=ins->std.waveMacroLoop);
loopIndicator[i]=(ins->std.waveMacro.loop!=-1 && i>=ins->std.waveMacro.loop);
}
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f));
ImVec2 areaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale);
if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) {
areaSize=ImVec2(400.0f*dpiScale,waveMax*32.0f*dpiScale);
PlotBitfield("##IWaveMacro",asInt,ins->std.waveMacroLen,0,(ins->type==DIV_INS_C64)?c64ShapeBits:ayShapeBits,waveMax,areaSize);
PlotBitfield("##IWaveMacro",asInt,ins->std.waveMacro.len,0,(ins->type==DIV_INS_C64)?c64ShapeBits:ayShapeBits,waveMax,areaSize);
bitMode=true;
} else {
ImGui::PlotHistogram("##IWaveMacro",asFloat,ins->std.waveMacroLen,0,NULL,0,waveMax,areaSize);
ImGui::PlotHistogram("##IWaveMacro",asFloat,ins->std.waveMacro.len,0,NULL,0,waveMax,areaSize);
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin();
@ -2816,27 +2873,27 @@ void FurnaceGUI::drawInsEdit() {
macroDragBitMode=bitMode;
macroDragInitialValueSet=false;
macroDragInitialValue=false;
macroDragLen=ins->std.waveMacroLen;
macroDragLen=ins->std.waveMacro.len;
macroDragActive=true;
macroDragTarget=ins->std.waveMacro;
macroDragTarget=ins->std.waveMacro.val;
macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
ImGui::PlotHistogram("##IWaveMacroLoop",loopIndicator,ins->std.waveMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
ImGui::PlotHistogram("##IWaveMacro.loop",loopIndicator,ins->std.waveMacro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.waveMacroLen;
macroLoopDragTarget=&ins->std.waveMacroLoop;
macroLoopDragLen=ins->std.waveMacro.len;
macroLoopDragTarget=&ins->std.waveMacro.loop;
macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.waveMacroLoop=-1;
ins->std.waveMacro.loop=-1;
}
ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IWaveMacroL",ImGuiDataType_U8,&ins->std.waveMacroLen,&_ONE,&_THREE)) {
if (ins->std.waveMacroLen>127) ins->std.waveMacroLen=127;
if (ImGui::InputScalar("Length##IWaveMacroL",ImGuiDataType_U8,&ins->std.waveMacro.len,&_ONE,&_THREE)) {
if (ins->std.waveMacro.len>127) ins->std.waveMacro.len=127;
}
}
@ -2848,39 +2905,39 @@ void FurnaceGUI::drawInsEdit() {
} else {
ImGui::Text("Extra 1 Macro");
}
for (int i=0; i<ins->std.ex1MacroLen; i++) {
asFloat[i]=ins->std.ex1Macro[i];
loopIndicator[i]=(ins->std.ex1MacroLoop!=-1 && i>=ins->std.ex1MacroLoop);
for (int i=0; i<ins->std.ex1Macro.len; i++) {
asFloat[i]=ins->std.ex1Macro.val[i];
loopIndicator[i]=(ins->std.ex1Macro.loop!=-1 && i>=ins->std.ex1Macro.loop);
}
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f));
ImGui::PlotHistogram("##IEx1Macro",asFloat,ins->std.ex1MacroLen,0,NULL,0,ex1Max,ImVec2(400.0f*dpiScale,200.0f*dpiScale));
ImGui::PlotHistogram("##IEx1Macro",asFloat,ins->std.ex1Macro.len,0,NULL,0,ex1Max,ImVec2(400.0f*dpiScale,200.0f*dpiScale));
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin();
macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale);
macroDragMin=0;
macroDragMax=ex1Max;
macroDragLen=ins->std.ex1MacroLen;
macroDragLen=ins->std.ex1Macro.len;
macroDragActive=true;
macroDragTarget=ins->std.ex1Macro;
macroDragTarget=ins->std.ex1Macro.val;
macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
ImGui::PlotHistogram("##IEx1MacroLoop",loopIndicator,ins->std.ex1MacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
ImGui::PlotHistogram("##IEx1Macro.loop",loopIndicator,ins->std.ex1Macro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale));
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.ex1MacroLen;
macroLoopDragTarget=&ins->std.ex1MacroLoop;
macroLoopDragLen=ins->std.ex1Macro.len;
macroLoopDragTarget=&ins->std.ex1Macro.loop;
macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.ex1MacroLoop=-1;
ins->std.ex1Macro.loop=-1;
}
ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IEx1MacroL",ImGuiDataType_U8,&ins->std.ex1MacroLen,&_ONE,&_THREE)) {
if (ins->std.ex1MacroLen>127) ins->std.ex1MacroLen=127;
if (ImGui::InputScalar("Length##IEx1MacroL",ImGuiDataType_U8,&ins->std.ex1Macro.len,&_ONE,&_THREE)) {
if (ins->std.ex1Macro.len>127) ins->std.ex1Macro.len=127;
}
}
}

77
src/gui/log.cpp Normal file
View file

@ -0,0 +1,77 @@
#include "gui.h"
#include "../ta-log.h"
#include <imgui.h>
const char* logLevels[5]={
"ERROR",
"warning",
"info",
"debug",
"trace"
};
FurnaceGUIColors logColors[5]={
GUI_COLOR_LOGLEVEL_ERROR,
GUI_COLOR_LOGLEVEL_WARNING,
GUI_COLOR_LOGLEVEL_INFO,
GUI_COLOR_LOGLEVEL_DEBUG,
GUI_COLOR_LOGLEVEL_TRACE
};
void FurnaceGUI::drawLog() {
if (nextWindow==GUI_WINDOW_LOG) {
logOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!logOpen) return;
if (ImGui::Begin("Log Viewer",&logOpen)) {
ImGui::Checkbox("Follow",&followLog);
ImGui::SameLine();
ImGui::Text("Level");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::Combo("##LogLevel",&logLevel,logLevels,5);
if (ImGui::BeginTable("LogView",3,ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersInnerV)) {
ImGui::PushFont(patFont);
float timeChars=ImGui::CalcTextSize("00:00:00").x;
float levelChars=ImGui::CalcTextSize("warning").x;
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,timeChars);
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,levelChars);
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupScrollFreeze(0,1);
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::TextUnformatted("time");
ImGui::TableNextColumn();
ImGui::TextUnformatted("level");
ImGui::TableNextColumn();
ImGui::TextUnformatted("message");
int pos=logPosition;
for (int i=0; i<TA_LOG_SIZE; i++) {
const LogEntry& logEntry=logEntries[(pos+i)&(TA_LOG_SIZE-1)];
if (!logEntry.ready) continue;
if (logLevel<logEntry.loglevel) continue;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%02d:%02d:%02d",logEntry.time.tm_hour,logEntry.time.tm_min,logEntry.time.tm_sec);
ImGui::TableNextColumn();
ImGui::TextColored(uiColors[logColors[logEntry.loglevel]],"%s",logLevels[logEntry.loglevel]);
ImGui::TableNextColumn();
ImGui::TextWrapped("%s",logEntry.text.c_str());
}
ImGui::PopFont();
if (followLog) {
ImGui::SetScrollY(ImGui::GetScrollMaxY());
}
ImGui::EndTable();
}
}
ImGui::End();
}

View file

@ -64,7 +64,7 @@ int MIDIMap::at(const TAMidiMessage& where) {
#define UNDERSTAND_ARRAY_OPTION(x,yMax) if (optionNameS==#x) { \
if (optionIndex<0 || optionIndex>=yMax) { \
logW("MIDI map array option %d out of range (0-%d) at line %d: %s\n",optionIndex,yMax,curLine,line); \
logW("MIDI map array option %d out of range (0-%d) at line %d: %s",optionIndex,yMax,curLine,line); \
break; \
} \
x[optionIndex]=std::stoi(optionValueS); \
@ -76,7 +76,7 @@ bool MIDIMap::read(String path) {
FILE* f=fopen(path.c_str(),"rb");
if (f==NULL) {
if (errno!=ENOENT) {
logE("error while loading MIDI mapping! %s\n",strerror(errno));
logE("error while loading MIDI mapping! %s",strerror(errno));
}
return false;
}
@ -93,7 +93,7 @@ bool MIDIMap::read(String path) {
int result=sscanf(line,"aOption %255s %d %255s",optionName,&optionIndex,optionValue);
if (result!=3) {
logW("MIDI map garbage data at line %d: %s\n",curLine,line);
logW("MIDI map garbage data at line %d: %s",curLine,line);
break;
}
@ -105,12 +105,12 @@ bool MIDIMap::read(String path) {
UNDERSTAND_ARRAY_OPTION(valueInputSpecificMSB,18) else
UNDERSTAND_ARRAY_OPTION(valueInputSpecificLSB,18) else
UNDERSTAND_ARRAY_OPTION(valueInputSpecificSingle,18) else {
logW("MIDI map unknown array option %s at line %d: %s\n",optionName,curLine,line);
logW("MIDI map unknown array option %s at line %d: %s",optionName,curLine,line);
}
} catch (std::out_of_range& e) {
logW("MIDI map invalid value %s for array option %s at line %d: %s\n",optionValue,optionName,curLine,line);
logW("MIDI map invalid value %s for array option %s at line %d: %s",optionValue,optionName,curLine,line);
} catch (std::invalid_argument& e) {
logW("MIDI map invalid value %s for array option %s at line %d: %s\n",optionValue,optionName,curLine,line);
logW("MIDI map invalid value %s for array option %s at line %d: %s",optionValue,optionName,curLine,line);
}
curLine++;
@ -122,7 +122,7 @@ bool MIDIMap::read(String path) {
String optionNameS, optionValueS;
int result=sscanf(line,"option %255s %255s",optionName,optionValue);
if (result!=2) {
logW("MIDI map garbage data at line %d: %s\n",curLine,line);
logW("MIDI map garbage data at line %d: %s",curLine,line);
break;
}
@ -143,12 +143,12 @@ bool MIDIMap::read(String path) {
UNDERSTAND_OPTION(valueInputControlLSB) else
UNDERSTAND_OPTION(valueInputControlSingle) else
UNDERSTAND_FLOAT_OPTION(volExp) else {
logW("MIDI map unknown option %s at line %d: %s\n",optionName,curLine,line);
logW("MIDI map unknown option %s at line %d: %s",optionName,curLine,line);
}
} catch (std::out_of_range& e) {
logW("MIDI map invalid value %s for option %s at line %d: %s\n",optionValue,optionName,curLine,line);
logW("MIDI map invalid value %s for option %s at line %d: %s",optionValue,optionName,curLine,line);
} catch (std::invalid_argument& e) {
logW("MIDI map invalid value %s for option %s at line %d: %s\n",optionValue,optionName,curLine,line);
logW("MIDI map invalid value %s for option %s at line %d: %s",optionValue,optionName,curLine,line);
}
curLine++;
@ -159,7 +159,7 @@ bool MIDIMap::read(String path) {
MIDIBind bind;
int result=sscanf(line,"%d %d %d %d %255s",&bind.type,&bind.channel,&bind.data1,&bind.data2,bindAction);
if (result!=5 || result==EOF) {
logW("MIDI map garbage data at line %d: %s\n",curLine,line);
logW("MIDI map garbage data at line %d: %s",curLine,line);
break;
}
@ -172,7 +172,7 @@ bool MIDIMap::read(String path) {
}
}
if (!foundAction) {
logW("MIDI map unknown action %s at line %d: %s\n",bindAction,curLine,line);
logW("MIDI map unknown action %s at line %d: %s",bindAction,curLine,line);
break;
}
@ -191,7 +191,7 @@ bool MIDIMap::read(String path) {
bool MIDIMap::write(String path) {
FILE* f=fopen(path.c_str(),"wb");
if (f==NULL) {
logE("error while saving MIDI mapping! %s\n",strerror(errno));
logE("error while saving MIDI mapping! %s",strerror(errno));
return false;
}
@ -218,7 +218,7 @@ bool MIDIMap::write(String path) {
for (MIDIBind& i: binds) {
if (fprintf(f,"%d %d %d %d %s\n",i.type,i.channel,i.data1,i.data2,guiActions[i.action].name)<0) {
logW("did not write MIDI mapping entirely! %s\n",strerror(errno));
logW("did not write MIDI mapping entirely! %s",strerror(errno));
break;
}
}
@ -274,6 +274,6 @@ void MIDIMap::compile() {
}
map[i.type-8][i.channel][i.data1][i.data2]=i.action;
logD("MIDI mapping %d %d %d %d to %d\n",i.type-8,i.channel,i.data1,i.data2,i.action);
logD("MIDI mapping %d %d %d %d to %d",i.type-8,i.channel,i.data1,i.data2,i.action);
}
}

View file

@ -102,10 +102,10 @@ void FurnaceGUI::drawOrders() {
e->lockSave([this,i,j]() {
if (changeAllOrders) {
for (int k=0; k<e->getTotalChannelCount(); k++) {
if (e->song.orders.ord[k][i]<0x7f) e->song.orders.ord[k][i]++;
if (e->song.orders.ord[k][i]<0xff) e->song.orders.ord[k][i]++;
}
} else {
if (e->song.orders.ord[j][i]<0x7f) e->song.orders.ord[j][i]++;
if (e->song.orders.ord[j][i]<0xff) e->song.orders.ord[j][i]++;
}
});
e->walkSong(loopOrder,loopRow,loopEnd);

View file

@ -18,6 +18,52 @@
*/
#include "gui.h"
#include "imgui_internal.h"
#include <imgui.h>
#include <math.h>
void FurnaceGUI::readOsc() {
int writePos=e->oscWritePos;
int readPos=e->oscReadPos;
int avail=0;
int total=0;
if (writePos>=readPos) {
avail=writePos-readPos;
} else {
avail=writePos-readPos+32768;
}
if (oscTotal==0) {
oscTotal=ImGui::GetIO().DeltaTime*e->getAudioDescGot().rate;
} else {
oscTotal=(oscTotal+(int)round(ImGui::GetIO().DeltaTime*e->getAudioDescGot().rate))>>1;
}
int bias=avail-oscTotal-e->getAudioDescGot().bufsize;
if (bias<0) bias=0;
total=oscTotal+(bias>>6);
if (total>avail) total=avail;
//printf("total: %d. avail: %d bias: %d\n",total,avail,bias);
for (int i=0; i<512; i++) {
int pos=(readPos+(i*total/512))&0x7fff;
oscValues[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f;
}
float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime;
for (int i=0; i<2; i++) {
peak[i]*=1.0-peakDecay;
if (peak[i]<0.0001) peak[i]=0.0;
float newPeak=peak[i];
for (int j=0; j<total; j++) {
int pos=(readPos+j)&0x7fff;
if (fabs(e->oscBuf[i][pos])>newPeak) {
newPeak=fabs(e->oscBuf[i][pos]);
}
}
peak[i]+=(newPeak-peak[i])*0.9;
}
readPos=(readPos+total)&0x7fff;
e->oscReadPos=readPos;
}
void FurnaceGUI::drawOsc() {
if (nextWindow==GUI_WINDOW_OSCILLOSCOPE) {
@ -27,21 +73,112 @@ void FurnaceGUI::drawOsc() {
}
if (!oscOpen) return;
ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0));
if (ImGui::Begin("Oscilloscope",&oscOpen)) {
float values[512];
for (int i=0; i<512; i++) {
int pos=i*e->oscSize/512;
values[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f;
}
//ImGui::SetCursorPos(ImVec2(0,0));
ImGui::BeginDisabled();
ImGui::PlotLines("##SingleOsc",values,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail());
ImGui::EndDisabled();
if (settings.oscTakesEntireWindow) {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0));
}
if (ImGui::Begin("Oscilloscope",&oscOpen)) {
if (oscZoomSlider) {
if (ImGui::VSliderFloat("##OscZoom",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscZoom,0.5,2.0)) {
if (oscZoom<0.5) oscZoom=0.5;
if (oscZoom>2.0) oscZoom=2.0;
}
ImGui::SameLine();
}
ImDrawList* dl=ImGui::GetWindowDrawList();
ImGuiWindow* window=ImGui::GetCurrentWindow();
ImVec2 waveform[512];
ImVec2 size=ImGui::GetContentRegionAvail();
ImVec2 minArea=window->DC.CursorPos;
ImVec2 maxArea=ImVec2(
minArea.x+size.x,
minArea.y+size.y
);
ImRect rect=ImRect(minArea,maxArea);
ImRect inRect=rect;
inRect.Min.x+=dpiScale;
inRect.Min.y+=dpiScale;
inRect.Max.x-=dpiScale;
inRect.Max.y-=dpiScale;
ImGuiStyle& style=ImGui::GetStyle();
ImU32 color=ImGui::GetColorU32(isClipping?uiColors[GUI_COLOR_OSC_WAVE_PEAK]:uiColors[GUI_COLOR_OSC_WAVE]);
ImU32 borderColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_BORDER]);
ImU32 refColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_REF]);
ImGui::ItemSize(size,style.FramePadding.y);
if (ImGui::ItemAdd(rect,ImGui::GetID("wsDisplay"))) {
// https://github.com/ocornut/imgui/issues/3710
const int v0 = dl->VtxBuffer.Size;
dl->AddRectFilled(inRect.Min,inRect.Max,0xffffffff,settings.oscRoundedCorners?(8.0f*dpiScale):0.0f);
const int v1 = dl->VtxBuffer.Size;
for (int i=v0; i<v1; i++) {
ImDrawVert* v=&dl->VtxBuffer.Data[i];
ImVec4 col0=uiColors[GUI_COLOR_OSC_BG1];
ImVec4 col1=uiColors[GUI_COLOR_OSC_BG3];
ImVec4 col2=uiColors[GUI_COLOR_OSC_BG2];
ImVec4 col3=uiColors[GUI_COLOR_OSC_BG4];
float shadeX=(v->pos.x-rect.Min.x)/(rect.Max.x-rect.Min.x);
float shadeY=(v->pos.y-rect.Min.y)/(rect.Max.y-rect.Min.y);
if (shadeX<0.0f) shadeX=0.0f;
if (shadeX>1.0f) shadeX=1.0f;
if (shadeY<0.0f) shadeY=0.0f;
if (shadeY>1.0f) shadeY=1.0f;
col0.x+=(col2.x-col0.x)*shadeX;
col0.y+=(col2.y-col0.y)*shadeX;
col0.z+=(col2.z-col0.z)*shadeX;
col0.w+=(col2.w-col0.w)*shadeX;
col1.x+=(col3.x-col1.x)*shadeX;
col1.y+=(col3.y-col1.y)*shadeX;
col1.z+=(col3.z-col1.z)*shadeX;
col1.w+=(col3.w-col1.w)*shadeX;
col0.x+=(col1.x-col0.x)*shadeY;
col0.y+=(col1.y-col0.y)*shadeY;
col0.z+=(col1.z-col0.z)*shadeY;
col0.w+=(col1.w-col0.w)*shadeY;
ImVec4 conv=ImGui::ColorConvertU32ToFloat4(v->col);
col0.x*=conv.x;
col0.y*=conv.y;
col0.z*=conv.z;
col0.w*=conv.w;
v->col=ImGui::ColorConvertFloat4ToU32(col0);
}
dl->AddLine(
ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)),
ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)),
refColor,
dpiScale
);
for (size_t i=0; i<512; i++) {
float x=(float)i/512.0f;
float y=oscValues[i]*oscZoom;
if (y<-0.5f) y=-0.5f;
if (y>0.5f) y=0.5f;
waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5f-y));
}
dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale);
if (settings.oscBorder) {
dl->AddRect(inRect.Min,inRect.Max,borderColor,settings.oscRoundedCorners?(8.0f*dpiScale):0.0f,0,1.5f*dpiScale);
}
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
oscZoomSlider=!oscZoomSlider;
}
}
if (settings.oscTakesEntireWindow) {
ImGui::PopStyleVar(3);
}
ImGui::PopStyleVar(3);
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_OSCILLOSCOPE;
ImGui::End();
}
}

View file

@ -17,8 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <SDL_timer.h>
#include <imgui.h>
#define _USE_MATH_DEFINES
#include "gui.h"
#include "../ta-log.h"
@ -284,27 +282,33 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
sprintf(id,"..##PE%d_%d_%d",k,i,j);
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
} else {
sprintf(id,"%.2X##PE%d_%d_%d",pat->data[i][index],k,i,j);
if (pat->data[i][index]<0x10) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[pat->data[i][index]]]);
} else if (pat->data[i][index]<0x20) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]);
} else if (pat->data[i][index]<0x30) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY]);
} else if (pat->data[i][index]<0x48) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]);
} else if (pat->data[i][index]<0x90) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
} else if (pat->data[i][index]<0xa0) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_MISC]);
} else if (pat->data[i][index]<0xc0) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
} else if (pat->data[i][index]<0xd0) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SPEED]);
} else if (pat->data[i][index]<0xe0) {
if (pat->data[i][index]>0xff) {
sprintf(id,"??##PE%d_%d_%d",k,i,j);
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
} else {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[extFxColors[pat->data[i][index]-0xe0]]);
const unsigned char data=pat->data[i][index];
sprintf(id,"%.2X##PE%d_%d_%d",data,k,i,j);
if (data<0x10) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]);
} else if (data<0x20) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]);
} else if (data<0x30) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY]);
} else if (data<0x48) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]);
} else if (data<0x90) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
} else if (data<0xa0) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_MISC]);
} else if (data<0xc0) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
} else if (data<0xd0) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SPEED]);
} else if (data<0xe0) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
} else {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[extFxColors[data-0xe0]]);
}
}
}
ImGui::SameLine(0.0f,0.0f);
@ -870,6 +874,6 @@ void FurnaceGUI::drawPattern() {
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PATTERN;
ImGui::End();
//int delta1=SDL_GetPerformanceCounter();
//logV("render time: %dµs\n",(delta1-delta0)/(SDL_GetPerformanceFrequency()/1000000));
//logV("render time: %dµs",(delta1-delta0)/(SDL_GetPerformanceFrequency()/1000000));
}

View file

@ -589,12 +589,12 @@ void FurnaceGUI::drawSampleEdit() {
sampleTex=NULL;
}
if (avail.x>=1 && avail.y>=1) {
logD("recreating sample texture.\n");
logD("recreating sample texture.");
sampleTex=SDL_CreateTexture(sdlRend,SDL_PIXELFORMAT_ABGR8888,SDL_TEXTUREACCESS_STREAMING,avail.x,avail.y);
sampleTexW=avail.x;
sampleTexH=avail.y;
if (sampleTex==NULL) {
logE("error while creating sample texture! %s\n",SDL_GetError());
logE("error while creating sample texture! %s",SDL_GetError());
} else {
updateSampleTex=true;
}
@ -605,9 +605,9 @@ void FurnaceGUI::drawSampleEdit() {
if (updateSampleTex) {
unsigned int* data=NULL;
int pitch=0;
logD("updating sample texture.\n");
logD("updating sample texture.");
if (SDL_LockTexture(sampleTex,NULL,(void**)&data,&pitch)!=0) {
logE("error while locking sample texture! %s\n",SDL_GetError());
logE("error while locking sample texture! %s",SDL_GetError());
} else {
ImU32 bgColor=ImGui::GetColorU32(ImGuiCol_FrameBg);
ImU32 bgColorLoop=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_FrameBgHovered,0.5));
@ -615,7 +615,7 @@ void FurnaceGUI::drawSampleEdit() {
ImU32 centerLineColor=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_PlotLines,0.25));
for (int i=0; i<availY; i++) {
for (int j=0; j<availX; j++) {
if (sample->loopStart>=0 && sample->loopStart<(int)sample->samples && j-samplePos>sample->loopStart) {
if (sample->loopStart>=0 && sample->loopStart<(int)sample->samples && ((j+samplePos)*sampleZoom)>sample->loopStart) {
data[i*availX+j]=bgColorLoop;
} else {
data[i*availX+j]=bgColor;
@ -880,4 +880,4 @@ void FurnaceGUI::doRedoSample() {
updateSampleTex=true;
}
});
}
}

View file

@ -148,7 +148,9 @@ const char* specificControls[18]={
}
#define UI_COLOR_CONFIG(what,label) \
ImGui::ColorEdit4(label "##CC_" #what,(float*)&uiColors[what]);
if (ImGui::ColorEdit4(label "##CC_" #what,(float*)&uiColors[what])) { \
applyUISettings(false); \
}
#define KEYBIND_CONFIG_BEGIN(id) \
if (ImGui::BeginTable(id,2)) {
@ -384,8 +386,8 @@ void FurnaceGUI::drawSettings() {
TAAudioDesc& audioWant=e->getAudioDescWant();
TAAudioDesc& audioGot=e->getAudioDescGot();
ImGui::Text("want: %d samples @ %.0fHz\n",audioWant.bufsize,audioWant.rate);
ImGui::Text("got: %d samples @ %.0fHz\n",audioGot.bufsize,audioGot.rate);
ImGui::Text("want: %d samples @ %.0fHz",audioWant.bufsize,audioWant.rate);
ImGui::Text("got: %d samples @ %.0fHz",audioGot.bufsize,audioGot.rate);
ImGui::Separator();
@ -894,6 +896,25 @@ void FurnaceGUI::drawSettings() {
ImGui::Separator();
ImGui::Text("Oscilloscope settings:");
bool oscRoundedCornersB=settings.oscRoundedCorners;
if (ImGui::Checkbox("Rounded corners",&oscRoundedCornersB)) {
settings.oscRoundedCorners=oscRoundedCornersB;
}
bool oscTakesEntireWindowB=settings.oscTakesEntireWindow;
if (ImGui::Checkbox("Fill entire window",&oscTakesEntireWindowB)) {
settings.oscTakesEntireWindow=oscTakesEntireWindowB;
}
bool oscBorderB=settings.oscBorder;
if (ImGui::Checkbox("Border",&oscBorderB)) {
settings.oscBorder=oscBorderB;
}
ImGui::Separator();
if (ImGui::TreeNode("Color scheme")) {
if (ImGui::Button("Import")) {
openFileDialog(GUI_FILE_IMPORT_COLORS);
@ -942,6 +963,18 @@ void FurnaceGUI::drawSettings() {
UI_COLOR_CONFIG(GUI_COLOR_FILE_OTHER,"Other");
ImGui::TreePop();
}
if (ImGui::TreeNode("Oscilloscope")) {
UI_COLOR_CONFIG(GUI_COLOR_OSC_BORDER,"Border");
UI_COLOR_CONFIG(GUI_COLOR_OSC_BG1,"Background (top-left)");
UI_COLOR_CONFIG(GUI_COLOR_OSC_BG2,"Background (top-right)");
UI_COLOR_CONFIG(GUI_COLOR_OSC_BG3,"Background (bottom-left)");
UI_COLOR_CONFIG(GUI_COLOR_OSC_BG4,"Background (bottom-right)");
UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE,"Waveform");
UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE_PEAK,"Waveform (clip)");
UI_COLOR_CONFIG(GUI_COLOR_OSC_REF,"Reference");
UI_COLOR_CONFIG(GUI_COLOR_OSC_GUIDE,"Guide");
ImGui::TreePop();
}
if (ImGui::TreeNode("Volume Meter")) {
UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_LOW,"Low");
UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_HIGH,"High");
@ -1041,6 +1074,14 @@ void FurnaceGUI::drawSettings() {
UI_COLOR_CONFIG(GUI_COLOR_EE_VALUE,"External command output");
ImGui::TreePop();
}
if (ImGui::TreeNode("Log Viewer")) {
UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_ERROR,"Log level: Error");
UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_WARNING,"Log level: Warning");
UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_INFO,"Log level: Info");
UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_DEBUG,"Log level: Debug");
UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_TRACE,"Log level: Trace/Verbose");
ImGui::TreePop();
}
ImGui::TreePop();
}
@ -1114,6 +1155,7 @@ void FurnaceGUI::drawSettings() {
UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_NOTES);
UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_CHANNELS);
UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_REGISTER_VIEW);
UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_LOG);
UI_KEYBIND_CONFIG(GUI_ACTION_COLLAPSE_WINDOW);
UI_KEYBIND_CONFIG(GUI_ACTION_CLOSE_WINDOW);
@ -1463,6 +1505,9 @@ void FurnaceGUI::syncSettings() {
settings.titleBarSys=e->getConfInt("titleBarSys",1);
settings.frameBorders=e->getConfInt("frameBorders",0);
settings.effectDeletionAltersValue=e->getConfInt("effectDeletionAltersValue",1);
settings.oscRoundedCorners=e->getConfInt("oscRoundedCorners",1);
settings.oscTakesEntireWindow=e->getConfInt("oscTakesEntireWindow",0);
settings.oscBorder=e->getConfInt("oscBorder",1);
clampSetting(settings.mainFontSize,2,96);
clampSetting(settings.patFontSize,2,96);
@ -1590,6 +1635,9 @@ void FurnaceGUI::commitSettings() {
e->setConf("titleBarSys",settings.titleBarSys);
e->setConf("frameBorders",settings.frameBorders);
e->setConf("effectDeletionAltersValue",settings.effectDeletionAltersValue);
e->setConf("oscRoundedCorners",settings.oscRoundedCorners);
e->setConf("oscTakesEntireWindow",settings.oscTakesEntireWindow);
e->setConf("oscBorder",settings.oscBorder);
// colors
for (int i=0; i<GUI_COLOR_MAX; i++) {
@ -1621,14 +1669,14 @@ void FurnaceGUI::commitSettings() {
ImGui_ImplSDLRenderer_DestroyFontsTexture();
if (!ImGui::GetIO().Fonts->Build()) {
logE("error while building font atlas!\n");
logE("error while building font atlas!");
showError("error while loading fonts! please check your settings.");
ImGui::GetIO().Fonts->Clear();
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
patFont=mainFont;
ImGui_ImplSDLRenderer_DestroyFontsTexture();
if (!ImGui::GetIO().Fonts->Build()) {
logE("error again while building font atlas!\n");
logE("error again while building font atlas!");
}
}
}
@ -1636,7 +1684,7 @@ void FurnaceGUI::commitSettings() {
bool FurnaceGUI::importColors(String path) {
FILE* f=ps_fopen(path.c_str(),"rb");
if (f==NULL) {
logW("error while opening color file for import: %s\n",strerror(errno));
logW("error while opening color file for import: %s",strerror(errno));
return false;
}
resetColors();
@ -1677,22 +1725,23 @@ bool FurnaceGUI::importColors(String path) {
break;
}
}
if (!found) logW("line invalid: %s\n",line);
if (!found) logW("line invalid: %s",line);
}
}
fclose(f);
applyUISettings(false);
return true;
}
bool FurnaceGUI::exportColors(String path) {
FILE* f=ps_fopen(path.c_str(),"wb");
if (f==NULL) {
logW("error while opening color file for export: %s\n",strerror(errno));
logW("error while opening color file for export: %s",strerror(errno));
return false;
}
for (int i=0; i<GUI_COLOR_MAX; i++) {
if (fprintf(f,"%s=%d\n",guiColors[i].name,ImGui::ColorConvertFloat4ToU32(uiColors[i]))<0) {
logW("error while exporting colors: %s\n",strerror(errno));
logW("error while exporting colors: %s",strerror(errno));
break;
}
}
@ -1703,7 +1752,7 @@ bool FurnaceGUI::exportColors(String path) {
bool FurnaceGUI::importKeybinds(String path) {
FILE* f=ps_fopen(path.c_str(),"rb");
if (f==NULL) {
logW("error while opening keybind file for import: %s\n",strerror(errno));
logW("error while opening keybind file for import: %s",strerror(errno));
return false;
}
resetKeybinds();
@ -1744,7 +1793,7 @@ bool FurnaceGUI::importKeybinds(String path) {
break;
}
}
if (!found) logW("line invalid: %s\n",line);
if (!found) logW("line invalid: %s",line);
}
}
fclose(f);
@ -1754,13 +1803,13 @@ bool FurnaceGUI::importKeybinds(String path) {
bool FurnaceGUI::exportKeybinds(String path) {
FILE* f=ps_fopen(path.c_str(),"wb");
if (f==NULL) {
logW("error while opening keybind file for export: %s\n",strerror(errno));
logW("error while opening keybind file for export: %s",strerror(errno));
return false;
}
for (int i=0; i<GUI_ACTION_MAX; i++) {
if (guiActions[i].defaultBind==-1) continue;
if (fprintf(f,"%s=%d\n",guiActions[i].name,actionKeys[i])<0) {
logW("error while exporting keybinds: %s\n",strerror(errno));
logW("error while exporting keybinds: %s",strerror(errno));
break;
}
}
@ -1771,7 +1820,7 @@ bool FurnaceGUI::exportKeybinds(String path) {
bool FurnaceGUI::importLayout(String path) {
FILE* f=ps_fopen(path.c_str(),"rb");
if (f==NULL) {
logW("error while opening keybind file for import: %s\n",strerror(errno));
logW("error while opening keybind file for import: %s",strerror(errno));
return false;
}
if (fseek(f,0,SEEK_END)<0) {
@ -1785,7 +1834,7 @@ bool FurnaceGUI::importLayout(String path) {
}
if (len<1) {
if (len==0) {
logE("that file is empty!\n");
logE("that file is empty!");
lastError="file is empty";
} else {
perror("tell error");
@ -1818,13 +1867,13 @@ bool FurnaceGUI::importLayout(String path) {
bool FurnaceGUI::exportLayout(String path) {
FILE* f=ps_fopen(path.c_str(),"wb");
if (f==NULL) {
logW("error while opening layout file for export: %s\n",strerror(errno));
logW("error while opening layout file for export: %s",strerror(errno));
return false;
}
size_t dataSize=0;
const char* data=ImGui::SaveIniSettingsToMemory(&dataSize);
if (fwrite(data,1,dataSize,f)!=dataSize) {
logW("error while exporting layout: %s\n",strerror(errno));
logW("error while exporting layout: %s",strerror(errno));
}
fclose(f);
return true;
@ -1924,7 +1973,7 @@ void FurnaceGUI::parseKeybinds() {
#define SYSTEM_PAT_FONT_PATH_3 "/usr/share/fonts/ubuntu/UbuntuMono-R.ttf"
#endif
void FurnaceGUI::applyUISettings() {
void FurnaceGUI::applyUISettings(bool updateFonts) {
ImGuiStyle sty;
if (settings.guiColorsBase) {
ImGui::StyleColorsLight(&sty);
@ -1935,8 +1984,10 @@ void FurnaceGUI::applyUISettings() {
if (settings.dpiScale>=0.5f) dpiScale=settings.dpiScale;
// colors
for (int i=0; i<GUI_COLOR_MAX; i++) {
uiColors[i]=ImGui::ColorConvertU32ToFloat4(e->getConfInt(guiColors[i].name,guiColors[i].defaultColor));
if (updateFonts) {
for (int i=0; i<GUI_COLOR_MAX; i++) {
uiColors[i]=ImGui::ColorConvertU32ToFloat4(e->getConfInt(guiColors[i].name,guiColors[i].defaultColor));
}
}
for (int i=0; i<64; i++) {
@ -2064,120 +2115,122 @@ void FurnaceGUI::applyUISettings() {
sysCmd2Grad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
}
// set to 800 for now due to problems with unifont
static const ImWchar upTo800[]={0x20,0x7e,0xa0,0x800,0};
ImFontGlyphRangesBuilder range;
ImVector<ImWchar> outRange;
if (updateFonts) {
// set to 800 for now due to problems with unifont
static const ImWchar upTo800[]={0x20,0x7e,0xa0,0x800,0};
ImFontGlyphRangesBuilder range;
ImVector<ImWchar> outRange;
range.AddRanges(upTo800);
if (settings.loadJapanese) {
range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesJapanese());
}
// I'm terribly sorry
range.UsedChars[0x80>>5]=0;
range.AddRanges(upTo800);
if (settings.loadJapanese) {
range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesJapanese());
}
// I'm terribly sorry
range.UsedChars[0x80>>5]=0;
range.BuildRanges(&outRange);
if (fontRange!=NULL) delete[] fontRange;
fontRange=new ImWchar[outRange.size()];
int index=0;
for (ImWchar& i: outRange) {
fontRange[index++]=i;
}
range.BuildRanges(&outRange);
if (fontRange!=NULL) delete[] fontRange;
fontRange=new ImWchar[outRange.size()];
int index=0;
for (ImWchar& i: outRange) {
fontRange[index++]=i;
}
if (settings.mainFont<0 || settings.mainFont>6) settings.mainFont=0;
if (settings.patFont<0 || settings.patFont>6) settings.patFont=0;
if (settings.mainFont<0 || settings.mainFont>6) settings.mainFont=0;
if (settings.patFont<0 || settings.patFont>6) settings.patFont=0;
if (settings.mainFont==6 && settings.mainFontPath.empty()) {
logW("UI font path is empty! reverting to default font\n");
settings.mainFont=0;
}
if (settings.patFont==6 && settings.patFontPath.empty()) {
logW("pattern font path is empty! reverting to default font\n");
settings.patFont=0;
}
ImFontConfig fc1;
fc1.MergeMode=true;
if (settings.mainFont==6) { // custom font
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logW("could not load UI font! reverting to default font\n");
if (settings.mainFont==6 && settings.mainFontPath.empty()) {
logW("UI font path is empty! reverting to default font");
settings.mainFont=0;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.\n");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
} else if (settings.mainFont==5) { // system font
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logW("could not load UI font! reverting to default font\n");
settings.mainFont=0;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.\n");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
if (settings.patFont==6 && settings.patFontPath.empty()) {
logW("pattern font path is empty! reverting to default font");
settings.patFont=0;
}
ImFontConfig fc1;
fc1.MergeMode=true;
if (settings.mainFont==6) { // custom font
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logW("could not load UI font! reverting to default font");
settings.mainFont=0;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
} else {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.\n");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
// two fallback fonts
mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_liberationSans_compressed_data,font_liberationSans_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange);
mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_unifont_compressed_data,font_unifont_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange);
ImFontConfig fc;
fc.MergeMode=true;
fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale;
static const ImWchar fontRangeIcon[]={ICON_MIN_FA,ICON_MAX_FA,0};
if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) {
logE("could not load icon font!\n");
}
if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) {
logD("using main font for pat font.\n");
patFont=mainFont;
} else {
if (settings.patFont==6) { // custom font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logW("could not load pattern font! reverting to default font\n");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.\n");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
} else if (settings.patFont==5) { // system font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logW("could not load pattern font! reverting to default font\n");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.\n");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
} else if (settings.mainFont==5) { // system font
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logW("could not load UI font! reverting to default font");
settings.mainFont=0;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
}
} else {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font!\n");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) {
logE("could not load big UI font!\n");
}
}
mainFont->FallbackChar='?';
mainFont->DotChar='.';
// two fallback fonts
mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_liberationSans_compressed_data,font_liberationSans_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange);
mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_unifont_compressed_data,font_unifont_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange);
ImFontConfig fc;
fc.MergeMode=true;
fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale;
static const ImWchar fontRangeIcon[]={ICON_MIN_FA,ICON_MAX_FA,0};
if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) {
logE("could not load icon font!");
}
if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) {
logD("using main font for pat font.");
patFont=mainFont;
} else {
if (settings.patFont==6) { // custom font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logW("could not load pattern font! reverting to default font");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
} else if (settings.patFont==5) { // system font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logW("could not load pattern font! reverting to default font");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
}
} else {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font!");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) {
logE("could not load big UI font!");
}
mainFont->FallbackChar='?';
mainFont->DotChar='.';
}
// TODO: allow changing these colors.
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir,"",uiColors[GUI_COLOR_FILE_DIR],ICON_FA_FOLDER_O);
@ -2203,6 +2256,8 @@ void FurnaceGUI::applyUISettings() {
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
if (fileDialog!=NULL) delete fileDialog;
fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog);
if (updateFonts) {
if (fileDialog!=NULL) delete fileDialog;
fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog);
}
}

View file

@ -122,7 +122,7 @@ void FurnaceGUI::drawSongInfo() {
int ordLen=e->song.ordersLen;
if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED
if (ordLen<1) ordLen=1;
if (ordLen>127) ordLen=127;
if (ordLen>256) ordLen=256;
e->song.ordersLen=ordLen;
if (e->getOrder()>=ordLen) {
e->setOrder(ordLen-1);

View file

@ -284,7 +284,7 @@ void FurnaceGUI::drawSysConf(int i) {
}
sysPal=flags&1;
if (ImGui::Checkbox("PAL",&sysPal)) {
e->setSysFlags(i,(flags&(~1))|sysPal,restart);
e->setSysFlags(i,(flags&(~1))|(unsigned int)sysPal,restart);
updateWindowTitle();
}
bool bypassLimits=flags&4;
@ -372,6 +372,11 @@ void FurnaceGUI::drawSysConf(int i) {
e->setSysFlags(i,(flags & ~(7 << 4)) | (((initialChannelLimit-1) & 7) << 4),restart);
updateWindowTitle();
} rightClickable
bool n163Multiplex=flags&128;
if (ImGui::Checkbox("Disable hissing",&n163Multiplex)) {
e->setSysFlags(i,(flags&(~128))|(n163Multiplex<<7),restart);
updateWindowTitle();
}
break;
}
case DIV_SYSTEM_GB:
@ -395,4 +400,4 @@ void FurnaceGUI::drawSysConf(int i) {
}
break;
}
}
}

View file

@ -49,17 +49,9 @@ void FurnaceGUI::drawVolMeter() {
ImGuiStyle& style=ImGui::GetStyle();
ImGui::ItemSize(ImVec2(4.0f,4.0f),style.FramePadding.y);
ImU32 lowColor=ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_LOW]);
float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime;
if (ImGui::ItemAdd(rect,ImGui::GetID("volMeter"))) {
ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding);
for (int i=0; i<2; i++) {
peak[i]*=1.0-peakDecay;
if (peak[i]<0.0001) peak[i]=0.0;
for (int j=0; j<e->oscSize; j++) {
if (fabs(e->oscBuf[i][j])>peak[i]) {
peak[i]=fabs(e->oscBuf[i][j]);
}
}
float logPeak=(20*log10(peak[i])/36.0);
if (logPeak==NAN) logPeak=0.0;
if (logPeak<-1.0) logPeak=-1.0;

View file

@ -17,12 +17,16 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// TODO: improve these routines to allow logging to memory for eventual log window!
#include "ta-log.h"
int logLevel=LOGLEVEL_INFO;
std::atomic<unsigned short> logPosition;
LogEntry logEntries[TA_LOG_SIZE];
static constexpr unsigned int TA_LOG_MASK=TA_LOG_SIZE-1;
int logV(const char* format, ...) {
va_list va;
int ret;
@ -55,21 +59,6 @@ int logD(const char* format, ...) {
return ret;
}
int logI(const char* format, ...) {
va_list va;
int ret;
if (logLevel<LOGLEVEL_INFO) return 0;
#ifdef _WIN32
printf("[info] ");
#else
printf("\x1b[1;32m[info]\x1b[m ");
#endif
va_start(va,format);
ret=vprintf(format,va);
va_end(va);
return ret;
}
int logW(const char* format, ...) {
va_list va;
int ret;
@ -100,3 +89,48 @@ int logE(const char* format, ...) {
return ret;
}
int writeLog(int level, const char* msg, fmt::printf_args& args) {
time_t thisMakesNoSense=time(NULL);
int pos=logPosition;
logPosition=(logPosition+1)&TA_LOG_MASK;
logEntries[pos].text=fmt::vsprintf(msg,args);
// why do I have to pass a pointer
// can't I just pass the time_t directly?!
#ifdef _WIN32
struct tm* tempTM=localtime(&thisMakesNoSense);
if (tempTM==NULL) {
memset(&logEntries[pos].time,0,sizeof(struct tm));
} else {
memcpy(&logEntries[pos].time,tempTM,sizeof(struct tm));
}
#else
if (localtime_r(&thisMakesNoSense,&logEntries[pos].time)==NULL) {
memset(&logEntries[pos].time,0,sizeof(struct tm));
}
#endif
logEntries[pos].loglevel=level;
logEntries[pos].ready=true;
if (logLevel<level) return 0;
switch (level) {
case LOGLEVEL_ERROR:
return fmt::printf("\x1b[1;31m[ERROR]\x1b[m %s\n",logEntries[pos].text);
case LOGLEVEL_WARN:
return fmt::printf("\x1b[1;33m[warning]\x1b[m %s\n",logEntries[pos].text);
case LOGLEVEL_INFO:
return fmt::printf("\x1b[1;32m[info]\x1b[m %s\n",logEntries[pos].text);
case LOGLEVEL_DEBUG:
return fmt::printf("\x1b[1;34m[debug]\x1b[m %s\n",logEntries[pos].text);
case LOGLEVEL_TRACE:
return fmt::printf("\x1b[1;37m[trace]\x1b[m %s\n",logEntries[pos].text);
}
return -1;
}
void initLog() {
logPosition=0;
for (int i=0; i<TA_LOG_SIZE; i++) {
logEntries[i].text.reserve(128);
}
}

View file

@ -75,7 +75,7 @@ bool pHelp(String) {
bool pAudio(String val) {
if (outName!="") {
logE("can't use -audio and -output at the same time.\n");
logE("can't use -audio and -output at the same time.");
return false;
}
if (val=="jack") {
@ -83,7 +83,7 @@ bool pAudio(String val) {
} else if (val=="sdl") {
e.setAudio(DIV_AUDIO_SDL);
} else {
logE("invalid value for audio engine! valid values are: jack, sdl.\n");
logE("invalid value for audio engine! valid values are: jack, sdl.");
return false;
}
return true;
@ -97,7 +97,7 @@ bool pView(String val) {
} else if (val=="nothing") {
e.setView(DIV_STATUS_NOTHING);
} else {
logE("invalid value for view type! valid values are: pattern, commands, nothing.\n");
logE("invalid value for view type! valid values are: pattern, commands, nothing.");
return false;
}
return true;
@ -120,7 +120,7 @@ bool pLogLevel(String val) {
} else if (val=="error") {
logLevel=LOGLEVEL_ERROR;
} else {
logE("invalid value for loglevel! valid values are: trace, debug, info, warning, error.\n");
logE("invalid value for loglevel! valid values are: trace, debug, info, warning, error.");
return false;
}
return true;
@ -181,7 +181,7 @@ bool pLoops(String val) {
loops=count+1;
}
} catch (std::exception& e) {
logE("loop count shall be a number.\n");
logE("loop count shall be a number.");
return false;
}
return true;
@ -195,7 +195,7 @@ bool pOutMode(String val) {
} else if (val=="perchan") {
outMode=DIV_EXPORT_MODE_MANY_CHAN;
} else {
logE("invalid value for outmode! valid values are: one, persys and perchan.\n");
logE("invalid value for outmode! valid values are: one, persys and perchan.");
return false;
}
return true;
@ -240,6 +240,7 @@ void initParams() {
}
int main(int argc, char** argv) {
initLog();
#if !(defined(__APPLE__) || defined(_WIN32))
// workaround for Wayland HiDPI issue
if (getenv("SDL_VIDEODRIVER")==NULL) {
@ -270,7 +271,7 @@ int main(int argc, char** argv) {
val=argv[i+1];
i++;
} else {
logE("incomplete param %s.\n",arg.c_str());
logE("incomplete param %s.",arg.c_str());
return 1;
}
}
@ -307,12 +308,12 @@ int main(int argc, char** argv) {
#endif
if (fileName.empty() && consoleMode) {
logI("usage: %s file\n",argv[0]);
logI("usage: %s file",argv[0]);
return 1;
}
logI("Furnace version " DIV_VERSION ".\n");
logI("Furnace version " DIV_VERSION ".");
if (!fileName.empty()) {
logI("loading module...\n");
logI("loading module...");
FILE* f=ps_fopen(fileName.c_str(),"rb");
if (f==NULL) {
perror("error");
@ -353,12 +354,12 @@ int main(int argc, char** argv) {
}
fclose(f);
if (!e.load(file,(size_t)len)) {
logE("could not open file!\n");
logE("could not open file!");
return 1;
}
}
if (!e.init()) {
logE("could not initialize engine!\n");
logE("could not initialize engine!");
if (consoleMode) {
return 1;
} else {
@ -374,12 +375,12 @@ int main(int argc, char** argv) {
fwrite(w->getFinalBuf(),1,w->size(),f);
fclose(f);
} else {
logE("could not open file! %s\n",strerror(errno));
logE("could not open file! %s",strerror(errno));
}
w->finish();
delete w;
} else {
logE("could not write VGM!\n");
logE("could not write VGM!");
}
}
if (outName!="") {
@ -391,7 +392,7 @@ int main(int argc, char** argv) {
}
if (consoleMode) {
logI("playing...\n");
logI("playing...");
e.play();
#ifdef HAVE_GUI
SDL_Event ev;
@ -417,7 +418,7 @@ int main(int argc, char** argv) {
if (!g.init()) return 1;
if (displayEngineFailError) {
logE("displaying engine fail error.\n");
logE("displaying engine fail error.");
g.showError("error while initializing audio!");
}
@ -426,13 +427,13 @@ int main(int argc, char** argv) {
}
g.loop();
logI("closing GUI.\n");
logI("closing GUI.");
g.finish();
#else
logE("GUI requested but GUI not compiled!\n");
logE("GUI requested but GUI not compiled!");
#endif
logI("stopping engine.\n");
logI("stopping engine.");
e.quit();
return 0;
}

View file

@ -21,6 +21,10 @@
#define _TA_LOG_H
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <atomic>
#include <string>
#include <fmt/printf.h>
#define LOGLEVEL_ERROR 0
#define LOGLEVEL_WARN 1
@ -28,11 +32,51 @@
#define LOGLEVEL_DEBUG 3
#define LOGLEVEL_TRACE 4
// this has to be a power of 2
#define TA_LOG_SIZE 2048
extern int logLevel;
int logV(const char* format, ...);
int logD(const char* format, ...);
int logI(const char* format, ...);
int logW(const char* format, ...);
int logE(const char* format, ...);
extern std::atomic<unsigned short> logPosition;
struct LogEntry {
int loglevel;
struct tm time;
std::string text;
bool ready;
LogEntry():
loglevel(0),
ready(false) {}
};
int writeLog(int level, const char* msg, fmt::printf_args& args);
extern LogEntry logEntries[TA_LOG_SIZE];
template<typename... T> int logV(const char* msg, const T&... args) {
fmt::printf_args a=fmt::make_printf_args(args...);
return writeLog(LOGLEVEL_TRACE,msg,a);
}
template<typename... T> int logD(const char* msg, const T&... args) {
fmt::printf_args a=fmt::make_printf_args(args...);
return writeLog(LOGLEVEL_DEBUG,msg,a);
}
template<typename... T> int logI(const char* msg, const T&... args) {
fmt::printf_args a=fmt::make_printf_args(args...);
return writeLog(LOGLEVEL_INFO,msg,a);
}
template<typename... T> int logW(const char* msg, const T&... args) {
fmt::printf_args a=fmt::make_printf_args(args...);
return writeLog(LOGLEVEL_WARN,msg,a);
}
template<typename... T> int logE(const char* msg, const T&... args) {
fmt::printf_args a=fmt::make_printf_args(args...);
return writeLog(LOGLEVEL_ERROR,msg,a);
}
void initLog();
#endif