VOID
FxDpc::DpcHandler(
    __in PKDPC Dpc,
    __in PVOID SystemArgument1,
    __in PVOID SystemArgument2
    )
{
    UNREFERENCED_PARAMETER(Dpc);
    UNREFERENCED_PARAMETER(SystemArgument1);
    UNREFERENCED_PARAMETER(SystemArgument2);

    FX_TRACK_DRIVER(GetDriverGlobals());
    
    if (m_Callback != NULL) {

        FxPerfTraceDpc(&m_Callback);

        if (m_CallbackLock != NULL) {
            KIRQL irql = 0;

            m_CallbackLock->Lock(&irql);
            m_Callback((WDFDPC)(this->GetObjectHandle()));
            m_CallbackLock->Unlock(irql);
        }
        else {
           m_Callback((WDFDPC)(this->GetObjectHandle()));
        }
    }
}
VOID
FxWorkItem::WorkItemHandler(
    VOID
    )
{
    KIRQL irql;
    
    FX_TRACK_DRIVER(GetDriverGlobals());

    Lock(&irql);

    //
    // Mark the workitem as no longer enqueued and completed
    //
    // The handler is allowed to re-enqueue, so mark it before the callback
    //
    m_Enqueued = FALSE;

    m_WorkItemRunningCount++;
    
    Unlock(irql);

    if (m_CallbackLock != NULL) {
        m_CallbackLock->Lock(&irql);
#if FX_IS_KERNEL_MODE
        FxPerfTraceWorkItem(&m_Callback);
#endif
        m_Callback(GetHandle());
        m_CallbackLock->Unlock(irql);
    }
    else {
#if FX_IS_KERNEL_MODE
        FxPerfTraceWorkItem(&m_Callback);
#endif
        m_Callback(GetHandle());
    }

    Lock(&irql);

    m_WorkItemRunningCount--;

    //
    // The workitem can be re-enqueued by the drivers
    // work item handler routine. We can't set the work
    // item completed event until we are sure there are
    // no outstanding work items.
    //

    if (m_WorkItemRunningCount == 0L && m_Enqueued == FALSE) {
        m_WorkItemCompleted.Set();
    }

    Unlock(irql);
}
Esempio n. 3
0
void CountdownTimer::UpdateCountdown(float dt)
{
	if(!m_bStarted)
	{
		return;
	}

	if(!m_bPaused)
	{
		m_elapsedTime += dt;
	}

	if(m_elapsedTime >= m_timeOutTime)
	{
		if(!m_bFinished)
		{
			// We have reached our countdown time, call our function callback
			if(m_Callback)
			{
				m_Callback(m_pCallbackData);
			}

			if(m_bLooping)
			{
				// If we are a looping timer, then just reset the elapsed time
				m_elapsedTime = 0.0f;
			}
			else
			{
				// We are not looping, so set our finished flag
				m_bFinished = true;
			}
		}
	}
}
Esempio n. 4
0
void CRealTimer::DoTimer()
{
	CBenchmark	bm;
	float	Error = 0;
	float	Period = 1.0f / m_Freq;
	int		PrevReset = 0;
	UINT	Clock = 0;
	HANDLE	ha[2] = {m_Event, m_Timer};
	while (m_State != DIE) {
		__int64	Due = round((Period - Error) * -1e7);	// relative UTC
		SetWaitableTimer(m_Timer, (LARGE_INTEGER *)&Due, 0, NULL, NULL, 0);
		WaitForMultipleObjects(m_State + 1, ha, FALSE, INFINITE);
		m_State = m_NewState;
		if (m_State == RUN) {
			m_Callback(m_Cookie);
			Clock++;
			Error = float(bm.Elapsed() - Clock * Period);
			if (m_Reset != PrevReset) {
				Period = 1.0f / m_Freq;
				PrevReset = m_Reset;
				Clock = 0;
				Error = 0;
				bm.Reset();
			}
		}
	}
}
Esempio n. 5
0
    void OnResponse( const char* data, size_t dataSize, CURLcode result )
    {
        m_RequestResult = result;

        m_Callback( *this, data, dataSize );
        
        m_Completed = true;
    }
Esempio n. 6
0
void MenuItem::MenuItemPressed()
{
	// Call the callback function callback if this class is just a simple button
	if(m_Callback)
	{
		m_Callback(m_pCallbackData);
	}
}
Esempio n. 7
0
bool CQuestionBox::OnButtonClick ( CGUIElement* pElement )
{
    m_uiLastButton = reinterpret_cast < unsigned int > ( pElement->GetUserData () );
    if ( m_Callback)
        m_Callback ( m_CallbackParameter, m_uiLastButton );
    
    if ( m_CallbackEdit && !m_EditList.empty() ) //Just grab the first editbox for now
        m_CallbackEdit ( m_CallbackParameter, m_uiLastButton, m_EditList[0]->GetText() );
    return true;
}
Esempio n. 8
0
void Transform::RebuildMatrix()
{
    m_LocalToWorldMatrix =
        Matrix4x4::Translate(m_Position) *
        Matrix4x4::RotateByZ(m_Rotation.z * Mathf::Deg2Rad)*
        Matrix4x4::RotateByY(m_Rotation.y * Mathf::Deg2Rad)*
        Matrix4x4::RotateByX(m_Rotation.x * Mathf::Deg2Rad);
    m_WorldToLocalMatrix = m_LocalToWorldMatrix.Inversed();
    if (m_Callback != nullptr)
        m_Callback();
}
Esempio n. 9
0
void MyRTSPServer::MyRTSPClientSession::handleCmd_PLAY(ServerMediaSubsession* subsession, char const* cseq, char const* fullRequestStr)
{
    printf( "====== MyRTSPServer::MyRTSPClientSession::handleCmd_PLAY ====== this=%p \n", this );
    RTSPServer::RTSPClientSession::handleCmd_PLAY( subsession, cseq, fullRequestStr );

    if ( NULL != m_Callback )
    {
        ReferrencePtr<uint8_t,DefaultObjectsDeleter> EventData;
        m_Callback( m_UserData, RTSP_ET_PLAY, EventData, 0 );
    }
}
Esempio n. 10
0
	void DelayedAction::CreateTimer()
	{
		m_IsPaused = true;
		m_pParent->GetScene()->GetStopwatch()->CreateTimer(
			m_UniqueID, m_Seconds, false, false,
			[&] () {
				if(m_Callback)
				{
					m_Callback();
					m_IsPaused = false;
					m_HasStarted = true;
				}
				Destroy();
			}, false);
	}
Esempio n. 11
0
void Button::MouseClicked(const MouseEvent& lEvent)
{
	if(IsDisabled())
	{
		return;
	}

	// Call the function if this class has a derived sub-class
	OnMouseClicked();

	if(m_bChangeLabelText)
	{
		if(IsHover())
		{
			for(unsigned int i = 0; i < m_vpAddedComponentList.size(); i++)
			{
				if(m_vpAddedComponentList[i]->GetComponentType() == EComponentType_Label)
				{
					((Label*)m_vpAddedComponentList[i])->SetColour(m_hoverLabelColour);
				}
			}
			m_label.SetColour(m_hoverLabelColour);
		}
		else
		{
			for(unsigned int i = 0; i < m_vpAddedComponentList.size(); i++)
			{
				if(m_vpAddedComponentList[i]->GetComponentType() == EComponentType_Label)
				{
					((Label*)m_vpAddedComponentList[i])->SetColour(m_normalLabelColour);
				}
			}
			m_label.SetColour(m_normalLabelColour);
		}
	}

	// Call the callback function callback if this class is just a simple button
	if(m_Callback)
	{
		m_Callback(m_pCallbackData);
	}
}
Esempio n. 12
0
void Active::Consume(){
    std::unique_lock<std::mutex> lock(m_IOMutex);
	while(m_Queue.empty()){
		m_ConditionVar.wait(lock);
	}

	m_SwapQueue.swap(m_Queue);
	lock.unlock();

	while(!m_SwapQueue.empty()){
		Buffer* pBuffer = m_SwapQueue.front();
		m_SwapQueue.pop();

		m_Callback(pBuffer);
		--m_PendingWorkNum;
		if (pBuffer){
            delete pBuffer;
		}
	}
}
Esempio n. 13
0
	virtual bool Process(void) override { m_Callback(m_Param1, m_Param2); return true; }
Esempio n. 14
0
	virtual bool Process(void) override { m_Callback(); return true; }
void CSliderCtrlEx::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) 
{
	int loopMax = colorList.GetSize();	// number of color ranges to process
	LPNMCUSTOMDRAW lpCustDraw = (LPNMCUSTOMDRAW)pNMHDR;

	////////////////////////////////////////////////////////////////////////////////
	// OnCustomDraw() is called at many different stages during the painting process
	// of the control. We only care about the PREPAINT state or the ITEMPREPAINT
	// state and not always then.
	//
	// If we want to be notified about subcontrol painting, we have to say so when
	// we get the initial PREPAINT message.
	////////////////////////////////////////////////////////////////////////////////
	if(lpCustDraw->dwDrawStage == CDDS_PREPAINT)
	{
		// should we report slider's position?
		int curVal = GetPos();
		if((m_Callback != NULL)	&& (curVal != m_oldPosition))
		{
			m_oldPosition = curVal;
			m_Callback(m_p2Object, m_data1, curVal, m_IsDragging);
		}

		// If we don't have any special coloring to do, skip all the silliness...
		if(loopMax <= 0)
		{
			*pResult = CDRF_DODEFAULT;
		}
		else
		{
			// We want to be informed when each part of the control is being
			// processed so we can intercept the channel drawing.
			*pResult = CDRF_NOTIFYITEMDRAW;	// send messages for each piece-part
		}
		return;
	}


	///////////////////////////////////////////////////////////////////////////////
	// A slider (track control) is drawn in several steps:
	//	1. Erase
	//	2. Tics
	//	3. Channel
	//	4. Thumb
	//
	// It would be nice to capture when the background has been painted and
	// before the other sub-pieces have been painted. Then we could just
	// substitute our own painting routine. But this doesn't seem to be
	// available.
	//
	// So this routine captures the tics by inserting operations before
	// painting the thumb.
	//
	// Look at the help on NMCUSTOMDRAW for complete details, but the pNMHDR
	// pointer looks at a structure like:
	//
	// typedef struct tagNMCUSTOMDRAWINFO {
    //	 NMHDR  hdr;
    //	 DWORD  dwDrawStage;	// This indicates what stage of the drawing process is involved
    //	 HDC    hdc;			// graphics context of the control (or sub-component)
    //	 RECT   rc;
    //	 DWORD  dwItemSpec;	// This is the particular piece-part of the slider involved
    //	 UINT   uItemState;
    //	 LPARAM lItemlParam;
	// } NMCUSTOMDRAW
	//
	// The stages include CDDS_PREPAINT, which is just before painting of the entire
	// control. However, unless the *pResult parameter is set to CDRF_NOTIFYITEMDRAW,
	// we will get notification for the control as a whole, not for each piece-part.
	// So the first thing to do is set *pResult. Thereafter, we must intercept
	// the sub-parts.
	//
	// We don't care about painting the background (we will re-paint later on). We
	// don't care about PREPAINT on the CHANNEL or the TICS since we will overwrite
	// everything when we get to the THUMB.
	/////////////////////////////////////////////////////////////////////////////////

	if((lpCustDraw->dwDrawStage == CDDS_ITEMPREPAINT) && (lpCustDraw->dwItemSpec != TBCD_THUMB))
	{
		*pResult = CDRF_DODEFAULT;
		return;
	}

	// get channel orientation
	BOOL IsVertical = (TBS_VERT & GetStyle()) ? TRUE : FALSE;

	// Get the coordinates of the control's window
	CRect crect;
	GetClientRect(crect);	// client coordinates (top = left = 0, bottom = height, right = width)

	// Much of this is "paraphrased" from Nic Wilson's work -- see the header file
	//////////////////////////////////////////////////////////////////////////////////
	// This bit does the tics marks transparently.
	// Create a memory dc to hold a copy of the oldbitmap data that includes the tics,
	// because when we add the background in we will lose the tic marks.
	///////////////////////////////////////////////////////////////////////////////////
	CDC *pDC = CDC::FromHandle(lpCustDraw->hdc);
	CDC SaveCDC;
	CBitmap SaveCBmp;

	//set the colours for the monochrome mask bitmap
	COLORREF crOldBack = pDC->SetBkColor(RGB(0,0,0));			// set to Black
	COLORREF crOldText = pDC->SetTextColor(RGB(255,255,255));	// set to White

	int iWidth  = crect.Width();	// channel width
	int iHeight = crect.Height();	// channel height

	////////////////////////////////////////////////////////////////////////////
	// Create an in-memory copy of displayed bitmap, including the tics.
	// This is a monochrome bitmap since it was created from a memory DC.
	// If it had been created from pDC (an actual device DC, not a memory
	// DC) then this would be something with 8, 16, 24, or 32 bits per pixel.
	//
	// This will have a black background, with the tic marks in white.
	//
	// For reasons I don't yet understand, this saves only the tic marks and
	// the channel's centerline (both originally in black), and not the other
	// colors (such as drawn AROUND the channel's centerline). I am not sure
	// what would have happened if the tic marks were not black...
	////////////////////////////////////////////////////////////////////////////
	SaveCDC.CreateCompatibleDC(pDC);
	SaveCBmp.CreateCompatibleBitmap(&SaveCDC, iWidth, iHeight);
	CBitmap* SaveCBmpOld = (CBitmap *)SaveCDC.SelectObject(SaveCBmp);
	SaveCDC.BitBlt(0, 0, iWidth, iHeight, pDC, crect.left, crect.top, SRCCOPY);

	if(m_dumpBitmaps)	// debugging stuff
	{
		SaveBitmap("MonoTicsMask.bmp",SaveCBmp);
	}

	// Do as much of this stuff in memory as possible, then blit it to the screen
	CDC memDC;
	memDC.CreateCompatibleDC(pDC);
	CBitmap memBM;
	memBM.CreateCompatibleBitmap(pDC,iWidth,iHeight);	// create from pDC, not memDC
	CBitmap *oldbm = memDC.SelectObject(&memBM);

	////////////////////////////////////////////////////////////////////////////////
	// copy screen bitmap to memory bitmap for manipulation. If this is the very
	// first time the control has been updated, the screen bitmap will show only
	// the tic marks (in black) and the default background color (RGB(214,207,189)).
	// If the control has been updated before, remnants of the previously drawn
	// background color ranges will also show up.
	////////////////////////////////////////////////////////////////////////////////
	memDC.BitBlt(0,0,iWidth,iHeight,pDC,0,0,SRCCOPY);

	if(m_dumpBitmaps)	// debugging
	{
		SaveBitmap("ScrnStart.bmp",memBM);
	}

	/////////////////////////////////////////////////////////////////////////////
	// Color parts of the channel if necessary. It SHOULD be necessary since we
	// don't get notifications unless there are colors to print, but we may have
	// a race condition and it is best to check.
	/////////////////////////////////////////////////////////////////////////////
	if(loopMax)
	{
		/////////////////////////////////////////////////////////////////////////////////
		// We need to draw colors over the subrange of the channel that the center of the
		// thumb traverses, rather than the entire client window. Later on, extend these
		// colors outwards to the ends of the client window (for nicer appearance). This
		// allows for more precise correlation with color and thumb position.
		/////////////////////////////////////////////////////////////////////////////////
		CRect chanRect;
		GetChannelRect(&chanRect);
		CRect thmbRect;
		GetThumbRect(&thmbRect);

		// For unknown reasons, GetChannelRect() returns a rectangle
		// as though it were a horizonally oriented slider, even if it isn't!
		if(IsVertical)
		{
			CRect n;	// could probably just change chanRect directly
			n.left = chanRect.top;
			n.right = chanRect.bottom;
			n.top = chanRect.left;
			n.bottom = chanRect.right;
			n.NormalizeRect();
			chanRect.CopyRect(&n);
		}

		// Offset into client rectangle for beginning of coloring range
		int Offset = chanRect.left + thmbRect.Width()/2;
		if(IsVertical)
		{
			Offset = chanRect.top + thmbRect.Height()/2;
		}

		// Range for center of thumb on the channel
		int ht = chanRect.Height() - thmbRect.Height();
		int wd = chanRect.Width()  - thmbRect.Width();

		// scaling between control range and bitmap
		int min,max;
		GetRange(min,max);	// range of values for the slider
		double scale = (double(max) - double(min))/double(IsVertical ? ht : wd);

		BOOL gotStartColor = FALSE;
		BOOL gotEndColor = FALSE;
		COLORREF startColor = 0, endColor = 0;

		int loop;	// Loop through the array of color ranges
		for(loop = 0; loop < loopMax; loop++)
		{
			clrRange clr;
			clr = colorList[loop];
			
			// Get the good values. If not set, then entire range is good
			int lval = clr.lval;
			int hval = clr.hval;
			if((lval < min) || (lval > max)) lval = min;
			if((hval > max) || (hval < min)) hval = max;

			if(lval == min)
			{
				gotStartColor = TRUE;
				startColor = clr.strColor;
			}
			if(hval == max)
			{
				gotEndColor = TRUE;
				endColor = clr.endColor;
			}

			int minVal = lval - min;	// offset into bitmap for this color
			minVal = int(double(minVal)/scale);

			// width (or height for vertical slider) inside bitmap for this color
			int widthVal = hval - lval;
			widthVal = int((double(widthVal)/scale) + 1.0);			
			
			// For drawing a gradient, we need to know the individual RGB values
			int sR,eR,sG,eG,sB,eB;	// start and end R, G, and B values
			sR = GetRValue(clr.strColor);
			eR = GetRValue(clr.endColor);
			sG = GetGValue(clr.strColor);
			eG = GetGValue(clr.endColor);
			sB = GetBValue(clr.strColor);
			eB = GetBValue(clr.endColor);

			if(GradientFill != NULL)
			{
				TRIVERTEX vert[2];	// for specifying range to gradient fill
				GRADIENT_RECT gRect;

// Warning C4244: conversion from 'int' to 'unsigned short', possible loss of data
#pragma warning (push)
#pragma warning (disable : 4244)
				vert[0].Red   = sR<<8;	// expects 16-bit color values!
				vert[0].Green = sG<<8;
				vert[0].Blue  = sB<<8;
				vert[0].Alpha = 0;		// no fading/transparency
				
				vert[1].Red   = eR<<8;
				vert[1].Green = eG<<8;
				vert[1].Blue  = eB<<8;
				vert[1].Alpha = 0;
#pragma warning (pop)

				gRect.UpperLeft = 0;
				gRect.LowerRight = 1;
				
				BOOL retval;
				if(IsVertical)	// vertically oriented?
				{
					vert[0].x = 0;
					vert[0].y = Offset + minVal;
					vert[1].x = iWidth;
					vert[1].y = Offset + minVal + widthVal;
					retval = GradientFill(memDC,vert,2,&gRect,1,GRADIENT_FILL_RECT_V);
				}
				else
				{
					vert[0].x = Offset + minVal;
					vert[0].y = 0;
					vert[1].x = Offset + minVal + widthVal;
					vert[1].y = iHeight;
					retval = GradientFill(memDC,vert,2,&gRect,1,GRADIENT_FILL_RECT_H);
				}
			}
			else
			{
				// Homebrew version of GradientFill for rectangles -- works pretty well, sort of.
				int i;
				for(i = 0; i < widthVal; i++)	// for each pixel column in bitmap color range
				{
					int R = sR;
					int G = sG;
					int B = sB;
					if(widthVal)
					{
						R += ::MulDiv(eR - sR, i, widthVal);
						G += ::MulDiv(eG - sG, i, widthVal);
						B += ::MulDiv(eB - sB, i, widthVal);
					}

					if(IsVertical)
					{
						// widthVal really refers to height
						//memDC.FillSolidRect(0,minVal+i,iWidth,widthVal-i,GetNearestColor(memDC,RGB(R,G,B)));
						memDC.FillSolidRect(
							0,						// starting X value
							Offset + minVal + i,	// starting Y value
							iWidth,					// full width
							1,						// one pixel height
							GetNearestColor(memDC,RGB(R,G,B)));
					}
					else
					{
						//memDC.FillSolidRect(minVal+i,0,widthVal-i,iHeight,GetNearestColor(memDC,RGB(R,G,B)));
						memDC.FillSolidRect(
							Offset + minVal + i,	// Starting X value
							0,						// Starting Y value
							1,						// 1 pixel wide
							iHeight,				// full height
							GetNearestColor(memDC,RGB(R,G,B)));
					}
				}
			}
		}

		if(m_extendColors)
		{
			// If we have put in colors at the slider ends, then extend those same
			// colors to the rest of the background. We could try to determine the
			// colors by examining the bitmap, but this is awkward and it is just
			// as easy to grab them on-the-fly in the coloring loop above.
			//
			// If you want to see why this is done, just set m_extendColors to FALSE
			// and take a look at the control. Ugly. But there might be a legitimate
			// reason for it so leave the option to suppress.
			if(IsVertical)
			{
				if(gotStartColor)
				{
					memDC.FillSolidRect(0, 0, iWidth, Offset, startColor);
				}
				if(gotEndColor)
				{
					memDC.FillSolidRect(0, iHeight - Offset - 1, iWidth, Offset, endColor);
				}
			}
			else
			{
				if(gotStartColor)
				{
					memDC.FillSolidRect(0, 0, Offset, iHeight, startColor);
				}
				if(gotEndColor)
				{
					memDC.FillSolidRect(iWidth - Offset - 1, 0, Offset, iHeight, endColor);
				}
			}
		}
	}

	// The screen bitmap should now have only the color ranges filled in, no tic
	// marks should be visible.
	if(m_dumpBitmaps)	// debugging
	{
		SaveBitmap("ScrnColors.bmp",memBM);
	}
	
	//////////////////////////////////////////////////////////////
	// More "paraphrasing" from Nic Wilson's work...
	//////////////////////////////////////////////////////////////

	////////////////////////////////////////////////////////////////////////////
	// At this point, memDC's bitmap contains just the color ranges drawn above.
	// No tic marks are visible. Doing SRCINVERT with the mask will draw in the
	// tic marks, but all the colors will be backwards. Also, the tics will be
	// whatever color was drawn in the color range stuff, rather than solid,
	// normal tic marks. SRCINVERT means the RGB values are changed by subtracting
	// from 255:
	//
	//		RGB(255,0,0)    --> RGB(0,255,255)
	//		RGB(247,8,0)    --> RGB(8,247,255)
	//		RGB(214,40,255) --> RGB(41,215,0)
	//
	/////////////////////////////////////////////////////////////////////////////
	memDC.SetBkColor(pDC->GetBkColor());
	memDC.SetTextColor(pDC->GetTextColor());
	memDC.BitBlt(0, 0, iWidth, iHeight, &SaveCDC, 0, 0, SRCINVERT);

	if(m_dumpBitmaps)	// debugging
	{
		SaveBitmap("ScrnInvert.bmp",memBM);
	}

	// Change the tic marks from the color range to the background color. This
	// changes only the tic marks (and the channel centerline) and leaves the
	// rest alone. The tic marks wind up black.
	memDC.BitBlt(0, 0, iWidth, iHeight, &SaveCDC, 0, 0, SRCAND);

	if(m_dumpBitmaps)	// debugging
	{
		SaveBitmap("ScrnAnd.bmp",memBM);
	}

	// Finally, invert the color ranges to their normal values. Since the tic
	// marks in the SaveCDC bitmap are white, they get inverted to black.
	memDC.BitBlt(0, 0, iWidth, iHeight, &SaveCDC, 0, 0, SRCINVERT);

	if(m_dumpBitmaps)	// debugging
	{
		SaveBitmap("ScrnFinal.bmp",memBM);
	}
	
	// Now copy out to screen
	pDC->BitBlt(0,0,iWidth,iHeight,&memDC,0,0,SRCCOPY);

	// restore and clean up
	pDC->SetBkColor(crOldBack);
	pDC->SetTextColor(crOldText);
	DeleteObject(SelectObject(SaveCDC, SaveCBmpOld));
	DeleteDC(SaveCDC);
	DeleteObject(SelectObject(memDC,oldbm));
	DeleteDC(memDC);

	*pResult = CDRF_DODEFAULT;

	m_dumpBitmaps = FALSE;	// only do this once!
}
Esempio n. 16
0
 bool Collider::onCollision(const irr::scene::ISceneNodeAnimatorCollisionResponse& a_Animator)
 {
     return m_Callback(a_Animator.getCollisionNode());
 }
int CMultiStepSequencerFilter::OnProcess(const std::vector<void *> &SourceBuffers,
                                   const std::vector<void *> &DestinationBuffers,
                                   const std::vector<std::shared_ptr<IMidiRenderer>> /*MidiRenderers*/,
                                   const std::vector<std::shared_ptr<IMidiHandler> > /*MidiHandlers*/,
                                   int NumFrames,
                                   std::uint32_t /*TimeStamp*/)
{
    const float* ClockInBuffer = (const float*)(SourceBuffers[0]);
    float* VelocityOutBuffer = (float*)(DestinationBuffers[0]);
    float* FreqOutBuffer = (float*)(DestinationBuffers[1]);
    float* GateOutBuffer = (float*)(DestinationBuffers[2]);
    float* TriggerOutBuffer = (float*)(DestinationBuffers[3]);

    if(ClockInBuffer)
    {
        const float* ClockInBufferEnd = ClockInBuffer + NumFrames;
        while(ClockInBuffer<ClockInBufferEnd)
        {
            if(m_ClockIn.RisingEdge(*ClockInBuffer))
            {
                m_MultiStepSequencer.AdvanceClock();
                // these values can only change upon advance clock of the sequencer!
                m_Frequency = m_MultiStepSequencer.GetFrequency();
                m_Velocity = m_MultiStepSequencer.GetVelocity();
                m_Gate = m_MultiStepSequencer.GetGate();
            }

            // this is not the optimal way, but works correctly
            if(FreqOutBuffer)
            {
                *FreqOutBuffer = m_Frequency;
                ++FreqOutBuffer;
            }
            if(VelocityOutBuffer)
            {
                *VelocityOutBuffer = m_Velocity;
                ++VelocityOutBuffer;
            }
            if(GateOutBuffer)
            {
                *GateOutBuffer = m_Gate;
                ++GateOutBuffer;
            }
            if(TriggerOutBuffer)
            {
                *TriggerOutBuffer = m_GateToTrigger(m_Gate);
                ++TriggerOutBuffer;
            }

            ++ClockInBuffer;
        }
    }
    else
    { // no clock in => no change
        if(FreqOutBuffer)
        {
            std::fill(FreqOutBuffer, FreqOutBuffer+NumFrames, m_Frequency);
        }
        if(VelocityOutBuffer)
        {
            std::fill(VelocityOutBuffer, VelocityOutBuffer+NumFrames, m_Velocity);
        }
        if(GateOutBuffer)
        {
            std::fill(GateOutBuffer, GateOutBuffer+NumFrames, m_Gate);
        }
        if(TriggerOutBuffer)
        {
            std::fill(TriggerOutBuffer, TriggerOutBuffer+NumFrames, 0);
        }
    }

    //?? here ??
    m_Callback(m_MultiStepSequencer.GetCurrentStep());

    return 0;
}