ft2_smpfx.c (29377B)
1 // for finding memory leaks in debug mode with Visual Studio 2 #if defined _DEBUG && defined _MSC_VER 3 #include <crtdbg.h> 4 #endif 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <stdint.h> 9 #include <stdbool.h> 10 #include <math.h> 11 #include "ft2_header.h" 12 #include "ft2_audio.h" 13 #include "ft2_pattern_ed.h" 14 #include "ft2_gui.h" 15 #include "ft2_sample_ed.h" 16 #include "ft2_structs.h" 17 #include "ft2_replayer.h" 18 19 #define RESONANCE_RANGE 99 20 #define RESONANCE_MIN 0.01 /* prevent massive blow-up */ 21 22 enum 23 { 24 REMOVE_SAMPLE_MARK = 0, 25 KEEP_SAMPLE_MARK = 1 26 }; 27 28 static struct 29 { 30 bool filled, keepSampleMark; 31 uint8_t flags, undoInstr, undoSmp; 32 uint32_t length, loopStart, loopLength; 33 int8_t *smpData8; 34 int16_t *smpData16; 35 } sampleUndo; 36 37 typedef struct 38 { 39 double a1, a2, a3, b1, b2; 40 double inTmp[2], outTmp[2]; 41 } resoFilter_t; 42 43 enum 44 { 45 FILTER_LOWPASS = 0, 46 FILTER_HIGHPASS = 1 47 }; 48 49 static bool normalization; 50 static uint8_t lastFilterType; 51 static int32_t lastLpCutoff = 2000, lastHpCutoff = 200, filterResonance, smpCycles = 1, lastWaveLength = 64, lastAmp = 75; 52 53 void clearSampleUndo(void) 54 { 55 if (sampleUndo.smpData8 != NULL) 56 { 57 free(sampleUndo.smpData8); 58 sampleUndo.smpData8 = NULL; 59 } 60 61 if (sampleUndo.smpData16 != NULL) 62 { 63 free(sampleUndo.smpData16); 64 sampleUndo.smpData16 = NULL; 65 } 66 67 sampleUndo.filled = false; 68 sampleUndo.keepSampleMark = false; 69 } 70 71 static void fillSampleUndo(bool keepSampleMark) 72 { 73 sampleUndo.filled = false; 74 75 sample_t *s = getCurSample(); 76 if (s != NULL && s->length > 0) 77 { 78 pauseAudio(); 79 unfixSample(s); 80 81 clearSampleUndo(); 82 83 sampleUndo.undoInstr = editor.curInstr; 84 sampleUndo.undoSmp = editor.curSmp; 85 sampleUndo.flags = s->flags; 86 sampleUndo.length = s->length; 87 sampleUndo.loopStart = s->loopStart; 88 sampleUndo.loopLength = s->loopLength; 89 sampleUndo.keepSampleMark = keepSampleMark; 90 91 if (s->flags & SAMPLE_16BIT) 92 { 93 sampleUndo.smpData16 = (int16_t *)malloc(s->length * sizeof (int16_t)); 94 if (sampleUndo.smpData16 != NULL) 95 { 96 memcpy(sampleUndo.smpData16, s->dataPtr, s->length * sizeof (int16_t)); 97 sampleUndo.filled = true; 98 } 99 } 100 else 101 { 102 sampleUndo.smpData8 = (int8_t *)malloc(s->length * sizeof (int8_t)); 103 if (sampleUndo.smpData8 != NULL) 104 { 105 memcpy(sampleUndo.smpData8, s->dataPtr, s->length * sizeof (int8_t)); 106 sampleUndo.filled = true; 107 } 108 } 109 110 fixSample(s); 111 resumeAudio(); 112 } 113 } 114 115 static sample_t *setupNewSample(uint32_t length) 116 { 117 pauseAudio(); 118 119 if (instr[editor.curInstr] == NULL) 120 allocateInstr(editor.curInstr); 121 122 if (instr[editor.curInstr] == NULL) 123 goto Error; 124 125 sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp]; 126 127 if (!reallocateSmpData(s, length, true)) 128 goto Error; 129 130 s->isFixed = false; 131 s->length = length; 132 s->loopLength = s->loopStart = 0; 133 s->flags = SAMPLE_16BIT; 134 135 resumeAudio(); 136 return s; 137 138 Error: 139 resumeAudio(); 140 return NULL; 141 } 142 143 void cbSfxNormalization(void) 144 { 145 normalization ^= 1; 146 } 147 148 static void drawSampleCycles(void) 149 { 150 const int16_t x = 54; 151 152 fillRect(x, 352, 7*3, 8, PAL_DESKTOP); 153 154 char str[16]; 155 sprintf(str, "%03d", smpCycles); 156 textOut(x, 352, PAL_FORGRND, str); 157 } 158 159 void pbSfxCyclesUp(void) 160 { 161 if (smpCycles < 256) 162 { 163 smpCycles++; 164 drawSampleCycles(); 165 } 166 } 167 168 void pbSfxCyclesDown(void) 169 { 170 if (smpCycles > 1) 171 { 172 smpCycles--; 173 drawSampleCycles(); 174 } 175 } 176 177 void pbSfxTriangle(void) 178 { 179 char lengthStr[5+1]; 180 memset(lengthStr, '\0', sizeof (lengthStr)); 181 snprintf(lengthStr, sizeof (lengthStr), "%d", lastWaveLength); 182 183 if (inputBox(1, "Enter new waveform length:", lengthStr, sizeof (lengthStr)-1) != 1) 184 return; 185 186 if (lengthStr[0] == '\0') 187 return; 188 189 lastWaveLength = (int32_t)atoi(lengthStr); 190 if (lastWaveLength <= 1 || lastWaveLength > 65536) 191 { 192 okBox(0, "System message", "Illegal range! Allowed range is 2..65535", NULL); 193 return; 194 } 195 196 fillSampleUndo(REMOVE_SAMPLE_MARK); 197 198 int32_t newLength = lastWaveLength * smpCycles; 199 200 pauseAudio(); 201 202 sample_t *s = setupNewSample(newLength); 203 if (s == NULL) 204 { 205 resumeAudio(); 206 okBox(0, "System message", "Not enough memory!", NULL); 207 return; 208 } 209 210 const double delta = 4.0 / lastWaveLength; 211 double phase = 0.0; 212 213 int16_t *ptr16 = (int16_t *)s->dataPtr; 214 for (int32_t i = 0; i < newLength; i++) 215 { 216 double t = phase; 217 if (t > 3.0) 218 t -= 4.0; 219 else if (t >= 1.0) 220 t = 2.0 - t; 221 222 *ptr16++ = (int16_t)(t * INT16_MAX); 223 phase = fmod(phase + delta, 4.0); 224 } 225 226 s->loopLength = newLength; 227 s->flags |= LOOP_FORWARD; 228 fixSample(s); 229 resumeAudio(); 230 231 updateSampleEditorSample(); 232 } 233 234 void pbSfxSaw(void) 235 { 236 char lengthStr[5+1]; 237 memset(lengthStr, '\0', sizeof (lengthStr)); 238 snprintf(lengthStr, sizeof (lengthStr), "%d", lastWaveLength); 239 240 if (inputBox(1, "Enter new waveform length:", lengthStr, sizeof (lengthStr)-1) != 1) 241 return; 242 243 if (lengthStr[0] == '\0') 244 return; 245 246 lastWaveLength = (int32_t)atoi(lengthStr); 247 if (lastWaveLength <= 1 || lastWaveLength > 65536) 248 { 249 okBox(0, "System message", "Illegal range! Allowed range is 2..65535", NULL); 250 return; 251 } 252 253 fillSampleUndo(REMOVE_SAMPLE_MARK); 254 255 int32_t newLength = lastWaveLength * smpCycles; 256 257 pauseAudio(); 258 259 sample_t *s = setupNewSample(newLength); 260 if (s == NULL) 261 { 262 resumeAudio(); 263 okBox(0, "System message", "Not enough memory!", NULL); 264 return; 265 } 266 267 uint64_t point64 = 0; 268 uint64_t delta64 = ((uint64_t)(INT16_MAX*2) << 32ULL) / lastWaveLength; 269 270 int16_t *ptr16 = (int16_t *)s->dataPtr; 271 for (int32_t i = 0; i < newLength; i++) 272 { 273 *ptr16++ = (int16_t)(point64 >> 32); 274 point64 += delta64; 275 } 276 277 s->loopLength = newLength; 278 s->flags |= LOOP_FORWARD; 279 fixSample(s); 280 resumeAudio(); 281 282 updateSampleEditorSample(); 283 } 284 285 void pbSfxSine(void) 286 { 287 char lengthStr[5+1]; 288 memset(lengthStr, '\0', sizeof (lengthStr)); 289 snprintf(lengthStr, sizeof (lengthStr), "%d", lastWaveLength); 290 291 if (inputBox(1, "Enter new waveform length:", lengthStr, sizeof (lengthStr)-1) != 1) 292 return; 293 294 if (lengthStr[0] == '\0') 295 return; 296 297 lastWaveLength = (int32_t)atoi(lengthStr); 298 if (lastWaveLength <= 1 || lastWaveLength > 65536) 299 { 300 okBox(0, "System message", "Illegal range! Allowed range is 2..65535", NULL); 301 return; 302 } 303 304 fillSampleUndo(REMOVE_SAMPLE_MARK); 305 306 int32_t newLength = lastWaveLength * smpCycles; 307 308 pauseAudio(); 309 310 sample_t *s = setupNewSample(newLength); 311 if (s == NULL) 312 { 313 resumeAudio(); 314 okBox(0, "System message", "Not enough memory!", NULL); 315 return; 316 } 317 318 const double dMul = (2.0 * M_PI) / lastWaveLength; 319 320 int16_t *ptr16 = (int16_t *)s->dataPtr; 321 for (int32_t i = 0; i < newLength; i++) 322 *ptr16++ = (int16_t)(INT16_MAX * sin(i * dMul)); 323 324 s->loopLength = newLength; 325 s->flags |= LOOP_FORWARD; 326 fixSample(s); 327 resumeAudio(); 328 329 updateSampleEditorSample(); 330 } 331 332 void pbSfxSquare(void) 333 { 334 char lengthStr[5+1]; 335 memset(lengthStr, '\0', sizeof (lengthStr)); 336 snprintf(lengthStr, sizeof (lengthStr), "%d", lastWaveLength); 337 338 if (inputBox(1, "Enter new waveform length:", lengthStr, sizeof (lengthStr)-1) != 1) 339 return; 340 341 if (lengthStr[0] == '\0') 342 return; 343 344 lastWaveLength = (int32_t)atoi(lengthStr); 345 if (lastWaveLength <= 1 || lastWaveLength > 65536) 346 { 347 okBox(0, "System message", "Illegal range! Allowed range is 2..65535", NULL); 348 return; 349 } 350 351 fillSampleUndo(REMOVE_SAMPLE_MARK); 352 353 uint32_t newLength = lastWaveLength * smpCycles; 354 355 pauseAudio(); 356 357 sample_t *s = setupNewSample(newLength); 358 if (s == NULL) 359 { 360 resumeAudio(); 361 okBox(0, "System message", "Not enough memory!", NULL); 362 return; 363 } 364 365 const uint32_t halfWaveLength = lastWaveLength / 2; 366 367 int16_t currValue = INT16_MAX; 368 uint32_t counter = 0; 369 370 int16_t *ptr16 = (int16_t *)s->dataPtr; 371 for (uint32_t i = 0; i < newLength; i++) 372 { 373 *ptr16++ = currValue; 374 if (++counter >= halfWaveLength) 375 { 376 counter = 0; 377 currValue = -currValue; 378 } 379 } 380 381 s->loopLength = newLength; 382 s->flags |= LOOP_FORWARD; 383 fixSample(s); 384 resumeAudio(); 385 386 updateSampleEditorSample(); 387 } 388 389 void drawFilterResonance(void) 390 { 391 const int16_t x = 172; 392 393 fillRect(x, 352, 18, 12, PAL_DESKTOP); 394 395 if (filterResonance <= 0) 396 { 397 textOut(x, 352, PAL_FORGRND, "off"); 398 } 399 else 400 { 401 char str[16]; 402 sprintf(str, "%02d", filterResonance); 403 textOut(x+3, 352, PAL_FORGRND, str); 404 } 405 } 406 407 void pbSfxResoUp(void) 408 { 409 if (filterResonance < RESONANCE_RANGE) 410 { 411 filterResonance++; 412 drawFilterResonance(); 413 } 414 } 415 416 void pbSfxResoDown(void) 417 { 418 if (filterResonance > 0) 419 { 420 filterResonance--; 421 drawFilterResonance(); 422 } 423 } 424 425 #define CUTOFF_EPSILON (1E-4) 426 427 static void setupResoLpFilter(sample_t *s, resoFilter_t *f, double cutoff, uint32_t resonance, bool absoluteCutoff) 428 { 429 // 12dB/oct resonant low-pass filter 430 431 if (!absoluteCutoff) 432 { 433 const double sampleFreq = getSampleC4Rate(s); 434 if (cutoff >= sampleFreq/2.0) 435 cutoff = (sampleFreq/2.0) - CUTOFF_EPSILON; 436 437 cutoff /= sampleFreq; 438 } 439 440 double r = sqrt(2.0); 441 if (resonance > 0) 442 { 443 r = pow(10.0, (resonance * -24.0) / (RESONANCE_RANGE * 20.0)); 444 if (r < RESONANCE_MIN) 445 r = RESONANCE_MIN; 446 } 447 448 const double c = 1.0 / tan(PI * cutoff); 449 450 f->a1 = 1.0 / (1.0 + r * c + c * c); 451 f->a2 = 2.0 * f->a1; 452 f->a3 = f->a1; 453 f->b1 = 2.0 * (1.0 - c*c) * f->a1; 454 f->b2 = (1.0 - r * c + c * c) * f->a1; 455 456 f->inTmp[0] = f->inTmp[1] = f->outTmp[0] = f->outTmp[1] = 0.0; // clear filter history 457 } 458 459 static void setupResoHpFilter(sample_t *s, resoFilter_t *f, double cutoff, uint32_t resonance, bool absoluteCutoff) 460 { 461 // 12dB/oct resonant high-pass filter 462 463 if (!absoluteCutoff) 464 { 465 const double sampleFreq = getSampleC4Rate(s); 466 if (cutoff >= sampleFreq/2.0) 467 cutoff = (sampleFreq/2.0) - CUTOFF_EPSILON; 468 469 cutoff /= sampleFreq; 470 } 471 472 double r = sqrt(2.0); 473 if (resonance > 0) 474 { 475 r = pow(10.0, (resonance * -24.0) / (RESONANCE_RANGE * 20.0)); 476 if (r < RESONANCE_MIN) 477 r = RESONANCE_MIN; 478 } 479 480 const double c = tan(PI * cutoff); 481 482 f->a1 = 1.0 / (1.0 + r * c + c * c); 483 f->a2 = -2.0 * f->a1; 484 f->a3 = f->a1; 485 f->b1 = 2.0 * (c*c - 1.0) * f->a1; 486 f->b2 = (1.0 - r * c + c * c) * f->a1; 487 488 f->inTmp[0] = f->inTmp[1] = f->outTmp[0] = f->outTmp[1] = 0.0; // clear filter history 489 } 490 491 static bool applyResoFilter(sample_t *s, resoFilter_t *f) 492 { 493 int32_t x1, x2; 494 if (smpEd_Rx1 < smpEd_Rx2) 495 { 496 x1 = smpEd_Rx1; 497 x2 = smpEd_Rx2; 498 499 if (x2 > s->length) 500 x2 = s->length; 501 502 if (x1 < 0) 503 x1 = 0; 504 505 if (x2 <= x1) 506 return true; 507 } 508 else 509 { 510 // no mark, operate on whole sample 511 x1 = 0; 512 x2 = s->length; 513 } 514 515 const int32_t len = x2 - x1; 516 517 if (!normalization) 518 { 519 pauseAudio(); 520 unfixSample(s); 521 522 if (s->flags & SAMPLE_16BIT) 523 { 524 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 525 for (int32_t i = 0; i < len; i++) 526 { 527 double out = (f->a1*ptr16[i]) + (f->a2*f->inTmp[0]) + (f->a3*f->inTmp[1]) - (f->b1*f->outTmp[0]) - (f->b2*f->outTmp[1]); 528 529 f->inTmp[1] = f->inTmp[0]; 530 f->inTmp[0] = ptr16[i]; 531 532 f->outTmp[1] = f->outTmp[0]; 533 f->outTmp[0] = out; 534 535 ptr16[i] = (int16_t)CLAMP(out, INT16_MIN, INT16_MAX); 536 } 537 } 538 else 539 { 540 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 541 for (int32_t i = 0; i < len; i++) 542 { 543 double out = (f->a1*ptr8[i]) + (f->a2*f->inTmp[0]) + (f->a3*f->inTmp[1]) - (f->b1*f->outTmp[0]) - (f->b2*f->outTmp[1]); 544 545 f->inTmp[1] = f->inTmp[0]; 546 f->inTmp[0] = ptr8[i]; 547 548 f->outTmp[1] = f->outTmp[0]; 549 f->outTmp[0] = out; 550 551 ptr8[i] = (int8_t)CLAMP(out, INT8_MIN, INT8_MAX); 552 } 553 } 554 555 fixSample(s); 556 resumeAudio(); 557 } 558 else // normalize peak, no clipping 559 { 560 double *dSmp = (double *)malloc(len * sizeof (double)); 561 if (dSmp == NULL) 562 { 563 okBox(0, "System message", "Not enough memory!", NULL); 564 return false; 565 } 566 567 pauseAudio(); 568 unfixSample(s); 569 570 if (s->flags & SAMPLE_16BIT) 571 { 572 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 573 for (int32_t i = 0; i < len; i++) 574 dSmp[i] = (double)ptr16[i]; 575 } 576 else 577 { 578 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 579 for (int32_t i = 0; i < len; i++) 580 dSmp[i] = (double)ptr8[i]; 581 } 582 583 double peak = 0.0; 584 for (int32_t i = 0; i < len; i++) 585 { 586 const double out = (f->a1*dSmp[i]) + (f->a2*f->inTmp[0]) + (f->a3*f->inTmp[1]) - (f->b1*f->outTmp[0]) - (f->b2*f->outTmp[1]); 587 588 f->inTmp[1] = f->inTmp[0]; 589 f->inTmp[0] = dSmp[i]; 590 591 f->outTmp[1] = f->outTmp[0]; 592 f->outTmp[0] = out; 593 594 dSmp[i] = out; 595 596 const double outAbs = fabs(out); 597 if (outAbs > peak) 598 peak = outAbs; 599 } 600 601 if (s->flags & SAMPLE_16BIT) 602 { 603 const double scale = INT16_MAX / peak; 604 605 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 606 for (int32_t i = 0; i < len; i++) 607 ptr16[i] = (int16_t)(dSmp[i] * scale); 608 } 609 else 610 { 611 const double scale = INT8_MAX / peak; 612 613 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 614 for (int32_t i = 0; i < len; i++) 615 ptr8[i] = (int8_t)(dSmp[i] * scale); 616 } 617 618 free(dSmp); 619 620 fixSample(s); 621 resumeAudio(); 622 } 623 624 return true; 625 } 626 627 void pbSfxLowPass(void) 628 { 629 resoFilter_t f; 630 631 sample_t *s = getCurSample(); 632 if (s == NULL || s->dataPtr == NULL) 633 return; 634 635 char lengthStr[5+1]; 636 memset(lengthStr, '\0', sizeof (lengthStr)); 637 snprintf(lengthStr, sizeof (lengthStr), "%d", lastLpCutoff); 638 639 lastFilterType = FILTER_LOWPASS; 640 if (inputBox(6, "Enter low-pass filter cutoff (in Hz):", lengthStr, sizeof (lengthStr)-1) != 1) 641 return; 642 643 if (lengthStr[0] == '\0') 644 return; 645 646 lastLpCutoff = (int32_t)atoi(lengthStr); 647 if (lastLpCutoff < 1 || lastLpCutoff > 99999) 648 { 649 okBox(0, "System message", "Illegal range! Allowed range is 1..99999", NULL); 650 return; 651 } 652 653 setupResoLpFilter(s, &f, lastLpCutoff, filterResonance, false); 654 fillSampleUndo(KEEP_SAMPLE_MARK); 655 applyResoFilter(s, &f); 656 writeSample(true); 657 } 658 659 void pbSfxHighPass(void) 660 { 661 resoFilter_t f; 662 663 sample_t *s = getCurSample(); 664 if (s == NULL || s->dataPtr == NULL) 665 return; 666 667 char lengthStr[5+1]; 668 memset(lengthStr, '\0', sizeof (lengthStr)); 669 snprintf(lengthStr, sizeof (lengthStr), "%d", lastHpCutoff); 670 671 lastFilterType = FILTER_HIGHPASS; 672 if (inputBox(6, "Enter high-pass filter cutoff (in Hz):", lengthStr, sizeof (lengthStr)-1) != 1) 673 return; 674 675 if (lengthStr[0] == '\0') 676 return; 677 678 lastHpCutoff = (int32_t)atoi(lengthStr); 679 if (lastHpCutoff < 1 || lastHpCutoff > 99999) 680 { 681 okBox(0, "System message", "Illegal range! Allowed range is 1..99999", NULL); 682 return; 683 } 684 685 setupResoHpFilter(s, &f, lastHpCutoff, filterResonance, false); 686 fillSampleUndo(KEEP_SAMPLE_MARK); 687 applyResoFilter(s, &f); 688 writeSample(true); 689 } 690 691 void sfxPreviewFilter(uint32_t cutoff) 692 { 693 sample_t oldSample; 694 resoFilter_t f; 695 696 sample_t *s = getCurSample(); 697 if (s == NULL || s->dataPtr == NULL || s->length == 0 || cutoff < 1 || cutoff > 99999) 698 return; 699 700 int32_t x1, x2; 701 if (smpEd_Rx1 < smpEd_Rx2) 702 { 703 x1 = smpEd_Rx1; 704 x2 = smpEd_Rx2; 705 706 if (x2 > s->length) 707 x2 = s->length; 708 709 if (x1 < 0) 710 x1 = 0; 711 712 if (x2 <= x1) 713 return; 714 } 715 else 716 { 717 // no mark, operate on whole sample 718 x1 = 0; 719 x2 = s->length; 720 } 721 722 const int32_t len = x2 - x1; 723 724 pauseAudio(); 725 unfixSample(s); 726 memcpy(&oldSample, s, sizeof (sample_t)); 727 728 if (lastFilterType == FILTER_LOWPASS) 729 setupResoLpFilter(s, &f, cutoff, filterResonance, false); 730 else 731 setupResoHpFilter(s, &f, cutoff, filterResonance, false); 732 733 // prepare new sample 734 int8_t *sampleData; 735 if (s->flags & SAMPLE_16BIT) 736 { 737 sampleData = (int8_t *)malloc((len * sizeof (int16_t)) + SAMPLE_PAD_LENGTH); 738 if (sampleData == NULL) 739 goto Error; 740 741 memcpy(sampleData + SMP_DAT_OFFSET, (int16_t *)s->dataPtr + x1, len * sizeof (int16_t)); 742 } 743 else 744 { 745 sampleData = (int8_t *)malloc((len * sizeof (int8_t)) + SAMPLE_PAD_LENGTH); 746 if (sampleData == NULL) 747 goto Error; 748 749 memcpy(sampleData + SMP_DAT_OFFSET, (int8_t *)s->dataPtr + x1, len * sizeof (int8_t)); 750 } 751 752 s->origDataPtr = sampleData; 753 s->length = len; 754 s->dataPtr = s->origDataPtr + SMP_DAT_OFFSET; 755 s->loopStart = s->loopLength = 0; 756 fixSample(s); 757 758 const int32_t oldX1 = smpEd_Rx1; 759 const int32_t oldX2 = smpEd_Rx2; 760 smpEd_Rx1 = smpEd_Rx2 = 0; 761 applyResoFilter(s, &f); 762 smpEd_Rx1 = oldX1; 763 smpEd_Rx2 = oldX2; 764 765 // set up preview sample on channel 0 766 channel_t *ch = &channel[0]; 767 uint8_t note = editor.smpEd_NoteNr; 768 ch->smpNum = editor.curSmp; 769 ch->instrNum = editor.curInstr; 770 ch->copyOfInstrAndNote = (ch->instrNum << 8) | note; 771 ch->efx = 0; 772 ch->smpStartPos = 0; 773 resumeAudio(); 774 triggerNote(note, 0, 0, ch); 775 resetVolumes(ch); 776 triggerInstrument(ch); 777 ch->realVol = ch->outVol = ch->oldVol = 64; 778 updateVolPanAutoVib(ch); 779 780 while (ch->status & IS_Trigger); // wait for sample to latch in mixer 781 SDL_Delay(1500); // wait 1.5 seconds 782 783 // we're done, stop voice and free temporary data 784 pauseAudio(); 785 free(sampleData); 786 787 Error: 788 // set back old sample 789 memcpy(s, &oldSample, sizeof (sample_t)); 790 fixSample(s); 791 resumeAudio(); 792 } 793 794 void pbSfxSubBass(void) 795 { 796 resoFilter_t f; 797 798 sample_t *s = getCurSample(); 799 if (s == NULL || s->dataPtr == NULL) 800 return; 801 802 setupResoHpFilter(s, &f, 0.001, 0, true); 803 fillSampleUndo(KEEP_SAMPLE_MARK); 804 applyResoFilter(s, &f); 805 writeSample(true); 806 } 807 808 void pbSfxAddBass(void) 809 { 810 resoFilter_t f; 811 812 sample_t *s = getCurSample(); 813 if (s == NULL || s->dataPtr == NULL) 814 return; 815 816 int32_t x1, x2; 817 if (smpEd_Rx1 < smpEd_Rx2) 818 { 819 x1 = smpEd_Rx1; 820 x2 = smpEd_Rx2; 821 822 if (x2 > s->length) 823 x2 = s->length; 824 825 if (x1 < 0) 826 x1 = 0; 827 828 if (x2 <= x1) 829 return; 830 } 831 else 832 { 833 // no mark, operate on whole sample 834 x1 = 0; 835 x2 = s->length; 836 } 837 838 const int32_t len = x2 - x1; 839 840 setupResoLpFilter(s, &f, 0.015, 0, true); 841 842 double *dSmp = (double *)malloc(len * sizeof (double)); 843 if (dSmp == NULL) 844 { 845 okBox(0, "System message", "Not enough memory!", NULL); 846 return; 847 } 848 849 fillSampleUndo(KEEP_SAMPLE_MARK); 850 851 pauseAudio(); 852 unfixSample(s); 853 854 if (s->flags & SAMPLE_16BIT) 855 { 856 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 857 for (int32_t i = 0; i < len; i++) 858 dSmp[i] = (double)ptr16[i]; 859 } 860 else 861 { 862 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 863 for (int32_t i = 0; i < len; i++) 864 dSmp[i] = (double)ptr8[i]; 865 } 866 867 if (!normalization) 868 { 869 for (int32_t i = 0; i < len; i++) 870 { 871 double out = (f.a1*dSmp[i]) + (f.a2*f.inTmp[0]) + (f.a3*f.inTmp[1]) - (f.b1*f.outTmp[0]) - (f.b2*f.outTmp[1]); 872 873 f.inTmp[1] = f.inTmp[0]; 874 f.inTmp[0] = dSmp[i]; 875 876 f.outTmp[1] = f.outTmp[0]; 877 f.outTmp[0] = out; 878 879 dSmp[i] = out; 880 } 881 882 if (s->flags & SAMPLE_16BIT) 883 { 884 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 885 for (int32_t i = 0; i < len; i++) 886 { 887 double out = ptr16[i] + (dSmp[i] * 0.25); 888 out = CLAMP(out, INT16_MIN, INT16_MAX); 889 890 ptr16[i] = (int16_t)out; 891 } 892 } 893 else 894 { 895 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 896 for (int32_t i = 0; i < len; i++) 897 { 898 double out = ptr8[i] + (dSmp[i] * 0.25); 899 out = CLAMP(out, INT8_MIN, INT8_MAX); 900 901 ptr8[i] = (int8_t)out; 902 } 903 } 904 } 905 else 906 { 907 if (s->flags & SAMPLE_16BIT) 908 { 909 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 910 911 double peak = 0.0; 912 for (int32_t i = 0; i < len; i++) 913 { 914 double out = (f.a1*dSmp[i]) + (f.a2*f.inTmp[0]) + (f.a3*f.inTmp[1]) - (f.b1*f.outTmp[0]) - (f.b2*f.outTmp[1]); 915 916 f.inTmp[1] = f.inTmp[0]; 917 f.inTmp[0] = dSmp[i]; 918 919 f.outTmp[1] = f.outTmp[0]; 920 f.outTmp[0] = out; 921 922 dSmp[i] = out; 923 double bass = ptr16[i] + (out * 0.25); 924 925 const double outAbs = fabs(bass); 926 if (outAbs > peak) 927 peak = outAbs; 928 } 929 930 double scale = INT16_MAX / peak; 931 for (int32_t i = 0; i < len; i++) 932 ptr16[i] = (int16_t)((ptr16[i] + (dSmp[i] * 0.25)) * scale); 933 } 934 else 935 { 936 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 937 938 double peak = 0.0; 939 for (int32_t i = 0; i < len; i++) 940 { 941 double out = (f.a1*dSmp[i]) + (f.a2*f.inTmp[0]) + (f.a3*f.inTmp[1]) - (f.b1*f.outTmp[0]) - (f.b2*f.outTmp[1]); 942 943 f.inTmp[1] = f.inTmp[0]; 944 f.inTmp[0] = dSmp[i]; 945 946 f.outTmp[1] = f.outTmp[0]; 947 f.outTmp[0] = out; 948 949 dSmp[i] = out; 950 double bass = ptr8[i] + (out * 0.25); 951 952 const double outAbs = fabs(bass); 953 if (outAbs > peak) 954 peak = outAbs; 955 } 956 957 double scale = INT8_MAX / peak; 958 for (int32_t i = 0; i < len; i++) 959 ptr8[i] = (int8_t)((ptr8[i] + (dSmp[i] * 0.25)) * scale); 960 } 961 } 962 963 free(dSmp); 964 965 fixSample(s); 966 resumeAudio(); 967 968 writeSample(true); 969 } 970 971 void pbSfxSubTreble(void) 972 { 973 resoFilter_t f; 974 975 sample_t *s = getCurSample(); 976 if (s == NULL || s->dataPtr == NULL) 977 return; 978 979 setupResoLpFilter(s, &f, 0.33, 0, true); 980 fillSampleUndo(KEEP_SAMPLE_MARK); 981 applyResoFilter(s, &f); 982 writeSample(true); 983 } 984 985 void pbSfxAddTreble(void) 986 { 987 resoFilter_t f; 988 989 sample_t *s = getCurSample(); 990 if (s == NULL || s->dataPtr == NULL) 991 return; 992 993 int32_t x1, x2; 994 if (smpEd_Rx1 < smpEd_Rx2) 995 { 996 x1 = smpEd_Rx1; 997 x2 = smpEd_Rx2; 998 999 if (x2 > s->length) 1000 x2 = s->length; 1001 1002 if (x1 < 0) 1003 x1 = 0; 1004 1005 if (x2 <= x1) 1006 return; 1007 } 1008 else 1009 { 1010 // no mark, operate on whole sample 1011 x1 = 0; 1012 x2 = s->length; 1013 } 1014 1015 const int32_t len = x2 - x1; 1016 1017 setupResoHpFilter(s, &f, 0.27, 0, true); 1018 1019 double *dSmp = (double *)malloc(len * sizeof (double)); 1020 if (dSmp == NULL) 1021 { 1022 okBox(0, "System message", "Not enough memory!", NULL); 1023 return; 1024 } 1025 1026 fillSampleUndo(KEEP_SAMPLE_MARK); 1027 1028 pauseAudio(); 1029 unfixSample(s); 1030 1031 if (s->flags & SAMPLE_16BIT) 1032 { 1033 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 1034 for (int32_t i = 0; i < len; i++) 1035 dSmp[i] = (double)ptr16[i]; 1036 } 1037 else 1038 { 1039 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 1040 for (int32_t i = 0; i < len; i++) 1041 dSmp[i] = (double)ptr8[i]; 1042 } 1043 1044 if (!normalization) 1045 { 1046 for (int32_t i = 0; i < len; i++) 1047 { 1048 double out = (f.a1*dSmp[i]) + (f.a2*f.inTmp[0]) + (f.a3*f.inTmp[1]) - (f.b1*f.outTmp[0]) - (f.b2*f.outTmp[1]); 1049 1050 f.inTmp[1] = f.inTmp[0]; 1051 f.inTmp[0] = dSmp[i]; 1052 1053 f.outTmp[1] = f.outTmp[0]; 1054 f.outTmp[0] = out; 1055 1056 dSmp[i] = out; 1057 } 1058 1059 if (s->flags & SAMPLE_16BIT) 1060 { 1061 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 1062 for (int32_t i = 0; i < len; i++) 1063 { 1064 double out = ptr16[i] - (dSmp[i] * 0.25); 1065 out = CLAMP(out, INT16_MIN, INT16_MAX); 1066 1067 ptr16[i] = (int16_t)out; 1068 } 1069 } 1070 else 1071 { 1072 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 1073 for (int32_t i = 0; i < len; i++) 1074 { 1075 double out = ptr8[i] - (dSmp[i] * 0.25); 1076 out = CLAMP(out, INT8_MIN, INT8_MAX); 1077 1078 ptr8[i] = (int8_t)out; 1079 } 1080 } 1081 } 1082 else 1083 { 1084 if (s->flags & SAMPLE_16BIT) 1085 { 1086 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 1087 1088 double peak = 0.0; 1089 for (int32_t i = 0; i < len; i++) 1090 { 1091 double out = (f.a1*dSmp[i]) + (f.a2*f.inTmp[0]) + (f.a3*f.inTmp[1]) - (f.b1*f.outTmp[0]) - (f.b2*f.outTmp[1]); 1092 1093 f.inTmp[1] = f.inTmp[0]; 1094 f.inTmp[0] = dSmp[i]; 1095 1096 f.outTmp[1] = f.outTmp[0]; 1097 f.outTmp[0] = out; 1098 1099 dSmp[i] = out; 1100 double treble = ptr16[i] - (out * 0.25); 1101 1102 const double outAbs = fabs(treble); 1103 if (outAbs > peak) 1104 peak = outAbs; 1105 } 1106 1107 double scale = INT16_MAX / peak; 1108 for (int32_t i = 0; i < len; i++) 1109 ptr16[i] = (int16_t)((ptr16[i] - (dSmp[i] * 0.25)) * scale); 1110 } 1111 else 1112 { 1113 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 1114 1115 double peak = 0.0; 1116 for (int32_t i = 0; i < len; i++) 1117 { 1118 double out = (f.a1*dSmp[i]) + (f.a2*f.inTmp[0]) + (f.a3*f.inTmp[1]) - (f.b1*f.outTmp[0]) - (f.b2*f.outTmp[1]); 1119 1120 f.inTmp[1] = f.inTmp[0]; 1121 f.inTmp[0] = dSmp[i]; 1122 1123 f.outTmp[1] = f.outTmp[0]; 1124 f.outTmp[0] = out; 1125 1126 dSmp[i] = out; 1127 double treble = ptr8[i] - (out * 0.25); 1128 1129 const double outAbs = fabs(treble); 1130 if (outAbs > peak) 1131 peak = outAbs; 1132 } 1133 1134 double scale = INT8_MAX / peak; 1135 for (int32_t i = 0; i < len; i++) 1136 ptr8[i] = (int8_t)((ptr8[i] - (dSmp[i] * 0.25)) * scale); 1137 } 1138 } 1139 1140 free(dSmp); 1141 1142 fixSample(s); 1143 resumeAudio(); 1144 1145 writeSample(true); 1146 } 1147 1148 void pbSfxSetAmp(void) 1149 { 1150 sample_t *s = getCurSample(); 1151 if (s == NULL || s->dataPtr == NULL) 1152 return; 1153 1154 int32_t x1, x2; 1155 if (smpEd_Rx1 < smpEd_Rx2) 1156 { 1157 x1 = smpEd_Rx1; 1158 x2 = smpEd_Rx2; 1159 1160 if (x2 > s->length) 1161 x2 = s->length; 1162 1163 if (x1 < 0) 1164 x1 = 0; 1165 1166 if (x2 <= x1) 1167 return; 1168 } 1169 else 1170 { 1171 // no mark, operate on whole sample 1172 x1 = 0; 1173 x2 = s->length; 1174 } 1175 1176 const int32_t len = x2 - x1; 1177 1178 char ampStr[3+1]; 1179 memset(ampStr, '\0', sizeof (ampStr)); 1180 snprintf(ampStr, sizeof (ampStr), "%d", lastAmp); 1181 1182 if (inputBox(1, "Change sample amplitude (in percentage, 0..999):", ampStr, sizeof (ampStr)-1) != 1) 1183 return; 1184 1185 if (ampStr[0] == '\0') 1186 return; 1187 1188 lastAmp = (int32_t)atoi(ampStr); 1189 1190 fillSampleUndo(KEEP_SAMPLE_MARK); 1191 1192 pauseAudio(); 1193 unfixSample(s); 1194 1195 const int32_t mul = (int32_t)round((1 << 22UL) * (lastAmp / 100.0)); 1196 1197 if (s->flags & SAMPLE_16BIT) 1198 { 1199 int16_t *ptr16 = (int16_t *)s->dataPtr + x1; 1200 for (int32_t i = 0; i < len; i++) 1201 { 1202 int32_t sample = ((int64_t)ptr16[i] * (int32_t)mul) >> 22; 1203 sample = CLAMP(sample, INT16_MIN, INT16_MAX); 1204 ptr16[i] = (int16_t)sample; 1205 } 1206 } 1207 else 1208 { 1209 int8_t *ptr8 = (int8_t *)s->dataPtr + x1; 1210 for (int32_t i = 0; i < len; i++) 1211 { 1212 int32_t sample = ((int64_t)ptr8[i] * (int32_t)mul) >> 22; 1213 sample = CLAMP(sample, INT8_MIN, INT8_MAX); 1214 ptr8[i] = (int8_t)sample; 1215 } 1216 } 1217 1218 fixSample(s); 1219 resumeAudio(); 1220 1221 writeSample(true); 1222 } 1223 1224 void pbSfxUndo(void) 1225 { 1226 if (!sampleUndo.filled || sampleUndo.undoInstr != editor.curInstr || sampleUndo.undoSmp != editor.curSmp) 1227 return; 1228 1229 sample_t *s = getCurSample(); 1230 if (s == NULL || s->dataPtr == NULL) 1231 return; 1232 1233 pauseAudio(); 1234 1235 freeSmpData(s); 1236 s->flags = sampleUndo.flags; 1237 s->length = sampleUndo.length; 1238 s->loopStart = sampleUndo.loopStart; 1239 s->loopLength = sampleUndo.loopLength; 1240 1241 if (allocateSmpData(s, s->length, !!(s->flags & SAMPLE_16BIT))) 1242 { 1243 if (s->flags & SAMPLE_16BIT) 1244 memcpy(s->dataPtr, sampleUndo.smpData16, s->length * sizeof (int16_t)); 1245 else 1246 memcpy(s->dataPtr, sampleUndo.smpData8, s->length * sizeof (int8_t)); 1247 1248 fixSample(s); 1249 resumeAudio(); 1250 } 1251 else 1252 { 1253 resumeAudio(); 1254 okBox(0, "System message", "Not enough memory!", NULL); 1255 } 1256 1257 int32_t oldRx1 = smpEd_Rx1; 1258 int32_t oldRx2 = smpEd_Rx2; 1259 1260 updateSampleEditorSample(); 1261 1262 if (sampleUndo.keepSampleMark && oldRx1 < oldRx2) 1263 { 1264 smpEd_Rx1 = oldRx1; 1265 smpEd_Rx2 = oldRx2; 1266 writeSample(false); // redraw sample mark only 1267 } 1268 1269 sampleUndo.keepSampleMark = false; 1270 sampleUndo.filled = false; 1271 } 1272 1273 void hideSampleEffectsScreen(void) 1274 { 1275 ui.sampleEditorEffectsShown = false; 1276 1277 hideCheckBox(CB_SAMPFX_NORMALIZATION); 1278 hidePushButton(PB_SAMPFX_CYCLES_UP); 1279 hidePushButton(PB_SAMPFX_CYCLES_DOWN); 1280 hidePushButton(PB_SAMPFX_TRIANGLE); 1281 hidePushButton(PB_SAMPFX_SAW); 1282 hidePushButton(PB_SAMPFX_SINE); 1283 hidePushButton(PB_SAMPFX_SQUARE); 1284 hidePushButton(PB_SAMPFX_RESO_UP); 1285 hidePushButton(PB_SAMPFX_RESO_DOWN); 1286 hidePushButton(PB_SAMPFX_LOWPASS); 1287 hidePushButton(PB_SAMPFX_HIGHPASS); 1288 hidePushButton(PB_SAMPFX_SUB_BASS); 1289 hidePushButton(PB_SAMPFX_SUB_TREBLE); 1290 hidePushButton(PB_SAMPFX_ADD_BASS); 1291 hidePushButton(PB_SAMPFX_ADD_TREBLE); 1292 hidePushButton(PB_SAMPFX_SET_AMP); 1293 hidePushButton(PB_SAMPFX_UNDO); 1294 hidePushButton(PB_SAMPFX_XFADE); 1295 hidePushButton(PB_SAMPFX_BACK); 1296 1297 drawFramework(0, 346, 115, 54, FRAMEWORK_TYPE1); 1298 drawFramework(115, 346, 133, 54, FRAMEWORK_TYPE1); 1299 drawFramework(248, 346, 49, 54, FRAMEWORK_TYPE1); 1300 drawFramework(297, 346, 56, 54, FRAMEWORK_TYPE1); 1301 1302 showPushButton(PB_SAMP_PNOTE_UP); 1303 showPushButton(PB_SAMP_PNOTE_DOWN); 1304 showPushButton(PB_SAMP_STOP); 1305 showPushButton(PB_SAMP_PWAVE); 1306 showPushButton(PB_SAMP_PRANGE); 1307 showPushButton(PB_SAMP_PDISPLAY); 1308 showPushButton(PB_SAMP_SHOW_RANGE); 1309 showPushButton(PB_SAMP_RANGE_ALL); 1310 showPushButton(PB_SAMP_CLR_RANGE); 1311 showPushButton(PB_SAMP_ZOOM_OUT); 1312 showPushButton(PB_SAMP_SHOW_ALL); 1313 showPushButton(PB_SAMP_SAVE_RNG); 1314 showPushButton(PB_SAMP_CUT); 1315 showPushButton(PB_SAMP_COPY); 1316 showPushButton(PB_SAMP_PASTE); 1317 showPushButton(PB_SAMP_CROP); 1318 showPushButton(PB_SAMP_VOLUME); 1319 showPushButton(PB_SAMP_EFFECTS); 1320 1321 drawFramework(2, 366, 34, 15, FRAMEWORK_TYPE2); 1322 textOutShadow(5, 352, PAL_FORGRND, PAL_DSKTOP2, "Play:"); 1323 updateSampleEditor(); 1324 } 1325 1326 void pbEffects(void) 1327 { 1328 hidePushButton(PB_SAMP_PNOTE_UP); 1329 hidePushButton(PB_SAMP_PNOTE_DOWN); 1330 hidePushButton(PB_SAMP_STOP); 1331 hidePushButton(PB_SAMP_PWAVE); 1332 hidePushButton(PB_SAMP_PRANGE); 1333 hidePushButton(PB_SAMP_PDISPLAY); 1334 hidePushButton(PB_SAMP_SHOW_RANGE); 1335 hidePushButton(PB_SAMP_RANGE_ALL); 1336 hidePushButton(PB_SAMP_CLR_RANGE); 1337 hidePushButton(PB_SAMP_ZOOM_OUT); 1338 hidePushButton(PB_SAMP_SHOW_ALL); 1339 hidePushButton(PB_SAMP_SAVE_RNG); 1340 hidePushButton(PB_SAMP_CUT); 1341 hidePushButton(PB_SAMP_COPY); 1342 hidePushButton(PB_SAMP_PASTE); 1343 hidePushButton(PB_SAMP_CROP); 1344 hidePushButton(PB_SAMP_VOLUME); 1345 hidePushButton(PB_SAMP_EFFECTS); 1346 1347 drawFramework(0, 346, 116, 54, FRAMEWORK_TYPE1); 1348 drawFramework(116, 346, 114, 54, FRAMEWORK_TYPE1); 1349 drawFramework(230, 346, 67, 54, FRAMEWORK_TYPE1); 1350 drawFramework(297, 346, 56, 54, FRAMEWORK_TYPE1); 1351 1352 checkBoxes[CB_SAMPFX_NORMALIZATION].checked = normalization ? true : false; 1353 showCheckBox(CB_SAMPFX_NORMALIZATION); 1354 showPushButton(PB_SAMPFX_CYCLES_UP); 1355 showPushButton(PB_SAMPFX_CYCLES_DOWN); 1356 showPushButton(PB_SAMPFX_TRIANGLE); 1357 showPushButton(PB_SAMPFX_SAW); 1358 showPushButton(PB_SAMPFX_SINE); 1359 showPushButton(PB_SAMPFX_SQUARE); 1360 showPushButton(PB_SAMPFX_RESO_UP); 1361 showPushButton(PB_SAMPFX_RESO_DOWN); 1362 showPushButton(PB_SAMPFX_LOWPASS); 1363 showPushButton(PB_SAMPFX_HIGHPASS); 1364 showPushButton(PB_SAMPFX_SUB_BASS); 1365 showPushButton(PB_SAMPFX_SUB_TREBLE); 1366 showPushButton(PB_SAMPFX_ADD_BASS); 1367 showPushButton(PB_SAMPFX_ADD_TREBLE); 1368 showPushButton(PB_SAMPFX_SET_AMP); 1369 showPushButton(PB_SAMPFX_UNDO); 1370 showPushButton(PB_SAMPFX_XFADE); 1371 showPushButton(PB_SAMPFX_BACK); 1372 1373 textOutShadow(4, 352, PAL_FORGRND, PAL_DSKTOP2, "Cycles:"); 1374 drawSampleCycles(); 1375 1376 textOutShadow(121, 352, PAL_FORGRND, PAL_DSKTOP2, "Reson.:"); 1377 drawFilterResonance(); 1378 1379 textOutShadow(135, 386, PAL_FORGRND, PAL_DSKTOP2, "Normalization"); 1380 1381 textOutShadow(235, 352, PAL_FORGRND, PAL_DSKTOP2, "Bass"); 1382 textOutShadow(235, 369, PAL_FORGRND, PAL_DSKTOP2, "Treb."); 1383 1384 ui.sampleEditorEffectsShown = true; 1385 }