Skip to content

Commit

Permalink
Fix audio drift in ntsc/pal composite Closes randyrossi#13
Browse files Browse the repository at this point in the history
Turns out the Pi's composite out has a vertical refresh rate
_slightly_ greater than 50 or 60 hz.  This was causing too much
audio data to get pushed to the buffer and audio 'drift'
occurred over time.  I ended up timing the actual vertical
refresh rates on composite.  This works for PAL or NTSC
progressive modes for composite.  I haven't tried interlace
to see if that makes a difference.
  • Loading branch information
randyrossi committed Apr 5, 2019
1 parent 815c96b commit 9c1aa0a
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 25 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ This project uses VICE for emulation without any O/S (Linux) distribution instal
* http://accentual.com/bmc64

# Timing
The machine config defaults to PAL 50hz for both HDMI and composite. You can change this (see below).
The machine config provided defaults to PAL 50hz for HDMI. If you want to use composite out, you MUST change the machine_timing parameter in cmdline.txt to 'pal-composite'. Otherwise, you will have audio synchronization issues. You can change the machine to be NTSC if you want (see below).

# FileSystem/Drives

Expand Down Expand Up @@ -135,9 +135,10 @@ Q: Can I switch the machine to NTSC?
A: Yes, you must edit BOTH config.txt and cmdline.txt.

In config.txt, select an hdmi_mode that is 60hz.
In cmdline.txt, change machine_timing to ntsc
In cmdline.txt, change machine_timing to ntsc or ntsc-hdmi for HDMI
If using composite, machine_timing MUST be ntsc-composite. Othersie you will get audio synchronization issues.

Be aware that some demos/games will not run if the machine is NTSC. If you mix those two settings, your machine will likely run fast/slow and not look good.
Be aware that some demos/games will not run if the machine is NTSC. If you mix those two settings, your machine will likely run fast/slow, not look good or have audio issues (or all of the above).

Q: Why does the video look soft/stretched/dark?

Expand Down
15 changes: 15 additions & 0 deletions cmdline.txt
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
hide_console=1 fast=true canvas_width=384 canvas_height=272 machine_timing=pal

# Kernel options must appear on a single line separated by spaces.
#
# machine_timing
#
# For 50hz modes (PAL)
# Set to 'pal' or 'pal-hdmi' when using an HDMI display
# Set to 'pal-composite' when using the Pi's composite out
#
# For 60hz modes (NTSC)
# Set to 'ntsc' or 'ntsc-hdmi' when using an HDMI display
# Set to 'ntsc-composite' when using the Pi's composite out
#
# If you try to use pal or pal-hdmi with composite out, you will get
# audio synchronization issues with ReSid.
35 changes: 33 additions & 2 deletions kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ extern "C" {
void circle_boot_complete() {
static_kernel->circle_boot_complete();
}

int circle_cycles_per_sec() {
return static_kernel->circle_cycles_per_second();
}
};

bool CKernel::uiShift = false;
Expand Down Expand Up @@ -390,7 +394,8 @@ ViceApp::TShutdownMode CKernel::Run (void)
// See arch/raspi/videoarch.c

char timing_option[8];
if (circle_get_machine_timing() == MACHINE_TIMING_NTSC) {
if (circle_get_machine_timing() == MACHINE_TIMING_NTSC_HDMI ||
circle_get_machine_timing() == MACHINE_TIMING_NTSC_COMPOSITE) {
strcpy(timing_option, "-ntsc");
} else {
strcpy(timing_option, "-pal");
Expand Down Expand Up @@ -442,7 +447,7 @@ ssize_t CKernel::vice_write (int fd, const void * buf, size_t count) {
}

int CKernel::circle_get_machine_timing () {
// Returns 0 for ntsc, 1 for pal
// See circle.h for valid values
return mViceOptions.GetMachineTiming();
}

Expand Down Expand Up @@ -858,3 +863,29 @@ void CKernel::circle_lock_release() {
void CKernel::circle_boot_complete() {
DisableBootStat();
}

// 1025700 60hz NTSC hdmi
// 1022730 59.826hz NTSC composite
// 982800 50hz for hdmi
// 985248 50.125hz for composite
int CKernel::circle_cycles_per_second() {
if (circle_get_machine_timing() == MACHINE_TIMING_NTSC_HDMI) {
// 60hz
return 1025700;
} else if (circle_get_machine_timing() == MACHINE_TIMING_NTSC_COMPOSITE) {
// Actual C64's NTSC Composite frequency is 59.826 but the Pi's vertical
// sync frequency on composite is 60.055. See c64.h for how this is
// calculated. This keeps audio buffer to a minimum using ReSid.
return 1026640;
} else if (circle_get_machine_timing() == MACHINE_TIMING_PAL_HDMI) {
// 50hz
return 982800;
} else if (circle_get_machine_timing() == MACHINE_TIMING_PAL_COMPOSITE) {
// Actual C64's PAL Composite frequency is 50.125 but the Pi's vertical
// sync frequency on composite is 50.0816. See c64.h for how this is
// calculated. This keep audio buffer to a minimum using ReSid.
return 984404;
} else {
return 982800;
}
}
1 change: 1 addition & 0 deletions kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class CKernel : public ViceStdioApp
void circle_lock_acquire();
void circle_lock_release();
void circle_boot_complete();
int circle_cycles_per_second();

private:
static bool uiShift;
Expand Down
5 changes: 5 additions & 0 deletions third_party/vice-3.2/src/arch/raspi/circle.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@

#include <sys/types.h>

#define MACHINE_TIMING_NTSC_HDMI 0
#define MACHINE_TIMING_PAL_HDMI 1
#define MACHINE_TIMING_NTSC_COMPOSITE 2
#define MACHINE_TIMING_PAL_COMPOSITE 3

#define USB_PREF_ANALOG 0
#define USB_PREF_HAT 1

Expand Down
18 changes: 18 additions & 0 deletions third_party/vice-3.2/src/arch/raspi/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,24 @@ void build_menu(struct menu_item* root) {
strcpy(current_dir_names[i], default_dir_names[i]);
}

switch (circle_get_machine_timing()) {
case MACHINE_TIMING_NTSC_HDMI:
ui_menu_add_button(MENU_TEXT, root, "Timing: NTSC 60Hz HDMI");
break;
case MACHINE_TIMING_NTSC_COMPOSITE:
ui_menu_add_button(MENU_TEXT, root, "Timing: NTSC 60Hz Composite");
break;
case MACHINE_TIMING_PAL_HDMI:
ui_menu_add_button(MENU_TEXT, root, "Timing: PAL 50Hz HDMI");
break;
case MACHINE_TIMING_PAL_COMPOSITE:
ui_menu_add_button(MENU_TEXT, root, "Timing: PAL 50Hz Composite");
break;
default:
ui_menu_add_button(MENU_TEXT, root, "Timing: ERROR");
break;
}

ui_menu_add_button(MENU_ABOUT, root, "About...");
ui_menu_add_button(MENU_LICENSE, root, "License...");

Expand Down
8 changes: 5 additions & 3 deletions third_party/vice-3.2/src/arch/raspi/videoarch.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,9 @@ void video_arch_canvas_init(struct video_canvas_s *canvas){
int h = circle_get_display_h();
bzero(fb, h*fb_pitch);

if (circle_get_machine_timing() == 0) {
int timing = circle_get_machine_timing();
if (timing == MACHINE_TIMING_NTSC_HDMI ||
timing == MACHINE_TIMING_NTSC_COMPOSITE) {
canvas->refreshrate = C64_NTSC_RFSH_PER_SEC;
} else {
canvas->refreshrate = C64_PAL_RFSH_PER_SEC;
Expand Down Expand Up @@ -366,7 +368,7 @@ void videoarch_swap() {
// Show the region we just drew.
circle_set_fb_y(video_state.offscreen_buffer_y);
// Swap buffer ptr for next frame.
video_state.offscreen_buffer_y = circle_get_display_h() -
video_state.offscreen_buffer_y = circle_get_display_h() -
video_state.offscreen_buffer_y;
}

Expand Down Expand Up @@ -459,7 +461,7 @@ void vsyncarch_postsync(void){
}

if (raspi_demo_mode) {
demo_check();
demo_check();
}
}

Expand Down
22 changes: 16 additions & 6 deletions third_party/vice-3.2/src/c64/c64.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,16 @@
#define VICE_C64_H

#ifdef RASPI_COMPILE
// This is necessary to match the actual ticks we need to simulate
// between frames. RASPI is tied to vsync which is exactly 50hz.
#define C64_PAL_CYCLES_PER_SEC 982800
extern int circle_cycles_per_sec();
#endif

#ifdef RASPI_COMPILE
// Raspi needs to change between 50hz and 50.125hz depending on what
// the user sets in kernel options (cmdline.txt). This this was changed
// to give results from a function rather than hard coded constant.
// 982800 // 50hz for hdmi
// 985248 // 50.125hz for composite
#define C64_PAL_CYCLES_PER_SEC (circle_cycles_per_sec())
#else
#define C64_PAL_CYCLES_PER_SEC 985248
#endif
Expand All @@ -46,9 +53,12 @@
#define C64_PAL_RFSH_PER_SEC (1.0 / ((double)C64_PAL_CYCLES_PER_RFSH / (double)C64_PAL_CYCLES_PER_SEC))

#ifdef RASPI_COMPILE
// This is necessary to match the actual ticks we need to simulate
// between frames. RASPI is tied to vsync which is exactly 60hz.
#define C64_NTSC_CYCLES_PER_SEC 1025700
// Raspi needs to change between 50hz and 50.125hz depending on what
// the user sets in kernel options (cmdline.txt). This this was changed
// to give results from a function rather than hard coded constant.
// 1025700 60hz NTSC hdmi
// 1022730 59.826hz NTSC composite
#define C64_NTSC_CYCLES_PER_SEC (circle_cycles_per_sec())
#else
#define C64_NTSC_CYCLES_PER_SEC 1022730
#endif
Expand Down
1 change: 0 additions & 1 deletion viceapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ class ViceApp
{
return false;
}
mSerial.Write("here\n",5);

if (!mInterrupt.Initialize ()) {
return false;
Expand Down
22 changes: 15 additions & 7 deletions viceoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@
#include <string.h>
#include <stdlib.h>

extern "C" {
#include "third_party/vice-3.2/src/arch/raspi/circle.h"
}

#define INVALID_VALUE ((unsigned) -1)

ViceOptions *ViceOptions::s_pThis = 0;

ViceOptions::ViceOptions (void) :
m_nCanvasWidth (DEFAULT_CANVAS_WIDTH),
m_nCanvasHeight (DEFAULT_CANVAS_HEIGHT),
m_nMachineTiming (MACHINE_TIMING_PAL),
m_nMachineTiming (MACHINE_TIMING_PAL_HDMI),
m_bHideConsole(true),
m_bDemoMode(false)
{
Expand Down Expand Up @@ -77,12 +81,16 @@ ViceOptions::ViceOptions (void) :
}
else if (strcmp (pOption, "machine_timing") == 0)
{
if (strcmp(pValue, "ntsc") == 0)
{
m_nMachineTiming = MACHINE_TIMING_NTSC;
}
else {
m_nMachineTiming = MACHINE_TIMING_PAL;
if (strcmp(pValue, "ntsc") == 0 ||
strcmp(pValue, "ntsc-hdmi") == 0) {
m_nMachineTiming = MACHINE_TIMING_NTSC_HDMI;
} else if (strcmp(pValue, "ntsc-composite") == 0) {
m_nMachineTiming = MACHINE_TIMING_NTSC_COMPOSITE;
} else if (strcmp(pValue, "pal") == 0 ||
strcmp(pValue, "pal-hdmi") == 0) {
m_nMachineTiming = MACHINE_TIMING_PAL_HDMI;
} else if (strcmp(pValue, "pal-composite") == 0) {
m_nMachineTiming = MACHINE_TIMING_PAL_COMPOSITE;
}
}
else if (strcmp (pOption, "hide_console") == 0)
Expand Down
3 changes: 0 additions & 3 deletions viceoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
#define DEFAULT_CANVAS_WIDTH 384
#define DEFAULT_CANVAS_HEIGHT 272

#define MACHINE_TIMING_NTSC 0
#define MACHINE_TIMING_PAL 1

#define TEST_PIN_TARGET_NONE 0
#define TEST_PIN_TARGET_SPACE 1
#define TEST_PIN_TARGET_FIRE_1 2
Expand Down

0 comments on commit 9c1aa0a

Please sign in to comment.