1 module pxtone.woice; 2 // '12/03/03 pxtnWoice. 3 4 import pxtone.pxtn; 5 6 import pxtone.descriptor; 7 import pxtone.error; 8 import pxtone.evelist; 9 import pxtone.pulse.noise; 10 import pxtone.pulse.noisebuilder; 11 import pxtone.pulse.oscillator; 12 import pxtone.pulse.pcm; 13 import pxtone.pulse.oggv; 14 import pxtone.woiceptv; 15 16 enum pxtnMAX_TUNEWOICENAME = 16; // fixture. 17 18 enum pxtnMAX_UNITCONTROLVOICE = 2; // max-woice per unit 19 20 enum pxtnBUFSIZE_TIMEPAN = 0x40; 21 enum pxtnBITPERSAMPLE = 16; 22 23 enum PTV_VOICEFLAG_WAVELOOP = 0x00000001; 24 enum PTV_VOICEFLAG_SMOOTH = 0x00000002; 25 enum PTV_VOICEFLAG_BEATFIT = 0x00000004; 26 enum PTV_VOICEFLAG_UNCOVERED = 0xfffffff8; 27 28 enum PTV_DATAFLAG_WAVE = 0x00000001; 29 enum PTV_DATAFLAG_ENVELOPE = 0x00000002; 30 enum PTV_DATAFLAG_UNCOVERED = 0xfffffffc; 31 32 immutable _code = "PTVOICE-"; 33 34 enum pxtnWOICETYPE { 35 None = 0, 36 PCM, 37 PTV, 38 PTN, 39 OGGV, 40 } 41 42 enum pxtnVOICETYPE { 43 Coodinate = 0, 44 Overtone, 45 Noise, 46 Sampling, 47 OggVorbis, 48 } 49 50 struct pxtnVOICEINSTANCE { 51 int smp_head_w; 52 int smp_body_w; 53 int smp_tail_w; 54 ubyte[] p_smp_w; 55 56 ubyte[] p_env; 57 int env_size; 58 int env_release; 59 } 60 61 struct pxtnVOICEENVELOPE { 62 int fps; 63 int head_num; 64 int body_num; 65 int tail_num; 66 pxtnPOINT[] points; 67 } 68 69 struct pxtnVOICEWAVE { 70 int num; 71 int reso; // COODINATERESOLUTION 72 pxtnPOINT[] points; 73 } 74 75 struct pxtnVOICEUNIT { 76 int basic_key; 77 int volume; 78 int pan; 79 float tuning; 80 uint voice_flags; 81 uint data_flags; 82 83 pxtnVOICETYPE type; 84 pxtnPulse_PCM p_pcm; 85 pxtnPulse_Noise p_ptn; 86 version (pxINCLUDE_OGGVORBIS) { 87 pxtnPulse_Oggv p_oggv; 88 } 89 90 pxtnVOICEWAVE wave; 91 pxtnVOICEENVELOPE envelope; 92 } 93 94 struct pxtnVOICETONE { 95 double smp_pos; 96 float offset_freq; 97 int env_volume; 98 int life_count; 99 int on_count; 100 101 int smp_count; 102 int env_start; 103 int env_pos; 104 int env_release_clock; 105 106 int smooth_volume; 107 } 108 109 private void _Voice_Release(pxtnVOICEUNIT* p_vc, pxtnVOICEINSTANCE* p_vi) nothrow @system { 110 if (p_vc) { 111 p_vc.envelope.points = null; 112 p_vc.envelope = pxtnVOICEENVELOPE.init; 113 p_vc.wave.points = null; 114 p_vc.wave = pxtnVOICEWAVE.init; 115 } 116 if (p_vi) { 117 p_vi.p_env = null; 118 p_vi.p_smp_w = null; 119 *p_vi = pxtnVOICEINSTANCE.init; 120 } 121 } 122 123 void _UpdateWavePTV(pxtnVOICEUNIT* p_vc, pxtnVOICEINSTANCE* p_vi, int ch, int sps, int bps) nothrow @system { 124 double work, osc; 125 int long_; 126 int[2] pan_volume = [64, 64]; 127 bool b_ovt; 128 129 pxtnPulse_Oscillator osci; 130 131 if (ch == 2) { 132 if (p_vc.pan > 64) { 133 pan_volume[0] = (128 - p_vc.pan); 134 } 135 if (p_vc.pan < 64) { 136 pan_volume[1] = (p_vc.pan); 137 } 138 } 139 140 osci.ReadyGetSample(p_vc.wave.points, p_vc.wave.num, p_vc.volume, p_vi.smp_body_w, p_vc.wave.reso); 141 142 if (p_vc.type == pxtnVOICETYPE.Overtone) { 143 b_ovt = true; 144 } else { 145 b_ovt = false; 146 } 147 148 // 8bit 149 if (bps == 8) { 150 ubyte* p = cast(ubyte*) p_vi.p_smp_w; 151 for (int s = 0; s < p_vi.smp_body_w; s++) { 152 if (b_ovt) { 153 osc = osci.GetOneSample_Overtone(s); 154 } else { 155 osc = osci.GetOneSample_Coodinate(s); 156 } 157 for (int c = 0; c < ch; c++) { 158 work = osc * pan_volume[c] / 64; 159 if (work > 1.0) { 160 work = 1.0; 161 } 162 if (work < -1.0) { 163 work = -1.0; 164 } 165 long_ = cast(int)(work * 127); 166 p[s * ch + c] = cast(ubyte)(long_ + 128); 167 } 168 } 169 170 // 16bit 171 } else { 172 short* p = cast(short*) p_vi.p_smp_w; 173 for (int s = 0; s < p_vi.smp_body_w; s++) { 174 if (b_ovt) { 175 osc = osci.GetOneSample_Overtone(s); 176 } else { 177 osc = osci.GetOneSample_Coodinate(s); 178 } 179 for (int c = 0; c < ch; c++) { 180 work = osc * pan_volume[c] / 64; 181 if (work > 1.0) { 182 work = 1.0; 183 } 184 if (work < -1.0) { 185 work = -1.0; 186 } 187 long_ = cast(int)(work * 32767); 188 p[s * ch + c] = cast(short) long_; 189 } 190 } 191 } 192 } 193 194 // 24byte ================= 195 struct _MATERIALSTRUCT_PCM { 196 ushort x3x_unit_no; 197 ushort basic_key; 198 uint voice_flags; 199 ushort ch; 200 ushort bps; 201 uint sps; 202 float tuning = 0.0; 203 uint data_size; 204 } 205 206 ///////////// 207 // matePTN 208 ///////////// 209 210 // 16byte ================= 211 struct _MATERIALSTRUCT_PTN { 212 ushort x3x_unit_no; 213 ushort basic_key; 214 uint voice_flags; 215 float tuning = 0.0; 216 int rrr; // 0: -v.0.9.2.3 217 // 1: v.0.9.2.4- 218 } 219 220 ///////////////// 221 // matePTV 222 ///////////////// 223 224 // 24byte ================= 225 struct _MATERIALSTRUCT_PTV { 226 ushort x3x_unit_no; 227 ushort rrr; 228 float x3x_tuning = 0.0; 229 int size; 230 } 231 232 ////////////////////// 233 // mateOGGV 234 ////////////////////// 235 236 // 16byte ================= 237 struct _MATERIALSTRUCT_OGGV { 238 ushort xxx; //ch; 239 ushort basic_key; 240 uint voice_flags; 241 float tuning = 0.0; 242 } 243 244 //////////////////////// 245 // publics.. 246 //////////////////////// 247 248 struct pxtnWoice { 249 private: 250 int _voice_num; 251 252 char[pxtnMAX_TUNEWOICENAME + 1] _name_buf; 253 uint _name_size; 254 255 pxtnWOICETYPE _type = pxtnWOICETYPE.None; 256 pxtnVOICEUNIT[] _voices; 257 pxtnVOICEINSTANCE[] _voinsts; 258 259 float _x3x_tuning; 260 int _x3x_basic_key; // tuning old-fmt when key-event 261 262 public: 263 264 ~this() nothrow @system { 265 Voice_Release(); 266 } 267 268 int get_voice_num() const nothrow @safe { 269 return _voice_num; 270 } 271 272 float get_x3x_tuning() const nothrow @safe { 273 return _x3x_tuning; 274 } 275 276 int get_x3x_basic_key() const nothrow @safe { 277 return _x3x_basic_key; 278 } 279 280 pxtnWOICETYPE get_type() const nothrow @safe { 281 return _type; 282 } 283 284 inout(pxtnVOICEUNIT)* get_voice(int idx) inout nothrow @safe { 285 if (idx < 0 || idx >= _voice_num) { 286 return null; 287 } 288 return &_voices[idx]; 289 } 290 291 const(pxtnVOICEINSTANCE)* get_instance(int idx) const nothrow @safe { 292 if (idx < 0 || idx >= _voice_num) { 293 return null; 294 } 295 return &_voinsts[idx]; 296 } 297 298 bool set_name_buf(const(char)[] name) nothrow @safe { 299 if (!name || name.length < 0 || name.length > pxtnMAX_TUNEWOICENAME) { 300 return false; 301 } 302 _name_buf[] = 0; 303 _name_size = cast(uint)name.length; 304 if (name.length) { 305 _name_buf[0 .. name.length] = name; 306 } 307 return true; 308 } 309 310 const(char)[] get_name_buf() const return nothrow @safe { 311 return _name_buf[0 .. _name_size]; 312 } 313 314 bool is_name_buf() const nothrow @safe { 315 if (_name_size > 0) { 316 return true; 317 } 318 return false; 319 } 320 321 void Voice_Allocate(int voice_num) @system { 322 Voice_Release(); 323 324 scope(failure) { 325 Voice_Release(); 326 } 327 _voices = new pxtnVOICEUNIT[](voice_num); 328 _voinsts = new pxtnVOICEINSTANCE[](voice_num); 329 _voice_num = voice_num; 330 331 for (int i = 0; i < voice_num; i++) { 332 pxtnVOICEUNIT* p_vc = &_voices[i]; 333 p_vc.basic_key = EVENTDEFAULT_BASICKEY; 334 p_vc.volume = 128; 335 p_vc.pan = 64; 336 p_vc.tuning = 1.0f; 337 p_vc.voice_flags = PTV_VOICEFLAG_SMOOTH; 338 p_vc.data_flags = PTV_DATAFLAG_WAVE; 339 p_vc.p_pcm = pxtnPulse_PCM.init; 340 p_vc.p_ptn = pxtnPulse_Noise.init; 341 version (pxINCLUDE_OGGVORBIS) { 342 p_vc.p_oggv = pxtnPulse_Oggv.init; 343 } 344 p_vc.envelope = pxtnVOICEENVELOPE.init; 345 } 346 } 347 348 void Voice_Release() nothrow @system { 349 for (int v = 0; v < _voice_num; v++) { 350 _Voice_Release(&_voices[v], &_voinsts[v]); 351 } 352 _voices = null; 353 _voinsts = null; 354 _voice_num = 0; 355 } 356 357 bool Copy(pxtnWoice* p_dst) const @system { 358 bool b_ret = false; 359 int v, num; 360 size_t size; 361 const(pxtnVOICEUNIT)* p_vc1 = null; 362 pxtnVOICEUNIT* p_vc2 = null; 363 364 p_dst.Voice_Allocate(_voice_num); 365 scope(failure) { 366 p_dst.Voice_Release(); 367 } 368 369 p_dst._type = _type; 370 371 p_dst._name_buf = _name_buf; 372 373 for (v = 0; v < _voice_num; v++) { 374 p_vc1 = &_voices[v]; 375 p_vc2 = &p_dst._voices[v]; 376 377 p_vc2.tuning = p_vc1.tuning; 378 p_vc2.data_flags = p_vc1.data_flags; 379 p_vc2.basic_key = p_vc1.basic_key; 380 p_vc2.pan = p_vc1.pan; 381 p_vc2.type = p_vc1.type; 382 p_vc2.voice_flags = p_vc1.voice_flags; 383 p_vc2.volume = p_vc1.volume; 384 385 // envelope 386 p_vc2.envelope.body_num = p_vc1.envelope.body_num; 387 p_vc2.envelope.fps = p_vc1.envelope.fps; 388 p_vc2.envelope.head_num = p_vc1.envelope.head_num; 389 p_vc2.envelope.tail_num = p_vc1.envelope.tail_num; 390 num = p_vc2.envelope.head_num + p_vc2.envelope.body_num + p_vc2.envelope.tail_num; 391 size = pxtnPOINT.sizeof * num; 392 p_vc2.envelope.points = new pxtnPOINT[](size / pxtnPOINT.sizeof); 393 if (!p_vc2.envelope.points) { 394 goto End; 395 } 396 p_vc2.envelope.points[0 .. size] = p_vc1.envelope.points[0 .. size]; 397 398 // wave 399 p_vc2.wave.num = p_vc1.wave.num; 400 p_vc2.wave.reso = p_vc1.wave.reso; 401 size = pxtnPOINT.sizeof * p_vc2.wave.num; 402 p_vc2.wave.points = new pxtnPOINT[](size / pxtnPOINT.sizeof); 403 if (!p_vc2.wave.points) { 404 goto End; 405 } 406 p_vc2.wave.points[0 .. size] = p_vc1.wave.points[0 .. size]; 407 408 p_vc1.p_pcm.Copy(p_vc2.p_pcm); 409 if (!p_vc1.p_ptn.Copy(p_vc2.p_ptn)) { 410 goto End; 411 } 412 version (pxINCLUDE_OGGVORBIS) { 413 if (!p_vc1.p_oggv.Copy(p_vc2.p_oggv)) { 414 goto End; 415 } 416 } 417 } 418 419 b_ret = true; 420 End: 421 if (!b_ret) { 422 p_dst.Voice_Release(); 423 } 424 425 return b_ret; 426 } 427 428 void Slim() nothrow @system { 429 for (int i = _voice_num - 1; i >= 0; i--) { 430 bool b_remove = false; 431 432 if (!_voices[i].volume) { 433 b_remove = true; 434 } 435 436 if (_voices[i].type == pxtnVOICETYPE.Coodinate && _voices[i].wave.num <= 1) { 437 b_remove = true; 438 } 439 440 if (b_remove) { 441 _Voice_Release(&_voices[i], &_voinsts[i]); 442 _voice_num--; 443 for (int j = i; j < _voice_num; j++) { 444 _voices[j] = _voices[j + 1]; 445 } 446 _voices[_voice_num] = pxtnVOICEUNIT.init; 447 } 448 } 449 } 450 451 void read(ref pxtnDescriptor desc, pxtnWOICETYPE type) @system { 452 switch (type) { 453 // PCM 454 case pxtnWOICETYPE.PCM: { 455 pxtnVOICEUNIT* p_vc; 456 Voice_Allocate(1); 457 p_vc = &_voices[0]; 458 p_vc.type = pxtnVOICETYPE.Sampling; 459 p_vc.p_pcm.read(desc); 460 // if under 0.005 sec, set LOOP. 461 if (p_vc.p_pcm.get_sec() < 0.005f) { 462 p_vc.voice_flags |= PTV_VOICEFLAG_WAVELOOP; 463 } else { 464 p_vc.voice_flags &= ~PTV_VOICEFLAG_WAVELOOP; 465 } 466 _type = pxtnWOICETYPE.PCM; 467 } 468 break; 469 470 // PTV 471 case pxtnWOICETYPE.PTV: { 472 PTV_Read(desc); 473 } 474 break; 475 476 // PTN 477 case pxtnWOICETYPE.PTN: 478 Voice_Allocate(1); 479 { 480 pxtnVOICEUNIT* p_vc = &_voices[0]; 481 p_vc.type = pxtnVOICETYPE.Noise; 482 p_vc.p_ptn.read(desc); 483 _type = pxtnWOICETYPE.PTN; 484 } 485 break; 486 487 // OGGV 488 case pxtnWOICETYPE.OGGV: 489 version (pxINCLUDE_OGGVORBIS) { 490 Voice_Allocate(1); 491 { 492 pxtnVOICEUNIT* p_vc; 493 p_vc = &_voices[0]; 494 p_vc.type = pxtnVOICETYPE.OggVorbis; 495 p_vc.p_oggv.ogg_read(desc); 496 _type = pxtnWOICETYPE.OGGV; 497 } 498 break; 499 } else { 500 throw new PxtoneException("Ogg Vorbis support is required"); 501 } 502 503 default: 504 throw new PxtoneException("Unknown woice type"); 505 } 506 } 507 508 bool PTV_Write(ref pxtnDescriptor p_doc, int* p_total) const @system { 509 bool b_ret = false; 510 const(pxtnVOICEUNIT)* p_vc = null; 511 uint work = 0; 512 int v = 0; 513 int total = 0; 514 515 p_doc.w_asfile(_code); 516 p_doc.w_asfile(_version); 517 p_doc.w_asfile(total); 518 519 work = 0; 520 521 // p_ptv. (5) 522 p_doc.v_w_asfile(work, total); 523 p_doc.v_w_asfile(work, total); 524 p_doc.v_w_asfile(work, total); 525 p_doc.v_w_asfile(_voice_num, total); 526 527 for (v = 0; v < _voice_num; v++) { 528 // p_ptvv. (9) 529 p_vc = &_voices[v]; 530 if (!p_vc) { 531 goto End; 532 } 533 534 p_doc.v_w_asfile(p_vc.basic_key, total); 535 p_doc.v_w_asfile(p_vc.volume, total); 536 p_doc.v_w_asfile(p_vc.pan, total); 537 work = *(cast(uint*)&p_vc.tuning); 538 p_doc.v_w_asfile(work, total); 539 p_doc.v_w_asfile(p_vc.voice_flags, total); 540 p_doc.v_w_asfile(p_vc.data_flags, total); 541 542 if (p_vc.data_flags & PTV_DATAFLAG_WAVE) { 543 _Write_Wave(p_doc, p_vc, total); 544 } 545 if (p_vc.data_flags & PTV_DATAFLAG_ENVELOPE) { 546 _Write_Envelope(p_doc, p_vc, total); 547 } 548 } 549 550 // total size 551 p_doc.seek(pxtnSEEK.cur, -(total + 4)); 552 p_doc.w_asfile(total); 553 p_doc.seek(pxtnSEEK.cur, total); 554 555 if (p_total) { 556 *p_total = 16 + total; 557 } 558 b_ret = true; 559 End: 560 561 return b_ret; 562 } 563 564 void PTV_Read(ref pxtnDescriptor p_doc) @system { 565 pxtnVOICEUNIT* p_vc = null; 566 ubyte[8] code = 0; 567 int version_ = 0; 568 int work1 = 0; 569 int work2 = 0; 570 int total = 0; 571 int num = 0; 572 573 p_doc.r(code[]); 574 p_doc.r(version_); 575 if (code[0 .. 8] != _code) { 576 throw new PxtoneException("inv code"); 577 } 578 p_doc.r(total); 579 if (version_ > _version) { 580 throw new PxtoneException("fmt new"); 581 } 582 583 // p_ptv. (5) 584 p_doc.v_r(_x3x_basic_key); 585 p_doc.v_r(work1); 586 p_doc.v_r(work2); 587 if (work1 || work2) { 588 throw new PxtoneException("fmt unknown"); 589 } 590 p_doc.v_r(num); 591 Voice_Allocate(num); 592 593 for (int v = 0; v < _voice_num; v++) { 594 // p_ptvv. (8) 595 p_vc = &_voices[v]; 596 if (!p_vc) { 597 throw new PxtoneException("FATAL"); 598 } 599 p_doc.v_r(p_vc.basic_key); 600 p_doc.v_r(p_vc.volume); 601 p_doc.v_r(p_vc.pan); 602 p_doc.v_r(work1); 603 p_vc.tuning = *(cast(float*)&work1); 604 p_doc.v_r(*cast(int*)&p_vc.voice_flags); 605 p_doc.v_r(*cast(int*)&p_vc.data_flags); 606 607 // no support. 608 if (p_vc.voice_flags & PTV_VOICEFLAG_UNCOVERED) { 609 throw new PxtoneException("fmt unknown"); 610 } 611 if (p_vc.data_flags & PTV_DATAFLAG_UNCOVERED) { 612 throw new PxtoneException("fmt unknown"); 613 } 614 if (p_vc.data_flags & PTV_DATAFLAG_WAVE) { 615 _Read_Wave(p_doc, p_vc); 616 } 617 if (p_vc.data_flags & PTV_DATAFLAG_ENVELOPE) { 618 _Read_Envelope(p_doc, p_vc); 619 } 620 } 621 _type = pxtnWOICETYPE.PTV; 622 } 623 624 void io_matePCM_w(ref pxtnDescriptor p_doc) const @system { 625 const pxtnPulse_PCM* p_pcm = &_voices[0].p_pcm; 626 const(pxtnVOICEUNIT)* p_vc = &_voices[0]; 627 _MATERIALSTRUCT_PCM pcm; 628 629 pcm.sps = cast(uint) p_pcm.get_sps(); 630 pcm.bps = cast(ushort) p_pcm.get_bps(); 631 pcm.ch = cast(ushort) p_pcm.get_ch(); 632 pcm.data_size = cast(uint) p_pcm.get_buf_size(); 633 pcm.x3x_unit_no = cast(ushort) 0; 634 pcm.tuning = p_vc.tuning; 635 pcm.voice_flags = p_vc.voice_flags; 636 pcm.basic_key = cast(ushort) p_vc.basic_key; 637 638 uint size = cast(uint)(_MATERIALSTRUCT_PCM.sizeof + pcm.data_size); 639 p_doc.w_asfile(size); 640 p_doc.w_asfile(pcm); 641 p_doc.w_asfile(p_pcm.get_p_buf()); 642 } 643 644 void io_matePCM_r(ref pxtnDescriptor p_doc) @system { 645 _MATERIALSTRUCT_PCM pcm; 646 int size = 0; 647 648 p_doc.r(size); 649 p_doc.r(pcm); 650 651 if ((cast(int) pcm.voice_flags) & PTV_VOICEFLAG_UNCOVERED) { 652 throw new PxtoneException("fmt unknown"); 653 } 654 655 Voice_Allocate(1); 656 scope(failure) { 657 Voice_Release(); 658 } 659 660 { 661 pxtnVOICEUNIT* p_vc = &_voices[0]; 662 663 p_vc.type = pxtnVOICETYPE.Sampling; 664 665 p_vc.p_pcm.Create(pcm.ch, pcm.sps, pcm.bps, pcm.data_size / (pcm.bps / 8 * pcm.ch)); 666 p_doc.r(p_vc.p_pcm.get_p_buf()[0 .. pcm.data_size]); 667 _type = pxtnWOICETYPE.PCM; 668 669 p_vc.voice_flags = pcm.voice_flags; 670 p_vc.basic_key = pcm.basic_key; 671 p_vc.tuning = pcm.tuning; 672 _x3x_basic_key = pcm.basic_key; 673 _x3x_tuning = 0; 674 } 675 } 676 677 void io_matePTN_w(ref pxtnDescriptor p_doc) const @system { 678 _MATERIALSTRUCT_PTN ptn; 679 const(pxtnVOICEUNIT)* p_vc; 680 int size = 0; 681 682 // ptv ------------------------- 683 ptn.x3x_unit_no = cast(ushort) 0; 684 685 p_vc = &_voices[0]; 686 ptn.tuning = p_vc.tuning; 687 ptn.voice_flags = p_vc.voice_flags; 688 ptn.basic_key = cast(ushort) p_vc.basic_key; 689 ptn.rrr = 1; 690 691 // pre 692 p_doc.w_asfile(size); 693 p_doc.w_asfile(ptn); 694 size += _MATERIALSTRUCT_PTN.sizeof; 695 p_vc.p_ptn.write(p_doc, &size); 696 p_doc.seek(pxtnSEEK.cur, cast(int)(-size - int.sizeof)); 697 p_doc.w_asfile(size); 698 p_doc.seek(pxtnSEEK.cur, size); 699 } 700 701 void io_matePTN_r(ref pxtnDescriptor p_doc) @system { 702 _MATERIALSTRUCT_PTN ptn; 703 int size = 0; 704 705 scope(failure) { 706 Voice_Release(); 707 } 708 p_doc.r(size); 709 p_doc.r(ptn); 710 711 if (ptn.rrr > 1) { 712 throw new PxtoneException("fmt unknown"); 713 } else if (ptn.rrr < 0) { 714 throw new PxtoneException("fmt unknown"); 715 } 716 717 Voice_Allocate(1); 718 719 { 720 pxtnVOICEUNIT* p_vc = &_voices[0]; 721 722 p_vc.type = pxtnVOICETYPE.Noise; 723 p_vc.p_ptn.read(p_doc); 724 _type = pxtnWOICETYPE.PTN; 725 p_vc.voice_flags = ptn.voice_flags; 726 p_vc.basic_key = ptn.basic_key; 727 p_vc.tuning = ptn.tuning; 728 } 729 730 _x3x_basic_key = ptn.basic_key; 731 _x3x_tuning = 0; 732 } 733 734 bool io_matePTV_w(ref pxtnDescriptor p_doc) const @system { 735 _MATERIALSTRUCT_PTV ptv; 736 int head_size = _MATERIALSTRUCT_PTV.sizeof + int.sizeof; 737 int size = 0; 738 739 // ptv ------------------------- 740 ptv.x3x_unit_no = cast(ushort) 0; 741 ptv.x3x_tuning = 0; //1.0f;//p_w.tuning; 742 ptv.size = 0; 743 744 // pre write 745 p_doc.w_asfile(size); 746 p_doc.w_asfile(ptv); 747 if (!PTV_Write(p_doc, &ptv.size)) { 748 return false; 749 } 750 751 p_doc.seek(pxtnSEEK.cur, -(ptv.size + head_size)); 752 753 size = cast(int)(ptv.size + _MATERIALSTRUCT_PTV.sizeof); 754 p_doc.w_asfile(size); 755 p_doc.w_asfile(ptv); 756 757 p_doc.seek(pxtnSEEK.cur, ptv.size); 758 759 return true; 760 } 761 762 void io_matePTV_r(ref pxtnDescriptor p_doc) @system { 763 _MATERIALSTRUCT_PTV ptv; 764 int size = 0; 765 766 p_doc.r(size); 767 p_doc.r(ptv); 768 if (ptv.rrr) { 769 throw new PxtoneException("fmt unknown"); 770 } 771 PTV_Read(p_doc); 772 773 if (ptv.x3x_tuning != 1.0) { 774 _x3x_tuning = ptv.x3x_tuning; 775 } else { 776 _x3x_tuning = 0; 777 } 778 } 779 780 version (pxINCLUDE_OGGVORBIS) { 781 bool io_mateOGGV_w(ref pxtnDescriptor p_doc) const @system { 782 if (!_voices) { 783 return false; 784 } 785 786 _MATERIALSTRUCT_OGGV mate; 787 const(pxtnVOICEUNIT)* p_vc = &_voices[0]; 788 789 int oggv_size = p_vc.p_oggv.GetSize(); 790 791 mate.tuning = p_vc.tuning; 792 mate.voice_flags = p_vc.voice_flags; 793 mate.basic_key = cast(ushort) p_vc.basic_key; 794 795 uint size = cast(uint)(_MATERIALSTRUCT_OGGV.sizeof + oggv_size); 796 p_doc.w_asfile(size); 797 p_doc.w_asfile(mate); 798 p_vc.p_oggv.pxtn_write(p_doc); 799 800 return true; 801 } 802 803 void io_mateOGGV_r(ref pxtnDescriptor p_doc) @system { 804 _MATERIALSTRUCT_OGGV mate; 805 int size = 0; 806 807 p_doc.r(size); 808 p_doc.r(mate); 809 810 if ((cast(int) mate.voice_flags) & PTV_VOICEFLAG_UNCOVERED) { 811 throw new PxtoneException("fmt unknown"); 812 } 813 814 Voice_Allocate(1); 815 scope(failure) { 816 Voice_Release(); 817 } 818 819 { 820 pxtnVOICEUNIT* p_vc = &_voices[0]; 821 p_vc.type = pxtnVOICETYPE.OggVorbis; 822 823 p_vc.p_oggv.pxtn_read(p_doc); 824 825 p_vc.voice_flags = mate.voice_flags; 826 p_vc.basic_key = mate.basic_key; 827 p_vc.tuning = mate.tuning; 828 } 829 830 _x3x_basic_key = mate.basic_key; 831 _x3x_tuning = 0; 832 _type = pxtnWOICETYPE.OGGV; 833 } 834 } 835 836 void Tone_Ready_sample(const pxtnPulse_NoiseBuilder ptn_bldr) @system { 837 pxtnVOICEINSTANCE* p_vi = null; 838 pxtnVOICEUNIT* p_vc = null; 839 pxtnPulse_PCM pcm_work; 840 841 int ch = 2; 842 int sps = 44100; 843 int bps = 16; 844 845 for (int v = 0; v < _voice_num; v++) { 846 p_vi = &_voinsts[v]; 847 p_vi.p_smp_w = null; 848 p_vi.smp_head_w = 0; 849 p_vi.smp_body_w = 0; 850 p_vi.smp_tail_w = 0; 851 } 852 scope (failure) { 853 for (int v = 0; v < _voice_num; v++) { 854 p_vi = &_voinsts[v]; 855 p_vi.p_smp_w = null; 856 p_vi.smp_head_w = 0; 857 p_vi.smp_body_w = 0; 858 p_vi.smp_tail_w = 0; 859 } 860 } 861 862 for (int v = 0; v < _voice_num; v++) { 863 p_vi = &_voinsts[v]; 864 p_vc = &_voices[v]; 865 866 switch (p_vc.type) { 867 case pxtnVOICETYPE.OggVorbis: 868 869 version (pxINCLUDE_OGGVORBIS) { 870 p_vc.p_oggv.Decode(&pcm_work); 871 pcm_work.Convert(ch, sps, bps); 872 p_vi.smp_head_w = pcm_work.get_smp_head(); 873 p_vi.smp_body_w = pcm_work.get_smp_body(); 874 p_vi.smp_tail_w = pcm_work.get_smp_tail(); 875 p_vi.p_smp_w = cast(ubyte[]) pcm_work.Devolve_SamplingBuffer(); 876 break; 877 } else { 878 throw new PxtoneException("Ogg Vorbis support is required"); 879 } 880 881 case pxtnVOICETYPE.Sampling: 882 883 p_vc.p_pcm.Copy(pcm_work); 884 pcm_work.Convert(ch, sps, bps); 885 p_vi.smp_head_w = pcm_work.get_smp_head(); 886 p_vi.smp_body_w = pcm_work.get_smp_body(); 887 p_vi.smp_tail_w = pcm_work.get_smp_tail(); 888 p_vi.p_smp_w = cast(ubyte[]) pcm_work.Devolve_SamplingBuffer(); 889 break; 890 891 case pxtnVOICETYPE.Overtone: 892 case pxtnVOICETYPE.Coodinate: { 893 p_vi.smp_body_w = 400; 894 int size = p_vi.smp_body_w * ch * bps / 8; 895 p_vi.p_smp_w = new ubyte[](size); 896 p_vi.p_smp_w[0 .. size] = 0x00; 897 _UpdateWavePTV(p_vc, p_vi, ch, sps, bps); 898 break; 899 } 900 901 case pxtnVOICETYPE.Noise: { 902 pxtnPulse_PCM p_pcm = ptn_bldr.BuildNoise(p_vc.p_ptn, ch, sps, bps); 903 p_vi.p_smp_w = cast(ubyte[]) p_pcm.Devolve_SamplingBuffer(); 904 p_vi.smp_body_w = p_vc.p_ptn.get_smp_num_44k(); 905 break; 906 } 907 default: 908 break; 909 } 910 } 911 } 912 913 void Tone_Ready_envelope(int sps) @system { 914 int e = 0; 915 pxtnPOINT[] p_point = null; 916 917 scope(failure) { 918 for (int v = 0; v < _voice_num; v++) { 919 _voinsts[v].p_env = null; 920 } 921 } 922 for (int v = 0; v < _voice_num; v++) { 923 pxtnVOICEINSTANCE* p_vi = &_voinsts[v]; 924 pxtnVOICEUNIT* p_vc = &_voices[v]; 925 pxtnVOICEENVELOPE* p_enve = &p_vc.envelope; 926 int size = 0; 927 928 p_vi.p_env = null; 929 930 if (p_enve.head_num) { 931 for (e = 0; e < p_enve.head_num; e++) { 932 size += p_enve.points[e].x; 933 } 934 p_vi.env_size = cast(int)(cast(double) size * sps / p_enve.fps); 935 if (!p_vi.env_size) { 936 p_vi.env_size = 1; 937 } 938 939 p_vi.p_env = new ubyte[](p_vi.env_size); 940 p_point = new pxtnPOINT[](p_enve.head_num); 941 942 // convert points. 943 int offset = 0; 944 int head_num = 0; 945 for (e = 0; e < p_enve.head_num; e++) { 946 if (!e || p_enve.points[e].x || p_enve.points[e].y) { 947 offset += cast(int)(cast(double) p_enve.points[e].x * sps / p_enve.fps); 948 p_point[e].x = offset; 949 p_point[e].y = p_enve.points[e].y; 950 head_num++; 951 } 952 } 953 954 pxtnPOINT start; 955 e = start.x = start.y = 0; 956 for (int s = 0; s < p_vi.env_size; s++) { 957 while (e < head_num && s >= p_point[e].x) { 958 start.x = p_point[e].x; 959 start.y = p_point[e].y; 960 e++; 961 } 962 963 if (e < head_num) { 964 p_vi.p_env[s] = cast(ubyte)(start.y + (p_point[e].y - start.y) * (s - start.x) / (p_point[e].x - start.x)); 965 } else { 966 p_vi.p_env[s] = cast(ubyte) start.y; 967 } 968 } 969 970 p_point = null; 971 } 972 973 if (p_enve.tail_num) { 974 p_vi.env_release = cast(int)(cast(double) p_enve.points[p_enve.head_num].x * sps / p_enve.fps); 975 } else { 976 p_vi.env_release = 0; 977 } 978 } 979 p_point = null; 980 } 981 982 void Tone_Ready(const pxtnPulse_NoiseBuilder ptn_bldr, int sps) @system { 983 Tone_Ready_sample(ptn_bldr); 984 Tone_Ready_envelope(sps); 985 } 986 }