44//
55// SPDX-License-Identifier: MIT
66
7- // 48 kHz stereo DVI audio for the RP2350 picodvi Framebuffer.
7+ // 32, 44.1 or 48 kHz stereo DVI audio for the RP2350 picodvi Framebuffer.
88// No interrupt-time allocation, sample conversion, packet encoding, or Python callbacks.
99
1010#include <string.h>
2424#include "supervisor/background_callback.h"
2525#include "supervisor/port.h"
2626
27- #define DVI_AUDIO_RATE 48000u
27+ typedef struct {
28+ uint32_t sample_rate ;
29+ // The usual ACR N, for when no N gives an exact CTS.
30+ uint32_t usual_n ;
31+ } dvi_audio_rate_t ;
32+
33+ // The basic audio rates every DVI sink takes.
34+ static const dvi_audio_rate_t dvi_audio_rates [] = {
35+ { 32000 , 4096 },
36+ { 44100 , 6272 },
37+ { 48000 , 6144 },
38+ };
39+ #define DVI_AUDIO_RATE_COUNT MP_ARRAY_SIZE(dvi_audio_rates)
2840#define DVI_AUDIO_H_TOTAL (MODE_640_H_FRONT_PORCH + MODE_640_H_SYNC_WIDTH + MODE_640_H_BACK_PORCH + MODE_640_H_ACTIVE_PIXELS)
2941// Lines per frame that carry a data island. At the usual 25 MHz pixel clock
30- // a 625 line frame needs 240 sample packets, 20 ACR packets and 2
42+ // and 48 kHz a 625 line frame needs 240 sample packets, 20 ACR packets and 2
3143// InfoFrames.
3244#define DVI_AUDIO_SLOTS 280
3345// Buffers for encoded sample packets. Other packets never change, so their
34- // islands point at fixed copies. 160 hold about 13 ms of audio.
46+ // islands point at fixed copies. 160 hold about 13 ms of 48 kHz audio.
3547#define DVI_AUDIO_POOL 160
3648// Packet words of an island, without its two guard band words at each end.
3749#define DVI_AUDIO_SLOT_WORDS (HSTX_DATA_ISLAND_WORDS - 4)
@@ -82,8 +94,12 @@ typedef struct dvi_audio_state {
8294 size_t pool_tail ;
8395 size_t pool_count ;
8496 uint32_t pixel_clock ;
85- // ACR packets per second, 128 * 48000 / N.
86- uint32_t acr_rate ;
97+ // The rate being sent, and the rate play() asked for, which takes over
98+ // from the next slot written. Indexes into dvi_audio_rates.
99+ size_t rate_index ;
100+ size_t next_rate_index ;
101+ // ACR packets per second at each rate, 128 * fs / N.
102+ uint32_t acr_rate [DVI_AUDIO_RATE_COUNT ];
87103 // Sample and ACR timing, carried from slot to slot.
88104 uint64_t sample_phase ;
89105 uint64_t acr_phase ;
@@ -100,10 +116,10 @@ typedef struct dvi_audio_state {
100116 uint16_t slot_line [DVI_AUDIO_SLOTS ];
101117 uint8_t slot_samples [DVI_AUDIO_SLOTS ];
102118 // Packets that never change, for blanking [0] and vsync [1] lines.
103- dvi_audio_island_t acr [2 ];
119+ dvi_audio_island_t acr [DVI_AUDIO_RATE_COUNT ][ 2 ];
104120 dvi_audio_island_t null_packet [2 ];
105121 dvi_audio_island_t silence [2 ];
106- dvi_audio_island_t audio_infoframe ;
122+ dvi_audio_island_t audio_infoframe [ DVI_AUDIO_RATE_COUNT ] ;
107123 dvi_audio_island_t avi_infoframe ;
108124 uint32_t prefix [2 ][DVI_AUDIO_PREFIX_WORDS ];
109125 uint32_t suffix_blank [2 ][DVI_AUDIO_SUFFIX_BLANK_WORDS ];
@@ -215,19 +231,17 @@ static uint32_t *dvi_audio_slot_island(dvi_audio_state_t *audio, size_t slot) {
215231 return & audio -> commands [(audio -> slot_entry [slot ] + 1 ) * audio -> command_size - 1 ];
216232}
217233
218- static void dvi_audio_init_packets (dvi_audio_state_t * audio ) {
219- hstx_packet_t packet ;
220- // Pick N so that every frame has the same whole number of ACR packets,
221- // and CTS is exact. Then a frame of silence repeats exactly and needs no
222- // rewriting. N may be anything from 128 * fs / 1500 to 128 * fs / 300.
223- // If no N fits, use the usual 6144 and round CTS.
234+ // Pick N so that every frame has the same whole number of ACR packets, and
235+ // CTS is exact. Then a frame of silence repeats exactly and needs no
236+ // rewriting. N may be anything from 128 * fs / 1500 to 128 * fs / 300.
237+ // If no N fits, use the usual N for the rate and round CTS.
238+ static uint32_t dvi_audio_find_n (uint32_t pixel_clock , const dvi_audio_rate_t * rate_info ) {
224239 const uint64_t frame_pixels = (uint64_t )MODE_640_V_TOTAL_LINES * DVI_AUDIO_H_TOTAL ;
225- const uint32_t n_times_rate = 128 * DVI_AUDIO_RATE ;
226- uint32_t n = 6144 ;
227- uint32_t per_frame = (1000 * frame_pixels + audio -> pixel_clock / 2 ) / audio -> pixel_clock ;
240+ const uint32_t n_times_rate = 128 * rate_info -> sample_rate ;
241+ uint32_t per_frame = (1000 * frame_pixels + pixel_clock / 2 ) / pixel_clock ;
228242 for (uint32_t k = per_frame - 1 ; k <= per_frame + 1 ; k ++ ) {
229243 // ACR packets per second when each frame has k.
230- uint64_t rate = (uint64_t )k * audio -> pixel_clock ;
244+ uint64_t rate = (uint64_t )k * pixel_clock ;
231245 if (k == 0 || rate % frame_pixels != 0 ) {
232246 continue ;
233247 }
@@ -237,30 +251,43 @@ static void dvi_audio_init_packets(dvi_audio_state_t *audio) {
237251 }
238252 uint32_t candidate = n_times_rate / rate ;
239253 if (candidate >= n_times_rate / 1500 && candidate <= n_times_rate / 300 &&
240- ((uint64_t )audio -> pixel_clock * candidate ) % n_times_rate == 0 ) {
241- n = candidate ;
242- break ;
254+ ((uint64_t )pixel_clock * candidate ) % n_times_rate == 0 ) {
255+ return candidate ;
243256 }
244257 }
245- audio -> acr_rate = n_times_rate / n ;
246- uint32_t cts = ((uint64_t )audio -> pixel_clock * n + n_times_rate / 2 ) / n_times_rate ;
247- hstx_packet_set_acr (& packet , n , cts );
248- for (int vsync = 0 ; vsync < 2 ; vsync ++ ) {
249- dvi_audio_encode (audio -> acr [vsync ], & packet , vsync );
258+ return rate_info -> usual_n ;
259+ }
260+
261+ static void dvi_audio_init_packets (dvi_audio_state_t * audio ) {
262+ hstx_packet_t packet ;
263+ for (size_t rate_index = 0 ; rate_index < DVI_AUDIO_RATE_COUNT ; rate_index ++ ) {
264+ const dvi_audio_rate_t * rate_info = & dvi_audio_rates [rate_index ];
265+ const uint32_t n_times_rate = 128 * rate_info -> sample_rate ;
266+ uint32_t n = dvi_audio_find_n (audio -> pixel_clock , rate_info );
267+ audio -> acr_rate [rate_index ] = n_times_rate / n ;
268+ uint32_t cts = ((uint64_t )audio -> pixel_clock * n + n_times_rate / 2 ) / n_times_rate ;
269+ hstx_packet_set_acr (& packet , n , cts );
270+ for (int vsync = 0 ; vsync < 2 ; vsync ++ ) {
271+ dvi_audio_encode (audio -> acr [rate_index ][vsync ], & packet , vsync );
272+ }
273+ // The first two slots of every frame carry the InfoFrames.
274+ hstx_packet_set_audio_infoframe (& packet , rate_info -> sample_rate , 2 , 16 );
275+ dvi_audio_encode (audio -> audio_infoframe [rate_index ], & packet , dvi_audio_slot_vsync (audio , 0 ));
250276 }
277+ // 48 kHz until play() asks for another rate.
278+ audio -> rate_index = DVI_AUDIO_RATE_COUNT - 1 ;
279+ audio -> next_rate_index = audio -> rate_index ;
251280 hstx_packet_init (& packet );
252281 for (int vsync = 0 ; vsync < 2 ; vsync ++ ) {
253282 dvi_audio_encode (audio -> null_packet [vsync ], & packet , vsync );
254283 }
255- // Frame position 4 never sets the block start flag.
284+ // Frame position 4 never sets the block start flag, and frames 4 to 7
285+ // carry no channel status bits, so silence is the same at every rate.
256286 audio_sample_t silence [4 ] = {{0 }};
257- hstx_packet_set_audio_samples (& packet , silence , 4 , 4 );
287+ hstx_packet_set_audio_samples (& packet , silence , 4 , 4 , dvi_audio_rates [ DVI_AUDIO_RATE_COUNT - 1 ]. sample_rate );
258288 for (int vsync = 0 ; vsync < 2 ; vsync ++ ) {
259289 dvi_audio_encode (audio -> silence [vsync ], & packet , vsync );
260290 }
261- // The first two slots of every frame carry the InfoFrames.
262- hstx_packet_set_audio_infoframe (& packet , DVI_AUDIO_RATE , 2 , 16 );
263- dvi_audio_encode (audio -> audio_infoframe , & packet , dvi_audio_slot_vsync (audio , 0 ));
264291 // Unspecified VIC: preserve CircuitPython's existing 625-line timing.
265292 hstx_packet_set_avi_infoframe (& packet , 0 , 0 );
266293 dvi_audio_encode (audio -> avi_infoframe , & packet , dvi_audio_slot_vsync (audio , 1 ));
@@ -404,8 +431,8 @@ static const uint32_t *dvi_audio_next_packet(dvi_audio_state_t *audio, const int
404431 size_t previous = slot == 0 ? DVI_AUDIO_SLOTS - 1 : slot - 1 ;
405432 size_t lines = (audio -> slot_line [slot ] + MODE_640_V_TOTAL_LINES - audio -> slot_line [previous ]) % MODE_640_V_TOTAL_LINES ;
406433 const uint64_t pixel_clock = audio -> pixel_clock ;
407- uint64_t sample_phase = audio -> sample_phase + (uint64_t )lines * DVI_AUDIO_RATE * DVI_AUDIO_H_TOTAL ;
408- uint64_t acr_phase = audio -> acr_phase + (uint64_t )lines * audio -> acr_rate * DVI_AUDIO_H_TOTAL ;
434+ uint64_t sample_phase = audio -> sample_phase + (uint64_t )lines * dvi_audio_rates [ audio -> rate_index ]. sample_rate * DVI_AUDIO_H_TOTAL ;
435+ uint64_t acr_phase = audio -> acr_phase + (uint64_t )lines * audio -> acr_rate [ audio -> rate_index ] * DVI_AUDIO_H_TOTAL ;
409436 // Never let sample timing build up a long burst.
410437 if (sample_phase > pixel_clock * 12 ) {
411438 sample_phase = pixel_clock * 12 ;
@@ -414,12 +441,12 @@ static const uint32_t *dvi_audio_next_packet(dvi_audio_state_t *audio, const int
414441 const uint32_t * island ;
415442 * count = 0 ;
416443 if (slot == 0 ) {
417- island = audio -> audio_infoframe ;
444+ island = audio -> audio_infoframe [ audio -> rate_index ] ;
418445 } else if (slot == 1 ) {
419446 island = audio -> avi_infoframe ;
420447 } else if (acr_phase >= pixel_clock ) {
421448 acr_phase -= pixel_clock ;
422- island = audio -> acr [vsync ];
449+ island = audio -> acr [audio -> rate_index ][ vsync ];
423450 } else {
424451 // Sample packets carry four frames, fewer only at the end of a
425452 // sample.
@@ -438,7 +465,8 @@ static const uint32_t *dvi_audio_next_packet(dvi_audio_state_t *audio, const int
438465 packet_samples [i ].right = samples [2 * i + 1 ];
439466 }
440467 hstx_packet_t packet ;
441- audio -> channel_frame = hstx_packet_set_audio_samples (& packet , packet_samples , n , audio -> channel_frame );
468+ audio -> channel_frame = hstx_packet_set_audio_samples (& packet , packet_samples , n , audio -> channel_frame ,
469+ dvi_audio_rates [audio -> rate_index ].sample_rate );
442470 uint32_t * buffer = audio -> pool [audio -> pool_head ];
443471 dvi_audio_encode (buffer , & packet , vsync );
444472 audio -> pool_position [audio -> pool_head ] = audio -> write_position ;
@@ -466,7 +494,9 @@ static const uint32_t *dvi_audio_next_packet(dvi_audio_state_t *audio, const int
466494//
467495// With nothing to play, every frame comes out the same once the timing at
468496// slot 0 repeats. Then the slots already hold the right packets, and this
469- // stops writing until there is something to play.
497+ // stops writing until there is something to play. At 44.1 kHz a frame holds
498+ // 882 samples, not a whole number of packets, so frames never repeat and
499+ // silence keeps being written.
470500static bool dvi_audio_fill_slot (picodvi_framebuffer_obj_t * self , dvi_audio_state_t * audio , const int16_t * samples , size_t available , bool wait , size_t * used ) {
471501 * used = 0 ;
472502 bool idle = available == 0 && !wait ;
@@ -489,6 +519,7 @@ static bool dvi_audio_fill_slot(picodvi_framebuffer_obj_t *self, dvi_audio_state
489519 audio -> idle_steady = false;
490520 audio -> idle_run = 0 ;
491521 }
522+ audio -> rate_index = audio -> next_rate_index ;
492523 // Free the pool buffers DMA has finished with.
493524 while (audio -> pool_count > 0 && audio -> pool_position [audio -> pool_tail ] < read ) {
494525 audio -> pool_tail = (audio -> pool_tail + 1 ) % DVI_AUDIO_POOL ;
@@ -692,6 +723,12 @@ static void picodvi_framebuffer_audio_stop(picodvi_framebuffer_obj_t *self) {
692723 memset (audio -> slot_samples , 0 , sizeof (audio -> slot_samples ));
693724}
694725
726+ // Sends the rate at rate_index in dvi_audio_rates from the next slot written.
727+ // The packets already written ahead of DMA keep the old rate.
728+ static void picodvi_framebuffer_audio_set_rate (picodvi_framebuffer_obj_t * self , size_t rate_index ) {
729+ self -> dvi_audio -> next_rate_index = rate_index ;
730+ }
731+
695732// Convert up to space frames of the current sample buffer into the stage.
696733static void audioout_convert (picodvi_audioout_obj_t * self , size_t space ) {
697734 audiosample_base_t * base = audiosample_cast_obj (self -> sample );
@@ -885,12 +922,19 @@ void common_hal_picodvi_audioout_deinit(picodvi_audioout_obj_t *self) {
885922
886923void common_hal_picodvi_audioout_play (picodvi_audioout_obj_t * self , mp_obj_t sample , bool loop ) {
887924 audiosample_base_t * base = audiosample_check (sample );
888- mp_arg_validate_int (base -> sample_rate , 48000 , MP_QSTR_sample_rate );
925+ size_t rate_index = 0 ;
926+ while (rate_index < DVI_AUDIO_RATE_COUNT && dvi_audio_rates [rate_index ].sample_rate != base -> sample_rate ) {
927+ rate_index ++ ;
928+ }
929+ if (rate_index == DVI_AUDIO_RATE_COUNT ) {
930+ mp_raise_ValueError_varg (MP_ERROR_TEXT ("Invalid %q" ), MP_QSTR_sample_rate );
931+ }
889932 mp_arg_validate_int_range (base -> channel_count , 1 , 2 , MP_QSTR_channel_count );
890933 if (base -> bits_per_sample != 8 && base -> bits_per_sample != 16 ) {
891934 mp_raise_ValueError_varg (MP_ERROR_TEXT ("Invalid %q" ), MP_QSTR_bits_per_sample );
892935 }
893936 common_hal_picodvi_audioout_stop (self );
937+ picodvi_framebuffer_audio_set_rate (self -> framebuffer , rate_index );
894938 audiosample_reset_buffer (sample , false, 0 );
895939 self -> bytes_per_frame = base -> channel_count * base -> bits_per_sample / 8 ;
896940 self -> source_frames = 0 ;
0 commit comments