Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Threading and overrun/underrun #72

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/lcd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,6 @@ void LCD_Update(void)

if (!mcu_cm300 && !mcu_st && !mcu_scb55)
{
MCU_WorkThread_Lock();

if (!lcd_enable && !mcu_jv880)
{
memset(lcd_buffer, 0, sizeof(lcd_buffer));
Expand Down Expand Up @@ -512,8 +510,6 @@ void LCD_Update(void)
}
}

MCU_WorkThread_Unlock();

SDL_UpdateTexture(texture, NULL, lcd_buffer, lcd_width_max * 4);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
Expand Down
87 changes: 44 additions & 43 deletions src/mcu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -923,40 +923,13 @@ void MCU_UpdateUART_TX(void)
// printf("tx:%x\n", dev_register[DEV_TDR]);
}

static bool work_thread_run = false;

static SDL_mutex *work_thread_lock;

void MCU_WorkThread_Lock(void)
{
SDL_LockMutex(work_thread_lock);
}

void MCU_WorkThread_Unlock(void)
{
SDL_UnlockMutex(work_thread_lock);
}

int SDLCALL work_thread(void* data)
int SDLCALL work_thread(void)
{
work_thread_lock = SDL_CreateMutex();

MCU_WorkThread_Lock();
while (work_thread_run)
{
if (pcm.config_reg_3c & 0x40)
sample_write_ptr &= ~3;
else
sample_write_ptr &= ~1;
if (sample_read_ptr == sample_write_ptr)
{
MCU_WorkThread_Unlock();
while (sample_read_ptr == sample_write_ptr)
{
SDL_Delay(1);
}
MCU_WorkThread_Lock();
}

if (!mcu.ex_ignore)
MCU_Interrupt_Handle();
Expand Down Expand Up @@ -998,31 +971,30 @@ int SDLCALL work_thread(void* data)
}
}
}
MCU_WorkThread_Unlock();

SDL_DestroyMutex(work_thread_lock);

return 0;
}

static void MCU_Run()
{
bool working = true;
Uint64 counts_per_second = SDL_GetPerformanceFrequency();

work_thread_run = true;
SDL_Thread *thread = SDL_CreateThread(work_thread, "work thread", 0);

Uint64 start_count = SDL_GetPerformanceCounter();
while (working)
{
if(LCD_QuitRequested())
working = false;

LCD_Update();
SDL_Delay(15);
}
work_thread();
Uint64 end_count = SDL_GetPerformanceCounter();

work_thread_run = false;
SDL_WaitThread(thread, 0);
if( ( end_count - start_count ) > ( 1.0/60.0 * counts_per_second ) )
{
start_count = SDL_GetPerformanceCounter();
LCD_Update();
}
}
}

void MCU_PatchROM(void)
Expand Down Expand Up @@ -1094,13 +1066,32 @@ void unscramble(uint8_t *src, uint8_t *dst, int len)
}
}

unsigned overrun = 0;
void audio_callback(void* /*userdata*/, Uint8* stream, int len)
{
len /= 2;
memcpy(stream, &sample_buffer[sample_read_ptr], len * 2);
memset(&sample_buffer[sample_read_ptr], 0, len * 2);
sample_read_ptr += len;
int samples_ready = ( sample_write_ptr >= sample_read_ptr )
? ( sample_write_ptr - sample_read_ptr )
: ( audio_buffer_size - sample_read_ptr ) + sample_write_ptr;

int samples_requested = len / 2;
int samples_len = ( samples_requested < samples_ready ) ? samples_requested : samples_ready;

memcpy(stream, &sample_buffer[sample_read_ptr], samples_len * 2);
sample_read_ptr += samples_len;
sample_read_ptr %= audio_buffer_size;

int underrun = samples_requested - samples_len;
if ( underrun )
{
fprintf(stderr, "Underrun by %d\n", underrun );
memset(&stream[samples_len], 0, len - (samples_len * 2));
}

if ( overrun )
{
fprintf(stderr, "Overrun by %d\n", overrun );
overrun = 0;
}
}

static const char* audio_format_to_str(int format)
Expand Down Expand Up @@ -1216,6 +1207,16 @@ void MCU_PostSample(int *sample)
sample_buffer[sample_write_ptr + 0] = sample[0];
sample_buffer[sample_write_ptr + 1] = sample[1];
sample_write_ptr = (sample_write_ptr + 2) % audio_buffer_size;

// If the write pointer is the same as the read pointer
// after it has been incremented then there's no space
// in the buffer. The oldest sample is dropped by
// overwriting it above, so advance the read ptr
if ( sample_write_ptr == sample_read_ptr )
{
++overrun;
sample_read_ptr = (sample_read_ptr + 2) % audio_buffer_size;
}
}

void MCU_GA_SetGAInt(int line, int value)
Expand Down
3 changes: 0 additions & 3 deletions src/mcu.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,3 @@ void MCU_EncoderTrigger(int dir);

void MCU_PostSample(int *sample);
void MCU_PostUART(uint8_t data);

void MCU_WorkThread_Lock(void);
void MCU_WorkThread_Unlock(void);