mirror of
https://github.com/tildearrow/furnace.git
synced 2024-12-18 14:30:15 +00:00
parent
0c1e2ddcb0
commit
5bd076d13e
9 changed files with 162 additions and 72 deletions
|
@ -579,6 +579,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
wave->data[j]=reader.readI();
|
||||
}
|
||||
wave->data[j]&=wave->max;
|
||||
}
|
||||
// #FDS4Bit
|
||||
if (ds.system[0]==DIV_SYSTEM_NES_FDS && ds.version<0x1a) {
|
||||
|
|
|
@ -516,7 +516,7 @@ struct DivInstrumentWaveSynth {
|
|||
oneShot(false),
|
||||
enabled(false),
|
||||
global(false),
|
||||
speed(1),
|
||||
speed(0),
|
||||
param1(0),
|
||||
param2(0),
|
||||
param3(0),
|
||||
|
|
|
@ -91,20 +91,11 @@ void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
|||
}
|
||||
|
||||
void DivPlatformGB::updateWave() {
|
||||
DivWavetable* wt=parent->getWave(chan[2].wave);
|
||||
rWrite(0x1a,0);
|
||||
for (int i=0; i<16; i++) {
|
||||
if (wt->max<1 || wt->len<1) {
|
||||
rWrite(0x30+i,0);
|
||||
} else {
|
||||
int nibble1=15-((wt->data[(i*2)*wt->len/32]*15)/wt->max);
|
||||
int nibble2=15-((wt->data[(1+i*2)*wt->len/32]*15)/wt->max);
|
||||
if (nibble1<0) nibble1=0;
|
||||
if (nibble1>15) nibble1=15;
|
||||
if (nibble2<0) nibble2=0;
|
||||
if (nibble2>15) nibble2=15;
|
||||
rWrite(0x30+i,(nibble1<<4)|nibble2);
|
||||
}
|
||||
int nibble1=15-ws.output[i<<1];
|
||||
int nibble2=15-ws.output[1+(i<<1)];
|
||||
rWrite(0x30+i,(nibble1<<4)|nibble2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,10 +185,16 @@ void DivPlatformGB::tick() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.hadWave) {
|
||||
if (chan[i].wave!=chan[i].std.wave) {
|
||||
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) {
|
||||
ws.changeWave1(chan[i].wave);
|
||||
if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (i==2) {
|
||||
if (chan[i].active) {
|
||||
if (ws.tick()) {
|
||||
updateWave();
|
||||
if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||
}
|
||||
|
@ -222,10 +219,6 @@ void DivPlatformGB::tick() {
|
|||
}
|
||||
if (chan[i].keyOn) {
|
||||
if (i==2) { // wave
|
||||
if (chan[i].wave<0) {
|
||||
chan[i].wave=0;
|
||||
updateWave();
|
||||
}
|
||||
rWrite(16+i*5,0x80);
|
||||
rWrite(16+i*5+2,gbVolMap[chan[i].vol]);
|
||||
} else {
|
||||
|
@ -261,7 +254,8 @@ void DivPlatformGB::muteChannel(int ch, bool mute) {
|
|||
|
||||
int DivPlatformGB::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON:
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
if (c.chan==3) { // noise
|
||||
chan[c.chan].baseFreq=c.value;
|
||||
|
@ -273,8 +267,17 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].std.init(ins);
|
||||
if (c.chan==2) {
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
ws.changeWave1(chan[c.chan].wave);
|
||||
}
|
||||
ws.init(ins,32,15,chan[c.chan].insChanged);
|
||||
}
|
||||
chan[c.chan].insChanged=false;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
|
@ -287,6 +290,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
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;
|
||||
if (c.chan!=2) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
chan[c.chan].vol=ins->gb.envVol;
|
||||
|
@ -312,7 +316,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
case DIV_CMD_WAVE:
|
||||
if (c.chan!=2) break;
|
||||
chan[c.chan].wave=c.value;
|
||||
updateWave();
|
||||
ws.changeWave1(chan[c.chan].wave);
|
||||
chan[c.chan].keyOn=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
|
@ -415,6 +419,8 @@ void DivPlatformGB::reset() {
|
|||
for (int i=0; i<4; i++) {
|
||||
chan[i]=DivPlatformGB::Channel();
|
||||
}
|
||||
ws.setEngine(parent);
|
||||
ws.init(NULL,32,15,false);
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
|
@ -445,6 +451,7 @@ void DivPlatformGB::notifyInsChange(int ins) {
|
|||
|
||||
void DivPlatformGB::notifyWaveChange(int wave) {
|
||||
if (chan[2].wave==wave) {
|
||||
ws.changeWave1(wave);
|
||||
updateWave();
|
||||
if (!chan[2].keyOff) chan[2].keyOn=true;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "../dispatch.h"
|
||||
#include "../macroInt.h"
|
||||
#include "../waveSynth.h"
|
||||
#include "sound/gb/gb.h"
|
||||
|
||||
class DivPlatformGB: public DivDispatch {
|
||||
|
@ -53,6 +54,7 @@ class DivPlatformGB: public DivDispatch {
|
|||
Channel chan[4];
|
||||
bool isMuted[4];
|
||||
unsigned char lastPan;
|
||||
DivWaveSynth ws;
|
||||
|
||||
GB_gameboy_t* gb;
|
||||
unsigned char regPool[128];
|
||||
|
|
|
@ -131,18 +131,10 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
|||
}
|
||||
|
||||
void DivPlatformPCE::updateWave(int ch) {
|
||||
DivWavetable* wt=parent->getWave(chan[ch].wave);
|
||||
chWrite(ch,0x04,0x5f);
|
||||
chWrite(ch,0x04,0x1f);
|
||||
for (int i=0; i<32; i++) {
|
||||
if (wt->max<1 || wt->len<1) {
|
||||
chWrite(ch,0x06,0);
|
||||
} else {
|
||||
int data=wt->data[i*wt->len/32]*31/wt->max;
|
||||
if (data<0) data=0;
|
||||
if (data>31) data=31;
|
||||
chWrite(ch,0x06,data);
|
||||
}
|
||||
chWrite(ch,0x06,chan[ch].ws.output[i]);
|
||||
}
|
||||
if (chan[ch].active) {
|
||||
chWrite(ch,0x04,0x80|chan[ch].outVol);
|
||||
|
@ -198,12 +190,17 @@ void DivPlatformPCE::tick() {
|
|||
}
|
||||
}
|
||||
if (chan[i].std.hadWave && !chan[i].pcm) {
|
||||
if (chan[i].wave!=chan[i].std.wave) {
|
||||
if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) {
|
||||
chan[i].wave=chan[i].std.wave;
|
||||
updateWave(i);
|
||||
chan[i].ws.changeWave1(chan[i].wave);
|
||||
if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].active) {
|
||||
if (chan[i].ws.tick()) {
|
||||
updateWave(i);
|
||||
}
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true);
|
||||
|
@ -224,10 +221,6 @@ void DivPlatformPCE::tick() {
|
|||
chWrite(i,0x02,chan[i].freq&0xff);
|
||||
chWrite(i,0x03,chan[i].freq>>8);
|
||||
if (chan[i].keyOn) {
|
||||
if (chan[i].wave<0) {
|
||||
chan[i].wave=0;
|
||||
updateWave(i);
|
||||
}
|
||||
//rWrite(16+i*5,0x80);
|
||||
//chWrite(i,0x04,0x80|chan[i].vol);
|
||||
}
|
||||
|
@ -310,6 +303,12 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOn=true;
|
||||
chWrite(c.chan,0x04,0x80|chan[c.chan].vol);
|
||||
chan[c.chan].std.init(ins);
|
||||
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,32,31,chan[c.chan].insChanged);
|
||||
chan[c.chan].insChanged=false;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
|
@ -327,6 +326,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
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:
|
||||
|
@ -350,7 +350,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_WAVE:
|
||||
chan[c.chan].wave=c.value;
|
||||
updateWave(c.chan);
|
||||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
chan[c.chan].keyOn=true;
|
||||
break;
|
||||
case DIV_CMD_PCE_LFO_MODE:
|
||||
|
@ -462,6 +462,8 @@ void DivPlatformPCE::reset() {
|
|||
memset(regPool,0,128);
|
||||
for (int i=0; i<6; i++) {
|
||||
chan[i]=DivPlatformPCE::Channel();
|
||||
chan[i].ws.setEngine(parent);
|
||||
chan[i].ws.init(NULL,32,31,false);
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
|
@ -499,6 +501,7 @@ bool DivPlatformPCE::keyOffAffectsArp(int ch) {
|
|||
void DivPlatformPCE::notifyWaveChange(int wave) {
|
||||
for (int i=0; i<6; i++) {
|
||||
if (chan[i].wave==wave) {
|
||||
chan[i].ws.changeWave1(wave);
|
||||
updateWave(i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "../dispatch.h"
|
||||
#include <queue>
|
||||
#include "../macroInt.h"
|
||||
#include "../waveSynth.h"
|
||||
#include "sound/pce_psg.h"
|
||||
|
||||
class DivPlatformPCE: public DivDispatch {
|
||||
|
@ -35,6 +36,7 @@ class DivPlatformPCE: public DivDispatch {
|
|||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac;
|
||||
signed char vol, outVol, wave;
|
||||
DivMacroInt std;
|
||||
DivWaveSynth ws;
|
||||
Channel():
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
|
|
|
@ -1,52 +1,99 @@
|
|||
#include "waveSynth.h"
|
||||
#include "engine.h"
|
||||
#include "instrument.h"
|
||||
|
||||
bool DivWaveSynth::activeChanged() {
|
||||
if (activeChangedB) {
|
||||
activeChangedB=false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DivWaveSynth::tick() {
|
||||
bool updated=first;
|
||||
first=false;
|
||||
if (!state.enabled) return updated;
|
||||
|
||||
if (--divCounter<=0) {
|
||||
// run effect
|
||||
switch (state.effect) {
|
||||
case DIV_WS_INVERT:
|
||||
for (int i=0; i<=state.speed; i++) {
|
||||
output[pos]=height-output[pos];
|
||||
if (++pos>=width) pos=0;
|
||||
}
|
||||
updated=true;
|
||||
break;
|
||||
}
|
||||
divCounter=state.rateDivider;
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
void DivWaveSynth::changeWave1(int num) {
|
||||
DivWavetable* w1=e->getWave(num);
|
||||
for (int i=0; i<width; i++) {
|
||||
if (w1->max<1 || w1->len<1) {
|
||||
wave1[i]=0;
|
||||
output[i]=0;
|
||||
} else {
|
||||
int data=w1->data[i*w1->len/width]*height/w1->max;
|
||||
if (data<0) data=0;
|
||||
if (data>height) data=height;
|
||||
wave1[i]=data;
|
||||
output[i]=data;
|
||||
}
|
||||
}
|
||||
first=true;
|
||||
}
|
||||
|
||||
void DivWaveSynth::changeWave2(int num) {
|
||||
DivWavetable* w2=e->getWave(num);
|
||||
for (int i=0; i<width; i++) {
|
||||
if (w2->max<1 || w2->len<1) {
|
||||
wave2[i]=0;
|
||||
} else {
|
||||
int data=w2->data[i*w2->len/width]*height/w2->max;
|
||||
if (data<0) data=0;
|
||||
if (data>height) data=height;
|
||||
wave2[i]=data;
|
||||
}
|
||||
}
|
||||
first=true;
|
||||
}
|
||||
|
||||
void DivWaveSynth::setEngine(DivEngine* engine) {
|
||||
e=engine;
|
||||
}
|
||||
|
||||
void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) {
|
||||
if (e==NULL) return;
|
||||
if (which==NULL) {
|
||||
state=DivInstrumentWaveSynth();
|
||||
}
|
||||
state=which->ws;
|
||||
width=w;
|
||||
height=h;
|
||||
pos=0;
|
||||
stage=0;
|
||||
divCounter=0;
|
||||
first=true;
|
||||
|
||||
DivWavetable* w1=e->getWave(state.wave1);
|
||||
DivWavetable* w2=e->getWave(state.wave2);
|
||||
for (int i=0; i<width; i++) {
|
||||
if (w1->max<1 || w1->len<1) {
|
||||
wave1[i]=0;
|
||||
} else {
|
||||
int data=w1->data[i*w1->len/width]*height/w1->max;
|
||||
if (data<0) data=0;
|
||||
if (data>31) data=31;
|
||||
wave1[i]=data;
|
||||
}
|
||||
if (width<0) width=0;
|
||||
if (width>256) width=256;
|
||||
if (e==NULL) return;
|
||||
if (which==NULL) {
|
||||
if (state.enabled) activeChangedB=true;
|
||||
state=DivInstrumentWaveSynth();
|
||||
return;
|
||||
}
|
||||
if (!which->ws.enabled) {
|
||||
if (state.enabled) activeChangedB=true;
|
||||
state=DivInstrumentWaveSynth();
|
||||
return;
|
||||
} else {
|
||||
if (!state.enabled) activeChangedB=true;
|
||||
}
|
||||
state=which->ws;
|
||||
if (insChanged || !state.global) {
|
||||
pos=0;
|
||||
stage=0;
|
||||
divCounter=1+state.rateDivider;
|
||||
first=true;
|
||||
|
||||
for (int i=0; i<width; i++) {
|
||||
if (w2->max<1 || w2->len<1) {
|
||||
wave2[i]=0;
|
||||
} else {
|
||||
int data=w2->data[i*w2->len/width]*height/w2->max;
|
||||
if (data<0) data=0;
|
||||
if (data>31) data=31;
|
||||
wave2[i]=data;
|
||||
}
|
||||
changeWave1(state.wave1);
|
||||
changeWave2(state.wave2);
|
||||
}
|
||||
}
|
|
@ -29,16 +29,41 @@ class DivWaveSynth {
|
|||
DivEngine* e;
|
||||
DivInstrumentWaveSynth state;
|
||||
int pos, stage, divCounter, width, height;
|
||||
bool first;
|
||||
bool first, activeChangedB;
|
||||
unsigned char wave1[256];
|
||||
unsigned char wave2[256];
|
||||
int output[256];
|
||||
public:
|
||||
/**
|
||||
* the output.
|
||||
*/
|
||||
int output[256];
|
||||
/**
|
||||
* check whether the "active" status has changed.
|
||||
* @return truth.
|
||||
*/
|
||||
bool activeChanged();
|
||||
/**
|
||||
* tick this DivWaveSynth.
|
||||
* @return whether the wave has changed.
|
||||
*/
|
||||
bool tick();
|
||||
/**
|
||||
* change the first wave.
|
||||
* @param num wavetable number.
|
||||
*/
|
||||
void changeWave1(int num);
|
||||
/**
|
||||
* change the second wave.
|
||||
* @param num wavetable number.
|
||||
*/
|
||||
void changeWave2(int num);
|
||||
/**
|
||||
* initialize this DivWaveSynth.
|
||||
* @param which the instrument.
|
||||
* @param width the system's wave width.
|
||||
* @param height the system's wave height.
|
||||
* @param insChanged whether the instrument has changed.
|
||||
*/
|
||||
void init(DivInstrument* which, int width, int height, bool insChanged=false);
|
||||
void setEngine(DivEngine* engine);
|
||||
DivWaveSynth():
|
||||
|
@ -48,7 +73,8 @@ class DivWaveSynth {
|
|||
divCounter(0),
|
||||
width(32),
|
||||
height(31),
|
||||
first(false) {
|
||||
first(false),
|
||||
activeChangedB(false) {
|
||||
memset(wave1,0,sizeof(int)*256);
|
||||
memset(wave2,0,sizeof(int)*256);
|
||||
memset(output,0,sizeof(int)*256);
|
||||
|
|
|
@ -2418,6 +2418,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::InputScalar("Amount",ImGuiDataType_U8,&ins->ws.param1,&_ONE,&_SEVEN);
|
||||
|
||||
ImGui::Checkbox("Global",&ins->ws.global);
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue