1 module pxtone.unit;
2 // '12/03/03
3 
4 import pxtone.pxtn;
5 
6 import pxtone.descriptor;
7 import pxtone.error;
8 import pxtone.evelist;
9 import pxtone.max;
10 import pxtone.woice;
11 
12 import std.exception;
13 
14 // v1x (20byte) =================
15 struct _x1x_UNIT {
16 	char[pxtnMAX_TUNEUNITNAME] name;
17 	ushort type;
18 	ushort group;
19 }
20 
21 ///////////////////
22 // pxtnUNIT x3x
23 ///////////////////
24 
25 struct _x3x_UNIT {
26 	ushort type;
27 	ushort group;
28 }
29 
30 struct pxtnUnit {
31 private:
32 	bool _bOperated = true;
33 	bool _bPlayed = true;
34 	char[pxtnMAX_TUNEUNITNAME + 1] _name_buf = "no name";
35 	int _name_size = "no name".length;
36 
37 	//	TUNEUNITTONESTRUCT
38 	int _key_now;
39 	int _key_start;
40 	int _key_margin;
41 	int _portament_sample_pos;
42 	int _portament_sample_num;
43 	int[pxtnMAX_CHANNEL] _pan_vols;
44 	int[pxtnMAX_CHANNEL] _pan_times;
45 	int[pxtnBUFSIZE_TIMEPAN][pxtnMAX_CHANNEL] _pan_time_bufs;
46 	int _v_VOLUME;
47 	int _v_VELOCITY;
48 	int _v_GROUPNO;
49 	float _v_TUNING = 0.0;
50 
51 	const(pxtnWoice)* _p_woice;
52 
53 	pxtnVOICETONE[pxtnMAX_UNITCONTROLVOICE] _vts;
54 
55 public:
56 
57 	void Tone_Init() nothrow @safe {
58 		_v_GROUPNO = EVENTDEFAULT_GROUPNO;
59 		_v_VELOCITY = EVENTDEFAULT_VELOCITY;
60 		_v_VOLUME = EVENTDEFAULT_VOLUME;
61 		_v_TUNING = EVENTDEFAULT_TUNING;
62 		_portament_sample_num = 0;
63 		_portament_sample_pos = 0;
64 
65 		for (int i = 0; i < pxtnMAX_CHANNEL; i++) {
66 			_pan_vols[i] = 64;
67 			_pan_times[i] = 0;
68 		}
69 	}
70 
71 	void Tone_Clear() nothrow @safe {
72 		for (int i = 0; i < pxtnMAX_CHANNEL; i++) {
73 			_pan_time_bufs[i][0 .. pxtnBUFSIZE_TIMEPAN] = 0;
74 		}
75 	}
76 
77 	void Tone_Reset_and_2prm(int voice_idx, int env_rls_clock, float offset_freq) nothrow @safe {
78 		pxtnVOICETONE* p_tone = &_vts[voice_idx];
79 		p_tone.life_count = 0;
80 		p_tone.on_count = 0;
81 		p_tone.smp_pos = 0;
82 		p_tone.smooth_volume = 0;
83 		p_tone.env_release_clock = env_rls_clock;
84 		p_tone.offset_freq = offset_freq;
85 	}
86 
87 	void Tone_Envelope() nothrow @safe {
88 		if (!_p_woice) {
89 			return;
90 		}
91 
92 		for (int v = 0; v < _p_woice.get_voice_num(); v++) {
93 			const pxtnVOICEINSTANCE* p_vi = _p_woice.get_instance(v);
94 			pxtnVOICETONE* p_vt = &_vts[v];
95 
96 			if (p_vt.life_count > 0 && p_vi.env_size) {
97 				if (p_vt.on_count > 0) {
98 					if (p_vt.env_pos < p_vi.env_size) {
99 						p_vt.env_volume = p_vi.p_env[p_vt.env_pos];
100 						p_vt.env_pos++;
101 					}
102 				}  // release.
103 				else {
104 					p_vt.env_volume = p_vt.env_start + (0 - p_vt.env_start) * p_vt.env_pos / p_vi.env_release;
105 					p_vt.env_pos++;
106 				}
107 			}
108 		}
109 	}
110 
111 	void Tone_KeyOn() nothrow @safe {
112 		_key_now = _key_start + _key_margin;
113 		_key_start = _key_now;
114 		_key_margin = 0;
115 	}
116 
117 	void Tone_ZeroLives() nothrow @safe {
118 		for (int i = 0; i < pxtnMAX_CHANNEL; i++) {
119 			_vts[i].life_count = 0;
120 		}
121 	}
122 
123 	void Tone_Key(int key) nothrow @safe {
124 		_key_start = _key_now;
125 		_key_margin = key - _key_start;
126 		_portament_sample_pos = 0;
127 	}
128 
129 	void Tone_Pan_Volume(int ch, int pan) nothrow @safe {
130 		_pan_vols[0] = 64;
131 		_pan_vols[1] = 64;
132 		if (ch == 2) {
133 			if (pan >= 64) {
134 				_pan_vols[0] = 128 - pan;
135 			} else {
136 				_pan_vols[1] = pan;
137 			}
138 		}
139 	}
140 
141 	void Tone_Pan_Time(int ch, int pan, int sps) nothrow @safe {
142 		_pan_times[0] = 0;
143 		_pan_times[1] = 0;
144 
145 		if (ch == 2) {
146 			if (pan >= 64) {
147 				_pan_times[0] = pan - 64;
148 				if (_pan_times[0] > 63) {
149 					_pan_times[0] = 63;
150 				}
151 				_pan_times[0] = (_pan_times[0] * 44100) / sps;
152 			} else {
153 				_pan_times[1] = 64 - pan;
154 				if (_pan_times[1] > 63) {
155 					_pan_times[1] = 63;
156 				}
157 				_pan_times[1] = (_pan_times[1] * 44100) / sps;
158 			}
159 		}
160 	}
161 
162 	void Tone_Velocity(int val) nothrow @safe {
163 		_v_VELOCITY = val;
164 	}
165 
166 	void Tone_Volume(int val) nothrow @safe {
167 		_v_VOLUME = val;
168 	}
169 
170 	void Tone_Portament(int val) nothrow @safe {
171 		_portament_sample_num = val;
172 	}
173 
174 	void Tone_GroupNo(int val) nothrow @safe {
175 		_v_GROUPNO = val;
176 	}
177 
178 	void Tone_Tuning(float val) nothrow @safe {
179 		_v_TUNING = val;
180 	}
181 
182 	void Tone_Sample(bool b_mute_by_unit, int ch_num, int time_pan_index, int smooth_smp) nothrow @safe {
183 		if (!_p_woice) {
184 			return;
185 		}
186 
187 		if (b_mute_by_unit && !_bPlayed) {
188 			for (int ch = 0; ch < ch_num; ch++) {
189 				_pan_time_bufs[ch][time_pan_index] = 0;
190 			}
191 			return;
192 		}
193 
194 		for (int ch = 0; ch < pxtnMAX_CHANNEL; ch++) {
195 			int time_pan_buf = 0;
196 
197 			for (int v = 0; v < _p_woice.get_voice_num(); v++) {
198 				pxtnVOICETONE* p_vt = &_vts[v];
199 				const pxtnVOICEINSTANCE* p_vi = _p_woice.get_instance(v);
200 
201 				int work = 0;
202 
203 				if (p_vt.life_count > 0) {
204 					int pos = cast(int) p_vt.smp_pos * 2 + ch;
205 					work += (cast(const(short)[])p_vi.p_smp_w)[pos];
206 
207 					if (ch_num == 1) {
208 						work += (cast(const(short)[])p_vi.p_smp_w)[pos + 1];
209 						work = work / 2;
210 					}
211 
212 					work = (work * _v_VELOCITY) / 128;
213 					work = (work * _v_VOLUME) / 128;
214 					work = work * _pan_vols[ch] / 64;
215 
216 					if (p_vi.env_size) {
217 						work = work * p_vt.env_volume / 128;
218 					}
219 
220 					// smooth tail
221 					if (_p_woice.get_voice(v).voice_flags & PTV_VOICEFLAG_SMOOTH && p_vt.life_count < smooth_smp) {
222 						work = work * p_vt.life_count / smooth_smp;
223 					}
224 				}
225 				time_pan_buf += work;
226 			}
227 			_pan_time_bufs[ch][time_pan_index] = time_pan_buf;
228 		}
229 	}
230 
231 	void Tone_Supple(int[] group_smps, int ch, int time_pan_index) const nothrow @safe {
232 		int idx = (time_pan_index - _pan_times[ch]) & (pxtnBUFSIZE_TIMEPAN - 1);
233 		group_smps[_v_GROUPNO] += _pan_time_bufs[ch][idx];
234 	}
235 
236 	int Tone_Increment_Key() nothrow @safe {
237 		// prtament..
238 		if (_portament_sample_num && _key_margin) {
239 			if (_portament_sample_pos < _portament_sample_num) {
240 				_portament_sample_pos++;
241 				_key_now = cast(int)(_key_start + cast(double) _key_margin * _portament_sample_pos / _portament_sample_num);
242 			} else {
243 				_key_now = _key_start + _key_margin;
244 				_key_start = _key_now;
245 				_key_margin = 0;
246 			}
247 		} else {
248 			_key_now = _key_start + _key_margin;
249 		}
250 		return _key_now;
251 	}
252 
253 	void Tone_Increment_Sample(float freq) nothrow @safe {
254 		if (!_p_woice) {
255 			return;
256 		}
257 
258 		for (int v = 0; v < _p_woice.get_voice_num(); v++) {
259 			const pxtnVOICEINSTANCE* p_vi = _p_woice.get_instance(v);
260 			pxtnVOICETONE* p_vt = &_vts[v];
261 
262 			if (p_vt.life_count > 0) {
263 				p_vt.life_count--;
264 			}
265 			if (p_vt.life_count > 0) {
266 				p_vt.on_count--;
267 
268 				p_vt.smp_pos += p_vt.offset_freq * _v_TUNING * freq;
269 
270 				if (p_vt.smp_pos >= p_vi.smp_body_w) {
271 					if (_p_woice.get_voice(v).voice_flags & PTV_VOICEFLAG_WAVELOOP) {
272 						if (p_vt.smp_pos >= p_vi.smp_body_w) {
273 							p_vt.smp_pos -= p_vi.smp_body_w;
274 						}
275 						if (p_vt.smp_pos >= p_vi.smp_body_w) {
276 							p_vt.smp_pos = 0;
277 						}
278 					} else {
279 						p_vt.life_count = 0;
280 					}
281 				}
282 
283 				// OFF
284 				if (p_vt.on_count == 0 && p_vi.env_size) {
285 					p_vt.env_start = p_vt.env_volume;
286 					p_vt.env_pos = 0;
287 				}
288 			}
289 		}
290 	}
291 
292 	bool set_woice(const(pxtnWoice)* p_woice) nothrow @safe {
293 		if (!p_woice) {
294 			return false;
295 		}
296 		_p_woice = p_woice;
297 		_key_now = EVENTDEFAULT_KEY;
298 		_key_margin = 0;
299 		_key_start = EVENTDEFAULT_KEY;
300 		return true;
301 	}
302 
303 	const(pxtnWoice)* get_woice() const nothrow @safe {
304 		return _p_woice;
305 	}
306 
307 	bool setNameBuf(scope const char[] name) nothrow @safe {
308 		if (!name || name.length > pxtnMAX_TUNEUNITNAME) {
309 			return false;
310 		}
311 		_name_buf[0 .. $] = 0;
312 		if (name.length) {
313 			_name_buf[0 .. name.length] = name;
314 		}
315 		_name_size = cast(int)name.length;
316 		return true;
317 	}
318 
319 	const(char)* get_name_buf(int* p_buf_size) const return nothrow @system {
320 		if (p_buf_size) {
321 			*p_buf_size = _name_size;
322 		}
323 		return _name_buf.ptr;
324 	}
325 
326 	bool is_name_buf() const nothrow @safe {
327 		if (_name_size > 0) {
328 			return true;
329 		}
330 		return false;
331 	}
332 
333 	pxtnVOICETONE* get_tone(int voice_idx) return nothrow @safe {
334 		return &_vts[voice_idx];
335 	}
336 
337 	void set_operated(bool b) nothrow @safe {
338 		_bOperated = b;
339 	}
340 
341 	void set_played(bool b) nothrow @safe {
342 		_bPlayed = b;
343 	}
344 
345 	bool get_operated() const nothrow @safe {
346 		return _bOperated;
347 	}
348 
349 	bool get_played() const nothrow @safe {
350 		return _bPlayed;
351 	}
352 
353 	void Read_v3x(ref pxtnDescriptor p_doc, int* p_group) @system {
354 		_x3x_UNIT unit;
355 		int size = 0;
356 
357 		p_doc.r(size);
358 		p_doc.r(unit);
359 		if (cast(pxtnWOICETYPE) unit.type != pxtnWOICETYPE.PCM && cast(pxtnWOICETYPE) unit.type != pxtnWOICETYPE.PTV && cast(pxtnWOICETYPE) unit.type != pxtnWOICETYPE.PTN) {
360 			throw new PxtoneException("fmt unknown");
361 		}
362 		*p_group = unit.group;
363 	}
364 
365 	void Read_v1x(ref pxtnDescriptor p_doc, int* p_group) @system {
366 		_x1x_UNIT unit;
367 		int size;
368 
369 		p_doc.r(size);
370 		p_doc.r(unit);
371 		enforce(cast(pxtnWOICETYPE) unit.type == pxtnWOICETYPE.PCM, new PxtoneException("Expecting a PCM unit"));
372 
373 		_name_buf[0 .. pxtnMAX_TUNEUNITNAME] = unit.name[0 .. pxtnMAX_TUNEUNITNAME];
374 		_name_buf[pxtnMAX_TUNEUNITNAME] = '\0';
375 		*p_group = unit.group;
376 	}
377 }