apply volExp on velocity input - PLEASE READ

DivDispatch::mapVelocity() now takes a float instead of an unsigned char
This commit is contained in:
tildearrow 2023-12-16 19:52:37 -05:00
parent 99dd85bcb4
commit 51b385a1ef
18 changed files with 39 additions and 24 deletions

View file

@ -594,10 +594,10 @@ class DivDispatch {
/**
* map MIDI velocity (from 0 to 127) to chip volume.
* @param ch the chip channel. -1 means N/A.
* @param vel input velocity.
* @param vel input velocity, from 0.0 to 1.0.
* @return output volume.
*/
virtual int mapVelocity(int ch, unsigned char vel);
virtual int mapVelocity(int ch, float vel);
/**
* get the lowest note in a portamento.

View file

@ -3385,6 +3385,10 @@ void DivEngine::setMidiDirect(bool value) {
midiIsDirect=value;
}
void DivEngine::setMidiVolExp(float value) {
midiVolExp=value;
}
void DivEngine::setMidiCallback(std::function<int(const TAMidiMessage&)> what) {
midiCallback=what;
}

View file

@ -423,6 +423,7 @@ class DivEngine {
bool midiOutProgramChange;
int midiOutMode;
int midiOutTimeRate;
float midiVolExp;
int softLockCount;
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats, curSpeed;
size_t curSubSongIndex;
@ -1184,6 +1185,9 @@ class DivEngine {
// set MIDI direct channel map
void setMidiDirect(bool value);
// set MIDI volume curve exponent
void setMidiVolExp(float value);
// set MIDI input callback
// if the specified function returns -2, note feedback will be inhibited.
void setMidiCallback(std::function<int(const TAMidiMessage&)> what);
@ -1261,6 +1265,7 @@ class DivEngine {
midiOutProgramChange(false),
midiOutMode(DIV_MIDI_MODE_NOTE),
midiOutTimeRate(0),
midiVolExp(2.0f), // General MIDI standard
softLockCount(0),
subticks(0),
ticks(0),

View file

@ -102,9 +102,9 @@ bool DivDispatch::isVolGlobal() {
return false;
}
int DivDispatch::mapVelocity(int ch, unsigned char vel) {
int DivDispatch::mapVelocity(int ch, float vel) {
const int volMax=MAX(1,dispatch(DivCommand(DIV_CMD_GET_VOLMAX,MAX(ch,0))));
return (vel*volMax)/127;
return round(vel*volMax);
}
int DivDispatch::getPortaFloor(int ch) {

View file

@ -719,8 +719,8 @@ DivDispatchOscBuffer* DivPlatformAY8910::getOscBuffer(int ch) {
return oscBuf[ch];
}
int DivPlatformAY8910::mapVelocity(int ch, unsigned char vel) {
return round(15.0*pow(((double)vel/127.0),0.33));
int DivPlatformAY8910::mapVelocity(int ch, float vel) {
return round(15.0*pow(vel,0.33));
}
unsigned char* DivPlatformAY8910::getRegisterPool() {

View file

@ -131,7 +131,7 @@ class DivPlatformAY8910: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
int mapVelocity(int ch, unsigned char vel);
int mapVelocity(int ch, float vel);
unsigned char* getRegisterPool();
int getRegisterPoolSize();
void flushWrites();

View file

@ -718,8 +718,8 @@ DivDispatchOscBuffer* DivPlatformAY8930::getOscBuffer(int ch) {
return oscBuf[ch];
}
int DivPlatformAY8930::mapVelocity(int ch, unsigned char vel) {
return round(31.0*pow(((double)vel/127.0),0.22));
int DivPlatformAY8930::mapVelocity(int ch, float vel) {
return round(31.0*pow(vel,0.22));
}
unsigned char* DivPlatformAY8930::getRegisterPool() {

View file

@ -132,7 +132,7 @@ class DivPlatformAY8930: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
int mapVelocity(int ch, unsigned char vel);
int mapVelocity(int ch, float vel);
unsigned char* getRegisterPool();
int getRegisterPoolSize();
void reset();

View file

@ -122,7 +122,7 @@ class DivPlatformFMBase: public DivDispatch {
}
}
virtual int mapVelocity(int ch, unsigned char vel) {
virtual int mapVelocity(int ch, float vel) {
// -0.75dB per step
// -6: 64: 8
// -12: 32: 16
@ -133,7 +133,7 @@ class DivPlatformFMBase: public DivDispatch {
// -42: 1: 56
if (vel==0) return 0;
if (vel==127) return 127;
return CLAMP(round(128.0-(56.0-log2(vel)*8.0)),0,127);
return CLAMP(round(128.0-(56.0-log2(vel*127.0)*8.0)),0,127);
}
friend void putDispatchChan(void*,int,int);

View file

@ -539,8 +539,8 @@ DivDispatchOscBuffer* DivPlatformPCE::getOscBuffer(int ch) {
return oscBuf[ch];
}
int DivPlatformPCE::mapVelocity(int ch, unsigned char vel) {
return round(31.0*pow(((double)vel/127.0),0.22));
int DivPlatformPCE::mapVelocity(int ch, float vel) {
return round(31.0*pow(vel,0.22));
}
unsigned char* DivPlatformPCE::getRegisterPool() {

View file

@ -86,7 +86,7 @@ class DivPlatformPCE: public DivDispatch {
DivChannelModeHints getModeHints(int chan);
DivSamplePos getSamplePos(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
int mapVelocity(int ch, unsigned char vel);
int mapVelocity(int ch, float vel);
unsigned char* getRegisterPool();
int getRegisterPoolSize();
void reset();

View file

@ -462,8 +462,8 @@ DivDispatchOscBuffer* DivPlatformSMS::getOscBuffer(int ch) {
return oscBuf[ch];
}
int DivPlatformSMS::mapVelocity(int ch, unsigned char vel) {
return round(15.0*pow(((double)vel/127.0),0.33));
int DivPlatformSMS::mapVelocity(int ch, float vel) {
return round(15.0*pow(vel,0.33));
}
unsigned char* DivPlatformSMS::getRegisterPool() {

View file

@ -79,7 +79,7 @@ class DivPlatformSMS: public DivDispatch {
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
int mapVelocity(int ch, unsigned char vel);
int mapVelocity(int ch, float vel);
unsigned char* getRegisterPool();
int getRegisterPoolSize();
void reset();

View file

@ -308,8 +308,8 @@ DivDispatchOscBuffer* DivPlatformT6W28::getOscBuffer(int ch) {
return oscBuf[ch];
}
int DivPlatformT6W28::mapVelocity(int ch, unsigned char vel) {
return round(15.0*pow(((double)vel/127.0),0.33));
int DivPlatformT6W28::mapVelocity(int ch, float vel) {
return round(15.0*pow(vel,0.33));
}
unsigned char* DivPlatformT6W28::getRegisterPool() {

View file

@ -65,7 +65,7 @@ class DivPlatformT6W28: public DivDispatch {
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
int mapVelocity(int ch, unsigned char vel);
int mapVelocity(int ch, float vel);
unsigned char* getRegisterPool();
int getRegisterPoolSize();
void reset();

View file

@ -1373,7 +1373,8 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
if (note.on) {
dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,note.channel,note.ins,1));
if (note.volume>=0 && !disCont[dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
int mappedVol=disCont[dispatchOfChan[note.channel]].dispatch->mapVelocity(dispatchChanOfChan[note.channel],note.volume);
float curvedVol=pow((float)note.volume/127.0f,midiVolExp);
int mappedVol=disCont[dispatchOfChan[note.channel]].dispatch->mapVelocity(dispatchChanOfChan[note.channel],curvedVol);
logV("dispatching volume (%d -> %d)",note.volume,mappedVol);
dispatchCmd(DivCommand(DIV_CMD_VOLUME,note.channel,mappedVol));
}

View file

@ -1003,7 +1003,7 @@ struct MIDIMap {
valueInputControlMSB(0),
valueInputControlLSB(0),
valueInputControlSingle(0),
volExp(1.0f),
volExp(2.0f),
valueInputCurMSB(0),
valueInputCurLSB(0),
valueInputCurSingle(0) {

View file

@ -1139,7 +1139,10 @@ void FurnaceGUI::drawSettings() {
// TODO
//ImGui::Checkbox("Use raw velocity value (don't map from linear to log)",&midiMap.rawVolume);
//ImGui::Checkbox("Polyphonic/chord input",&midiMap.polyInput);
if (ImGui::Checkbox("Map MIDI channels to direct channels",&midiMap.directChannel)) settingsChanged=true;
if (ImGui::Checkbox("Map MIDI channels to direct channels",&midiMap.directChannel)) {
e->setMidiDirect(midiMap.directChannel);
settingsChanged=true;
}
if (ImGui::Checkbox("Map Yamaha FM voice data to instruments",&midiMap.yamahaFMResponse)) settingsChanged=true;
if (ImGui::Checkbox("Program change is instrument selection",&midiMap.programChange)) settingsChanged=true;
//ImGui::Checkbox("Listen to MIDI clock",&midiMap.midiClock);
@ -1198,6 +1201,7 @@ void FurnaceGUI::drawSettings() {
if (ImGui::SliderFloat("Volume curve",&midiMap.volExp,0.01,8.0,"%.2f")) {
if (midiMap.volExp<0.01) midiMap.volExp=0.01;
if (midiMap.volExp>8.0) midiMap.volExp=8.0;
e->setMidiVolExp(midiMap.volExp);
settingsChanged=true;
} rightClickable
float curve[128];
@ -4025,6 +4029,7 @@ void FurnaceGUI::syncSettings() {
midiMap.compile();
e->setMidiDirect(midiMap.directChannel);
e->setMidiVolExp(midiMap.volExp);
e->setMetronomeVol(((float)settings.metroVol)/100.0f);
e->setSamplePreviewVol(((float)settings.sampleVol)/100.0f);
}