SMS Harmonizer part1
Posted by hordia on July 31st, 2007
This implementation, is mainly based on many SMS pitch-shiftings (one for each voice) and a control gain for each one. Pitch controls are based on equal-tempered scale semitones, following
relation for each voice.
This was my first version of the network:

Testing it, my voice never sounded so musical, hehehe… but still awful, so I was thinking in your ears health and demos are with Elvis one
Disclaimer: all audio demos are early testing versions (still with artifacts and clicks that should be removed soon)
Elvis harmonized demo: elvis-harmonized.ogg (to hear the online/streaming version go here)
Prototype:

Configuration:

Note: demos were done without residual processing because adding residual does not improve results much and adds a lot of overhead.
Then, following xamat’s suggestions I also added a detunning effect (and delay, but this one isn’t working properly yet)

Elvis harmonized (detunned version) demo: elvis-harmonized-detunned.ogg (to hear the online/streaming version go here)
but wait! a lot of graphics and this is also a ‘coding’ blog!!! here you have some code… and btw you can see that programming under CLAM could be very easy once you get the basics…
bool SMSHarmonizer::Do( const SpectralPeakArray& inPeaks,
const Fundamental& inFund,
const Spectrum& inSpectrum,
SpectralPeakArray& outPeaks,
Fundamental& outFund,
Spectrum& outSpectrum
)
{
outPeaks = inPeaks;
outFund = inFund;
outSpectrum = inSpectrum;
TData gain0 = mInputVoiceGain.GetLastValue();
mSinusoidalGain.GetInControl("Gain").DoControl(gain0);
mSinusoidalGain.Do(outPeaks,outPeaks);
SpectralPeakArray mtmpPeaks;
Fundamental mtmpFund;
Spectrum mtmpSpectrum;
for (int i=0; i < mVoicesPitch.Size(); i++)
{
TData gain = mVoicesGain[i].GetLastValue();
if (gain<0.01) //means voice OFF
continue;
TData amount = mVoicesPitch[i].GetLastValue() + frand()*mVoicesDetuningAmount[i].GetLastValue(); //detuning
amount = CLAM_pow( 2., amount/12. ); //adjust to equal-tempered scale semitones
mPitchShift.GetInControl("PitchSteps").DoControl(amount);
mPitchShift.Do( inPeaks,
inFund,
inSpectrum,
mtmpPeaks,
mtmpFund,
mtmpSpectrum);
mSinusoidalGain.GetInControl("Gain").DoControl(gain);
mSinusoidalGain.Do(mtmpPeaks,mtmpPeaks);
TData delay = mVoicesDelay[i].GetLastValue();
if (delay>0.)
{
mPeaksDelay.GetInControl("Delay Control").DoControl(delay);
mPeaksDelay.Do(mtmpPeaks, mtmpPeaks);
}
outPeaks = outPeaks + mtmpPeaks;
if (!mIgnoreResidual)
mSpectrumAdder.Do(outSpectrum, mtmpSpectrum, outSpectrum);
}
return true;
}
The plan includes add MIDI control for each voice pitch (then will be easy to control them for example by a keyboard by the same singing person)
Next post: SMSMorph.




