Peak meter animation using BGE


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)


BGE 1.1 can export the Movie Control

The Wisegui library has been updated to support the Movie Control. The Movie Control can be exported by Bitwise Gui Editor 1.1


Using the Movie Control

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:

  1. 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.

  2. 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);
}        
    


WiseMeter in action: