/
reds
/
OpenDAW
Обзор
Документация
Войти
/
reds
/
OpenDAW
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
src/io/AudioDevice.cpp
191 строка
6 KB
OpenDAW Developer
feat(v0.4.0): Add Audio Device Backend (ALSA)
21 фев 2026, 02:32
21 фев 2026, 02:32
8473a58
Код
Авторство
О чём код?
#include <opendaw/io/AudioDevice.h> #include <iostream> #include <thread> #include <chrono> #include <vector> #include <cmath> #ifdef HAVE_ALSA #include <alsa/asoundlib.h> #endif namespace opendaw { AudioDevice::AudioDevice() = default; AudioDevice::~AudioDevice() { shutdown(); } bool AudioDevice::initialize(const AudioDeviceConfig& config) { config_ = config; std::cout << "[AudioDevice] Initializing..." << std::endl; std::cout << " Sample rate: " << config_.sampleRate << " Hz" << std::endl; std::cout << " Block size: " << config_.blockSize << " samples" << std::endl; std::cout << " Latency: " << config_.getLatencyMs() << " ms" << std::endl; #ifdef HAVE_ALSA // ALSA инициализация snd_pcm_t* handle; int err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { std::cerr << "[AudioDevice] ALSA error: " << snd_strerror(err) << std::endl; std::cout << "[AudioDevice] Falling back to stub mode" << std::endl; } else { alsaHandle_ = handle; std::cout << "[AudioDevice] ALSA initialized" << std::endl; } #else std::cout << "[AudioDevice] ALSA not available, using stub mode" << std::endl; #endif status_ = AudioDeviceStatus::Initialized; return true; } void AudioDevice::shutdown() { stop(); #ifdef HAVE_ALSA if (alsaHandle_) { snd_pcm_close(static_cast<snd_pcm_t*>(alsaHandle_)); alsaHandle_ = nullptr; } #endif status_ = AudioDeviceStatus::Uninitialized; } bool AudioDevice::start() { if (status_ == AudioDeviceStatus::Running) { return true; } std::cout << "[AudioDevice] Starting audio thread..." << std::endl; shouldStop_ = false; audioThread_ = std::thread(&AudioDevice::audioThreadFunc, this); status_ = AudioDeviceStatus::Running; return true; } void AudioDevice::stop() { if (status_ != AudioDeviceStatus::Running) { return; } std::cout << "[AudioDevice] Stopping audio thread..." << std::endl; shouldStop_ = true; if (audioThread_.joinable()) { audioThread_.join(); } status_ = AudioDeviceStatus::Initialized; } void AudioDevice::audioThreadFunc() { std::cout << "[AudioDevice] Audio thread started" << std::endl; const int numChannels = std::max(config_.numInputChannels, config_.numOutputChannels); const int blockSize = config_.blockSize; const double sampleRate = config_.sampleRate; const double interval = static_cast<double>(blockSize) / sampleRate; // Буферы для audio callback std::vector<std::vector<float>> inputBuffers(numChannels); std::vector<std::vector<float>> outputBuffers(numChannels); std::vector<const float*> inputPtrs(numChannels); std::vector<float*> outputPtrs(numChannels); for (int ch = 0; ch < numChannels; ++ch) { inputBuffers[ch].resize(blockSize, 0.0f); outputBuffers[ch].resize(blockSize, 0.0f); inputPtrs[ch] = inputBuffers[ch].data(); outputPtrs[ch] = outputBuffers[ch].data(); } // Для генерации тестового сигнала double phase = 0.0; const double frequency = 440.0; // A4 while (!shouldStop_) { // Генерация тестового сигнала (синусоида) for (int ch = 0; ch < std::min(2, numChannels); ++ch) { for (int i = 0; i < blockSize; ++i) { double t = phase + static_cast<double>(i) / sampleRate; outputBuffers[ch][i] = 0.1f * std::sin(2.0 * 3.14159265359 * frequency * t); if (ch == 1) { outputBuffers[ch][i] *= 0.5f; // Тише на правом канале } } } phase += static_cast<double>(blockSize) / sampleRate; if (phase >= 1.0 / frequency) { phase -= 1.0 / frequency; } // Вызов audio callback if (audioCallback_) { audioCallback_( inputPtrs.data(), outputPtrs.data(), blockSize, config_.numInputChannels, config_.numOutputChannels ); } #ifdef HAVE_ALSA // Запись в ALSA if (alsaHandle_) { snd_pcm_writei(static_cast<snd_pcm_t*>(alsaHandle_), outputBuffers[0].data(), blockSize); } #endif // Сон до следующего блока auto startTime = std::chrono::steady_clock::now(); auto wakeTime = startTime + std::chrono::duration<double>(interval * 0.8); std::this_thread::sleep_until(wakeTime); } std::cout << "[AudioDevice] Audio thread stopped" << std::endl; } std::vector<std::string> AudioDevice::getAvailableDevices() { std::vector<std::string> devices; #ifdef HAVE_ALSA void** hints; if (snd_device_name_hint(-1, "pcm", &hints) == 0) { void** n = hints; while (*n != nullptr) { char* name = snd_device_name_get_hint(*n, "NAME"); char* desc = snd_device_name_get_hint(*n, "DESC"); if (name && desc) { devices.push_back(std::string(name) + " - " + std::string(desc)); } if (name) free(name); if (desc) free(desc); n++; } snd_device_name_free_hint(hints); } #else devices.push_back("default - Default audio device (stub)"); #endif return devices; } std::unique_ptr<AudioDevice> AudioDevice::createDefault() { return std::make_unique<AudioDevice>(); } } // namespace opendaw