ok, some more 'accurate' results...
(these scales give 'acceptable' in tune results, over at least 5 octaves)
test 1
midi -> cv out -> MI : Plaits Oscillator -> tuner
output scale factor 0.911484
this scale seemed "good" for all cv outs (both salt and salt+) ,
but its noticeable each cv out has a slightly different offset, but less than a semitone when converted to a pitch.
as mentioned before offset required is unimportant , as usually the target oscillator etc, will have a offset adjustment.
test 2a
all on salt
midi -> cv out (salt) -> cv in -> SinOsc ->tuner
input scale factor 1.00395
ok, theoretically , offset is useful here BUT since we have a hardwire offset with the pots in practice its again unimportant.
test 2b
Squarp Pyramid CV out -> cv in -> SinOsc -> tuner
input scale factor 1.00245
(again, offset unimportant, due to hardwire pot)
test 3
Squarp Pyramid -> MI : Plaits Oscillator -> tuner
this was to give an indication of how well the Pyramid track (test 2b) and MI Plaits (test 1), to see how they might have influenced calibration.
generally they track very well together, not 100% perfect, there probably is a tiny scaling factory required.
but much smaller than the above...
unfortunately, as i don't have another accurate pitch tracking CV generator nor, oscillator, I cant really say which introduces the error, it could be one or both 😉
but i think it's negligible.
conclusion
offsets are pretty irrelevant, though they theoretically reduce your CV range.
theres a bit of scaling on input... circa 1.003
output scaling is more significantly ~0.911. (it might be a touch less, given diff of test 2a.b)
Im pretty confident of these numbers as test 2a/2b/3 show inputs as fairly accurate.
of course this is only one salt/salt+ it may be other units vary..
It would be more accurate/easier to do this test by measuring voltages, but you need a well calibrated voltmeter/oscilloscope to get decent results.
this is the code i used, which i ran interactively, altering it for bits of the tests (hence lines commented out)
MIDIClient.init;
MIDIIn.connectAll;
// input
~sw_in=6;
~t1_in=15;
~t2_in=14;
~t3_in=1;
~t4_in=3;
// output
~led_pwm=7;
~led1=2;
~led2=4;
~led3=8;
~led4=9;
~t1_out=0;
~t2_out=5;
~t3_out=12;
~t4_out=13;
Ndef(\led_pwm,{DigitalIO.ar(~led_pwm, pinMode:1, output:LFPulse.ar( freq:(44100/32), width: 0.5))});
// 0.911484 cvout
// 1.00395 cvout -> cvin
// 1.00245 pyramid ->cvin
g = Group.new;
g.freeAll;
(
SynthDef (\cvio, {
arg ipin,note=64;
// var m = 0.911484;
var mul = AnalogIn.kr(2);
var add = AnalogIn.kr(3);
// var m = 1.00395; // cvout > cvin
// var c = 0.0;
var m = (mul / 10.0) + 1.0;
var c = (add - 0.5) / 10.0;
// var vout = (note.linlin(0,120,0,1) * m ) + c;
var vin = AnalogIn.kr(ipin);
// var diff = vout - vin;
// vin.poll(0.1, label:\vin);
// diff.poll(0.1, label:\diff);
var v = ((vin * m ) + c );
var notein = v.linlin(0,1,0,120);
// var freq = notein.midicps;
var freq = (notein - 24).midicps;
var sig = SinOsc.ar(freq);
m.poll(0.1,label:\mul);
c.poll(0.1,label:\add);
v.poll(0.1,label:\volt);
Out.ar(0,sig);
}).add;
)
~synthtest.free;
~synthtest= Synth(\cvio,[\ipin, 0],g);
(
SynthDef(\cvout, {
arg opin, tpin, lpin, gate=0,note=64;
// var mul = AnalogIn.kr(0);
// var add = AnalogIn.kr(1);
// var m = (mul + 0.5 );
// var c = add;
var m = 0.911484;
var c = 0.0;
var v = (note.linlin(0,120,0,1) * m ) + c;
// m.poll(0.1,label:\mul);
// c.poll(0.1,label:\add);
// v.poll(0.1,label:\volt);
AnalogOut.kr(opin,v);
DigitalIO.kr(tpin,output:gate, pinMode:1 );
DigitalIO.kr(lpin,output:0, pinMode:gate );
}).add;
)
~synths = [
Synth(\cvout,[\opin, 7, \tpin, ~t1_out, \lpin, ~led1],g),
];
MIDIdef.noteOn(\noteon, {
arg vel, note, chan;
~synths[0].set(\note, note);
~synths[0].set(\gate, vel>0);
~synthtest.set(\note, note);
});
MIDIdef.noteOff(\noteoff, {
arg vel, note, chan;
~synths[0].set(\note, note);
~synths[0].set(\gate, 0);
});