AmEvent* ArpVelocityMapFilter::HandleEvent(AmEvent* event, const am_filter_params* /*params*/)
{
	if (!event) return event;
	ArpVALIDATE(mAddOn != NULL && mHolder != NULL, return event);
	event->SetNextFilter(mHolder->ConnectionAt(0) );
	if (event->Type() != event->NOTEON_TYPE) return event;
	AmNoteOn*		e = dynamic_cast<AmNoteOn*>(event);
	if (!e || !in_range(e, mFromRange) ) return event;

	int32		fromStart = mFromRange.start, fromEnd = mFromRange.end;
	int32		toStart = mToRange.start, toEnd = mToRange.end;
	/* If both the from and start are reversed, but them back to normal.
	 * Otherwise leave them skewed, to allow users to invert the range.
	 */
	if (fromEnd < fromStart && toEnd < toStart) {
		fromStart = mFromRange.end;
		fromEnd = mFromRange.start;
		toStart = mToRange.end;
		toEnd = mToRange.start;
	}
	float		scale = fabs(float(fromEnd - fromStart) / float(toEnd - toStart));
	if (mToRange.end < mToRange.start) scale = -scale;
	int32		newVel = int32(toStart + ((e->Velocity() - fromStart) * scale));
	
	if (toStart < toEnd) {
		if (newVel < toStart) newVel = toStart;
		else if (newVel > toEnd) newVel = toEnd;
	} else {
		if (newVel < toEnd) newVel = toEnd;
		else if (newVel > toStart) newVel = toStart;
	}
	e->SetVelocity(newVel);
	
	return event;
}
AmEvent* ArpAccentRandomizerFilter::HandleEvent(AmEvent* event, const am_filter_params* /*params*/)
{
	if(!event)
		return event;
	ArpVALIDATE(mAddOn != 0 && mHolder != 0, return event);
	
	event->SetNextFilter(mHolder->FirstConnection() );
	
	if( (event->Type() == event->NOTEON_TYPE) && (0 < mRandomizeAmount) ) {
		AmNoteOn* note = dynamic_cast<AmNoteOn*>(event);
		if(!note)
			return event;
		int32 delta = rand() % mRandomizeAmount;
		if(rand() % 2) // flip sign with 50% chance
			delta *= -1;
		int32 vel = note->Velocity();
		vel += delta;
		if(vel > 127)
			vel = 127;
		if(vel < 0)
			vel = 0;
		note->SetVelocity(vel);
	}
	return event;
}
AmEvent* ArpVaccineFilter::HandleEvent(AmEvent* event, const am_filter_params* params)
{
	if (!event) return event;
	if (mFrequency == 0 || mAmount == 0) return event;
	if (event->Type() != event->NOTEON_TYPE && event->Type() != event->NOTEOFF_TYPE) return event;
	if ( !ShouldVaccinate(mFrequency) ) return event;
	ArpVALIDATE(params && params->cur_signature, return event);
	const AmSignature*	curSig = params->cur_signature;
	AmSignature			sig;
	if ( !get_signature(event->StartTime(), curSig, sig) ) return event;

	int32				prox = (int32)(proximity_to_beat(event->StartTime(), sig) * 100);
	
	float	prox2 = (float)abs(mProximity - prox) / 100;
//	printf("proximity is %ld, that puts prox2 at %f\n", prox, prox2);
	if (prox2 < 0) prox2 = 0;
	else if (prox2 > 1) prox2 = 1;
	prox2 = 1 - prox2;

	/* If there are tool params, set my amount based on the param data.
	 */
	int32				amount = mAmount;
	if (params->flags&AMFF_TOOL_PARAMS) {
		if (mAmount >= 0) amount = (int32)(params->view_orig_y_pixel - params->view_cur_y_pixel);
		else amount = (int32)(params->view_cur_y_pixel - params->view_orig_y_pixel);
		if (amount < MIN_AMOUNT) amount = MIN_AMOUNT;
		else if (amount > MAX_AMOUNT) amount = MAX_AMOUNT;
	}
	
	if (event->Type() == event->NOTEON_TYPE) {
		AmNoteOn*	noe = dynamic_cast<AmNoteOn*>(event);
		if (noe) {
			int32	vel = noe->Velocity();
			float	scale = ((float)amount / 100) * prox2;
			vel = vel + (int32)(vel * scale);
			if (vel < 0) vel = 0;
			else if (vel > 127) vel = 127;
			noe->SetVelocity(vel);
		}
	} else if (event->Type() == event->NOTEOFF_TYPE) {
	}

	return event;
}