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 }