1 module pxtone.service;
2 
3 import pxtone.pxtn;
4 
5 import pxtone.descriptor;
6 import pxtone.pulse.noisebuilder;
7 
8 import pxtone.error;
9 import pxtone.max;
10 import pxtone.text;
11 import pxtone.delay;
12 import pxtone.overdrive;
13 import pxtone.master;
14 import pxtone.woice;
15 import pxtone.pulse.frequency;
16 import pxtone.unit;
17 import pxtone.evelist;
18 
19 import std.algorithm.comparison;
20 import std.exception;
21 import std.format;
22 import std.math;
23 import std.stdio;
24 import std.typecons;
25 
26 enum PXTONEERRORSIZE = 64;
27 
28 enum pxtnFlags {
29 	loop = 1 << 0,
30 	unitMute = 1 << 1
31 }
32 
33 enum _VERSIONSIZE = 16;
34 enum _CODESIZE = 8;
35 
36 //                                       0123456789012345
37 immutable _code_tune_x2x = "PTTUNE--20050608";
38 immutable _code_tune_x3x = "PTTUNE--20060115";
39 immutable _code_tune_x4x = "PTTUNE--20060930";
40 immutable _code_tune_v5 = "PTTUNE--20071119";
41 
42 immutable _code_proj_x1x = "PTCOLLAGE-050227";
43 immutable _code_proj_x2x = "PTCOLLAGE-050608";
44 immutable _code_proj_x3x = "PTCOLLAGE-060115";
45 immutable _code_proj_x4x = "PTCOLLAGE-060930";
46 immutable _code_proj_v5 = "PTCOLLAGE-071119";
47 
48 immutable _code_x1x_PROJ = "PROJECT=";
49 immutable _code_x1x_EVEN = "EVENT===";
50 immutable _code_x1x_UNIT = "UNIT====";
51 immutable _code_x1x_END = "END=====";
52 immutable _code_x1x_PCM = "matePCM=";
53 
54 immutable _code_x3x_pxtnUNIT = "pxtnUNIT";
55 immutable _code_x4x_evenMAST = "evenMAST";
56 immutable _code_x4x_evenUNIT = "evenUNIT";
57 
58 immutable _code_antiOPER = "antiOPER"; // anti operation(edit)
59 
60 immutable _code_num_UNIT = "num UNIT";
61 immutable _code_MasterV5 = "MasterV5";
62 immutable _code_Event_V5 = "Event V5";
63 immutable _code_matePCM = "matePCM ";
64 immutable _code_matePTV = "matePTV ";
65 immutable _code_matePTN = "matePTN ";
66 immutable _code_mateOGGV = "mateOGGV";
67 immutable _code_effeDELA = "effeDELA";
68 immutable _code_effeOVER = "effeOVER";
69 immutable _code_textNAME = "textNAME";
70 immutable _code_textCOMM = "textCOMM";
71 immutable _code_assiUNIT = "assiUNIT";
72 immutable _code_assiWOIC = "assiWOIC";
73 immutable _code_pxtoneND = "pxtoneND";
74 
75 enum _enum_Tag {
76 	Unknown = 0,
77 	antiOPER,
78 
79 	x1x_PROJ,
80 	x1x_UNIT,
81 	x1x_PCM,
82 	x1x_EVEN,
83 	x1x_END,
84 	x3x_pxtnUNIT,
85 	x4x_evenMAST,
86 	x4x_evenUNIT,
87 
88 	num_UNIT,
89 	MasterV5,
90 	Event_V5,
91 	matePCM,
92 	matePTV,
93 	matePTN,
94 	mateOGGV,
95 	effeDELA,
96 	effeOVER,
97 	textNAME,
98 	textCOMM,
99 	assiUNIT,
100 	assiWOIC,
101 	pxtoneND
102 
103 }
104 
105 private _enum_Tag _CheckTagCode(const char[] p_code) nothrow @safe {
106 	switch(p_code[0 .. _CODESIZE]) {
107 		case _code_antiOPER: return _enum_Tag.antiOPER;
108 		case _code_x1x_PROJ: return _enum_Tag.x1x_PROJ;
109 		case _code_x1x_UNIT: return _enum_Tag.x1x_UNIT;
110 		case _code_x1x_PCM: return _enum_Tag.x1x_PCM;
111 		case _code_x1x_EVEN: return _enum_Tag.x1x_EVEN;
112 		case _code_x1x_END: return _enum_Tag.x1x_END;
113 		case _code_x3x_pxtnUNIT: return _enum_Tag.x3x_pxtnUNIT;
114 		case _code_x4x_evenMAST: return _enum_Tag.x4x_evenMAST;
115 		case _code_x4x_evenUNIT: return _enum_Tag.x4x_evenUNIT;
116 		case _code_num_UNIT: return _enum_Tag.num_UNIT;
117 		case _code_Event_V5: return _enum_Tag.Event_V5;
118 		case _code_MasterV5: return _enum_Tag.MasterV5;
119 		case _code_matePCM: return _enum_Tag.matePCM;
120 		case _code_matePTV: return _enum_Tag.matePTV;
121 		case _code_matePTN: return _enum_Tag.matePTN;
122 		case _code_mateOGGV: return _enum_Tag.mateOGGV;
123 		case _code_effeDELA: return _enum_Tag.effeDELA;
124 		case _code_effeOVER: return _enum_Tag.effeOVER;
125 		case _code_textNAME: return _enum_Tag.textNAME;
126 		case _code_textCOMM: return _enum_Tag.textCOMM;
127 		case _code_assiUNIT: return _enum_Tag.assiUNIT;
128 		case _code_assiWOIC: return _enum_Tag.assiWOIC;
129 		case _code_pxtoneND: return _enum_Tag.pxtoneND;
130 		default: return _enum_Tag.Unknown;
131 	}
132 }
133 
134 struct _ASSIST_WOICE {
135 	ushort woice_index;
136 	ushort rrr;
137 	char[pxtnMAX_TUNEWOICENAME] name = 0;
138 }
139 
140 struct _ASSIST_UNIT {
141 	ushort unit_index;
142 	ushort rrr;
143 	char[pxtnMAX_TUNEUNITNAME] name = 0;
144 }
145 
146 struct _NUM_UNIT {
147 	short num;
148 	short rrr;
149 }
150 
151 enum _MAX_FMTVER_x1x_EVENTNUM = 10000;
152 
153 // x1x project..------------------
154 
155 enum _MAX_PROJECTNAME_x1x = 16;
156 
157 // project (36byte) ================
158 struct _x1x_PROJECT {
159 	char[_MAX_PROJECTNAME_x1x] x1x_name = 0;
160 
161 	float x1x_beat_tempo = 0.0;
162 	ushort x1x_beat_clock;
163 	ushort x1x_beat_num;
164 	ushort x1x_beat_note;
165 	ushort x1x_meas_num;
166 	ushort x1x_channel_num;
167 	ushort x1x_bps;
168 	uint x1x_sps;
169 }
170 
171 struct pxtnVOMITPREPARATION {
172 	int start_pos_meas = 0;
173 	int start_pos_sample = 0;
174 	float start_pos_float = 0.0;
175 
176 	int meas_end = 0;
177 	int meas_repeat = 0;
178 	float fadein_sec = 0.0;
179 
180 	BitFlags!pxtnFlags flags;
181 	float master_volume = 1.0;
182 	invariant {
183 		import std.math : isNaN;
184 		assert(!master_volume.isNaN, "Master volume should never be NaN!");
185 		assert(!fadein_sec.isNaN, "fadein_sec should never be NaN!");
186 		assert(!start_pos_float.isNaN, "start_pos_float should never be NaN!");
187 	}
188 }
189 
190 alias pxtnSampledCallback = bool function(void* user, const(pxtnService)* pxtn) nothrow;
191 
192 struct pxtnService {
193 private:
194 	enum _enum_FMTVER {
195 		_enum_FMTVER_unknown = 0,
196 		_enum_FMTVER_x1x, // fix event num = 10000
197 		_enum_FMTVER_x2x, // no version of exe
198 		_enum_FMTVER_x3x, // unit has voice / basic-key for only view
199 		_enum_FMTVER_x4x, // unit has event
200 		_enum_FMTVER_v5,
201 	}
202 
203 	bool _b_init;
204 	bool _b_edit;
205 	bool _b_fix_evels_num;
206 
207 	int _dst_ch_num, _dst_sps, _dst_byte_per_smp;
208 
209 	pxtnPulse_NoiseBuilder _ptn_bldr;
210 
211 	int _delay_num;
212 	pxtnDelay[] _delays;
213 	int _ovdrv_num;
214 	pxtnOverDrive*[] _ovdrvs;
215 	int _woice_num;
216 	pxtnWoice*[] _woices;
217 	int _unit_num;
218 	pxtnUnit[] _units;
219 
220 	int _group_num;
221 
222 	void _ReadVersion(ref pxtnDescriptor p_doc, out _enum_FMTVER p_fmt_ver, out ushort p_exe_ver) @safe {
223 		if (!_b_init) {
224 			throw new PxtoneException("pxtnService not initialized");
225 		}
226 
227 		char[_VERSIONSIZE] version_ = '\0';
228 		ushort dummy;
229 
230 		p_doc.r(version_[]);
231 
232 		// fmt version
233 		if (version_[0 .. _VERSIONSIZE] == _code_proj_x1x) {
234 			p_fmt_ver = _enum_FMTVER._enum_FMTVER_x1x;
235 			p_exe_ver = 0;
236 			return;
237 		} else if (version_[0 .. _VERSIONSIZE] == _code_proj_x2x) {
238 			p_fmt_ver = _enum_FMTVER._enum_FMTVER_x2x;
239 			p_exe_ver = 0;
240 			return;
241 		} else if (version_[0 .. _VERSIONSIZE] == _code_proj_x3x) {
242 			p_fmt_ver = _enum_FMTVER._enum_FMTVER_x3x;
243 		} else if (version_[0 .. _VERSIONSIZE] == _code_proj_x4x) {
244 			p_fmt_ver = _enum_FMTVER._enum_FMTVER_x4x;
245 		} else if (version_[0 .. _VERSIONSIZE] == _code_proj_v5) {
246 			p_fmt_ver = _enum_FMTVER._enum_FMTVER_v5;
247 		} else if (version_[0 .. _VERSIONSIZE] == _code_tune_x2x) {
248 			p_fmt_ver = _enum_FMTVER._enum_FMTVER_x2x;
249 			p_exe_ver = 0;
250 			return;
251 		} else if (version_[0 .. _VERSIONSIZE] == _code_tune_x3x) {
252 			p_fmt_ver = _enum_FMTVER._enum_FMTVER_x3x;
253 		} else if (version_[0 .. _VERSIONSIZE] == _code_tune_x4x) {
254 			p_fmt_ver = _enum_FMTVER._enum_FMTVER_x4x;
255 		} else if (version_[0 .. _VERSIONSIZE] == _code_tune_v5) {
256 			p_fmt_ver = _enum_FMTVER._enum_FMTVER_v5;
257 		} else {
258 			throw new PxtoneException("fmt unknown");
259 		}
260 
261 		// exe version
262 		p_doc.r(p_exe_ver);
263 		p_doc.r(dummy);
264 	}
265 	////////////////////////////////////////
266 	// Read Project //////////////
267 	////////////////////////////////////////
268 
269 	void _ReadTuneItems(ref pxtnDescriptor p_doc) @system {
270 		if (!_b_init) {
271 			throw new PxtoneException("pxtnService not initialized");
272 		}
273 
274 		bool b_end = false;
275 		char[_CODESIZE + 1] code = '\0';
276 
277 		/// must the unit before the voice.
278 		while (!b_end) {
279 			p_doc.r(code[0 .._CODESIZE]);
280 
281 			_enum_Tag tag = _CheckTagCode(code);
282 			switch (tag) {
283 			case _enum_Tag.antiOPER:
284 				throw new PxtoneException("AntiOPER tag detected");
285 
286 				// new -------
287 			case _enum_Tag.num_UNIT: {
288 					int num = 0;
289 					_io_UNIT_num_r(p_doc, num);
290 					for (int i = 0; i < num; i++) {
291 						_units[i] = pxtnUnit.init;
292 					}
293 					_unit_num = num;
294 					break;
295 				}
296 			case _enum_Tag.MasterV5:
297 				master.io_r_v5(p_doc);
298 				break;
299 			case _enum_Tag.Event_V5:
300 				evels.io_Read(p_doc);
301 				break;
302 
303 			case _enum_Tag.matePCM:
304 				_io_Read_Woice(p_doc, pxtnWOICETYPE.PCM);
305 				break;
306 			case _enum_Tag.matePTV:
307 				_io_Read_Woice(p_doc, pxtnWOICETYPE.PTV);
308 				break;
309 			case _enum_Tag.matePTN:
310 				_io_Read_Woice(p_doc, pxtnWOICETYPE.PTN);
311 				break;
312 
313 			case _enum_Tag.mateOGGV:
314 
315 				version (pxINCLUDE_OGGVORBIS) {
316 					_io_Read_Woice(p_doc, pxtnWOICETYPE.OGGV);
317 					break;
318 				} else {
319 					throw new PxtoneException("Ogg Vorbis support is required");
320 				}
321 
322 			case _enum_Tag.effeDELA:
323 				_io_Read_Delay(p_doc);
324 				break;
325 			case _enum_Tag.effeOVER:
326 				_io_Read_OverDrive(p_doc);
327 				break;
328 			case _enum_Tag.textNAME:
329 				text.Name_r(p_doc);
330 				break;
331 			case _enum_Tag.textCOMM:
332 				text.Comment_r(p_doc);
333 				break;
334 			case _enum_Tag.assiWOIC:
335 				_io_assiWOIC_r(p_doc);
336 				break;
337 			case _enum_Tag.assiUNIT:
338 				_io_assiUNIT_r(p_doc);
339 				break;
340 			case _enum_Tag.pxtoneND:
341 				b_end = true;
342 				break;
343 
344 				// old -------
345 			case _enum_Tag.x4x_evenMAST:
346 				master.io_r_x4x(p_doc);
347 				break;
348 			case _enum_Tag.x4x_evenUNIT:
349 				evels.io_Unit_Read_x4x_EVENT(p_doc, false, true);
350 				break;
351 			case _enum_Tag.x3x_pxtnUNIT:
352 				_io_Read_OldUnit(p_doc, 3);
353 				break;
354 			case _enum_Tag.x1x_PROJ:
355 				_x1x_Project_Read(p_doc);
356 				break;
357 			case _enum_Tag.x1x_UNIT:
358 				_io_Read_OldUnit(p_doc, 1);
359 				break;
360 			case _enum_Tag.x1x_PCM:
361 				_io_Read_Woice(p_doc, pxtnWOICETYPE.PCM);
362 				break;
363 			case _enum_Tag.x1x_EVEN:
364 				evels.io_Unit_Read_x4x_EVENT(p_doc, true, false);
365 				break;
366 			case _enum_Tag.x1x_END:
367 				b_end = true;
368 				break;
369 
370 			default:
371 				throw new PxtoneException("fmt unknown");
372 			}
373 		}
374 
375 	}
376 
377 	void _x1x_Project_Read(ref pxtnDescriptor p_doc) @system {
378 		if (!_b_init) {
379 			throw new PxtoneException("pxtnService not initialized");
380 		}
381 
382 		_x1x_PROJECT prjc;
383 		int beat_num, beat_clock;
384 		int size;
385 		float beat_tempo;
386 
387 		p_doc.r(size);
388 		p_doc.r(prjc);
389 
390 		beat_num = prjc.x1x_beat_num;
391 		beat_tempo = prjc.x1x_beat_tempo;
392 		beat_clock = prjc.x1x_beat_clock;
393 
394 		int ns = 0;
395 		for ( /+ns+/ ; ns < _MAX_PROJECTNAME_x1x; ns++) {
396 			if (!prjc.x1x_name[ns]) {
397 				break;
398 			}
399 		}
400 
401 		text.set_name_buf(prjc.x1x_name.ptr, ns);
402 		master.Set(beat_num, beat_tempo, beat_clock);
403 	}
404 
405 	void _io_Read_Delay(ref pxtnDescriptor p_doc) @system {
406 		if (!_b_init) {
407 			throw new PxtoneException("pxtnService not initialized");
408 		}
409 		if (!_delays) {
410 			throw new PxtoneException("pxtnService delays not initialized");
411 		}
412 		if (_delay_num >= _delays.length) {
413 			throw new PxtoneException("fmt unknown");
414 		}
415 
416 		pxtnDelay delay;
417 
418 		delay.Read(p_doc);
419 		_delays[_delay_num] = delay;
420 		_delay_num++;
421 	}
422 
423 	void _io_Read_OverDrive(ref pxtnDescriptor p_doc) @system {
424 		if (!_b_init) {
425 			throw new PxtoneException("pxtnService not initialized");
426 		}
427 		if (!_ovdrvs) {
428 			throw new PxtoneException("pxtnService overdrives not initialized");
429 		}
430 		if (_ovdrv_num >= _ovdrvs.length) {
431 			throw new PxtoneException("fmt unknown");
432 		}
433 
434 		pxtnOverDrive* ovdrv = new pxtnOverDrive();
435 		ovdrv.Read(p_doc);
436 		_ovdrvs[_ovdrv_num] = ovdrv;
437 		_ovdrv_num++;
438 	}
439 
440 	void _io_Read_Woice(ref pxtnDescriptor p_doc, pxtnWOICETYPE type) @system {
441 		if (!_b_init) {
442 			throw new PxtoneException("pxtnService not initialized");
443 		}
444 		if (!_woices) {
445 			throw new PxtoneException("pxtnService woices not initialized");
446 		}
447 		if (_woice_num >= _woices.length) {
448 			throw new PxtoneException("Too many woices");
449 		}
450 
451 		pxtnWoice* woice = new pxtnWoice();
452 
453 		switch (type) {
454 		case pxtnWOICETYPE.PCM:
455 			woice.io_matePCM_r(p_doc);
456 			break;
457 		case pxtnWOICETYPE.PTV:
458 			woice.io_matePTV_r(p_doc);
459 			break;
460 		case pxtnWOICETYPE.PTN:
461 			woice.io_matePTN_r(p_doc);
462 			break;
463 		case pxtnWOICETYPE.OGGV:
464 			version (pxINCLUDE_OGGVORBIS) {
465 				woice.io_mateOGGV_r(p_doc);
466 				break;
467 			} else {
468 				throw new PxtoneException("Ogg Vorbis support is required");
469 			}
470 
471 		default:
472 			throw new PxtoneException("fmt unknown");
473 		}
474 		_woices[_woice_num] = woice;
475 		_woice_num++;
476 	}
477 
478 	void _io_Read_OldUnit(ref pxtnDescriptor p_doc, int ver) @system {
479 		if (!_b_init) {
480 			throw new PxtoneException("pxtnService not initialized");
481 		}
482 		if (!_units) {
483 			throw new PxtoneException("pxtnService units not initialized");
484 		}
485 		if (_unit_num >= _units.length) {
486 			throw new PxtoneException("fmt unknown");
487 		}
488 
489 		pxtnUnit* unit = new pxtnUnit();
490 		int group = 0;
491 		switch (ver) {
492 		case 1:
493 			unit.Read_v1x(p_doc, &group);
494 			break;
495 		case 3:
496 			unit.Read_v3x(p_doc, &group);
497 			break;
498 		default:
499 			throw new PxtoneException("fmt unknown");
500 		}
501 
502 		if (group >= _group_num) {
503 			group = _group_num - 1;
504 		}
505 
506 		evels.x4x_Read_Add(0, cast(ubyte) _unit_num, EVENTKIND.GROUPNO, cast(int) group);
507 		evels.x4x_Read_NewKind();
508 		evels.x4x_Read_Add(0, cast(ubyte) _unit_num, EVENTKIND.VOICENO, cast(int) _unit_num);
509 		evels.x4x_Read_NewKind();
510 
511 	term:
512 		_units[_unit_num] = *unit;
513 		_unit_num++;
514 	}
515 
516 	/////////////
517 	// assi woice
518 	/////////////
519 
520 	bool _io_assiWOIC_w(ref pxtnDescriptor p_doc, int idx) const @system {
521 		if (!_b_init) {
522 			return false;
523 		}
524 
525 		_ASSIST_WOICE assi;
526 		int size;
527 		const char[] p_name = _woices[idx].get_name_buf();
528 
529 		if (p_name.length > pxtnMAX_TUNEWOICENAME) {
530 			return false;
531 		}
532 
533 		assi.name[0 .. p_name.length] = p_name;
534 		assi.woice_index = cast(ushort) idx;
535 
536 		size = _ASSIST_WOICE.sizeof;
537 		p_doc.w_asfile(size);
538 		p_doc.w_asfile(assi);
539 
540 		return true;
541 	}
542 
543 	void _io_assiWOIC_r(ref pxtnDescriptor p_doc) @system {
544 		if (!_b_init) {
545 			throw new PxtoneException("pxtnService not initialized");
546 		}
547 
548 		_ASSIST_WOICE assi;
549 		int size = 0;
550 
551 		p_doc.r(size);
552 		if (size != assi.sizeof) {
553 			throw new PxtoneException("fmt unknown");
554 		}
555 		p_doc.r(assi);
556 		if (assi.rrr) {
557 			throw new PxtoneException("fmt unknown");
558 		}
559 		if (assi.woice_index >= _woice_num) {
560 			throw new PxtoneException("fmt unknown");
561 		}
562 
563 		if (!_woices[assi.woice_index].set_name_buf(assi.name)) {
564 			throw new PxtoneException("FATAL");
565 		}
566 	}
567 	// -----
568 	// assi unit.
569 	// -----
570 
571 	bool _io_assiUNIT_w(ref pxtnDescriptor p_doc, int idx) const @system {
572 		if (!_b_init) {
573 			return false;
574 		}
575 
576 		_ASSIST_UNIT assi;
577 		int size;
578 		int name_size;
579 		const char* p_name = _units[idx].get_name_buf(&name_size);
580 
581 		assi.name[0 .. name_size] = p_name[0 .. name_size];
582 		assi.unit_index = cast(ushort) idx;
583 
584 		size = assi.sizeof;
585 		p_doc.w_asfile(size);
586 		p_doc.w_asfile(assi);
587 
588 		return true;
589 	}
590 
591 	void _io_assiUNIT_r(ref pxtnDescriptor p_doc) @safe {
592 		if (!_b_init) {
593 			throw new PxtoneException("pxtnService not initialized");
594 		}
595 
596 		_ASSIST_UNIT assi;
597 		int size;
598 
599 		p_doc.r(size);
600 		if (size != assi.sizeof) {
601 			throw new PxtoneException("fmt unknown");
602 		}
603 		p_doc.r(assi);
604 		if (assi.rrr) {
605 			throw new PxtoneException("fmt unknown");
606 		}
607 		if (assi.unit_index >= _unit_num) {
608 			throw new PxtoneException("fmt unknown");
609 		}
610 
611 		if (!_units[assi.unit_index].setNameBuf(assi.name[])) {
612 			throw new PxtoneException("FATAL");
613 		}
614 	}
615 	// -----
616 	// unit num
617 	// -----
618 
619 	void _io_UNIT_num_w(ref pxtnDescriptor p_doc) const @system {
620 		if (!_b_init) {
621 			throw new PxtoneException("pxtnService not initialized");
622 		}
623 
624 		_NUM_UNIT data;
625 		int size;
626 
627 		data.num = cast(short) _unit_num;
628 
629 		size = _NUM_UNIT.sizeof;
630 		p_doc.w_asfile(size);
631 		p_doc.w_asfile(data);
632 	}
633 
634 	void _io_UNIT_num_r(ref pxtnDescriptor p_doc, out int p_num) @system {
635 		if (!_b_init) {
636 			throw new PxtoneException("pxtnService not initialized");
637 		}
638 
639 		_NUM_UNIT data;
640 		int size = 0;
641 
642 		p_doc.r(size);
643 		if (size != _NUM_UNIT.sizeof) {
644 			throw new PxtoneException("fmt unknown");
645 		}
646 		p_doc.r(data);
647 		if (data.rrr) {
648 			throw new PxtoneException("fmt unknown");
649 		}
650 		if (data.num > _units.length) {
651 			throw new PxtoneException("fmt new");
652 		}
653 		if (data.num < 0) {
654 			throw new PxtoneException("fmt unknown");
655 		}
656 		p_num = data.num;
657 	}
658 
659 	// fix old key event
660 	bool _x3x_TuningKeyEvent() nothrow @system {
661 		if (!_b_init) {
662 			return false;
663 		}
664 
665 		if (_unit_num > _woice_num) {
666 			return false;
667 		}
668 
669 		for (int u = 0; u < _unit_num; u++) {
670 			if (u >= _woice_num) {
671 				return false;
672 			}
673 
674 			int change_value = _woices[u].get_x3x_basic_key() - EVENTDEFAULT_BASICKEY;
675 
676 			if (!evels.get_Count(cast(ubyte) u, cast(ubyte) EVENTKIND.KEY)) {
677 				evels.Record_Add_i(0, cast(ubyte) u, EVENTKIND.KEY, cast(int) 0x6000);
678 			}
679 			evels.Record_Value_Change(0, -1, cast(ubyte) u, EVENTKIND.KEY, change_value);
680 		}
681 		return true;
682 	}
683 
684 	// fix old tuning (1.0)
685 	bool _x3x_AddTuningEvent() nothrow @system {
686 		if (!_b_init) {
687 			return false;
688 		}
689 
690 		if (_unit_num > _woice_num) {
691 			return false;
692 		}
693 
694 		for (int u = 0; u < _unit_num; u++) {
695 			float tuning = _woices[u].get_x3x_tuning();
696 			if (tuning) {
697 				evels.Record_Add_f(0, cast(ubyte) u, EVENTKIND.TUNING, tuning);
698 			}
699 		}
700 
701 		return true;
702 	}
703 
704 	bool _x3x_SetVoiceNames() nothrow @system {
705 		if (!_b_init) {
706 			return false;
707 		}
708 
709 		for (int i = 0; i < _woice_num; i++) {
710 			char[pxtnMAX_TUNEWOICENAME + 1] name = 0;
711 			try {
712 				sformat(name[], "voice_%02d", i);
713 			} catch (Exception) { //This will never actually happen...
714 				return false;
715 			}
716 			_woices[i].set_name_buf(name);
717 		}
718 		return true;
719 	}
720 
721 	//////////////
722 	// vomit..
723 	//////////////
724 	bool _moo_b_valid_data;
725 	bool _moo_b_end_vomit = true;
726 	bool _moo_b_init;
727 
728 	bool _moo_b_mute_by_unit;
729 	bool _moo_b_loop = true;
730 
731 	int _moo_smp_smooth;
732 	float _moo_clock_rate; // as the sample
733 	int _moo_smp_count;
734 	int _moo_smp_start;
735 	int _moo_smp_end;
736 	int _moo_smp_repeat;
737 
738 	int _moo_fade_count;
739 	int _moo_fade_max;
740 	int _moo_fade_fade;
741 	float _moo_master_vol = 1.0f;
742 
743 	int _moo_top;
744 	float _moo_smp_stride;
745 	int _moo_time_pan_index;
746 
747 	float _moo_bt_tempo;
748 
749 	// for make now-meas
750 	int _moo_bt_clock;
751 	int _moo_bt_num;
752 
753 	int[] _moo_group_smps;
754 
755 	const(EVERECORD)* _moo_p_eve;
756 
757 	pxtnPulse_Frequency* _moo_freq;
758 
759 	void _init(int fix_evels_num, bool b_edit) @system {
760 		if (_b_init) {
761 			throw new PxtoneException("pxtnService not initialized");
762 		}
763 
764 		scope(failure) {
765 			_release();
766 		}
767 
768 		int byte_size = 0;
769 
770 		version (pxINCLUDE_OGGVORBIS) {
771 			import derelict.vorbis;
772 
773 			try {
774 				DerelictVorbis.load();
775 				DerelictVorbisFile.load();
776 			} catch (Exception e) {
777 				throw new PxtoneException("Vorbis library failed to load");
778 			}
779 		}
780 
781 		text = pxtnText.init;
782 		master = pxtnMaster.init;
783 		evels = pxtnEvelist.init;
784 		_ptn_bldr = pxtnPulse_NoiseBuilder.init;
785 
786 		if (fix_evels_num) {
787 			_b_fix_evels_num = true;
788 			evels.Allocate(fix_evels_num);
789 		} else {
790 			_b_fix_evels_num = false;
791 		}
792 
793 		// delay
794 		_delays = new pxtnDelay[](pxtnMAX_TUNEDELAYSTRUCT);
795 
796 		// over-drive
797 		_ovdrvs = new pxtnOverDrive*[](pxtnMAX_TUNEOVERDRIVESTRUCT);
798 
799 		// woice
800 		_woices = new pxtnWoice*[](pxtnMAX_TUNEWOICESTRUCT);
801 
802 		// unit
803 		_units = new pxtnUnit[](pxtnMAX_TUNEUNITSTRUCT);
804 
805 		_group_num = pxtnMAX_TUNEGROUPNUM;
806 
807 		if (!_moo_init()) {
808 			throw new PxtoneException("_moo_init failed");
809 		}
810 
811 		if (fix_evels_num) {
812 			_moo_b_valid_data = true;
813 		}
814 
815 		_b_edit = b_edit;
816 		_b_init = true;
817 
818 	}
819 
820 	bool _release() nothrow @system {
821 		if (!_b_init) {
822 			return false;
823 		}
824 		_b_init = false;
825 
826 		_moo_destructer();
827 
828 		_delays = null;
829 		_ovdrvs = null;
830 		_woices = null;
831 		_units = null;
832 		return true;
833 	}
834 
835 	void _pre_count_event(ref pxtnDescriptor p_doc, out int p_count) @system {
836 		if (!_b_init) {
837 			throw new PxtoneException("pxtnService not initialized");
838 		}
839 
840 		bool b_end = false;
841 
842 		int count = 0;
843 		int c = 0;
844 		int size = 0;
845 		char[_CODESIZE + 1] code = '\0';
846 
847 		ushort exe_ver = 0;
848 		_enum_FMTVER fmt_ver = _enum_FMTVER._enum_FMTVER_unknown;
849 
850 		scope(failure) {
851 			p_count = 0;
852 		}
853 
854 		_ReadVersion(p_doc, fmt_ver, exe_ver);
855 
856 		if (fmt_ver == _enum_FMTVER._enum_FMTVER_x1x) {
857 			count = _MAX_FMTVER_x1x_EVENTNUM;
858 			goto term;
859 		}
860 
861 		while (!b_end) {
862 			p_doc.r(code[0 .. _CODESIZE]);
863 
864 			switch (_CheckTagCode(code)) {
865 			case _enum_Tag.Event_V5:
866 				count += evels.io_Read_EventNum(p_doc);
867 				break;
868 			case _enum_Tag.MasterV5:
869 				count += master.io_r_v5_EventNum(p_doc);
870 				break;
871 			case _enum_Tag.x4x_evenMAST:
872 				count += master.io_r_x4x_EventNum(p_doc);
873 				break;
874 			case _enum_Tag.x4x_evenUNIT:
875 				evels.io_Read_x4x_EventNum(p_doc, &c);
876 				count += c;
877 				break;
878 			case _enum_Tag.pxtoneND:
879 				b_end = true;
880 				break;
881 
882 				// skip
883 			case _enum_Tag.antiOPER:
884 			case _enum_Tag.num_UNIT:
885 			case _enum_Tag.x3x_pxtnUNIT:
886 			case _enum_Tag.matePCM:
887 			case _enum_Tag.matePTV:
888 			case _enum_Tag.matePTN:
889 			case _enum_Tag.mateOGGV:
890 			case _enum_Tag.effeDELA:
891 			case _enum_Tag.effeOVER:
892 			case _enum_Tag.textNAME:
893 			case _enum_Tag.textCOMM:
894 			case _enum_Tag.assiUNIT:
895 			case _enum_Tag.assiWOIC:
896 
897 				p_doc.r(size);
898 				p_doc.seek(pxtnSEEK.cur, size);
899 				break;
900 
901 				// ignore
902 			case _enum_Tag.x1x_PROJ:
903 			case _enum_Tag.x1x_UNIT:
904 			case _enum_Tag.x1x_PCM:
905 			case _enum_Tag.x1x_EVEN:
906 			case _enum_Tag.x1x_END:
907 				throw new PxtoneException("x1x ignore");
908 			default:
909 				throw new PxtoneException("FATAL");
910 			}
911 		}
912 
913 		if (fmt_ver <= _enum_FMTVER._enum_FMTVER_x3x) {
914 			count += pxtnMAX_TUNEUNITSTRUCT * 4; // voice_no, group_no, key tuning, key event x3x
915 		}
916 
917 	term:
918 
919 		p_count = count;
920 	}
921 
922 	void _moo_destructer() nothrow @system {
923 
924 		_moo_release();
925 	}
926 
927 	bool _moo_init() nothrow @system {
928 		bool b_ret = false;
929 
930 		_moo_freq = new pxtnPulse_Frequency();
931 		if (!_moo_freq) {
932 			goto term;
933 		}
934 		_moo_group_smps = new int[](_group_num);
935 		if (!_moo_group_smps) {
936 			goto term;
937 		}
938 
939 		_moo_b_init = true;
940 		b_ret = true;
941 	term:
942 		if (!b_ret) {
943 			_moo_release();
944 		}
945 
946 		return b_ret;
947 	}
948 
949 	bool _moo_release() nothrow @system {
950 		if (!_moo_b_init) {
951 			return false;
952 		}
953 		_moo_b_init = false;
954 		_moo_freq = null;
955 		_moo_group_smps = null;
956 		return true;
957 	}
958 
959 	////////////////////////////////////////////////
960 	// Units   ////////////////////////////////////
961 	////////////////////////////////////////////////
962 
963 	bool _moo_ResetVoiceOn(pxtnUnit* p_u, int w) const nothrow @safe {
964 		if (!_moo_b_init) {
965 			return false;
966 		}
967 
968 		const(pxtnVOICEINSTANCE)* p_inst;
969 		const(pxtnVOICEUNIT)* p_vc;
970 		const(pxtnWoice)* p_wc = Woice_Get(w);
971 
972 		if (!p_wc) {
973 			return false;
974 		}
975 
976 		p_u.set_woice(p_wc);
977 
978 		for (int v = 0; v < p_wc.get_voice_num(); v++) {
979 			p_inst = p_wc.get_instance(v);
980 			p_vc = p_wc.get_voice(v);
981 
982 			float ofs_freq = 0;
983 			if (p_vc.voice_flags & PTV_VOICEFLAG_BEATFIT) {
984 				ofs_freq = (p_inst.smp_body_w * _moo_bt_tempo) / (44100 * 60 * p_vc.tuning);
985 			} else {
986 				ofs_freq = _moo_freq.Get(EVENTDEFAULT_BASICKEY - p_vc.basic_key) * p_vc.tuning;
987 			}
988 			p_u.Tone_Reset_and_2prm(v, cast(int)(p_inst.env_release / _moo_clock_rate), ofs_freq);
989 		}
990 		return true;
991 	}
992 
993 	bool _moo_InitUnitTone() nothrow @safe {
994 		if (!_moo_b_init) {
995 			return false;
996 		}
997 		for (int u = 0; u < _unit_num; u++) {
998 			pxtnUnit* p_u = Unit_Get(u);
999 			p_u.Tone_Init();
1000 			_moo_ResetVoiceOn(p_u, EVENTDEFAULT_VOICENO);
1001 		}
1002 		return true;
1003 	}
1004 
1005 	bool _moo_PXTONE_SAMPLE(ubyte[] p_data) nothrow @safe {
1006 		if (!_moo_b_init) {
1007 			return false;
1008 		}
1009 
1010 		// envelope..
1011 		for (int u = 0; u < _unit_num; u++) {
1012 			_units[u].Tone_Envelope();
1013 		}
1014 
1015 		int clock = cast(int)(_moo_smp_count / _moo_clock_rate);
1016 
1017 		// events..
1018 		for (; _moo_p_eve && _moo_p_eve.clock <= clock; _moo_p_eve = _moo_p_eve.next) {
1019 			int u = _moo_p_eve.unit_no;
1020 			pxtnUnit* p_u = &_units[u];
1021 			pxtnVOICETONE* p_tone;
1022 			const(pxtnWoice)* p_wc;
1023 			const(pxtnVOICEINSTANCE)* p_vi;
1024 
1025 			switch (_moo_p_eve.kind) {
1026 			case EVENTKIND.ON: {
1027 					int on_count = cast(int)((_moo_p_eve.clock + _moo_p_eve.value - clock) * _moo_clock_rate);
1028 					if (on_count <= 0) {
1029 						p_u.Tone_ZeroLives();
1030 						break;
1031 					}
1032 
1033 					p_u.Tone_KeyOn();
1034 
1035 					p_wc = p_u.get_woice();
1036 					if (!(p_wc)) {
1037 						break;
1038 					}
1039 					for (int v = 0; v < p_wc.get_voice_num(); v++) {
1040 						p_tone = p_u.get_tone(v);
1041 						p_vi = p_wc.get_instance(v);
1042 
1043 						// release..
1044 						if (p_vi.env_release) {
1045 							int max_life_count1 = cast(int)((_moo_p_eve.value - (clock - _moo_p_eve.clock)) * _moo_clock_rate) + p_vi.env_release;
1046 							int max_life_count2;
1047 							int c = _moo_p_eve.clock + _moo_p_eve.value + p_tone.env_release_clock;
1048 							const(EVERECORD)* next = null;
1049 							for (const(EVERECORD)* p = _moo_p_eve.next; p; p = p.next) {
1050 								if (p.clock > c) {
1051 									break;
1052 								}
1053 								if (p.unit_no == u && p.kind == EVENTKIND.ON) {
1054 									next = p;
1055 									break;
1056 								}
1057 							}
1058 							if (!next) {
1059 								max_life_count2 = _moo_smp_end - cast(int)(clock * _moo_clock_rate);
1060 							} else {
1061 								max_life_count2 = cast(int)((next.clock - clock) * _moo_clock_rate);
1062 							}
1063 							if (max_life_count1 < max_life_count2) {
1064 								p_tone.life_count = max_life_count1;
1065 							} else {
1066 								p_tone.life_count = max_life_count2;
1067 							}
1068 						}  // no-release..
1069 						else {
1070 							p_tone.life_count = cast(int)((_moo_p_eve.value - (clock - _moo_p_eve.clock)) * _moo_clock_rate);
1071 						}
1072 
1073 						if (p_tone.life_count > 0) {
1074 							p_tone.on_count = on_count;
1075 							p_tone.smp_pos = 0;
1076 							p_tone.env_pos = 0;
1077 							if (p_vi.env_size) {
1078 								p_tone.env_volume = p_tone.env_start = 0; // envelope
1079 							} else {
1080 								p_tone.env_volume = p_tone.env_start = 128; // no-envelope
1081 							}
1082 						}
1083 					}
1084 					break;
1085 				}
1086 
1087 			case EVENTKIND.KEY:
1088 				p_u.Tone_Key(_moo_p_eve.value);
1089 				break;
1090 			case EVENTKIND.PAN_VOLUME:
1091 				p_u.Tone_Pan_Volume(_dst_ch_num, _moo_p_eve.value);
1092 				break;
1093 			case EVENTKIND.PAN_TIME:
1094 				p_u.Tone_Pan_Time(_dst_ch_num, _moo_p_eve.value, _dst_sps);
1095 				break;
1096 			case EVENTKIND.VELOCITY:
1097 				p_u.Tone_Velocity(_moo_p_eve.value);
1098 				break;
1099 			case EVENTKIND.VOLUME:
1100 				p_u.Tone_Volume(_moo_p_eve.value);
1101 				break;
1102 			case EVENTKIND.PORTAMENT:
1103 				p_u.Tone_Portament(cast(int)(_moo_p_eve.value * _moo_clock_rate));
1104 				break;
1105 			case EVENTKIND.BEATCLOCK:
1106 				break;
1107 			case EVENTKIND.BEATTEMPO:
1108 				break;
1109 			case EVENTKIND.BEATNUM:
1110 				break;
1111 			case EVENTKIND.REPEAT:
1112 				break;
1113 			case EVENTKIND.LAST:
1114 				break;
1115 			case EVENTKIND.VOICENO:
1116 				_moo_ResetVoiceOn(p_u, _moo_p_eve.value);
1117 				break;
1118 			case EVENTKIND.GROUPNO:
1119 				p_u.Tone_GroupNo(_moo_p_eve.value);
1120 				break;
1121 			case EVENTKIND.TUNING:
1122 				p_u.Tone_Tuning(*(cast(const(float)*)(&_moo_p_eve.value)));
1123 				break;
1124 			default:
1125 				break;
1126 			}
1127 		}
1128 
1129 		// sampling..
1130 		for (int u = 0; u < _unit_num; u++) {
1131 			_units[u].Tone_Sample(_moo_b_mute_by_unit, _dst_ch_num, _moo_time_pan_index, _moo_smp_smooth);
1132 		}
1133 
1134 		for (int ch = 0; ch < _dst_ch_num; ch++) {
1135 			for (int g = 0; g < _group_num; g++) {
1136 				_moo_group_smps[g] = 0;
1137 			}
1138 			for (int u = 0; u < _unit_num; u++) {
1139 				_units[u].Tone_Supple(_moo_group_smps, ch, _moo_time_pan_index);
1140 			}
1141 			for (int o = 0; o < _ovdrv_num; o++) {
1142 				_ovdrvs[o].Tone_Supple(_moo_group_smps);
1143 			}
1144 			for (int d = 0; d < _delay_num; d++) {
1145 				_delays[d].Tone_Supple(ch, _moo_group_smps);
1146 			}
1147 
1148 			// collect.
1149 			int work = 0;
1150 			for (int g = 0; g < _group_num; g++) {
1151 				work += _moo_group_smps[g];
1152 			}
1153 
1154 			// fade..
1155 			if (_moo_fade_fade) {
1156 				work = work * (_moo_fade_count >> 8) / _moo_fade_max;
1157 			}
1158 
1159 			// master volume
1160 			work = cast(int)(work * _moo_master_vol);
1161 
1162 			// to buffer..
1163 			if (work > _moo_top) {
1164 				work = _moo_top;
1165 			}
1166 			if (work < -_moo_top) {
1167 				work = -_moo_top;
1168 			}
1169 			(cast(short[])p_data)[ch] = cast(short)(work);
1170 		}
1171 
1172 		// --------------
1173 		// increments..
1174 
1175 		_moo_smp_count++;
1176 		_moo_time_pan_index = (_moo_time_pan_index + 1) & (pxtnBUFSIZE_TIMEPAN - 1);
1177 
1178 		for (int u = 0; u < _unit_num; u++) {
1179 			int key_now = _units[u].Tone_Increment_Key();
1180 			_units[u].Tone_Increment_Sample(_moo_freq.Get2(key_now) * _moo_smp_stride);
1181 		}
1182 
1183 		// delay
1184 		for (int d = 0; d < _delay_num; d++) {
1185 			_delays[d].Tone_Increment();
1186 		}
1187 
1188 		// fade out
1189 		if (_moo_fade_fade < 0) {
1190 			if (_moo_fade_count > 0) {
1191 				_moo_fade_count--;
1192 			} else {
1193 				return false;
1194 			}
1195 		}  // fade in
1196 		else if (_moo_fade_fade > 0) {
1197 			if (_moo_fade_count < (_moo_fade_max << 8)) {
1198 				_moo_fade_count++;
1199 			} else {
1200 				_moo_fade_fade = 0;
1201 			}
1202 		}
1203 
1204 		if (_moo_smp_count >= _moo_smp_end) {
1205 			if (!_moo_b_loop) {
1206 				return false;
1207 			}
1208 			_moo_smp_count = _moo_smp_repeat;
1209 			_moo_p_eve = evels.get_Records();
1210 			_moo_InitUnitTone();
1211 		}
1212 		return true;
1213 	}
1214 
1215 	pxtnSampledCallback _sampled_proc;
1216 	void* _sampled_user;
1217 
1218 public:
1219 
1220 	void load(ubyte[] buffer) @system {
1221 		pxtnDescriptor desc;
1222 		desc.set_memory_r(buffer);
1223 		read(desc);
1224 		tones_ready();
1225 	}
1226 
1227 	void load(File fd) @system {
1228 		pxtnDescriptor desc;
1229 		desc.set_file_r(fd);
1230 		read(desc);
1231 		tones_ready();
1232 	}
1233 
1234 	 ~this() nothrow @system {
1235 		_release();
1236 	}
1237 
1238 	pxtnText text;
1239 	pxtnMaster master;
1240 	pxtnEvelist evels;
1241 
1242 	void initialize() @system {
1243 		_init(0, false);
1244 	}
1245 
1246 	void init_collage(int fix_evels_num) @system {
1247 		return _init(fix_evels_num, true);
1248 	}
1249 
1250 	bool clear() nothrow @system {
1251 		if (!_b_init) {
1252 			return false;
1253 		}
1254 
1255 		if (!_b_edit) {
1256 			_moo_b_valid_data = false;
1257 		}
1258 
1259 		if (!text.set_name_buf("", 0)) {
1260 			return false;
1261 		}
1262 		if (!text.set_comment_buf("", 0)) {
1263 			return false;
1264 		}
1265 
1266 		evels.Clear();
1267 
1268 		_delay_num = 0;
1269 		_ovdrvs[0 .. _ovdrv_num] = null;
1270 		_ovdrv_num = 0;
1271 		_woices[0 .. _woice_num] = null;
1272 		_woice_num = 0;
1273 		_unit_num = 0;
1274 
1275 		master.Reset();
1276 
1277 		if (!_b_edit) {
1278 			evels.Release();
1279 		} else {
1280 			evels.Clear();
1281 		}
1282 		return true;
1283 	}
1284 
1285 	////////////////////////////////////////
1286 	// save               //////////////////
1287 	////////////////////////////////////////
1288 
1289 	void write(ref pxtnDescriptor p_doc, bool b_tune, ushort exe_ver) @system {
1290 		if (!_b_init) {
1291 			throw new PxtoneException("pxtnService not initialized");
1292 		}
1293 
1294 		bool b_ret = false;
1295 		int rough = b_tune ? 10 : 1;
1296 		ushort rrr = 0;
1297 
1298 		// format version
1299 		if (b_tune) {
1300 			p_doc.w_asfile(_code_tune_v5);
1301 		} else {
1302 			p_doc.w_asfile(_code_proj_v5);
1303 		}
1304 
1305 		// exe version
1306 		p_doc.w_asfile(exe_ver);
1307 		p_doc.w_asfile(rrr);
1308 
1309 		// master
1310 		p_doc.w_asfile(_code_MasterV5);
1311 		master.io_w_v5(p_doc, rough);
1312 
1313 		// event
1314 		p_doc.w_asfile(_code_Event_V5);
1315 		evels.io_Write(p_doc, rough);
1316 
1317 		// name
1318 		if (text.is_name_buf()) {
1319 			p_doc.w_asfile(_code_textNAME);
1320 			if (!text.Name_w(p_doc)) {
1321 				throw new PxtoneException("desc w");
1322 			}
1323 		}
1324 
1325 		// comment
1326 		if (text.is_comment_buf()) {
1327 			p_doc.w_asfile(_code_textCOMM);
1328 			if (!text.Comment_w(p_doc)) {
1329 				throw new PxtoneException("desc w");
1330 			}
1331 		}
1332 
1333 		// delay
1334 		for (int d = 0; d < _delay_num; d++) {
1335 			p_doc.w_asfile(_code_effeDELA);
1336 			_delays[d].Write(p_doc);
1337 		}
1338 
1339 		// overdrive
1340 		for (int o = 0; o < _ovdrv_num; o++) {
1341 			p_doc.w_asfile(_code_effeOVER);
1342 			_ovdrvs[o].Write(p_doc);
1343 		}
1344 
1345 		// woice
1346 		for (int w = 0; w < _woice_num; w++) {
1347 			pxtnWoice* p_w = _woices[w];
1348 
1349 			switch (p_w.get_type()) {
1350 			case pxtnWOICETYPE.PCM:
1351 				p_doc.w_asfile(_code_matePCM);
1352 				p_w.io_matePCM_w(p_doc);
1353 				break;
1354 			case pxtnWOICETYPE.PTV:
1355 				p_doc.w_asfile(_code_matePTV);
1356 				if (!p_w.io_matePTV_w(p_doc)) {
1357 					throw new PxtoneException("desc w");
1358 				}
1359 				break;
1360 			case pxtnWOICETYPE.PTN:
1361 				p_doc.w_asfile(_code_matePTN);
1362 				p_w.io_matePTN_w(p_doc);
1363 				break;
1364 			case pxtnWOICETYPE.OGGV:
1365 
1366 				version (pxINCLUDE_OGGVORBIS) {
1367 					p_doc.w_asfile(_code_mateOGGV);
1368 					if (!p_w.io_mateOGGV_w(p_doc)) {
1369 						throw new PxtoneException("desc w");
1370 					}
1371 					break;
1372 				} else {
1373 					throw new PxtoneException("Ogg vorbis support is required");
1374 				}
1375 			default:
1376 				throw new PxtoneException("inv data");
1377 			}
1378 
1379 			if (!b_tune && p_w.is_name_buf()) {
1380 				p_doc.w_asfile(_code_assiWOIC);
1381 				if (!_io_assiWOIC_w(p_doc, w)) {
1382 					throw new PxtoneException("desc w");
1383 				}
1384 			}
1385 		}
1386 
1387 		// unit
1388 		p_doc.w_asfile(_code_num_UNIT);
1389 		_io_UNIT_num_w(p_doc);
1390 
1391 		for (int u = 0; u < _unit_num; u++) {
1392 			if (!b_tune && _units[u].is_name_buf()) {
1393 				p_doc.w_asfile(_code_assiUNIT);
1394 				if (!_io_assiUNIT_w(p_doc, u)) {
1395 					throw new PxtoneException("desc w");
1396 				}
1397 			}
1398 		}
1399 
1400 		{
1401 			int end_size = 0;
1402 			p_doc.w_asfile(_code_pxtoneND);
1403 			p_doc.w_asfile(end_size);
1404 		}
1405 	}
1406 
1407 	void read(ref pxtnDescriptor p_doc) @system {
1408 		if (!_b_init) {
1409 			throw new PxtoneException("pxtnService not initialized");
1410 		}
1411 
1412 		ushort exe_ver = 0;
1413 		_enum_FMTVER fmt_ver = _enum_FMTVER._enum_FMTVER_unknown;
1414 		int event_num = 0;
1415 
1416 		clear();
1417 
1418 		scope(failure) {
1419 			clear();
1420 		}
1421 
1422 		_pre_count_event(p_doc, event_num);
1423 		p_doc.seek(pxtnSEEK.set, 0);
1424 
1425 		if (_b_fix_evels_num) {
1426 			if (event_num > evels.get_Num_Max()) {
1427 				throw new PxtoneException("Too many events");
1428 			}
1429 		} else {
1430 			evels.Allocate(event_num);
1431 		}
1432 
1433 		_ReadVersion(p_doc, fmt_ver, exe_ver);
1434 
1435 		if (fmt_ver >= _enum_FMTVER._enum_FMTVER_v5) {
1436 			evels.Linear_Start();
1437 		} else {
1438 			evels.x4x_Read_Start();
1439 		}
1440 
1441 		_ReadTuneItems(p_doc);
1442 
1443 		if (fmt_ver >= _enum_FMTVER._enum_FMTVER_v5) {
1444 			evels.Linear_End(true);
1445 		}
1446 
1447 		if (fmt_ver <= _enum_FMTVER._enum_FMTVER_x3x) {
1448 			if (!_x3x_TuningKeyEvent()) {
1449 				throw new PxtoneException("x3x key");
1450 			}
1451 			if (!_x3x_AddTuningEvent()) {
1452 				throw new PxtoneException("x3x add tuning");
1453 			}
1454 			_x3x_SetVoiceNames();
1455 		}
1456 
1457 		if (_b_edit && master.get_beat_clock() != EVENTDEFAULT_BEATCLOCK) {
1458 			throw new PxtoneException("deny beatclock");
1459 		}
1460 
1461 		{
1462 			int clock1 = evels.get_Max_Clock();
1463 			int clock2 = master.get_last_clock();
1464 
1465 			if (clock1 > clock2) {
1466 				master.AdjustMeasNum(clock1);
1467 			} else {
1468 				master.AdjustMeasNum(clock2);
1469 			}
1470 		}
1471 
1472 		_moo_b_valid_data = true;
1473 	}
1474 
1475 	bool AdjustMeasNum() nothrow @safe {
1476 		if (!_b_init) {
1477 			return false;
1478 		}
1479 		master.AdjustMeasNum(evels.get_Max_Clock());
1480 		return true;
1481 	}
1482 
1483 	void tones_ready() @system {
1484 		if (!_b_init) {
1485 			throw new PxtoneException("pxtnService not initialized");
1486 		}
1487 
1488 		int beat_num = master.get_beat_num();
1489 		float beat_tempo = master.get_beat_tempo();
1490 
1491 		for (int i = 0; i < _delay_num; i++) {
1492 			_delays[i].Tone_Ready(beat_num, beat_tempo, _dst_sps);
1493 		}
1494 		for (int i = 0; i < _ovdrv_num; i++) {
1495 			_ovdrvs[i].Tone_Ready();
1496 		}
1497 		for (int i = 0; i < _woice_num; i++) {
1498 			_woices[i].Tone_Ready(_ptn_bldr, _dst_sps);
1499 		}
1500 	}
1501 
1502 	bool tones_clear() nothrow @system {
1503 		if (!_b_init) {
1504 			return false;
1505 		}
1506 		for (int i = 0; i < _delay_num; i++) {
1507 			_delays[i].Tone_Clear();
1508 		}
1509 		for (int i = 0; i < _unit_num; i++) {
1510 			_units[i].Tone_Clear();
1511 		}
1512 		return true;
1513 	}
1514 
1515 	int Group_Num() const nothrow @safe {
1516 		return _b_init ? _group_num : 0;
1517 	}
1518 
1519 	// ---------------------------
1520 	// Delay..
1521 	// ---------------------------
1522 
1523 	int Delay_Num() const nothrow @safe {
1524 		return _b_init ? _delay_num : 0;
1525 	}
1526 
1527 	int Delay_Max() const nothrow @safe {
1528 		return _b_init ? cast(int)_delays.length : 0;
1529 	}
1530 
1531 	bool Delay_Set(int idx, DELAYUNIT unit, float freq, float rate, int group) nothrow @system {
1532 		if (!_b_init) {
1533 			return false;
1534 		}
1535 		if (idx >= _delay_num) {
1536 			return false;
1537 		}
1538 		_delays[idx].Set(unit, freq, rate, group);
1539 		return true;
1540 	}
1541 
1542 	bool Delay_Add(DELAYUNIT unit, float freq, float rate, int group) nothrow @system {
1543 		if (!_b_init) {
1544 			return false;
1545 		}
1546 		if (_delay_num >= _delays.length) {
1547 			return false;
1548 		}
1549 		_delays[_delay_num] = pxtnDelay.init;
1550 		_delays[_delay_num].Set(unit, freq, rate, group);
1551 		_delay_num++;
1552 		return true;
1553 	}
1554 
1555 	bool Delay_Remove(int idx) nothrow @system {
1556 		if (!_b_init) {
1557 			return false;
1558 		}
1559 		if (idx >= _delay_num) {
1560 			return false;
1561 		}
1562 
1563 		_delay_num--;
1564 		for (int i = idx; i < _delay_num; i++) {
1565 			_delays[i] = _delays[i + 1];
1566 		}
1567 		_delays[_delay_num] = pxtnDelay.init;
1568 		return true;
1569 	}
1570 
1571 	void Delay_ReadyTone(int idx) @system {
1572 		if (!_b_init) {
1573 			throw new PxtoneException("pxtnService not initialized");
1574 		}
1575 		if (idx < 0 || idx >= _delay_num) {
1576 			throw new PxtoneException("param");
1577 		}
1578 		_delays[idx].Tone_Ready(master.get_beat_num(), master.get_beat_tempo(), _dst_sps);
1579 	}
1580 
1581 	pxtnDelay* Delay_Get(int idx) nothrow @system {
1582 		if (!_b_init) {
1583 			return null;
1584 		}
1585 		if (idx < 0 || idx >= _delay_num) {
1586 			return null;
1587 		}
1588 		return &_delays[idx];
1589 	}
1590 
1591 	// ---------------------------
1592 	// Over Drive..
1593 	// ---------------------------
1594 
1595 	int OverDrive_Num() const nothrow @safe {
1596 		return _b_init ? _ovdrv_num : 0;
1597 	}
1598 
1599 	int OverDrive_Max() const nothrow @safe {
1600 		return _b_init ? cast(int)_ovdrvs.length : 0;
1601 	}
1602 
1603 	bool OverDrive_Set(int idx, float cut, float amp, int group) nothrow @system {
1604 		if (!_b_init) {
1605 			return false;
1606 		}
1607 		if (idx >= _ovdrv_num) {
1608 			return false;
1609 		}
1610 		_ovdrvs[idx].Set(cut, amp, group);
1611 		return true;
1612 	}
1613 
1614 	bool OverDrive_Add(float cut, float amp, int group) nothrow @system {
1615 		if (!_b_init) {
1616 			return false;
1617 		}
1618 		if (_ovdrv_num >= _ovdrvs.length) {
1619 			return false;
1620 		}
1621 		_ovdrvs[_ovdrv_num] = new pxtnOverDrive();
1622 		_ovdrvs[_ovdrv_num].Set(cut, amp, group);
1623 		_ovdrv_num++;
1624 		return true;
1625 	}
1626 
1627 	bool OverDrive_Remove(int idx) nothrow @system {
1628 		if (!_b_init) {
1629 			return false;
1630 		}
1631 		if (idx >= _ovdrv_num) {
1632 			return false;
1633 		}
1634 
1635 		_ovdrvs[idx] = null;
1636 		_ovdrv_num--;
1637 		for (int i = idx; i < _ovdrv_num; i++) {
1638 			_ovdrvs[i] = _ovdrvs[i + 1];
1639 		}
1640 		_ovdrvs[_ovdrv_num] = null;
1641 		return true;
1642 	}
1643 
1644 	bool OverDrive_ReadyTone(int idx) nothrow @system {
1645 		if (!_b_init) {
1646 			return false;
1647 		}
1648 		if (idx < 0 || idx >= _ovdrv_num) {
1649 			return false;
1650 		}
1651 		_ovdrvs[idx].Tone_Ready();
1652 		return true;
1653 	}
1654 
1655 	pxtnOverDrive* OverDrive_Get(int idx) nothrow @system {
1656 		if (!_b_init) {
1657 			return null;
1658 		}
1659 		if (idx < 0 || idx >= _ovdrv_num) {
1660 			return null;
1661 		}
1662 		return _ovdrvs[idx];
1663 	}
1664 
1665 	// ---------------------------
1666 	// Woice..
1667 	// ---------------------------
1668 
1669 	int Woice_Num() const nothrow @safe {
1670 		return _b_init ? _woice_num : 0;
1671 	}
1672 
1673 	int Woice_Max() const nothrow @safe {
1674 		return _b_init ? cast(int)_woices.length : 0;
1675 	}
1676 
1677 	inout(pxtnWoice)* Woice_Get(int idx) inout nothrow @safe {
1678 		if (!_b_init) {
1679 			return null;
1680 		}
1681 		if (idx < 0 || idx >= _woice_num) {
1682 			return null;
1683 		}
1684 		return _woices[idx];
1685 	}
1686 
1687 	void Woice_read(int idx, ref pxtnDescriptor desc, pxtnWOICETYPE type) @system {
1688 		if (!_b_init) {
1689 			throw new PxtoneException("pxtnService not initialized");
1690 		}
1691 		if (idx < 0 || idx >= _woices.length) {
1692 			throw new PxtoneException("param");
1693 		}
1694 		if (idx > _woice_num) {
1695 			throw new PxtoneException("param");
1696 		}
1697 		if (idx == _woice_num) {
1698 			_woices[idx] = new pxtnWoice();
1699 			_woice_num++;
1700 		}
1701 
1702 		scope(failure) {
1703 			Woice_Remove(idx);
1704 		}
1705 		_woices[idx].read(desc, type);
1706 	}
1707 
1708 	void Woice_ReadyTone(int idx) @system {
1709 		if (!_b_init) {
1710 			throw new PxtoneException("pxtnService not initialized");
1711 		}
1712 		if (idx < 0 || idx >= _woice_num) {
1713 			throw new PxtoneException("param");
1714 		}
1715 		_woices[idx].Tone_Ready(_ptn_bldr, _dst_sps);
1716 	}
1717 
1718 	bool Woice_Remove(int idx) nothrow @system {
1719 		if (!_b_init) {
1720 			return false;
1721 		}
1722 		if (idx < 0 || idx >= _woice_num) {
1723 			return false;
1724 		}
1725 		_woices[idx] = null;
1726 		_woice_num--;
1727 		for (int i = idx; i < _woice_num; i++) {
1728 			_woices[i] = _woices[i + 1];
1729 		}
1730 		_woices[_woice_num] = null;
1731 		return true;
1732 	}
1733 
1734 	bool Woice_Replace(int old_place, int new_place) nothrow @system {
1735 		if (!_b_init) {
1736 			return false;
1737 		}
1738 
1739 		pxtnWoice* p_w = _woices[old_place];
1740 		int max_place = _woice_num - 1;
1741 
1742 		if (new_place > max_place) {
1743 			new_place = max_place;
1744 		}
1745 		if (new_place == old_place) {
1746 			return true;
1747 		}
1748 
1749 		if (old_place < new_place) {
1750 			for (int w = old_place; w < new_place; w++) {
1751 				if (_woices[w]) {
1752 					_woices[w] = _woices[w + 1];
1753 				}
1754 			}
1755 		} else {
1756 			for (int w = old_place; w > new_place; w--) {
1757 				if (_woices[w]) {
1758 					_woices[w] = _woices[w - 1];
1759 				}
1760 			}
1761 		}
1762 
1763 		_woices[new_place] = p_w;
1764 		return true;
1765 	}
1766 
1767 	// ---------------------------
1768 	// Unit..
1769 	// ---------------------------
1770 
1771 	int Unit_Num() const nothrow @safe {
1772 		return _b_init ? _unit_num : 0;
1773 	}
1774 
1775 	int Unit_Max() const nothrow @safe {
1776 		return _b_init ? cast(int)_units.length : 0;
1777 	}
1778 
1779 	inout(pxtnUnit)* Unit_Get(int idx) inout nothrow @safe {
1780 		if (!_b_init) {
1781 			return null;
1782 		}
1783 		if (idx < 0 || idx >= _unit_num) {
1784 			return null;
1785 		}
1786 		return &_units[idx];
1787 	}
1788 
1789 	bool Unit_Remove(int idx) nothrow @system {
1790 		if (!_b_init) {
1791 			return false;
1792 		}
1793 		if (idx < 0 || idx >= _unit_num) {
1794 			return false;
1795 		}
1796 		_unit_num--;
1797 		for (int i = idx; i < _unit_num; i++) {
1798 			_units[i] = _units[i + 1];
1799 		}
1800 		_units[_unit_num] = pxtnUnit.init;
1801 		return true;
1802 	}
1803 
1804 	bool Unit_Replace(int old_place, int new_place) nothrow @system {
1805 		if (!_b_init) {
1806 			return false;
1807 		}
1808 
1809 		pxtnUnit p_w = _units[old_place];
1810 		int max_place = _unit_num - 1;
1811 
1812 		if (new_place > max_place) {
1813 			new_place = max_place;
1814 		}
1815 		if (new_place == old_place) {
1816 			return true;
1817 		}
1818 
1819 		if (old_place < new_place) {
1820 			for (int w = old_place; w < new_place; w++) {
1821 				_units[w] = _units[w + 1];
1822 			}
1823 		} else {
1824 			for (int w = old_place; w > new_place; w--) {
1825 				_units[w] = _units[w - 1];
1826 			}
1827 		}
1828 		_units[new_place] = p_w;
1829 		return true;
1830 	}
1831 
1832 	bool Unit_AddNew() nothrow @system {
1833 		if (_unit_num >= _units.length) {
1834 			return false;
1835 		}
1836 		_units[_unit_num] = pxtnUnit.init;
1837 		_unit_num++;
1838 		return true;
1839 	}
1840 
1841 	bool Unit_SetOpratedAll(bool b) nothrow @system {
1842 		if (!_b_init) {
1843 			return false;
1844 		}
1845 		for (int u = 0; u < _unit_num; u++) {
1846 			_units[u].set_operated(b);
1847 			if (b) {
1848 				_units[u].set_played(true);
1849 			}
1850 		}
1851 		return true;
1852 	}
1853 
1854 	bool Unit_Solo(int idx) nothrow @system {
1855 		if (!_b_init) {
1856 			return false;
1857 		}
1858 		for (int u = 0; u < _unit_num; u++) {
1859 			if (u == idx) {
1860 				_units[u].set_played(true);
1861 			} else {
1862 				_units[u].set_played(false);
1863 			}
1864 		}
1865 		return false;
1866 	}
1867 
1868 	// ---------------------------
1869 	// Quality..
1870 	// ---------------------------
1871 
1872 	void set_destination_quality(int ch_num, int sps) @safe {
1873 		enforce(_b_init, new PxtoneException("pxtnService not initialized"));
1874 		switch (ch_num) {
1875 		case 1:
1876 			break;
1877 		case 2:
1878 			break;
1879 		default:
1880 			throw new PxtoneException("Unsupported sample rate");
1881 		}
1882 
1883 		_dst_ch_num = ch_num;
1884 		_dst_sps = sps;
1885 		_dst_byte_per_smp = pxtnBITPERSAMPLE / 8 * ch_num;
1886 	}
1887 
1888 	void get_destination_quality(int* p_ch_num, int* p_sps) const @safe {
1889 		enforce(_b_init, new PxtoneException("pxtnService not initialized"));
1890 		if (p_ch_num) {
1891 			*p_ch_num = _dst_ch_num;
1892 		}
1893 		if (p_sps) {
1894 			*p_sps = _dst_sps;
1895 		}
1896 	}
1897 
1898 	void set_sampled_callback(pxtnSampledCallback proc, void* user) @safe {
1899 		enforce(_b_init, new PxtoneException("pxtnService not initialized"));
1900 		_sampled_proc = proc;
1901 		_sampled_user = user;
1902 	}
1903 
1904 	//////////////
1905 	// Moo..
1906 	//////////////
1907 
1908 	///////////////////////
1909 	// get / set
1910 	///////////////////////
1911 
1912 	bool moo_is_valid_data() const @safe {
1913 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1914 		return _moo_b_valid_data;
1915 	}
1916 
1917 	bool moo_is_end_vomit() const @safe {
1918 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1919 		return _moo_b_end_vomit;
1920 	}
1921 
1922 	void moo_set_mute_by_unit(bool b) @safe {
1923 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1924 		_moo_b_mute_by_unit = b;
1925 	}
1926 
1927 	void moo_set_loop(bool b) @safe {
1928 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1929 		_moo_b_loop = b;
1930 	}
1931 
1932 	void moo_set_fade(int fade, float sec) @safe {
1933 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1934 		_moo_fade_max = cast(int)(cast(float) _dst_sps * sec) >> 8;
1935 		if (fade < 0) {
1936 			_moo_fade_fade = -1;
1937 			_moo_fade_count = _moo_fade_max << 8;
1938 		}  // out
1939 		else if (fade > 0) {
1940 			_moo_fade_fade = 1;
1941 			_moo_fade_count = 0;
1942 		}  // in
1943 		else {
1944 			_moo_fade_fade = 0;
1945 			_moo_fade_count = 0;
1946 		} // off
1947 	}
1948 
1949 	void moo_set_master_volume(float v) @safe {
1950 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1951 		if (v < 0) {
1952 			v = 0;
1953 		}
1954 		if (v > 1) {
1955 			v = 1;
1956 		}
1957 		_moo_master_vol = v;
1958 	}
1959 
1960 	int moo_get_total_sample() const @system {
1961 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1962 		enforce(_moo_b_valid_data, new PxtoneException("no valid data loaded"));
1963 
1964 		int meas_num;
1965 		int beat_num;
1966 		float beat_tempo;
1967 		master.Get(&beat_num, &beat_tempo, null, &meas_num);
1968 		return pxtnService_moo_CalcSampleNum(meas_num, beat_num, _dst_sps, master.get_beat_tempo());
1969 	}
1970 
1971 	int moo_get_now_clock() const @safe {
1972 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1973 		enforce(_moo_clock_rate, new PxtoneException("No clock rate set"));
1974 		return cast(int)(_moo_smp_count / _moo_clock_rate);
1975 	}
1976 
1977 	int moo_get_end_clock() const @safe {
1978 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1979 		enforce(_moo_clock_rate, new PxtoneException("No clock rate set"));
1980 		return cast(int)(_moo_smp_end / _moo_clock_rate);
1981 	}
1982 
1983 	int moo_get_sampling_offset() const @safe {
1984 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1985 		enforce(!_moo_b_end_vomit, new PxtoneException("playback has ended"));
1986 		return _moo_smp_count;
1987 	}
1988 
1989 	int moo_get_sampling_end() const @safe {
1990 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
1991 		enforce(!_moo_b_end_vomit, new PxtoneException("playback has ended"));
1992 		return _moo_smp_end;
1993 	}
1994 
1995 	// preparation
1996 	void moo_preparation() @system {
1997 		return moo_preparation(pxtnVOMITPREPARATION.init);
1998 	}
1999 	void moo_preparation(in pxtnVOMITPREPARATION p_prep) @system {
2000 		scope(failure) {
2001 			_moo_b_end_vomit = true;
2002 		}
2003 		enforce(_moo_b_init, new PxtoneException("pxtnService not initialized"));
2004 		enforce(_moo_b_valid_data, new PxtoneException("no valid data loaded"));
2005 		enforce(_dst_ch_num, new PxtoneException("invalid channel number specified"));
2006 		enforce(_dst_sps, new PxtoneException("invalid sample rate specified"));
2007 		enforce(_dst_byte_per_smp, new PxtoneException("invalid sample size"));
2008 
2009 		int meas_end = master.get_play_meas();
2010 		int meas_repeat = master.get_repeat_meas();
2011 
2012 		if (p_prep.meas_end) {
2013 			meas_end = p_prep.meas_end;
2014 		}
2015 		if (p_prep.meas_repeat) {
2016 			meas_repeat = p_prep.meas_repeat;
2017 		}
2018 
2019 		_moo_b_mute_by_unit = p_prep.flags.unitMute;
2020 		_moo_b_loop = p_prep.flags.loop;
2021 
2022 		setVolume(p_prep.master_volume);
2023 
2024 		_moo_bt_clock = master.get_beat_clock();
2025 		_moo_bt_num = master.get_beat_num();
2026 		_moo_bt_tempo = master.get_beat_tempo();
2027 		_moo_clock_rate = cast(float)(60.0f * cast(double) _dst_sps / (cast(double) _moo_bt_tempo * cast(double) _moo_bt_clock));
2028 		_moo_smp_stride = (44100.0f / _dst_sps);
2029 		_moo_top = 0x7fff;
2030 
2031 		_moo_time_pan_index = 0;
2032 
2033 		_moo_smp_end = cast(int)(cast(double) meas_end * cast(double) _moo_bt_num * cast(double) _moo_bt_clock * _moo_clock_rate);
2034 		_moo_smp_repeat = cast(int)(cast(double) meas_repeat * cast(double) _moo_bt_num * cast(double) _moo_bt_clock * _moo_clock_rate);
2035 
2036 		if (p_prep.start_pos_float) {
2037 			_moo_smp_start = cast(int)(cast(float) moo_get_total_sample() * p_prep.start_pos_float);
2038 		} else if (p_prep.start_pos_sample) {
2039 			_moo_smp_start = p_prep.start_pos_sample;
2040 		} else {
2041 			_moo_smp_start = cast(int)(cast(double) p_prep.start_pos_meas * cast(double) _moo_bt_num * cast(double) _moo_bt_clock * _moo_clock_rate);
2042 		}
2043 
2044 		_moo_smp_count = _moo_smp_start;
2045 		_moo_smp_smooth = _dst_sps / 250; // (0.004sec) // (0.010sec)
2046 
2047 		if (p_prep.fadein_sec > 0) {
2048 			moo_set_fade(1, p_prep.fadein_sec);
2049 		} else {
2050 			moo_set_fade(0, 0);
2051 		}
2052 		start();
2053 	}
2054 
2055 	void setVolume(float volume) @system {
2056 		enforce(!volume.isNaN, "Volume must be a number");
2057 		_moo_master_vol = clamp(volume, 0.0, 1.0);
2058 	}
2059 
2060 	void start() @system {
2061 		tones_clear();
2062 
2063 		_moo_p_eve = evels.get_Records();
2064 
2065 		_moo_InitUnitTone();
2066 
2067 		_moo_b_end_vomit = false;
2068 	}
2069 
2070 	////////////////////
2071 	//
2072 	////////////////////
2073 
2074 	bool Moo(ubyte[] p_buf) nothrow @system {
2075 		if (!_moo_b_init) {
2076 			return false;
2077 		}
2078 		if (!_moo_b_valid_data) {
2079 			return false;
2080 		}
2081 		if (_moo_b_end_vomit) {
2082 			return false;
2083 		}
2084 
2085 		bool b_ret = false;
2086 
2087 		int smp_w = 0;
2088 
2089 		if (p_buf.length % _dst_byte_per_smp) {
2090 			return false;
2091 		}
2092 
2093 		int smp_num = cast(int)(p_buf.length / _dst_byte_per_smp);
2094 
2095 		{
2096 			short[] p16 = cast(short[]) p_buf;
2097 			short[2] sample;
2098 
2099 			for (smp_w = 0; smp_w < smp_num; smp_w++) {
2100 				if (!_moo_PXTONE_SAMPLE(cast(ubyte[])(sample[]))) {
2101 					_moo_b_end_vomit = true;
2102 					break;
2103 				}
2104 				for (int ch = 0; ch < _dst_ch_num; ch++, p16 = p16[1 .. $]) {
2105 					p16[0] = sample[ch];
2106 				}
2107 			}
2108 			for (; smp_w < smp_num; smp_w++) {
2109 				for (int ch = 0; ch < _dst_ch_num; ch++, p16 = p16[1 .. $]) {
2110 					p16[0] = 0;
2111 				}
2112 			}
2113 		}
2114 
2115 		if (_sampled_proc) {
2116 			int clock = cast(int)(_moo_smp_count / _moo_clock_rate);
2117 			if (!_sampled_proc(_sampled_user, &this)) {
2118 				_moo_b_end_vomit = true;
2119 				goto term;
2120 			}
2121 		}
2122 
2123 		b_ret = true;
2124 	term:
2125 		return b_ret;
2126 	}
2127 }
2128 
2129 int pxtnService_moo_CalcSampleNum(int meas_num, int beat_num, int sps, float beat_tempo) nothrow @safe {
2130 	uint total_beat_num;
2131 	uint sample_num;
2132 	if (!beat_tempo) {
2133 		return 0;
2134 	}
2135 	total_beat_num = meas_num * beat_num;
2136 	sample_num = cast(uint)(cast(double) sps * 60 * cast(double) total_beat_num / cast(double) beat_tempo);
2137 	return sample_num;
2138 }