Layer 1
size: 16x128
|
Layer 2
size: 16x128, semi-transparent
|
Layer 3
16 stacked rectangles (16x8). Solid border, transparent fill
|
Animate the second layer so that it shifts upwards, setting as many frames as the small rectangles plus one (16 + 1 in this case)
The Wisegui library has been updated to support the Movie Control. The Movie Control can be exported by Bitwise Gui Editor 1.1
The value associated with a Movie Control selects the index of the movie frame to display.
The following example has two Movie Controls, one for the left channel (movLeftMeter) and on for the right channel (movRightMeter).
There are two ways to update a control using RequestControlUpdate:
The control has a value that is wrapped by ParamInfo. This value is stored outside the gui and the View (gui) can update its associated control "indirectly", asking the vst for its value. This request is identified by UPDATE_REQ_TYPE_INDIRECT.
The control has a value as long as the gui is open and the control "temporarily" handles a value stored outside the the gui. The value is set "directly" (and immediately) upon the update request. To use this update method, make sure the gui is open and the current view contains the control you want to update. This request is identified by UPDATE_REQ_TYPE_DIRECT.
PeakWise class (the engine)
// Thread unsigned int PeakWise::Refresher(void *ref) { PeakWise *pw = (PeakWise *)ref; HANDLE evts[] = {pw->timer_event, pw->quit_event}; for (;;) { DWORD wres = WaitForMultipleObjects(2, evts, false, INFINITE); if (wres == WAIT_FAILED) break; if (wres == WAIT_OBJECT_0 + 1) // quit_event break; int l, r; if (pw->queue.Dequeue(&l, &r)) { pw->buddy->GetGui()->RequestControlUpdate( movLeftMeter, l, UPDATE_REQ_TYPE_DIRECT); pw->buddy->GetGui()->RequestControlUpdate( movRightMeter, r, UPDATE_REQ_TYPE_DIRECT); } } _endthreadex(0); return 0; }
void PeakWise::Start(float SampleRate) { int rt = 50; // msec maxl = maxr = -1; frames_read = 0; refresh_time = rt / 1000.f; frames_refresh = (int)(refresh_time * SampleRate); ... }
void PeakWise::DataIn(float *inl, float *inr, int frames) { int frames_needed = frames_refresh - frames_read; while (frames >= frames_needed) { updatePeak(inl, inr, frames_needed); if (buddy->IsGuiOpen()) { int indexl = LevelToIndex(maxl); int indexr = LevelToIndex(maxr); queue.Enqueue(indexl, indexr); } frames -= frames_needed; inl += frames_needed; inr += frames_needed; maxl = maxr = -1; frames_read = 0; frames_needed = frames_refresh; } if (frames > 0) { updatePeak(inl, inr, frames); frames_read += frames; } }
void PeakWise::updatePeak(float *framesl, float *framesr, int count) { for (int i = 0; i < count; i++) { if (fabs(framesl[i]) > maxl) maxl = fabs(framesl[i]); if (fabs(framesr[i]) > maxr) maxr = fabs(framesr[i]); } }
int PeakWise::LevelToIndex(double level) { double dbmin = -120; double min = pow(10, dbmin / 20.0); int zerodb_index = 12; if (level < 0) level = -level; if (level < min) level = min; double db = 20 * log10(level); int index = (int)(zerodb_index - zerodb_index * db / dbmin); return index; }
Vst
void WiseMeter::setSampleRate(float sampleRate) { sample_rate = sampleRate; } void WiseMeter::resume() { engine->Start(sample_rate); } void WiseMeter::suspend() { engine->Stop(); } void WiseMeter::processReplacing(float **inputs, float **outputs, VstInt32 frames) { float *outl = outputs[0]; float *outr = outputs[1]; float *inl = inputs[0]; float *inr = inputs[1]; memcpy(outl, inl, frames * sizeof(float)); memcpy(outr, inr, frames * sizeof(float)); engine->DataIn(inl, inr, frames); }