1 module pxtone.pulse.frequency;
2 
3 enum _OCTAVE_NUM = 16; // octave num.
4 enum _KEY_PER_OCTAVE = 12; // key per octave
5 enum _FREQUENCY_PER_KEY = 0x10; // sample per key
6 
7 enum _BASIC_FREQUENCY_INDEX = ((_OCTAVE_NUM / 2) * _KEY_PER_OCTAVE * _FREQUENCY_PER_KEY);
8 enum _TABLE_SIZE = (_OCTAVE_NUM * _KEY_PER_OCTAVE * _FREQUENCY_PER_KEY);
9 
10 struct pxtnPulse_Frequency {
11 	static immutable float[] _freq_table = genTables();
12 
13 	float Get(int key) const nothrow @safe {
14 		int i;
15 
16 		i = (key + 0x6000) * _FREQUENCY_PER_KEY / 0x100;
17 		if (i < 0) {
18 			i = 0;
19 		} else if (i >= _TABLE_SIZE) {
20 			i = _TABLE_SIZE - 1;
21 		}
22 		return _freq_table[i];
23 	}
24 
25 	float Get2(int key) nothrow @safe {
26 		int i = key >> 4;
27 		if (i < 0) {
28 			i = 0;
29 		} else if (i >= _TABLE_SIZE) {
30 			i = _TABLE_SIZE - 1;
31 		}
32 		return _freq_table[i];
33 	}
34 
35 	const(float)[] GetDirect(int* p_size) nothrow @safe {
36 		*p_size = _TABLE_SIZE;
37 		return _freq_table;
38 	}
39 }
40 
41 private double _GetDivideOctaveRate(int divi) nothrow @safe {
42 	double parameter = 1.0;
43 	double work;
44 	double result;
45 	double add;
46 	int i, j, k;
47 
48 	// double is 17keta.
49 	for (i = 0; i < 17; i++) {
50 		// make add.
51 		add = 1;
52 		for (j = 0; j < i; j++) {
53 			add = add * 0.1;
54 		}
55 
56 		// check 0 .. 9
57 		for (j = 0; j < 10; j++) {
58 			work = parameter + add * j;
59 
60 			// divide
61 			result = 1.0;
62 			for (k = 0; k < divi; k++) {
63 				result *= work;
64 				if (result >= 2.0) {
65 					break;
66 				}
67 			}
68 
69 			// under '2'
70 			if (k != divi) {
71 				break;
72 			}
73 		}
74 		// before '2'
75 		parameter += add * (j - 1);
76 	}
77 
78 	return parameter;
79 }
80 private float[] genTables() @safe {
81 	float[] _freq_table;
82 	static immutable double[_OCTAVE_NUM] oct_table = [0.00390625, //0  -8
83 		0.0078125, //1  -7
84 		0.015625, //2  -6
85 		0.03125, //3  -5
86 		0.0625, //4  -4
87 		0.125, //5  -3
88 		0.25, //6  -2
89 		0.5, //7  -1
90 		1, //8
91 		2, //9   1
92 		4, //a   2
93 		8, //b   3
94 		16, //c   4
95 		32, //d   5
96 		64, //e   6
97 		128, //f   7
98 	];
99 
100 	int key;
101 	int f;
102 	double oct_x24;
103 	double work;
104 
105 	_freq_table = new float[_TABLE_SIZE];
106 	//if (!(_freq_table)) {
107 	//	goto End;
108 	//}
109 
110 	oct_x24 = _GetDivideOctaveRate(_KEY_PER_OCTAVE * _FREQUENCY_PER_KEY);
111 
112 	for (f = 0; f < _OCTAVE_NUM * (_KEY_PER_OCTAVE * _FREQUENCY_PER_KEY); f++) {
113 		work = oct_table[f / (_KEY_PER_OCTAVE * _FREQUENCY_PER_KEY)];
114 		for (key = 0; key < f % (_KEY_PER_OCTAVE * _FREQUENCY_PER_KEY); key++) {
115 			work *= oct_x24;
116 		}
117 		_freq_table[f] = cast(float) work;
118 	}
119 	return _freq_table;
120 }