summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Pomarède <npomarede@corp.free.fr>2022-07-24 12:19:35 (GMT)
committerNicolas Pomarède <npomarede@corp.free.fr>2022-07-24 12:19:35 (GMT)
commitf91714f2903679186431b23a7cf57f91efa37ee8 (patch)
treee42ca90549f6013e2e183bc41a996098d2601a27
parent8bb87e4d6a939cf6008955da26b015f34d08ea35 (diff)
downloadhatari-f91714f2903679186431b23a7cf57f91efa37ee8.zip
hatari-f91714f2903679186431b23a7cf57f91efa37ee8.tar.gz
Much more precise function to convert CPU clocks to YM2149 clock, fix some STE sound glitches
Previous method using floating point was not always accurate in STE mode and accumulated too much error after a while. This new method will cover both STF and STE/TT/Falcon clocks' conversion using only integer operation and no rounding spreading over time
-rw-r--r--src/clocks_timings.c30
-rw-r--r--src/includes/clocks_timings.h9
-rw-r--r--src/sound.c34
3 files changed, 66 insertions, 7 deletions
diff --git a/src/clocks_timings.c b/src/clocks_timings.c
index 4af8e8d..ad80829 100644
--- a/src/clocks_timings.c
+++ b/src/clocks_timings.c
@@ -542,3 +542,33 @@ Sint64 ClocksTimings_GetSamplesPerVBL ( MACHINETYPE MachineType , int ScreenRefr
return SamplesPerVBL;
}
+
+
+
+/*-----------------------------------------------------------------------------------------*/
+/**
+ * Convert a number of cycles "CyclesIn" for a clock running at "ClockFreqIn" into
+ * an equivalent number of cycles for a clock running at "ClockFreqOut".
+ * As clocks are rarely multiple of each other, this will give a remainder that must be kept
+ * and used on next call.
+ * This method uses only integer operations (integer division and modulo) and gives much more
+ * precise results than using floating point, because there's no roundings that accumulate
+ * after a while.
+ */
+void ClocksTimings_ConvertCycles ( Uint32 CyclesIn , Uint64 ClockFreqIn , CLOCKS_CYCLES_STRUCT *CyclesStructOut , Uint64 ClockFreqOut )
+{
+ Uint64 CyclesTotal;
+ Uint64 CyclesOut;
+ Uint64 CyclesOut_remainder;
+
+ CyclesTotal = CyclesIn * ClockFreqOut;
+ CyclesTotal += CyclesStructOut->Remainder;
+
+ CyclesOut = CyclesTotal / ClockFreqIn;
+ CyclesOut_remainder = CyclesTotal % ClockFreqIn;
+
+ CyclesStructOut->Cycles = CyclesOut;
+ CyclesStructOut->Remainder = CyclesOut_remainder;
+}
+
+
diff --git a/src/includes/clocks_timings.h b/src/includes/clocks_timings.h
index 8c50521..87aea86 100644
--- a/src/includes/clocks_timings.h
+++ b/src/includes/clocks_timings.h
@@ -54,9 +54,15 @@ typedef struct
} CLOCKS_STRUCT;
+extern CLOCKS_STRUCT MachineClocks;
-extern CLOCKS_STRUCT MachineClocks;
+
+typedef struct {
+ Uint64 Cycles;
+ Uint64 Remainder;
+} CLOCKS_CYCLES_STRUCT;
+
extern bool RoundVBLPerSec;
@@ -72,6 +78,7 @@ Uint32 ClocksTimings_GetVBLPerSec ( MACHINETYPE MachineType , int ScreenRefreshR
Uint32 ClocksTimings_GetVBLDuration_micro ( MACHINETYPE MachineType , int ScreenRefreshRate );
Sint64 ClocksTimings_GetSamplesPerVBL ( MACHINETYPE MachineType , int ScreenRefreshRate , int AudioFreq );
+void ClocksTimings_ConvertCycles ( Uint32 CyclesIn , Uint64 ClockFreqIn , CLOCKS_CYCLES_STRUCT *CyclesStructOut , Uint64 ClockFreqOut );
diff --git a/src/sound.c b/src/sound.c
index 3da5b33..42840ae 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -329,6 +329,8 @@ static int Sound_Stats_Index = 0;
static int Sound_Stats_SamplePerVBL;
+static CLOCKS_CYCLES_STRUCT YM2149_ConvertCycles_250;
+
/*--------------------------------------------------------------*/
/* Local functions prototypes */
@@ -782,7 +784,7 @@ static void Ym2149_BuildVolumeTable(void)
/*-----------------------------------------------------------------------*/
/**
* Convert a CPU clock value (as in CyclesGlobalClockCounter)
- * into a 250 kHz YM2149 clock (taking nCpuFreqShift into account)
+ * into a 250 kHz YM2149 clock.
*
* NOTE : we should not use this simple method :
* Clock_250 = CpuClock / ( 32 << nCpuFreqShift )
@@ -792,11 +794,10 @@ static void Ym2149_BuildVolumeTable(void)
* To get the correct 250 kHZ clock, we must compute how many CpuClock units
* elapsed since the previous call and convert this increment into
* an increment for the 250 kHz clock
- * To update YM2149_Clock_250_CpuClock we should only take into account
- * the part of CpuClockDiff that corresponds to an integer increment YM_inc :
- * the ignored (remainder) CpuClockDiff's units will be taken into account on the next call.
+ * After each call the remainder will be saved to be used on the next call
*/
+#if 0
/* integer version : use it when YM2149's clock is the same as CPU's clock (eg STF) */
static void YM2149_UpdateClock_250_int ( Uint64 CpuClock )
@@ -850,7 +851,24 @@ static void YM2149_UpdateClock_250_float ( Uint64 CpuClock )
//fprintf ( stderr , "update_250 clock_cpu=%ld -> ym_inc=%ld clock_250=%ld clock_250_cpu_clock=%ld\n" , CpuClock , YM_Inc , YM2149_Clock_250 , YM2149_Clock_250_CpuClock );
}
+#endif
+
+
+static void YM2149_UpdateClock_250_int_new ( Uint64 CpuClock )
+{
+ Uint64 CpuClockDiff;
+
+ CpuClockDiff = CpuClock - YM2149_Clock_250_CpuClock;
+ ClocksTimings_ConvertCycles ( CpuClockDiff , MachineClocks.CPU_Freq_Emul , &YM2149_ConvertCycles_250 , YM_ATARI_CLOCK_COUNTER );
+
+ YM2149_Clock_250 += YM2149_ConvertCycles_250.Cycles;
+ YM2149_Clock_250_CpuClock = CpuClock;
+//fprintf ( stderr , "update_250_new out clock_cpu=%lu cpu_diff=%lu inc=%lu rem=%lu clock_250_in=%lu\n" , CpuClock, CpuClockDiff, YM2149_ConvertCycles_250.Cycles, YM2149_ConvertCycles_250.Remainder , YM2149_Clock_250 );
+
+
+//fprintf ( stderr , "update_250 clock_cpu=%ld -> ym_inc=%ld clock_250=%ld clock_250_cpu_clock=%ld\n" , CpuClock , YM2149_ConvertCycles_250.Cycles , YM2149_Clock_250 , YM2149_Clock_250_CpuClock );
+}
/*
@@ -865,9 +883,13 @@ static void YM2149_UpdateClock_250_float ( Uint64 CpuClock )
static void YM2149_UpdateClock_250 ( Uint64 CpuClock )
{
if ( ConfigureParams.System.nMachineType == MACHINE_ST || ConfigureParams.System.nMachineType == MACHINE_MEGA_ST )
- YM2149_UpdateClock_250_int ( CpuClock );
+{
+// YM2149_UpdateClock_250_int ( CpuClock );
+ YM2149_UpdateClock_250_int_new ( CpuClock );
+}
else
- YM2149_UpdateClock_250_float ( CpuClock );
+// YM2149_UpdateClock_250_float ( CpuClock );
+ YM2149_UpdateClock_250_int_new ( CpuClock );
}