CLAM-Development  1.4.0
SMSHarmonizer.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #include "SMSHarmonizer.hxx"
23 #include "ProcessingFactory.hxx"
24 
25 namespace CLAM
26 {
27 
28 namespace Hidden
29 {
30  static const char * metadata[] = {
31  "key", "SMSHarmonizer",
32  "category", "SMS Transformations",
33  "description", "SMSHarmonizer",
34  0
35  };
36  static FactoryRegistrator<ProcessingFactory, SMSHarmonizer> reg = metadata;
37 }
38 
40 {
41  CopyAsConcreteConfig( mConfig, config );
42 
43  if ( mConfig.GetNumberOfVoices()==0 )
44  {
45  AddConfigErrorMessage("The provided config object lacked NumberOfVoices value");
46  return false;
47  }
48 
49  mIgnoreResidual = mConfig.GetIgnoreResidual();
50 
51  mPitchShift.Configure( FrameTransformationConfig() );
52  SendFloatToInControl(mPitchShift,"IgnoreResidual",mIgnoreResidual);
53 
54  mInputVoiceGain.SetBounds(-2.,2.);
55  mInputVoiceGain.SetDefaultValue(0.);
56  mInputVoiceGain.DoControl(0.);
57 
58  int n_voices = mConfig.GetNumberOfVoices();
59 
60  if (n_voices>MAX_AMOUNT_OF_VOICES) n_voices = MAX_AMOUNT_OF_VOICES;
61 
62  mVoicesPitch.Resize(n_voices, "Pitch", this);
63  mVoicesGain.Resize(n_voices, "Gain", this);
64  mVoicesDetuningAmount.Resize(n_voices, "Voice Detuning", this);
65  mVoicesDelay.Resize(n_voices, "Voice Delay", this);
66  for (int i=0; i < mVoicesPitch.Size(); i++)
67  {
68  mVoicesGain[i].SetBounds(0.,2.);
69  mVoicesGain[i].SetDefaultValue(0.);
70  mVoicesGain[i].DoControl(0.);
71 
72  mVoicesPitch[i].SetBounds(-24.,24.);
73  mVoicesPitch[i].SetDefaultValue(0.); //no pitch shift
74  mVoicesPitch[i].DoControl(0.);
75 
76  mVoicesDetuningAmount[i].SetBounds(0.,1.);
77  mVoicesDetuningAmount[i].SetDefaultValue(0.);
78  mVoicesDetuningAmount[i].DoControl(0.);
79 
80  mVoicesDelay[i].SetBounds(0.,1.);
81  mVoicesDelay[i].SetDefaultValue(0.);
82  mVoicesDelay[i].DoControl(0.);
83  }
84 
85  return true;
86 }
87 
88 bool SMSHarmonizer::Do(const Frame& in, Frame& out)
89 {
90  return Do( in.GetSpectralPeakArray(),
91  in.GetFundamental(),
92  in.GetResidualSpec(),
93 
94  out.GetSpectralPeakArray(),
95  out.GetFundamental(),
96  out.GetResidualSpec()
97  );
98 }
99 
101  const SpectralPeakArray& inPeaks,
102  const Fundamental& inFund,
103  const Spectrum& inSpectrum,
104  SpectralPeakArray& outPeaks,
105  Fundamental& outFund,
106  Spectrum& outSpectrum
107  )
108 {
109  outPeaks = inPeaks;
110  outFund = inFund;
111  outSpectrum = inSpectrum; //residual processing is ignored by default, so the output residual is the input one
112 
113  TData gain0 = mInputVoiceGain.GetLastValue();
114  SendFloatToInControl(mSinusoidalGain,"Gain",gain0);
115  mSinusoidalGain.Do(outPeaks,outPeaks);
116  //TODO add detuning and delay for input voice?
117 
118  SpectralPeakArray mtmpPeaks;
119  Fundamental mtmpFund;
120  Spectrum mtmpSpectrum;
121 
122  for (int i=0; i < mVoicesPitch.Size(); i++)
123  {
124  TData gain = mVoicesGain[i].GetLastValue();
125  if (gain<0.01) //means voice OFF
126  continue;
127 
128  TData amount = mVoicesPitch[i].GetLastValue() + frand()*mVoicesDetuningAmount[i].GetLastValue(); //detuning
129  amount = CLAM_pow( 2., amount/12. ); //adjust to equal-tempered scale semitones
130 
131  SendFloatToInControl(mPitchShift,"PitchSteps",amount);
132  mPitchShift.Do( inPeaks,
133  inFund,
134  inSpectrum,
135  mtmpPeaks,
136  mtmpFund,
137  mtmpSpectrum);
138 
139  SendFloatToInControl(mSinusoidalGain,"Gain",gain);
140  mSinusoidalGain.Do(mtmpPeaks,mtmpPeaks);
141 
142  TData delay = mVoicesDelay[i].GetLastValue();
143  if (delay>0.)
144  {
145  SendFloatToInControl(mPeaksDelay,"Delay Control",delay);
146  mPeaksDelay.Do(mtmpPeaks, mtmpPeaks);
147  }
148 
149  outPeaks = outPeaks + mtmpPeaks;
150 
151  if (!mIgnoreResidual)
152  mSpectrumAdder.Do(outSpectrum, mtmpSpectrum, outSpectrum);
153  }
154  return true;
155 }
156 
157 }