Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #93394 > unrolled thread
| Started by | bvdp <bob@mellowood.ca> |
|---|---|
| First post | 2015-07-01 17:12 -0700 |
| Last post | 2015-07-02 10:05 -0500 |
| Articles | 14 — 9 participants |
Back to article view | Back to comp.lang.python
"normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-01 17:12 -0700
Re: "normalizing" a value MRAB <python@mrabarnett.plus.com> - 2015-07-02 01:30 +0100
Re: "normalizing" a value Paul Rubin <no.email@nospam.invalid> - 2015-07-01 17:36 -0700
Re: "normalizing" a value Denis McMahon <denismfmcmahon@gmail.com> - 2015-07-02 01:06 +0000
Re: "normalizing" a value random832@fastmail.us - 2015-07-01 21:27 -0400
Re: "normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-01 18:49 -0700
Re: "normalizing" a value random832@fastmail.us - 2015-07-01 22:23 -0400
Re: "normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-01 19:41 -0700
Re: "normalizing" a value Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2015-07-01 23:36 -0400
Re: "normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-02 10:03 -0700
Re: "normalizing" a value Steven D'Aprano <steve@pearwood.info> - 2015-07-02 12:15 +1000
Re: "normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-01 19:42 -0700
Re: "normalizing" a value Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-07-02 05:41 +0100
Re: "normalizing" a value Skip Montanaro <skip.montanaro@gmail.com> - 2015-07-02 10:05 -0500
| From | bvdp <bob@mellowood.ca> |
|---|---|
| Date | 2015-07-01 17:12 -0700 |
| Subject | "normalizing" a value |
| Message-ID | <fd370a7b-ea6a-48e5-90f4-9d86b89a745e@googlegroups.com> |
Not sure what this is called (and I'm sure it's not normalize). Perhaps "scaling"? Anyway, I need to convert various values ranging from around -50 to 50 to an 0 to 12 range (this is part of a MIDI music program). I have a number of places where I do: while x < 0: x += 12 while x >= 12: x -= 12 Okay, that works. Just wondering if there is an easier (or faster) way to accomplish this.
[toc] | [next] | [standalone]
| From | MRAB <python@mrabarnett.plus.com> |
|---|---|
| Date | 2015-07-02 01:30 +0100 |
| Message-ID | <mailman.229.1435797056.3674.python-list@python.org> |
| In reply to | #93394 |
On 2015-07-02 01:12, bvdp wrote:
> Not sure what this is called (and I'm sure it's not normalize). Perhaps "scaling"?
>
> Anyway, I need to convert various values ranging from around -50 to 50 to an 0 to 12 range (this is part of a MIDI music program). I have a number of places where I do:
>
> while x < 0: x += 12
> while x >= 12: x -= 12
>
> Okay, that works. Just wondering if there is an easier (or faster) way to accomplish this.
>
That's called "modular arithmetic". Use the modulo operator, '%':
x = x % 12
or just:
x %= 12
[toc] | [prev] | [next] | [standalone]
| From | Paul Rubin <no.email@nospam.invalid> |
|---|---|
| Date | 2015-07-01 17:36 -0700 |
| Message-ID | <87a8vfqttm.fsf@nightsong.com> |
| In reply to | #93394 |
bvdp <bob@mellowood.ca> writes: > while x < 0: x += 12 > while x >= 12: x -= 12 > Okay, that works. Just wondering if there is an easier (or faster) way > to accomplish this. x = x % 12 should be the same as the above. But are you sure that's really what you want?
[toc] | [prev] | [next] | [standalone]
| From | Denis McMahon <denismfmcmahon@gmail.com> |
|---|---|
| Date | 2015-07-02 01:06 +0000 |
| Message-ID | <mn22qf$l6g$3@dont-email.me> |
| In reply to | #93394 |
On Wed, 01 Jul 2015 17:12:36 -0700, bvdp wrote:
> Not sure what this is called (and I'm sure it's not normalize). Perhaps
> "scaling"?
>
> Anyway, I need to convert various values ranging from around -50 to 50
> to an 0 to 12 range (this is part of a MIDI music program). I have a
> number of places where I do:
>
> while x < 0: x += 12 while x >= 12: x -= 12
>
> Okay, that works. Just wondering if there is an easier (or faster) way
> to accomplish this.
Are you sure it works? Do you simply want to reduce it to the arbitrary
range, or do you want to also retain the relationship between different x
values such that if x1 < x2, f(x1) < f(x2)?
Consider the following x values:
-11, -12, -13, 11, 12, 13
-11 -> 1
-12 -> 0
-13 -> 11
11 -> 11
12 -> 0
13 -> 1
So -13 gives the same output value as 11 in your current code. Is this
what you want?
You could try the following:
# step 1, limit x to the range -50 .. 50
if x < -50:
x = -50.0
ix x >= 50:
x = 50.0
# step 2, scale x to the range 0 .. 12
x = x * 0.12 + 6.0
If you want an integer value, you need to determine which method is most
relevant. I would suggest rounding.
--
Denis McMahon, denismfmcmahon@gmail.com
[toc] | [prev] | [next] | [standalone]
| From | random832@fastmail.us |
|---|---|
| Date | 2015-07-01 21:27 -0400 |
| Message-ID | <mailman.230.1435800465.3674.python-list@python.org> |
| In reply to | #93394 |
On Wed, Jul 1, 2015, at 20:12, bvdp wrote: > Not sure what this is called (and I'm sure it's not normalize). Perhaps > "scaling"? > > Anyway, I need to convert various values ranging from around -50 to 50 to > an 0 to 12 range (this is part of a MIDI music program). I have a number > of places where I do: > > while x < 0: x += 12 > while x >= 12: x -= 12 And this gives you what you want? With e.g. 13=1, 14=2, 22=10, 23=11, 24=0, 25 = 1, etc. Seems unusual that that's what you would want. Also note this gives an 0 to 11 range for the results, not 0 to 12. Anyway, x %= 12 will give the same results.
[toc] | [prev] | [next] | [standalone]
| From | bvdp <bob@mellowood.ca> |
|---|---|
| Date | 2015-07-01 18:49 -0700 |
| Message-ID | <948e2800-e52b-429a-9e00-f268fcff5085@googlegroups.com> |
| In reply to | #93400 |
On Wednesday, July 1, 2015 at 6:27:57 PM UTC-7, rand...@fastmail.us wrote: > On Wed, Jul 1, 2015, at 20:12, bvdp wrote: > > Not sure what this is called (and I'm sure it's not normalize). Perhaps > > "scaling"? > > > > Anyway, I need to convert various values ranging from around -50 to 50 to > > an 0 to 12 range (this is part of a MIDI music program). I have a number > > of places where I do: > > > > while x < 0: x += 12 > > while x >= 12: x -= 12 > > And this gives you what you want? With e.g. 13=1, 14=2, 22=10, 23=11, > 24=0, 25 = 1, etc. Seems unusual that that's what you would want. > > Also note this gives an 0 to 11 range for the results, not 0 to 12. > > Anyway, x %= 12 will give the same results. Thanks guys. Yes, that is exactly what I want. I have a number of places where a MIDI note value is being generated. MIDI should be 0..127, but the process creates notes outside the range. Guess that's another question: if the value I have is <0 or >127 I add/subtract 12 'til it's in range. Don't see using modulo working on this??? As far as the original question: Yes, that's what I need. At times I need to take a note (say 14) and map it into a single octave range. So, the 12 becomes 2. Both 14 and 2 are numeric values for note "d", just an octave apart. Interesting that negative values translate properly. That's an non-intuitive result to me. Guess I should have studied that math stuff harder way back when!
[toc] | [prev] | [next] | [standalone]
| From | random832@fastmail.us |
|---|---|
| Date | 2015-07-01 22:23 -0400 |
| Message-ID | <mailman.231.1435803787.3674.python-list@python.org> |
| In reply to | #93401 |
On Wed, Jul 1, 2015, at 21:49, bvdp wrote: > Interesting that negative values translate properly. That's an > non-intuitive result to me. Guess I should have studied that math stuff > harder way back when! There are multiple interpretations of the operation, and not all languages behave the same way as Python does with negative operands. Python is the odd one out when one considers C/C++, C#, and Java which all behave a different way. In general, almost all languages behave in a way so that given q, r = a // b, a % b; q * b + r == a. However, this simply changes the question to how division results involving negative operands are rounded. Here's an article by GvR about why python behaves the way it does: http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
[toc] | [prev] | [next] | [standalone]
| From | bvdp <bob@mellowood.ca> |
|---|---|
| Date | 2015-07-01 19:41 -0700 |
| Message-ID | <7016792e-ac01-4ee5-a644-1bea9a204d8c@googlegroups.com> |
| In reply to | #93405 |
On Wednesday, July 1, 2015 at 7:23:19 PM UTC-7, rand...@fastmail.us wrote: > On Wed, Jul 1, 2015, at 21:49, bvdp wrote: > > Interesting that negative values translate properly. That's an > > non-intuitive result to me. Guess I should have studied that math stuff > > harder way back when! > > There are multiple interpretations of the operation, and not all > languages behave the same way as Python does with negative operands. > Python is the odd one out when one considers C/C++, C#, and Java which > all behave a different way. > > In general, almost all languages behave in a way so that given q, r = a > // b, a % b; q * b + r == a. However, this simply changes the question > to how division results involving negative operands are rounded. > > Here's an article by GvR about why python behaves the way it does: > http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html Interesting link. Thanks. I always thought that modulo was modulo. Guess this is another example of why converting code between languages is hard :) Anyway, far as shoving my MIDI notes into a single octave, x % 12 seems to be perfect.
[toc] | [prev] | [next] | [standalone]
| From | Dennis Lee Bieber <wlfraed@ix.netcom.com> |
|---|---|
| Date | 2015-07-01 23:36 -0400 |
| Message-ID | <mailman.233.1435808221.3674.python-list@python.org> |
| In reply to | #93401 |
On Wed, 1 Jul 2015 18:49:34 -0700 (PDT), bvdp <bob@mellowood.ca> declaimed
the following:
>
>Thanks guys. Yes, that is exactly what I want. I have a number of places where a MIDI note value is being generated. MIDI should be 0..127, but the process creates notes outside the range. Guess that's another question: if the value I have is <0 or >127 I add/subtract 12 'til it's in range. Don't see using modulo working on this???
>
>As far as the original question: Yes, that's what I need. At times I need to take a note (say 14) and map it into a single octave range. So, the 12 becomes 2. Both 14 and 2 are numeric values for note "d", just an octave apart.
>
Modulo will give you the "note", but throws out the octave.
Your original post specified -50..50, which spans only 101 values, whereas
MIDI spans 128 values -- so what do you really consider out of range? And
what MIDI value is -50 supposed to map against. Is input 0 supposed to
represent middle-C with negative values being notes on the bass clef and
positive values being treble clef?
MIDI middle-C is note 60. Presuming your 0 is supposed to be middle-C, I'd
do the transformation as:
midiNote = invalue + 60
if midiNote < 0: midiNote = midiNote % 12
if midiNote > 127: midiNote = (midiNote % 12) + 115
which actually means input values of -60..+67 are shifted directly to a
midi note number, and values outside of that range are shadowed as the
lowest or highest octave.
>>> for i in range(-70, 80, 4):
... midiNote = i + 60
... if midiNote < 0: midiNote = midiNote % 12
... if midiNote > 127: midiNote = ((midiNote - 5) % 12) + 113
... print i, midiNote, "CcDdEFfGgAaB"[midiNote % 12], divmod(midiNote,
12)
...
-70 2 D (0, 2)
-66 6 f (0, 6)
-62 10 a (0, 10)
-58 2 D (0, 2)
-54 6 f (0, 6)
-50 10 a (0, 10)
-46 14 D (1, 2)
-42 18 f (1, 6)
-38 22 a (1, 10)
-34 26 D (2, 2)
-30 30 f (2, 6)
-26 34 a (2, 10)
-22 38 D (3, 2)
-18 42 f (3, 6)
-14 46 a (3, 10)
-10 50 D (4, 2)
-6 54 f (4, 6)
-2 58 a (4, 10)
2 62 D (5, 2)
6 66 f (5, 6)
10 70 a (5, 10)
14 74 D (6, 2)
18 78 f (6, 6)
22 82 a (6, 10)
26 86 D (7, 2)
30 90 f (7, 6)
34 94 a (7, 10)
38 98 D (8, 2)
42 102 f (8, 6)
46 106 a (8, 10)
50 110 D (9, 2)
54 114 f (9, 6)
58 118 a (9, 10)
62 122 D (10, 2)
66 126 f (10, 6)
70 118 a (9, 10)
74 122 D (10, 2)
78 114 f (9, 6)
>>>
The oddity for the >127 case is that 127 is not an even octave break point.
divmod() gives you the "octave" and the note.
--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com HTTP://wlfraed.home.netcom.com/
[toc] | [prev] | [next] | [standalone]
| From | bvdp <bob@mellowood.ca> |
|---|---|
| Date | 2015-07-02 10:03 -0700 |
| Message-ID | <4c0721c0-b5f5-4e0d-9db4-822f838f3708@googlegroups.com> |
| In reply to | #93410 |
On Wednesday, July 1, 2015 at 8:37:18 PM UTC-7, Dennis Lee Bieber wrote: > On Wed, 1 Jul 2015 18:49:34 -0700 (PDT), bvdp <bob@mellowood.ca> declaimed > the following: > > > > >Thanks guys. Yes, that is exactly what I want. I have a number of places where a MIDI note value is being generated. MIDI should be 0..127, but the process creates notes outside the range. Guess that's another question: if the value I have is <0 or >127 I add/subtract 12 'til it's in range. Don't see using modulo working on this??? > > > >As far as the original question: Yes, that's what I need. At times I need to take a note (say 14) and map it into a single octave range. So, the 12 becomes 2. Both 14 and 2 are numeric values for note "d", just an octave apart. > > > > Modulo will give you the "note", but throws out the octave. > > Your original post specified -50..50, which spans only 101 values, whereas > MIDI spans 128 values -- so what do you really consider out of range? And > what MIDI value is -50 supposed to map against. Is input 0 supposed to > represent middle-C with negative values being notes on the bass clef and > positive values being treble clef? > > MIDI middle-C is note 60. Presuming your 0 is supposed to be middle-C, I'd > do the transformation as: > > midiNote = invalue + 60 > if midiNote < 0: midiNote = midiNote % 12 > if midiNote > 127: midiNote = (midiNote % 12) + 115 > > which actually means input values of -60..+67 are shifted directly to a > midi note number, and values outside of that range are shadowed as the > lowest or highest octave. > > >>> for i in range(-70, 80, 4): > ... midiNote = i + 60 > ... if midiNote < 0: midiNote = midiNote % 12 > ... if midiNote > 127: midiNote = ((midiNote - 5) % 12) + 113 > ... print i, midiNote, "CcDdEFfGgAaB"[midiNote % 12], divmod(midiNote, > 12) > ... > -70 2 D (0, 2) > -66 6 f (0, 6) > -62 10 a (0, 10) > -58 2 D (0, 2) > -54 6 f (0, 6) > -50 10 a (0, 10) > -46 14 D (1, 2) > -42 18 f (1, 6) > -38 22 a (1, 10) > -34 26 D (2, 2) > -30 30 f (2, 6) > -26 34 a (2, 10) > -22 38 D (3, 2) > -18 42 f (3, 6) > -14 46 a (3, 10) > -10 50 D (4, 2) > -6 54 f (4, 6) > -2 58 a (4, 10) > 2 62 D (5, 2) > 6 66 f (5, 6) > 10 70 a (5, 10) > 14 74 D (6, 2) > 18 78 f (6, 6) > 22 82 a (6, 10) > 26 86 D (7, 2) > 30 90 f (7, 6) > 34 94 a (7, 10) > 38 98 D (8, 2) > 42 102 f (8, 6) > 46 106 a (8, 10) > 50 110 D (9, 2) > 54 114 f (9, 6) > 58 118 a (9, 10) > 62 122 D (10, 2) > 66 126 f (10, 6) > 70 118 a (9, 10) > 74 122 D (10, 2) > 78 114 f (9, 6) > >>> > > The oddity for the >127 case is that 127 is not an even octave break point. > divmod() gives you the "octave" and the note. > -- > Wulfraed Dennis Lee Bieber AF6VN > wlfraed@ix.netcom.com HTTP://wlfraed.home.netcom.com/ Thanks. I like your solution for values <0 >127. Makes more sense than mindlessly adding/subtracting 12 to bring into range. In this case I'm just trying to take an out-of-range note to the top/bottom of the valid midi range.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2015-07-02 12:15 +1000 |
| Message-ID | <55949eaf$0$1642$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #93394 |
On Thu, 2 Jul 2015 10:12 am, bvdp wrote:
> Not sure what this is called (and I'm sure it's not normalize). Perhaps
> "scaling"?
Could be normalising, could be scaling.
> Anyway, I need to convert various values ranging from around -50 to 50 to
> an 0 to 12 range (this is part of a MIDI music program). I have a number
> of places where I do:
You say "around" -50 to 50. Can you get 51? 151? How do you want to treat
such out of range numbers?
Are the values integer valued, or can they include fractional values like
27.356?
> while x < 0: x += 12
> while x >= 12: x -= 12
>
> Okay, that works. Just wondering if there is an easier (or faster) way to
> accomplish this.
One approach is to just re-scale the numbers from the range -50...50 to
0...12 inclusive. That is:
before => after
-50 => 0
0 => 6
50 => 12
and everything in between is scaled equivalently. Given x between -50 and 50
inclusive, calculate:
y = (x+50)/100.0*12
(Note that in Python 2, you need to make at least one of those values a
float, otherwise you may get unexpected results.)
That will give you y values from the range 0.0 to 12.0 inclusive. If x is
less than -50.0 or more than +50.0 y will likewise be out of range. You can
clip the result:
y = min(12.0, max(0.0, y))
If your x values are integer values (no fractional values) between -50 and
+50 you can use clock arithmetic. Think of a clock marked 0 to 12 (so there
are 13 values), once you reach 12 adding 1 takes you back to 0.
0, 13, 26, 39 => 0
1, 14, 27, 40 => 1
2, 15, 28, 41 => 2
...
12, 25, 38, 51 => 12
Extending that to negative values in the most obvious fashion:
-1, -14, -27, -40 => 12
...
-12, -25, -38, -51 => 1
-13, -26, -39, -52 => 0
We can do that easily with the % (modulo) operator:
y = x % y
Modulo even works with non-integer values:
py> 13.5 % 13
0.5
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | bvdp <bob@mellowood.ca> |
|---|---|
| Date | 2015-07-01 19:42 -0700 |
| Message-ID | <29e00fb7-ac8f-41d7-b59b-4e0a39c77496@googlegroups.com> |
| In reply to | #93404 |
On Wednesday, July 1, 2015 at 7:15:28 PM UTC-7, Steven D'Aprano wrote: > On Thu, 2 Jul 2015 10:12 am, bvdp wrote: > > > Not sure what this is called (and I'm sure it's not normalize). Perhaps > > "scaling"? > > > Could be normalising, could be scaling. > > > Anyway, I need to convert various values ranging from around -50 to 50 to > > an 0 to 12 range (this is part of a MIDI music program). I have a number > > of places where I do: > > You say "around" -50 to 50. Can you get 51? 151? How do you want to treat > such out of range numbers? > > Are the values integer valued, or can they include fractional values like > 27.356? > > > while x < 0: x += 12 > > while x >= 12: x -= 12 > > > > Okay, that works. Just wondering if there is an easier (or faster) way to > > accomplish this. > > > One approach is to just re-scale the numbers from the range -50...50 to > 0...12 inclusive. That is: > > before => after > -50 => 0 > 0 => 6 > 50 => 12 > > > and everything in between is scaled equivalently. Given x between -50 and 50 > inclusive, calculate: > > y = (x+50)/100.0*12 > > > (Note that in Python 2, you need to make at least one of those values a > float, otherwise you may get unexpected results.) > > That will give you y values from the range 0.0 to 12.0 inclusive. If x is > less than -50.0 or more than +50.0 y will likewise be out of range. You can > clip the result: > > y = min(12.0, max(0.0, y)) > > If your x values are integer values (no fractional values) between -50 and > +50 you can use clock arithmetic. Think of a clock marked 0 to 12 (so there > are 13 values), once you reach 12 adding 1 takes you back to 0. > > 0, 13, 26, 39 => 0 > 1, 14, 27, 40 => 1 > 2, 15, 28, 41 => 2 > ... > 12, 25, 38, 51 => 12 > > > Extending that to negative values in the most obvious fashion: > > -1, -14, -27, -40 => 12 > ... > -12, -25, -38, -51 => 1 > -13, -26, -39, -52 => 0 > > > We can do that easily with the % (modulo) operator: > > y = x % y > > > Modulo even works with non-integer values: > > py> 13.5 % 13 > 0.5 > > > > -- > Steven Thanks for this Steven. However, I think it's not correct in this case. Like I said in another message X%12 is working just fine. No matter what the value is.
[toc] | [prev] | [next] | [standalone]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2015-07-02 05:41 +0100 |
| Message-ID | <mailman.234.1435812108.3674.python-list@python.org> |
| In reply to | #93394 |
On 02/07/2015 01:12, bvdp wrote: > Not sure what this is called (and I'm sure it's not normalize). Perhaps "scaling"? > > Anyway, I need to convert various values ranging from around -50 to 50 to an 0 to 12 range (this is part of a MIDI music program). I have a number of places where I do: > > while x < 0: x += 12 > while x >= 12: x -= 12 > > Okay, that works. Just wondering if there is an easier (or faster) way to accomplish this. > Further to other answers have you tried looking for a library, or even just a recipe, that has already been written and tested that does this for you? -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence
[toc] | [prev] | [next] | [standalone]
| From | Skip Montanaro <skip.montanaro@gmail.com> |
|---|---|
| Date | 2015-07-02 10:05 -0500 |
| Message-ID | <mailman.244.1435849550.3674.python-list@python.org> |
| In reply to | #93394 |
This looks like a straightforward linear transformation issue to me (like Fahrenheit to Celsius). Add 50 to all input values, giving you values in the range 0 to 100. Then scale them into your 0 to 12 range by multiplying them by 12/100: >>> for n in range(-50, 50, 3): ... print n, n + 50, (n + 50) * 12 / 100 ... -50 0 0.0 -47 3 0.36 -44 6 0.72 -41 9 1.08 -38 12 1.44 ... 34 84 10.08 37 87 10.44 40 90 10.8 43 93 11.16 46 96 11.52 49 99 11.88 Did I misread your request in some way? Skip
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web