Generate a pitched tom drum: 3 harmonics at tuningHz/2x/3x with 60ms decay + noise attack. Sits at male vocal F0 frequency (~150Hz) but lacks formant structure.
| 657 | /// Generate a pitched tom drum: 3 harmonics at tuningHz/2x/3x with 60ms decay + noise attack. |
| 658 | /// Sits at male vocal F0 frequency (~150Hz) but lacks formant structure. |
| 659 | inline Sample makePitchedTom(float tuningHz, fl::u32 timestamp, |
| 660 | float amplitude = 16000.0f, int count = 512, |
| 661 | float sampleRate = 44100.0f) { |
| 662 | fl::fl_random rng(9876); |
| 663 | fl::vector<fl::i16> data(count, 0); |
| 664 | for (int i = 0; i < count; ++i) { |
| 665 | float t = static_cast<float>(i) / sampleRate; |
| 666 | float bodyDecay = fl::expf(-t / 0.060f); |
| 667 | // 3 harmonics |
| 668 | float body = 0.0f; |
| 669 | for (int h = 1; h <= 3; ++h) { |
| 670 | float hFreq = tuningHz * static_cast<float>(h); |
| 671 | body += amplitude * 0.5f / static_cast<float>(h) * bodyDecay |
| 672 | * fl::sinf(2.0f * FL_M_PI * hFreq * t); |
| 673 | } |
| 674 | // Noise attack burst (3ms decay) |
| 675 | float attackDecay = fl::expf(-t / 0.003f); |
| 676 | float noise = (static_cast<float>(rng.random16()) / 32767.5f) - 1.0f; |
| 677 | float attack = amplitude * 0.4f * attackDecay * noise; |
| 678 | float sample = body + attack; |
| 679 | data[i] = static_cast<fl::i16>(fl::clamp(sample, -32768.0f, 32767.0f)); |
| 680 | } |
| 681 | return Sample(data, timestamp); |
| 682 | } |
| 683 | |
| 684 | } // namespace test |
| 685 | } // namespace audio |