|  |  | @@ -18,11 +18,12 @@ struct MIDICCToCVInterface : Module { | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | midi::InputQueue midiInput; | 
		
	
		
			
			|  |  |  | int8_t ccs[128]; | 
		
	
		
			
			|  |  |  | int8_t values[128]; | 
		
	
		
			
			|  |  |  | dsp::ExponentialFilter ccFilters[16]; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | int learningId = -1; | 
		
	
		
			
			|  |  |  | int learnedCcs[16] = {}; | 
		
	
		
			
			|  |  |  | bool jump[16] = {}; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | MIDICCToCVInterface() { | 
		
	
		
			
			|  |  |  | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | 
		
	
	
		
			
				|  |  | @@ -31,7 +32,7 @@ struct MIDICCToCVInterface : Module { | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | void onReset() override { | 
		
	
		
			
			|  |  |  | for (int i = 0; i < 128; i++) { | 
		
	
		
			
			|  |  |  | ccs[i] = 0; | 
		
	
		
			
			|  |  |  | values[i] = 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | for (int i = 0; i < 16; i++) { | 
		
	
		
			
			|  |  |  | learnedCcs[i] = i; | 
		
	
	
		
			
				|  |  | @@ -45,12 +46,20 @@ struct MIDICCToCVInterface : Module { | 
		
	
		
			
			|  |  |  | processMessage(msg); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | float lambda = 100.f * app()->engine->getSampleTime(); | 
		
	
		
			
			|  |  |  | float lambda = app()->engine->getSampleTime() * 100.f; | 
		
	
		
			
			|  |  |  | for (int i = 0; i < 16; i++) { | 
		
	
		
			
			|  |  |  | int learnedCc = learnedCcs[i]; | 
		
	
		
			
			|  |  |  | float value = rescale(clamp(ccs[learnedCc], -127, 127), 0, 127, 0.f, 10.f); | 
		
	
		
			
			|  |  |  | float value = rescale(values[learnedCc], 0, 127, 0.f, 10.f); | 
		
	
		
			
			|  |  |  | ccFilters[i].lambda = lambda; | 
		
	
		
			
			|  |  |  | outputs[CC_OUTPUT + i].setVoltage(ccFilters[i].process(value)); | 
		
	
		
			
			|  |  |  | // Smooth value unless we're jumping there | 
		
	
		
			
			|  |  |  | if (jump[i]) { | 
		
	
		
			
			|  |  |  | ccFilters[i].out = value; | 
		
	
		
			
			|  |  |  | jump[i] = false; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | else { | 
		
	
		
			
			|  |  |  | ccFilters[i].process(value); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | outputs[CC_OUTPUT + i].setVoltage(ccFilters[i].out); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -60,13 +69,19 @@ struct MIDICCToCVInterface : Module { | 
		
	
		
			
			|  |  |  | case 0xb: { | 
		
	
		
			
			|  |  |  | uint8_t cc = msg.note(); | 
		
	
		
			
			|  |  |  | // Learn | 
		
	
		
			
			|  |  |  | if (learningId >= 0 && ccs[cc] != msg.data2) { | 
		
	
		
			
			|  |  |  | if (learningId >= 0 && values[cc] != msg.data2) { | 
		
	
		
			
			|  |  |  | learnedCcs[learningId] = cc; | 
		
	
		
			
			|  |  |  | learningId = -1; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | // Set CV | 
		
	
		
			
			|  |  |  | // Allow CC to be negative if the 8th bit is set | 
		
	
		
			
			|  |  |  | ccs[cc] = msg.data2; | 
		
	
		
			
			|  |  |  | int8_t oldValue = values[cc]; | 
		
	
		
			
			|  |  |  | // Allow CC to be negative if the 8th bit is set. | 
		
	
		
			
			|  |  |  | // The gamepad driver abuses this, for example. | 
		
	
		
			
			|  |  |  | int8_t value = msg.data2; | 
		
	
		
			
			|  |  |  | // Detect behavior from MIDI buttons. | 
		
	
		
			
			|  |  |  | // Don't run these through a smoothing filter. | 
		
	
		
			
			|  |  |  | if ((oldValue == 0 && value == 127) || (oldValue == 127 && value == 0)) | 
		
	
		
			
			|  |  |  | jump[cc] = true; | 
		
	
		
			
			|  |  |  | values[cc] = value; | 
		
	
		
			
			|  |  |  | } break; | 
		
	
		
			
			|  |  |  | default: break; | 
		
	
		
			
			|  |  |  | } | 
		
	
	
		
			
				|  |  | 
 |