|  | #include "mscHack.hpp"
#include "window.hpp"
//-----------------------------------------------------
// Procedure:   constructor
//-----------------------------------------------------
void EnvelopeData::Init( int mode, int range, bool bGate, float fsegsize )
{
	m_bInitialized  = false;
    m_Mode = mode;
    m_Range = range;
    m_bGateMode = bGate;
    m_fsegsize = fsegsize;
	for( int hd = 0; hd < ENVELOPE_HANDLES; hd++ )
		m_HandleVal[ hd ] = 0.5f;
    recalcLine( -1 );
    setMode( m_Mode );
    m_bInitialized  = true;
}
//-----------------------------------------------------
// Procedure:   Preset
//-----------------------------------------------------
void EnvelopeData::Preset( int preset )
{
    int i;
    float a, div;
    if( preset < 0 || preset >= EnvelopeData::nPRESETS )
    	return;
    switch( preset )
    {
    case EnvelopeData::PRESET_CLEAR:
        resetValAll( 0.0f );
        break;
    case EnvelopeData::PRESET_SET:
        resetValAll( 1.0f );
        break;
    case EnvelopeData::PRESET_HALF:
        resetValAll( 0.5f );
        break;
    case EnvelopeData::PRESET_SIN:
        div = (float)(ENVELOPE_HANDLES - 1) / (PI * 2.0f);
        for( i = 0; i < ENVELOPE_HANDLES; i++ )
        {
            a = ( 1.0f + sinf( (float)i / div ) ) / 2.0f;
            setVal( i, a );
        }
        break;
    case EnvelopeData::PRESET_COS:
        div = (float)(ENVELOPE_HANDLES - 1) / (PI * 2.0f);
        for( i = 0; i < ENVELOPE_HANDLES; i++ )
        {
            a = ( 1.0f + cosf( (float)i / div ) ) / 2.0f;
            setVal( i, a );
        }
        break;
    case EnvelopeData::PRESET_COS_HALF:
        div = (float)(ENVELOPE_HANDLES - 1) / (PI * 1.0f);
        for( i = 0; i < ENVELOPE_HANDLES; i++ )
        {
            a = ( 1.0f + cosf( (float)i / div ) ) / 2.0f;
            setVal( i, a );
        }
        break;
    case EnvelopeData::PRESET_TRI_FULL:
        div = 1.0f / 16.0f;
        a = 0;
        for( i = 0; i < ENVELOPE_HANDLES; i++ )
        {
        	setVal( i, a );
            a += div;
        }
        break;
    case EnvelopeData::PRESET_TRI_HALF:
        div = 1.0f / 8.0f;
        a = 0;
        for( i = 0; i < ENVELOPE_HANDLES; i++ )
        {
        	setVal( i, a );
            a += div;
            if( i == 8 )
                a = 0.0f;
        }
        break;
    case EnvelopeData::PRESET_SQR:
        a = 0;
        for( i = 0; i < ENVELOPE_HANDLES; i++ )
        {
        	setVal( i, a );
            if( i == 8 )
                a = 1.0f;
        }
        break;
    default:
        break;
    }
}
//-----------------------------------------------------
// Procedure:   getActualVal
//-----------------------------------------------------
float EnvelopeData::getActualVal( float inval )
{
    float val = 0.0f;
    switch( m_Range )
    {
    case EnvelopeData_Ranges::RANGE_0to5:
        val = inval * 5.0f;
        break;
    case EnvelopeData_Ranges::RANGE_n5to5:
        val = ( ( inval * 2 ) - 1.0 ) * 5.0f;
        break;
    case EnvelopeData_Ranges::RANGE_0to10:
        val = inval * 10.0f;
        break;
    case EnvelopeData_Ranges::RANGE_n10to10:
        val = ( ( inval * 2 ) - 1.0 ) * 10.0f;
        break;
    case EnvelopeData_Ranges::RANGE_0to1:
    	val = inval;
    	break;
    case EnvelopeData_Ranges::RANGE_n1to1:
    	val = ( ( inval * 2 ) - 1.0 );
    	break;
    case EnvelopeData_Ranges::RANGE_Audio:
    	val = ( ( inval * 2 ) - 1.0 ) * AUDIO_MAX;
    	break;
    }
    return val;
}
//-----------------------------------------------------
// Function:    line_from_points				
//
//-----------------------------------------------------
void EnvelopeData::line_from_points( float x1, float y1, float x2, float y2, fLine *L )
{
    float m;
	float xdiff, ydiff;
    if( !L )
        return;
    memset( L, 0, sizeof( fLine ) );
    L->bSet  = true;
	xdiff = x2 - x1;
	xdiff = fabs( xdiff );
	ydiff = y2 - y1;
	ydiff = fabs( ydiff );
    // line is vertical
    if( xdiff < 0.000000001 )
    {
        L->fx     = x1;
        L->bVert = true;
        return;
    }
	else if( ydiff < 0.000000001 )
	{
		L->fy     = y1;
        L->bHorz = true;
		return;
	}
	//normal line
    m = (y2 - y1) / (x2 - x1);
    // point slope form
	//y = mx + b
    L->fmx = m;
    L->fb  = y1 - (m * x1);
}
//-----------------------------------------------------
// Procedure:   valfromline
//-----------------------------------------------------
float EnvelopeData::valfromline( int handle, float x )
{
    fLine *L;
    if( m_bGateMode )
        return getActualVal( m_HandleVal[ handle ] );
    L = &m_Lines[ handle ];
    if( L->bHorz )
        return getActualVal( L->fy );
    return getActualVal( (x * L->fmx) + L->fb );
}
//-----------------------------------------------------
// Procedure:   recalcLine
//-----------------------------------------------------
void EnvelopeData::recalcLine( int handle )
{
    float fx1, fx2, fy1, fy2;
    int i;
    // calc all lines
    if( handle == -1 )
    {
		for( int h = 0; h < ENVELOPE_DIVISIONS; h++ )
		{
			for( int delta = -1; delta < 1; delta++ )
			{
				i = ( h + delta ) & 0xF;
				fx1 = (m_fsegsize * i);
				fx2 = fx1 + m_fsegsize;
				fy1 = m_HandleVal[ i ];
				fy2 = m_HandleVal[ i + 1 ];
				line_from_points( fx1, fy1, fx2, fy2, &m_Lines[ i ] );
			}
		}
    }
    // calc line before and line after handle
    else
    {
        for( int delta = -1; delta < 1; delta++ )
        {
            i = ( handle + delta ) & 0xF;
            fx1 = (m_fsegsize * i);
            fx2 = fx1 + m_fsegsize;
            fy1 = m_HandleVal[ i ];
            fy2 = m_HandleVal[ i + 1 ];
            line_from_points( fx1, fy1, fx2, fy2, &m_Lines[ i ] );
        }
    }
}
//-----------------------------------------------------
// Procedure:   resetVal
//-----------------------------------------------------
void EnvelopeData::resetValAll( float val )
{
    if( !m_bInitialized )
        return;
    for( int i = 0; i < ENVELOPE_HANDLES; i++ )
    {
        m_HandleVal[ i ] = val;
    }
    recalcLine( -1 );
}
//-----------------------------------------------------
// Procedure:   setVal
//-----------------------------------------------------
void EnvelopeData::setVal( int handle, float val )
{
    if( !m_bInitialized )
        return;
    m_HandleVal[ handle ] = val;
    recalcLine( handle );
}
//-----------------------------------------------------
// Procedure:   setMode
//-----------------------------------------------------
void EnvelopeData::setMode( int Mode )
{
    if( !m_bInitialized )
        return;
    switch( Mode )
    {
    case MODE_LOOP:
        m_Clock.state = STATE_RUN;
        break;
    case MODE_REVERSE:
        m_Clock.state = STATE_RUN_REV;
        break;
    case MODE_ONESHOT:
        m_Clock.fpos = 0;
        m_Clock.state = STATE_WAIT_TRIG;
        break;
    case MODE_TWOSHOT:
        m_Clock.fpos = 0;
        m_Clock.state = STATE_WAIT_TRIG;
        break;
    case MODE_PINGPONG:
        if( m_Clock.state == STATE_WAIT_TRIG )
            m_Clock.state = STATE_RUN;
        else if( m_Clock.state == STATE_WAIT_TRIG_REV )
            m_Clock.state = STATE_RUN_REV;
        break;
    default:
        return;
    }
    m_Clock.prevstate = m_Clock.state;
    m_Mode = Mode;
}
//-----------------------------------------------------
// Procedure:   setDataAll
//-----------------------------------------------------
void EnvelopeData::setDataAll( int *pint )
{
    int j, count = 0;
    if( !m_bInitialized || !pint )
    {
        return;
    }
	for( j = 0; j < ENVELOPE_HANDLES; j++ )
	{
		m_HandleVal[ j ] = clamp( (float)pint[ count++ ] / 10000.0f, 0.0f, 1.0f );
	}
    // recalc all lines
    recalcLine( -1 );
}
//-----------------------------------------------------
// Procedure:   getDataAll
//-----------------------------------------------------
void EnvelopeData::getDataAll( int *pint )
{
    int j, count = 0;
    if( !m_bInitialized || !pint )
    {
        return;
    }
	for( j = 0; j < ENVELOPE_HANDLES; j++ )
	{
		pint[ count++ ] = (int)( m_HandleVal[ j ] * 10000.0 );
	}
}
//-----------------------------------------------------
// Procedure:   process_state
//-----------------------------------------------------
bool EnvelopeData::process_state( bool bTrig, bool bHold )
{
    switch( m_Clock.state )
    {
    case STATE_RUN:
    case STATE_RUN_REV:
        if( bHold )
        {
            m_Clock.prevstate = m_Clock.state;
            m_Clock.state = STATE_HOLD;
            break;
        }
        
        // run reverse
        if( m_Clock.state == STATE_RUN_REV )
        {
            m_Clock.fpos -= m_Clock.syncInc;
            if( m_Clock.fpos <= 0.0f )
            {
                switch( m_Mode )
                {
                case MODE_TWOSHOT:
                    m_Clock.fpos = 0;
                    m_Clock.state = STATE_WAIT_TRIG;
                    break;
                case MODE_PINGPONG:
                    m_Clock.fpos = -m_Clock.fpos;
                    m_Clock.state = STATE_RUN;
                    break;
                case MODE_REVERSE:
                default:
                    m_Clock.fpos += engineGetSampleRate();
                }
            }
        }
        // run forward
        else
        {
            m_Clock.fpos += m_Clock.syncInc;
            if( m_Clock.fpos >= engineGetSampleRate() )
            {
                switch( m_Mode )
                {
                case MODE_ONESHOT:
                    m_Clock.fpos = engineGetSampleRate() - 1.0f;;
                    m_Clock.state = STATE_WAIT_TRIG;
                    break;
                case MODE_TWOSHOT:
                    m_Clock.fpos = engineGetSampleRate() - 1.0f;
                    m_Clock.state = STATE_WAIT_TRIG_REV;
                    break;
                case MODE_PINGPONG:
                    m_Clock.fpos -= (m_Clock.fpos - engineGetSampleRate()) * 2.0f;
                    m_Clock.state = STATE_RUN_REV;
                    break;
                case MODE_LOOP:
                default:
                    m_Clock.fpos -= engineGetSampleRate();
                }
            }
        }
        break;
    case STATE_WAIT_TRIG:
        if( bTrig )
        {
            m_Clock.fpos = 0;
            m_Clock.state = STATE_RUN;
        }
        break;
    case STATE_WAIT_TRIG_REV:
        if( bTrig )
        {
            m_Clock.fpos = engineGetSampleRate();
            m_Clock.state = STATE_RUN_REV;
        }
        break;
    case STATE_HOLD:
        if( !bHold )
        {
            m_Clock.state = m_Clock.prevstate;
            break;
        }
        break;
    }
    return true;
}
//-----------------------------------------------------
// Procedure:   procStep
//-----------------------------------------------------
float EnvelopeData::procStep( bool bTrig, bool bHold )
{
    int handle;
    if( !m_bInitialized )
    	return 0.0f;
    process_state( bTrig, bHold );
    m_fIndicator = m_Clock.fpos / engineGetSampleRate();
    handle = (int)( m_Clock.fpos / ( engineGetSampleRate() / (float)ENVELOPE_DIVISIONS ) );
    return valfromline( handle, m_fIndicator * m_fsegsize * (float)ENVELOPE_DIVISIONS );
}
 |