I thought it would be best practice to start learning a bit more about audio development. Edges eurorack code seems ideal to it It’s focused on only a few functions and it doesn’t seem super complex.
However I (already) fail to understand the usage of bitwise operations in the voice allocation class.
I’m quite new to it. When I program, I only use decimal numbers and const to indicate things. Edges source code is using bitwise operations all the time. I know how to count bitwise and what the operators do, however I’m not sure why, when and how to use it for code.
E.g. I try to understand this peace of code:
pool_[voice] = 0x80 | note;
// … later:
if ((pool_[voice] & 0x7f) == note) {
// I tried it and it’s true, but why is it true? is there any way to understand this? I know what & and | is doing, but not why to use it.
}
Why not directly saving the note value e.g. 60 and then check it? Maybe there is something I’m missing
Or in noteOff you are using: pool_[voice] &= 0x7f;
Why not pool_[voice] = 0;?
Same: clearNotes: lru_[i] = kMaxPolyphony – i – 1; //e.g. lru_0 = 4 – 0 – 1 = 3? Why 3?
ClearNotes could be lru_0 = 0?
And where is the difference between lru_[] and pool_[]?
You’re looking at a rather difficult chunk of code!
pool_ stores the state of each voice. lru_ is used to figure out the “age” of each voice - the lower the number, the most recent the voice has been used, the less desirable it is to steal it.
I stuff two pieces of information in the pool_ array. The highest bit is whether the note is active; the lowest 7 bits is the actual MIDI note. To retrieve the note, I mask the 7 lower bits (& 0x7f). To retrieve the highest bit, I mask the highest bit (& 0x80). To write both a note and an “active note” bit, I or both (0x80 | note). To clear the “active note” bit, I mask the rest of the data with a 7 lower bits mask (& 0x7f). Now why do I need to store both pieces of information? When a new note arrive and I need to allocate a channel for it, I want to use, in priority, the least recently used inactive channel (there might still be the “tail” of a decaying envelope…) ; if none is available, the least recently used active channel. So even if a note is off I still need to keep track of it in the array!
The LRU array (“least recently used” – that’s very classic computer science stuff) is filled “backwards” because when I start the machine I want the first note played to be sent to the first channel, then on the second channel etc (it would be weird if when you boot up Ambika or a MIDIpal dispatcher or Edges and press a first note in poly mode, you’d get the last voicecard/MIDI channel/channel to sound). So the channel 1 has to be marked as least recently used