Mcaster1DSPEncoder — Refactor & Development Roadmap

Fork of: EdCast/Oddsock DSP encoder by Ed Zaleski Maintainer: Dave St. John <davestj@gmail.com> Repository: github.com/davestj/Mcaster1DSPEncoder Phase 1: COMPLETE Phase 2: COMPLETE Phase 3: COMPLETE Phase 4: COMPLETE Phase 5: IN PROGRESS Last Updated: 2026-02-22

Project Overview

Mcaster1DSPEncoder is an open-source, multi-format audio streaming DSP encoder suite — a maintained, modernized fork of the EdCast/Oddsock DSP encoder lineage. It ships as a plugin for Winamp, foobar2000, and RadioDJ, and as a self-contained encoder application targeting Shoutcast and Icecast servers.

Phase 1
VS2022 Build Fix

All 4 build targets compiling and running under VS2022 v143 toolset.


COMPLETE
Phase 2
Rebrand & Refactor

Full AltaCast → Mcaster1DSPEncoder rename, ResizableLib UI, Segoe UI, native LAME.


COMPLETE
Phase 3
Audio Modernization

MP3/LAME, Opus, HE-AAC/fdk-aac, OggVorbis, FLAC. PortAudio WASAPI capture. Volume slider. All codecs integrated and tested.


COMPLETE
Phase 4
YAML Multi-Station

YAML-first init across all 4 targets. Per-encoder YAML files, legacy .cfg migration. config_yaml.cpp in all vcxproj files.


COMPLETE
Phase 5
Podcast & ICY 2.2

Podcast RSS feed gen, Podcast Settings tab, ICY 2.2 Extended tab (all 12 categories), header injection on Icecast2 connect, config save hardening.


IN PROGRESS
Phase 6
Mcaster1DNAS Integration

Auto-discovery, shared YAML config, live health feedback, song history push API.


PLANNED
Phase 7
Mcaster1Castit

Castit VC6 → VS2022: libxml2 / libcurl / libmariadb via vcpkg. Broadcast scheduler modernization.


PLANNED
Phase 8
Analytics & Engagement

Listener metrics, tune-in/tune-out signals, platform engagement via ICY 2.1, Castit playlist optimization.


PLANNED

Phase 1 — VS2022 Build Fix COMPLETE

All issues blocking compilation under Visual Studio 2022 (v143 toolset, Windows 10 SDK) were resolved. All 4 build targets compile cleanly and run without crashes.

TargetOutputStatus
Core encoder librarylibmcaster1dspencoder.libDONE
Winamp DSP plugindsp_mcaster1.dllDONE
RadioDJ DSP plugindsp_mcaster1_radiodj.dllDONE
foobar2000 componentfoo_mcaster1.dllDONE
Encoder applicationMcaster1DSPEncoder.exeDONE

Fixes Applied

Phase 2 — Rebrand & Refactor COMPLETE

Goal: Complete renaming of every AltaCast identity in the codebase. No new features. "Standalone" is dropped from all names — the application is self-contained by definition.

2.1 Naming Conventions

Old NameNew NameNotes
altacastStandalone.exeMcaster1DSPEncoder.exeDrop "Standalone" — implied
altacastStandalone.vcxprojMcaster1DSPEncoder.vcxproj
libaltacast/libmcaster1dspencoder/Rename directory
libaltacast.liblibmcaster1dspencoder.lib
libaltacast.vcxprojlibmcaster1dspencoder.vcxproj
libaltacast.cpp / .hlibmcaster1dspencoder.cpp / .h
libaltacast_socket.*libmcaster1dspencoder_socket.*
libaltacast_resample.*libmcaster1dspencoder_resample.*
dsp_altacast.dlldsp_mcaster1.dllWinamp plugin
altacast_winamp.vcxprojmcaster1_winamp.vcxproj
dsp_radiodj.dlldsp_mcaster1_radiodj.dllRadioDJ plugin
altacast_radiodj.vcxprojmcaster1_radiodj.vcxproj
foo_altacast.dllfoo_mcaster1.dllfoobar2000 component
altacast_foobar.vcxprojmcaster1_foobar.vcxproj
altacast.hmcaster1dspencoder.hShared plugin header
altacast.rcmcaster1dspencoder.rcShared resource file
altacastStandalone.slnMcaster1DSPEncoder.sln
altacaststandalone_N.cfgmcaster1dspencoder.cfgAlready done
APP_NAME=altacast_*APP_NAME=mcaster1_*Preprocessor defines

2.2 Deep Naming Audit — All 150+ Instances

Complete inventory of all instances requiring change, organized by category.

Category 1 — Class Names
CurrentNewFile
CaltacastStandaloneAppCMcaster1DSPEncoderAppaltacastStandalone.h:22
dsp_altacast (class)dsp_mcaster1altacast_foobar.cpp:153,253
initquit_altacastinitquit_mcaster1altacast_foobar.cpp:331
altacast_play_callback_uimcaster1_play_callback_uialtacast_foobar.cpp:356
altacastGlobals (struct)mcaster1Globalslibaltacast/libaltacast.h (all refs)
Category 2 — Function Names
CurrentNewFile(s)
altacast_init(altacastGlobals *g)mcaster1_init(mcaster1Globals *g)MainWindow.cpp:28,401,954,1005,1274,1360
altacast_init(altacastGlobals *g)mcaster1_init(mcaster1Globals *g)altacastStandalone.cpp:60
altacast_init(altacastGlobals *g)mcaster1_init(mcaster1Globals *g)altacast_radiodj.cpp:110
altacast_init(altacastGlobals *g)mcaster1_init(mcaster1Globals *g)altacast_foobar.cpp:68
altacast_init(altacastGlobals *g)mcaster1_init(mcaster1Globals *g)altacast_winamp.cpp:110
Category 3 — Preprocessor Defines & Header Guards
CurrentNewFile
#ifndef __DSP_ALTACAST_H#ifndef __DSP_MCASTER1_Hlibaltacast.h:1
#define __DSP_ALTACAST_H#define __DSP_MCASTER1_Hlibaltacast.h:2
FRONT_END_ALTACAST_PLUGIN 1FRONT_END_MCASTER1_PLUGIN 1libaltacast.h:110
AFX_ALTACASTSTANDALONE_H__*AFX_MCASTER1DSPENCODER_H__*altacastStandalone.h:4,5,50
#ifndef ALTACASTSTANDALONE#ifndef MCASTER1DSPENCODEREditMetadata.cpp:191
#ifdef ALTACASTSTANDALONE#ifdef MCASTER1DSPENCODERMainWindow.cpp:978,1061,1247
#ifndef ALTACASTSTANDALONE#ifndef MCASTER1DSPENCODERMainWindow.cpp:1482,1681
#ifdef altacastSTANDALONE#ifdef MCASTER1DSPENCODERlibaltacast.cpp:3090
IDD_ALTACAST_CONFIGIDD_MCASTER1_CONFIGresource.h:7
IDD_ALTACAST 301IDD_MCASTER1 301resource.h:30
IDD = IDD_ALTACASTIDD = IDD_MCASTER1MainWindow.h:56
ALTACAST_PLUGINMCASTER1_PLUGINaltacast_foobar.vcxproj:76,124
ALTACAST_PLUGINMCASTER1_PLUGINaltacast_radiodj.vcxproj:82,134
ALTACAST_WINAMP_EXPORTSMCASTER1_WINAMP_EXPORTSaltacast_winamp.vcxproj:82,131
ALTACAST_RADIODJ_EXPORTSMCASTER1_RADIODJ_EXPORTSaltacast_radiodj.vcxproj:82,134
ALTACASTSTANDALONEMCASTER1DSPENCODERaltacastStandalone.vcxproj:79,91,127
APP_NAME=altacast_foobarAPP_NAME=mcaster1_foobaraltacast_foobar.vcxproj:76,124
APP_NAME=altacast_radiodjAPP_NAME=mcaster1_radiodjaltacast_radiodj.vcxproj:82,134
APP_NAME=altacast_winampAPP_NAME=mcaster1_winampaltacast_winamp.vcxproj:82,131
Category 4 — String Literals & UI Text
Current StringNew StringFile
"AltaCast" (dialog caption)"Mcaster1 DSP Encoder"altacast.rc:35
"AltaCast 1.1" (about text)"Mcaster1 DSP Encoder"altacast.rc:189
"AltaCast Standalone" (caption)"Mcaster1 DSP Encoder"altacast.rc:197
"altacast\n" (foobar info)"mcaster1dspencoder\n"altacast_foobar.cpp:36
"Written by admin@altacast.com\n""Maintained by davestj@gmail.com\n"altacast_foobar.cpp:37
"dsp_altacastv2" (cfg key)"dsp_mcaster1v2"altacast_foobar.cpp:40
"altacast_foo" (log prefix)"mcaster1_foo"altacast_foobar.cpp:104
"altacast V3" (version str)"mcaster1dspencoder V3"altacast_foobar.cpp:282
"dsp_altacast" (log prefix)"dsp_mcaster1"altacast_radiodj.cpp:20
"altacaststandalone" (log prefix)"mcaster1dspencoder"altacastStandalone.cpp:19
LoadConfigs(currentDir, "altacaststandalone")LoadConfigs(currentDir, "mcaster1dspencoder")altacastStandalone.cpp:168
"dsp_altacast" (log prefix)"dsp_mcaster1"altacast_winamp.cpp:20
LoadConfigs(".", "altacaststandalone")LoadConfigs(".", "mcaster1dspencoder")Dummy.cpp:98
CInternetSession session("altacast")CInternetSession session("mcaster1dspencoder")MainWindow.cpp:193
"altacast" (tray notification)"mcaster1dspencoder"MainWindow.cpp:639
"altacast.chm" (help file)"mcaster1dspencoder.chm"MainWindow.cpp:1543
"altacast.log""mcaster1dspencoder.log"libaltacast.cpp:127
"altacast" (defaultConfigName)"mcaster1dspencoder"libaltacast.cpp:600,670,694
"altacast_aacp.ini""mcaster1_aacp.ini"libaltacast.cpp:2090
"ENCODEDBY","altacast" (FLAC tag)"ENCODEDBY","mcaster1dspencoder"libaltacast.cpp:2415
strcpy(g->gAppName, "altacast")strcpy(g->gAppName, "mcaster1dspencoder")libaltacast.cpp:2798,3253
"http://www.altacast.com""https://github.com/davestj/Mcaster1DSPEncoder"libaltacast.cpp:2834
Category 5 — Resource IDs & Dialog References
CurrentNewFile
IDD_ALTACASTIDD_MCASTER1altacast.rc:32
IDD_ALTACAST_CONFIGIDD_MCASTER1_CONFIGresource.h:7
mainWindow->Create((UINT)IDD_ALTACAST,...)mainWindow->Create((UINT)IDD_MCASTER1,...)altacast_foobar.cpp:131
mainWindow->Create((UINT)IDD_ALTACAST,...)mainWindow->Create((UINT)IDD_MCASTER1,...)altacast_radiodj.cpp:246
mainWindow->Create((UINT)IDD_ALTACAST,...)mainWindow->Create((UINT)IDD_MCASTER1,...)altacast_winamp.cpp:246
mainWindow->Create((UINT)IDD_ALTACAST,...)mainWindow->Create((UINT)IDD_MCASTER1,...)Dummy.cpp:108
Category 6 — DLL/EXE Output Names in vcxproj
CurrentNewFile
<TargetName>dsp_altacast</TargetName><TargetName>dsp_mcaster1</TargetName>altacast_winamp.vcxproj:47
<TargetName>foo_altacast</TargetName><TargetName>foo_mcaster1</TargetName>altacast_foobar.vcxproj:47
$(OutDir)dsp_altacast.dll$(OutDir)dsp_mcaster1.dllaltacast_winamp.vcxproj:101,148
foo_altacast.dll/.pdb/.libfoo_mcaster1.dll/.pdb/.libaltacast_foobar.vcxproj:93,103,141
$(OutDir)altacastStandalone.exe$(OutDir)Mcaster1DSPEncoder.exealtacastStandalone.vcxproj:96,144
libaltacast.lib/.pch/.bsclibmcaster1dspencoder.lib/.pch/.bsclibaltacast.vcxproj:76,81,105,110
Category 7 — Solution Files (.sln)
CurrentNewFile
Project name "altacastStandalone""Mcaster1DSPEncoder"altacastStandalone.sln:6
Project name "libaltacast""libmcaster1dspencoder"all .sln files
Project name "altacast_winamp""mcaster1_winamp"altacast_winamp.sln
Project name "altacast_foobar""mcaster1_foobar"altacast_foobar.sln
Project name "altacast_radiodj""mcaster1_radiodj"altacast_radiodj.sln
Category 8 — vcxproj Internal Paths & Namespaces
CurrentNewFiles
<RootNamespace>altacastStandalone</RootNamespace><RootNamespace>mcaster1dspencoder</RootNamespace>altacastStandalone.vcxproj:19
<RootNamespace>altacast_*</RootNamespace><RootNamespace>mcaster1_*</RootNamespace>all plugin vcxproj
<RootNamespace>libaltacast</RootNamespace><RootNamespace>libmcaster1dspencoder</RootNamespace>libaltacast.vcxproj:15
libaltacast;libaltacast_config (include dirs)libmcaster1dspencoder;libmcaster1dspencoder_configall vcxproj
libaltacast/Debug (lib dirs)libmcaster1dspencoder/Debugall vcxproj
ProjectReference Include="libaltacast\libaltacast.vcxproj"ProjectReference Include="libmcaster1dspencoder\libmcaster1dspencoder.vcxproj"all consumer vcxproj
Include="altacast.h" / Include="altacast.rc"Include="mcaster1dspencoder.h" / .rcall vcxproj
Include="altacast_winamp.cpp"Include="mcaster1_winamp.cpp"mcaster1_winamp.vcxproj
Include="altacast_foobar.cpp"Include="mcaster1_foobar.cpp"mcaster1_foobar.vcxproj
Include="altacast_radiodj.cpp"Include="mcaster1_radiodj.cpp"mcaster1_radiodj.vcxproj
Include="libaltacast.cpp/h"Include="libmcaster1dspencoder.cpp/h"libmcaster1dspencoder.vcxproj
Category 9 — InnoSetup Installer

All references in *.iss installer script:

2.3 File & Directory Renames

Ordered sequence to avoid broken references mid-rename:

Step 1 — Rename source files inside libaltacast/:
  libaltacast.cpp         → libmcaster1dspencoder.cpp
  libaltacast.h           → libmcaster1dspencoder.h
  libaltacast_socket.cpp  → libmcaster1dspencoder_socket.cpp
  libaltacast_socket.h    → libmcaster1dspencoder_socket.h
  libaltacast_resample.h  → libmcaster1dspencoder_resample.h
  libaltacast.vcxproj     → libmcaster1dspencoder.vcxproj

Step 2 — Rename libaltacast/ folder:
  src/libaltacast/        → src/libmcaster1dspencoder/

Step 3 — Rename plugin source files:
  altacast_winamp.cpp     → mcaster1_winamp.cpp
  altacast_winamp.h       → mcaster1_winamp.h
  altacast_foobar.cpp     → mcaster1_foobar.cpp
  altacast_radiodj.cpp    → mcaster1_radiodj.cpp
  altacast_radiodj.h      → mcaster1_radiodj.h

Step 4 — Rename shared files:
  altacast.h              → mcaster1dspencoder.h
  altacast.rc             → mcaster1dspencoder.rc
  altacastStandalone.h    → Mcaster1DSPEncoder.h
  altacastStandalone.cpp  → Mcaster1DSPEncoder.cpp

Step 5 — Rename project files:
  altacastStandalone.vcxproj  → Mcaster1DSPEncoder.vcxproj
  altacast_winamp.vcxproj     → mcaster1_winamp.vcxproj
  altacast_foobar.vcxproj     → mcaster1_foobar.vcxproj
  altacast_radiodj.vcxproj    → mcaster1_radiodj.vcxproj

Step 6 — Rename solution files:
  altacastStandalone.sln  → Mcaster1DSPEncoder.sln
  altacast_winamp.sln     → mcaster1_winamp.sln
  altacast_foobar.sln     → mcaster1_foobar.sln
  altacast_radiodj.sln    → mcaster1_radiodj.sln

2.4 Credits & Attribution

In all About dialogs, splash screens, installer text, and source file headers:

Mcaster1 DSP Encoder
Maintainer: Dave St. John <davestj@gmail.com>
https://github.com/davestj/Mcaster1DSPEncoder

Based on EdCast/Oddsock DSP encoder by Ed Zaleski
Original project: https://www.oddsock.org/

All source file copyright comment blocks — ADD, do not replace original:

// Mcaster1DSPEncoder — fork of EdCast/Oddsock DSP encoder
// Maintainer: Dave St. John <davestj@gmail.com>
// Original Author: Ed Zaleski

2.5 MP3 — Replace BladeMP3 with Native LAME

AltaCast uses BladeMP3EncDLL.h — an obsolete Windows-only interface. All US MP3 patents expired April 23, 2017. LAME (LGPL) is now freely distributable. LAME 3.100 source is in external/lame/; also available via vcpkg mp3lame:x64-windows.

  1. Upgrade external/lame/vc_solution/vc9_libmp3lame_dll.vcproj to v143, build libmp3lame.dll
  2. Replace #ifdef WIN32 BladeMP3 guards with #ifdef HAVE_LAME using standard lame.h API
  3. Remove BladeMP3EncDLL.h from external/include/
  4. Distribute libmp3lame.dll with all targets

2.6 Dual-Platform Build: x86 (Win32) and x64

Goal: Ship both 32-bit and 64-bit builds to maximize Windows compatibility. x64 for modern systems (Windows 10/11); x86 for legacy environments and 32-bit host applications (older Winamp builds, 32-bit RadioDJ, etc.). DSP plugins must match the bitness of the host application, so shipping both ensures broadest compatibility.

Step 1 — Install x86-windows vcpkg triplets x64-windows packages are already installed. Add x86 alongside them:
.\vcpkg install opus:x86-windows libopusenc:x86-windows mp3lame:x86-windows libyaml:x86-windows libflac:x86-windows libogg:x86-windows libvorbis:x86-windows fdk-aac[he-aac]:x86-windows libxml2:x86-windows curl:x86-windows

Step 2 — Add x64 Configurations to All vcxproj Files

Each project currently has Win32|Debug and Win32|Release. Add x64|Debug and x64|Release to each. Key changes per x64 config group:

Step 3 — DRY vcpkg Paths via MSBuild Property

<PropertyGroup>
  <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows</VcpkgTriplet>
  <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows</VcpkgTriplet>
  <VcpkgInclude>$(VCPKG_ROOT)\installed\$(VcpkgTriplet)\include</VcpkgInclude>
  <VcpkgLib>$(VCPKG_ROOT)\installed\$(VcpkgTriplet)\lib</VcpkgLib>
</PropertyGroup>

Step 4 — Release Artifact Layout

dist/
  Win32/
    Mcaster1DSPEncoder.exe
    dsp_mcaster1.dll  dsp_mcaster1_radiodj.dll  foo_mcaster1.dll
    libmp3lame.dll  opus.dll  opusenc.dll  fdk-aac.dll  ...
  x64/
    Mcaster1DSPEncoder.exe
    dsp_mcaster1.dll  dsp_mcaster1_radiodj.dll  foo_mcaster1.dll
    libmp3lame.dll  opus.dll  opusenc.dll  fdk-aac.dll  ...

Compatibility Matrix

Targetx86 Buildx64 Build
Mcaster1DSPEncoder.exeWin7+ (32-bit)Win10+ (64-bit)
dsp_mcaster1.dll (Winamp)Winamp 5.x 32-bitWinamp 5.9+ 64-bit
foo_mcaster1.dll (foobar2000)foobar2000 32-bitfoobar2000 64-bit
dsp_mcaster1_radiodj.dllRadioDJ (32-bit)RadioDJ 64-bit (future)
Plugin Bitness Must Match Host A 32-bit Winamp can only load 32-bit DSP plugins; a 64-bit Winamp requires 64-bit DLLs. Ship both builds so users install the one matching their host application.

2.7 Build System Cleanup

2.8 Phase 2 Deliverables

2.9 ResizableLib & Dialog Modernization COMPLETE

All MFC dialogs were modernized with resizable layout and professional flat styling using ResizableLib (Paolo Messina, Artistic License) from external/ResizableLib/. This was completed as part of Phase 2 to establish a consistent UI foundation before audio codec work.

Changes Applied

DialogClassChange
Main windowCMainWindowCDialogCResizableDialog, AddAnchor for all controls, encoder list anchors to BOTTOM_RIGHT
Config shellCConfigCResizableDialog, OnSize() to resize embedded tab page child dialogs via MoveWindow()
Basic Settings tabCBasicSettingsCResizableDialog, server/encoder fields anchor TOP_LEFT→TOP_RIGHT
YP Settings tabCYPSettingsCResizableDialog, stream metadata fields anchor TOP_LEFT→TOP_RIGHT
Advanced Settings tabCAdvancedSettingsCResizableDialog, log/archive path fields anchor TOP_LEFT→TOP_RIGHT
Edit MetadataCEditMetadataCResizableDialog, text fields expand, OK/Cancel anchor BOTTOM
Find WindowCFindWindowDlgCResizableDialog, list anchors BOTTOM_RIGHT

Dialog Style Updates (mcaster1dspencoder.rc)

Build Integration — All 4 Targets

ResizableLib sources compiled into all 4 build targets (standalone EXE + 3 DLL plugins), since all plugin projects compile the full MFC dialog source set. Each target's vcxproj has 8 ResizableLib ClCompile entries with:

<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalOptions>/wd4005 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>../external/ResizableLib;...</AdditionalIncludeDirectories>

NotUsing allows ResizableLib to find its own StdAfx.h (which defines WINVER=0x0501) via directory-first include resolution. /wd4005 suppresses the WINVER redefinition warning against the project-level 0x0601.

Plugin Build Gotcha — Resolved Plugin projects include MainWindow.h which declares CMainWindow : public CResizableDialog. ResizableDialog.h was only included via the main project's PCH, not available in plugin builds. Fix: #include "ResizableDialog.h" added directly inside MainWindow.h (making it self-contained regardless of which project includes it).

Phase 3 — Audio Backend Modernization COMPLETE

Goal: Remove WMA (end-of-life). Add dual MP3 paths (LAME built-in + ACM), Opus, and full HE-AAC (AAC-LC / HE-AACv1 / HE-AACv2) via fdk-aac. Replace bass.dll capture with statically-linked PortAudio (WASAPI / ASIO / MME / DS / WDM-KS). Achieve format parity with RadioBOSS: MP3 (×2), AAC-LC, AAC+, AAC++, Ogg Vorbis, Opus, FLAC.

vcpkg Packages for Phase 3

PackageVersionPurposeStatus
opus:x64-windows1.5.2Core Opus codecInstalled
libopusenc:x64-windows0.3High-level Opus encoding APIInstalled
fdk-aac:x64-windows[he-aac]2.0.3AAC-LC / HE-AAC / HE-AAC v2 encodingInstall Required
libflac:x64-windows1.5.0Updated FLACInstalled
libvorbis:x64-windows1.3.7Updated VorbisInstalled
Install fdk-aac before Phase 3 cd C:\vcpkg && .\vcpkg install fdk-aac[he-aac]:x64-windows
The [he-aac] feature enables HE-AAC (AAC+) and HE-AAC v2 (AAC++) alongside standard AAC-LC.

3.1 Remove basswma.dll / WMA REMOVE

Microsoft deprecated Windows Media Services. basswma.dll is a proprietary Un4seen plugin and is EOL.

3.2 Add Opus Encoder

vcpkg provides opus + libopusenc ready to link. Integration via libopusenc high-level API:

#include <opusenc.h>

OggOpusComments *comments = ope_comments_create();
ope_comments_add(comments, "ENCODER", "mcaster1dspencoder");
OggOpusEnc *enc = ope_encoder_create_callbacks(
    &callbacks, userdata, comments, 48000, channels, 0, &error);
ope_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate * 1000));
ope_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10));
ope_encoder_write(enc, pcm, samples_per_channel);
ope_encoder_drain(enc);
ope_encoder_destroy(enc);
ope_comments_destroy(comments);

MIME: audio/ogg; codecs=opus. Mount point extension: .opus.

3.3 Add AAC and AAC+ (HE-AAC) via fdk-aac

Replace the legacy libfaac dependency with fdk-aac 2.0.3, which supports AAC-LC, HE-AAC (AAC+), and HE-AAC v2 (AAC++/eAAC+). This achieves full RadioBOSS format parity.

Format Matrix

FormatProfileTypical BitrateBest For
AAC-LCLow Complexity96–256 kbpsHigh quality, broad compatibility
AAC+ (HE-AAC v1)High Efficiency32–96 kbpsLow-bitrate streaming
AAC++ (HE-AAC v2)High Efficiency v216–48 kbpsVery low bitrate (SBR + PS)

Integration via fdk-aac C API

#include <fdk-aac/aacenc_lib.h>

HANDLE_AACENCODER hEncoder;
aacEncOpen(&hEncoder, 0, channels);

// Profile selection:
// AOT_AAC_LC (2)  = standard AAC-LC
// AOT_SBR    (5)  = HE-AAC v1 (AAC+)  — adds Spectral Band Replication
// AOT_PS     (29) = HE-AAC v2 (AAC++) — adds Parametric Stereo on top of SBR
aacEncoder_SetParam(hEncoder, AACENC_AOT,         AOT_SBR);   // AAC+ example
aacEncoder_SetParam(hEncoder, AACENC_SAMPLERATE,  44100);
aacEncoder_SetParam(hEncoder, AACENC_CHANNELMODE, MODE_2);
aacEncoder_SetParam(hEncoder, AACENC_BITRATE,     64000);
aacEncoder_SetParam(hEncoder, AACENC_TRANSMUX,    TT_MP4_ADTS); // ADTS for live streaming

aacEncEncode(hEncoder, &inBufDesc, &outBufDesc, &inArgs, &outArgs);
aacEncClose(&hEncoder);

Recommended Bitrates (RadioBOSS Parity)

ProfileRecommended Bitrates
AAC-LC96, 128, 192, 256 kbps
AAC+ (HE-AACv1)32, 40, 48, 64 kbps
AAC++ (HE-AACv2)16, 24, 32 kbps
Patent Notice HE-AAC patents are managed through the Via Licensing AAC patent pool. The fdk-aac library itself is BSD-2 licensed. Verify your distribution license before shipping commercially. For non-commercial / internal use, no license fee applies.

3.4 Replace bass.dll with PortAudio

3.5 RadioBOSS Format Parity Summary

FormatLibraryStatus After Phase 3
MP3LAME (Phase 2)Done in Phase 2
AAC-LCfdk-aacNew in Phase 3
AAC+ (HE-AACv1)fdk-aac [he-aac]New in Phase 3
AAC++ (HE-AACv2)fdk-aac [he-aac]New in Phase 3
Ogg VorbislibvorbisExisting (updated)
OpuslibopusencNew in Phase 3
FLAClibFLACExisting (updated)
WMAbasswma.dllRemoved (EOL)

3.6 Phase 3 Deliverables

Phase 4 — YAML Multi-Station Configuration COMPLETE

Goal: Replace legacy flat key=value config with structured YAML supporting multiple simultaneous stations, per-station encoder chains, ICY/YP metadata, and save-to-WAV.

Already Available libyaml:x64-windows 0.2.5 is already installed in vcpkg — ready to integrate after Phase 2 x64 migration.

4.1 Current Config Problems

How the numbered files actually work (from source code) The encoder maintains altacastGlobals *g[MAX_ENCODERS] (max 10 slots, MainWindow.h:43). On startup each active slot is assigned encoderNumber = i + 1 (1-indexed). Config filenames are constructed in libaltacast.cpp as:

sprintf(configFile, "%s_%d.cfg", g->gConfigFileName, g->encoderNumber);
// → mcaster1dspencoder_1.cfg, mcaster1dspencoder_2.cfg, ...

Each numbered file is one encoder connection slot, not one station. To stream MP3 and Ogg simultaneously to the same server you need two slots (_1.cfg and _2.cfg) each pointing at the same server with different format settings.

4.2 New YAML Config Format

File: mcaster1dspencoder.yaml

global:
  log_level: info
  log_file: mcaster1dspencoder.log
  reconnect_delay: 5
  reconnect_on_drop: true

stations:
  - id: 1
    name: "My Rock Station"
    enabled: true
    icy:
      name: "My Rock Station"
      genre: "Rock"
      url: "https://mystation.example.com"
      description: "The best rock on the internet"
      pub: true
    server:
      type: icecast2
      host: stream.example.com
      port: 8000
      password: "hackme"
      mount: /rock
    encoders:
      - format: mp3
        bitrate: 128
        samplerate: 44100
        channels: 2
        quality: 5
        vbr: false
      - format: ogg
        bitrate: 96
        samplerate: 44100
        channels: 2
        quality: 0.6
      - format: opus
        bitrate: 128
        samplerate: 48000
        channels: 2
        complexity: 10
        signal: audio
      - format: aac
        profile: he-aacv1     # lc | he-aacv1 | he-aacv2
        bitrate: 64
        samplerate: 44100
        channels: 2
    archive:
      enabled: false
      path: "./recordings/"
      filename_pattern: "{station_id}_{date}_{time}.wav"
      max_size_mb: 2048

  - id: 2
    name: "My Jazz Stream"
    enabled: false
    icy:
      name: "Smooth Jazz 24/7"
      genre: "Jazz"
      url: "https://jazz.example.com"
      pub: false
    server:
      type: shoutcast2
      host: shout2.example.com
      port: 8002
      password: "jazzpass"
      mount: /jazz
    encoders:
      - format: mp3
        bitrate: 192
        samplerate: 44100
        channels: 2
        quality: 2
        vbr: true
        vbr_min: 96
        vbr_max: 320
    archive:
      enabled: true
      path: "D:/archive/jazz/"
      filename_pattern: "jazz_{date}.wav"
      max_size_mb: 4096

4.3 YAML Library — libyaml (already in vcpkg)

New module: libmcaster1dspencoder/config_yaml.cpp + config_yaml.h

int mcaster1_load_yaml_config(const char *path, mcaster1_config_t *cfg);
int mcaster1_get_station_count(const mcaster1_config_t *cfg);
int mcaster1_get_station(const mcaster1_config_t *cfg, int idx, mcaster1_station_t *st);
int mcaster1_save_yaml_config(const char *path, const mcaster1_config_t *cfg);

Legacy key=value reader retained as fallback. Format auto-detected by file extension.

4.4 Multi-Station Architecture

MAX_ENCODERS increased from 10 → 32. Each YAML station encoder entry maps to one mcaster1Globals slot. Audio input is fanned out to all active encoder threads from a single capture/input callback using the existing pthreadVSE threading model.

4.5 Phase 4 Deliverables

Phase 5 — Podcast Feature Set & ICY 2.2 Metadata IN PROGRESS

Goal: Transform the encoder into a first-class podcast platform. When a DJ saves a live stream to a local file it becomes an archived podcast episode. Phase 5 adds a dedicated Podcast Settings UI tab, automatic RSS 2.0 + iTunes feed generation alongside each saved recording, and full ICY 2.2 extended header injection on every Icecast2 / Mcaster1DNAS connect. Config save hardening ensures settings are never lost on exit.

IMPLEMENTATION COMPLETE (2026-02-22) All Phase 5 code has been written. Pending: build verification + E2E test (connect to Mcaster1DNAS, verify ICY 2.2 headers; stream + record, check .rss file).

5.1 Podcast Settings & Archive Recording

The existing “Advanced Settings” config tab has been redesigned as a proper Podcast Settings tab (IDD_PROPPAGE_LARGE2). Log settings are now in their own group box at the bottom. New controls:

Field resolution order (first non-empty wins): Podcast Settings → YP Settings → safe defaults.

5.2 RSS 2.0 + iTunes Feed Generation

New files src/podcast_rss_gen.h and src/podcast_rss_gen.cpp implement a pure-C RSS writer with zero extra dependencies (pure fprintf). Triggered automatically from closeArchiveFile() when Generate RSS is enabled.

FeatureDetail
Output fileSame directory + base name as audio file, .rss extension
FormatRSS 2.0 with xmlns:itunes + xmlns:content namespaces
MIME detection.mp3 → audio/mpeg  |  .ogg/.opus → audio/ogg  |  .aac/.m4a → audio/aac  |  .wav → audio/wav
DurationWAV: estimated from bytes ÷ (samplerate × channels × 2); encoded: omitted
iTunes tags<itunes:author>, <itunes:category>, <itunes:image>, <itunes:duration>, <itunes:explicit>
XML safetyAll text fields XML-escaped (&amp; &lt; &gt; &quot; &apos;)

5.3 ICY 2.2 Extended Header Integration

A new 4th config tab “ICY 2.2 Extended” (IDD_PROPPAGE_LARGE3) exposes all 12 ICY 2.2 header categories from the ICY 2.2 spec. On every Icecast2 SOURCE connect, appendICY22Headers() appends all non-empty fields after the standard ICE headers.

CategoryKey Fields
Station Identitystation-id, station-logo, verify-status
Show / Programmingshow-title, show-start/end, next-show, schedule-url, autodj, playlist-name
DJ / Hostdj-handle, dj-bio, dj-genre, dj-rating
Social & Discoverycreator-handle, Twitter, Twitch, Instagram, TikTok, YouTube, Facebook, LinkedIn, Linktree, emoji, hashtags
Listener Engagementrequest-url, chat-url, tip-url, events-url
Broadcast Distributioncrosspost platforms, session-id (UUID auto-gen), cdn-region, relay-origin
Compliance / Contentnsfw, ai-generator, geo-region, license-type, royalty-free, license-territory
Station Noticenotice-text, notice-url, notice-expires
Video / Simulcastvideo-type, video-link, video-title, video-poster, platform, video-live, codec, fps, resolution, rating
Audio Technicalaudio-codec (auto), samplerate (auto), channels (auto), encoder: Mcaster1DSPEncoder/1.0, loudness (LUFS)

The session-id is auto-generated as a UUID via CoCreateGuid() on the first connect if the field is blank. Shoutcast servers silently ignore the unknown headers — safe to send always.

5.4 Config Save Hardening

5.5 Phase 5 Deliverables

Phase 6 — Mcaster1DNAS Integration PLANNED

Goal: First-class integration between Mcaster1DSPEncoder and the Mcaster1DNAS streaming server. They are already ecosystem companions — this phase makes them work together seamlessly as a matched pair, better together than either is with generic third-party tools.

Integration Features

FeatureDescription
Auto-discoveryEncoder detects local Mcaster1DNAS instances on the LAN and offers them in a server picker (mDNS / simple UDP broadcast). No manual IP/port entry for local setups.
Shared YAML configEncoder and DNAS share a common mcaster1.yaml with station definitions, eliminating duplicate configuration between the two applications.
Live stream healthDNAS reports listener count, bitrate stability, and buffer state back to the encoder UI in real time. Red/amber/green status indicator per encoder slot.
Song history pushEncoder pushes structured now-playing data directly to the DNAS ring buffer API on each track change — no polling delay, no metadata lag.
Admin API authEncoder uses the same API key as the DNAS admin panel. Single credential, single configuration point.
Relay/fallback coordinationEncoder can trigger a DNAS relay switch if the live source drops, and signal DNAS to resume live source when the connection recovers.

Phase 6 Deliverables

Phase 7 — Mcaster1Castit PLANNED

Goal: Resurrect and modernize Castit — the original live broadcast scheduling and automation tool built for casterclub.com in 2001 with Ed Zaleski's guidance. Castit was written against VC6 and will be upgraded to Visual Studio 2022 as a first-class member of the Mcaster1 ecosystem.

Historical Context Castit was the first project Dave St. John and Ed Zaleski worked on together, beginning in 2001. Ed mentored Dave in C/C++ and MFC/Windows programming while helping build the broadcast infrastructure for casterclub.com. The original VC6 source is the direct ancestor of this codebase. Bringing Castit into the Mcaster1 ecosystem closes the circle on that collaboration.

Upgrade Plan

ComponentOld (VC6)New (VS2022)
Compiler / ToolsetVC6 (v60 toolset)VS2022 (v143 toolset)
Windows SDKWindows 98/ME/2000 eraWindows 10 SDK (10.0.x)
XML processingBundled libxml2 (VC6 era)libxml2:x86-windows via vcpkg
HTTP clientCustom / early libcurl buildlibcurl:x86-windows via vcpkg (TLS 1.3, HTTP/2)
DatabaseMySQL direct client (VC6)libmariadb via vcpkg (preferred) or libmysql — to be confirmed
UI FrameworkMFC VC6 dialogs (fixed-size)MFC VS2022 + ResizableLib (matching Mcaster1DSPEncoder)
ConfigurationLegacy flat configYAML via libyaml (matching Mcaster1DSPEncoder)
Encoding integrationCastit-internal encoderDelegates to Mcaster1DSPEncoder engine via shared lib
MetadataLegacy ICY textICY 2.2 extended headers — podcast, social, DJ, compliance, video (Phase 5)
Database Choice: MariaDB vs MySQL libmariadb is preferred over the Oracle MySQL client. MariaDB is a true open-source, community-maintained drop-in replacement for MySQL with the same wire protocol, no Oracle license constraints, and active development. This will be confirmed before implementation begins. vcpkg package: libmariadb:x86-windows.

Mcaster1Castit Feature Goals

Phase 7 Deliverables

Phase 8 — Analytics, Metrics & Platform Engagement PLANNED

Goal: Leverage the ICY 2.1 protocol and the Mcaster1DNAS song history ring buffer to build a statistical metrics and analytics layer that gives station operators actionable listener engagement data — without requiring third-party analytics services or sharing data with external platforms.

Analytics Architecture

[Listeners] ──ICY 2.1 engagement signals──► [Mcaster1DNAS]
                                                    │
                                          [Analytics Ring Buffer]
                                                    │
                           ┌────────────────────────┼──────────────────────────┐
                           ▼                        ▼                          ▼
                  [Track Play Stats]        [Listener Peaks]          [Format Stats]
                  Most played, rotation     Hour-by-hour curve        Codec popularity
                           │
                  [Mcaster1Castit Scheduler]
                           │
                  [Optimize playlist rotation
                   based on engagement data]

Planned Metrics

MetricSourceUse Case
Track play countDNAS ring bufferMost-played tracks, rotation analysis, eliminate overplayed songs
Listener count at track changeDNAS stats APIMeasure which tracks retain vs lose listeners
Format & bitrate popularityDNAS mount statsWhich codec/bitrate combinations listeners actually use
Peak listening hoursDNAS listener timeseriesSchedule high-value content at real peak times
Tune-in / tune-out momentsICY 2.1 engagement signalIdentify tracks and times that cause listeners to disconnect
Music service click-throughTrack History page analyticsWhich tracks generate Spotify/Apple Music lookups from listeners
Geographic distributionDNAS connection metadataWhere your listeners are — optimize relay server placement

Platform Engagement via ICY 2.1

The ICY 2.1 metadata block includes a history_url field pointing to the DNAS track history API. Listener-side players that support ICY 2.1 can display:

This creates a direct engagement path from the audio stream to music service platforms, measurable through history_url click analytics on the DNAS side — without requiring a third-party ad network or analytics vendor.

Mcaster1Castit Playlist Intelligence

Phase 8 closes the loop: analytics data collected by Mcaster1DNAS feeds back into Mcaster1Castit's scheduling engine. High-engagement tracks get scheduled more frequently at the hours when their listener segments are most active. Tracks that consistently cause tune-outs get flagged for rotation review. All processing happens on-premises — no data leaves your infrastructure.

Phase 8 Deliverables

Dependency Matrix

DependencyPurposeLicenseDistributePhasevcpkg
libmp3lame.dllMP3 encodingLGPL v2Yes (patents expired 2017)2mp3lame:x64
vorbis.dll / vorbisenc.dllOgg VorbisBSDYesexistinglibvorbis:x64
ogg.dllOgg containerBSDYesexistinglibogg:x64
libFLAC.dllFLAC encodingBSDYesexistinglibflac:x64
fdk-aac.dllAAC-LC / AAC+ / AAC++ encodingBSD-2 (HE-AAC patent license)Yes3fdk-aac:x64[he-aac] — install required
libcurl.dllHTTP / streamingMIT/curlYesexistingcurl:x64
pthreadVSE.dllThreadingLGPLYesexistingpthreads:x64
opus.dllOpus core codecBSDYes3opus:x64
opusenc.dllOpus encoding APIBSDYes3libopusenc:x64
PortAudio 19.7.0Device capture (WASAPI/ASIO/MME/DS/WDM-KS)MITStatic link — baked into EXE only, no DLL3 ✓Built from source with Steinberg ASIO SDK
libyamlYAML config parserMITYes (static)4libyaml:x86-windows
ResizableLibResizable MFC dialog frameworkArtisticSource compiled in2 ✓external/ResizableLib/
bass.dllAudio capture (legacy)ProprietaryREMOVED Phase 3
basswma.dllWMA encoding (legacy)ProprietaryREMOVED Phase 3
libmariadbMariaDB/MySQL client (Castit)LGPLYes7libmariadb:x86-windows
libxml2.dllXML / YPMITYesexistinglibxml2:x64
iconv.dllEncoding conv.LGPLYesexistinglibiconv:x64

Git Repository Setup & Release Tags

git init
git remote add origin https://github.com/davestj/Mcaster1DSPEncoder.git
git add .
git commit -m "feat: Phase 5 — Podcast RSS, ICY 2.2 headers, Podcast + ICY 2.2 UI tabs"
git tag v0.2.0
git push -u origin main

Release Version Plan

TagPhaseStatusDescription
v0.1.0Phase 1TAGGEDVS2022 build fixes — all 4 targets compile and run
v0.2.0Phase 2TAGGEDFull rebrand, ResizableLib UI, Segoe UI, native LAME, all 4 targets clean
v0.3.0Phase 3COMPLETEMP3/LAME, Opus, HE-AAC/fdk-aac, OggVorbis, FLAC. PortAudio WASAPI. Volume slider fixed.
v0.4.0Phase 4COMPLETEYAML-first config across all 4 targets, per-encoder YAML files, legacy .cfg migration
v0.5.0Phase 5IN PROGRESSPodcast RSS feed gen, ICY 2.2 extended headers (all 12 categories), Podcast + ICY 2.2 UI tabs, config save hardening
v0.6.0Phase 6PLANNEDMcaster1DNAS deep integration — auto-discovery, shared YAML, live health, song push
v1.0.0Phase 7PLANNEDMcaster1Castit — Castit VC6 → VS2022, full Mcaster1 platform launch
v1.1.0Phase 8PLANNEDAnalytics, metrics & platform engagement via ICY 2.1 signals

Phase Summary

PhaseNameStatusKey Outputs
1VS2022 Build FixCOMPLETEAll 4 targets compile and run
2Rebrand & RefactorCOMPLETEFull rename, ResizableLib UI, Segoe UI, native LAME, all 4 targets clean
3Audio ModernizationIN PROGRESSDual MP3, Opus, HE-AAC, WMA removed, PortAudio — pending E2E verification
4YAML Multi-StationPLANNEDYAML config, multi-station, per-station encoders, archive
5ICY 2.1 Enhanced MetadataPLANNEDJSON blocks, album art, track IDs, DNAS history API linkage
6Mcaster1DNAS IntegrationPLANNEDAuto-discovery, shared config, live health feedback, song history push
7Mcaster1CastitPLANNEDCastit VC6 → VS2022, libxml2/libcurl/libmariadb via vcpkg, broadcast scheduler
8Analytics & EngagementPLANNEDListener metrics, tune signals, platform engagement via ICY 2.1