1 module pxtone.pulse.pcm;
2 
3 import pxtone.pxtn;
4 
5 import pxtone.error;
6 import pxtone.descriptor;
7 
8 struct WAVEFORMATCHUNK {
9 	ushort formatID; // PCM:0x0001
10 	ushort ch; //
11 	uint sps; //
12 	uint byte_per_sec; // byte per sec.
13 	ushort block_size; //
14 	ushort bps; // bit per sample.
15 	ushort ext; // no use for pcm.
16 }
17 
18 struct pxtnPulse_PCM {
19 private:
20 	int _ch;
21 	int _sps;
22 	int _bps;
23 	int _smp_head; // no use. 0
24 	int _smp_body;
25 	int _smp_tail; // no use. 0
26 	ubyte[] _p_smp;
27 
28 	// stereo / mono
29 	bool _Convert_ChannelNum(int new_ch) nothrow @system {
30 		ubyte[] p_work = null;
31 		int sample_size;
32 		int work_size;
33 		int a, b;
34 		int temp1;
35 		int temp2;
36 
37 		sample_size = (_smp_head + _smp_body + _smp_tail) * _ch * _bps / 8;
38 
39 		if (_p_smp == null) {
40 			return false;
41 		}
42 		if (_ch == new_ch) {
43 			return true;
44 		}
45 
46 		// mono to stereo --------
47 		if (new_ch == 2) {
48 			work_size = sample_size * 2;
49 			p_work = new ubyte[](work_size);
50 			if (!p_work) {
51 				return false;
52 			}
53 
54 			switch (_bps) {
55 			case 8:
56 				b = 0;
57 				for (a = 0; a < sample_size; a++) {
58 					p_work[b] = _p_smp[a];
59 					p_work[b + 1] = _p_smp[a];
60 					b += 2;
61 				}
62 				break;
63 			case 16:
64 				b = 0;
65 				for (a = 0; a < sample_size; a += 2) {
66 					p_work[b] = _p_smp[a];
67 					p_work[b + 1] = _p_smp[a + 1];
68 					p_work[b + 2] = _p_smp[a];
69 					p_work[b + 3] = _p_smp[a + 1];
70 					b += 4;
71 				}
72 				break;
73 			default:
74 				break;
75 			}
76 
77 		}  // stereo to mono --------
78 		else {
79 			work_size = sample_size / 2;
80 			p_work = new ubyte[](work_size);
81 			if (!p_work) {
82 				return false;
83 			}
84 
85 			switch (_bps) {
86 			case 8:
87 				b = 0;
88 				for (a = 0; a < sample_size; a += 2) {
89 					temp1 = cast(int) _p_smp[a] + cast(int) _p_smp[a + 1];
90 					p_work[b] = cast(ubyte)(temp1 / 2);
91 					b++;
92 				}
93 				break;
94 			case 16:
95 				b = 0;
96 				for (a = 0; a < sample_size; a += 4) {
97 					temp1 = *(cast(short*)(&_p_smp[a]));
98 					temp2 = *(cast(short*)(&_p_smp[a + 2]));
99 					*cast(short*)(&p_work[b]) = cast(short)((temp1 + temp2) / 2);
100 					b += 2;
101 				}
102 				break;
103 			default:
104 				break;
105 			}
106 		}
107 
108 		// release once.
109 		_p_smp = null;
110 
111 		_p_smp = new ubyte[](work_size);
112 		if (!(_p_smp)) {
113 			return false;
114 		}
115 		_p_smp[0 .. work_size] = p_work[0 .. work_size];
116 
117 		// update param.
118 		_ch = new_ch;
119 
120 		return true;
121 	}
122 
123 	// change bps
124 	bool _Convert_BitPerSample(int new_bps) nothrow @system {
125 		ubyte[] p_work;
126 		int sample_size;
127 		int work_size;
128 		int a, b;
129 		int temp1;
130 
131 		if (!_p_smp) {
132 			return false;
133 		}
134 		if (_bps == new_bps) {
135 			return true;
136 		}
137 
138 		sample_size = (_smp_head + _smp_body + _smp_tail) * _ch * _bps / 8;
139 
140 		switch (new_bps) {
141 			// 16 to 8 --------
142 		case 8:
143 			work_size = sample_size / 2;
144 			p_work = new ubyte[](work_size);
145 			if (!p_work) {
146 				return false;
147 			}
148 			b = 0;
149 			for (a = 0; a < sample_size; a += 2) {
150 				temp1 = *(cast(short*)(&_p_smp[a]));
151 				temp1 = (temp1 / 0x100) + 128;
152 				p_work[b] = cast(ubyte) temp1;
153 				b++;
154 			}
155 			break;
156 			//  8 to 16 --------
157 		case 16:
158 			work_size = sample_size * 2;
159 			p_work = new ubyte[](work_size);
160 			if (!p_work) {
161 				return false;
162 			}
163 			b = 0;
164 			for (a = 0; a < sample_size; a++) {
165 				temp1 = _p_smp[a];
166 				temp1 = (temp1 - 128) * 0x100;
167 				*(cast(short*)(&p_work[b])) = cast(short) temp1;
168 				b += 2;
169 			}
170 			break;
171 
172 		default:
173 			return false;
174 		}
175 
176 		// release once.
177 		_p_smp = null;
178 
179 		_p_smp = new ubyte[](work_size);
180 		if (!(_p_smp)) {
181 			return false;
182 		}
183 		_p_smp[0 .. work_size] = p_work[0 .. work_size];
184 
185 		// update param.
186 		_bps = new_bps;
187 
188 		return true;
189 	}
190 	// sps
191 	bool _Convert_SamplePerSecond(int new_sps) nothrow @system {
192 		bool b_ret = false;
193 		int sample_num;
194 		int work_size;
195 
196 		int head_size, body_size, tail_size;
197 
198 		ubyte[] p1byte_data;
199 		ushort[] p2byte_data;
200 		uint[] p4byte_data;
201 
202 		ubyte[] p1byte_work = null;
203 		ushort[] p2byte_work = null;
204 		uint[] p4byte_work = null;
205 
206 		int a, b;
207 
208 		if (!_p_smp) {
209 			return false;
210 		}
211 		if (_sps == new_sps) {
212 			return true;
213 		}
214 
215 		head_size = _smp_head * _ch * _bps / 8;
216 		body_size = _smp_body * _ch * _bps / 8;
217 		tail_size = _smp_tail * _ch * _bps / 8;
218 
219 		head_size = cast(int)((cast(double) head_size * cast(double) new_sps + cast(double)(_sps) - 1) / _sps);
220 		body_size = cast(int)((cast(double) body_size * cast(double) new_sps + cast(double)(_sps) - 1) / _sps);
221 		tail_size = cast(int)((cast(double) tail_size * cast(double) new_sps + cast(double)(_sps) - 1) / _sps);
222 
223 		work_size = head_size + body_size + tail_size;
224 
225 		// stereo 16bit ========
226 		if (_ch == 2 && _bps == 16) {
227 			_smp_head = head_size / 4;
228 			_smp_body = body_size / 4;
229 			_smp_tail = tail_size / 4;
230 			sample_num = work_size / 4;
231 			work_size = sample_num * 4;
232 			p4byte_data = cast(uint[]) _p_smp;
233 			p4byte_work = new uint[](work_size / uint.sizeof);
234 			if (!p4byte_work) {
235 				goto End;
236 			}
237 			for (a = 0; a < sample_num; a++) {
238 				b = cast(int)(cast(double) a * cast(double)(_sps) / cast(double) new_sps);
239 				p4byte_work[a] = p4byte_data[b];
240 			}
241 		}  // mono 8bit ========
242 		else if (_ch == 1 && _bps == 8) {
243 			_smp_head = head_size / 1;
244 			_smp_body = body_size / 1;
245 			_smp_tail = tail_size / 1;
246 			sample_num = work_size / 1;
247 			work_size = sample_num * 1;
248 			p1byte_data = cast(ubyte[]) _p_smp;
249 			p1byte_work = new ubyte[](work_size);
250 			if (!p1byte_work) {
251 				goto End;
252 			}
253 			for (a = 0; a < sample_num; a++) {
254 				b = cast(int)(cast(double) a * cast(double)(_sps) / cast(double)(new_sps));
255 				p1byte_work[a] = p1byte_data[b];
256 			}
257 		} else // mono 16bit / stereo 8bit ========
258 		{
259 			_smp_head = head_size / 2;
260 			_smp_body = body_size / 2;
261 			_smp_tail = tail_size / 2;
262 			sample_num = work_size / 2;
263 			work_size = sample_num * 2;
264 			p2byte_data = cast(ushort[]) _p_smp;
265 			p2byte_work = new ushort[](work_size / ushort.sizeof);
266 			if (!p2byte_work) {
267 				goto End;
268 			}
269 			for (a = 0; a < sample_num; a++) {
270 				b = cast(int)(cast(double) a * cast(double)(_sps) / cast(double) new_sps);
271 				p2byte_work[a] = p2byte_data[b];
272 			}
273 		}
274 
275 		// release once.
276 		_p_smp = new ubyte[](work_size);
277 		if (!_p_smp) {
278 			goto End;
279 		}
280 
281 		if (p4byte_work) {
282 			_p_smp[0 .. work_size] = (cast(ubyte*)p4byte_work)[0 .. work_size];
283 		} else if (p2byte_work) {
284 			_p_smp[0 .. work_size] = (cast(ubyte*)p2byte_work)[0 .. work_size];
285 		} else if (p1byte_work) {
286 			_p_smp[0 .. work_size] = p1byte_work[0 .. work_size];
287 		} else {
288 			goto End;
289 		}
290 
291 		// update.
292 		_sps = new_sps;
293 
294 		b_ret = true;
295 	End:
296 
297 		if (!b_ret) {
298 			_smp_head = 0;
299 			_smp_body = 0;
300 			_smp_tail = 0;
301 		}
302 
303 		return b_ret;
304 	}
305 
306 public:
307 	 ~this() nothrow @system {
308 		Release();
309 	}
310 
311 	void Create(int ch, int sps, int bps, int sample_num) @system {
312 		Release();
313 
314 		if (bps != 8 && bps != 16) {
315 			throw new PxtoneException("pcm unknown");
316 		}
317 
318 		int size = 0;
319 
320 		_p_smp = null;
321 		_ch = ch;
322 		_sps = sps;
323 		_bps = bps;
324 		_smp_head = 0;
325 		_smp_body = sample_num;
326 		_smp_tail = 0;
327 
328 		// bit / sample is 8 or 16
329 		size = _smp_body * _bps * _ch / 8;
330 
331 		_p_smp = new ubyte[](size);
332 
333 		if (_bps == 8) {
334 			_p_smp[0 .. size] = 128;
335 		} else {
336 			_p_smp[0 .. size] = 0;
337 		}
338 	}
339 
340 	void Release() nothrow @system {
341 		_p_smp = null;
342 		_ch = 0;
343 		_sps = 0;
344 		_bps = 0;
345 		_smp_head = 0;
346 		_smp_body = 0;
347 		_smp_tail = 0;
348 	}
349 
350 	void read(ref pxtnDescriptor doc) @system {
351 		char[16] buf = 0;
352 		uint size = 0;
353 		WAVEFORMATCHUNK format;
354 
355 		_p_smp = null;
356 		scope(failure) {
357 			_p_smp = null;
358 		}
359 
360 		// 'RIFFxxxxWAVEfmt '
361 		doc.r(buf[]);
362 
363 		if (buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' || buf[8] != 'W' || buf[9] != 'A' || buf[10] != 'V' || buf[11] != 'E' || buf[12] != 'f' || buf[13] != 'm' || buf[14] != 't' || buf[15] != ' ') {
364 			throw new PxtoneException("pcm unknown");
365 		}
366 
367 		// read format.
368 		doc.r(size);
369 		doc.r(format);
370 
371 		if (format.formatID != 0x0001) {
372 			throw new PxtoneException("pcm unknown");
373 		}
374 		if (format.ch != 1 && format.ch != 2) {
375 			throw new PxtoneException("pcm unknown");
376 		}
377 		if (format.bps != 8 && format.bps != 16) {
378 			throw new PxtoneException("pcm unknown");
379 		}
380 
381 		// find 'data'
382 		doc.seek(pxtnSEEK.set, 12);
383 	 	// skip 'RIFFxxxxWAVE'
384 
385 		while (1) {
386 			doc.r(buf[0 .. 4]);
387 			doc.r(size);
388 			if (buf[0] == 'd' && buf[1] == 'a' && buf[2] == 't' && buf[3] == 'a') {
389 				break;
390 			}
391 			doc.seek(pxtnSEEK.cur, size);
392 		}
393 
394 		Create(format.ch, format.sps, format.bps, size * 8 / format.bps / format.ch);
395 
396 		doc.r(_p_smp[0 .. size]);
397 	}
398 
399 	void write(ref pxtnDescriptor doc, const char[] pstrLIST) const @system {
400 		if (!_p_smp) {
401 			throw new PxtoneException("_p_smp");
402 		}
403 
404 		WAVEFORMATCHUNK format;
405 		uint riff_size;
406 		uint fact_size; // num sample.
407 		uint list_size; // num list text.
408 		uint isft_size;
409 		uint sample_size;
410 
411 		bool bText;
412 
413 		char[4] tag_RIFF = ['R', 'I', 'F', 'F'];
414 		char[4] tag_WAVE = ['W', 'A', 'V', 'E'];
415 		char[8] tag_fmt_ = ['f', 'm', 't', ' ', 0x12, 0, 0, 0];
416 		char[8] tag_fact = ['f', 'a', 'c', 't', 0x04, 0, 0, 0];
417 		char[4] tag_data = ['d', 'a', 't', 'a'];
418 		char[4] tag_LIST = ['L', 'I', 'S', 'T'];
419 		char[8] tag_INFO = ['I', 'N', 'F', 'O', 'I', 'S', 'F', 'T'];
420 
421 		if (pstrLIST && pstrLIST.length) {
422 			bText = true;
423 		} else {
424 			bText = false;
425 		}
426 
427 		sample_size = (_smp_head + _smp_body + _smp_tail) * _ch * _bps / 8;
428 
429 		format.formatID = 0x0001; // PCM
430 		format.ch = cast(ushort) _ch;
431 		format.sps = cast(uint) _sps;
432 		format.bps = cast(ushort) _bps;
433 		format.byte_per_sec = cast(uint)(_sps * _bps * _ch / 8);
434 		format.block_size = cast(ushort)(_bps * _ch / 8);
435 		format.ext = 0;
436 
437 		fact_size = (_smp_head + _smp_body + _smp_tail);
438 		riff_size = sample_size;
439 		riff_size += 4; // 'WAVE'
440 		riff_size += 26; // 'fmt '
441 		riff_size += 12; // 'fact'
442 		riff_size += 8; // 'data'
443 
444 		if (bText) {
445 			isft_size = cast(uint) pstrLIST.length;
446 			list_size = 4 + 4 + 4 + isft_size; // "INFO" + "ISFT" + size + ver_Text;
447 			riff_size += 8 + list_size; // 'LIST'
448 		} else {
449 			isft_size = 0;
450 			list_size = 0;
451 		}
452 
453 		// open file..
454 
455 		doc.w_asfile(tag_RIFF);
456 		doc.w_asfile(riff_size);
457 		doc.w_asfile(tag_WAVE);
458 		doc.w_asfile(tag_fmt_);
459 		doc.w_asfile(format);
460 
461 		if (bText) {
462 			doc.w_asfile(tag_LIST);
463 			doc.w_asfile(list_size);
464 			doc.w_asfile(tag_INFO);
465 			doc.w_asfile(isft_size);
466 			doc.w_asfile(pstrLIST);
467 		}
468 
469 		doc.w_asfile(tag_fact);
470 		doc.w_asfile(fact_size);
471 		doc.w_asfile(tag_data);
472 		doc.w_asfile(sample_size);
473 		doc.w_asfile(_p_smp);
474 	}
475 
476 	// convert..
477 	void Convert(int new_ch, int new_sps, int new_bps) @system {
478 		if (!_Convert_ChannelNum(new_ch)) {
479 			throw new PxtoneException("_Convert_ChannelNum");
480 		}
481 		if (!_Convert_BitPerSample(new_bps)) {
482 			throw new PxtoneException("_Convert_BitPerSample");
483 		}
484 		if (!_Convert_SamplePerSecond(new_sps)) {
485 			throw new PxtoneException("_Convert_SamplePerSecond");
486 		}
487 	}
488 
489 	bool Convert_Volume(float v) nothrow @safe {
490 		if (!_p_smp) {
491 			return false;
492 		}
493 
494 		int sample_num = (_smp_head + _smp_body + _smp_tail) * _ch;
495 
496 		switch (_bps) {
497 		case 8: {
498 				ubyte[] p8 = _p_smp;
499 				for (int i = 0; i < sample_num; i++) {
500 					p8[0] = cast(ubyte)(((cast(float)(p8[0]) - 128) * v) + 128);
501 					p8 = p8[1 .. $];
502 				}
503 				break;
504 			}
505 		case 16: {
506 				short[] p16 = cast(short[]) _p_smp;
507 				for (int i = 0; i < sample_num; i++) {
508 					p16[0] = cast(short)(cast(float)p16[0] * v);
509 					p16 = p16[1 .. $];
510 				}
511 				break;
512 			}
513 		default:
514 			return false;
515 		}
516 		return true;
517 	}
518 
519 	void Copy(ref pxtnPulse_PCM p_dst) const @system {
520 		if (!_p_smp) {
521 			p_dst.Release();
522 			return;
523 		}
524 		p_dst.Create(_ch, _sps, _bps, _smp_body);
525 		const size = (_smp_head + _smp_body + _smp_tail) * _ch * _bps / 8;
526 		p_dst._p_smp[0 .. size] =_p_smp[0 .. size];
527 	}
528 
529 	bool Copy_(ref pxtnPulse_PCM p_dst, int start, int end) const @system {
530 		int size, offset;
531 
532 		if (_smp_head || _smp_tail) {
533 			return false;
534 		}
535 		if (!_p_smp) {
536 			p_dst.Release();
537 			return true;
538 		}
539 
540 		size = (end - start) * _ch * _bps / 8;
541 		offset = start * _ch * _bps / 8;
542 
543 		p_dst.Create(_ch, _sps, _bps, end - start);
544 
545 		p_dst._p_smp[0 .. size] = _p_smp[offset .. offset + size];
546 
547 		return true;
548 	}
549 
550 	void[] Devolve_SamplingBuffer() nothrow @safe {
551 		void[] p = _p_smp;
552 		_p_smp = null;
553 		return p;
554 	}
555 
556 	float get_sec() const nothrow @safe {
557 		return cast(float)(_smp_body + _smp_head + _smp_tail) / cast(float) _sps;
558 	}
559 
560 	int get_ch() const nothrow @safe {
561 		return _ch;
562 	}
563 
564 	int get_bps() const nothrow @safe {
565 		return _bps;
566 	}
567 
568 	int get_sps() const nothrow @safe {
569 		return _sps;
570 	}
571 
572 	int get_smp_body() const nothrow @safe {
573 		return _smp_body;
574 	}
575 
576 	int get_smp_head() const nothrow @safe {
577 		return _smp_head;
578 	}
579 
580 	int get_smp_tail() const nothrow @safe {
581 		return _smp_tail;
582 	}
583 
584 	int get_buf_size() const nothrow @safe {
585 		return (_smp_head + _smp_body + _smp_tail) * _ch * _bps / 8;
586 	}
587 
588 	inout(ubyte)[] get_p_buf() inout nothrow @safe {
589 		return _p_smp;
590 	}
591 }