Pink noise as a source (mode "pink")

Core: aes67_tx_pink_noise(), a ready-made TX source: xorshift32 white noise
through Paul Kellet's pink filter, -18 dBFS RMS (peaks about -6 dBFS), same
on L and R. The player uses it like the tone (straight to TX, no volume or
gain). Checked on the board: -18 dBFS RMS, octave bands 63 Hz-4 kHz flat
within +-0.4 dB, L = R.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-25 23:37:05 +10:00
parent bbeb7d3fd2
commit 122e46e862
8 changed files with 58 additions and 16 deletions
+17 -9
View File
@@ -27,9 +27,9 @@
static const char *TAG = "player";
typedef enum { MODE_TONE, MODE_OFF, MODE_HLS, MODE_SPOTIFY, MODE_AUTO } mode_t_;
static const char *const SRC_NAME[] = { "tone", "off", "hls", "spotify" };
static const char *const MODE_NAME[] = { "tone", "off", "hls", "spotify", "auto" };
typedef enum { MODE_TONE, MODE_OFF, MODE_HLS, MODE_SPOTIFY, MODE_AUTO, MODE_PINK } mode_t_;
static const char *const SRC_NAME[] = { "tone", "off", "hls", "spotify", "pink" };
static const char *const MODE_NAME[] = { "tone", "off", "hls", "spotify", "auto", "pink" };
static volatile mode_t_ s_mode = MODE_OFF;
static volatile player_src_t s_src = PLAYER_SRC_OFF; // what is playing now
@@ -110,7 +110,7 @@ static void apply_fade(int32_t *buf, size_t frames, int *left, bool in)
static mode_t_ mode_of(const char *m)
{
return !strcmp(m, "tone") ? MODE_TONE : !strcmp(m, "hls") ? MODE_HLS : !strcmp(m, "spotify") ? MODE_SPOTIFY :
!strcmp(m, "auto") ? MODE_AUTO : MODE_OFF;
!strcmp(m, "auto") ? MODE_AUTO : !strcmp(m, "pink") ? MODE_PINK : MODE_OFF;
}
/* ----- output (AES67 TX pull callback, TX task, must not block) ----- */
@@ -168,8 +168,14 @@ static size_t player_read(int32_t *buf, size_t frames)
return got;
}
// Set the source to play. Tone comes from TX itself (phase-locked to PTP), so switches from/to it
// are immediate; everything else fades through player_read.
// Test signals: straight from the core to TX, not through the ring, volume or gain.
static bool is_test_signal(player_src_t src)
{
return src == PLAYER_SRC_TONE || src == PLAYER_SRC_PINK;
}
// Set the source to play. Test signals come from the core (the tone phase-locked to PTP), so
// switches from/to them are immediate; everything else fades through player_read.
static void select_source(player_src_t src)
{
if (src == s_target) {
@@ -180,10 +186,11 @@ static void select_source(player_src_t src)
s_hls_paused = false;
hls_suspend(HLS_SUSPEND_USER, false);
}
if (src == PLAYER_SRC_TONE || s_src == PLAYER_SRC_TONE) {
if (is_test_signal(src) || is_test_signal(s_src)) {
s_target = s_src = src;
s_flush = true;
aes67_tx_set_source(src == PLAYER_SRC_TONE ? NULL : player_read);
aes67_tx_set_source(src == PLAYER_SRC_TONE ? NULL : src == PLAYER_SRC_PINK ? aes67_tx_pink_noise :
player_read);
return;
}
s_target = src; // player_read fades out and switches
@@ -213,6 +220,7 @@ static void apply_mode(void)
hls_suspend(HLS_SUSPEND_FAILOVER, mode == MODE_AUTO);
switch (mode) {
case MODE_TONE: select_source(PLAYER_SRC_TONE); break;
case MODE_PINK: select_source(PLAYER_SRC_PINK); break;
case MODE_HLS: select_source(PLAYER_SRC_HLS); break;
case MODE_SPOTIFY: select_source(PLAYER_SRC_SPOTIFY); break;
case MODE_AUTO: select_source(PLAYER_SRC_SPOTIFY); break; // Spotify inactive: HLS after the delay
@@ -369,7 +377,7 @@ static void on_ota(bool starting)
static const char *source_state(player_src_t src)
{
return src == PLAYER_SRC_TONE ? "playing" : src == PLAYER_SRC_OFF ? "idle" :
return is_test_signal(src) ? "playing" : src == PLAYER_SRC_OFF ? "idle" :
src == PLAYER_SRC_SPOTIFY && !spotify_session_active() ? "idle" :
src == PLAYER_SRC_SPOTIFY && s_paused ? "paused" :
src == PLAYER_SRC_HLS && s_hls_paused ? "paused" : s_playing ? "playing" : "buffering";
+2 -2
View File
@@ -1,4 +1,4 @@
// Project player: picks the audio source for AES67 TX (test tone, silence, HLS, Spotify).
// Project player: picks the audio source for AES67 TX (test tone, pink noise, silence, HLS, Spotify).
#pragma once
#include <stddef.h>
@@ -7,7 +7,7 @@
#include "cJSON.h"
#include "esp_err.h"
typedef enum { PLAYER_SRC_TONE, PLAYER_SRC_OFF, PLAYER_SRC_HLS, PLAYER_SRC_SPOTIFY } player_src_t;
typedef enum { PLAYER_SRC_TONE, PLAYER_SRC_OFF, PLAYER_SRC_HLS, PLAYER_SRC_SPOTIFY, PLAYER_SRC_PINK } player_src_t;
esp_err_t player_init(void);
// Apply the "source" config group (mode etc.).
+1 -1
View File
@@ -12,7 +12,7 @@ static const char SOURCE_DEFAULTS[] =
static bool source_validate(const cJSON *g, char *err, size_t n)
{
static const char *const modes[] = { "spotify", "hls", "auto", "tone", "off", NULL };
static const char *const modes[] = { "spotify", "hls", "auto", "tone", "pink", "off", NULL };
static const double bitrates[] = { 96, 160, 320 };
return cfg_check_enum(g, "mode", modes, err, n) &&
cfg_check_str(g, "spotify_name", 1, 63, err, n) &&