OSDN Git Service

#40813 コミット漏れ。
[dtxmania/dtxmania.git] / NVorbis / Utils.cs
1 /****************************************************************************
2  * NVorbis                                                                  *
3  * Copyright (C) 2014, Andrew Ward <afward@gmail.com>                       *
4  *                                                                          *
5  * See COPYING for license terms (Ms-PL).                                   *
6  *                                                                          *
7  ***************************************************************************/
8 namespace NVorbis
9 {
10     static class Utils
11     {
12         static internal int ilog(int x)
13         {
14             int cnt = 0;
15             while (x > 0)
16             {
17                 ++cnt;
18                 x >>= 1;    // this is safe because we'll never get here if the sign bit is set
19             }
20             return cnt;
21         }
22
23         static internal uint BitReverse(uint n)
24         {
25             return BitReverse(n, 32);
26         }
27
28         static internal uint BitReverse(uint n, int bits)
29         {
30             n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1);
31             n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2);
32             n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4);
33             n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8);
34             return ((n >> 16) | (n << 16)) >> (32 - bits);
35         }
36
37         // make it so we can twiddle bits in a float...
38         [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
39         struct FloatBits
40         {
41             [System.Runtime.InteropServices.FieldOffset(0)]
42             public float Float;
43             [System.Runtime.InteropServices.FieldOffset(0)]
44             public uint Bits;
45         }
46
47         static internal float ClipValue(float value, ref bool clipped)
48         {
49             /************
50              * There is some magic happening here... IEEE 754 single precision floats are built such that:
51              *   1) The only difference between x and -x is the sign bit (31)
52              *   2) If x is further from 0 than y, the bitwise value of x is greater than the bitwise value of y (ignoring the sign bit)
53              * 
54              * With those assumptions, we can just look for the bitwise magnitude to be too large...
55              */
56
57             FloatBits fb;
58             fb.Bits = 0;
59             fb.Float = value;
60
61             // as a courtesy to those writing out 24-bit and 16-bit samples, our full scale is 0.99999994 instead of 1.0
62             if ((fb.Bits & 0x7FFFFFFF) > 0x3f7fffff) // 0x3f7fffff == 0.99999994f
63             {
64                 clipped = true;
65                 fb.Bits = 0x3f7fffff | (fb.Bits & 0x80000000);
66             }
67             return fb.Float;
68         }
69
70         static internal float ConvertFromVorbisFloat32(uint bits)
71         {
72             // do as much as possible with bit tricks in integer math
73             var sign = ((int)bits >> 31);   // sign-extend to the full 32-bits
74             var exponent = (double)((int)((bits & 0x7fe00000) >> 21) - 788);  // grab the exponent, remove the bias, store as double (for the call to System.Math.Pow(...))
75             var mantissa = (float)(((bits & 0x1fffff) ^ sign) + (sign & 1));  // grab the mantissa and apply the sign bit.  store as float
76
77             // NB: We could use bit tricks to calc the exponent, but it can't be more than 63 in either direction.
78             //     This creates an issue, since the exponent field allows for a *lot* more than that.
79             //     On the flip side, larger exponent values don't seem to be used by the Vorbis codebooks...
80             //     Either way, we'll play it safe and let the BCL calculate it.
81
82             // now switch to single-precision and calc the return value
83             return mantissa * (float)System.Math.Pow(2.0, exponent);
84         }
85
86         // this is a no-allocation way to sum an int queue
87         static internal int Sum(System.Collections.Generic.Queue<int> queue)
88         {
89             var value = 0;
90             for (int i = 0; i < queue.Count; i++)
91             {
92                 var temp = queue.Dequeue();
93                 value += temp;
94                 queue.Enqueue(temp);
95             }
96             return value;
97         }
98     }
99 }