implement several effects
volume slides, vibrato, slides and portamento
This commit is contained in:
parent
775b88dae2
commit
eb692ca9a9
|
@ -15,15 +15,23 @@ enum DivDispatchCmds {
|
|||
|
||||
struct DivCommand {
|
||||
DivDispatchCmds cmd;
|
||||
unsigned char chan, value;
|
||||
DivCommand(DivDispatchCmds c, unsigned char ch, unsigned char val):
|
||||
unsigned char chan;
|
||||
int value, value2;
|
||||
DivCommand(DivDispatchCmds c, unsigned char ch, int val, int val2):
|
||||
cmd(c),
|
||||
chan(ch),
|
||||
value(val) {}
|
||||
value(val),
|
||||
value2(val2) {}
|
||||
DivCommand(DivDispatchCmds c, unsigned char ch, int val):
|
||||
cmd(c),
|
||||
chan(ch),
|
||||
value(val),
|
||||
value2(0) {}
|
||||
DivCommand(DivDispatchCmds c, unsigned char ch):
|
||||
cmd(c),
|
||||
chan(ch),
|
||||
value(0) {}
|
||||
value(0),
|
||||
value2(0) {}
|
||||
};
|
||||
|
||||
struct DivDelayedCommand {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "../audio/sdl.h"
|
||||
#include "platform/genesis.h"
|
||||
#include "platform/dummy.h"
|
||||
#include <math.h>
|
||||
#include <zlib.h>
|
||||
|
||||
void process(void* u, float** in, float** out, int inChans, int outChans, unsigned int size) {
|
||||
|
@ -662,6 +663,10 @@ bool DivEngine::init() {
|
|||
bbOut[0]=new short[got.bufsize];
|
||||
bbOut[1]=new short[got.bufsize];
|
||||
|
||||
for (int i=0; i<60; i++) {
|
||||
vibTable[i]=127*sin(((double)i/60.0)*(2*M_PI));
|
||||
}
|
||||
|
||||
switch (song.system) {
|
||||
case DIV_SYSTEM_GENESIS:
|
||||
dispatch=new DivPlatformGenesis;
|
||||
|
|
|
@ -9,8 +9,9 @@ struct DivChannelState {
|
|||
std::vector<DivDelayedCommand> delayed;
|
||||
int note, pitch, portaSpeed, portaNote;
|
||||
int volume, volSpeed;
|
||||
int vibratoDepth, vibratoRate;
|
||||
int tremoloDepth, tremoloRate;
|
||||
int vibratoDepth, vibratoRate, vibratoPos;
|
||||
int tremoloDepth, tremoloRate, tremoloPos;
|
||||
bool doNote;
|
||||
|
||||
DivChannelState():
|
||||
note(-1),
|
||||
|
@ -21,8 +22,11 @@ struct DivChannelState {
|
|||
volSpeed(0),
|
||||
vibratoDepth(0),
|
||||
vibratoRate(0),
|
||||
vibratoPos(0),
|
||||
tremoloDepth(0),
|
||||
tremoloRate(0) {}
|
||||
tremoloRate(0),
|
||||
tremoloPos(0),
|
||||
doNote(false) {}
|
||||
};
|
||||
|
||||
class DivEngine {
|
||||
|
@ -36,6 +40,8 @@ class DivEngine {
|
|||
int changeOrd, changePos;
|
||||
DivChannelState chan[17];
|
||||
|
||||
short vibTable[60];
|
||||
|
||||
blip_buffer_t* bb[2];
|
||||
short temp[2], prevSample[2];
|
||||
short* bbOut[2];
|
||||
|
|
|
@ -160,7 +160,8 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
rWrite(chanOffs[c.chan]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
|
||||
rWrite(chanOffs[c.chan]+0xb4,(chan[c.chan].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
}
|
||||
chan[c.chan].freq=644.0f*pow(2.0f,((float)c.value/12.0f));
|
||||
chan[c.chan].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f));
|
||||
chan[c.chan].freq=(chan[c.chan].baseFreq*(2048+chan[c.chan].pitch))>>11;
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].active=true;
|
||||
|
@ -206,6 +207,33 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
rWrite(chanOffs[c.chan]+0xb4,(chan[c.chan].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PITCH: {
|
||||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freq=(chan[c.chan].baseFreq*(2048+chan[c.chan].pitch))>>11;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=644.0f*pow(2.0f,((float)c.value2/12.0f));
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq=(chan[c.chan].baseFreq*(960+c.value))/960;
|
||||
if (chan[c.chan].baseFreq>=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq=(chan[c.chan].baseFreq*(960-c.value))/960;
|
||||
if (chan[c.chan].baseFreq<=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].freq=(chan[c.chan].baseFreq*(2048+chan[c.chan].pitch))>>11;
|
||||
chan[c.chan].freqChanged=true;
|
||||
if (return2) return 2;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_MODE: {
|
||||
if (c.chan==5) {
|
||||
dacMode=c.value;
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
class DivPlatformGenesis: public DivDispatch {
|
||||
struct Channel {
|
||||
unsigned char freqH, freqL;
|
||||
int freq;
|
||||
int freq, baseFreq, pitch;
|
||||
unsigned char ins;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff;
|
||||
signed char vol;
|
||||
unsigned char pan;
|
||||
Channel(): freqH(0), freqL(0), freq(0), ins(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), vol(0), pan(3) {}
|
||||
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), vol(0), pan(3) {}
|
||||
};
|
||||
Channel chan[10];
|
||||
struct QueuedWrite {
|
||||
|
|
|
@ -107,7 +107,7 @@ void DivEngine::nextRow() {
|
|||
dispatch->dispatch(DivCommand(DIV_CMD_NOTE_OFF,i));
|
||||
} else if (!(pat->data[curRow][0]==0 && pat->data[curRow][1]==0)) {
|
||||
chan[i].note=pat->data[curRow][0]+pat->data[curRow][1]*12;
|
||||
dispatch->dispatch(DivCommand(DIV_CMD_NOTE_ON,i,chan[i].note));
|
||||
chan[i].doNote=true;
|
||||
}
|
||||
|
||||
// volume
|
||||
|
@ -118,8 +118,8 @@ void DivEngine::nextRow() {
|
|||
|
||||
// effects
|
||||
for (int j=0; j<song.pat[i]->effectRows; j++) {
|
||||
unsigned char effect=pat->data[curRow][4+(j<<1)];
|
||||
unsigned char effectVal=pat->data[curRow][5+(j<<1)];
|
||||
short effect=pat->data[curRow][4+(j<<1)];
|
||||
short effectVal=pat->data[curRow][5+(j<<1)];
|
||||
|
||||
if (effectVal==-1) effectVal=0;
|
||||
|
||||
|
@ -147,7 +147,7 @@ void DivEngine::nextRow() {
|
|||
chan[i].portaNote=-1;
|
||||
chan[i].portaSpeed=-1;
|
||||
} else {
|
||||
chan[i].portaNote=0x7f;
|
||||
chan[i].portaNote=0x60;
|
||||
chan[i].portaSpeed=effectVal;
|
||||
}
|
||||
break;
|
||||
|
@ -167,11 +167,13 @@ void DivEngine::nextRow() {
|
|||
} else {
|
||||
chan[i].portaNote=chan[i].note;
|
||||
chan[i].portaSpeed=effectVal;
|
||||
chan[i].doNote=false;
|
||||
}
|
||||
break;
|
||||
case 0x04: // vibrato
|
||||
chan[i].vibratoDepth=effectVal&15;
|
||||
chan[i].vibratoRate=effectVal>>4;
|
||||
dispatch->dispatch(DivCommand(DIV_CMD_PITCH,i,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos])>>4));
|
||||
break;
|
||||
case 0x0a: // volume ramp
|
||||
if (effectVal!=0) {
|
||||
|
@ -187,17 +189,24 @@ void DivEngine::nextRow() {
|
|||
|
||||
case 0xe1: // portamento up
|
||||
chan[i].portaNote=chan[i].note+(effectVal&15);
|
||||
chan[i].portaSpeed=effectVal>>4;
|
||||
chan[i].portaSpeed=(effectVal>>4)*3;
|
||||
break;
|
||||
case 0xe2: // portamento down
|
||||
chan[i].portaNote=chan[i].note-(effectVal&15);
|
||||
chan[i].portaSpeed=effectVal>>4;
|
||||
chan[i].portaSpeed=(effectVal>>4)*3;
|
||||
break;
|
||||
case 0xe5: // pitch
|
||||
chan[i].pitch=effectVal-0x80;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].doNote) {
|
||||
chan[i].vibratoPos=0;
|
||||
dispatch->dispatch(DivCommand(DIV_CMD_PITCH,i,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos])>>2));
|
||||
dispatch->dispatch(DivCommand(DIV_CMD_NOTE_ON,i,chan[i].note));
|
||||
chan[i].doNote=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,6 +237,16 @@ void DivEngine::nextTick() {
|
|||
if (chan[i].volume<0) chan[i].volume=0;
|
||||
dispatch->dispatch(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||
}
|
||||
if (chan[i].vibratoDepth>0) {
|
||||
chan[i].vibratoPos+=chan[i].vibratoRate;
|
||||
if (chan[i].vibratoPos>=60) chan[i].vibratoPos-=60;
|
||||
dispatch->dispatch(DivCommand(DIV_CMD_PITCH,i,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos])>>4));
|
||||
}
|
||||
if (chan[i].portaSpeed>0) {
|
||||
if (dispatch->dispatch(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed,chan[i].portaNote))==2) {
|
||||
chan[i].portaSpeed=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// system tick
|
||||
|
|
Loading…
Reference in New Issue