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