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 }