1 #include "IPlugPolySynth.h"
2 #include "IPlug_include_in_plug_src.h"
6 #include "IKeyboardControl.h"
9 const int kNumPrograms
= 8;
12 #define TABLE_SIZE 512
15 #define M_PI 3.14159265
18 #define GAIN_FACTOR 0.2;
29 IPlugPolySynth::IPlugPolySynth(IPlugInstanceInfo instanceInfo
)
30 : IPLUG_CTOR(kNumParams
, kNumPrograms
, instanceInfo
),
39 mTable
= new double[TABLE_SIZE
];
41 for (int i
= 0; i
< TABLE_SIZE
; i
++)
43 mTable
[i
] = sin( i
/double(TABLE_SIZE
) * 2. * M_PI
);
44 //printf("mTable[%i] %f\n", i, mTable[i]);
47 mOsc
= new CWTOsc(mTable
, TABLE_SIZE
);
48 mEnv
= new CADSREnvL();
50 memset(mKeyStatus
, 0, 128 * sizeof(bool));
52 //arguments are: name, defaultVal, minVal, maxVal, step, label
53 GetParam(kAttack
)->InitDouble("Amp Attack", ATTACK_DEFAULT
, TIME_MIN
, TIME_MAX
, 0.001);
54 GetParam(kDecay
)->InitDouble("Amp Decay", DECAY_DEFAULT
, TIME_MIN
, TIME_MAX
, 0.001);
55 GetParam(kSustain
)->InitDouble("Amp Sustain", 1., 0., 1., 0.001);
56 GetParam(kRelease
)->InitDouble("Amp Release", RELEASE_DEFAULT
, TIME_MIN
, TIME_MAX
, 0.001);
58 IGraphics
* pGraphics
= MakeGraphics(this, kWidth
, kHeight
);
59 pGraphics
->AttachBackground(BG_ID
, BG_FN
);
61 IBitmap knob
= pGraphics
->LoadIBitmap(KNOB_ID
, KNOB_FN
, kKnobFrames
);
62 IText text
= IText(14);
63 IBitmap regular
= pGraphics
->LoadIBitmap(WHITE_KEY_ID
, WHITE_KEY_FN
, 6);
64 IBitmap sharp
= pGraphics
->LoadIBitmap(BLACK_KEY_ID
, BLACK_KEY_FN
);
67 int coords
[12] = { 0, 7, 12, 20, 24, 36, 43, 48, 56, 60, 69, 72 };
68 mKeyboard
= new IKeyboardControl(this, kKeybX
, kKeybY
, 48, 5, ®ular
, &sharp
, coords
);
70 pGraphics
->AttachControl(mKeyboard
);
72 IBitmap about
= pGraphics
->LoadIBitmap(ABOUTBOX_ID
, ABOUTBOX_FN
);
73 mAboutBox
= new IBitmapOverlayControl(this, 100, 100, &about
, IRECT(540, 250, 680, 290));
74 pGraphics
->AttachControl(mAboutBox
);
75 AttachGraphics(pGraphics
);
77 //MakePreset("preset 1", ... );
78 MakeDefaultPreset((char *) "-", kNumPrograms
);
81 IPlugPolySynth::~IPlugPolySynth()
88 int IPlugPolySynth::FindFreeVoice()
92 for(v
= 0; v
< MAX_VOICES
; v
++)
98 int quietestVoice
= 0;
101 for(v
= 0; v
< MAX_VOICES
; v
++)
103 double summed
= mVS
[v
].mEnv_ctx
.mPrev
;
113 DBGMSG("stealing voice %i\n", quietestVoice
);
114 return quietestVoice
;
117 void IPlugPolySynth::NoteOnOff(IMidiMsg
* pMsg
)
121 int status
= pMsg
->StatusMsg();
122 int velocity
= pMsg
->Velocity();
123 int note
= pMsg
->NoteNumber();
125 if (status
== IMidiMsg::kNoteOn
&& velocity
) // Note on
127 v
= FindFreeVoice(); // or quietest
129 mVS
[v
].mOsc_ctx
.mPhaseIncr
= (1./mSampleRate
) * midi2CPS(note
);
130 mVS
[v
].mEnv_ctx
.mLevel
= (double) velocity
/ 127.;
131 mVS
[v
].mEnv_ctx
.mStage
= kStageAttack
;
137 for (v
= 0; v
< MAX_VOICES
; v
++)
139 if (mVS
[v
].mKey
== note
)
141 if (mVS
[v
].GetBusy())
144 mVS
[v
].mEnv_ctx
.mStage
= kStageRelease
;
145 mVS
[v
].mEnv_ctx
.mReleaseLevel
= mVS
[v
].mEnv_ctx
.mPrev
;
155 void IPlugPolySynth::ProcessDoubleReplacing(double** inputs
, double** outputs
, int nFrames
)
157 // Mutex is already locked for us
158 IKeyboardControl
* pKeyboard
= (IKeyboardControl
*) mKeyboard
;
160 if (pKeyboard
->GetKey() != mKey
)
166 msg
.MakeNoteOffMsg(mKey
+ 48, 0, 0);
167 mMidiQueue
.Add(&msg
);
170 mKey
= pKeyboard
->GetKey();
174 msg
.MakeNoteOnMsg(mKey
+ 48, pKeyboard
->GetVelocity(), 0, 0);
175 mMidiQueue
.Add(&msg
);
179 if (mActiveVoices
> 0 || !mMidiQueue
.Empty()) // block not empty
181 double* out1
= outputs
[0];
182 double* out2
= outputs
[1];
187 for (int s
= 0; s
< nFrames
; ++s
)
189 while (!mMidiQueue
.Empty())
191 IMidiMsg
* pMsg
= mMidiQueue
.Peek();
193 if (pMsg
->mOffset
> s
) break;
195 int status
= pMsg
->StatusMsg(); // get the MIDI status byte
199 case IMidiMsg::kNoteOn
:
200 case IMidiMsg::kNoteOff
:
205 case IMidiMsg::kPitchWheel
:
217 for(int v
= 0; v
< MAX_VOICES
; v
++) // for each vs
223 output
+= mOsc
->process(&vs
->mOsc_ctx
) * mEnv
->process(&vs
->mEnv_ctx
);
227 output
*= GAIN_FACTOR
;
233 mMidiQueue
.Flush(nFrames
);
235 // else // empty block
240 void IPlugPolySynth::Reset()
243 IMutexLock
lock(this);
245 mSampleRate
= GetSampleRate();
246 mMidiQueue
.Resize(GetBlockSize());
247 mEnv
->setSampleRate(mSampleRate
);
250 void IPlugPolySynth::OnParamChange(int paramIdx
)
252 IMutexLock
lock(this);
257 mEnv
->setStageTime(kStageAttack
, GetParam(kAttack
)->Value());
260 mEnv
->setStageTime(kStageDecay
, GetParam(kDecay
)->Value());
263 mEnv
->setSustainLevel( GetParam(kSustain
)->Value() );
266 mEnv
->setStageTime(kStageRelease
, GetParam(kRelease
)->Value());
273 void IPlugPolySynth::ProcessMidiMsg(IMidiMsg
* pMsg
)
275 int status
= pMsg
->StatusMsg();
276 int velocity
= pMsg
->Velocity();
280 case IMidiMsg::kNoteOn
:
281 case IMidiMsg::kNoteOff
:
282 // filter only note messages
283 if (status
== IMidiMsg::kNoteOn
&& velocity
)
285 mKeyStatus
[pMsg
->NoteNumber()] = true;
290 mKeyStatus
[pMsg
->NoteNumber()] = false;
295 return; // if !note message, nothing gets added to the queue
299 mKeyboard
->SetDirty();
300 mMidiQueue
.Add(pMsg
);
303 // Should return non-zero if one or more keys are playing.
304 int IPlugPolySynth::GetNumKeys()
306 IMutexLock
lock(this);
310 // Should return true if the specified key is playing.
311 bool IPlugPolySynth::GetKeyStatus(int key
)
313 IMutexLock
lock(this);
314 return mKeyStatus
[key
];
317 //Called by the standalone wrapper if someone clicks about
318 bool IPlugPolySynth::HostRequestingAboutBox()
320 IMutexLock
lock(this);
323 // get the IBitmapOverlay to show
324 mAboutBox
->SetValueFromPlug(1.);
325 mAboutBox
->Hide(false);