oPossum 1,083 Posted February 24, 2013 Share Posted February 24, 2013 When working with electronic music (MIDI synth and such) it is sometimes necessary to adjust pitch by units of octaves, semitones, or cents. An octave is a 2:1 ratio. So the ratio between any number of octaves is 2^N. This is a simple bit shift. Easy. A semitone is 1/12 of an octave (typically), so the ratio for that is 2^(N/12). A cent is 1/1200 of an octave, so the ratio for that is 2^(N/1200). Can't use bit shifting for that! The C stdlib provides the pow() function that can be used for these calculations, but it uses rather slow floating point math. This code will do it with relatively fast fixed point integer math. This code could easily be adapted to almost any base and exponent by changing the look-up tables. It uses the property of exponents that 2 ^ (1 + 2 + 4 + 8) == (2 ^ 1) * (2 ^ 2) * (2 ^ 4) * (2 ^ 8) // // 2 ^ (n / (1200 * 8192)) // // n = 1 / 8,192 cent // = 1 / 819,200 semitone // = 1 / 9,830,400 octave // // range of n: -134,217,727 to +78,643,199 // = -13.65 to +7.99 octaves // // returned value is 8.24 fixed point // // + exponents in 8.24 format static const uint32_t etp[27] = { 0x01000001, // 00000001 1.0000000705 0x01000002, // 00000002 1.0000001410 0x01000005, // 00000004 1.0000002820 0x01000009, // 00000008 1.0000005641 0x01000013, // 00000010 1.0000011282 0x01000026, // 00000020 1.0000022563 0x0100004C, // 00000040 1.0000045127 0x01000097, // 00000080 1.0000090254 0x0100012F, // 00000100 1.0000180509 0x0100025E, // 00000200 1.0000361021 0x010004BB, // 00000400 1.0000722054 0x01000977, // 00000800 1.0001444161 0x010012EE, // 00001000 1.0002888530 0x010025DE, // 00002000 1.0005777895 0x01004BC1, // 00004000 1.0011559129 0x01009798, // 00008000 1.0023131618 0x01012F8B, // 00010000 1.0046316744 0x0102607D, // 00020000 1.0092848012 0x0104C6A1, // 00040000 1.0186558100 0x0109A410, // 00080000 1.0376596592 0x0113A513, // 00100000 1.0767375682 0x0128CC11, // 00200000 1.1593637909 0x01581889, // 00400000 1.3441243996 0x01CE81F4, // 00800000 1.8066704016 0x0343994D, // 01000000 3.2640579400 0x0AA77169, // 02000000 10.6540742354 0x71826157 // 04000000 113.5092978129 }; // - exponents in 8.24 format static const uint32_t etn[27] = { 0x00FFFFFF, // 00000001 0.9999999295 0x00FFFFFE, // 00000002 0.9999998590 0x00FFFFFB, // 00000004 0.9999997180 0x00FFFFF7, // 00000008 0.9999994359 0x00FFFFED, // 00000010 0.9999988718 0x00FFFFDA, // 00000020 0.9999977437 0x00FFFFB4, // 00000040 0.9999954873 0x00FFFF69, // 00000080 0.9999909747 0x00FFFED1, // 00000100 0.9999819495 0x00FFFDA2, // 00000200 0.9999638992 0x00FFFB45, // 00000400 0.9999277998 0x00FFF689, // 00000800 0.9998556048 0x00FFED13, // 00001000 0.9997112304 0x00FFDA28, // 00002000 0.9994225441 0x00FFB455, // 00004000 0.9988454217 0x00FF68C1, // 00008000 0.9976921765 0x00FED1DC, // 00010000 0.9953896791 0x00FDA51C, // 00020000 0.9908006133 0x00FB4FC4, // 00040000 0.9816858552 0x00F6B582, // 00080000 0.9637071184 0x00EDC157, // 00100000 0.9287314100 0x00DCCF8E, // 00200000 0.8625420320 0x00BE7564, // 00400000 0.7439787570 0x008DB277, // 00800000 0.5535043908 0x004E6E13, // 01000000 0.3063671106 0x00180743, // 02000000 0.0938608065 0x0002415D // 04000000 0.0088098510 }; uint32_t tpow(int32_t n) { const uint32_t *et = etp; // Assume + exponent if(n < 0) n = -n, et = etn; // Adjust for - exponent // uint32_t r = 1L << 24; // Init result to 1.0 in 8.24 format // do { // if(n & 1) r = mul824(r, *et); // Multiply by exponent if lsb of n is 1 ++et; // Next exponent } while(n >>= 1); // Next bit, loop until no more 1 bits // return r; // Return result } SirPatrick, Rickta59, nemui-kuma and 6 others 9 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.