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+ // IEC 60958 channel status byte 3.
32+ uint8_t channel_status ;
33+ } dvi_audio_rate_t ;
34+
35+ // The basic audio rates every DVI sink takes.
36+ static const dvi_audio_rate_t dvi_audio_rates [] = {
37+ { 32000 , 4096 , 0x03 },
38+ { 44100 , 6272 , 0x00 },
39+ { 48000 , 6144 , 0x02 },
40+ };
41+ #define DVI_AUDIO_RATE_COUNT MP_ARRAY_SIZE(dvi_audio_rates)
2842#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)
2943// 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
44+ // and 48 kHz a 625 line frame needs 240 sample packets, 20 ACR packets and 2
3145// InfoFrames.
3246#define DVI_AUDIO_SLOTS 280
3347// Buffers for encoded sample packets. Other packets never change, so their
34- // islands point at fixed copies. 160 hold about 13 ms of audio.
48+ // islands point at fixed copies. 160 hold about 13 ms of 48 kHz audio.
3549#define DVI_AUDIO_POOL 160
3650// Packet words of an island, without its two guard band words at each end.
3751#define DVI_AUDIO_SLOT_WORDS (HSTX_DATA_ISLAND_WORDS - 4)
@@ -82,8 +96,12 @@ typedef struct dvi_audio_state {
8296 size_t pool_tail ;
8397 size_t pool_count ;
8498 uint32_t pixel_clock ;
85- // ACR packets per second, 128 * 48000 / N.
86- uint32_t acr_rate ;
99+ // The rate being sent, and the rate play() asked for, which takes over
100+ // from the next slot written. Indexes into dvi_audio_rates.
101+ size_t rate_index ;
102+ size_t next_rate_index ;
103+ // ACR packets per second at each rate, 128 * fs / N.
104+ uint32_t acr_rate [DVI_AUDIO_RATE_COUNT ];
87105 // Sample and ACR timing, carried from slot to slot.
88106 uint64_t sample_phase ;
89107 uint64_t acr_phase ;
@@ -100,10 +118,10 @@ typedef struct dvi_audio_state {
100118 uint16_t slot_line [DVI_AUDIO_SLOTS ];
101119 uint8_t slot_samples [DVI_AUDIO_SLOTS ];
102120 // Packets that never change, for blanking [0] and vsync [1] lines.
103- dvi_audio_island_t acr [2 ];
121+ dvi_audio_island_t acr [DVI_AUDIO_RATE_COUNT ][ 2 ];
104122 dvi_audio_island_t null_packet [2 ];
105123 dvi_audio_island_t silence [2 ];
106- dvi_audio_island_t audio_infoframe ;
124+ dvi_audio_island_t audio_infoframe [ DVI_AUDIO_RATE_COUNT ] ;
107125 dvi_audio_island_t avi_infoframe ;
108126 uint32_t prefix [2 ][DVI_AUDIO_PREFIX_WORDS ];
109127 uint32_t suffix_blank [2 ][DVI_AUDIO_SUFFIX_BLANK_WORDS ];
@@ -215,19 +233,17 @@ static uint32_t *dvi_audio_slot_island(dvi_audio_state_t *audio, size_t slot) {
215233 return & audio -> commands [(audio -> slot_entry [slot ] + 1 ) * audio -> command_size - 1 ];
216234}
217235
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.
236+ // Pick N so that every frame has the same whole number of ACR packets, and
237+ // CTS is exact. Then a frame of silence repeats exactly and needs no
238+ // rewriting. N may be anything from 128 * fs / 1500 to 128 * fs / 300.
239+ // If no N fits, use the usual N for the rate and round CTS.
240+ static uint32_t dvi_audio_find_n (uint32_t pixel_clock , const dvi_audio_rate_t * rate_info ) {
224241 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 ;
242+ const uint32_t n_times_rate = 128 * rate_info -> sample_rate ;
243+ uint32_t per_frame = (1000 * frame_pixels + pixel_clock / 2 ) / pixel_clock ;
228244 for (uint32_t k = per_frame - 1 ; k <= per_frame + 1 ; k ++ ) {
229245 // ACR packets per second when each frame has k.
230- uint64_t rate = (uint64_t )k * audio -> pixel_clock ;
246+ uint64_t rate = (uint64_t )k * pixel_clock ;
231247 if (k == 0 || rate % frame_pixels != 0 ) {
232248 continue ;
233249 }
@@ -237,30 +253,43 @@ static void dvi_audio_init_packets(dvi_audio_state_t *audio) {
237253 }
238254 uint32_t candidate = n_times_rate / rate ;
239255 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 ;
256+ ((uint64_t )pixel_clock * candidate ) % n_times_rate == 0 ) {
257+ return candidate ;
243258 }
244259 }
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 );
260+ return rate_info -> usual_n ;
261+ }
262+
263+ static void dvi_audio_init_packets (dvi_audio_state_t * audio ) {
264+ hstx_packet_t packet ;
265+ for (size_t rate_index = 0 ; rate_index < DVI_AUDIO_RATE_COUNT ; rate_index ++ ) {
266+ const dvi_audio_rate_t * rate_info = & dvi_audio_rates [rate_index ];
267+ const uint32_t n_times_rate = 128 * rate_info -> sample_rate ;
268+ uint32_t n = dvi_audio_find_n (audio -> pixel_clock , rate_info );
269+ audio -> acr_rate [rate_index ] = n_times_rate / n ;
270+ uint32_t cts = ((uint64_t )audio -> pixel_clock * n + n_times_rate / 2 ) / n_times_rate ;
271+ hstx_packet_set_acr (& packet , n , cts );
272+ for (int vsync = 0 ; vsync < 2 ; vsync ++ ) {
273+ dvi_audio_encode (audio -> acr [rate_index ][vsync ], & packet , vsync );
274+ }
275+ // The first two slots of every frame carry the InfoFrames.
276+ hstx_packet_set_audio_infoframe (& packet , rate_info -> sample_rate , 2 , 16 );
277+ dvi_audio_encode (audio -> audio_infoframe [rate_index ], & packet , dvi_audio_slot_vsync (audio , 0 ));
250278 }
279+ // 48 kHz until play() asks for another rate.
280+ audio -> rate_index = DVI_AUDIO_RATE_COUNT - 1 ;
281+ audio -> next_rate_index = audio -> rate_index ;
251282 hstx_packet_init (& packet );
252283 for (int vsync = 0 ; vsync < 2 ; vsync ++ ) {
253284 dvi_audio_encode (audio -> null_packet [vsync ], & packet , vsync );
254285 }
255- // Frame position 4 never sets the block start flag.
286+ // Frame position 4 never sets the block start flag, and frames 4 to 7
287+ // carry no channel status bits, so silence is the same at every rate.
256288 audio_sample_t silence [4 ] = {{0 }};
257- hstx_packet_set_audio_samples (& packet , silence , 4 , 4 );
289+ hstx_packet_set_audio_samples (& packet , silence , 4 , 4 , dvi_audio_rates [ DVI_AUDIO_RATE_COUNT - 1 ]. channel_status );
258290 for (int vsync = 0 ; vsync < 2 ; vsync ++ ) {
259291 dvi_audio_encode (audio -> silence [vsync ], & packet , vsync );
260292 }
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 ));
264293 // Unspecified VIC: preserve CircuitPython's existing 625-line timing.
265294 hstx_packet_set_avi_infoframe (& packet , 0 , 0 );
266295 dvi_audio_encode (audio -> avi_infoframe , & packet , dvi_audio_slot_vsync (audio , 1 ));
@@ -404,8 +433,8 @@ static const uint32_t *dvi_audio_next_packet(dvi_audio_state_t *audio, const int
404433 size_t previous = slot == 0 ? DVI_AUDIO_SLOTS - 1 : slot - 1 ;
405434 size_t lines = (audio -> slot_line [slot ] + MODE_640_V_TOTAL_LINES - audio -> slot_line [previous ]) % MODE_640_V_TOTAL_LINES ;
406435 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 ;
436+ uint64_t sample_phase = audio -> sample_phase + (uint64_t )lines * dvi_audio_rates [ audio -> rate_index ]. sample_rate * DVI_AUDIO_H_TOTAL ;
437+ uint64_t acr_phase = audio -> acr_phase + (uint64_t )lines * audio -> acr_rate [ audio -> rate_index ] * DVI_AUDIO_H_TOTAL ;
409438 // Never let sample timing build up a long burst.
410439 if (sample_phase > pixel_clock * 12 ) {
411440 sample_phase = pixel_clock * 12 ;
@@ -414,12 +443,12 @@ static const uint32_t *dvi_audio_next_packet(dvi_audio_state_t *audio, const int
414443 const uint32_t * island ;
415444 * count = 0 ;
416445 if (slot == 0 ) {
417- island = audio -> audio_infoframe ;
446+ island = audio -> audio_infoframe [ audio -> rate_index ] ;
418447 } else if (slot == 1 ) {
419448 island = audio -> avi_infoframe ;
420449 } else if (acr_phase >= pixel_clock ) {
421450 acr_phase -= pixel_clock ;
422- island = audio -> acr [vsync ];
451+ island = audio -> acr [audio -> rate_index ][ vsync ];
423452 } else {
424453 // Sample packets carry four frames, fewer only at the end of a
425454 // sample.
@@ -438,7 +467,8 @@ static const uint32_t *dvi_audio_next_packet(dvi_audio_state_t *audio, const int
438467 packet_samples [i ].right = samples [2 * i + 1 ];
439468 }
440469 hstx_packet_t packet ;
441- audio -> channel_frame = hstx_packet_set_audio_samples (& packet , packet_samples , n , audio -> channel_frame );
470+ audio -> channel_frame = hstx_packet_set_audio_samples (& packet , packet_samples , n , audio -> channel_frame ,
471+ dvi_audio_rates [audio -> rate_index ].channel_status );
442472 uint32_t * buffer = audio -> pool [audio -> pool_head ];
443473 dvi_audio_encode (buffer , & packet , vsync );
444474 audio -> pool_position [audio -> pool_head ] = audio -> write_position ;
@@ -466,7 +496,9 @@ static const uint32_t *dvi_audio_next_packet(dvi_audio_state_t *audio, const int
466496//
467497// With nothing to play, every frame comes out the same once the timing at
468498// slot 0 repeats. Then the slots already hold the right packets, and this
469- // stops writing until there is something to play.
499+ // stops writing until there is something to play. At 44.1 kHz a frame holds
500+ // 882 samples, not a whole number of packets, so frames never repeat and
501+ // silence keeps being written.
470502static 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 ) {
471503 * used = 0 ;
472504 bool idle = available == 0 && !wait ;
@@ -489,6 +521,7 @@ static bool dvi_audio_fill_slot(picodvi_framebuffer_obj_t *self, dvi_audio_state
489521 audio -> idle_steady = false;
490522 audio -> idle_run = 0 ;
491523 }
524+ audio -> rate_index = audio -> next_rate_index ;
492525 // Free the pool buffers DMA has finished with.
493526 while (audio -> pool_count > 0 && audio -> pool_position [audio -> pool_tail ] < read ) {
494527 audio -> pool_tail = (audio -> pool_tail + 1 ) % DVI_AUDIO_POOL ;
@@ -692,6 +725,12 @@ static void picodvi_framebuffer_audio_stop(picodvi_framebuffer_obj_t *self) {
692725 memset (audio -> slot_samples , 0 , sizeof (audio -> slot_samples ));
693726}
694727
728+ // Sends the rate at rate_index in dvi_audio_rates from the next slot written.
729+ // The packets already written ahead of DMA keep the old rate.
730+ static void picodvi_framebuffer_audio_set_rate (picodvi_framebuffer_obj_t * self , size_t rate_index ) {
731+ self -> dvi_audio -> next_rate_index = rate_index ;
732+ }
733+
695734// Convert up to space frames of the current sample buffer into the stage.
696735static void audioout_convert (picodvi_audioout_obj_t * self , size_t space ) {
697736 audiosample_base_t * base = audiosample_cast_obj (self -> sample );
@@ -885,12 +924,19 @@ void common_hal_picodvi_audioout_deinit(picodvi_audioout_obj_t *self) {
885924
886925void common_hal_picodvi_audioout_play (picodvi_audioout_obj_t * self , mp_obj_t sample , bool loop ) {
887926 audiosample_base_t * base = audiosample_check (sample );
888- mp_arg_validate_int (base -> sample_rate , 48000 , MP_QSTR_sample_rate );
927+ size_t rate_index = 0 ;
928+ while (rate_index < DVI_AUDIO_RATE_COUNT && dvi_audio_rates [rate_index ].sample_rate != base -> sample_rate ) {
929+ rate_index ++ ;
930+ }
931+ if (rate_index == DVI_AUDIO_RATE_COUNT ) {
932+ mp_raise_ValueError_varg (MP_ERROR_TEXT ("Invalid %q" ), MP_QSTR_sample_rate );
933+ }
889934 mp_arg_validate_int_range (base -> channel_count , 1 , 2 , MP_QSTR_channel_count );
890935 if (base -> bits_per_sample != 8 && base -> bits_per_sample != 16 ) {
891936 mp_raise_ValueError_varg (MP_ERROR_TEXT ("Invalid %q" ), MP_QSTR_bits_per_sample );
892937 }
893938 common_hal_picodvi_audioout_stop (self );
939+ picodvi_framebuffer_audio_set_rate (self -> framebuffer , rate_index );
894940 audiosample_reset_buffer (sample , false, 0 );
895941 self -> bytes_per_frame = base -> channel_count * base -> bits_per_sample / 8 ;
896942 self -> source_frames = 0 ;
0 commit comments