MCPcopy Create free account
hub / github.com/FastLED/FastLED / makeVocalInFullMix

Function makeVocalInFullMix

tests/fl/audio/detector/vocal.hpp:581–651  ·  view source on GitHub ↗

Mix a vocal signal with guitar + drums/bass at a given vocal-to-backing ratio. ratio = 1.0 means equal levels, 0.5 means vocal is half as loud as backing. Matches real 3-way audio structure: guitar (broadband harmonics) + drums (kick+hihat) + optional voice. The guitar component is key — it adds formant-band energy that inflates backing formant ratio in 3-way mixes.

Source from the content-addressed store, hash-verified

579/// (kick+hihat) + optional voice. The guitar component is key — it adds
580/// formant-band energy that inflates backing formant ratio in 3-way mixes.
581inline audio::Sample makeVocalInFullMix(float vocalRatio, fl::u32 timestamp,
582 float amplitude = 16000.0f,
583 int count = 512, float sampleRate = 44100.0f) {
584 // 1. Vocal: jittered vowel /a/ (F0=150, F1=700, F2=1200)
585 auto vocal = makeJitteredVowel(150.0f, 700.0f, 1200.0f, timestamp,
586 amplitude * vocalRatio, count, sampleRate);
587
588 // 2. Guitar: harmonic series at 220Hz with 1/h^1.5 rolloff
589 // Adds energy in formant bands (F1=200-900Hz, F2=1000-3000Hz) that
590 // inflates backing formant ratio — matching real 3-way audio behavior.
591 fl::vector<fl::i16> guitarData(count, 0);
592 float guitarF0 = 220.0f;
593 float maxFreq = fl::min(5000.0f, sampleRate / 2.0f);
594 for (int h = 1; h * guitarF0 < maxFreq; ++h) {
595 float freq = guitarF0 * static_cast<float>(h);
596 float hAmp = amplitude * 0.25f / fl::powf(static_cast<float>(h), 1.5f);
597 for (int i = 0; i < count; ++i) {
598 float phase = 2.0f * FL_M_PI * freq * static_cast<float>(i) / sampleRate;
599 guitarData[i] += static_cast<fl::i16>(hAmp * fl::sinf(phase));
600 }
601 }
602
603 // 3. Bass guitar: 80 Hz fundamental with harmonics
604 fl::vector<fl::i16> bassData(count, 0);
605 float bassF0 = 80.0f;
606 for (int h = 1; h <= 5; ++h) {
607 float freq = bassF0 * static_cast<float>(h);
608 float hAmp = amplitude * 0.3f / static_cast<float>(h * h);
609 for (int i = 0; i < count; ++i) {
610 float phase = 2.0f * FL_M_PI * freq * static_cast<float>(i) / sampleRate;
611 bassData[i] += static_cast<fl::i16>(hAmp * fl::sinf(phase));
612 }
613 }
614
615 // 4. Kick drum pattern (amplitude-decayed)
616 fl::vector<fl::i16> kickData(count, 0);
617 for (int i = 0; i < count; ++i) {
618 float t = static_cast<float>(i) / sampleRate;
619 float decay = fl::expf(-t / 0.030f);
620 kickData[i] = static_cast<fl::i16>(amplitude * 0.3f * decay *
621 fl::sinf(2.0f * FL_M_PI * 55.0f * t));
622 }
623
624 // 5. Hi-hat noise (high-frequency percussion)
625 fl::fl_random rng(timestamp + 77);
626 fl::vector<fl::i16> hatData(count, 0);
627 float prevNoise = 0.0f;
628 for (int i = 0; i < count; ++i) {
629 float t = static_cast<float>(i) / sampleRate;
630 float decay = fl::expf(-t / 0.010f);
631 float noiseVal = (static_cast<float>(rng.random16()) / 32767.5f) - 1.0f;
632 float hp = noiseVal - 0.85f * prevNoise;
633 prevNoise = noiseVal;
634 hatData[i] = static_cast<fl::i16>(amplitude * 0.12f * decay * hp);
635 }
636
637 // Sum all components
638 const auto& vocalPcm = vocal.pcm();

Callers 2

vocal.hppFile · 0.85
runMixFunction · 0.85

Calls 6

makeJitteredVowelFunction · 0.85
powfFunction · 0.85
sinfFunction · 0.85
expfFunction · 0.85
random16Method · 0.80
SampleClass · 0.50

Tested by

no test coverage detected