implement several effects

volume slides, vibrato, slides and portamento
This commit is contained in:
tildearrow 2021-05-14 14:16:48 -05:00
parent 775b88dae2
commit eb692ca9a9
6 changed files with 82 additions and 16 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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];

View File

@ -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;

View File

@ -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 {

View File

@ -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