prepare for macroInt preview in instrument editor
This commit is contained in:
parent
9eb9561b53
commit
e8f29cf122
|
@ -35,74 +35,77 @@
|
||||||
// names as strings for the commands (and other debug stuff).
|
// names as strings for the commands (and other debug stuff).
|
||||||
//
|
//
|
||||||
// if you miss it, the program will crash or misbehave at some point.
|
// if you miss it, the program will crash or misbehave at some point.
|
||||||
|
//
|
||||||
|
// the comments are: (arg1, arg2) -> val
|
||||||
|
// not all commands have a return value
|
||||||
enum DivDispatchCmds {
|
enum DivDispatchCmds {
|
||||||
DIV_CMD_NOTE_ON=0,
|
DIV_CMD_NOTE_ON=0, // (note)
|
||||||
DIV_CMD_NOTE_OFF,
|
DIV_CMD_NOTE_OFF,
|
||||||
DIV_CMD_NOTE_OFF_ENV,
|
DIV_CMD_NOTE_OFF_ENV,
|
||||||
DIV_CMD_ENV_RELEASE,
|
DIV_CMD_ENV_RELEASE,
|
||||||
DIV_CMD_INSTRUMENT,
|
DIV_CMD_INSTRUMENT, // (ins, force)
|
||||||
DIV_CMD_VOLUME,
|
DIV_CMD_VOLUME, // (vol)
|
||||||
DIV_CMD_GET_VOLUME,
|
DIV_CMD_GET_VOLUME, // () -> vol
|
||||||
DIV_CMD_GET_VOLMAX,
|
DIV_CMD_GET_VOLMAX, // () -> volMax
|
||||||
DIV_CMD_NOTE_PORTA,
|
DIV_CMD_NOTE_PORTA, // (target, speed) -> 2 if target reached
|
||||||
DIV_CMD_PITCH,
|
DIV_CMD_PITCH, // (pitch)
|
||||||
DIV_CMD_PANNING,
|
DIV_CMD_PANNING, // (pan)
|
||||||
DIV_CMD_LEGATO,
|
DIV_CMD_LEGATO, // (note)
|
||||||
DIV_CMD_PRE_PORTA,
|
DIV_CMD_PRE_PORTA, // (inPorta, isPortaOrSlide)
|
||||||
DIV_CMD_PRE_NOTE, // used in C64
|
DIV_CMD_PRE_NOTE, // used in C64 (note)
|
||||||
|
|
||||||
DIV_CMD_SAMPLE_MODE,
|
DIV_CMD_SAMPLE_MODE, // (enabled)
|
||||||
DIV_CMD_SAMPLE_FREQ,
|
DIV_CMD_SAMPLE_FREQ, // (frequency)
|
||||||
DIV_CMD_SAMPLE_BANK,
|
DIV_CMD_SAMPLE_BANK, // (bank)
|
||||||
DIV_CMD_SAMPLE_POS,
|
DIV_CMD_SAMPLE_POS, // (pos)
|
||||||
|
|
||||||
DIV_CMD_FM_HARD_RESET,
|
DIV_CMD_FM_HARD_RESET, // (enabled)
|
||||||
DIV_CMD_FM_LFO,
|
DIV_CMD_FM_LFO, // (speed)
|
||||||
DIV_CMD_FM_LFO_WAVE,
|
DIV_CMD_FM_LFO_WAVE, // (waveform)
|
||||||
DIV_CMD_FM_TL,
|
DIV_CMD_FM_TL, // (op, value)
|
||||||
DIV_CMD_FM_AR,
|
DIV_CMD_FM_AR, // (op, value)
|
||||||
DIV_CMD_FM_FB,
|
DIV_CMD_FM_FB, // (value)
|
||||||
DIV_CMD_FM_MULT,
|
DIV_CMD_FM_MULT, // (op, value)
|
||||||
DIV_CMD_FM_EXTCH,
|
DIV_CMD_FM_EXTCH, // (enabled)
|
||||||
DIV_CMD_FM_AM_DEPTH,
|
DIV_CMD_FM_AM_DEPTH, // (depth)
|
||||||
DIV_CMD_FM_PM_DEPTH,
|
DIV_CMD_FM_PM_DEPTH, // (depth)
|
||||||
|
|
||||||
DIV_CMD_GENESIS_LFO,
|
DIV_CMD_GENESIS_LFO, // unused?
|
||||||
|
|
||||||
DIV_CMD_ARCADE_LFO,
|
DIV_CMD_ARCADE_LFO, // unused?
|
||||||
|
|
||||||
DIV_CMD_STD_NOISE_FREQ,
|
DIV_CMD_STD_NOISE_FREQ, // (freq)
|
||||||
DIV_CMD_STD_NOISE_MODE,
|
DIV_CMD_STD_NOISE_MODE, // (mode)
|
||||||
|
|
||||||
DIV_CMD_WAVE,
|
DIV_CMD_WAVE, // (waveform)
|
||||||
|
|
||||||
DIV_CMD_GB_SWEEP_TIME,
|
DIV_CMD_GB_SWEEP_TIME, // (time)
|
||||||
DIV_CMD_GB_SWEEP_DIR,
|
DIV_CMD_GB_SWEEP_DIR, // (direction)
|
||||||
|
|
||||||
DIV_CMD_PCE_LFO_MODE,
|
DIV_CMD_PCE_LFO_MODE, // (mode)
|
||||||
DIV_CMD_PCE_LFO_SPEED,
|
DIV_CMD_PCE_LFO_SPEED, // (speed)
|
||||||
|
|
||||||
DIV_CMD_NES_SWEEP,
|
DIV_CMD_NES_SWEEP, // (direction, value)
|
||||||
|
|
||||||
DIV_CMD_C64_CUTOFF,
|
DIV_CMD_C64_CUTOFF, // (value)
|
||||||
DIV_CMD_C64_RESONANCE,
|
DIV_CMD_C64_RESONANCE, // (value)
|
||||||
DIV_CMD_C64_FILTER_MODE,
|
DIV_CMD_C64_FILTER_MODE, // (value)
|
||||||
DIV_CMD_C64_RESET_TIME,
|
DIV_CMD_C64_RESET_TIME, // (value)
|
||||||
DIV_CMD_C64_RESET_MASK,
|
DIV_CMD_C64_RESET_MASK, // (mask)
|
||||||
DIV_CMD_C64_FILTER_RESET,
|
DIV_CMD_C64_FILTER_RESET, // (value)
|
||||||
DIV_CMD_C64_DUTY_RESET,
|
DIV_CMD_C64_DUTY_RESET, // (value)
|
||||||
DIV_CMD_C64_EXTENDED,
|
DIV_CMD_C64_EXTENDED, // (value)
|
||||||
DIV_CMD_C64_FINE_DUTY,
|
DIV_CMD_C64_FINE_DUTY, // (value)
|
||||||
DIV_CMD_C64_FINE_CUTOFF,
|
DIV_CMD_C64_FINE_CUTOFF, // (value)
|
||||||
|
|
||||||
DIV_CMD_AY_ENVELOPE_SET,
|
DIV_CMD_AY_ENVELOPE_SET,
|
||||||
DIV_CMD_AY_ENVELOPE_LOW,
|
DIV_CMD_AY_ENVELOPE_LOW,
|
||||||
DIV_CMD_AY_ENVELOPE_HIGH,
|
DIV_CMD_AY_ENVELOPE_HIGH,
|
||||||
DIV_CMD_AY_ENVELOPE_SLIDE,
|
DIV_CMD_AY_ENVELOPE_SLIDE,
|
||||||
DIV_CMD_AY_NOISE_MASK_AND,
|
DIV_CMD_AY_NOISE_MASK_AND, // (value)
|
||||||
DIV_CMD_AY_NOISE_MASK_OR,
|
DIV_CMD_AY_NOISE_MASK_OR, // (value)
|
||||||
DIV_CMD_AY_AUTO_ENVELOPE,
|
DIV_CMD_AY_AUTO_ENVELOPE, // (value)
|
||||||
DIV_CMD_AY_IO_WRITE,
|
DIV_CMD_AY_IO_WRITE, // (port, value)
|
||||||
DIV_CMD_AY_AUTO_PWM,
|
DIV_CMD_AY_AUTO_PWM,
|
||||||
|
|
||||||
DIV_CMD_FDS_MOD_DEPTH,
|
DIV_CMD_FDS_MOD_DEPTH,
|
||||||
|
@ -111,13 +114,13 @@ enum DivDispatchCmds {
|
||||||
DIV_CMD_FDS_MOD_POS,
|
DIV_CMD_FDS_MOD_POS,
|
||||||
DIV_CMD_FDS_MOD_WAVE,
|
DIV_CMD_FDS_MOD_WAVE,
|
||||||
|
|
||||||
DIV_CMD_SAA_ENVELOPE,
|
DIV_CMD_SAA_ENVELOPE, // (value)
|
||||||
|
|
||||||
DIV_CMD_AMIGA_FILTER,
|
DIV_CMD_AMIGA_FILTER, // (enabled)
|
||||||
DIV_CMD_AMIGA_AM,
|
DIV_CMD_AMIGA_AM, // (enabled)
|
||||||
DIV_CMD_AMIGA_PM,
|
DIV_CMD_AMIGA_PM, // (enabled)
|
||||||
|
|
||||||
DIV_CMD_LYNX_LFSR_LOAD,
|
DIV_CMD_LYNX_LFSR_LOAD, // (value)
|
||||||
|
|
||||||
DIV_CMD_QSOUND_ECHO_FEEDBACK,
|
DIV_CMD_QSOUND_ECHO_FEEDBACK,
|
||||||
DIV_CMD_QSOUND_ECHO_DELAY,
|
DIV_CMD_QSOUND_ECHO_DELAY,
|
||||||
|
@ -146,7 +149,7 @@ enum DivDispatchCmds {
|
||||||
DIV_CMD_N163_GLOBAL_WAVE_LOADLEN,
|
DIV_CMD_N163_GLOBAL_WAVE_LOADLEN,
|
||||||
DIV_CMD_N163_GLOBAL_WAVE_LOADMODE,
|
DIV_CMD_N163_GLOBAL_WAVE_LOADMODE,
|
||||||
|
|
||||||
DIV_ALWAYS_SET_VOLUME,
|
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
||||||
|
|
||||||
DIV_CMD_MAX
|
DIV_CMD_MAX
|
||||||
};
|
};
|
||||||
|
@ -201,6 +204,7 @@ struct DivRegWrite {
|
||||||
};
|
};
|
||||||
|
|
||||||
class DivEngine;
|
class DivEngine;
|
||||||
|
class DivMacroInt;
|
||||||
|
|
||||||
class DivDispatch {
|
class DivDispatch {
|
||||||
protected:
|
protected:
|
||||||
|
@ -214,11 +218,13 @@ class DivDispatch {
|
||||||
/**
|
/**
|
||||||
* the rate the samples are provided.
|
* the rate the samples are provided.
|
||||||
* the engine shall resample to the output rate.
|
* the engine shall resample to the output rate.
|
||||||
|
* you have to initialize this one during init() or setFlags().
|
||||||
*/
|
*/
|
||||||
int rate;
|
int rate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the actual chip's clock.
|
* the actual chip's clock.
|
||||||
|
* you have to initialize this one during init() or setFlags().
|
||||||
*/
|
*/
|
||||||
int chipClock;
|
int chipClock;
|
||||||
|
|
||||||
|
@ -255,6 +261,12 @@ class DivDispatch {
|
||||||
*/
|
*/
|
||||||
virtual void* getChanState(int chan);
|
virtual void* getChanState(int chan);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the DivMacroInt of a chanmel.
|
||||||
|
* @return a pointer, or NULL.
|
||||||
|
*/
|
||||||
|
virtual DivMacroInt* getChanMacroInt(int chan);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the register pool of this dispatch.
|
* get the register pool of this dispatch.
|
||||||
* @return a pointer, or NULL.
|
* @return a pointer, or NULL.
|
||||||
|
@ -423,12 +435,25 @@ class DivDispatch {
|
||||||
virtual ~DivDispatch();
|
virtual ~DivDispatch();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// pitch calculation:
|
||||||
|
// - a DivDispatch usually contains four variables per channel:
|
||||||
|
// - baseFreq: this changes on new notes, legato, arpeggio and slides.
|
||||||
|
// - pitch: this changes with DIV_CMD_PITCH (E5xx/04xy).
|
||||||
|
// - freq: this is the result of combining baseFreq and pitch using DivEngine::calcFreq().
|
||||||
|
// - freqChanged: whether baseFreq and/or pitch have changed, and a frequency recalculation is required on the next tick.
|
||||||
|
// - the following definitions will help you calculate baseFreq.
|
||||||
|
// - to use them, define CHIP_DIVIDER and/or CHIP_FREQBASE in your code (not in the header though!).
|
||||||
#define NOTE_PERIODIC(x) round(parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true))
|
#define NOTE_PERIODIC(x) round(parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true))
|
||||||
#define NOTE_PERIODIC_NOROUND(x) parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true)
|
#define NOTE_PERIODIC_NOROUND(x) parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true)
|
||||||
#define NOTE_FREQUENCY(x) parent->calcBaseFreq(chipClock,CHIP_FREQBASE,x,false)
|
#define NOTE_FREQUENCY(x) parent->calcBaseFreq(chipClock,CHIP_FREQBASE,x,false)
|
||||||
|
|
||||||
|
// this is a special case definition. only use it for f-num/block-based chips.
|
||||||
#define NOTE_FNUM_BLOCK(x,bits) parent->calcBaseFreqFNumBlock(chipClock,CHIP_FREQBASE,x,bits)
|
#define NOTE_FNUM_BLOCK(x,bits) parent->calcBaseFreqFNumBlock(chipClock,CHIP_FREQBASE,x,bits)
|
||||||
|
|
||||||
|
// these are here for convenience.
|
||||||
|
// it is encouraged to use these, since you get an exact value this way.
|
||||||
|
// - NTSC colorburst: 3.58MHz
|
||||||
|
// - PAL colorburst: 4.43MHz
|
||||||
#define COLOR_NTSC (315000000.0/88.0)
|
#define COLOR_NTSC (315000000.0/88.0)
|
||||||
#define COLOR_PAL (283.75*15625.0+25.0)
|
#define COLOR_PAL (283.75*15625.0+25.0)
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,10 @@ void* DivDispatch::getChanState(int chan) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DivMacroInt* DivDispatch::getChanMacroInt(int chan) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char* DivDispatch::getRegisterPool() {
|
unsigned char* DivDispatch::getRegisterPool() {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
#include "su.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define minval(a,b) (((a)<(b))?(a):(b))
|
||||||
|
#define maxval(a,b) (((a)>(b))?(a):(b))
|
||||||
|
|
||||||
|
void SoundUnit::NextSample(short* l, short* r) {
|
||||||
|
for (int i=0; i<8; i++) {
|
||||||
|
if (chan[i].vol==0 && !chan[i].flags.swvol) {fns[i]=0; continue;}
|
||||||
|
if (chan[i].flags.pcm) {
|
||||||
|
ns[i]=pcm[chan[i].pcmpos];
|
||||||
|
} else switch (chan[i].flags.shape) {
|
||||||
|
case 0:
|
||||||
|
ns[i]=(((cycle[i]>>15)&127)>chan[i].duty)*127;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ns[i]=cycle[i]>>14;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ns[i]=SCsine[(cycle[i]>>14)&255];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ns[i]=SCtriangle[(cycle[i]>>14)&255];
|
||||||
|
break;
|
||||||
|
case 4: case 5:
|
||||||
|
ns[i]=(lfsr[i]&1)*127;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
ns[i]=((((cycle[i]>>15)&127)>chan[i].duty)*127)^(short)SCsine[(cycle[i]>>14)&255];
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
ns[i]=((((cycle[i]>>15)&127)>chan[i].duty)*127)^(short)SCtriangle[(cycle[i]>>14)&255];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan[i].flags.pcm) {
|
||||||
|
if (chan[i].freq>0x8000) {
|
||||||
|
pcmdec[i]+=0x8000;
|
||||||
|
} else {
|
||||||
|
pcmdec[i]+=chan[i].freq;
|
||||||
|
}
|
||||||
|
if (pcmdec[i]>=32768) {
|
||||||
|
pcmdec[i]-=32768;
|
||||||
|
if (chan[i].pcmpos<chan[i].pcmbnd) {
|
||||||
|
chan[i].pcmpos++;
|
||||||
|
chan[i].wc++;
|
||||||
|
if (chan[i].pcmpos==chan[i].pcmbnd) {
|
||||||
|
if (chan[i].flags.pcmloop) {
|
||||||
|
chan[i].pcmpos=chan[i].pcmrst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chan[i].pcmpos&=(SOUNDCHIP_PCM_SIZE-1);
|
||||||
|
} else if (chan[i].flags.pcmloop) {
|
||||||
|
chan[i].pcmpos=chan[i].pcmrst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ocycle[i]=cycle[i];
|
||||||
|
if (chan[i].flags.shape==5) {
|
||||||
|
switch ((chan[i].duty>>4)&3) {
|
||||||
|
case 0:
|
||||||
|
cycle[i]+=chan[i].freq*1-(chan[i].freq>>3);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cycle[i]+=chan[i].freq*2-(chan[i].freq>>3);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cycle[i]+=chan[i].freq*4-(chan[i].freq>>3);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
cycle[i]+=chan[i].freq*8-(chan[i].freq>>3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cycle[i]+=chan[i].freq;
|
||||||
|
}
|
||||||
|
if ((cycle[i]&0xf80000)!=(ocycle[i]&0xf80000)) {
|
||||||
|
if (chan[i].flags.shape==4) {
|
||||||
|
lfsr[i]=(lfsr[i]>>1|(((lfsr[i]) ^ (lfsr[i] >> 2) ^ (lfsr[i] >> 3) ^ (lfsr[i] >> 5) ) & 1)<<31);
|
||||||
|
} else {
|
||||||
|
switch ((chan[i].duty>>4)&3) {
|
||||||
|
case 0:
|
||||||
|
lfsr[i]=(lfsr[i]>>1|(((lfsr[i] >> 3) ^ (lfsr[i] >> 4) ) & 1)<<5);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
lfsr[i]=(lfsr[i]>>1|(((lfsr[i] >> 2) ^ (lfsr[i] >> 3) ) & 1)<<5);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
lfsr[i]=(lfsr[i]>>1|(((lfsr[i]) ^ (lfsr[i] >> 2) ^ (lfsr[i] >> 3) ) & 1)<<5);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
lfsr[i]=(lfsr[i]>>1|(((lfsr[i]) ^ (lfsr[i] >> 2) ^ (lfsr[i] >> 3) ^ (lfsr[i] >> 5) ) & 1)<<5);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((lfsr[i]&63)==0) {
|
||||||
|
lfsr[i]=0xaaaa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].flags.restim) {
|
||||||
|
if (--rcycle[i]<=0) {
|
||||||
|
cycle[i]=0;
|
||||||
|
rcycle[i]=chan[i].restimer;
|
||||||
|
lfsr[i]=0xaaaa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fns[i]=ns[i]*chan[i].vol*2;
|
||||||
|
if (chan[i].flags.fmode!=0) {
|
||||||
|
int ff=chan[i].cutoff;
|
||||||
|
nslow[i]=nslow[i]+(((ff)*nsband[i])>>16);
|
||||||
|
nshigh[i]=fns[i]-nslow[i]-(((256-chan[i].reson)*nsband[i])>>8);
|
||||||
|
nsband[i]=(((ff)*nshigh[i])>>16)+nsband[i];
|
||||||
|
fns[i]=(((chan[i].flags.fmode&1)?(nslow[i]):(0))+((chan[i].flags.fmode&2)?(nshigh[i]):(0))+((chan[i].flags.fmode&4)?(nsband[i]):(0)));
|
||||||
|
}
|
||||||
|
nsL[i]=(fns[i]*SCpantabL[(unsigned char)chan[i].pan])>>8;
|
||||||
|
nsR[i]=(fns[i]*SCpantabR[(unsigned char)chan[i].pan])>>8;
|
||||||
|
oldfreq[i]=chan[i].freq;
|
||||||
|
oldflags[i]=chan[i].flags.flags;
|
||||||
|
if (chan[i].flags.swvol) {
|
||||||
|
if (--swvolt[i]<=0) {
|
||||||
|
swvolt[i]=chan[i].swvol.speed;
|
||||||
|
if (chan[i].swvol.dir) {
|
||||||
|
chan[i].vol+=chan[i].swvol.amt;
|
||||||
|
if (chan[i].vol>chan[i].swvol.bound && !chan[i].swvol.loop) {
|
||||||
|
chan[i].vol=chan[i].swvol.bound;
|
||||||
|
}
|
||||||
|
if (chan[i].vol&0x80) {
|
||||||
|
if (chan[i].swvol.loop) {
|
||||||
|
if (chan[i].swvol.loopi) {
|
||||||
|
chan[i].swvol.dir=!chan[i].swvol.dir;
|
||||||
|
chan[i].vol=0xff-chan[i].vol;
|
||||||
|
} else {
|
||||||
|
chan[i].vol&=~0x80;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chan[i].vol=0x7f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chan[i].vol-=chan[i].swvol.amt;
|
||||||
|
if (chan[i].vol&0x80) {
|
||||||
|
if (chan[i].swvol.loop) {
|
||||||
|
if (chan[i].swvol.loopi) {
|
||||||
|
chan[i].swvol.dir=!chan[i].swvol.dir;
|
||||||
|
chan[i].vol=-chan[i].vol;
|
||||||
|
} else {
|
||||||
|
chan[i].vol&=~0x80;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chan[i].vol=0x0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].vol<chan[i].swvol.bound && !chan[i].swvol.loop) {
|
||||||
|
chan[i].vol=chan[i].swvol.bound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].flags.swfreq) {
|
||||||
|
if (--swfreqt[i]<=0) {
|
||||||
|
swfreqt[i]=chan[i].swfreq.speed;
|
||||||
|
if (chan[i].swfreq.dir) {
|
||||||
|
if (chan[i].freq>(0xffff-chan[i].swfreq.amt)) {
|
||||||
|
chan[i].freq=0xffff;
|
||||||
|
} else {
|
||||||
|
chan[i].freq=(chan[i].freq*(0x80+chan[i].swfreq.amt))>>7;
|
||||||
|
if ((chan[i].freq>>8)>chan[i].swfreq.bound) {
|
||||||
|
chan[i].freq=chan[i].swfreq.bound<<8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (chan[i].freq<chan[i].swfreq.amt) {
|
||||||
|
chan[i].freq=0;
|
||||||
|
} else {
|
||||||
|
chan[i].freq=(chan[i].freq*(0xff-chan[i].swfreq.amt))>>8;
|
||||||
|
if ((chan[i].freq>>8)<chan[i].swfreq.bound) {
|
||||||
|
chan[i].freq=chan[i].swfreq.bound<<8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].flags.swcut) {
|
||||||
|
if (--swcutt[i]<=0) {
|
||||||
|
swcutt[i]=chan[i].swcut.speed;
|
||||||
|
if (chan[i].swcut.dir) {
|
||||||
|
if (chan[i].cutoff>(0xffff-chan[i].swcut.amt)) {
|
||||||
|
chan[i].cutoff=0xffff;
|
||||||
|
} else {
|
||||||
|
chan[i].cutoff+=chan[i].swcut.amt;
|
||||||
|
if ((chan[i].cutoff>>8)>chan[i].swcut.bound) {
|
||||||
|
chan[i].cutoff=chan[i].swcut.bound<<8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (chan[i].cutoff<chan[i].swcut.amt) {
|
||||||
|
chan[i].cutoff=0;
|
||||||
|
} else {
|
||||||
|
chan[i].cutoff=((2048-(unsigned int)chan[i].swcut.amt)*(unsigned int)chan[i].cutoff)>>11;
|
||||||
|
if ((chan[i].cutoff>>8)<chan[i].swcut.bound) {
|
||||||
|
chan[i].cutoff=chan[i].swcut.bound<<8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].flags.resosc) {
|
||||||
|
cycle[i]=0;
|
||||||
|
rcycle[i]=chan[i].restimer;
|
||||||
|
ocycle[i]=0;
|
||||||
|
chan[i].flags.resosc=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tnsL=(nsL[0]+nsL[1]+nsL[2]+nsL[3]+nsL[4]+nsL[5]+nsL[6]+nsL[7])>>2;
|
||||||
|
tnsR=(nsR[0]+nsR[1]+nsR[2]+nsR[3]+nsR[4]+nsR[5]+nsR[6]+nsR[7])>>2;
|
||||||
|
|
||||||
|
*l=minval(32767,maxval(-32767,tnsL));
|
||||||
|
*r=minval(32767,maxval(-32767,tnsR));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundUnit::Init() {
|
||||||
|
Reset();
|
||||||
|
memset(pcm,0,SOUNDCHIP_PCM_SIZE);
|
||||||
|
for (int i=0; i<256; i++) {
|
||||||
|
SCsine[i]=sin((i/128.0f)*M_PI)*127;
|
||||||
|
SCtriangle[i]=(i>127)?(255-i):(i);
|
||||||
|
SCpantabL[i]=127;
|
||||||
|
SCpantabR[i]=127;
|
||||||
|
}
|
||||||
|
for (int i=0; i<128; i++) {
|
||||||
|
SCpantabL[i]=127-i;
|
||||||
|
SCpantabR[128+i]=i-1;
|
||||||
|
}
|
||||||
|
SCpantabR[128]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundUnit::Reset() {
|
||||||
|
for (int i=0; i<8; i++) {
|
||||||
|
cycle[i]=0;
|
||||||
|
resetfreq[i]=0;
|
||||||
|
voldcycles[i]=0;
|
||||||
|
volicycles[i]=0;
|
||||||
|
fscycles[i]=0;
|
||||||
|
sweep[i]=0;
|
||||||
|
ns[i]=0;
|
||||||
|
swvolt[i]=1;
|
||||||
|
swfreqt[i]=1;
|
||||||
|
swcutt[i]=1;
|
||||||
|
lfsr[i]=0xaaaa;
|
||||||
|
}
|
||||||
|
memset(chan,0,sizeof(SUChannel)*8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundUnit::Write(unsigned char addr, unsigned char data) {
|
||||||
|
((unsigned char*)chan)[addr]=data;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundUnit::SoundUnit() {
|
||||||
|
Init();
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define SOUNDCHIP_PCM_SIZE 8192
|
||||||
|
|
||||||
|
class SoundUnit {
|
||||||
|
signed char SCsine[256];
|
||||||
|
signed char SCtriangle[256];
|
||||||
|
signed char SCpantabL[256];
|
||||||
|
signed char SCpantabR[256];
|
||||||
|
unsigned int ocycle[8];
|
||||||
|
unsigned int cycle[8];
|
||||||
|
int rcycle[8];
|
||||||
|
unsigned int lfsr[8];
|
||||||
|
signed char ns[8];
|
||||||
|
int fns[8];
|
||||||
|
int nsL[8];
|
||||||
|
int nsR[8];
|
||||||
|
int nslow[8];
|
||||||
|
int nshigh[8];
|
||||||
|
int nsband[8];
|
||||||
|
int tnsL, tnsR;
|
||||||
|
unsigned short oldfreq[8];
|
||||||
|
unsigned short oldflags[8];
|
||||||
|
public:
|
||||||
|
unsigned short resetfreq[8];
|
||||||
|
unsigned short voldcycles[8];
|
||||||
|
unsigned short volicycles[8];
|
||||||
|
unsigned short fscycles[8];
|
||||||
|
unsigned char sweep[8];
|
||||||
|
unsigned short swvolt[8];
|
||||||
|
unsigned short swfreqt[8];
|
||||||
|
unsigned short swcutt[8];
|
||||||
|
unsigned short pcmdec[8];
|
||||||
|
struct SUChannel {
|
||||||
|
unsigned short freq;
|
||||||
|
signed char vol;
|
||||||
|
signed char pan;
|
||||||
|
union {
|
||||||
|
unsigned short flags;
|
||||||
|
struct {
|
||||||
|
unsigned char shape: 3;
|
||||||
|
unsigned char pcm: 1;
|
||||||
|
unsigned char ring: 1;
|
||||||
|
unsigned char fmode: 3;
|
||||||
|
unsigned char resosc: 1;
|
||||||
|
unsigned char resfilt: 1;
|
||||||
|
unsigned char pcmloop: 1;
|
||||||
|
unsigned char restim: 1;
|
||||||
|
unsigned char swfreq: 1;
|
||||||
|
unsigned char swvol: 1;
|
||||||
|
unsigned char swcut: 1;
|
||||||
|
unsigned char padding: 1;
|
||||||
|
};
|
||||||
|
} flags;
|
||||||
|
unsigned short cutoff;
|
||||||
|
unsigned char duty;
|
||||||
|
unsigned char reson;
|
||||||
|
unsigned short pcmpos;
|
||||||
|
unsigned short pcmbnd;
|
||||||
|
unsigned short pcmrst;
|
||||||
|
struct {
|
||||||
|
unsigned short speed;
|
||||||
|
unsigned char amt: 7;
|
||||||
|
unsigned char dir: 1;
|
||||||
|
unsigned char bound;
|
||||||
|
} swfreq;
|
||||||
|
struct {
|
||||||
|
unsigned short speed;
|
||||||
|
unsigned char amt: 5;
|
||||||
|
unsigned char dir: 1;
|
||||||
|
unsigned char loop: 1;
|
||||||
|
unsigned char loopi: 1;
|
||||||
|
unsigned char bound;
|
||||||
|
} swvol;
|
||||||
|
struct {
|
||||||
|
unsigned short speed;
|
||||||
|
unsigned char amt: 7;
|
||||||
|
unsigned char dir: 1;
|
||||||
|
unsigned char bound;
|
||||||
|
} swcut;
|
||||||
|
unsigned short wc;
|
||||||
|
unsigned short restimer;
|
||||||
|
} chan[8];
|
||||||
|
signed char pcm[SOUNDCHIP_PCM_SIZE];
|
||||||
|
void Write(unsigned char addr, unsigned char data);
|
||||||
|
void NextSample(short* l, short* r);
|
||||||
|
void Init();
|
||||||
|
void Reset();
|
||||||
|
SoundUnit();
|
||||||
|
};
|
|
@ -2670,6 +2670,7 @@ bool FurnaceGUI::loop() {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::BeginMenu("add system...")) {
|
if (ImGui::BeginMenu("add system...")) {
|
||||||
for (int j=0; availableSystems[j]; j++) {
|
for (int j=0; availableSystems[j]; j++) {
|
||||||
|
if (!settings.hiddenSystems && availableSystems[j]==DIV_SYSTEM_YMU759) continue;
|
||||||
sysAddOption((DivSystem)availableSystems[j]);
|
sysAddOption((DivSystem)availableSystems[j]);
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
|
@ -2687,6 +2688,7 @@ bool FurnaceGUI::loop() {
|
||||||
for (int i=0; i<e->song.systemLen; i++) {
|
for (int i=0; i<e->song.systemLen; i++) {
|
||||||
if (ImGui::BeginMenu(fmt::sprintf("%d. %s##_SYSC%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
|
if (ImGui::BeginMenu(fmt::sprintf("%d. %s##_SYSC%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
|
||||||
for (int j=0; availableSystems[j]; j++) {
|
for (int j=0; availableSystems[j]; j++) {
|
||||||
|
if (!settings.hiddenSystems && availableSystems[j]==DIV_SYSTEM_YMU759) continue;
|
||||||
sysChangeOption(i,(DivSystem)availableSystems[j]);
|
sysChangeOption(i,(DivSystem)availableSystems[j]);
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
|
@ -3886,6 +3888,7 @@ FurnaceGUI::FurnaceGUI():
|
||||||
lockLayout(false),
|
lockLayout(false),
|
||||||
editOptsVisible(false),
|
editOptsVisible(false),
|
||||||
latchNibble(false),
|
latchNibble(false),
|
||||||
|
nonLatchNibble(false),
|
||||||
curWindow(GUI_WINDOW_NOTHING),
|
curWindow(GUI_WINDOW_NOTHING),
|
||||||
nextWindow(GUI_WINDOW_NOTHING),
|
nextWindow(GUI_WINDOW_NOTHING),
|
||||||
nextDesc(NULL),
|
nextDesc(NULL),
|
||||||
|
|
|
@ -844,6 +844,7 @@ class FurnaceGUI {
|
||||||
int absorbInsInput;
|
int absorbInsInput;
|
||||||
int eventDelay;
|
int eventDelay;
|
||||||
int moveWindowTitle;
|
int moveWindowTitle;
|
||||||
|
int hiddenSystems;
|
||||||
unsigned int maxUndoSteps;
|
unsigned int maxUndoSteps;
|
||||||
String mainFontPath;
|
String mainFontPath;
|
||||||
String patFontPath;
|
String patFontPath;
|
||||||
|
@ -921,6 +922,7 @@ class FurnaceGUI {
|
||||||
absorbInsInput(0),
|
absorbInsInput(0),
|
||||||
eventDelay(0),
|
eventDelay(0),
|
||||||
moveWindowTitle(0),
|
moveWindowTitle(0),
|
||||||
|
hiddenSystems(0),
|
||||||
maxUndoSteps(100),
|
maxUndoSteps(100),
|
||||||
mainFontPath(""),
|
mainFontPath(""),
|
||||||
patFontPath(""),
|
patFontPath(""),
|
||||||
|
@ -949,7 +951,7 @@ class FurnaceGUI {
|
||||||
|
|
||||||
SelectionPoint selStart, selEnd, cursor;
|
SelectionPoint selStart, selEnd, cursor;
|
||||||
bool selecting, curNibble, orderNibble, followOrders, followPattern, changeAllOrders;
|
bool selecting, curNibble, orderNibble, followOrders, followPattern, changeAllOrders;
|
||||||
bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, lockLayout, editOptsVisible, latchNibble;
|
bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, lockLayout, editOptsVisible, latchNibble, nonLatchNibble;
|
||||||
FurnaceGUIWindows curWindow, nextWindow;
|
FurnaceGUIWindows curWindow, nextWindow;
|
||||||
float peak[2];
|
float peak[2];
|
||||||
float patChanX[DIV_MAX_CHANS+1];
|
float patChanX[DIV_MAX_CHANS+1];
|
||||||
|
|
|
@ -587,6 +587,7 @@ const int availableSystems[]={
|
||||||
DIV_SYSTEM_AY8910,
|
DIV_SYSTEM_AY8910,
|
||||||
DIV_SYSTEM_AMIGA,
|
DIV_SYSTEM_AMIGA,
|
||||||
DIV_SYSTEM_PCSPKR,
|
DIV_SYSTEM_PCSPKR,
|
||||||
|
DIV_SYSTEM_YMU759,
|
||||||
DIV_SYSTEM_OPLL,
|
DIV_SYSTEM_OPLL,
|
||||||
DIV_SYSTEM_OPLL_DRUMS,
|
DIV_SYSTEM_OPLL_DRUMS,
|
||||||
DIV_SYSTEM_VRC7,
|
DIV_SYSTEM_VRC7,
|
||||||
|
|
|
@ -952,6 +952,13 @@ void FurnaceGUI::drawSettings() {
|
||||||
settings.oplStandardWaveNames=oplStandardWaveNamesB;
|
settings.oplStandardWaveNames=oplStandardWaveNamesB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nonLatchNibble) {
|
||||||
|
bool hiddenSystemsB=settings.hiddenSystems;
|
||||||
|
if (ImGui::Checkbox(":smile: :star_struck: :sunglasses: :ok_hand:",&hiddenSystemsB)) {
|
||||||
|
settings.hiddenSystems=hiddenSystemsB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool overflowHighlightB=settings.overflowHighlight;
|
bool overflowHighlightB=settings.overflowHighlight;
|
||||||
if (ImGui::Checkbox("Overflow pattern highlights",&overflowHighlightB)) {
|
if (ImGui::Checkbox("Overflow pattern highlights",&overflowHighlightB)) {
|
||||||
settings.overflowHighlight=overflowHighlightB;
|
settings.overflowHighlight=overflowHighlightB;
|
||||||
|
@ -1668,6 +1675,7 @@ void FurnaceGUI::syncSettings() {
|
||||||
settings.absorbInsInput=e->getConfInt("absorbInsInput",0);
|
settings.absorbInsInput=e->getConfInt("absorbInsInput",0);
|
||||||
settings.eventDelay=e->getConfInt("eventDelay",0);
|
settings.eventDelay=e->getConfInt("eventDelay",0);
|
||||||
settings.moveWindowTitle=e->getConfInt("moveWindowTitle",0);
|
settings.moveWindowTitle=e->getConfInt("moveWindowTitle",0);
|
||||||
|
settings.hiddenSystems=e->getConfInt("hiddenSystems",0);
|
||||||
|
|
||||||
clampSetting(settings.mainFontSize,2,96);
|
clampSetting(settings.mainFontSize,2,96);
|
||||||
clampSetting(settings.patFontSize,2,96);
|
clampSetting(settings.patFontSize,2,96);
|
||||||
|
@ -1734,6 +1742,7 @@ void FurnaceGUI::syncSettings() {
|
||||||
clampSetting(settings.absorbInsInput,0,1);
|
clampSetting(settings.absorbInsInput,0,1);
|
||||||
clampSetting(settings.eventDelay,0,1);
|
clampSetting(settings.eventDelay,0,1);
|
||||||
clampSetting(settings.moveWindowTitle,0,1);
|
clampSetting(settings.moveWindowTitle,0,1);
|
||||||
|
clampSetting(settings.hiddenSystems,0,1);
|
||||||
|
|
||||||
// keybinds
|
// keybinds
|
||||||
for (int i=0; i<GUI_ACTION_MAX; i++) {
|
for (int i=0; i<GUI_ACTION_MAX; i++) {
|
||||||
|
@ -1827,6 +1836,7 @@ void FurnaceGUI::commitSettings() {
|
||||||
e->setConf("absorbInsInput",settings.absorbInsInput);
|
e->setConf("absorbInsInput",settings.absorbInsInput);
|
||||||
e->setConf("eventDelay",settings.eventDelay);
|
e->setConf("eventDelay",settings.eventDelay);
|
||||||
e->setConf("moveWindowTitle",settings.moveWindowTitle);
|
e->setConf("moveWindowTitle",settings.moveWindowTitle);
|
||||||
|
e->setConf("hiddenSystems",settings.hiddenSystems);
|
||||||
|
|
||||||
// colors
|
// colors
|
||||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||||
|
|
|
@ -41,6 +41,17 @@ void FurnaceGUI::drawSongInfo() {
|
||||||
if (ImGui::InputText("##Name",&e->song.name)) { MARK_MODIFIED
|
if (ImGui::InputText("##Name",&e->song.name)) { MARK_MODIFIED
|
||||||
updateWindowTitle();
|
updateWindowTitle();
|
||||||
}
|
}
|
||||||
|
if (e->song.name.size()==27) {
|
||||||
|
unsigned int checker=0x11111111;
|
||||||
|
unsigned int checker1=0;
|
||||||
|
for (int i=0; i<27; i++) {
|
||||||
|
checker^=e->song.name[i]<<i;
|
||||||
|
checker1+=e->song.name[i];
|
||||||
|
checker=(checker>>1|(((checker)^(checker>>2)^(checker>>3)^(checker>>5))&1)<<31);
|
||||||
|
checker1<<=1;
|
||||||
|
}
|
||||||
|
if (checker==0x94ffb4f7 && checker1==0x801c68a6) nonLatchNibble=true;
|
||||||
|
}
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Text("Author");
|
ImGui::Text("Author");
|
||||||
|
|
Loading…
Reference in New Issue