Math challenge :) 120 to 255

Hey everyone,

I'm programming a midi synth and need to convert notenumbers (0 to 127) to -128 to + 128 values for tuning a synth

I totally have no idea on how to convert this in c++

Any ideas? So middle C = 0 low C = -128

Well it's approximately n * 2 - 128
yea I was going to suggest that but if you need it precisely you will need to add a small amount for each value such that at 127 you add 2, and at 0 you add 0. This, more or less, you can tinker with it if you want to.

1
2
3
4
5
6
7
8
9
for(a = 0; a < 128; a++)
  {
	 b = (a-128) + a + (a+1)/64; //edit: I like a+1 a little better here
//but the +1 depends on whether you want the roundoff on the low or high end.
//or you can try to add even more junk to it so both ends match a little better. 
//one cheesy way is to do BOTH the +1 and not, and make a lookup table where you take 
//half of each result.  
	 cout << a << " " << b << endl; 	  
  }	  


doing it on both ends, then, like the lookup table I mentioned but via computations:
b = (a-128) + a + (a+(a-64>0))/64;

Important a and b are DOUBLES
Last edited on
Forgetting code for the moment, how you do this by hand using pen/paper?

The 'obvious' way is to multiply by 2 and subtract 128 - but that gives a range of -128 to +126. This gives 64 as the new 0.

Middle c is 60 on a scale of 0 - 127 so you want 60 to be the new 0?

127 -> 128
60 -> 0
0 -> -128

This isn't a straight linear conversion!

Can you provide some examples of the required conversion values?

As salem c points out there is a bit of bias, but a rough calculation gives reasonably close numbers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

int convert(int i)
{
   i *= 2;

   i -= 128;

   return i;
}

int main()
{
   std::cout << 0 << ' ' << convert(0) << '\n';

   std::cout << 127 << ' ' << convert(127) << '\n';
}
0 -128
127 126

It is possible to get a closer match for -128 to 128, but doing that would require some weighting. -128 to 126 is not a bad approximation.
Last edited on
Hey, in the mean time I found out that I don't need negative values, so the conversion would be from 0to120 -> 0to255 do the math would be *2,125 I think? but i can't have digit values so i guess it needs to be rounded, i don't know the syntax for that
@jonnin - that gives a range of -128 to +127 with 60 giving -8 rather than the required 0.
You are right, was looking at the ends too much and forgot the middle. ...

the syntax for rounding is std::round(value);
depending on what you really want, floor(), ceil() are also options, as are a couple of others.
Last edited on
Strict number conversion, without music note biasing....

0 ~ 120 converted to 0 ~ 255:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

unsigned int convert(unsigned int i)
{
  return static_cast<unsigned>(i * 2.125 + 0.5);
}

int main()
{
   std::cout << 0 << ' ' << convert(0) << '\n';

   std::cout << 120 << ' ' << convert(120) << '\n';
}
0 0
120 255

Why the cast? So the compiler doesn't complain with a warning about a "conversion from double to unsigned int, possible loss of data."
Last edited on
If the number is the midi number and it is being used to convert to a frequency/musical note scale then the conversion is more complicated.

See: https://newt.phys.unsw.edu.au/jw/notes.html which shows you how to do it with various equations.
yea the math side is just round(a/127.0 * 256 -128).
that is simple: you take the percent of what you have * the percent of the RANGE-DISTANCE you want and then shift the result to fit in the range you wanted.
but the midi/music side isnt, and I was trying to account for it (very badly) above.
I am starting to think you really are going to just want a lookup table.
Last edited on
@wimvandenborre

What do want middle c (60 on the original scale) to be in the new scale?

Do you mean 0 - 120 as opposed to 0 - 127 ?

Using the convert function in George's post above and an input range of 0 - 120, then the conversion gives:


0 0
1 2
2 4
3 6
4 9
5 11
6 13
7 15
8 17
9 19
10 21
11 23
12 26
13 28
14 30
15 32
16 34
17 36
18 38
19 40
20 43
21 45
22 47
23 49
24 51
25 53
26 55
27 57
28 60
29 62
30 64
31 66
32 68
33 70
34 72
35 74
36 77
37 79
38 81
39 83
40 85
41 87
42 89
43 91
44 94
45 96
46 98
47 100
48 102
49 104
50 106
51 108
52 111
53 113
54 115
55 117
56 119
57 121
58 123
59 125
60 128
61 130
62 132
63 134
64 136
65 138
66 140
67 142
68 145
69 147
70 149
71 151
72 153
73 155
74 157
75 159
76 162
77 164
78 166
79 168
80 170
81 172
82 174
83 176
84 179
85 181
86 183
87 185
88 187
89 189
90 191
91 193
92 196
93 198
94 200
95 202
96 204
97 206
98 208
99 210
100 213
101 215
102 217
103 219
104 221
105 223
106 225
107 227
108 230
109 232
110 234
111 236
112 238
113 240
114 242
115 244
116 247
117 249
118 251
119 253
120 255


Are these the correct numbers you are looking for?

1
2
3
4
5
6
7
8
9
#include <iostream>

int main() {
	for (unsigned a {}; a <= 120; ++a) {
		const auto b {static_cast<unsigned>(a * 2.125 + 0.5)};

		std::cout << a << " " << b << '\n';
	}
}

Last edited on
so the thing is the midi note does'nt needs to be translated to hertz, a piano indeed has 88 keys as againtry's link. but a midi synth can go from 0 to 120, this will then be outputted to a tuning knob that goes from -128 to 127. So I think that will work with basic math, I'm only receiving the synth tonight so I can't test for the moment, will keep you guys updated how it goes!!!
https://www.inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies

Middle C is 60 and (a pure) orchestra A is 69 on that scale.
Last edited on
https://www.inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies

It looks like MIDI range exceeds the range at both ends of a standard piano or organ.

The formula to get frequency from a MIDI number is, wow, complex, yet fairly easy(?) to convert to C/C++.

This looks like something I'd get a library to handle. Maybe the synthesizer might have documentation with a link.
It is possible to get a number progression -128 to +128 from 0 to +127, zero-centered on 60.
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

int main()
{
	for (int a {}; a <= 120; ++a)
	{
		const auto b { static_cast<int>(a * 2.13 + 0.5) - 128 };

		std::cout << a << " " << b << '\n';
	}
}

I'm about all music maths-ed out.

I don't know how well that would work with the synthesizer and the tuning knob setup.

Somewhere/somehow I've got 440Hz dancing in my noggin.
Dealing with the MIDI numbers that correspond to a piano keyboard, 21 to 108, the tuning knob limits are -83 to +102.
George P wrote:
It looks like MIDI range exceeds the range at both ends of a standard piano or organ.

It's nearly 11 octaves! Would scare my cat at the top of the range.


George P wrote:
Somewhere/somehow I've got 440Hz dancing in my noggin.

It's what you usually tune an orchestra to ("concert A").
Last edited on
lastchance wrote:
It's nearly 11 octaves! Would scare my cat at the top of the range.

Ah, some Klingon or Narn Opera, eh?
Topic archived. No new replies allowed.