diff --git a/README.md b/README.md index 4a09fa3..b9b9b67 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Module name: `dixwaveform` · target: **VLC 3.0.x**, macOS **arm64** (portable t - Reads the live 32-bit-float PCM buffer, computes real-time analysis, renders a 1280x720 analyzer frame, and **passes the audio through untouched**. - Shows engineering views: scrolling log spectrogram, FFT magnitude/peak-hold spectrum, stereo waveform/oscilloscope, and stereo phase + peak/RMS/crest/clip meters. - Plus a **`compose` view** that *hears the music*: a live chromagram (12 pitch classes), circle-of-fifths **key detection**, a nearest-note + cents tuning readout, and an **energy/build-drop ribbon** — grounded in the Dix music library (pitch math from *Mathematics and Music*; groove/structure from *Unlocking the Groove*). -- **Switch views in-window** — a row of clickable tabs across the top (`DASH · KEYS · SPECTRO · SPECTRUM · WAVE · STEREO`) lets you jump between layouts with a mouse click, no VLC menus. (`KEYS` = the compose/key view.) +- **Switch views in-window** — a row of clickable tabs across the top (`DASH · KEYS (COMPOSE) · SPECTRO · SPECTRUM · WAVE · STEREO`) lets you jump between layouts with a mouse click, no VLC menus. (`KEYS (COMPOSE)` = the key/compose view.) - Selectable via **Audio ▸ Visualizations ▸ Dix Analyzer**, or `--audio-visual=dixwaveform`. ## Install (macOS / Linux) @@ -104,7 +104,7 @@ The **`lufs`** panel is a real ITU-R BS.1770-4 / EBU R128 loudness meter: moment The music theory is grounded in the Dix library: pitch math (A440, `midi = 69 + 12·log2(f/440)`, cents) from *Mathematics and Music*; key/groove framing from *Unlocking the Groove* and the *Complete Idiot's Guide to Music Composition*. The DSP lives in `dix_pitch.h` and is unit-tested (see **Tests**). -**Access it:** click the **KEYS** tab at the top of the Dix window, launch with `--dix-layout=compose`, or set the layout in the plugin's advanced preferences. +**Access it:** click the **KEYS (COMPOSE)** tab at the top of the Dix window, launch with `--dix-layout=compose`, or set the layout in the plugin's advanced preferences. ## Tests & CI diff --git a/waveform.c b/waveform.c index da1d214..bf6544f 100644 --- a/waveform.c +++ b/waveform.c @@ -29,7 +29,7 @@ #include "dix_pitch.h" /* pure pitch/chroma/key DSP (unit-tested standalone) */ #include "dix_lufs.h" /* ITU-R BS.1770 loudness (unit-tested standalone) */ -#define DIX_VERSION "3.5.1" +#define DIX_VERSION "3.5.2" #define DIX_W 1280 #define DIX_H 720 #define DIX_MAX_FFT 8192 @@ -1559,20 +1559,34 @@ static const int dix_tab_layout[] = { DIX_LAYOUT_SPECTRUM, DIX_LAYOUT_WAVEFORM, DIX_LAYOUT_STEREO }; static const char *const dix_tab_label[] = { - "DASH", "KEYS", "SPECTRO", "SPECTRUM", "WAVE", "STEREO" + "DASH", "KEYS (COMPOSE)", "SPECTRO", "SPECTRUM", "WAVE", "STEREO" }; #define DIX_TAB_COUNT 6 #define DIX_TAB_Y 8 #define DIX_TAB_H 28 #define DIX_TAB_X0 60 -#define DIX_TAB_X1 ( DIX_W - 308 ) /* tabs end here; the info block sits beyond */ #define DIX_TAB_GAP 6 +#define DIX_TAB_PAD 15 /* px of padding on each side of a label */ + +/* Pixel width of a label at the tab text scale (2), matching draw_text()'s + * advance: 12 px per glyph, 8 px per space. */ +static int dix_text_w2( const char *t ) +{ + int w = 0; + for( const char *p = t; *p; p++ ) w += ( *p == ' ' ) ? 8 : 12; + return w; +} + +/* Tabs are sized to their labels (so "KEYS (COMPOSE)" isn't clipped) and laid + * out left to right. Both the renderer and the click hit-test call this, so + * drawing and hit-testing can never drift. */ +static int dix_tab_w( int i ) { return dix_text_w2( dix_tab_label[i] ) + DIX_TAB_PAD * 2; } static rect_t dix_tab_rect( int i ) { - int span = DIX_TAB_X1 - DIX_TAB_X0; - int tw = ( span - DIX_TAB_GAP * ( DIX_TAB_COUNT - 1 ) ) / DIX_TAB_COUNT; - rect_t r = { DIX_TAB_X0 + i * ( tw + DIX_TAB_GAP ), DIX_TAB_Y, tw, DIX_TAB_H }; + int x = DIX_TAB_X0; + for( int k = 0; k < i; k++ ) x += dix_tab_w( k ) + DIX_TAB_GAP; + rect_t r = { x, DIX_TAB_Y, dix_tab_w( i ), DIX_TAB_H }; return r; } @@ -1584,8 +1598,8 @@ static void draw_tab_bar( filter_sys_t *s ) int active = ( s->dash_count == 0 && s->layout == dix_tab_layout[i] ); fill_rect( s, r, active ? rgb( 34, 88, 74 ) : rgb( 15, 19, 27 ) ); draw_rect( s, r, active ? rgb( 120, 226, 180 ) : rgb( 52, 62, 78 ) ); - int lw = (int)strlen( dix_tab_label[i] ) * 12; /* scale-2 glyph = 12 px wide */ - int tx = r.x + ( r.w - lw ) / 2; if( tx < r.x + 4 ) tx = r.x + 4; + int lw = dix_text_w2( dix_tab_label[i] ); + int tx = r.x + ( r.w - lw ) / 2; int ty = r.y + ( r.h - 14 ) / 2; /* scale-2 glyph = 14 px tall */ draw_text( s, tx, ty, dix_tab_label[i], active ? rgb( 230, 255, 240 ) : rgb( 150, 166, 182 ), 2 );