mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-23 04:55:13 +00:00
apply volExp on velocity input - PLEASE READ
DivDispatch::mapVelocity() now takes a float instead of an unsigned char
This commit is contained in:
parent
99dd85bcb4
commit
51b385a1ef
18 changed files with 39 additions and 24 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -1003,7 +1003,7 @@ struct MIDIMap {
|
|||
valueInputControlMSB(0),
|
||||
valueInputControlLSB(0),
|
||||
valueInputControlSingle(0),
|
||||
volExp(1.0f),
|
||||
volExp(2.0f),
|
||||
valueInputCurMSB(0),
|
||||
valueInputCurLSB(0),
|
||||
valueInputCurSingle(0) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue