Skip to content

Commit

Permalink
Refactoring and optimizing for 1M sps playback.
Browse files Browse the repository at this point in the history
  • Loading branch information
laoo committed Dec 29, 2023
1 parent 7803989 commit 978eb16
Showing 1 changed file with 69 additions and 79 deletions.
148 changes: 69 additions & 79 deletions emu/cores/mikey.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ static int64_t min_i64( int64_t v1, int64_t v2 )
return v1 > v2 ? v2 : v1;
}

static int64_t max_i64( int64_t v1, int64_t v2 )
static int64_t clamp0_i64( int64_t v )
{
return v1 < v2 ? v2 : v1;
return v > 0 ? v : 0;
}

// mikey_timer_t::CONTROLA : uint8_t
Expand Down Expand Up @@ -221,16 +221,19 @@ static uint8_t mikey_timer_getCount( mikey_timer_t* timer, int64_t tick )
}

//mikey_timer_t private:
static int64_t mikey_timer_scaleDiff( const mikey_timer_t* timer, int64_t older, int64_t newer )
static uint64_t mikey_timer_scaleDiff( const mikey_timer_t* timer, uint64_t older, uint64_t newer )
{
int64_t const mask = (int64_t)( ~0ull << ( timer->mAudShift + 4 ) );
uint64_t const mask = ~0ull << ( timer->mAudShift + 4 );
return ( ( newer & mask ) - ( older & mask ) ) >> ( timer->mAudShift + 4 );
}

static void mikey_timer_updateValue( mikey_timer_t* timer, int64_t tick )
{
if ( timer->mEnableCount )
timer->mValue = (uint8_t)max_i64( (int64_t)0, timer->mValue - mikey_timer_scaleDiff( timer, timer->mValueUpdateTick, tick ) );
{
int64_t const scaledDiff = ( int64_t )mikey_timer_scaleDiff( timer, ( uint64_t )timer->mValueUpdateTick, ( uint64_t )tick );
timer->mValue = ( uint8_t )clamp0_i64( ( int64_t )timer->mValue - scaledDiff );
}
timer->mValueUpdateTick = tick;
}

Expand Down Expand Up @@ -404,14 +407,13 @@ static void mikey_audio_channel_trigger( mikey_audio_channel_t* ac )


/*
"Queue" holding event timepoints.
- 4 channel timer fire points
- 1 sample point
"Queue" holding events of channel timers fire timepoints.
Time is in 16 MHz units but only with 1 MHz resolution.
Four LSBs are used to encode event kind 0-3 are channels, 4 is sampling.
Two LSBs are used to encode channel number.
*/
// mikey_action_queue_t
#define AQ_TAB_SIZE 5
#define AQ_TAB_SIZE 4
#define AQ_TAB_MASK ( AQ_TAB_SIZE - 1 )
typedef struct
{
int64_t mTab[AQ_TAB_SIZE];
Expand All @@ -427,28 +429,16 @@ static void mikey_action_queue_ActionQueue( mikey_action_queue_t* aq )

static void mikey_action_queue_push( mikey_action_queue_t* aq, int64_t value )
{
size_t idx = value & 15;
if ( idx < AQ_TAB_SIZE )
{
if ( value & ~15 )
{
//writing only non-zero values
aq->mTab[idx] = value;
}
}
aq->mTab[value & AQ_TAB_MASK] = value;
}

static int64_t mikey_action_queue_pop( mikey_action_queue_t* aq )
{
int64_t min1 = min_i64( aq->mTab[0], aq->mTab[1] );
int64_t min2 = min_i64( aq->mTab[2], aq->mTab[3] );
int64_t min3 = min_i64( min1, aq->mTab[4] );
int64_t min4 = min_i64( min2, min3 );

//assert( ( min4 & 15 ) < AQ_TAB_SIZE );
aq->mTab[min4 & 15] = CNT_MAX | ( min4 & 15 );
int64_t min3 = min_i64( min1, min2 );

return min4;
return min3;
}


Expand All @@ -470,6 +460,9 @@ typedef struct

uint8_t mPan;
uint8_t mStereo;

mikey_audio_sample_t mSample;
bool mSampleValid;
} mikey_pimpl_t;

// mikey_pimpl_t public:
Expand Down Expand Up @@ -512,6 +505,7 @@ static void mikey_pimpl_reset( mikey_pimpl_t* mikey )
mikey->mAttenuationLeft[i] = 0x3c;
mikey->mAttenuationRight[i] = 0x3c;
}
mikey->mSampleValid = false;
}

static int64_t mikey_pimpl_write( mikey_pimpl_t* mikey, int64_t tick, uint8_t address, uint8_t value )
Expand All @@ -520,6 +514,8 @@ static int64_t mikey_pimpl_write( mikey_pimpl_t* mikey, int64_t tick, uint8_t ad
if ( address < 0x20 )
return 0;

mikey->mSampleValid = false;

if ( address < 0x40 )
{
size_t idx = ( address >> 3 ) & 3;
Expand Down Expand Up @@ -576,39 +572,45 @@ static int64_t mikey_pimpl_write( mikey_pimpl_t* mikey, int64_t tick, uint8_t ad

static int64_t mikey_pimpl_fireTimer( mikey_pimpl_t* mikey, int64_t tick )
{
size_t timer = tick & 0x0f;
//assert( timer < 4 );
mikey->mSampleValid = false;
size_t timer = tick & 3;
return mikey_audio_channel_fireAction( &mikey->mAudioChannels[timer], tick );
}

static mikey_audio_sample_t mikey_pimpl_sampleAudio( const mikey_pimpl_t* mikey )
static mikey_audio_sample_t mikey_pimpl_sampleAudio( mikey_pimpl_t* mikey )
{
int left = 0;
int right = 0;
size_t i;
mikey_audio_sample_t as;

for ( i = 0; i < 4; ++i )
if ( !mikey->mSampleValid )
{
if ( mikey->mMute[i] )
continue;
int left = 0;
int right = 0;

if ( ( mikey->mStereo & ( (uint8_t)0x01 << i ) ) == 0 )
if ( !mikey->mMute[0] )
{
const int attenuation = ( mikey->mPan & ( (uint8_t)0x01 << i ) ) != 0 ? mikey->mAttenuationLeft[i] : 0x3c;
left += mikey_audio_channel_getOutput( &mikey->mAudioChannels[i] ) * attenuation;
left += mikey->mAudioChannels[0].mOutput * ( ( ( mikey->mStereo & ( 0x01 << 0 ) ) == 0 ) ? ( ( mikey->mPan & ( 0x01 << 0 ) ) != 0 ? mikey->mAttenuationLeft[0] : 0x3c ) : 0 );
right += mikey->mAudioChannels[0].mOutput * ( ( ( mikey->mStereo & ( 0x10 << 0 ) ) == 0 ) ? ( ( mikey->mPan & ( 0x01 << 0 ) ) != 0 ? mikey->mAttenuationRight[0] : 0x3c ) : 0 );
}

if ( ( mikey->mStereo & ( (uint8_t)0x10 << i ) ) == 0 )
if ( !mikey->mMute[1] )
{
left += mikey->mAudioChannels[1].mOutput * ( ( ( mikey->mStereo & ( 0x01 << 1 ) ) == 0 ) ? ( ( mikey->mPan & ( 0x01 << 1 ) ) != 0 ? mikey->mAttenuationLeft[1] : 0x3c ) : 0 );
right += mikey->mAudioChannels[1].mOutput * ( ( ( mikey->mStereo & ( 0x10 << 1 ) ) == 0 ) ? ( ( mikey->mPan & ( 0x01 << 1 ) ) != 0 ? mikey->mAttenuationRight[1] : 0x3c ) : 0 );
}
if ( !mikey->mMute[2] )
{
left += mikey->mAudioChannels[2].mOutput * ( ( ( mikey->mStereo & ( 0x01 << 2 ) ) == 0 ) ? ( ( mikey->mPan & ( 0x01 << 2 ) ) != 0 ? mikey->mAttenuationLeft[2] : 0x3c ) : 0 );
right += mikey->mAudioChannels[2].mOutput * ( ( ( mikey->mStereo & ( 0x10 << 2 ) ) == 0 ) ? ( ( mikey->mPan & ( 0x01 << 2 ) ) != 0 ? mikey->mAttenuationRight[2] : 0x3c ) : 0 );
}
if ( !mikey->mMute[3] )
{
const int attenuation = ( mikey->mPan & ( (uint8_t)0x01 << i ) ) != 0 ? mikey->mAttenuationRight[i] : 0x3c;
right += mikey_audio_channel_getOutput( &mikey->mAudioChannels[i] ) * attenuation;
left += mikey->mAudioChannels[3].mOutput * ( ( ( mikey->mStereo & ( 0x01 << 3 ) ) == 0 ) ? ( ( mikey->mPan & ( 0x01 << 3 ) ) != 0 ? mikey->mAttenuationLeft[3] : 0x3c ) : 0 );
right += mikey->mAudioChannels[3].mOutput * ( ( ( mikey->mStereo & ( 0x10 << 3 ) ) == 0 ) ? ( ( mikey->mPan & ( 0x01 << 3 ) ) != 0 ? mikey->mAttenuationRight[3] : 0x3c ) : 0 );
}

mikey->mSample.left = ( int16_t )left;
mikey->mSample.right = ( int16_t )right;
mikey->mSampleValid = true;
}

as.left = (int16_t)left;
as.right = (int16_t)right;
return as;
return mikey->mSample;
}

static uint8_t mikey_pimpl_read( mikey_pimpl_t* mikey, int64_t tick, int address )
Expand Down Expand Up @@ -636,16 +638,14 @@ typedef struct
DEV_DATA devData;
mikey_pimpl_t mMikey;
mikey_action_queue_t mQueue;
uint64_t mTick;
uint64_t mNextTick;
int64_t mTick;
int64_t mNextTick;
uint32_t mSampleRate;
uint32_t mSamplesRemainder;
uint32_t mTicksPerSample1;
uint32_t mTicksPerSample2;
} mikey_t;

static void mikey_enqueueSampling( mikey_t* mikey );

static UINT8 mikey_start( const DEV_GEN_CFG* cfg, DEV_INFO* retDevInf )
{
mikey_t* mikey;
Expand Down Expand Up @@ -674,9 +674,8 @@ static void mikey_reset( void* info )
mikey_pimpl_reset( &mikey->mMikey );
mikey_action_queue_ActionQueue( &mikey->mQueue );
mikey->mTick = 0;
mikey->mNextTick = 0;
mikey->mSamplesRemainder = 0;
mikey_enqueueSampling( mikey );
mikey->mNextTick = mikey->mTicksPerSample1;
mikey->mSamplesRemainder = mikey->mTicksPerSample2;
}

static void mikey_stop( void* info )
Expand All @@ -697,43 +696,34 @@ static void mikey_write( void* info, uint8_t address, uint8_t value )
}
}

static void mikey_enqueueSampling( mikey_t* mikey )
{
mikey->mTick = mikey->mNextTick & ~15;
mikey->mNextTick = mikey->mNextTick + mikey->mTicksPerSample1;
mikey->mSamplesRemainder += mikey->mTicksPerSample2;
if ( mikey->mSamplesRemainder > mikey->mSampleRate )
{
mikey->mSamplesRemainder %= mikey->mSampleRate;
mikey->mNextTick += 1;
}

mikey_action_queue_push( &mikey->mQueue, ( mikey->mNextTick & ~15 ) | 4 );
}

static void mikey_update( void* info, UINT32 samples, DEV_SMPL** outputs )
{
mikey_t* mikey = (mikey_t*)info;
UINT32 i = 0;
while ( i < samples )
for ( ;; )
{
int64_t value = mikey_action_queue_pop( &mikey->mQueue );
if ( ( value & 4 ) == 0 )
{
int64_t newAction = mikey_pimpl_fireTimer( &mikey->mMikey, value );
if ( newAction )
{
mikey_action_queue_push( &mikey->mQueue, newAction );
}
}
else
while ( value > mikey->mTick )
{
mikey_audio_sample_t sample = mikey_pimpl_sampleAudio( &mikey->mMikey );
outputs[0][i] = sample.left;
outputs[1][i] = sample.right;
i += 1;
mikey_enqueueSampling( mikey );

mikey->mTick = mikey->mNextTick & ~15;
mikey->mNextTick = mikey->mNextTick + mikey->mTicksPerSample1;
mikey->mSamplesRemainder += mikey->mTicksPerSample2;
if ( mikey->mSamplesRemainder > mikey->mSampleRate )
{
mikey->mSamplesRemainder %= mikey->mSampleRate;
mikey->mNextTick += 1;
}

if ( ++i >= samples )
return;
}

int64_t newAction = mikey_pimpl_fireTimer( &mikey->mMikey, value );
mikey_action_queue_push( &mikey->mQueue, newAction );
}
}

Expand Down

0 comments on commit 978eb16

Please sign in to comment.