diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index bfdcf6883..6dcb6171e 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -48,7 +48,9 @@ enum DivDispatchCmds { DIV_CMD_ENV_RELEASE, DIV_CMD_INSTRUMENT, // (ins, force) DIV_CMD_VOLUME, // (vol) + // TODO: think of possibly moving this DIV_CMD_GET_VOLUME, // () -> vol + // TODO: move. shouldn't be a command. DIV_CMD_GET_VOLMAX, // () -> volMax DIV_CMD_NOTE_PORTA, // (target, speed) -> 2 if target reached DIV_CMD_PITCH, // (pitch) @@ -589,6 +591,14 @@ class DivDispatch { */ virtual bool isVolGlobal(); + /** + * map MIDI velocity (from 0 to 127) to chip volume. + * @param ch the chip channel. -1 means N/A. + * @param vel input velocity. + * @return output volume. + */ + virtual int mapVelocity(int ch, unsigned char vel); + /** * get the lowest note in a portamento. * @param ch the channel in question. diff --git a/src/engine/engine.h b/src/engine/engine.h index 4ffe7744b..db8cb7b34 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -190,7 +190,7 @@ struct DivNoteEvent { channel(-1), ins(0), note(0), - volume(0), + volume(-1), on(false), nop(true), pad1(false), diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index e0b0229cb..aaa27a494 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -102,6 +102,11 @@ bool DivDispatch::isVolGlobal() { return false; } +int DivDispatch::mapVelocity(int ch, unsigned char vel) { + const int volMax=MAX(1,dispatch(DivCommand(DIV_CMD_GET_VOLMAX,MAX(ch,0)))); + return (vel*volMax)/127; +} + int DivDispatch::getPortaFloor(int ch) { return 0x00; } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 0f90d0ac1..d2a0db179 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1372,7 +1372,11 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { } if (note.on) { dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,note.channel,note.ins,1)); - dispatchCmd(DivCommand(DIV_CMD_VOLUME,note.channel,(note.volume*(chan[note.channel].volMax>>8))/127)); + if (note.volume>=0) { + int mappedVol=disCont[dispatchOfChan[note.channel]].dispatch->mapVelocity(note.channel,note.volume); + logV("dispatching volume (%d -> %d)",note.volume,mappedVol); + dispatchCmd(DivCommand(DIV_CMD_VOLUME,note.channel,mappedVol)); + } dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,note.channel,note.note)); keyHit[note.channel]=true; chan[note.channel].releasing=false;