1 module pxtone.pulse.noise;
2 
3 import pxtone.pxtn;
4 
5 import pxtone.error;
6 import pxtone.descriptor;
7 import pxtone.pulse.frequency;
8 import pxtone.pulse.oscillator;
9 import pxtone.pulse.pcm;
10 
11 enum pxWAVETYPE {
12 	None = 0,
13 	Sine,
14 	Saw,
15 	Rect,
16 	Random,
17 	Saw2,
18 	Rect2,
19 
20 	Tri,
21 	Random2,
22 	Rect3,
23 	Rect4,
24 	Rect8,
25 	Rect16,
26 	Saw3,
27 	Saw4,
28 	Saw6,
29 	Saw8,
30 
31 	num,
32 }
33 
34 struct pxNOISEDESIGN_OSCILLATOR {
35 	pxWAVETYPE type;
36 	float freq = 0.0;
37 	float volume = 0.0;
38 	float offset = 0.0;
39 	bool b_rev;
40 }
41 
42 struct pxNOISEDESIGN_UNIT {
43 	bool bEnable;
44 	int enve_num;
45 	pxtnPOINT[] enves;
46 	int pan;
47 	pxNOISEDESIGN_OSCILLATOR main;
48 	pxNOISEDESIGN_OSCILLATOR freq;
49 	pxNOISEDESIGN_OSCILLATOR volu;
50 }
51 
52 enum NOISEDESIGNLIMIT_SMPNUM = (48000 * 10);
53 enum NOISEDESIGNLIMIT_ENVE_X = (1000 * 10);
54 enum NOISEDESIGNLIMIT_ENVE_Y = (100);
55 enum NOISEDESIGNLIMIT_OSC_FREQUENCY = 44100.0f;
56 enum NOISEDESIGNLIMIT_OSC_VOLUME = 200.0f;
57 enum NOISEDESIGNLIMIT_OSC_OFFSET = 100.0f;
58 
59 void _FixUnit(pxNOISEDESIGN_OSCILLATOR* p_osc) nothrow @safe {
60 	if (p_osc.type >= pxWAVETYPE.num) {
61 		p_osc.type = pxWAVETYPE.None;
62 	}
63 	if (p_osc.freq > NOISEDESIGNLIMIT_OSC_FREQUENCY) {
64 		p_osc.freq = NOISEDESIGNLIMIT_OSC_FREQUENCY;
65 	}
66 	if (p_osc.freq <= 0) {
67 		p_osc.freq = 0;
68 	}
69 	if (p_osc.volume > NOISEDESIGNLIMIT_OSC_VOLUME) {
70 		p_osc.volume = NOISEDESIGNLIMIT_OSC_VOLUME;
71 	}
72 	if (p_osc.volume <= 0) {
73 		p_osc.volume = 0;
74 	}
75 	if (p_osc.offset > NOISEDESIGNLIMIT_OSC_OFFSET) {
76 		p_osc.offset = NOISEDESIGNLIMIT_OSC_OFFSET;
77 	}
78 	if (p_osc.offset <= 0) {
79 		p_osc.offset = 0;
80 	}
81 }
82 
83 enum MAX_NOISEEDITUNITNUM = 4;
84 enum MAX_NOISEEDITENVELOPENUM = 3;
85 
86 enum NOISEEDITFLAG_XX1 = 0x0001;
87 enum NOISEEDITFLAG_XX2 = 0x0002;
88 enum NOISEEDITFLAG_ENVELOPE = 0x0004;
89 enum NOISEEDITFLAG_PAN = 0x0008;
90 enum NOISEEDITFLAG_OSC_MAIN = 0x0010;
91 enum NOISEEDITFLAG_OSC_FREQ = 0x0020;
92 enum NOISEEDITFLAG_OSC_VOLU = 0x0040;
93 enum NOISEEDITFLAG_OSC_PAN = 0x0080;
94 
95 enum NOISEEDITFLAG_UNCOVERED = 0xffffff83;
96 
97 immutable _code = "PTNOISE-";
98 //_ver =  20051028 ; -v.0.9.2.3
99 __gshared const uint _ver = 20120418; // 16 wave types.
100 
101 void _WriteOscillator(const(pxNOISEDESIGN_OSCILLATOR)* p_osc, ref pxtnDescriptor p_doc, ref int p_add) @system {
102 	int work;
103 	work = cast(int) p_osc.type;
104 	p_doc.v_w_asfile(work, p_add);
105 	work = cast(int) p_osc.b_rev;
106 	p_doc.v_w_asfile(work, p_add);
107 	work = cast(int)(p_osc.freq * 10);
108 	p_doc.v_w_asfile(work, p_add);
109 	work = cast(int)(p_osc.volume * 10);
110 	p_doc.v_w_asfile(work, p_add);
111 	work = cast(int)(p_osc.offset * 10);
112 	p_doc.v_w_asfile(work, p_add);
113 }
114 
115 void _ReadOscillator(pxNOISEDESIGN_OSCILLATOR* p_osc, ref pxtnDescriptor p_doc) @system {
116 	int work;
117 	p_doc.v_r(work);
118 	p_osc.type = cast(pxWAVETYPE) work;
119 	if (p_osc.type >= pxWAVETYPE.num) {
120 		throw new PxtoneException("fmt unknown");
121 	}
122 	p_doc.v_r(work);
123 	p_osc.b_rev = work ? true : false;
124 	p_doc.v_r(work);
125 	p_osc.freq = cast(float) work / 10;
126 	p_doc.v_r(work);
127 	p_osc.volume = cast(float) work / 10;
128 	p_doc.v_r(work);
129 	p_osc.offset = cast(float) work / 10;
130 }
131 
132 uint _MakeFlags(const(pxNOISEDESIGN_UNIT)* pU) nothrow @safe {
133 	uint flags = 0;
134 	flags |= NOISEEDITFLAG_ENVELOPE;
135 	if (pU.pan) {
136 		flags |= NOISEEDITFLAG_PAN;
137 	}
138 	if (pU.main.type != pxWAVETYPE.None) {
139 		flags |= NOISEEDITFLAG_OSC_MAIN;
140 	}
141 	if (pU.freq.type != pxWAVETYPE.None) {
142 		flags |= NOISEEDITFLAG_OSC_FREQ;
143 	}
144 	if (pU.volu.type != pxWAVETYPE.None) {
145 		flags |= NOISEEDITFLAG_OSC_VOLU;
146 	}
147 	return flags;
148 }
149 
150 int _CompareOsci(const(pxNOISEDESIGN_OSCILLATOR)* p_osc1, const(pxNOISEDESIGN_OSCILLATOR)* p_osc2) nothrow @safe {
151 	if (p_osc1.type != p_osc2.type) {
152 		return 1;
153 	}
154 	if (p_osc1.freq != p_osc2.freq) {
155 		return 1;
156 	}
157 	if (p_osc1.volume != p_osc2.volume) {
158 		return 1;
159 	}
160 	if (p_osc1.offset != p_osc2.offset) {
161 		return 1;
162 	}
163 	if (p_osc1.b_rev != p_osc2.b_rev) {
164 		return 1;
165 	}
166 	return 0;
167 }
168 
169 struct pxtnPulse_Noise {
170 private:
171 	int _smp_num_44k;
172 	int _unit_num;
173 	pxNOISEDESIGN_UNIT[] _units;
174 
175 public:
176 	 ~this() nothrow @system {
177 		Release();
178 	}
179 
180 	void write(ref pxtnDescriptor p_doc, int* p_add) const @system {
181 		bool b_ret = false;
182 		int u, e, seek, num_seek, flags;
183 		char _byte;
184 		char unit_num = 0;
185 		const(pxNOISEDESIGN_UNIT)* pU;
186 
187 		//	Fix();
188 
189 		if (p_add) {
190 			seek = *p_add;
191 		} else {
192 			seek = 0;
193 		}
194 
195 		p_doc.w_asfile(_code);
196 		p_doc.w_asfile(_ver);
197 		seek += 12;
198 		p_doc.v_w_asfile(_smp_num_44k, seek);
199 
200 		p_doc.w_asfile(unit_num);
201 		num_seek = seek;
202 		seek += 1;
203 
204 		for (u = 0; u < _unit_num; u++) {
205 			pU = &_units[u];
206 			if (pU.bEnable) {
207 				// フラグ
208 				flags = _MakeFlags(pU);
209 				p_doc.v_w_asfile(flags, seek);
210 				if (flags & NOISEEDITFLAG_ENVELOPE) {
211 					p_doc.v_w_asfile(pU.enve_num, seek);
212 					for (e = 0; e < pU.enve_num; e++) {
213 						p_doc.v_w_asfile(pU.enves[e].x, seek);
214 						p_doc.v_w_asfile(pU.enves[e].y, seek);
215 					}
216 				}
217 				if (flags & NOISEEDITFLAG_PAN) {
218 					_byte = cast(char) pU.pan;
219 					p_doc.w_asfile(_byte);
220 					seek++;
221 				}
222 				if (flags & NOISEEDITFLAG_OSC_MAIN) {
223 					_WriteOscillator(&pU.main, p_doc, seek);
224 				}
225 				if (flags & NOISEEDITFLAG_OSC_FREQ) {
226 					_WriteOscillator(&pU.freq, p_doc, seek);
227 				}
228 				if (flags & NOISEEDITFLAG_OSC_VOLU) {
229 					_WriteOscillator(&pU.volu, p_doc, seek);
230 				}
231 				unit_num++;
232 			}
233 		}
234 
235 		// update unit_num.
236 		p_doc.seek(pxtnSEEK.cur, num_seek - seek);
237 		p_doc.w_asfile(unit_num);
238 		p_doc.seek(pxtnSEEK.cur, seek - num_seek - 1);
239 		if (p_add) {
240 			*p_add = seek;
241 		}
242 
243 		b_ret = true;
244 	End:
245 
246 		if (!b_ret) {
247 			throw new PxtoneException("");
248 		}
249 	}
250 
251 	void read(ref pxtnDescriptor p_doc) @system {
252 		uint flags = 0;
253 		char unit_num = 0;
254 		char _byte = 0;
255 		uint ver = 0;
256 
257 		pxNOISEDESIGN_UNIT* pU = null;
258 
259 		char[8] code = 0;
260 
261 		Release();
262 
263 		scope(failure) {
264 			Release();
265 		}
266 		p_doc.r(code[]);
267 		if (code != _code[0 .. 8]) {
268 			throw new PxtoneException("inv code");
269 		}
270 		p_doc.r(ver);
271 		if (ver > _ver) {
272 			throw new PxtoneException("fmt new");
273 		}
274 		p_doc.v_r(_smp_num_44k);
275 		p_doc.r(unit_num);
276 		if (unit_num < 0) {
277 			throw new PxtoneException("inv data");
278 		}
279 		if (unit_num > MAX_NOISEEDITUNITNUM) {
280 			throw new PxtoneException("fmt unknown");
281 		}
282 		_unit_num = unit_num;
283 
284 		_units = new pxNOISEDESIGN_UNIT[](_unit_num);
285 
286 		for (int u = 0; u < _unit_num; u++) {
287 			pU = &_units[u];
288 			pU.bEnable = true;
289 
290 			p_doc.v_r(*cast(int*)&flags);
291 			if (flags & NOISEEDITFLAG_UNCOVERED) {
292 				throw new PxtoneException("fmt unknown");
293 			}
294 
295 			// envelope
296 			if (flags & NOISEEDITFLAG_ENVELOPE) {
297 				p_doc.v_r(pU.enve_num);
298 				if (pU.enve_num > MAX_NOISEEDITENVELOPENUM) {
299 					throw new PxtoneException("fmt unknown");
300 				}
301 				pU.enves = new pxtnPOINT[](pU.enve_num);
302 				for (int e = 0; e < pU.enve_num; e++) {
303 					p_doc.v_r(pU.enves[e].x);
304 					p_doc.v_r(pU.enves[e].y);
305 				}
306 			}
307 			// pan
308 			if (flags & NOISEEDITFLAG_PAN) {
309 				p_doc.r(_byte);
310 				pU.pan = _byte;
311 			}
312 
313 			if (flags & NOISEEDITFLAG_OSC_MAIN) {
314 				_ReadOscillator(&pU.main, p_doc);
315 			}
316 			if (flags & NOISEEDITFLAG_OSC_FREQ) {
317 				_ReadOscillator(&pU.freq, p_doc);
318 			}
319 			if (flags & NOISEEDITFLAG_OSC_VOLU) {
320 				_ReadOscillator(&pU.volu, p_doc);
321 			}
322 		}
323 	}
324 
325 	void Release() nothrow @system {
326 		if (_units) {
327 			_units = null;
328 			_unit_num = 0;
329 		}
330 	}
331 
332 	bool Allocate(int unit_num, int envelope_num) nothrow @system {
333 		bool b_ret = false;
334 
335 		Release();
336 
337 		_unit_num = unit_num;
338 		_units = new pxNOISEDESIGN_UNIT[](unit_num);
339 		if (!_units) {
340 			goto End;
341 		}
342 
343 		for (int u = 0; u < unit_num; u++) {
344 			pxNOISEDESIGN_UNIT* p_unit = &_units[u];
345 			p_unit.enve_num = envelope_num;
346 			p_unit.enves = new pxtnPOINT[](p_unit.enve_num);
347 			if (!p_unit.enves) {
348 				goto End;
349 			}
350 		}
351 
352 		b_ret = true;
353 	End:
354 		if (!b_ret) {
355 			Release();
356 		}
357 
358 		return b_ret;
359 	}
360 
361 	bool Copy(ref pxtnPulse_Noise p_dst) const nothrow @system {
362 		bool b_ret = false;
363 
364 		p_dst.Release();
365 		p_dst._smp_num_44k = _smp_num_44k;
366 
367 		if (_unit_num) {
368 			int enve_num = _units[0].enve_num;
369 			if (!p_dst.Allocate(_unit_num, enve_num)) {
370 				goto End;
371 			}
372 			for (int u = 0; u < _unit_num; u++) {
373 				p_dst._units[u].bEnable = _units[u].bEnable;
374 				p_dst._units[u].enve_num = _units[u].enve_num;
375 				p_dst._units[u].freq = _units[u].freq;
376 				p_dst._units[u].main = _units[u].main;
377 				p_dst._units[u].pan = _units[u].pan;
378 				p_dst._units[u].volu = _units[u].volu;
379 				p_dst._units[u].enves = new pxtnPOINT[](enve_num);
380 				if (!p_dst._units[u].enves) {
381 					goto End;
382 				}
383 				for (int e = 0; e < enve_num; e++) {
384 					p_dst._units[u].enves[e] = _units[u].enves[e];
385 				}
386 			}
387 		}
388 
389 		b_ret = true;
390 	End:
391 		if (!b_ret) {
392 			p_dst.Release();
393 		}
394 
395 		return b_ret;
396 	}
397 
398 	int Compare(const(pxtnPulse_Noise)* p_src) const nothrow @safe {
399 		if (!p_src) {
400 			return -1;
401 		}
402 
403 		if (p_src._smp_num_44k != _smp_num_44k) {
404 			return 1;
405 		}
406 		if (p_src._unit_num != _unit_num) {
407 			return 1;
408 		}
409 
410 		for (int u = 0; u < _unit_num; u++) {
411 			if (p_src._units[u].bEnable != _units[u].bEnable) {
412 				return 1;
413 			}
414 			if (p_src._units[u].enve_num != _units[u].enve_num) {
415 				return 1;
416 			}
417 			if (p_src._units[u].pan != _units[u].pan) {
418 				return 1;
419 			}
420 			if (_CompareOsci(&p_src._units[u].main, &_units[u].main)) {
421 				return 1;
422 			}
423 			if (_CompareOsci(&p_src._units[u].freq, &_units[u].freq)) {
424 				return 1;
425 			}
426 			if (_CompareOsci(&p_src._units[u].volu, &_units[u].volu)) {
427 				return 1;
428 			}
429 
430 			for (int e = 0; e < _units[u].enve_num; e++) {
431 				if (_units[u].enves[e].x != _units[u].enves[e].x) {
432 					return 1;
433 				}
434 				if (_units[u].enves[e].y != _units[u].enves[e].y) {
435 					return 1;
436 				}
437 			}
438 		}
439 		return 0;
440 	}
441 
442 	void Fix() nothrow @safe {
443 		pxNOISEDESIGN_UNIT* p_unit;
444 		int i, e;
445 
446 		if (_smp_num_44k > NOISEDESIGNLIMIT_SMPNUM) {
447 			_smp_num_44k = NOISEDESIGNLIMIT_SMPNUM;
448 		}
449 
450 		for (i = 0; i < _unit_num; i++) {
451 			p_unit = &_units[i];
452 			if (p_unit.bEnable) {
453 				for (e = 0; e < p_unit.enve_num; e++) {
454 					if (p_unit.enves[e].x > NOISEDESIGNLIMIT_ENVE_X) {
455 						p_unit.enves[e].x = NOISEDESIGNLIMIT_ENVE_X;
456 					}
457 					if (p_unit.enves[e].x < 0) {
458 						p_unit.enves[e].x = 0;
459 					}
460 					if (p_unit.enves[e].y > NOISEDESIGNLIMIT_ENVE_Y) {
461 						p_unit.enves[e].y = NOISEDESIGNLIMIT_ENVE_Y;
462 					}
463 					if (p_unit.enves[e].y < 0) {
464 						p_unit.enves[e].y = 0;
465 					}
466 				}
467 				if (p_unit.pan < -100) {
468 					p_unit.pan = -100;
469 				}
470 				if (p_unit.pan > 100) {
471 					p_unit.pan = 100;
472 				}
473 				_FixUnit(&p_unit.main);
474 				_FixUnit(&p_unit.freq);
475 				_FixUnit(&p_unit.volu);
476 			}
477 		}
478 	}
479 
480 	void set_smp_num_44k(int num) nothrow @safe {
481 		_smp_num_44k = num;
482 	}
483 
484 	int get_unit_num() const nothrow @safe {
485 		return _unit_num;
486 	}
487 
488 	int get_smp_num_44k() const nothrow @safe {
489 		return _smp_num_44k;
490 	}
491 
492 	float get_sec() const nothrow @safe {
493 		return cast(float) _smp_num_44k / 44100;
494 	}
495 
496 	pxNOISEDESIGN_UNIT* get_unit(int u) nothrow @safe {
497 		if (!_units || u < 0 || u >= _unit_num) {
498 			return null;
499 		}
500 		return &_units[u];
501 	}
502 }