[Csnd] A puzzlement

In this code (adapted from a full piece), I am taking incoming MIDI notes, converting to pch (octave.pitch-class) form, and then using a macro to “transpose” the pitch-class portion so that it is three semitones lower, but I want to keep it in the 0-11 range. The transposed value is printed as “iidx”.

The “transposition” is done with the Index macro, which as you can see subtracts 3, adds 13, and then returns the sum modulo 12.

When I play E-flat (MIDI 51), idx is 0 as expected. This is also true for any lower octave of E-flat. However, if I play E-flat one or more octaves higher (MIDI 63 or higher octaves), idx is 12.

I don’t understand how this is possible. How can 12 % 12 ever be anything but 0?

I hope someone can explain this before I lose what is left of my mind! I’m using Csound 7 built from the latest development code as of yesterday.

  • Dave
-d -m128 -n -Ma sr=48000 ksmps=1 nchnls=2 0dbfs=1

#define Index(N) #(($N - 3) + 12) % 12#

massign 0, 1
instr 1
inote = notnum()
ipch = pchmidinn(inote)
ioct = int(ipch)
itmp = frac(ipch) * 100
print itmp
iidx = $Index(itmp)
prints(“note=%d pch=%f oct=%f tmp=%f iidx=%f\n”, inote, ipch, ioct, itmp, iidx)
endin

f 0 36000 e

Csound mailing list Csound@listserv.heanet.ie https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND Send bugs reports to https://github.com/csound/csound/issues Discussions of bugs and features can be posted here

Correction: the macro subtracts 3, then adds 12, and returns the sum modulo 12.

Hi Dave,
I see that you multiply the fractional pitch by 100. Shouldn't this be 10?

At any rate, why not, work on the MIDI note first and then convert? I don't know how much of a change it will make, but it seems simpler and thus less error prone and easier to debug.

Best wishes,

Jeanette

Without examining it in detail, I think the issue that you are encountering is that one
expects the frac(x)*100 to be a whole number but the floating point operations are not giving you that.

What you are getting printed is an approximation so you don’t see it immediately.

See for instance representable numbers in

https://en.m.wikipedia.org/wiki/Floating-point_arithmetic

Since all numbers in Csound are floating-point there are some surprising results in certain type of arithmetic expressions.

Prof. Victor Lazzarini

Maynooth University
Ireland

Thanks, Jeanette. 100 is correct, because the pitch-class number uses the two digits to the right of the decimal point. For example, the note C# would be (depending on the octave) something like 8.01, so to make .01 an integer it must be multiplied by 100.

That’s an interesting idea of just working with the MIDI note directly, and I’ll look into that. Thanks for the suggestion!

  • Dave

Thanks, Victor, I was afraid it would be something like that. Since there’s no way to force Csound to treat a number as a plain (non floating point) integer, I may need to follow Jeanette’s suggestion and work with the MIDI note number directly.

  • Dave

hi dave -

you mention that "there's no way to force Csound to treat a number as a plain (non floating point) integer".

but when you use round(x)?

best -
  joachim

I think that even if you use round or floor (or int), the underlying data representation is still a floating point number. Usually this is not an issue, I guess I just hit an edge case.

This seems to work here:

#define Index(N) #round(($N - 3) + 12) % 12#

It does work, in general. If I put that expression in a loop where N runs from 0 to 11, all the answers are correct. But in context, where N is derived from a pch value and promoted to an integer using “frac(ipch) * 100”, it fails for inputs over a certain value. This is 100% repeatable, at least for me.

I have switched to just using “(inote - 3) % 12”, where inote is the value returned from notnum(), and this is working for all input values.