@@ -3,17 +3,30 @@ const testing = std.testing;
33const clock = @import ("../clock.zig" );
44
55pub const PendingAudioFrames = struct {
6+ master_cycles : u32 ,
67 fm_frames : u32 ,
78 psg_frames : u32 ,
9+ fm_start_remainder : u16 ,
10+ psg_start_remainder : u16 ,
811};
912
1013pub const AudioTiming = struct {
1114 fm_master_remainder : u16 = 0 ,
1215 psg_master_remainder : u16 = 0 ,
16+ pending_master_cycles : u32 = 0 ,
1317 pending_fm_frames : u32 = 0 ,
1418 pending_psg_frames : u32 = 0 ,
19+ pending_fm_start_remainder : u16 = 0 ,
20+ pending_psg_start_remainder : u16 = 0 ,
1521
1622 pub fn consumeMaster (self : * AudioTiming , master_cycles : u32 ) void {
23+ if (self .pending_master_cycles == 0 ) {
24+ self .pending_fm_start_remainder = self .fm_master_remainder ;
25+ self .pending_psg_start_remainder = self .psg_master_remainder ;
26+ }
27+
28+ self .pending_master_cycles += master_cycles ;
29+
1730 const fm_total = @as (u32 , self .fm_master_remainder ) + master_cycles ;
1831 self .pending_fm_frames += fm_total / clock .fm_master_cycles_per_sample ;
1932 self .fm_master_remainder = @intCast (fm_total % clock .fm_master_cycles_per_sample );
@@ -25,12 +38,18 @@ pub const AudioTiming = struct {
2538
2639 pub fn takePending (self : * AudioTiming ) PendingAudioFrames {
2740 const out = PendingAudioFrames {
41+ .master_cycles = self .pending_master_cycles ,
2842 .fm_frames = self .pending_fm_frames ,
2943 .psg_frames = self .pending_psg_frames ,
44+ .fm_start_remainder = self .pending_fm_start_remainder ,
45+ .psg_start_remainder = self .pending_psg_start_remainder ,
3046 };
3147
48+ self .pending_master_cycles = 0 ;
3249 self .pending_fm_frames = 0 ;
3350 self .pending_psg_frames = 0 ;
51+ self .pending_fm_start_remainder = 0 ;
52+ self .pending_psg_start_remainder = 0 ;
3453
3554 return out ;
3655 }
@@ -41,9 +60,29 @@ test "audio timing accrues FM/PSG native-rate frames from master cycles" {
4160 timing .consumeMaster (clock .ntsc_master_cycles_per_frame );
4261 const frames = timing .takePending ();
4362
63+ try testing .expectEqual (clock .ntsc_master_cycles_per_frame , frames .master_cycles );
4464 try testing .expectEqual (@as (u32 , 888 ), frames .fm_frames );
65+ try testing .expectEqual (@as (u16 , 0 ), frames .fm_start_remainder );
4566 try testing .expectEqual (@as (u16 , 936 ), timing .fm_master_remainder );
4667
4768 try testing .expectEqual (@as (u32 , 3733 ), frames .psg_frames );
69+ try testing .expectEqual (@as (u16 , 0 ), frames .psg_start_remainder );
4870 try testing .expectEqual (@as (u16 , 120 ), timing .psg_master_remainder );
4971}
72+
73+ test "audio timing snapshots start remainders for each pending window" {
74+ var timing = AudioTiming {};
75+
76+ timing .consumeMaster (clock .fm_master_cycles_per_sample - 8 );
77+ const first = timing .takePending ();
78+ try testing .expectEqual (@as (u32 , clock .fm_master_cycles_per_sample - 8 ), first .master_cycles );
79+ try testing .expectEqual (@as (u32 , 0 ), first .fm_frames );
80+ try testing .expectEqual (@as (u16 , 0 ), first .fm_start_remainder );
81+ try testing .expectEqual (@as (u16 , clock .fm_master_cycles_per_sample - 8 ), timing .fm_master_remainder );
82+
83+ timing .consumeMaster (16 );
84+ const second = timing .takePending ();
85+ try testing .expectEqual (@as (u32 , 16 ), second .master_cycles );
86+ try testing .expectEqual (@as (u32 , 1 ), second .fm_frames );
87+ try testing .expectEqual (@as (u16 , clock .fm_master_cycles_per_sample - 8 ), second .fm_start_remainder );
88+ }
0 commit comments