detuning

227 views
Skip to first unread message

Daniel Llermaly

unread,
Oct 3, 2023, 2:11:14 AM10/3/23
to Mozzi-users
Hello everyone in the group
I wanted to ask you a question regarding tuning in Mozzi.
I have been playing with the code of the hagiwo chords v1 module to be able to add a quantizer, what I did was read the reading values of the potentiometer and map them only to the frequencies of the chromatic scale tempered at 440
but when playing the 440, and any note, I have a small detuning, which is corrected if I increase the frequency by about 2Hz.
The module uses hifi mode
What is the cause of this detuning? It is normal?

greetings and thank you very much

tomco...@live.fr

unread,
Oct 3, 2023, 3:18:23 PM10/3/23
to Mozzi-users
Hi and welcome!
No, it isn't normal. From what I read, this module is based on an Nano v3, embedding an Atmega 328, something similar (?) than what is on the Uno if I am not mistaken, which is a widely use board. I am a bit surprised if such a drift would have gone unnoticed for so long but, that being said, this platform did not received lot of testing recently. I am also wondering on the fact that the drift seems to be systematic and not proportional to the frequency.
Will try to do some tests here soon with what I have at hand but in the meantime, would it be possible for you to provide these information:
 - are you using a genuine Arduino or something else (I do not have anything against that, just trying to narrow the causes like a mistuned oscillator)?
 - would it be possible to provide a minimal code displaying this malfunction?

Best,
Thomas

Daniel Llermaly

unread,
Oct 3, 2023, 3:49:03 PM10/3/23
to Mozzi-users
Hi Thomas, thank you very much for the response.
I am using a Chinese clone of the Arduino, can that affect me?

Below I am going to copy the code that I started working on to add a quantizer, just map the frequency values to the frequencies of the notes, the rest is the same as the original

#include <MozziGuts.h>
#include <mozzi_midi.h>
#include <Oscil.h> // oscillator template

#include <tables/saw2048_int8.h> // saw table for oscillator
#include <tables/square_no_alias512_int8.h> // saw table for oscillator
#include <tables/triangle_hermes_2048_int8.h> // saw table for oscillator
#include <tables/sin2048_int8.h> // sine table for oscillator
#include <tables/waveshape_chebyshev_3rd_256_int8.h> // sine table for oscillator
#include <tables/halfsin256_uint8.h> // sine table for oscillator
#include <tables/waveshape_sigmoid_int8.h> // sine table for oscillator
#include <tables/phasor256_int8.h> // sine table for oscillator

Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw1(SAW2048_DATA);
Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw2(SAW2048_DATA);
Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw3(SAW2048_DATA);
Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw4(SAW2048_DATA);
Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw5(SAW2048_DATA);

Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu1(SQUARE_NO_ALIAS512_DATA);
Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu2(SQUARE_NO_ALIAS512_DATA);
Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu3(SQUARE_NO_ALIAS512_DATA);
Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu4(SQUARE_NO_ALIAS512_DATA);
Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu5(SQUARE_NO_ALIAS512_DATA);

Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri1(TRIANGLE_HERMES_2048_DATA);
Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri2(TRIANGLE_HERMES_2048_DATA);
Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri3(TRIANGLE_HERMES_2048_DATA);
Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri4(TRIANGLE_HERMES_2048_DATA);
Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri5(TRIANGLE_HERMES_2048_DATA);

Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin1(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin2(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin3(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin4(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin5(SIN2048_DATA);

Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb1(CHEBYSHEV_3RD_256_DATA);
Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb2(CHEBYSHEV_3RD_256_DATA);
Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb3(CHEBYSHEV_3RD_256_DATA);
Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb4(CHEBYSHEV_3RD_256_DATA);
Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb5(CHEBYSHEV_3RD_256_DATA);

Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin1(HALFSIN256_DATA);
Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin2(HALFSIN256_DATA);
Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin3(HALFSIN256_DATA);
Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin4(HALFSIN256_DATA);
Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin5(HALFSIN256_DATA);

Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig1(WAVESHAPE_SIGMOID_DATA);
Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig2(WAVESHAPE_SIGMOID_DATA);
Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig3(WAVESHAPE_SIGMOID_DATA);
Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig4(WAVESHAPE_SIGMOID_DATA);
Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig5(WAVESHAPE_SIGMOID_DATA);

Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha1(PHASOR256_DATA);
Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha2(PHASOR256_DATA);
Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha3(PHASOR256_DATA);
Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha4(PHASOR256_DATA);
Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha5(PHASOR256_DATA);
#define CONTROL_RATE 128 // Hz, powers of 2 are most reliable
float freq1 = 110;//base freq
int freqi = 110;//base freq
const static float notas[13] = {132.00, 138.59, 147.83, 156.56, 166.00, 175.61, 184.99, 196.00, 207.65, 220.00, 233.08, 246.94, 261.63};

int voct = 1000;//external V/OCT LSB

int freqv1 = 440;//apply voct
int freqv2 = 440;
int freqv3 = 440;
int freqv4 = 440;
int freqv5 = 440;

byte note1 = 0;//Root
byte note2 = 0;//2nd
byte note3 = 0;//3rd
byte note4 = 0;//4th
byte note5 = 0;//Root

byte inv_aply1 = 0; //0 = no inv , 1 = inv , Root
byte inv_aply2 = 0; //2nd
byte inv_aply3 = 0; //3rd
byte inv_aply4 = 0; //4th
bool inv_aply5 = 0; //0 = no output root sound , 1 = output root sound

int inv = 0;
int inv_knob = 0;
int chord = 0;
byte wave = 0;//0=saw,1=squ,2=tri,3=sin,etc...

const static float voctpow[1024] PROGMEM = {
 0,  0.004882, 0.009765, 0.014648, 0.019531, 0.024414, 0.029296, 0.034179, 0.039062, 0.043945, 0.048828, 0.05371,  0.058593, 0.063476, 0.068359, 0.073242, 0.078125, 0.083007, 0.08789,  0.092773, 0.097656, 0.102539, 0.107421, 0.112304, 0.117187, 0.12207,  0.126953, 0.131835, 0.136718, 0.141601, 0.146484, 0.151367, 0.15625,  0.161132, 0.166015, 0.170898, 0.175781, 0.180664, 0.185546, 0.190429, 0.195312, 0.200195, 0.205078, 0.20996,  0.214843, 0.219726, 0.224609, 0.229492, 0.234375, 0.239257, 0.24414,  0.249023, 0.253906, 0.258789, 0.263671, 0.268554, 0.273437, 0.27832,  0.283203, 0.288085, 0.292968, 0.297851, 0.302734, 0.307617, 0.3125, 0.317382, 0.322265, 0.327148, 0.332031, 0.336914, 0.341796, 0.346679, 0.351562, 0.356445, 0.361328, 0.36621,  0.371093, 0.375976, 0.380859, 0.385742, 0.390625, 0.395507, 0.40039,  0.405273, 0.410156, 0.415039, 0.419921, 0.424804, 0.429687, 0.43457,  0.439453, 0.444335, 0.449218, 0.454101, 0.458984, 0.463867, 0.46875,  0.473632, 0.478515, 0.483398, 0.488281, 0.493164, 0.498046, 0.502929, 0.507812, 0.512695, 0.517578, 0.52246,  0.527343, 0.532226, 0.537109, 0.541992, 0.546875, 0.551757, 0.55664,  0.561523, 0.566406, 0.571289, 0.576171, 0.581054, 0.585937, 0.59082,  0.595703, 0.600585, 0.605468, 0.610351, 0.615234, 0.620117, 0.625,  0.629882, 0.634765, 0.639648, 0.644531, 0.649414, 0.654296, 0.659179, 0.664062, 0.668945, 0.673828, 0.67871,  0.683593, 0.688476, 0.693359, 0.698242, 0.703125, 0.708007, 0.71289,  0.717773, 0.722656, 0.727539, 0.732421, 0.737304, 0.742187, 0.74707,  0.751953, 0.756835, 0.761718, 0.766601, 0.771484, 0.776367, 0.78125,  0.786132, 0.791015, 0.795898, 0.800781, 0.805664, 0.810546, 0.815429, 0.820312, 0.825195, 0.830078, 0.83496,  0.839843, 0.844726, 0.849609, 0.854492, 0.859375, 0.864257, 0.86914,  0.874023, 0.878906, 0.883789, 0.888671, 0.893554, 0.898437, 0.90332,  0.908203, 0.913085, 0.917968, 0.922851, 0.927734, 0.932617, 0.9375, 0.942382, 0.947265, 0.952148, 0.957031, 0.961914, 0.966796, 0.971679, 0.976562, 0.981445, 0.986328, 0.99121,  0.996093, 1.000976, 1.005859, 1.010742, 1.015625, 1.020507, 1.02539,  1.030273, 1.035156, 1.040039, 1.044921, 1.049804, 1.054687, 1.05957,  1.064453, 1.069335, 1.074218, 1.079101, 1.083984, 1.088867, 1.09375,  1.098632, 1.103515, 1.108398, 1.113281, 1.118164, 1.123046, 1.127929, 1.132812, 1.137695, 1.142578, 1.14746,  1.152343, 1.157226, 1.162109, 1.166992, 1.171875, 1.176757, 1.18164,  1.186523, 1.191406, 1.196289, 1.201171, 1.206054, 1.210937, 1.21582,  1.220703, 1.225585, 1.230468, 1.235351, 1.240234, 1.245117, 1.25, 1.254882, 1.259765, 1.264648, 1.269531, 1.274414, 1.279296, 1.284179, 1.289062, 1.293945, 1.298828, 1.30371,  1.308593, 1.313476, 1.318359, 1.323242, 1.328125, 1.333007, 1.33789,  1.342773, 1.347656, 1.352539, 1.357421, 1.362304, 1.367187, 1.37207,  1.376953, 1.381835, 1.386718, 1.391601, 1.396484, 1.401367, 1.40625,  1.411132, 1.416015, 1.420898, 1.425781, 1.430664, 1.435546, 1.440429, 1.445312, 1.450195, 1.455078, 1.45996,  1.464843, 1.469726, 1.474609, 1.479492, 1.484375, 1.489257, 1.49414,  1.499023, 1.503906, 1.508789, 1.513671, 1.518554, 1.523437, 1.52832,  1.533203, 1.538085, 1.542968, 1.547851, 1.552734, 1.557617, 1.5625, 1.567382, 1.572265, 1.577148, 1.582031, 1.586914, 1.591796, 1.596679, 1.601562, 1.606445, 1.611328, 1.61621,  1.621093, 1.625976, 1.630859, 1.635742, 1.640625, 1.645507, 1.65039,  1.655273, 1.660156, 1.665039, 1.669921, 1.674804, 1.679687, 1.68457,  1.689453, 1.694335, 1.699218, 1.704101, 1.708984, 1.713867, 1.71875,  1.723632, 1.728515, 1.733398, 1.738281, 1.743164, 1.748046, 1.752929, 1.757812, 1.762695, 1.767578, 1.77246,  1.777343, 1.782226, 1.787109, 1.791992, 1.796875, 1.801757, 1.80664,  1.811523, 1.816406, 1.821289, 1.826171, 1.831054, 1.835937, 1.84082,  1.845703, 1.850585, 1.855468, 1.860351, 1.865234, 1.870117, 1.875,  1.879882, 1.884765, 1.889648, 1.894531, 1.899414, 1.904296, 1.909179, 1.914062, 1.918945, 1.923828, 1.92871,  1.933593, 1.938476, 1.943359, 1.948242, 1.953125, 1.958007, 1.96289,  1.967773, 1.972656, 1.977539, 1.982421, 1.987304, 1.992187, 1.99707,  2.001953, 2.006835, 2.011718, 2.016601, 2.021484, 2.026367, 2.03125,  2.036132, 2.041015, 2.045898, 2.050781, 2.055664, 2.060546, 2.065429, 2.070312, 2.075195, 2.080078, 2.08496,  2.089843, 2.094726, 2.099609, 2.104492, 2.109375, 2.114257, 2.11914,  2.124023, 2.128906, 2.133789, 2.138671, 2.143554, 2.148437, 2.15332,  2.158203, 2.163085, 2.167968, 2.172851, 2.177734, 2.182617, 2.1875, 2.192382, 2.197265, 2.202148, 2.207031, 2.211914, 2.216796, 2.221679, 2.226562, 2.231445, 2.236328, 2.24121,  2.246093, 2.250976, 2.255859, 2.260742, 2.265625, 2.270507, 2.27539,  2.280273, 2.285156, 2.290039, 2.294921, 2.299804, 2.304687, 2.30957,  2.314453, 2.319335, 2.324218, 2.329101, 2.333984, 2.338867, 2.34375,  2.348632, 2.353515, 2.358398, 2.363281, 2.368164, 2.373046, 2.377929, 2.382812, 2.387695, 2.392578, 2.39746,  2.402343, 2.407226, 2.412109, 2.416992, 2.421875, 2.426757, 2.43164,  2.436523, 2.441406, 2.446289, 2.451171, 2.456054, 2.460937, 2.46582,  2.470703, 2.475585, 2.480468, 2.485351, 2.490234, 2.495117, 2.5,  2.504882, 2.509765, 2.514648, 2.519531, 2.524414, 2.529296, 2.534179, 2.539062, 2.543945, 2.548828, 2.55371,  2.558593, 2.563476, 2.568359, 2.573242, 2.578125, 2.583007, 2.58789,  2.592773, 2.597656, 2.602539, 2.607421, 2.612304, 2.617187, 2.62207,  2.626953, 2.631835, 2.636718, 2.641601, 2.646484, 2.651367, 2.65625,  2.661132, 2.666015, 2.670898, 2.675781, 2.680664, 2.685546, 2.690429, 2.695312, 2.700195, 2.705078, 2.70996,  2.714843, 2.719726, 2.724609, 2.729492, 2.734375, 2.739257, 2.74414,  2.749023, 2.753906, 2.758789, 2.763671, 2.768554, 2.773437, 2.77832,  2.783203, 2.788085, 2.792968, 2.797851, 2.802734, 2.807617, 2.8125, 2.817382, 2.822265, 2.827148, 2.832031, 2.836914, 2.841796, 2.846679, 2.851562, 2.856445, 2.861328, 2.86621,  2.871093, 2.875976, 2.880859, 2.885742, 2.890625, 2.895507, 2.90039,  2.905273, 2.910156, 2.915039, 2.919921, 2.924804, 2.929687, 2.93457,  2.939453, 2.944335, 2.949218, 2.954101, 2.958984, 2.963867, 2.96875,  2.973632, 2.978515, 2.983398, 2.988281, 2.993164, 2.998046, 3.002929, 3.007812, 3.012695, 3.017578, 3.02246,  3.027343, 3.032226, 3.037109, 3.041992, 3.046875, 3.051757, 3.05664,  3.061523, 3.066406, 3.071289, 3.076171, 3.081054, 3.085937, 3.09082,  3.095703, 3.100585, 3.105468, 3.110351, 3.115234, 3.120117, 3.125,  3.129882, 3.134765, 3.139648, 3.144531, 3.149414, 3.154296, 3.159179, 3.164062, 3.168945, 3.173828, 3.17871,  3.183593, 3.188476, 3.193359, 3.198242, 3.203125, 3.208007, 3.21289,  3.217773, 3.222656, 3.227539, 3.232421, 3.237304, 3.242187, 3.24707,  3.251953, 3.256835, 3.261718, 3.266601, 3.271484, 3.276367, 3.28125,  3.286132, 3.291015, 3.295898, 3.300781, 3.305664, 3.310546, 3.315429, 3.320312, 3.325195, 3.330078, 3.33496,  3.339843, 3.344726, 3.349609, 3.354492, 3.359375, 3.364257, 3.36914,  3.374023, 3.378906, 3.383789, 3.388671, 3.393554, 3.398437, 3.40332,  3.408203, 3.413085, 3.417968, 3.422851, 3.427734, 3.432617, 3.4375, 3.442382, 3.447265, 3.452148, 3.457031, 3.461914, 3.466796, 3.471679, 3.476562, 3.481445, 3.486328, 3.49121,  3.496093, 3.500976, 3.505859, 3.510742, 3.515625, 3.520507, 3.52539,  3.530273, 3.535156, 3.540039, 3.544921, 3.549804, 3.554687, 3.55957,  3.564453, 3.569335, 3.574218, 3.579101, 3.583984, 3.588867, 3.59375,  3.598632, 3.603515, 3.608398, 3.613281, 3.618164, 3.623046, 3.627929, 3.632812, 3.637695, 3.642578, 3.64746,  3.652343, 3.657226, 3.662109, 3.666992, 3.671875, 3.676757, 3.68164,  3.686523, 3.691406, 3.696289, 3.701171, 3.706054, 3.710937, 3.71582,  3.720703, 3.725585, 3.730468, 3.735351, 3.740234, 3.745117, 3.75, 3.754882, 3.759765, 3.764648, 3.769531, 3.774414, 3.779296, 3.784179, 3.789062, 3.793945, 3.798828, 3.80371,  3.808593, 3.813476, 3.818359, 3.823242, 3.828125, 3.833007, 3.83789,  3.842773, 3.847656, 3.852539, 3.857421, 3.862304, 3.867187, 3.87207,  3.876953, 3.881835, 3.886718, 3.891601, 3.896484, 3.901367, 3.90625,  3.911132, 3.916015, 3.920898, 3.925781, 3.930664, 3.935546, 3.940429, 3.945312, 3.950195, 3.955078, 3.95996,  3.964843, 3.969726, 3.974609, 3.979492, 3.984375, 3.989257, 3.99414,  3.999023, 4.003906, 4.008789, 4.013671, 4.018554, 4.023437, 4.02832,  4.033203, 4.038085, 4.042968, 4.047851, 4.052734, 4.057617, 4.0625, 4.067382, 4.072265, 4.077148, 4.082031, 4.086914, 4.091796, 4.096679, 4.101562, 4.106445, 4.111328, 4.11621,  4.121093, 4.125976, 4.130859, 4.135742, 4.140625, 4.145507, 4.15039,  4.155273, 4.160156, 4.165039, 4.169921, 4.174804, 4.179687, 4.18457,  4.189453, 4.194335, 4.199218, 4.204101, 4.208984, 4.213867, 4.21875,  4.223632, 4.228515, 4.233398, 4.238281, 4.243164, 4.248046, 4.252929, 4.257812, 4.262695, 4.267578, 4.27246,  4.277343, 4.282226, 4.287109, 4.291992, 4.296875, 4.301757, 4.30664,  4.311523, 4.316406, 4.321289, 4.326171, 4.331054, 4.335937, 4.34082,  4.345703, 4.350585, 4.355468, 4.360351, 4.365234, 4.370117, 4.375,  4.379882, 4.384765, 4.389648, 4.394531, 4.399414, 4.404296, 4.409179, 4.414062, 4.418945, 4.423828, 4.42871,  4.433593, 4.438476, 4.443359, 4.448242, 4.453125, 4.458007, 4.46289,  4.467773, 4.472656, 4.477539, 4.482421, 4.487304, 4.492187, 4.49707,  4.501953, 4.506835, 4.511718, 4.516601, 4.521484, 4.526367, 4.53125,  4.536132, 4.541015, 4.545898, 4.550781, 4.555664, 4.560546, 4.565429, 4.570312, 4.575195, 4.580078, 4.58496,  4.589843, 4.594726, 4.599609, 4.604492, 4.609375, 4.614257, 4.61914,  4.624023, 4.628906, 4.633789, 4.638671, 4.643554, 4.648437, 4.65332,  4.658203, 4.663085, 4.667968, 4.672851, 4.677734, 4.682617, 4.6875, 4.692382, 4.697265, 4.702148, 4.707031, 4.711914, 4.716796, 4.721679, 4.726562, 4.731445, 4.736328, 4.74121,  4.746093, 4.750976, 4.755859, 4.760742, 4.765625, 4.770507, 4.77539,  4.780273, 4.785156, 4.790039, 4.794921, 4.799804, 4.804687, 4.80957,  4.814453, 4.819335, 4.824218, 4.829101, 4.833984, 4.838867, 4.84375,  4.848632, 4.853515, 4.858398, 4.863281, 4.868164, 4.873046, 4.877929, 4.882812, 4.887695, 4.892578, 4.89746,  4.902343, 4.907226, 4.912109, 4.916992, 4.921875, 4.926757, 4.93164,  4.936523, 4.941406, 4.946289, 4.951171, 4.956054, 4.960937, 4.96582,  4.970703, 4.975585, 4.980468, 4.985351, 4.990234, 4.995117
};
const static byte chord_table[8][4]PROGMEM = {
 {  0,  68, 119,  205,  },//Maj
 { 0,  68, 119,  187,  },//Maj7
 { 0,  68, 119,  239,  },//Majadd9
 { 0,  34, 119,  205,  },//sus2
 { 0,  51, 119,  239,  },//minadd9
 { 0,  51, 119,  170,  },//min7
 { 0,  51, 119,  205,  },//min
 { 0,  0,  0,  0,  }//root
};

void setup()
{
 startMozzi(CONTROL_RATE); // :)
 Serial.begin(9600);

}
void updateControl() {
 //chord setting
 chord = (mozziAnalogRead(3) / 128) + (mozziAnalogRead(5) / 128);
 chord = constrain(chord, 0, 7);

 //inversion setting
 inv_knob = mozziAnalogRead(1);
 inv = (inv_knob  / 64)+ (mozziAnalogRead(4) / 64);
 inv = constrain(inv, 0, 15);

 if (inv_knob < 1020) { //when selecting wave , not apply
   switch (inv) {
     case 0:
       inv_aply1 = 0;
       inv_aply2 = 0;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 0;
       break;

     case 1:
       inv_aply1 = 1;
       inv_aply2 = 0;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 0;
       break;

     case 2:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 0;
       break;

     case 3:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 0;
       inv_aply5 = 0;
       break;

     case 4:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 0;
       break;

     case 5:
       inv_aply1 = 2;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 0;
       break;

     case 6:
       inv_aply1 = 2;
       inv_aply2 = 2;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 0;
       break;

     case 7:
       inv_aply1 = 2;
       inv_aply2 = 2;
       inv_aply3 = 2;
       inv_aply4 = 1;
       inv_aply5 = 0;
       break;

     case 8:
       inv_aply1 = 2;
       inv_aply2 = 2;
       inv_aply3 = 2;
       inv_aply4 = 1;
       inv_aply5 = 1;
       break;

     case 9:
       inv_aply1 = 2;
       inv_aply2 = 2;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 1;
       break;

     case 10:
       inv_aply1 = 2;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 1;
       break;

     case 11:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 1;
       break;

     case 12:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 0;
       inv_aply5 = 1;
       break;

     case 13:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 1;
       break;

     case 14:
       inv_aply1 = 1;
       inv_aply2 = 0;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 1;
       break;

     case 15:
       inv_aply1 = 0;
       inv_aply2 = 0;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 1;
       break;
   }
 }
 //setting chord note
 if (inv_knob < 1020) { //when selecting wave , not apply
   note1 = (pgm_read_byte(&(chord_table[chord][0])));
   note2 = (pgm_read_byte(&(chord_table[chord][1])));
   note3 = (pgm_read_byte(&(chord_table[chord][2])));
   note4 = (pgm_read_byte(&(chord_table[chord][3])));
   note5 = (pgm_read_byte(&(chord_table[chord][0])));
 }

 //OSC frequency knob
 freqi = round(constrain((mozziAnalogRead(0) / 80),0 , 12));
 freq1 = notas[freqi];
Serial.print(freq1);
  Serial.print("    ");
//
//
 Serial.println(freqi);

 //set wave
 if (inv_knob >= 1020) { //inv knob max
   wave = (mozziAnalogRead(3) / 128);
 }

 //frequency setting
 voct = mozziAnalogRead(7) ;
 freqv1 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply1 + note1])))); //ROOT
 freqv2 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply2 + note2])))); //2nd
 freqv3 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply3 + note3])))); //3rd
 freqv4 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply4 + note4])))); //4th
 freqv5 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + note5])))); //ROOT

 switch (wave) {
   case 0://saw
     aSaw1.setFreq(freqv1); // set the frequency
     aSaw2.setFreq(freqv2);
     aSaw3.setFreq(freqv3);
     aSaw4.setFreq(freqv4);
     aSaw5.setFreq(freqv5);
     break;

   case 1://squ
     aSqu1.setFreq(freqv1); // set the frequency
     aSqu2.setFreq(freqv2);
     aSqu3.setFreq(freqv3);
     aSqu4.setFreq(freqv4);
     aSqu5.setFreq(freqv5);
     break;

   case 2://tri
     aTri1.setFreq(freqv1); // set the frequency
     aTri2.setFreq(freqv2);
     aTri3.setFreq(freqv3);
     aTri4.setFreq(freqv4);
     aTri5.setFreq(freqv5);
     break;

   case 3://sin
     aSin1.setFreq(freqv1); // set the frequency
     aSin2.setFreq(freqv2);
     aSin3.setFreq(freqv3);
     aSin4.setFreq(freqv4);
     aSin5.setFreq(freqv5);
     break;

   case 4://
     aChb1.setFreq(freqv1); // set the frequency
     aChb2.setFreq(freqv2);
     aChb3.setFreq(freqv3);
     aChb4.setFreq(freqv4);
     aChb5.setFreq(freqv5);
     break;

   case 5://
     ahSin1.setFreq(freqv1); // set the frequency
     ahSin2.setFreq(freqv2);
     ahSin3.setFreq(freqv3);
     ahSin4.setFreq(freqv4);
     ahSin5.setFreq(freqv5);
     break;

   case 6://
     aSig1.setFreq(freqv1); // set the frequency
     aSig2.setFreq(freqv2);
     aSig3.setFreq(freqv3);
     aSig4.setFreq(freqv4);
     aSig5.setFreq(freqv5);
     break;

   case 7://
     aPha1.setFreq(freqv1); // set the frequency
     aPha2.setFreq(freqv2);
     aPha3.setFreq(freqv3);
     aPha4.setFreq(freqv4);
     aPha5.setFreq(freqv5);
     break;
 }
}

int updateAudio() {
 switch (wave) {

   case 0:
     return MonoOutput::from8Bit(aSaw1.next() / 32 + aSaw2.next() / 32 + aSaw3.next() / 32 + aSaw4.next() / 32 + aSaw5.next() / 32 * inv_aply5);
     break;

   case 1:
     return MonoOutput::from8Bit(aSqu1.next() / 32 + aSqu2.next() / 32 + aSqu3.next() / 32 + aSqu4.next() / 32 + aSqu5.next() / 32 * inv_aply5);
     break;

   case 2:
     return MonoOutput::from8Bit(aTri1.next() / 32 + aTri2.next() / 32 + aTri3.next() / 32 + aTri4.next() / 32 + aTri5.next() / 32 * inv_aply5);
     break;

   case 3:
     return MonoOutput::from8Bit(aSin1.next() / 32 + aSin2.next() / 32 + aSin3.next() / 32 + aSin4.next() / 32 + aSin5.next() / 32 * inv_aply5);
     break;

   case 4:
     return MonoOutput::from8Bit(aChb1.next() / 32 + aChb2.next() / 32 + aChb3.next() / 32 + aChb4.next() / 32 + aChb5.next() / 32 * inv_aply5);
     break;

   case 5:
     return MonoOutput::from8Bit(ahSin1.next() / 32 + ahSin2.next() / 32 + ahSin3.next() / 32 + ahSin4.next() / 32 + ahSin5.next() / 32 * inv_aply5);
     break;

   case 6:
     return MonoOutput::from8Bit(aSig1.next() / 32 + aSig2.next() / 32 + aSig3.next() / 32 + aSig4.next() / 32 + aSig5.next() / 32 * inv_aply5);
     break;

   case 7:
     return MonoOutput::from8Bit(aPha1.next() / 32 + aPha2.next() / 32 + aPha3.next() / 32 + aPha4.next() / 32 + aPha5.next() / 32 * inv_aply5);
     break;

 }
}
void loop() {
 audioHook(); // required here
}

tomco...@live.fr

unread,
Oct 4, 2023, 7:25:52 AM10/4/23
to Mozzi-users
Hi!

Thanks for sharing the code! Before I run some tests on my side, I actually have a few comments while over-reading it.

Most of these microcontrollers (and the ATMegas particularly) do not possess an Floating Point Unit (FPU), hence dealing with floats is generally very slow and not advised if possible. But Mozzi got you covered as a huge effort has been put in making the calculation using fixed point number which are WAY more efficient. Not sure it might be related to your problem or not but I think better to use the full power of the board and of Mozzi to both rule that out but also to allow better synthesis to be performed without moving to more powerful boards.

freq1 is a float but all the freqv are ints, so there is a necessary loss of all the decimals there. I would suggest using Mozzi's fixed decimal point types, in particular Q16n16 for dealing with frequencies, the resolution will be way greater and you can set the oscillators frequencies using Oscil.setFreq_Q16n16.

For chords and all, you basically compute the needed frequency from the base frequency. But it is actually quite simpler to deal in terms of midi notes and not frequencies, especially as Mozzi can converts these notes straigh into Q16n16 frequencies very efficiently using Q16n16_mtof(). So, for instance you can define a major chord by its integer notation (converted to Q16n16): Q16n16 chord[3] = {Q16n0_to_Q16n16(0), Q16n0_to_Q16n16(4), Q16n0_to_Q16n16(7)} (root, major third (+4 semi-tones), fifth (+7 semi-tones).
And then setting your oscillators is super easy, let's say you read a note of 64 thanks to the potentiometer:
 int base_note=64:  //just simulating a read
Q16n16 base_note_Q16n16 = Q16n0_to_Q16n16(base_note);
 aSaw1.setFreq_Q16n16(Q16n16_mtof(base_note_Q16n16 + chord[0]));
 aSaw2.setFreq_Q16n16(Q16n16_mtof(base_note_Q16n16 + chord[1]));
 aSaw2.setFreq_Q16n16(Q16n16_mtof(base_note_16n16 + chord[2]));

Of course, this can be done in a small for loop.

The idea is to hide the frequency calculation and actually letting Mozzi doing that for you (in a very efficient way). It will make your code lighter and more efficient which is always a good thing :)

I did type this without testing on a board, there might be some mistakes but I hope the concept is clear!

I will try to test a naked board with a simple frequency soon to see if I can reproduce this drift also.

Best,

Daniel Llermaly

unread,
Oct 4, 2023, 11:39:36 PM10/4/23
to Mozzi-users
Thank you very much Thomas!
I'm going to check what you tell me
and try to optimize the code

thank you so much

Daniel Llermaly

unread,
Oct 6, 2023, 9:00:56 PM10/6/23
to Mozzi-users
Hello everyone in the group

I was trying to change the variable type for the frequencies using Q16n16, but I don't have any sound
Then I tried the sinewave example but using those types of variables, and they don't sound anything either.
Am I misunderstanding something?
I copy the code from the example


greetings and thank you very much



#include <MozziGuts.h>
#include <Oscil.h> // oscillator template
#include <tables/sin2048_int8.h> // sine table for oscillator

// use: Oscil <table_size, update_rate> oscilName (wavetable), look in .h file of table #included above
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin(SIN2048_DATA);
Q16n16 freq1 = 440;//base freq


void setup(){
  startMozzi(); // uses the default control rate of 64, defined in mozzi_config.h
  aSin.setFreq_Q16n16  (freq1);  
}


void updateControl(){}


AudioOutput_t updateAudio(){
  // this would make more sense with a higher resolution signal
  // MonoOutput::from8Bit() (and it friends from16Bit() and fromNBit()) take care of scaling the output signal
  // as appropiate for the platform (to 14 bits on AVR with AUDIO_MODE HIFI).
  return MonoOutput::from8Bit(aSin.next());

}


void loop(){
  audioHook(); // required here
}

Mr Sensorium

unread,
Oct 7, 2023, 7:52:41 AM10/7/23
to Mozzi-users
Hi Daniel,

try changing this line:
    Q16n16 freq1 = 440;//base freq
to:
   Q16n16 freq1 = Q16n0_to_Q16n16(440);//base freq

You could also do this (it's the same thing):
    Q16n16 freq1 = (unsigned long)440<<16;//base freq

docs for Mozzi's fixed math are:

And it's worth searching for some info about fixed math to make more sense of it!

Daniel Llermaly

unread,
Oct 7, 2023, 1:17:34 PM10/7/23
to Mozzi-users
Thank you very much, it worked in the example!

I'm going to check the fix maths

So in my code should I do the same with all the variables that define the frequency? convert them to Q16n16


greetings and thank you very much

Daniel Llermaly

unread,
Oct 7, 2023, 2:51:30 PM10/7/23
to Mozzi-users
So for example to do this operation


  freqv1 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply1 + note1])))); //ROOT


  Should I pass the variables note1 and inv_apply, which are byte and int, to Q16n16? or is it compatible to operate Q16n16 with byte?

And to read the fix it would have to be something like pgm_read_Q16n16? or do I read it as float and then transform it? greetings and thank you very much

Daniel Llermaly

unread,
Oct 7, 2023, 5:02:32 PM10/7/23
to Mozzi-users
And another question (sorry, I think I'm understanding but I'm confused with some things) is it important to avoid using floats throughout the code? or only in what corresponds to the frequency assignment?

tomco...@live.fr

unread,
Oct 8, 2023, 3:25:12 PM10/8/23
to Mozzi-users
Hi,
Tried the one non-genuine nano I found in a drawer but of course do not manage to upload to it, will see if I can find another atmega board around…

In the meantime:
>> freqv1 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply1 + note1])))); //ROOT

I think trying to calculate yourself the frequencies is not a good idea (compared to using midi notes like in my first answer. Note that midi notes can be fractionnal, allowing for pitchbend and portamento, basically it gives you access to the same frequencies but at a fraction of the computing cost and with actually simpler code). In particular if I remember well pow is a particularly heavy function that should be avoided as standard. Working with notes allows you to deal with addition and substraction instead of multiplication and division (and power), the former are notoriously more efficient ;).

This brings me to your last post (sorry for the delay, I only receive the digests from time to time):
On boards like this, that does not have an FPU, it is, as a basic rule never a good idea to have floats. They need to be emulated in software and as such, are extremely costing whenever any operation is involved (+, -, /…), hence the fixed maths (which are actually integers for the processor). That being said, the impact of using will not be the same depending on where floats are used in the code: they are especially problematic in any time sensitive code:
- updateAudio() for instance is really targeted to run fast: it should supply one sample at the frequency the sound is updated. Any delay there (as this function is called often) can be problematic and can lead to empty buffers (cliks, artefacts) as the samples were not processed in a short enough time
- updateControl() is normally called way less often, so it is less sensitive to delays, even though it is good practice to avoid them in there too as a too long control loop will end up affecting the global performances as a whole.
- setup() is called only once, at the beginning. Having a long and heavy code there is completely harmless if you are okay for the sound to start a few milliseconds later, hence using floats in there is no problem. I am actually doing that in some of my projects in order to compute Look-up-tables: I compute them in float in the setup and convert them in another type (int, uint32_t…) at the end of the setup.

Hope this helps!
Tom

tomco...@live.fr

unread,
Oct 8, 2023, 4:19:08 PM10/8/23
to Mozzi-users
Small update:

tested with a (non-genuine) Mega, that the same family of processor.

Indeed, I have a small drift, but this is not constant with the frequency: around 4Hz at 440, around 16Hz at 1600: this seems proportionnal to the base frequency which looks like an non-tune crystal oscillator (giving the processor frequency).
Maybe someone with a genuine arduino could have a try?

Out of curiosity Daniel, how do you measure that?
Best,
Tom

Daniel Llermaly

unread,
Oct 8, 2023, 4:36:45 PM10/8/23
to Mozzi-users
hello
Thank you very much for the reply
Yes, I understood that doing it with miditof would be optimal, but I want to keep the option without quantizing at 1v/oct, being able to change it with a switch, that's why I'm trying to keep the code, but for the next idea I'll do it all with midi

To test, I used a guitar tuner and through trial and error I tuned it, and I obtained a difference of about 2 Hz for all the frequencies of the 3 octave.

I will keep trying

greetings and thank you very much again

tomco...@live.fr

unread,
Oct 9, 2023, 2:56:57 PM10/9/23
to Mozzi-users
Hi!
> but I want to keep the option without quantizing at 1v/oct,

Note that midi notes can have decimals, hence you can both enable (by removing the decimals) and disable (by keeping the decimals) quantize. The advantage is that the 1V/oct is a logarithmic scale whereas 1V/12MidiNotes is linear (which is why we use note in music ;).
Just a quick example (untested), saying that the ADC gives values between 0-1023 over 5V. That makes 204.8 per volt or 204.8 per 12 midi notes or 17.0667 per midi notes.

Q16n16 inv_conversion_factor = float_to_Q16n16(5.*12/1024.); // to be computed in the setup or as a global variable (we actually compute the inverse to save a division)
Q16n16 base_note = Q8n0_to_Q16n16(24); // that's the note for 0V input.
bool quantized = false;

uint16_t AR = mozziAnalogRead(your_pin);
Q16n16 note = Q16n0_to_Q16n16(AR)  * inv_conversion_factor + base_note;
if (quantized) note = (note >>16) << 16; // removing the last 16th bits that are the decimals (could be done with a bit mask) You can also keep one bit of decimals to quantize at the quarter tone level for instance.

Q16n16 freq = Q16n16_mtof(note);
Oscil.setFreq_Q16n16(freq);


And that's it! In the pure code, the only costy operation was the multiplication between two 32 bits.
Of course, if you are adapting from a working code and do not want to change its behavior I guess you have little choice than adaptating the way you are doing now.

By the way, I quickly look at the AVR implementation for Mozzi but did not see any obvious things that could relate to the drift. Without testing on more boards it is hard to tell if the problem is software or hardware.
I suggest adding a fine button (just adding a portion of midi notes to the final note ;) )

Hope this helps!

tomco...@live.fr

unread,
Oct 9, 2023, 4:18:16 PM10/9/23
to Mozzi-users
Figured out there might be some missing shifts in my previous snipset, should be more like (I think):
Q16n16 note = AR * inv_conversion_factor + base_note; //AR is actually in Q16n0, Q16n0*Q16n16 should gives the result in the correct range, otherwise a >>16 is needed.
Sorry!

Daniel Llermaly

unread,
Oct 10, 2023, 12:33:57 AM10/10/23
to Mozzi-users
Yes, just after sending the last message I realized the possibility of using midi note portions
I think I'll go that way

but the doubt of the detuning remains

I'm going to try with an esp32 to see what happens

greetings and thank you very much for the help

tomco...@live.fr

unread,
Oct 10, 2023, 3:14:52 PM10/10/23
to Mozzi-users
Just for the record, testing on an Arduino Uno (genuine), I record a drift of 0.25% on a broad range of frequencies. This is not a lot but is might be hearable when playing with other tuned instruments.
I posted an issue on github: https://github.com/sensorium/Mozzi/issues/201, from my calculations, the frequency should normally be off by 0.0576%, which is quite less.

Thanks for reporting this!

Daniel Llermaly

unread,
Oct 13, 2023, 2:57:14 PM10/13/23
to Mozzi-users
hello everyone!!
Finally I rewrote the code using Mozzi Midi. I only did the quantized part, when I have a little time I will add an unquantized v/oct mode. Below I paste the code.
Now I would like to test how it sounds with a pt 2811 dac. For that, in addition to the mzzi setup files, I would only have to change this line:

      return MonoOutput::from8Bit(ahSin1.next() / 32 + ahSin2.next() / 32 + ahSin3.next() / 32 + ahSin4.next() / 32 + ahSin5.next() / 32 * inv_aply5);


to

     return MonoOutput::from16Bit(ahSin1.next() / 32 + ahSin2.next() / 32 + ahSin3.next() / 32 + ahSin4.next() / 32 + ahSin5.next() / 32 * inv_aply5);



greetings and thank you very much

#include <FastLED.h>


#include <MozziGuts.h>
#include <mozzi_midi.h>
#include <Oscil.h> // oscillator template
#include <Bounce2.h>

// INSTANTIATE A Bounce OBJECT
Bounce bounce = Bounce();
Q16n16 notar = 69;//base freq
Q16n16 nota1 = 69;
Q16n16 nota2 = 69;
Q16n16 nota3 = 69;
Q16n16 nota4 = 69;
Q16n16 nota5 = 69;
Q16n16 freqi = 110;//base freq


int voct = 1000;//external V/OCT LSB

int LED_r_PIN = 8;
int LED_g_PIN = 6;
int LED_v_PIN = 7;



Q16n16 freqv1 = 440;//apply voct
Q16n16 freqv2 = 440;
Q16n16 freqv3 = 440;
Q16n16 freqv4 = 440;
Q16n16 freqv5 = 440;

int formaOnda = 0;
const int debounceDelay = 50;  // Tiempo de debounce en milisegundos
unsigned long lastDebounceTime = 0;  // Último momento en que se cambió el estado del botón
int buttonState ;  // Estado actual del botón (HIGH o LOW)
int lastButtonState = LOW;  // Estado anterior del botón (HIGH o LOW)


byte note1 = 0;//Root
byte note2 = 0;//2nd
byte note3 = 0;//3rd
byte note4 = 0;//4th
byte note5 = 0;//Root

byte inv_aply1 = 0; //0 = no inv , 1 = inv , Root
byte inv_aply2 = 0; //2nd
byte inv_aply3 = 0; //3rd
byte inv_aply4 = 0; //4th
bool inv_aply5 = 0; //0 = no output root sound , 1 = output root sound

int inv = 0;
int inv_knob = 0;
int chord = 0;
byte wave = 0;//0=saw,1=squ,2=tri,3=sin,etc...

const static byte chord_table[8][4]PROGMEM = {
 { 0,  4, 7,  12,  },//Maj
 { 0,  4, 7,  11,  },//Maj7
 { 0,  4, 7,  14,  },//Majadd9
 { 0,  2, 7,  12,  },//sus2
 { 0,  3, 7,  14,  },//minadd9
 { 0,  3, 7,  10,  },//min7
 { 0,  3, 7,  12,  },//min

 { 0,  0, 0,  0,  }//root
};

void setup()
{
 startMozzi(CONTROL_RATE); // :)
 pinMode(LED_r_PIN, OUTPUT);
 pinMode(LED_g_PIN, OUTPUT);
 pinMode(LED_v_PIN, OUTPUT);
//Serial.begin(9600);
 bounce.attach( 3 ,  INPUT_PULLUP ); // USE INTERNAL PULL-UP
 bounce.interval(10); // interval in ms




}
void updateControl() {
 //chord setting
 chord = (mozziAnalogRead(3) / 128) + (mozziAnalogRead(5) / 128);
 chord = constrain(chord, 0, 7);
 bounce.update();
if(bounce.changed()){
        int deboucedInput = bounce.read();

    if ( deboucedInput == LOW ) {
              formaOnda = (formaOnda + 1) % 8;

       
    }
    Serial.print(formaOnda);

   }


 //inversion setting
 inv_knob = mozziAnalogRead(1);
 inv = (inv_knob  / 64)+ (mozziAnalogRead(4) / 64);
 inv = constrain(inv, 0, 15);

 
   note1 = (pgm_read_byte(&(chord_table[chord][0])));
   note2 = (pgm_read_byte(&(chord_table[chord][1])));
   note3 = (pgm_read_byte(&(chord_table[chord][2])));
   note4 = (pgm_read_byte(&(chord_table[chord][3])));
   note5 = (pgm_read_byte(&(chord_table[chord][0])));


 //OSC frequency knob
 voct = mozziAnalogRead(7)/100 ;
 notar = Q16n0_to_Q16n16  (48 + mozziAnalogRead(0) / 79 + voct);

 

//   Serial.print(" voct ");
//    Serial.print(voct);
//  Serial.print("    ");
//  Serial.print(freqv1);
//  Serial.print("    ");
//  Serial.println(freqi);
//

 //set wave

 
 //frequency setting
 voct = mozziAnalogRead(7) ;
 Q16n16 nota1 = notar + Q16n0_to_Q16n16 (note1 + 12 * inv_aply1);//base freq
 Q16n16 nota2 = notar + Q16n0_to_Q16n16 (note2 + 12 * inv_aply2);
 Q16n16 nota3 = notar + Q16n0_to_Q16n16 (note3 + 12 * inv_aply3);
 Q16n16 nota4 = notar + Q16n0_to_Q16n16 (note4 + 12 * inv_aply4);
 Q16n16 nota5 = notar + Q16n0_to_Q16n16 (note5);

//Serial.print(" ch ");
//  Serial.print((chord));
//  Serial.print(" inver ");
//  Serial.print((inv));
//Serial.print(" inv1 ");
//  Serial.print( (inv_aply1));
//  Serial.print(" inv2 ");
//  Serial.print( (inv_aply2));
//  Serial.print(" inv3 ");
//  Serial.print( (inv_aply3));
//  Serial.print(" inv4 ");
//  Serial.print( (inv_aply4));
//  Serial.print(" inv5 ");
//  Serial.print( (inv_aply5));
//
// Serial.print(" nota1 ");
//  Serial.print(Q16n16_to_float (nota1));
//  
//  Serial.print(" nota2 ");
//  Serial.print(Q16n16_to_float (nota2));
//  
//  Serial.print(" nota3 ");
//  Serial.print(Q16n16_to_float (nota3));
//  
//  Serial.print(" nota4 ");
//  Serial.print(Q16n16_to_float (nota4));
//  
//  Serial.print(" nota5 ");
//  Serial.println(Q16n16_to_float( nota5));
 
 freqv1 = Q16n16_mtof(nota1); //ROOT
 freqv2 = Q16n16_mtof(nota2);
 freqv3 = Q16n16_mtof(nota3);
 freqv4 = Q16n16_mtof(nota4);
 freqv5 = Q16n16_mtof(nota5);
 //freqv2 = Q16n0_to_Q16n16 (freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply2 + note2]))))); //2nd
// freqv3 = Q16n0_to_Q16n16 (freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply3 + note3]))))); //3rd
// freqv4 = Q16n0_to_Q16n16 (freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply4 + note4]))))); //4th
// freqv5 = Q16n0_to_Q16n16 (freq1 * pow(2, (pgm_read_float(&(voctpow[voct + note5]))))); //ROOT

 switch (formaOnda) {
   case 0://saw
     aSaw1.setFreq_Q16n16(freqv1); // set the frequency
     aSaw2.setFreq_Q16n16(freqv2);
     aSaw3.setFreq_Q16n16(freqv3);
     aSaw4.setFreq_Q16n16(freqv4);
     aSaw5.setFreq_Q16n16(freqv5);
     digitalWrite(LED_v_PIN,HIGH);
     digitalWrite(LED_g_PIN,LOW);
     digitalWrite(LED_r_PIN,LOW);
     Serial.print(formaOnda);
     break;

   case 1://squ
     aSqu1.setFreq_Q16n16(freqv1); // set the frequency
     aSqu2.setFreq_Q16n16(freqv2);
     aSqu3.setFreq_Q16n16(freqv3);
     aSqu4.setFreq_Q16n16(freqv4);
     aSqu5.setFreq_Q16n16(freqv5);
     digitalWrite(LED_v_PIN,HIGH);
     digitalWrite(LED_g_PIN,HIGH);
     digitalWrite(LED_r_PIN,HIGH);
     break;

   case 2://tri
     aTri1.setFreq_Q16n16(freqv1); // set the frequency
     aTri2.setFreq_Q16n16(freqv2);
     aTri3.setFreq_Q16n16(freqv3);
     aTri4.setFreq_Q16n16(freqv4);
     aTri5.setFreq_Q16n16(freqv5);
     digitalWrite(LED_v_PIN,LOW);
     digitalWrite(LED_g_PIN,HIGH);
     digitalWrite(LED_r_PIN,LOW);
     break;

   case 3://sin
     aSin1.setFreq_Q16n16(freqv1); // set the frequency
     aSin2.setFreq_Q16n16(freqv2);
     aSin3.setFreq_Q16n16(freqv3);
     aSin4.setFreq_Q16n16(freqv4);
     aSin5.setFreq_Q16n16(freqv5);
     digitalWrite(LED_v_PIN,LOW);
     digitalWrite(LED_g_PIN,LOW);
     digitalWrite(LED_r_PIN,HIGH);
     break;

   case 4://
     aChb1.setFreq_Q16n16(freqv1); // set the frequency
     aChb2.setFreq_Q16n16(freqv2);
     aChb3.setFreq_Q16n16(freqv3);
     aChb4.setFreq_Q16n16(freqv4);
     aChb5.setFreq_Q16n16(freqv5);
     digitalWrite(LED_v_PIN,HIGH);
     digitalWrite(LED_g_PIN,LOW);
     digitalWrite(LED_r_PIN,HIGH);
     break;

   case 5://
     ahSin1.setFreq_Q16n16(freqv1); // set the frequency
     ahSin2.setFreq_Q16n16(freqv2);
     ahSin3.setFreq_Q16n16(freqv3);
     ahSin4.setFreq_Q16n16(freqv4);
     ahSin5.setFreq_Q16n16(freqv5);
     break;

   case 6://
     aSig1.setFreq_Q16n16(freqv1); // set the frequency
     aSig2.setFreq_Q16n16(freqv2);
     aSig3.setFreq_Q16n16(freqv3);
     aSig4.setFreq_Q16n16(freqv4);
     aSig5.setFreq_Q16n16(freqv5);
     digitalWrite(LED_v_PIN,HIGH);
     digitalWrite(LED_g_PIN,HIGH);
     digitalWrite(LED_r_PIN,LOW);
     break;

   case 7://
     aPha1.setFreq_Q16n16(freqv1); // set the frequency
     aPha2.setFreq_Q16n16(freqv2);
     aPha3.setFreq_Q16n16(freqv3);
     aPha4.setFreq_Q16n16(freqv4);
     aPha5.setFreq_Q16n16(freqv5);
     digitalWrite(LED_v_PIN,HIGH);
     digitalWrite(LED_g_PIN,HIGH);
     digitalWrite(LED_r_PIN,HIGH);
     break;
 }
}

int updateAudio() {
 switch (formaOnda) {

Daniel Llermaly

unread,
Oct 14, 2023, 12:38:58 AM10/14/23
to Mozzi-users
hello everyone
I was trying to add the pt8211 dac
I based it on the pt_stereo_16 bit example (which I was able to run and listen to), and I was able to compile my code, but I have no sound

am I forgetting something?
Below I paste the code

greetings and thank you very much for the help

#include <FastLED.h>

#include <MozziGuts.h>
#include <mozzi_midi.h>
#include <Oscil.h> // oscillator template
#include <Bounce2.h>
#include <SPI.h>
#define WS_pin 2   // channel select pin for the DAC
void audioOutput(const AudioOutput f) // f is a structure containing both channels

{

/* Note:
 *  the digital writes here can be optimised using portWrite if more speed is needed
 */

  digitalWrite(WS_pin, LOW);  //select Right channel
  SPI.transfer16(f.r());

  digitalWrite(WS_pin, HIGH);  // select Left channel
  SPI.transfer16(f.l());
 SPI.begin();
  SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0));  //MSB first, according to the DAC spec
AudioOutput_t updateAudio() {
 switch (formaOnda) {

   case 0:
     return MonoOutput::from16Bit(aSaw1.next() / 32 + aSaw2.next() / 32 + aSaw3.next() / 32 + aSaw4.next() / 32 + aSaw5.next() / 32 * inv_aply5);
     break;

   case 1:
     return MonoOutput::from16Bit(aSqu1.next() / 32 + aSqu2.next() / 32 + aSqu3.next() / 32 + aSqu4.next() / 32 + aSqu5.next() / 32 * inv_aply5);
     break;

   case 2:
     return MonoOutput::from16Bit(aTri1.next() / 32 + aTri2.next() / 32 + aTri3.next() / 32 + aTri4.next() / 32 + aTri5.next() / 32 * inv_aply5);
     break;

   case 3:
     return MonoOutput::from16Bit(aSin1.next() / 32 + aSin2.next() / 32 + aSin3.next() / 32 + aSin4.next() / 32 + aSin5.next() / 32 * inv_aply5);
     break;

   case 4:
     return MonoOutput::from16Bit(aChb1.next() / 32 + aChb2.next() / 32 + aChb3.next() / 32 + aChb4.next() / 32 + aChb5.next() / 32 * inv_aply5);
     break;

   case 5:

     return MonoOutput::from16Bit(ahSin1.next() / 32 + ahSin2.next() / 32 + ahSin3.next() / 32 + ahSin4.next() / 32 + ahSin5.next() / 32 * inv_aply5);
     break;

   case 6:
     return MonoOutput::from16Bit(aSig1.next() / 32 + aSig2.next() / 32 + aSig3.next() / 32 + aSig4.next() / 32 + aSig5.next() / 32 * inv_aply5);
     break;

   case 7:
     return MonoOutput::from16Bit(aPha1.next() / 32 + aPha2.next() / 32 + aPha3.next() / 32 + aPha4.next() / 32 + aPha5.next() / 32 * inv_aply5);

     break;

 }
}
void loop() {
 audioHook(); // required here
}

tomco...@live.fr

unread,
Oct 14, 2023, 1:47:23 PM10/14/23
to Mozzi-users
Hi,

Scanning quickly through your code,I see that you are reusing the audioOutput function from the example, which is a stereo example. Here, you are missing one channel so one of the two SPI.transfer16 should not be there (I do not remember which exactly now, I put my bet on the right). All the digitalWrite should stay though!

Daniel Llermaly

unread,
Oct 14, 2023, 3:41:01 PM10/14/23
to Mozzi-users
thank you very much Tom
I tried deleting the 2 lines you told me about and still no sound.
I also tried in stereo, copying the information in channel r (separating it by commas) and there is no sound either.
Can you think of anything else to try?
What's the difference between using AudioOutput_t updateAudio() { or int updateAudio() {
   at the exit?


greetings and thank you very much

tomco...@live.fr

unread,
Oct 14, 2023, 4:04:32 PM10/14/23
to Mozzi-users
Hi again,
Just to make sure, normally, only one line should be deleted in the end.

So just to summarize:
 - you sketch is working when not using the DAC right?
 - you managed to get some sound out from the DAC using the example right?
 - the example was in stereo, as you sketch is in mono, you changed mozzi_config.h accordingly (and asking it to output on the external dac)?
 - did you try outputting another mono sketch (like one of the examples) using the DAC?

Best,

Daniel Llermaly

unread,
Oct 14, 2023, 6:17:21 PM10/14/23
to Mozzi-users
thanks Thomas


 - you sketch is working when not using the DAC right?   Yes
 - you managed to get some sound out from the DAC using the example right?   Yes
 - the example was in stereo, as you sketch is in mono, you changed mozzi_config.h accordingly (and asking it to output on the external dac)? Yes
 - did you try outputting another mono sketch (like one of the examples) using the DAC? No

I didn't find mono examples for the pt8211, or should I change one of the basic examples, for example the sinewave, so that it uses the dac? thank you very much again!!

tomco...@live.fr

unread,
Oct 15, 2023, 5:07:39 PM10/15/23
to Mozzi-users
Hi,

Okay, from your answers you should be quite close to a working solution.

First off, the audioOutput, for mono should be:

void audioOutput(const AudioOutput f) // f is a structure containing both channels
{
  digitalWrite(WS_pin, LOW);  //select Right channel
  mySPI.transfer16(f.l());

  digitalWrite(WS_pin, HIGH);  // select Left channel
}


if you want to try on a mono example first, basically copy paste everything concerning the DAC from the example except this function which should be like this (one instruction removed). If that works, you should be able to reproduce for your sketch!
By the way, I see that I forgot to answer:

> What's the difference between using AudioOutput_t updateAudio() { or int updateAudio() {
   at the exit?

In mono, it is actually the same, AudioOutput_t is an int. Now, in stereo it is *two* ints. This was changed in order to allow one structure to be valid whatever the number of channels to output.

PS: I may have found a fix for the detuning, if you want you can try: https://github.com/sensorium/Mozzi/pull/202

Daniel Llermaly

unread,
Oct 16, 2023, 1:40:28 AM10/16/23
to Mozzi-users
Hello Thomas
Thank you very much for the help!!
I was testing, and changed the pt8211 example to make it mono and got it to work. But when I removed the envelope it no longer sounded, I corrected that by multiplying by 127 and there I could hear the sine wave.
I tried to do the same with my code and it didn't sound, but when I raised the volume to maximum I realized that my code was playing, but at a very low volume.
I tried multiplying by 127 again but it didn't increase the volume, and if I multiplied by a larger amount, it didn't play.
Tomorrow I will continue testing, but what I have a doubt about is that when comparing the sine wave generated in hifi mode vs. that of pt8211 and looking at it on the oscilloscope, it gives the impression that in hifi mode a cleaner wave is obtained than the one obtained with the dac
Is this possible or should I review my code?

And the last question, to test the fix you made to the tuning, should I download and install the latest version of the library again? I think I didn't understand that very well.

Greetings and thank you very much
WhatsApp Image 2023-10-15 at 11.32.55 PM.jpeg
hifi mode

WhatsApp Image 2023-10-15 at 11.27.41 PM.jpeg
with dac

tomco...@live.fr

unread,
Oct 16, 2023, 3:57:02 PM10/16/23
to Mozzi-users
Hi Daniel,
> Tomorrow I will continue testing, but what I have a doubt about is that when comparing the sine wave generated in hifi mode vs. that of pt8211 and looking at it on the oscilloscope, it gives the impression that in hifi mode a cleaner wave is obtained than the one obtained with the dac

Very nice test! Indeed it looks cleaner on the scope with HiFi, the output of the DAC is looking very steppy. But there are a few things to consider: I don't know your exact circuit but I guess this HiFi output is low pass filtered, otherwise, as it is based on two PWM pins (which can output two values each, 0-1 at any moment) you would have four steps as output. I guess the dac output is not filtered hence the steps. Note that the steps do not come from the resolution of the DAC, but from the resolution of what you are outputting: if this is just a sinewave, nothing else, then it is on 8bits. This 8-bits digitilization are the steps you are seeing. Now if you have a real 16bits signal (for instance by multiplying to oscillators), the steps will be so small that the scope won't peek them. Also, the final judge should be your ears, and do not forget to filter a bit the pt8211, there are a few schematics in its datasheet. HiFi mode should be *only* 14 bits, whereas the PT should be 16bits (from 16384 values to 65536 values, quite a bit!).

This brings me naturally to the low level you are experiencing: from what I have seen, you are outputting this from updateAudio on 8bits:
> return MonoOutput::from8Bit(aPha1.next() / 32 + aPha2.next() / 32 + aPha3.next() / 32 + aPha4.next() / 32 + aPha5.next() / 32 * inv_aply5);

As the dac is in 16bits, outputting things in 8 is basically getting rid of the last 8bits, hence of the interest of having the dac. You should aim to output things to 16bits (getting rid of the /32 is already a good start) and not 8.
I think we are getting there :)

Best,

Daniel Llermaly

unread,
Dec 22, 2023, 6:25:31 PM12/22/23
to Mozzi-users
hello everyone in the for
After a time in which I had to attend to other matters, I was able to resume the chord module. I finally used midi notes in mozzi, and decided not to use the dac for the moment. I didn't understand the detuning issue very well, but it was finally solved by multiplying the frequency by 0.15. Maybe I should change that factor for different scales, but for now it's pretty good.
Now what happens to me and what I have been trying to solve is that the G note sounds with a noise, a kind of beat or distortion. This always happens with notes 31, 43, etc., regardless of whether the correction factor changes and what is actually sounding is another note. Whenever the note read is G, that noise appears. If I send the data to the serial monitor I can see that the reading is quite stable, so that is not the problem too (use rolling average) I am attaching a video and the code to see if anyone has any ideas

greetings and thank you very much



WhatsApp Video 2023-12-22 at 5.20.06 PM.mp4
acordesMidi.ino.zip

tomco...@live.fr

unread,
Dec 24, 2023, 6:23:24 AM12/24/23
to Mozzi-users
Hi,

I looked at your code but did not find anything striking at the first glance. I did not try it though.
It does indeed sound like a beat… Here are some ideas for debugging:

 - do you have the possibility to visualize the waveform? If you are using PWM an analogic low pass on the output will allow you to visualize the real waveform. This is to rule out any overflow in the output.
 - does this happen will all the waveforms you have available (8, if I count well)?
 - does this happen if you remove part of your output function? For instance removing some of the terms in MonoOutput::from8Bit(aSaw1.next() / 8 + aSaw2.next() / 16 + aSaw3.next() / 16 + aSaw4.next() / 16 + aSaw5.next() / 16 * inv_aply5);

A small note while I am at it, X/8 and X/16 are equivalent to (X>>3) and (X>>4) (parenthesis are important, shift has a lower hierarchical order than divide). As the AVR has to emulate the division, this is usually very slow. That being said, as you are dividing by power of two, the compiler might optimize it away hence no gain (but I am not sure of that). Also, shifting allows you to know exactly the number of bits you have in any number. Just a suggestion.
Reply all
Reply to author
Forward
0 new messages