Compare commits
6 commits
saxotone
...
kurumitsu-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ff7439627 | ||
|
|
33fa17ff46 | ||
|
|
cf4d72dd7c | ||
|
|
1755e5b371 | ||
|
|
8817ebbac3 | ||
|
|
3831bc249c |
17 changed files with 903 additions and 56 deletions
|
|
@ -815,6 +815,7 @@ src/engine/platform/bifurcator.cpp
|
|||
src/engine/platform/sid2.cpp
|
||||
src/engine/platform/sid3.cpp
|
||||
src/engine/platform/multipcm.cpp
|
||||
src/engine/platform/kurumitsu8l.cpp
|
||||
src/engine/platform/pcmdac.cpp
|
||||
src/engine/platform/dummy.cpp
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
#include "platform/sid2.h"
|
||||
#include "platform/sid3.h"
|
||||
#include "platform/multipcm.h"
|
||||
#include "platform/kurumitsu8l.h"
|
||||
#include "platform/dummy.h"
|
||||
#include "../ta-log.h"
|
||||
#include "song.h"
|
||||
|
|
@ -791,6 +792,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_MULTIPCM:
|
||||
dispatch=new DivPlatformMultiPCM;
|
||||
break;
|
||||
case DIV_SYSTEM_KURUMITSU_8L:
|
||||
dispatch=new DivPlatformKurumitsu8L;
|
||||
break;
|
||||
case DIV_SYSTEM_DUMMY:
|
||||
dispatch=new DivPlatformDummy;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -583,7 +583,7 @@ class DivEngine {
|
|||
void processRow(int i, bool afterDelay);
|
||||
void nextOrder();
|
||||
void nextRow();
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES, int rateCorrection);
|
||||
void performVGMWrite(SafeWriter* w, int disIdx, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES, int rateCorrection);
|
||||
// returns true if end of song.
|
||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ enum DivROMExportOptions {
|
|||
DIV_ROM_SAP_R,
|
||||
DIV_ROM_IPOD,
|
||||
DIV_ROM_GRUB,
|
||||
DIV_ROM_KMM,
|
||||
|
||||
DIV_ROM_MAX
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1444,6 +1444,8 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
|
|||
break;
|
||||
case DIV_INS_UPD1771C:
|
||||
break;
|
||||
case DIV_INS_KURUMITSU_8L:
|
||||
break;
|
||||
case DIV_INS_MAX:
|
||||
break;
|
||||
case DIV_INS_NULL:
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ enum DivInstrumentType: unsigned short {
|
|||
DIV_INS_SUPERVISION=64,
|
||||
DIV_INS_UPD1771C=65,
|
||||
DIV_INS_SID3=66,
|
||||
DIV_INS_KURUMITSU_8L=67,
|
||||
DIV_INS_MAX,
|
||||
DIV_INS_NULL
|
||||
};
|
||||
|
|
|
|||
660
src/engine/platform/kurumitsu8l.cpp
Normal file
660
src/engine/platform/kurumitsu8l.cpp
Normal file
|
|
@ -0,0 +1,660 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "kurumitsu8l.h"
|
||||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#define chRead(c,a) regPool[(c)*32+(a)]
|
||||
#define chWrite(c,a,v) if (!skipRegisterWrites) {regPool[(c)*32+(a)]=v; if (dumpWrites) {addWrite((c)*32+(a),v);} }
|
||||
#define chDWrite(c,a,v) regPool[(c)*32+(a)]=v;
|
||||
|
||||
#define CHIP_FREQBASE 67108864
|
||||
|
||||
const char* regCheatSheetKurumitsu8L[]={
|
||||
"CHxWPtr", "00+x*20",
|
||||
"CHxSPtr", "04+x*20",
|
||||
"CHxVol", "09+x*20",
|
||||
"CHxModF", "0A+x*20",
|
||||
"CHxModI", "0B+x*20",
|
||||
"CHxPanL", "0C+x*20",
|
||||
"CHxPanR", "0E+x*20",
|
||||
"CHxLoopE", "10+x*20",
|
||||
"CHxLoopL", "12+x*20",
|
||||
"CHxFreq", "14+x*20",
|
||||
"CHxAcc", "18+x*20",
|
||||
"CHxOut", "1C+x*20",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char** DivPlatformKurumitsu8L::getRegisterSheet() {
|
||||
return regCheatSheetKurumitsu8L;
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::acquire(short** buf, size_t len) {
|
||||
// channel diagram:
|
||||
// .---[ModF]-------+-[PanL]-> DryL
|
||||
// V |
|
||||
// [Freq]->(+)->[Wave]-[Env]-+-[PanR]-> DryR
|
||||
// ^ |
|
||||
// Wet ---[ModI]---' '--------> Wet
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->begin(len);
|
||||
}
|
||||
|
||||
for (size_t h=0; h<len; h++) {
|
||||
int outAL=0;
|
||||
int outAR=0;
|
||||
int modData=0;
|
||||
for (int i=0; i<8; i++) {
|
||||
unsigned char vol=chRead(i,9);
|
||||
unsigned char fb=chRead(i,10);
|
||||
unsigned char mod=chRead(i,11);
|
||||
short panL=chRead(i,12)|((short)chRead(i,13)<<8);
|
||||
short panR=chRead(i,14)|((short)chRead(i,15)<<8);
|
||||
unsigned freq=chRead(i,20)|((unsigned)chRead(i,21)<<8)|((unsigned)chRead(i,22)<<16)|((unsigned)chRead(i,23)<<24);
|
||||
unsigned phase=chRead(i,24)|((unsigned)chRead(i,25)<<8)|((unsigned)chRead(i,26)<<16)|((unsigned)chRead(i,27)<<24);
|
||||
unsigned loopE=chRead(i,18)|((unsigned)chRead(i,19)<<8);
|
||||
short fbData1=chRead(i,28)|((short)chRead(i,29)<<8);
|
||||
short fbData2=chRead(i,30)|((short)chRead(i,31)<<8);
|
||||
|
||||
int data=0;
|
||||
int phase_inc=(((int)fbData1+fbData2)*fb)+((modData*mod)<<3);
|
||||
if (loopE==0) {
|
||||
// wavetable, does stable phasemod
|
||||
data=wtMem[i][((phase+phase_inc)>>16)&255];
|
||||
phase+=freq;
|
||||
} else {
|
||||
// samples, does unstable pitchmod
|
||||
unsigned base=chRead(i,4)|((unsigned)chRead(i,5)<<8)|((unsigned)chRead(i,6)<<16)|((unsigned)chRead(i,7)<<24);
|
||||
unsigned loopL=chRead(i,16)|((unsigned)chRead(i,17)<<8);
|
||||
data=sampleMem[base+(phase>>16)];
|
||||
phase_inc=(phase_inc>>9)+freq;
|
||||
// ROM symphony prevention
|
||||
if (phase_inc<0) phase_inc=0;
|
||||
if ((unsigned)phase_inc>(loopL<<16)) phase_inc=loopL<<16;
|
||||
int64_t newPhase=phase+phase_inc;
|
||||
if (newPhase>=0x100000000LL || newPhase>=(loopE<<16)) {
|
||||
newPhase-=loopL<<16;
|
||||
}
|
||||
phase=newPhase;
|
||||
}
|
||||
int out=data*vol; // 16 bits
|
||||
fbData2=fbData1;
|
||||
fbData1=out;
|
||||
modData=out;
|
||||
outAL+=out*panL; // 29 bits
|
||||
outAR+=out*panR;
|
||||
oscBuf[i]->putSample(h,(out*((int)abs(panL)+abs(panR)))>>15);
|
||||
|
||||
chDWrite(i,24,phase&0xff);
|
||||
chDWrite(i,25,(phase>>8)&0xff);
|
||||
chDWrite(i,26,(phase>>16)&0xff);
|
||||
chDWrite(i,27,(phase>>24)&0xff);
|
||||
chDWrite(i,28,fbData1&0xff);
|
||||
chDWrite(i,29,(fbData1>>8)&0xff);
|
||||
chDWrite(i,30,fbData2&0xff);
|
||||
chDWrite(i,31,(fbData2>>24)&0xff);
|
||||
} // 32 bits
|
||||
buf[0][h]=outAL>>16; // 16 bits
|
||||
buf[1][h]=outAR>>16;
|
||||
}
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->end(len);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::updateWave(int ch) {
|
||||
for (int i=0; i<256; i++) {
|
||||
wtMem[ch][i]=chan[ch].ws.output[i]^128;
|
||||
}
|
||||
if (!skipRegisterWrites && dumpWrites) {
|
||||
addWrite(0x10000+ch*256,256);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::writePan(int ch) {
|
||||
if (!isMuted[ch] && chan[ch].active) {
|
||||
int valL=chan[ch].panL*chan[ch].vol*(chan[ch].invertL?-1:1)/8;
|
||||
int valR=chan[ch].panR*chan[ch].vol*(chan[ch].invertR?-1:1)/8;
|
||||
chWrite(ch,12,valL&0xff);
|
||||
chWrite(ch,13,valL>>8);
|
||||
chWrite(ch,14,valR&0xff);
|
||||
chWrite(ch,15,valR>>8);
|
||||
} else {
|
||||
chWrite(ch,12,0);
|
||||
chWrite(ch,13,0);
|
||||
chWrite(ch,14,0);
|
||||
chWrite(ch,15,0);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::tick(bool sysTick) {
|
||||
for (int i=0; i<8; i++) {
|
||||
bool panChanged=false;
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=chan[i].std.vol.val*(chan[i].isAmiga?4:1);
|
||||
if (chan[i].outVol>255) chan[i].outVol=255;
|
||||
if (!isMuted[i] && chan[i].active) {
|
||||
chWrite(i,9,chan[i].outVol);
|
||||
}
|
||||
}
|
||||
if (NEW_ARP_STRAT) {
|
||||
chan[i].handleArp();
|
||||
} else if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].panL=chan[i].std.panL.val;
|
||||
panChanged=true;
|
||||
}
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[i].panR=chan[i].std.panR.val;
|
||||
panChanged=true;
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
chan[i].pitch2+=chan[i].std.pitch.val;
|
||||
CLAMP_VAR(chan[i].pitch2,-1048575,1048575);
|
||||
} else {
|
||||
chan[i].pitch2=chan[i].std.pitch.val;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1 && chan[i].active) {
|
||||
if (chan[i].pcm) {
|
||||
chan[i].audPos=0;
|
||||
chan[i].setPos=true;
|
||||
} else {
|
||||
chWrite(i,24,0);
|
||||
chWrite(i,25,0);
|
||||
chWrite(i,26,0);
|
||||
chWrite(i,27,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
chWrite(i,10,chan[i].std.ex1.val);
|
||||
}
|
||||
if (chan[i].std.ex2.had) {
|
||||
chWrite(i,11,chan[i].std.ex2.val);
|
||||
}
|
||||
if (chan[i].std.ex3.had) {
|
||||
chan[i].invertL=chan[i].std.ex3.val&2;
|
||||
chan[i].invertR=chan[i].std.ex3.val&1;
|
||||
panChanged=true;
|
||||
}
|
||||
if (chan[i].setPos) {
|
||||
// force keyon
|
||||
chan[i].keyOn=true;
|
||||
chan[i].setPos=false;
|
||||
} else {
|
||||
chan[i].audPos=0;
|
||||
}
|
||||
if (chan[i].active) {
|
||||
if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1)) {
|
||||
updateWave(i);
|
||||
}
|
||||
}
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE);
|
||||
if (chan[i].pcm) {
|
||||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
double off=(s->centerRate>=1)?((double)s->centerRate/parent->getCenterRate()):1.0;
|
||||
chan[i].freq*=off/16.;
|
||||
}
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
if (chan[i].freq>8388608) chan[i].freq=8388608;
|
||||
chWrite(i,20,chan[i].freq&0xff);
|
||||
chWrite(i,21,(chan[i].freq>>8)&0xff);
|
||||
chWrite(i,22,(chan[i].freq>>16)&0xff);
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
if (!chan[i].std.vol.had) {
|
||||
chan[i].outVol=255;
|
||||
}
|
||||
if (!isMuted[i] && chan[i].active) {
|
||||
chWrite(i,9,chan[i].outVol);
|
||||
} else {
|
||||
chWrite(i,9,0);
|
||||
}
|
||||
panChanged=true;
|
||||
if (chan[i].keyOn) {
|
||||
chan[i].keyOn=false;
|
||||
if (chan[i].pcm) {
|
||||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
unsigned int start, loopEnd, loopLength;
|
||||
start=sampleOff[chan[i].sample];
|
||||
if (s->isLoopable()) {
|
||||
loopEnd=s->loopEnd;
|
||||
loopLength=s->loopEnd-s->loopStart;
|
||||
} else {
|
||||
loopEnd=s->samples+16;
|
||||
loopLength=16;
|
||||
}
|
||||
if (loopEnd>65535) loopEnd=65535;
|
||||
chWrite(i,4,start&0xff);
|
||||
chWrite(i,5,(start>>8)&0xff);
|
||||
chWrite(i,6,(start>>16)&0xff);
|
||||
chWrite(i,16,loopLength&0xff);
|
||||
chWrite(i,17,(loopLength>>8)&0xff);
|
||||
chWrite(i,18,loopEnd&0xff);
|
||||
chWrite(i,19,(loopEnd>>8)&0xff);
|
||||
chWrite(i,24,0);
|
||||
chWrite(i,25,0);
|
||||
chWrite(i,26,chan[i].audPos);
|
||||
chWrite(i,27,(chan[i].audPos>>8)&0xff);
|
||||
} else {
|
||||
chWrite(i,18,0);
|
||||
chWrite(i,19,0);
|
||||
}
|
||||
}
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
}
|
||||
if (panChanged) writePan(i);
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformKurumitsu8L::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
chan[c.chan].isAmiga=ins->type==DIV_INS_AMIGA;
|
||||
chan[c.chan].pcm=ins->type==DIV_INS_AMIGA || ins->amiga.useSample;
|
||||
if (chan[c.chan].pcm && c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
} else {
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
}
|
||||
chan[c.chan].ws.init(ins,256,255,chan[c.chan].insChanged);
|
||||
}
|
||||
if (!chan[c.chan].pcm || chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].sample=-1;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=255;
|
||||
if (!isMuted[c.chan] && chan[c.chan].active) {
|
||||
chWrite(c.chan,9,chan[c.chan].outVol);
|
||||
}
|
||||
}
|
||||
chan[c.chan].insChanged=false;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].sample=-1;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
if (chan[c.chan].ins!=c.value || c.value2==1) {
|
||||
chan[c.chan].ins=c.value;
|
||||
chan[c.chan].insChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_VOLUME:
|
||||
if (chan[c.chan].vol!=c.value) {
|
||||
chan[c.chan].vol=c.value;
|
||||
writePan(c.chan);
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_GET_VOLUME:
|
||||
return chan[c.chan].vol;
|
||||
break;
|
||||
case DIV_CMD_SNES_INVERT:
|
||||
chan[c.chan].invertL=(c.value>>4);
|
||||
chan[c.chan].invertR=c.value&15;
|
||||
writePan(c.chan);
|
||||
break;
|
||||
case DIV_CMD_PITCH:
|
||||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_WAVE:
|
||||
chan[c.chan].wave=c.value;
|
||||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
chan[c.chan].keyOn=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch==2)?1:8);
|
||||
if (chan[c.chan].baseFreq>=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch==2)?1:8);
|
||||
if (chan[c.chan].baseFreq<=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].freqChanged=true;
|
||||
if (return2) {
|
||||
chan[c.chan].inPorta=false;
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].panL=c.value;
|
||||
chan[c.chan].panR=c.value2;
|
||||
writePan(c.chan);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
|
||||
}
|
||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_POS:
|
||||
chan[c.chan].audPos=c.value;
|
||||
chan[c.chan].setPos=true;
|
||||
break;
|
||||
case DIV_CMD_FM_FB: {
|
||||
chWrite(c.chan,10,c.value);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_PM_DEPTH: {
|
||||
chWrite(c.chan,11,c.value);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 255;
|
||||
break;
|
||||
case DIV_CMD_MACRO_OFF:
|
||||
chan[c.chan].std.mask(c.value,true);
|
||||
break;
|
||||
case DIV_CMD_MACRO_ON:
|
||||
chan[c.chan].std.mask(c.value,false);
|
||||
break;
|
||||
case DIV_CMD_MACRO_RESTART:
|
||||
chan[c.chan].std.restart(c.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (!mute && chan[ch].active) {
|
||||
chWrite(ch,9,chan[ch].outVol);
|
||||
writePan(ch);
|
||||
} else {
|
||||
chWrite(ch,9,0);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::forceIns() {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
chan[i].audPos=0;
|
||||
chan[i].sample=-1;
|
||||
updateWave(i);
|
||||
writePan(i);
|
||||
}
|
||||
}
|
||||
|
||||
void* DivPlatformKurumitsu8L::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformKurumitsu8L::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
unsigned short DivPlatformKurumitsu8L::getPan(int ch) {
|
||||
short panL=abs(chRead(ch,12)|((short)chRead(ch,13)<<8));
|
||||
short panR=abs(chRead(ch,14)|((short)chRead(ch,15)<<8));
|
||||
return ((panL/128)<<8)|(panR/128);
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::getPaired(int ch, std::vector<DivChannelPair>& ret) {
|
||||
if (ch==0) return;
|
||||
unsigned char mod=chRead(ch,11);
|
||||
if (mod!=0) {
|
||||
sprintf(modLabel[ch],"%d",mod);
|
||||
ret.push_back(DivChannelPair(modLabel[ch],ch-1));
|
||||
}
|
||||
}
|
||||
|
||||
DivSamplePos DivPlatformKurumitsu8L::getSamplePos(int ch) {
|
||||
if (!chan[ch].pcm || chan[ch].sample<0 ||
|
||||
chan[ch].sample>=parent->song.sampleLen || !chan[ch].active
|
||||
) {
|
||||
return DivSamplePos();
|
||||
}
|
||||
return DivSamplePos(
|
||||
chan[ch].sample,
|
||||
(((int)regPool[0x7a]|((int)regPool[0x7b]<<8)|((int)regPool[0x73]<<16)))-sampleOff[chan[ch].sample],
|
||||
(int64_t)chan[ch].freq*rate/0x10000
|
||||
);
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformKurumitsu8L::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformKurumitsu8L::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
||||
int DivPlatformKurumitsu8L::getRegisterPoolSize() {
|
||||
return 32*8;
|
||||
}
|
||||
|
||||
const void* DivPlatformKurumitsu8L::getSampleMem(int index) {
|
||||
if (index == 0) return sampleMem;
|
||||
if (index == 1) return wtMem;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t DivPlatformKurumitsu8L::getSampleMemCapacity(int index) {
|
||||
return index == 0 ? 16777216 : 0;
|
||||
}
|
||||
|
||||
size_t DivPlatformKurumitsu8L::getSampleMemUsage(int index) {
|
||||
return index == 0 ? sampleMemLen : 0;
|
||||
}
|
||||
|
||||
bool DivPlatformKurumitsu8L::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
const DivMemoryComposition* DivPlatformKurumitsu8L::getMemCompo(int index) {
|
||||
switch (index) {
|
||||
case 0: return &romMemCompo;
|
||||
case 1: return &wtMemCompo;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::renderSamples(int sysID) {
|
||||
int maxPos=getSampleMemCapacity();
|
||||
memset(sampleMem,0,maxPos);
|
||||
romMemCompo.entries.clear();
|
||||
romMemCompo.capacity=maxPos;
|
||||
|
||||
int memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOff[i]=0;
|
||||
continue;
|
||||
}
|
||||
if (memPos>=maxPos) {
|
||||
logW("out of Kurumitsu-8L PCM memory for sample %d!",i);
|
||||
break;
|
||||
}
|
||||
int length=s->isLoopable()?s->loopEnd:s->samples;
|
||||
int actualLength=length;
|
||||
// if it's one-shot, add 16 silent samples for looping area
|
||||
// this should be enough for most cases even though the
|
||||
// frequency register can make position jump by up to 256 samples
|
||||
int oneShotLength=length;
|
||||
if (!s->isLoopable()) actualLength+=16;
|
||||
if (actualLength>65535) actualLength=65535;
|
||||
if (actualLength>(maxPos-memPos)) actualLength=maxPos-memPos;
|
||||
if (!s->isLoopable()) oneShotLength=actualLength-16;
|
||||
sampleOff[i]=memPos;
|
||||
memcpy(&sampleMem[memPos],s->data8,oneShotLength);
|
||||
memPos+=actualLength;
|
||||
romMemCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_SAMPLE,"PCM",i,sampleOff[i],memPos));
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleMemLen=memPos;
|
||||
romMemCompo.used=sampleMemLen;
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::reset() {
|
||||
memset(regPool,0,sizeof(regPool));
|
||||
memset(wtMem,0,sizeof(wtMem));
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i]=DivPlatformKurumitsu8L::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
chan[i].ws.setEngine(parent);
|
||||
chan[i].ws.init(NULL,256,255,false);
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformKurumitsu8L::getOutputCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool DivPlatformKurumitsu8L::keyOffAffectsArp(int ch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::notifyWaveChange(int wave) {
|
||||
for (int i=0; i<8; i++) {
|
||||
if (chan[i].wave==wave) {
|
||||
chan[i].ws.changeWave1(wave);
|
||||
updateWave(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::setFlags(const DivConfig& flags) {
|
||||
chipClock=3072000;
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/64;
|
||||
for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->setRate(rate);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::poke(unsigned int addr, unsigned short val) {
|
||||
if (addr < (unsigned int)getRegisterPoolSize()) chWrite(addr/32,addr%32,val);
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::poke(std::vector<DivRegWrite>& wlist) {
|
||||
for (DivRegWrite& i: wlist) {
|
||||
if (i.addr < (unsigned int)getRegisterPoolSize()) chWrite(i.addr/32,i.addr%32,i.val);
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformKurumitsu8L::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
memset(modLabel,0,sizeof(modLabel));
|
||||
for (int i=0; i<8; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
sampleMem=new signed char[getSampleMemCapacity()];
|
||||
sampleMemLen=0;
|
||||
romMemCompo=DivMemoryComposition();
|
||||
romMemCompo.name="Sample ROM";
|
||||
wtMemCompo=DivMemoryComposition();
|
||||
wtMemCompo.name="Wavetable RAM";
|
||||
wtMemCompo.capacity=256*8;
|
||||
wtMemCompo.memory=(unsigned char*)wtMem;
|
||||
wtMemCompo.waveformView=DIV_MEMORY_WAVE_8BIT_SIGNED;
|
||||
wtMemCompo.used=256*8;
|
||||
wtMemCompo.entries.clear();
|
||||
for (int i=0; i<8; i++) {
|
||||
wtMemCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_WAVE_RAM, fmt::sprintf("Channel %d",i+1),-1,i*256,i*256+256));
|
||||
}
|
||||
setFlags(flags);
|
||||
reset();
|
||||
return 8;
|
||||
}
|
||||
|
||||
void DivPlatformKurumitsu8L::quit() {
|
||||
for (int i=0; i<8; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformKurumitsu8L::~DivPlatformKurumitsu8L() {
|
||||
}
|
||||
99
src/engine/platform/kurumitsu8l.h
Normal file
99
src/engine/platform/kurumitsu8l.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _KURUMITSU_8L_H
|
||||
#define _KURUMITSU_8L_H
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include "../../fixedQueue.h"
|
||||
#include "../waveSynth.h"
|
||||
|
||||
class DivPlatformKurumitsu8L: public DivDispatch {
|
||||
struct Channel: public SharedChannel<int> {
|
||||
unsigned char panL, panR;
|
||||
unsigned int audPos;
|
||||
int sample, wave;
|
||||
bool invertL, invertR;
|
||||
bool pcm, setPos, isAmiga;
|
||||
DivWaveSynth ws;
|
||||
Channel():
|
||||
SharedChannel<int>(255),
|
||||
panL(255),
|
||||
panR(255),
|
||||
audPos(0),
|
||||
sample(-1),
|
||||
wave(-1),
|
||||
invertL(false),
|
||||
invertR(false),
|
||||
pcm(false),
|
||||
setPos(false),
|
||||
isAmiga(false) {}
|
||||
};
|
||||
Channel chan[8];
|
||||
DivDispatchOscBuffer* oscBuf[8];
|
||||
bool isMuted[8];
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
|
||||
unsigned char regPool[8*32];
|
||||
signed char wtMem[8][256];
|
||||
char modLabel[8][4];
|
||||
signed char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
DivMemoryComposition romMemCompo;
|
||||
DivMemoryComposition wtMemCompo;
|
||||
void updateWave(int ch);
|
||||
void writePan(int ch);
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
void acquire(short** buf, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
unsigned short getPan(int chan);
|
||||
void getPaired(int ch, std::vector<DivChannelPair>& ret);
|
||||
DivSamplePos getSamplePos(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
int getOutputCount();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void setFlags(const DivConfig& flags);
|
||||
void notifyWaveChange(int wave);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const void* getSampleMem(int index = 0);
|
||||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
const DivMemoryComposition* getMemCompo(int index);
|
||||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
~DivPlatformKurumitsu8L();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -146,6 +146,7 @@ enum DivSystem {
|
|||
DIV_SYSTEM_UPD1771C,
|
||||
DIV_SYSTEM_SID3,
|
||||
DIV_SYSTEM_C64_PCM,
|
||||
DIV_SYSTEM_KURUMITSU_8L,
|
||||
|
||||
DIV_SYSTEM_MAX
|
||||
};
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ const char* DivEngine::getChannelName(int chan) {
|
|||
if (chan<0 || chan>chans) return "??";
|
||||
if (!curSubSong->chanName[chan].empty()) return curSubSong->chanName[chan].c_str();
|
||||
if (sysDefs[sysOfChan[chan]]==NULL) return "??";
|
||||
|
||||
|
||||
const char* ret=sysDefs[sysOfChan[chan]]->chanNames[dispatchChanOfChan[chan]];
|
||||
if (ret==NULL) return "??";
|
||||
return ret;
|
||||
|
|
@ -324,7 +324,7 @@ const char* DivEngine::getChannelShortName(int chan) {
|
|||
if (chan<0 || chan>chans) return "??";
|
||||
if (!curSubSong->chanShortName[chan].empty()) return curSubSong->chanShortName[chan].c_str();
|
||||
if (sysDefs[sysOfChan[chan]]==NULL) return "??";
|
||||
|
||||
|
||||
const char* ret=sysDefs[sysOfChan[chan]]->chanShortNames[dispatchChanOfChan[chan]];
|
||||
if (ret==NULL) return "??";
|
||||
return ret;
|
||||
|
|
@ -2174,7 +2174,7 @@ void DivEngine::registerSystems() {
|
|||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_ESFM]=new DivSysDef(
|
||||
_("ESS ES1xxx series (ESFM)"), NULL, 0xd1, 0, 18, true, false, 0, false, 0, 0, 0,
|
||||
_("ESS ES1xxx series (ESFM)"), NULL, 0xd1, 0, 18, true, false, 0, false, 0, 0, 0,
|
||||
_("a unique FM synth featured in PC sound cards.\nbased on the OPL3 design, but with lots of its features extended."),
|
||||
{_("FM 1"), _("FM 2"), _("FM 3"), _("FM 4"), _("FM 5"), _("FM 6"), _("FM 7"), _("FM 8"), _("FM 9"), _("FM 10"), _("FM 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("FM 16"), _("FM 17"), _("FM 18")},
|
||||
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"},
|
||||
|
|
@ -2186,9 +2186,9 @@ void DivEngine::registerSystems() {
|
|||
},
|
||||
fmESFMPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
||||
sysDefs[DIV_SYSTEM_POWERNOISE]=new DivSysDef(
|
||||
_("PowerNoise"), NULL, 0xd4, 0, 4, false, false, 0, false, 0, 0, 0,
|
||||
_("PowerNoise"), NULL, 0xd4, 0, 4, false, false, 0, false, 0, 0, 0,
|
||||
_("a fantasy sound chip designed by jvsTSX and The Beesh-Spweesh!\nused in the Hexheld fantasy console."),
|
||||
{_("Noise 1"), _("Noise 2"), _("Noise 3"), _("Slope")},
|
||||
{"N1", "N2", "N3", "SL"},
|
||||
|
|
@ -2222,7 +2222,7 @@ void DivEngine::registerSystems() {
|
|||
{0x16, {DIV_CMD_DAVE_CLOCK_DIV, _("16xx: Set clock divider (0: /2; 1: /3)")}},
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
sysDefs[DIV_SYSTEM_GBA_DMA]=new DivSysDef(
|
||||
_("Game Boy Advance DMA Sound"), NULL, 0xd7, 0, 2, false, true, 0, false, 1U<<DIV_SAMPLE_DEPTH_8BIT, 0, 256,
|
||||
_("additional PCM FIFO channels in Game Boy Advance driven directly by its DMA hardware."),
|
||||
|
|
@ -2305,7 +2305,7 @@ void DivEngine::registerSystems() {
|
|||
}
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_SID2]=new DivSysDef(
|
||||
sysDefs[DIV_SYSTEM_SID2]=new DivSysDef(
|
||||
_("SID2"), NULL, 0xf0, 0, 3, false, true, 0, false, 0, 0, 0,
|
||||
_("a fantasy sound chip created by LTVA. it is similar to the SID chip, but with many of its problems fixed."),
|
||||
{_("Channel 1"), _("Channel 2"), _("Channel 3")},
|
||||
|
|
@ -2313,11 +2313,11 @@ void DivEngine::registerSystems() {
|
|||
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
|
||||
{DIV_INS_SID2, DIV_INS_SID2, DIV_INS_SID2},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
SID2PostEffectHandlerMap
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_SID3]=new DivSysDef(
|
||||
sysDefs[DIV_SYSTEM_SID3]=new DivSysDef(
|
||||
_("SID3"), NULL, 0xf5, 0, 7, false, true, 0, false, (1U<<DIV_SAMPLE_DEPTH_8BIT)|(1U<<DIV_SAMPLE_DEPTH_16BIT), 256, 256,
|
||||
_("a fantasy sound chip created by LTVA. it is a big rework of SID chip with probably too many features added on top."),
|
||||
{_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Wave")},
|
||||
|
|
@ -2325,7 +2325,7 @@ void DivEngine::registerSystems() {
|
|||
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_WAVE},
|
||||
{DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
SID3PostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
|
@ -2350,6 +2350,22 @@ void DivEngine::registerSystems() {
|
|||
{DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_KURUMITSU_8L]=new DivSysDef(
|
||||
_("Kurumitsu-8L"), NULL, 0xfe, 0, 8, false, true, 0x151, false, 1U<<DIV_SAMPLE_DEPTH_8BIT, 256, 256,
|
||||
_(":zrobilusmiech:"),
|
||||
{_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Channel 7"), _("Channel 8")},
|
||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
|
||||
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
|
||||
{DIV_INS_KURUMITSU_8L, DIV_INS_KURUMITSU_8L, DIV_INS_KURUMITSU_8L, DIV_INS_KURUMITSU_8L, DIV_INS_KURUMITSU_8L, DIV_INS_KURUMITSU_8L, DIV_INS_KURUMITSU_8L, DIV_INS_KURUMITSU_8L},
|
||||
{},
|
||||
{
|
||||
{0x10, {DIV_CMD_WAVE, _("10xx: Set waveform")}},
|
||||
{0x11, {DIV_CMD_FM_FB, _("11xx: Set feedback")}},
|
||||
{0x12, {DIV_CMD_FM_PM_DEPTH, _("12xx: Set modulation")}},
|
||||
{0x14, {DIV_CMD_SNES_INVERT, _("14xy: Toggle invert (x: left; y: right)")}},
|
||||
}
|
||||
);
|
||||
|
||||
for (int i=0; i<DIV_MAX_CHIP_DEFS; i++) {
|
||||
if (sysDefs[i]==NULL) continue;
|
||||
if (sysDefs[i]->id!=0) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
// this function is so long
|
||||
// may as well make it something else
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES, int rateCorrection) {
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, int disIdx, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES, int rateCorrection) {
|
||||
unsigned char baseAddr1=isSecond?0xa0:0x50;
|
||||
unsigned char baseAddr2=isSecond?0x80:0;
|
||||
unsigned short baseAddr2S=isSecond?0x8000:0;
|
||||
|
|
@ -226,7 +226,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(0x28);
|
||||
w->writeC(5+i);
|
||||
}
|
||||
|
||||
|
||||
// reset AY
|
||||
w->writeC(8|baseAddr1);
|
||||
w->writeC(7);
|
||||
|
|
@ -970,7 +970,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
} else {
|
||||
w->writeC(baseAddr2|(write.addr&0xff));
|
||||
}
|
||||
|
||||
|
||||
w->writeC(write.val);
|
||||
break;
|
||||
case DIV_SYSTEM_YM2151:
|
||||
|
|
@ -1236,6 +1236,23 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(baseAddr2|(write.addr&0x7f));
|
||||
w->writeC(write.val);
|
||||
break;
|
||||
case DIV_SYSTEM_KURUMITSU_8L: // HACK
|
||||
if (write.addr>=0x10000) {
|
||||
// wavetable writes
|
||||
const signed char* wtMem=(const signed char*)disCont[disIdx].dispatch->getSampleMem(1);
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0xc0);
|
||||
w->writeI(write.val+2);
|
||||
w->writeS(write.addr&0xffff);
|
||||
w->write(&wtMem[write.addr&0xffff],write.val);
|
||||
} else {
|
||||
// register writes
|
||||
w->writeC(0xa0);
|
||||
w->writeC(write.addr&0xff);
|
||||
w->writeC(write.val);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logW("write not handled!");
|
||||
break;
|
||||
|
|
@ -1419,7 +1436,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
DivDispatch* writeNES[2]={NULL,NULL};
|
||||
DivDispatch* writePCM_OPL4[2]={NULL,NULL};
|
||||
DivDispatch* writeMultiPCM[2]={NULL,NULL};
|
||||
|
||||
|
||||
int writeNESIndex[2]={0,0};
|
||||
|
||||
size_t bankOffsetNESCurrent=0;
|
||||
|
|
@ -2054,6 +2071,14 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
howManyChips++;
|
||||
}
|
||||
break;
|
||||
// HACK
|
||||
case DIV_SYSTEM_KURUMITSU_8L:
|
||||
if (!hasAY) {
|
||||
hasAY=disCont[i].dispatch->chipClock|0x40000000;
|
||||
willExport[i]=true;
|
||||
writeSegaPCM[0]=disCont[i].dispatch;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -2140,7 +2165,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
w->writeC(0); // loop count
|
||||
// 1.51
|
||||
w->writeC(0); // loop modifier
|
||||
|
||||
|
||||
if (version>=0x161) {
|
||||
w->writeI(hasGB);
|
||||
w->writeI(hasNES);
|
||||
|
|
@ -2905,7 +2930,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
lastOne=i.second.time;
|
||||
}
|
||||
// write write
|
||||
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream,sampleStoppable,dpcm07,writeNES,correctedRate);
|
||||
performVGMWrite(w,i.first,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream,sampleStoppable,dpcm07,writeNES,correctedRate);
|
||||
writeCount++;
|
||||
}
|
||||
sortedWrites.clear();
|
||||
|
|
|
|||
|
|
@ -373,6 +373,7 @@ enum FurnaceGUIColors {
|
|||
GUI_COLOR_INSTR_SUPERVISION,
|
||||
GUI_COLOR_INSTR_UPD1771C,
|
||||
GUI_COLOR_INSTR_SID3,
|
||||
GUI_COLOR_INSTR_KURUMITSU_8L,
|
||||
GUI_COLOR_INSTR_UNKNOWN,
|
||||
|
||||
GUI_COLOR_CHANNEL_BG,
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ const char* insTypes[DIV_INS_MAX+1][3]={
|
|||
{"Watara Supervision",ICON_FA_GAMEPAD,ICON_FUR_INS_SUPERVISION},
|
||||
{"NEC μPD1771C",ICON_FA_BAR_CHART,ICON_FUR_INS_UPD1771C},
|
||||
{"SID3",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID3},
|
||||
{"Kurumitsu-8L",ICON_FA_CALCULATOR,ICON_FA_QUESTION},
|
||||
{NULL,ICON_FA_QUESTION,ICON_FA_QUESTION}
|
||||
};
|
||||
|
||||
|
|
@ -248,7 +249,7 @@ const char* chanNames[CHANNEL_TYPE_MAX+1]={
|
|||
_N("Square"),
|
||||
_N("Triangle"), // NES
|
||||
_N("Saw"), // VRC6
|
||||
_N("Ext. Operator"),
|
||||
_N("Ext. Operator"),
|
||||
_N("Drums"),
|
||||
_N("Slope"), // PowerNoise
|
||||
_N("Wave"), // not wavetable (VERA, 5E01)
|
||||
|
|
@ -1069,6 +1070,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
D(GUI_COLOR_INSTR_SUPERVISION,"",ImVec4(0.52f,1.0f,0.6f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_UPD1771C,"",ImVec4(0.94f,0.52f,0.6f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_SID3,"",ImVec4(0.6f,0.75f,0.6f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_KURUMITSU_8L,"",ImVec4(0.9f,0.3f,0.3f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)),
|
||||
|
|
@ -1331,6 +1333,7 @@ const int availableSystems[]={
|
|||
DIV_SYSTEM_UPD1771C,
|
||||
DIV_SYSTEM_SID3,
|
||||
DIV_SYSTEM_MULTIPCM,
|
||||
DIV_SYSTEM_KURUMITSU_8L,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
|
|
@ -1404,6 +1407,7 @@ const int chipsWave[]={
|
|||
DIV_SYSTEM_NAMCO,
|
||||
DIV_SYSTEM_NAMCO_15XX,
|
||||
DIV_SYSTEM_NAMCO_CUS30,
|
||||
DIV_SYSTEM_KURUMITSU_8L,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1146,14 +1146,14 @@ WaveFunc waveFuncsIns[]={
|
|||
quartSin,
|
||||
squiSin,
|
||||
squiAbsSin,
|
||||
|
||||
|
||||
rectSaw,
|
||||
absSaw,
|
||||
|
||||
|
||||
cubSaw,
|
||||
rectCubSaw,
|
||||
absCubSaw,
|
||||
|
||||
|
||||
cubSine,
|
||||
rectCubSin,
|
||||
absCubSin,
|
||||
|
|
@ -1934,7 +1934,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s
|
|||
ImGui::ItemSize(size,style.FramePadding.y);
|
||||
if (ImGui::ItemAdd(rect,ImGui::GetID("gbEnv"))) {
|
||||
ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding);
|
||||
|
||||
|
||||
float volY=1.0-((float)vol/15.0);
|
||||
float lenPos=(sLen>62)?1.0:((float)sLen/384.0);
|
||||
float envEndPoint=((float)len/7.0)*((float)(dir?(15-vol):vol)/15.0);
|
||||
|
|
@ -2450,7 +2450,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(_("Release"));
|
||||
|
|
@ -2757,7 +2757,7 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros, FurnaceGUI
|
|||
ImGui::TableNextColumn();
|
||||
|
||||
if (++curColumn>=columns) curColumn=0;
|
||||
|
||||
|
||||
float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace;
|
||||
int totalFit=i.macro->len;
|
||||
if (totalFit<1) totalFit=1;
|
||||
|
|
@ -3459,7 +3459,8 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) {
|
|||
ins->type==DIV_INS_SU ||
|
||||
ins->type==DIV_INS_NDS ||
|
||||
ins->type==DIV_INS_SUPERVISION ||
|
||||
ins->type==DIV_INS_SID3) {
|
||||
ins->type==DIV_INS_SID3 ||
|
||||
ins->type==DIV_INS_KURUMITSU_8L) {
|
||||
P(ImGui::Checkbox(_("Use sample"),&ins->amiga.useSample));
|
||||
if (ins->type==DIV_INS_X1_010) {
|
||||
if (ImGui::InputInt(_("Sample bank slot##BANKSLOT"),&ins->x1_010.bankSlot,1,4)) { PARAMETER
|
||||
|
|
@ -4110,7 +4111,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
if (ImGui::Button(_("Request from TX81Z"))) {
|
||||
doAction(GUI_ACTION_TX81Z_REQUEST);
|
||||
}
|
||||
/*
|
||||
/*
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Send to TX81Z")) {
|
||||
showError("Coming soon!");
|
||||
|
|
@ -5128,7 +5129,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
}
|
||||
|
||||
ImGui::SetCursorPos(prevCurPos);
|
||||
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
switch (ins->type) {
|
||||
case DIV_INS_FM: {
|
||||
|
|
@ -5145,7 +5146,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,_(ssgEnvTypes[ssgEnv]))) { PARAMETER
|
||||
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
|
||||
}
|
||||
|
||||
|
||||
// params
|
||||
ImGui::Separator();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
|
@ -5219,7 +5220,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
if (ImGui::Checkbox(FM_NAME(FM_EGS),&ssgOn)) { PARAMETER
|
||||
op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3);
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
|
|
@ -5265,11 +5266,11 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER
|
||||
op.sus=susOn;
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
pushWarningColor(ins->type==DIV_INS_OPL_DRUMS && i==0);
|
||||
pushWarningColor(ins->type==DIV_INS_OPL_DRUMS && i==0);
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
|
||||
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
|
||||
|
|
@ -5314,7 +5315,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
if (block>7) block=7;
|
||||
op.dt=block;
|
||||
}
|
||||
|
||||
|
||||
ImGui::Text(_("Freq"));
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPos(ImVec2(cursorAlign.x,ImGui::GetCursorPosY()));
|
||||
|
|
@ -5871,7 +5872,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
ImGui::Separator();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Separator();
|
||||
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
|
@ -5953,7 +5954,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
} else {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
pushWarningColor(ins->type==DIV_INS_OPL_DRUMS && i==0);
|
||||
pushWarningColor(ins->type==DIV_INS_OPL_DRUMS && i==0);
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(CWSliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
if (ins->type==DIV_INS_OPL_DRUMS && i==0) {
|
||||
|
|
@ -5965,7 +5966,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_MULT));
|
||||
}
|
||||
|
||||
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
||||
if (!(ins->type==DIV_INS_OPZ && op.egt)) {
|
||||
int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7];
|
||||
|
|
@ -6275,7 +6276,7 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) {
|
|||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
|
||||
if (!ins->sid3.doWavetable) {
|
||||
strncpy(buffer,macroSID3WaveMixMode(0,(float)ins->sid3.mixMode,NULL).c_str(),40);
|
||||
P(CWSliderScalar(_("Wave Mix Mode"),ImGuiDataType_U8,&ins->sid3.mixMode,&_ZERO,&_FOUR,buffer));
|
||||
|
|
@ -6764,7 +6765,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (ImGui::BeginTabBar("insEditTab")) {
|
||||
std::vector<FurnaceGUIMacroDesc> macroList;
|
||||
|
|
@ -6926,7 +6927,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc(_("Op. Pitch"),&ins->std.opMacros[ordi].susMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode,NULL,false,NULL,false,NULL,false,true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DR),&ins->std.opMacros[ordi].drMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_D2R),&ins->std.opMacros[ordi].d2rMacro,0,31,64,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
|
||||
|
|
@ -7284,7 +7285,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
P(ImGui::Checkbox(_("Enable filter"),&ins->c64.toFilter));
|
||||
P(ImGui::Checkbox(_("Initialize filter"),&ins->c64.initFilter));
|
||||
|
||||
|
||||
if (ins->type==DIV_INS_SID2) {
|
||||
P(CWSliderScalar(_("Cutoff"),ImGuiDataType_U16,&ins->c64.cut,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE)); rightClickable
|
||||
P(CWSliderScalar(_("Resonance"),ImGuiDataType_U8,&ins->c64.res,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
|
||||
|
|
@ -7769,7 +7770,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
|
||||
ImGui::InhibitInertialScroll();
|
||||
}
|
||||
|
||||
|
||||
if (ImGui::Button(modTableHex?"Hex##MTHex":"Dec##MTHex")) {
|
||||
modTableHex=!modTableHex;
|
||||
}
|
||||
|
|
@ -8060,7 +8061,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ins->type==DIV_INS_SNES ||
|
||||
ins->type==DIV_INS_NAMCO ||
|
||||
ins->type==DIV_INS_SM8521 ||
|
||||
(ins->type==DIV_INS_GBA_MINMOD && ins->amiga.useWave))
|
||||
(ins->type==DIV_INS_GBA_MINMOD && ins->amiga.useWave) ||
|
||||
ins->type==DIV_INS_KURUMITSU_8L)
|
||||
{
|
||||
insTabWavetable(ins);
|
||||
}
|
||||
|
|
@ -8719,7 +8721,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc(_("Ring Mod Source"),&ins->std.fmsMacro,0,SID3_NUM_CHANNELS,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Hard Sync Source"),&ins->std.amsMacro,0,SID3_NUM_CHANNELS - 1,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Phase Mod Source"),&ins->std.fbMacro,0,SID3_NUM_CHANNELS - 1,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan));
|
||||
|
||||
|
||||
if (!ins->sid3.doWavetable) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Feedback"),&ins->std.opMacros[3].arMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
}
|
||||
|
|
@ -8745,6 +8747,18 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc(_("Sample Mode"),&ins->std.opMacros[1].arMacro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true));
|
||||
}
|
||||
break;
|
||||
case DIV_INS_KURUMITSU_8L:
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Envelope"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Feedback"),&ins->std.ex1Macro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,NULL));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Modulation"),&ins->std.ex2Macro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,NULL));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Special"),&ins->std.ex3Macro,0,2,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,minModModeBits));
|
||||
break;
|
||||
case DIV_INS_MAX:
|
||||
case DIV_INS_NULL:
|
||||
break;
|
||||
|
|
@ -8792,7 +8806,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ins->type==DIV_INS_PCE ||
|
||||
ins->type==DIV_INS_X1_010 ||
|
||||
ins->type==DIV_INS_SWAN ||
|
||||
ins->type==DIV_INS_VRC6) {
|
||||
ins->type==DIV_INS_VRC6 ||
|
||||
ins->type==DIV_INS_KURUMITSU_8L) {
|
||||
insTabSample(ins);
|
||||
}
|
||||
if (ins->type>=DIV_INS_MAX) {
|
||||
|
|
@ -8934,7 +8949,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3784,6 +3784,11 @@ void FurnaceGUI::initSystemPresets() {
|
|||
CH(DIV_SYSTEM_X1_010, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
ENTRY(
|
||||
_("Kurumitsu-8L"), {
|
||||
CH(DIV_SYSTEM_KURUMITSU_8L, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
CATEGORY_END;
|
||||
|
||||
CATEGORY_BEGIN(_("Specialized"),_("chips/systems with unique sound synthesis methods."));
|
||||
|
|
|
|||
|
|
@ -580,6 +580,17 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
SAMPLE_WARN(warnLength,_("MultiPCM: maximum sample length is 65535"));
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_KURUMITSU_8L:
|
||||
if (sample->isLoopable()) {
|
||||
if (sample->samples>65535) {
|
||||
SAMPLE_WARN(warnLength,"Kurumitsu-8L: maximum sample length is 65535");
|
||||
}
|
||||
} else {
|
||||
if (sample->samples>65519) {
|
||||
SAMPLE_WARN(warnLength,"Kurumitsu-8L: maximum sample length is 65519");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -669,7 +680,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::Text(_("Chips"));
|
||||
}
|
||||
|
||||
|
||||
if (sampleInfo) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
|
@ -774,7 +785,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sample->centerRate=targetRate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(_("Note"));
|
||||
ImGui::SameLine();
|
||||
|
|
@ -1053,7 +1064,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
|
|
@ -2125,7 +2136,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
start^=end;
|
||||
}
|
||||
ImVec2 p1=rectMin;
|
||||
p1.x+=(e->getSamplePreviewPos()-samplePos)/sampleZoom;
|
||||
p1.x+=(e->getSamplePreviewPos()-samplePos)/sampleZoom;
|
||||
ImVec4 posColor=uiColors[GUI_COLOR_SAMPLE_NEEDLE];
|
||||
ImVec4 posTrail1=posColor;
|
||||
ImVec4 posTrail2=posColor;
|
||||
|
|
@ -2163,7 +2174,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
start^=end;
|
||||
}
|
||||
ImVec2 p1=rectMin;
|
||||
p1.x+=(chanPos.pos-samplePos)/sampleZoom;
|
||||
p1.x+=(chanPos.pos-samplePos)/sampleZoom;
|
||||
ImVec4 posColor=uiColors[GUI_COLOR_SAMPLE_NEEDLE_PLAYING];
|
||||
ImVec4 posTrail1=posColor;
|
||||
ImVec4 posTrail2=posColor;
|
||||
|
|
@ -2427,7 +2438,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT && sampleDragMode) {
|
||||
statusBar=_("Non-8/16-bit samples cannot be edited without prior conversion.");
|
||||
}
|
||||
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY()+ImGui::GetStyle().ScrollbarSize);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0,0));
|
||||
if (ImGui::BeginTable("SEStatus",3,ImGuiTableFlags_BordersInnerV)) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
|
||||
switch (type) {
|
||||
case DIV_SYSTEM_YM2612:
|
||||
case DIV_SYSTEM_YM2612_EXT:
|
||||
case DIV_SYSTEM_YM2612_EXT:
|
||||
case DIV_SYSTEM_YM2612_DUALPCM:
|
||||
case DIV_SYSTEM_YM2612_DUALPCM_EXT:
|
||||
case DIV_SYSTEM_YM2612_CSM: {
|
||||
|
|
@ -108,7 +108,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
if (interruptSimCycles>256) interruptSimCycles=256;
|
||||
altered=true;
|
||||
} rightClickable
|
||||
|
||||
|
||||
if (altered) {
|
||||
e->lockSave([&]() {
|
||||
flags.set("clockSel",clockSel);
|
||||
|
|
@ -761,7 +761,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
altered=true;
|
||||
}
|
||||
popWarningColor();
|
||||
|
||||
|
||||
ImGui::Text(_("- 0 disables envelope reset. not recommended!\n- 1 may trigger SID envelope bugs.\n- values that are too high may result in notes being skipped."));
|
||||
|
||||
if (ImGui::Checkbox(_("Disable 1Exy env update (compatibility)"),&no1EUpdate)) {
|
||||
|
|
@ -1591,7 +1591,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
altered=true;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
|
||||
|
||||
int chipClock=flags.getInt("customClock",0);
|
||||
if (!chipClock) {
|
||||
switch (clockSel) {
|
||||
|
|
@ -2044,7 +2044,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
if (ImGui::Checkbox(_("Enable echo"),&echo)) {
|
||||
altered=true;
|
||||
}
|
||||
|
||||
|
||||
ImGui::Text(_("Initial echo state:"));
|
||||
for (int i=0; i<8; i++) {
|
||||
bool echoChan=(bool)(echoMask&(1<<i));
|
||||
|
|
@ -2221,7 +2221,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
altered=true;
|
||||
} rightClickable
|
||||
}
|
||||
|
||||
|
||||
ImGui::Text(_("Initial part volume (channel 1-4):"));
|
||||
for (int i=0; i<4; i++) {
|
||||
snprintf(temp,63,"%d'##GRPV%d",2<<i,i);
|
||||
|
|
@ -2729,6 +2729,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
case DIV_SYSTEM_POWERNOISE:
|
||||
case DIV_SYSTEM_UPD1771C:
|
||||
case DIV_SYSTEM_MULTIPCM:
|
||||
case DIV_SYSTEM_KURUMITSU_8L:
|
||||
break;
|
||||
case DIV_SYSTEM_YMU759:
|
||||
case DIV_SYSTEM_ESFM:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue