dropped portaudio for miniaudio

This commit is contained in:
2026-03-25 19:49:37 +01:00
parent f1f58168f3
commit 548db30cdd
6 changed files with 96083 additions and 11 deletions

View File

@@ -19,7 +19,6 @@ find_package(OpenGL REQUIRED)
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
pkg_check_modules(FFTW3F REQUIRED IMPORTED_TARGET fftw3f)
pkg_check_modules(PORTAUDIO REQUIRED IMPORTED_TARGET portaudio-2.0)
pkg_check_modules(SNDFILE REQUIRED IMPORTED_TARGET sndfile)
# ── ImGui via FetchContent ────────────────────────────────────────────────────
@@ -55,7 +54,7 @@ set(SOURCES
src/dsp/WindowFunctions.cpp
src/dsp/FFTProcessor.cpp
src/dsp/SpectrumAnalyzer.cpp
src/audio/PortAudioSource.cpp
src/audio/MiniAudioSource.cpp
src/audio/FileSource.cpp
src/ui/ColorMap.cpp
src/ui/WaterfallDisplay.cpp
@@ -71,13 +70,12 @@ target_link_libraries(baudline PRIVATE
imgui
PkgConfig::SDL2
PkgConfig::FFTW3F
PkgConfig::PORTAUDIO
PkgConfig::SNDFILE
OpenGL::GL
pthread
)
# Link math library on Unix
# Link math library and dl on Unix (dl needed by miniaudio for backend loading)
if(UNIX)
target_link_libraries(baudline PRIVATE m)
target_link_libraries(baudline PRIVATE m dl)
endif()

View File

@@ -0,0 +1,157 @@
#define MINIAUDIO_IMPLEMENTATION
#include "audio/miniaudio.h"
#include "audio/MiniAudioSource.h"
#include <cstdio>
#include <cstring>
namespace baudline {
// ── Shared context (lazy-initialized) ────────────────────────────────────────
static ma_context* sharedContext() {
static ma_context ctx;
static bool init = false;
if (!init) {
if (ma_context_init(nullptr, 0, nullptr, &ctx) != MA_SUCCESS) {
std::fprintf(stderr, "miniaudio: failed to init context\n");
return nullptr;
}
init = true;
}
return &ctx;
}
// ── Device enumeration ───────────────────────────────────────────────────────
std::vector<MiniAudioSource::DeviceInfo> MiniAudioSource::listInputDevices() {
std::vector<DeviceInfo> result;
ma_context* ctx = sharedContext();
if (!ctx) return result;
ma_device_info* captureDevices;
ma_uint32 captureCount;
if (ma_context_get_devices(ctx, nullptr, nullptr,
&captureDevices, &captureCount) != MA_SUCCESS) {
return result;
}
for (ma_uint32 i = 0; i < captureCount; ++i) {
// Query full device info for channel count and sample rate.
ma_device_info fullInfo;
if (ma_context_get_device_info(ctx, ma_device_type_capture,
&captureDevices[i].id, &fullInfo) != MA_SUCCESS) {
fullInfo = captureDevices[i];
}
int maxCh = static_cast<int>(fullInfo.nativeDataFormatCount > 0
? fullInfo.nativeDataFormats[0].channels : 2);
// Find max channels across native formats.
for (ma_uint32 f = 1; f < fullInfo.nativeDataFormatCount; ++f) {
int ch = static_cast<int>(fullInfo.nativeDataFormats[f].channels);
if (ch > maxCh) maxCh = ch;
}
double defaultSR = 48000.0;
if (fullInfo.nativeDataFormatCount > 0 && fullInfo.nativeDataFormats[0].sampleRate > 0)
defaultSR = static_cast<double>(fullInfo.nativeDataFormats[0].sampleRate);
result.push_back({
static_cast<int>(i),
fullInfo.name,
maxCh,
defaultSR
});
}
return result;
}
// ── Construction / destruction ───────────────────────────────────────────────
MiniAudioSource::MiniAudioSource(double sampleRate, int channels, int deviceIndex)
: sampleRate_(sampleRate)
, channels_(channels)
, deviceIndex_(deviceIndex)
{
size_t ringSize = static_cast<size_t>(sampleRate * channels * 2); // ~2 seconds
ringBuf_ = std::make_unique<RingBuffer<float>>(ringSize);
}
MiniAudioSource::~MiniAudioSource() {
close();
}
// ── Callback ─────────────────────────────────────────────────────────────────
void MiniAudioSource::dataCallback(ma_device* device, void* /*output*/,
const void* input, unsigned int frameCount) {
auto* self = static_cast<MiniAudioSource*>(device->pUserData);
if (input) {
const auto* in = static_cast<const float*>(input);
self->ringBuf_->write(in, frameCount * self->channels_);
}
}
// ── Open / close / read ──────────────────────────────────────────────────────
bool MiniAudioSource::open() {
if (opened_) return true;
ma_context* ctx = sharedContext();
if (!ctx) return false;
// Resolve device ID if a specific index was requested.
ma_device_id* pDeviceID = nullptr;
ma_device_id deviceID{};
if (deviceIndex_ >= 0) {
ma_device_info* captureDevices;
ma_uint32 captureCount;
if (ma_context_get_devices(ctx, nullptr, nullptr,
&captureDevices, &captureCount) == MA_SUCCESS) {
if (deviceIndex_ < static_cast<int>(captureCount)) {
deviceID = captureDevices[deviceIndex_].id;
pDeviceID = &deviceID;
}
}
}
ma_device_config config = ma_device_config_init(ma_device_type_capture);
config.capture.pDeviceID = pDeviceID;
config.capture.format = ma_format_f32;
config.capture.channels = static_cast<ma_uint32>(channels_);
config.sampleRate = static_cast<ma_uint32>(sampleRate_);
config.dataCallback = dataCallback;
config.pUserData = this;
config.periodSizeInFrames = 512;
device_ = std::make_unique<ma_device>();
if (ma_device_init(ctx, &config, device_.get()) != MA_SUCCESS) {
std::fprintf(stderr, "miniaudio: failed to init device\n");
device_.reset();
return false;
}
if (ma_device_start(device_.get()) != MA_SUCCESS) {
std::fprintf(stderr, "miniaudio: failed to start device\n");
ma_device_uninit(device_.get());
device_.reset();
return false;
}
opened_ = true;
return true;
}
void MiniAudioSource::close() {
if (device_) {
ma_device_uninit(device_.get());
device_.reset();
}
opened_ = false;
}
size_t MiniAudioSource::read(float* buffer, size_t frames) {
return ringBuf_->read(buffer, frames * channels_) / channels_;
}
} // namespace baudline

View File

@@ -0,0 +1,53 @@
#pragma once
#include "audio/AudioSource.h"
#include "core/RingBuffer.h"
#include <memory>
#include <string>
#include <vector>
// Forward-declare miniaudio types to avoid pulling the huge header into every TU.
struct ma_device;
struct ma_context;
namespace baudline {
class MiniAudioSource : public AudioSource {
public:
// deviceIndex = -1 for default input device
MiniAudioSource(double sampleRate = 48000.0, int channels = 1,
int deviceIndex = -1);
~MiniAudioSource() override;
bool open() override;
void close() override;
size_t read(float* buffer, size_t frames) override;
double sampleRate() const override { return sampleRate_; }
int channels() const override { return channels_; }
bool isRealTime() const override { return true; }
bool isEOF() const override { return false; }
// List available input devices (for UI enumeration).
struct DeviceInfo {
int index;
std::string name;
int maxInputChannels;
double defaultSampleRate;
};
static std::vector<DeviceInfo> listInputDevices();
private:
static void dataCallback(ma_device* device, void* output,
const void* input, unsigned int frameCount);
double sampleRate_;
int channels_;
int deviceIndex_;
bool opened_ = false;
std::unique_ptr<ma_device> device_;
std::unique_ptr<RingBuffer<float>> ringBuf_;
};
} // namespace baudline

95864
src/audio/miniaudio.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -78,7 +78,7 @@ bool Application::init(int argc, char** argv) {
ImGui_ImplOpenGL3_Init("#version 120");
// Enumerate audio devices
paDevices_ = PortAudioSource::listInputDevices();
paDevices_ = MiniAudioSource::listInputDevices();
// Load saved config (overwrites defaults for FFT size, overlap, window, etc.)
loadConfig();
@@ -302,7 +302,7 @@ void Application::render() {
saveConfig();
}
}
if (ImGui::MenuItem("Open PortAudio")) {
if (ImGui::MenuItem("Open Audio Device")) {
openPortAudio();
updateAnalyzerSettings();
}
@@ -1094,14 +1094,14 @@ void Application::openPortAudio() {
if (paDeviceIdx_ >= 0 && paDeviceIdx_ < static_cast<int>(paDevices_.size()))
reqCh = std::min(paDevices_[paDeviceIdx_].maxInputChannels, kMaxChannels);
if (reqCh < 1) reqCh = 1;
auto src = std::make_unique<PortAudioSource>(sr, reqCh, deviceIdx);
auto src = std::make_unique<MiniAudioSource>(sr, reqCh, deviceIdx);
if (src->open()) {
audioSource_ = std::move(src);
settings_.sampleRate = sr;
settings_.isIQ = false;
settings_.numChannels = audioSource_->channels();
} else {
std::fprintf(stderr, "Failed to open PortAudio device\n");
std::fprintf(stderr, "Failed to open audio device\n");
}
}

View File

@@ -4,7 +4,7 @@
#include "core/Config.h"
#include "dsp/SpectrumAnalyzer.h"
#include "audio/AudioSource.h"
#include "audio/PortAudioSource.h"
#include "audio/MiniAudioSource.h"
#include "ui/ColorMap.h"
#include "ui/WaterfallDisplay.h"
#include "ui/SpectrumDisplay.h"
@@ -144,7 +144,7 @@ private:
bool fileLoop_ = true;
// Device selection
std::vector<PortAudioSource::DeviceInfo> paDevices_;
std::vector<MiniAudioSource::DeviceInfo> paDevices_;
int paDeviceIdx_ = 0;
// Channel colors (up to kMaxChannels). Defaults: L=purple, R=green.