mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2026-04-19 14:52:43 +00:00
fix
This commit is contained in:
@@ -1,314 +0,0 @@
|
||||
#include <signal_path/audio.h>
|
||||
|
||||
namespace audio {
|
||||
std::map<std::string, AudioStream_t*> streams;
|
||||
|
||||
double registerMonoStream(dsp::stream<float>* stream, std::string name, std::string vfoName, int (*sampleRateChangeHandler)(void* ctx, double sampleRate), void* ctx) {
|
||||
AudioStream_t* astr = new AudioStream_t;
|
||||
astr->type = STREAM_TYPE_MONO;
|
||||
astr->ctx = ctx;
|
||||
astr->audio = new io::AudioSink;
|
||||
astr->audio->init(1);
|
||||
astr->deviceId = astr->audio->getDeviceId();
|
||||
double sampleRate = astr->audio->devices[astr->deviceId].sampleRates[0];
|
||||
int blockSize = sampleRate / 200.0; // default block size
|
||||
astr->monoAudioStream = new dsp::stream<float>;
|
||||
astr->audio->setBlockSize(blockSize);
|
||||
astr->audio->setStreamType(io::AudioSink::MONO);
|
||||
astr->audio->setMonoInput(astr->monoAudioStream);
|
||||
astr->audio->setSampleRate(sampleRate);
|
||||
astr->blockSize = blockSize;
|
||||
astr->sampleRate = sampleRate;
|
||||
astr->monoStream = stream;
|
||||
astr->sampleRateChangeHandler = sampleRateChangeHandler;
|
||||
astr->monoDynSplit = new dsp::Splitter<float>(stream);
|
||||
astr->monoDynSplit->bindStream(astr->monoAudioStream);
|
||||
astr->running = false;
|
||||
astr->volume = 1.0f;
|
||||
astr->sampleRateId = 0;
|
||||
astr->vfoName = vfoName;
|
||||
streams[name] = astr;
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
double registerStereoStream(dsp::stream<dsp::stereo_t>* stream, std::string name, std::string vfoName, int (*sampleRateChangeHandler)(void* ctx, double sampleRate), void* ctx) {
|
||||
AudioStream_t* astr = new AudioStream_t;
|
||||
astr->type = STREAM_TYPE_STEREO;
|
||||
astr->ctx = ctx;
|
||||
astr->audio = new io::AudioSink;
|
||||
astr->audio->init(1);
|
||||
double sampleRate = astr->audio->devices[astr->audio->getDeviceId()].sampleRates[0];
|
||||
int blockSize = sampleRate / 200.0; // default block size
|
||||
astr->stereoAudioStream = new dsp::stream<dsp::stereo_t>;
|
||||
astr->audio->setBlockSize(blockSize);
|
||||
astr->audio->setStreamType(io::AudioSink::STEREO);
|
||||
astr->audio->setStereoInput(astr->stereoAudioStream);
|
||||
astr->audio->setSampleRate(sampleRate);
|
||||
astr->blockSize = blockSize;
|
||||
astr->sampleRate = sampleRate;
|
||||
astr->stereoStream = stream;
|
||||
astr->sampleRateChangeHandler = sampleRateChangeHandler;
|
||||
astr->stereoDynSplit = new dsp::Splitter<dsp::stereo_t>(stream);
|
||||
astr->stereoDynSplit->bindStream(astr->stereoAudioStream);
|
||||
astr->running = false;
|
||||
streams[name] = astr;
|
||||
astr->vfoName = vfoName;
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
void startStream(std::string name) {
|
||||
AudioStream_t* astr = streams[name];
|
||||
if (astr->running) {
|
||||
return;
|
||||
}
|
||||
if (astr->type == STREAM_TYPE_MONO) {
|
||||
astr->monoDynSplit->start();
|
||||
}
|
||||
else {
|
||||
astr->stereoDynSplit->start();
|
||||
}
|
||||
astr->audio->start();
|
||||
astr->running = true;
|
||||
}
|
||||
|
||||
void stopStream(std::string name) {
|
||||
AudioStream_t* astr = streams[name];
|
||||
if (!astr->running) {
|
||||
return;
|
||||
}
|
||||
if (astr->type == STREAM_TYPE_MONO) {
|
||||
astr->monoDynSplit->stop();
|
||||
}
|
||||
else {
|
||||
astr->stereoDynSplit->stop();
|
||||
}
|
||||
astr->audio->stop();
|
||||
astr->running = false;
|
||||
}
|
||||
|
||||
void removeStream(std::string name) {
|
||||
AudioStream_t* astr = streams[name];
|
||||
stopStream(name);
|
||||
for (int i = 0; i < astr->boundStreams.size(); i++) {
|
||||
astr->boundStreams[i].streamRemovedHandler(astr->ctx);
|
||||
}
|
||||
delete astr->monoDynSplit;
|
||||
}
|
||||
|
||||
dsp::stream<float>* bindToStreamMono(std::string name, void (*streamRemovedHandler)(void* ctx), void (*sampleRateChangeHandler)(void* ctx, double sampleRate, int blockSize), void* ctx) {
|
||||
AudioStream_t* astr = streams[name];
|
||||
BoundStream_t bstr;
|
||||
bstr.type = STREAM_TYPE_MONO;
|
||||
bstr.ctx = ctx;
|
||||
bstr.streamRemovedHandler = streamRemovedHandler;
|
||||
bstr.sampleRateChangeHandler = sampleRateChangeHandler;
|
||||
if (astr->type == STREAM_TYPE_MONO) {
|
||||
bstr.monoStream = new dsp::stream<float>;
|
||||
astr->monoDynSplit->stop();
|
||||
astr->monoDynSplit->bindStream(bstr.monoStream);
|
||||
if (astr->running) {
|
||||
astr->monoDynSplit->start();
|
||||
}
|
||||
astr->boundStreams.push_back(bstr);
|
||||
return bstr.monoStream;
|
||||
}
|
||||
bstr.stereoStream = new dsp::stream<dsp::stereo_t>;
|
||||
bstr.s2m = new dsp::StereoToMono(bstr.stereoStream);
|
||||
bstr.monoStream = &bstr.s2m->out;
|
||||
astr->stereoDynSplit->stop();
|
||||
astr->stereoDynSplit->bindStream(bstr.stereoStream);
|
||||
if (astr->running) {
|
||||
astr->stereoDynSplit->start();
|
||||
}
|
||||
bstr.s2m->start();
|
||||
astr->boundStreams.push_back(bstr);
|
||||
return bstr.monoStream;
|
||||
}
|
||||
|
||||
dsp::stream<dsp::stereo_t>* bindToStreamStereo(std::string name, void (*streamRemovedHandler)(void* ctx), void (*sampleRateChangeHandler)(void* ctx, double sampleRate, int blockSize), void* ctx) {
|
||||
AudioStream_t* astr = streams[name];
|
||||
BoundStream_t bstr;
|
||||
bstr.type = STREAM_TYPE_STEREO;
|
||||
bstr.ctx = ctx;
|
||||
bstr.streamRemovedHandler = streamRemovedHandler;
|
||||
bstr.sampleRateChangeHandler = sampleRateChangeHandler;
|
||||
if (astr->type == STREAM_TYPE_STEREO) {
|
||||
bstr.stereoStream = new dsp::stream<dsp::stereo_t>;
|
||||
astr->stereoDynSplit->stop();
|
||||
astr->stereoDynSplit->bindStream(bstr.stereoStream);
|
||||
if (astr->running) {
|
||||
astr->stereoDynSplit->start();
|
||||
}
|
||||
astr->boundStreams.push_back(bstr);
|
||||
return bstr.stereoStream;
|
||||
}
|
||||
bstr.monoStream = new dsp::stream<float>;
|
||||
bstr.m2s = new dsp::MonoToStereo(bstr.monoStream);
|
||||
bstr.stereoStream = &bstr.m2s->out;
|
||||
astr->monoDynSplit->stop();
|
||||
astr->monoDynSplit->bindStream(bstr.monoStream);
|
||||
if (astr->running) {
|
||||
astr->monoDynSplit->start();
|
||||
}
|
||||
bstr.m2s->start();
|
||||
astr->boundStreams.push_back(bstr);
|
||||
return bstr.stereoStream;
|
||||
}
|
||||
|
||||
void setBlockSize(std::string name, int blockSize) {
|
||||
// NOTE: THIS SHOULD NOT BE NEEDED ANYMORE
|
||||
|
||||
// AudioStream_t* astr = streams[name];
|
||||
// if (astr->running) {
|
||||
// return;
|
||||
// }
|
||||
// if (astr->type == STREAM_TYPE_MONO) {
|
||||
// astr->monoDynSplit->setBlockSize(blockSize);
|
||||
// for (int i = 0; i < astr->boundStreams.size(); i++) {
|
||||
// BoundStream_t bstr = astr->boundStreams[i];
|
||||
// bstr.monoStream->setMaxLatency(blockSize * 2);
|
||||
// if (bstr.type == STREAM_TYPE_STEREO) {
|
||||
// bstr.m2s->stop();
|
||||
// bstr.m2s->setBlockSize(blockSize);
|
||||
// bstr.m2s->start();
|
||||
// }
|
||||
// }
|
||||
// astr->blockSize = blockSize;
|
||||
// return;
|
||||
// }
|
||||
// astr->monoDynSplit->setBlockSize(blockSize);
|
||||
// for (int i = 0; i < astr->boundStreams.size(); i++) {
|
||||
// BoundStream_t bstr = astr->boundStreams[i];
|
||||
// bstr.stereoStream->setMaxLatency(blockSize * 2);
|
||||
// if (bstr.type == STREAM_TYPE_MONO) {
|
||||
// bstr.s2m->stop();
|
||||
// bstr.s2m->setBlockSize(blockSize);
|
||||
// bstr.s2m->start();
|
||||
// }
|
||||
// }
|
||||
// astr->blockSize = blockSize;
|
||||
}
|
||||
|
||||
void unbindFromStreamMono(std::string name, dsp::stream<float>* stream) {
|
||||
AudioStream_t* astr = streams[name];
|
||||
for (int i = 0; i < astr->boundStreams.size(); i++) {
|
||||
BoundStream_t bstr = astr->boundStreams[i];
|
||||
if (bstr.monoStream != stream) {
|
||||
continue;
|
||||
}
|
||||
if (astr->type == STREAM_TYPE_STEREO) {
|
||||
astr->stereoDynSplit->stop();
|
||||
astr->stereoDynSplit->unbindStream(bstr.stereoStream);
|
||||
if (astr->running) {
|
||||
astr->stereoDynSplit->start();
|
||||
}
|
||||
bstr.s2m->stop();
|
||||
delete bstr.s2m;
|
||||
return;
|
||||
}
|
||||
astr->monoDynSplit->stop();
|
||||
astr->monoDynSplit->unbindStream(bstr.monoStream);
|
||||
if (astr->running) {
|
||||
astr->monoDynSplit->start();
|
||||
}
|
||||
delete stream;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void unbindFromStreamStereo(std::string name, dsp::stream<dsp::stereo_t>* stream) {
|
||||
AudioStream_t* astr = streams[name];
|
||||
for (int i = 0; i < astr->boundStreams.size(); i++) {
|
||||
BoundStream_t bstr = astr->boundStreams[i];
|
||||
if (bstr.stereoStream != stream) {
|
||||
continue;
|
||||
}
|
||||
if (astr->type == STREAM_TYPE_MONO) {
|
||||
astr->monoDynSplit->stop();
|
||||
astr->monoDynSplit->unbindStream(bstr.monoStream);
|
||||
if (astr->running) {
|
||||
astr->monoDynSplit->start();
|
||||
}
|
||||
bstr.m2s->stop();
|
||||
delete bstr.m2s;
|
||||
return;
|
||||
}
|
||||
astr->stereoDynSplit->stop();
|
||||
astr->stereoDynSplit->unbindStream(bstr.stereoStream);
|
||||
if (astr->running) {
|
||||
astr->stereoDynSplit->start();
|
||||
}
|
||||
delete stream;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getNameFromVFO(std::string vfoName) {
|
||||
for (auto const& [name, stream] : streams) {
|
||||
if (stream->vfoName == vfoName) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void setSampleRate(std::string name, double sampleRate) {
|
||||
AudioStream_t* astr = streams[name];
|
||||
if (astr->running) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: All the blocksize stuff needs removal
|
||||
|
||||
int blockSize = astr->sampleRateChangeHandler(astr->ctx, sampleRate);
|
||||
astr->audio->setSampleRate(sampleRate);
|
||||
//astr->audio->setBlockSize(blockSize);
|
||||
if (astr->type == STREAM_TYPE_MONO) {
|
||||
//astr->monoDynSplit->setBlockSize(blockSize);
|
||||
for (int i = 0; i < astr->boundStreams.size(); i++) {
|
||||
BoundStream_t bstr = astr->boundStreams[i];
|
||||
if (bstr.type == STREAM_TYPE_STEREO) {
|
||||
bstr.m2s->stop();
|
||||
//bstr.m2s->setBlockSize(blockSize);
|
||||
bstr.sampleRateChangeHandler(bstr.ctx, sampleRate, blockSize);
|
||||
bstr.m2s->start();
|
||||
continue;
|
||||
}
|
||||
bstr.sampleRateChangeHandler(bstr.ctx, sampleRate, blockSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//astr->stereoDynSplit->setBlockSize(blockSize);
|
||||
for (int i = 0; i < astr->boundStreams.size(); i++) {
|
||||
BoundStream_t bstr = astr->boundStreams[i];
|
||||
if (bstr.type == STREAM_TYPE_MONO) {
|
||||
bstr.s2m->stop();
|
||||
//bstr.s2m->setBlockSize(blockSize);
|
||||
bstr.sampleRateChangeHandler(bstr.ctx, sampleRate, blockSize);
|
||||
bstr.s2m->start();
|
||||
continue;
|
||||
}
|
||||
bstr.sampleRateChangeHandler(bstr.ctx, sampleRate, blockSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setAudioDevice(std::string name, int deviceId, double sampleRate) {
|
||||
AudioStream_t* astr = streams[name];
|
||||
if (astr->running) {
|
||||
return;
|
||||
}
|
||||
astr->deviceId = deviceId;
|
||||
astr->audio->setDevice(deviceId);
|
||||
setSampleRate(name, sampleRate);
|
||||
}
|
||||
|
||||
std::vector<std::string> getStreamNameList() {
|
||||
std::vector<std::string> list;
|
||||
for (auto [name, stream] : streams) {
|
||||
list.push_back(name);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
#include <dsp/stream.h>
|
||||
#include <dsp/routing.h>
|
||||
#include <dsp/audio.h>
|
||||
#include <io/audio.h>
|
||||
#include <map>
|
||||
|
||||
namespace audio {
|
||||
enum {
|
||||
STREAM_TYPE_MONO,
|
||||
STREAM_TYPE_STEREO,
|
||||
_STREAM_TYPE_COUNT
|
||||
};
|
||||
|
||||
// TODO: Create a manager class and an instance class
|
||||
|
||||
struct BoundStream_t {
|
||||
dsp::stream<float>* monoStream;
|
||||
dsp::stream<dsp::stereo_t>* stereoStream;
|
||||
dsp::StereoToMono* s2m;
|
||||
dsp::MonoToStereo* m2s;
|
||||
void (*streamRemovedHandler)(void* ctx);
|
||||
void (*sampleRateChangeHandler)(void* ctx, double sampleRate, int blockSize);
|
||||
void* ctx;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct AudioStream_t {
|
||||
io::AudioSink* audio;
|
||||
dsp::stream<float>* monoAudioStream;
|
||||
dsp::stream<dsp::stereo_t>* stereoAudioStream;
|
||||
std::vector<BoundStream_t> boundStreams;
|
||||
dsp::stream<float>* monoStream;
|
||||
dsp::Splitter<float>* monoDynSplit;
|
||||
dsp::stream<dsp::stereo_t>* stereoStream;
|
||||
dsp::Splitter<dsp::stereo_t>* stereoDynSplit;
|
||||
int (*sampleRateChangeHandler)(void* ctx, double sampleRate);
|
||||
double sampleRate;
|
||||
int blockSize;
|
||||
int type;
|
||||
bool running = false;
|
||||
float volume;
|
||||
int sampleRateId;
|
||||
int deviceId;
|
||||
void* ctx;
|
||||
std::string vfoName;
|
||||
};
|
||||
|
||||
extern std::map<std::string, AudioStream_t*> streams;
|
||||
|
||||
double registerMonoStream(dsp::stream<float>* stream, std::string name, std::string vfoName, int (*sampleRateChangeHandler)(void* ctx, double sampleRate), void* ctx);
|
||||
double registerStereoStream(dsp::stream<dsp::stereo_t>* stream, std::string name, std::string vfoName, int (*sampleRateChangeHandler)(void* ctx, double sampleRate), void* ctx);
|
||||
void startStream(std::string name);
|
||||
void stopStream(std::string name);
|
||||
void removeStream(std::string name);
|
||||
dsp::stream<float>* bindToStreamMono(std::string name, void (*streamRemovedHandler)(void* ctx), void (*sampleRateChangeHandler)(void* ctx, double sampleRate, int blockSize), void* ctx);
|
||||
dsp::stream<dsp::stereo_t>* bindToStreamStereo(std::string name, void (*streamRemovedHandler)(void* ctx), void (*sampleRateChangeHandler)(void* ctx, double sampleRate, int blockSize), void* ctx);
|
||||
void setBlockSize(std::string name, int blockSize);
|
||||
void unbindFromStreamMono(std::string name, dsp::stream<float>* stream);
|
||||
void unbindFromStreamStereo(std::string name, dsp::stream<dsp::stereo_t>* stream);
|
||||
std::string getNameFromVFO(std::string vfoName);
|
||||
void setSampleRate(std::string name, double sampleRate);
|
||||
void setAudioDevice(std::string name, int deviceId, double sampleRate);
|
||||
std::vector<std::string> getStreamNameList();
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <signal_path/sink.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <imgui/imgui.h>
|
||||
#include <gui/style.h>
|
||||
#include <gui/icons.h>
|
||||
#include <core.h>
|
||||
|
||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||
@@ -12,16 +14,26 @@ SinkManager::SinkManager() {
|
||||
}
|
||||
|
||||
SinkManager::Stream::Stream(dsp::stream<dsp::stereo_t>* in, const Event<float>::EventHandler& srChangeHandler, float sampleRate) {
|
||||
init(in, srChangeHandler, sampleRate);
|
||||
}
|
||||
|
||||
void SinkManager::Stream::init(dsp::stream<dsp::stereo_t>* in, const Event<float>::EventHandler& srChangeHandler, float sampleRate) {
|
||||
_in = in;
|
||||
srChange.bindHandler(srChangeHandler);
|
||||
_sampleRate = sampleRate;
|
||||
splitter.init(_in);
|
||||
splitter.bindStream(&volumeInput);
|
||||
volumeAjust.init(&volumeInput, 1.0f);
|
||||
sinkOut = &volumeAjust.out;
|
||||
}
|
||||
|
||||
void SinkManager::Stream::start() {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
|
||||
splitter.start();
|
||||
volumeAjust.start();
|
||||
sink->start();
|
||||
running = true;
|
||||
}
|
||||
@@ -30,10 +42,25 @@ void SinkManager::Stream::stop() {
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
splitter.stop();
|
||||
volumeAjust.stop();
|
||||
sink->stop();
|
||||
running = false;
|
||||
}
|
||||
|
||||
void SinkManager::Stream::setVolume(float volume) {
|
||||
guiVolume = volume;
|
||||
volumeAjust.setVolume(volume);
|
||||
}
|
||||
|
||||
float SinkManager::Stream::getVolume() {
|
||||
return guiVolume;
|
||||
}
|
||||
|
||||
float SinkManager::Stream::getSampleRate() {
|
||||
return _sampleRate;
|
||||
}
|
||||
|
||||
void SinkManager::Stream::setInput(dsp::stream<dsp::stereo_t>* in) {
|
||||
std::lock_guard<std::mutex> lck(ctrlMtx);
|
||||
_in = in;
|
||||
@@ -71,20 +98,15 @@ void SinkManager::registerStream(std::string name, SinkManager::Stream* stream)
|
||||
spdlog::error("Cannot register stream '{0}', this name is already taken", name);
|
||||
return;
|
||||
}
|
||||
|
||||
core::configManager.aquire();
|
||||
std::string providerName = core::configManager.conf["defaultSink"];
|
||||
core::configManager.release();
|
||||
|
||||
SinkManager::SinkProvider provider;
|
||||
if (providers.find(providerName) == providers.end()) {
|
||||
// TODO: get default
|
||||
}
|
||||
else {
|
||||
provider = providers[providerName];
|
||||
}
|
||||
|
||||
provider = providers["None"];
|
||||
|
||||
stream->sink = provider.create(stream, name, provider.ctx);
|
||||
|
||||
streams[name] = stream;
|
||||
streamNames.push_back(name);
|
||||
}
|
||||
|
||||
void SinkManager::unregisterStream(std::string name) {
|
||||
@@ -92,6 +114,7 @@ void SinkManager::unregisterStream(std::string name) {
|
||||
spdlog::error("Cannot unregister stream '{0}', this stream doesn't exist", name);
|
||||
return;
|
||||
}
|
||||
spdlog::error("unregisterStream NOT IMPLEMENTED!!!!!!!");
|
||||
SinkManager::Stream* stream = streams[name];
|
||||
delete stream->sink;
|
||||
delete stream;
|
||||
@@ -113,6 +136,14 @@ void SinkManager::stopStream(std::string name) {
|
||||
streams[name]->stop();
|
||||
}
|
||||
|
||||
float SinkManager::getStreamSampleRate(std::string name) {
|
||||
if (streams.find(name) == streams.end()) {
|
||||
spdlog::error("Cannot get sample rate of stream '{0}', this stream doesn't exist", name);
|
||||
return -1.0f;
|
||||
}
|
||||
return streams[name]->getSampleRate();
|
||||
}
|
||||
|
||||
dsp::stream<dsp::stereo_t>* SinkManager::bindStream(std::string name) {
|
||||
if (streams.find(name) == streams.end()) {
|
||||
spdlog::error("Cannot bind to stream '{0}'. Stream doesn't exist", name);
|
||||
@@ -130,7 +161,93 @@ void SinkManager::unbindStream(std::string name, dsp::stream<dsp::stereo_t>* str
|
||||
}
|
||||
|
||||
void SinkManager::setStreamSink(std::string name, std::string providerName) {
|
||||
spdlog::warn("setStreamSink is NOT implemented!!!");
|
||||
}
|
||||
|
||||
void SinkManager::showVolumeSlider(std::string name, std::string prefix, float width) {
|
||||
// TODO: Replace map with some hashmap for it to be faster
|
||||
float height = ImGui::GetTextLineHeightWithSpacing() + 2;
|
||||
|
||||
if (streams.find(name) == streams.end()) {
|
||||
float dummy = 0.0f;
|
||||
style::beginDisabled();
|
||||
ImGui::SetNextItemWidth(width - height);
|
||||
ImGui::SliderFloat((prefix + name).c_str(), &dummy, 0.0f, 1.0f, "");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushID(ImGui::GetID(("sdrpp_dummy_mute_btn_" + name).c_str()));
|
||||
ImGui::ImageButton(icons::STOP, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), 0);
|
||||
ImGui::PopID();
|
||||
style::endDisabled();
|
||||
}
|
||||
|
||||
SinkManager::Stream* stream = streams[name];
|
||||
ImGui::SetNextItemWidth(width - height - 10);
|
||||
if (ImGui::SliderFloat((prefix + name).c_str(), &stream->guiVolume, 0.0f, 1.0f, "")) {
|
||||
stream->setVolume(stream->guiVolume);
|
||||
core::configManager.aquire();
|
||||
saveStreamConfig(name);
|
||||
core::configManager.release(true);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (stream->volumeAjust.getMuted()) {
|
||||
ImGui::PushID(ImGui::GetID(("sdrpp_unmute_btn_" + name).c_str()));
|
||||
if (ImGui::ImageButton(icons::PLAY, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
||||
stream->volumeAjust.setMuted(false);
|
||||
core::configManager.aquire();
|
||||
saveStreamConfig(name);
|
||||
core::configManager.release(true);
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
else {
|
||||
ImGui::PushID(ImGui::GetID(("sdrpp_mute_btn_" + name).c_str()));
|
||||
if (ImGui::ImageButton(icons::STOP, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
||||
stream->volumeAjust.setMuted(true);
|
||||
core::configManager.aquire();
|
||||
saveStreamConfig(name);
|
||||
core::configManager.release(true);
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
void SinkManager::loadStreamConfig(std::string name) {
|
||||
json conf = core::configManager.conf["streams"][name];
|
||||
SinkManager::Stream* stream = streams[name];
|
||||
std::string provName = conf["sink"];
|
||||
if (providers.find(provName) == providers.end()) {
|
||||
provName = providerNames[0];
|
||||
}
|
||||
if (stream->running) {
|
||||
stream->sink->stop();
|
||||
}
|
||||
delete stream->sink;
|
||||
SinkManager::SinkProvider prov = providers[provName];
|
||||
stream->providerId = std::distance(providerNames.begin(), std::find(providerNames.begin(), providerNames.end(), provName));
|
||||
stream->sink = prov.create(stream, name, prov.ctx);
|
||||
if (stream->running) {
|
||||
stream->sink->start();
|
||||
}
|
||||
stream->setVolume(conf["volume"]);
|
||||
stream->volumeAjust.setMuted(conf["muted"]);
|
||||
}
|
||||
|
||||
void SinkManager::saveStreamConfig(std::string name) {
|
||||
SinkManager::Stream* stream = streams[name];
|
||||
json conf;
|
||||
conf["sink"] = providerNames[stream->providerId];
|
||||
conf["volume"] = stream->getVolume();
|
||||
conf["muted"] = stream->volumeAjust.getMuted();
|
||||
core::configManager.conf["streams"][name] = conf;
|
||||
}
|
||||
|
||||
// Note: aquire and release config before running this
|
||||
void SinkManager::loadSinksFromConfig() {
|
||||
for (auto const& [name, stream] : streams) {
|
||||
if (!core::configManager.conf["streams"].contains(name)) { continue; }
|
||||
loadStreamConfig(name);
|
||||
}
|
||||
}
|
||||
|
||||
void SinkManager::showMenu() {
|
||||
@@ -139,7 +256,7 @@ void SinkManager::showMenu() {
|
||||
int maxCount = streams.size();
|
||||
|
||||
std::string provStr = "";
|
||||
for (auto const& [name, provider] : providers) {
|
||||
for (auto const& name : providerNames) {
|
||||
provStr += name;
|
||||
provStr += '\0';
|
||||
}
|
||||
@@ -148,6 +265,7 @@ void SinkManager::showMenu() {
|
||||
ImGui::SetCursorPosX((menuWidth / 2.0f) - (ImGui::CalcTextSize(name.c_str()).x / 2.0f));
|
||||
ImGui::Text("%s", name.c_str());
|
||||
|
||||
ImGui::SetNextItemWidth(menuWidth);
|
||||
if (ImGui::Combo(CONCAT("##_sdrpp_sink_select_", name), &stream->providerId, provStr.c_str())) {
|
||||
if (stream->running) {
|
||||
stream->sink->stop();
|
||||
@@ -158,11 +276,15 @@ void SinkManager::showMenu() {
|
||||
if (stream->running) {
|
||||
stream->sink->start();
|
||||
}
|
||||
core::configManager.aquire();
|
||||
saveStreamConfig(name);
|
||||
core::configManager.release(true);
|
||||
}
|
||||
|
||||
stream->sink->menuHandler();
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
showVolumeSlider(name, "##_sdrpp_sink_menu_vol_", menuWidth);
|
||||
|
||||
count++;
|
||||
if (count < maxCount) {
|
||||
ImGui::Spacing();
|
||||
@@ -170,4 +292,8 @@ void SinkManager::showMenu() {
|
||||
}
|
||||
ImGui::Spacing();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> SinkManager::getStreamNames() {
|
||||
return streamNames;
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <dsp/stream.h>
|
||||
#include <dsp/types.h>
|
||||
#include <dsp/routing.h>
|
||||
#include <dsp/processing.h>
|
||||
#include <dsp/sink.h>
|
||||
#include <mutex>
|
||||
#include <event.h>
|
||||
@@ -22,11 +23,20 @@ public:
|
||||
|
||||
class Stream {
|
||||
public:
|
||||
Stream() {}
|
||||
Stream(dsp::stream<dsp::stereo_t>* in, const Event<float>::EventHandler& srChangeHandler, float sampleRate);
|
||||
|
||||
void init(dsp::stream<dsp::stereo_t>* in, const Event<float>::EventHandler& srChangeHandler, float sampleRate);
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
void setVolume(float volume);
|
||||
float getVolume();
|
||||
|
||||
void setSampleRate(float sampleRate);
|
||||
float getSampleRate();
|
||||
|
||||
void setInput(dsp::stream<dsp::stereo_t>* in);
|
||||
|
||||
dsp::stream<dsp::stereo_t>* bindStream();
|
||||
@@ -35,18 +45,22 @@ public:
|
||||
friend SinkManager;
|
||||
friend SinkManager::Sink;
|
||||
|
||||
dsp::stream<dsp::stereo_t>* sinkOut;
|
||||
|
||||
Event<float> srChange;
|
||||
|
||||
private:
|
||||
void setSampleRate(float sampleRate);
|
||||
|
||||
dsp::stream<dsp::stereo_t>* _in;
|
||||
dsp::Splitter<dsp::stereo_t> splitter;
|
||||
SinkManager::Sink* sink;
|
||||
dsp::stream<dsp::stereo_t> volumeInput;
|
||||
dsp::Volume<dsp::stereo_t> volumeAjust;
|
||||
std::mutex ctrlMtx;
|
||||
float _sampleRate;
|
||||
int providerId = 0;
|
||||
bool running = false;
|
||||
|
||||
float guiVolume = 1.0f;
|
||||
};
|
||||
|
||||
struct SinkProvider {
|
||||
@@ -56,13 +70,21 @@ public:
|
||||
|
||||
class NullSink : SinkManager::Sink {
|
||||
public:
|
||||
void start() {}
|
||||
void stop() {}
|
||||
NullSink(SinkManager::Stream* stream) {
|
||||
ns.init(stream->sinkOut);
|
||||
}
|
||||
void start() { ns.start(); }
|
||||
void stop() { ns.stop(); }
|
||||
void menuHandler() {}
|
||||
|
||||
static SinkManager::Sink* create(SinkManager::Stream* stream, std::string streamName, void* ctx) {
|
||||
return new SinkManager::NullSink;
|
||||
stream->srChange.emit(48000);
|
||||
return new SinkManager::NullSink(stream);
|
||||
}
|
||||
|
||||
private:
|
||||
dsp::NullSink<dsp::stereo_t> ns;
|
||||
|
||||
};
|
||||
|
||||
void registerSinkProvider(std::string name, SinkProvider provider);
|
||||
@@ -73,16 +95,27 @@ public:
|
||||
void startStream(std::string name);
|
||||
void stopStream(std::string name);
|
||||
|
||||
float getStreamSampleRate(std::string name);
|
||||
|
||||
void setStreamSink(std::string name, std::string providerName);
|
||||
|
||||
void showVolumeSlider(std::string name, std::string prefix, float width);
|
||||
|
||||
dsp::stream<dsp::stereo_t>* bindStream(std::string name);
|
||||
void unbindStream(std::string name, dsp::stream<dsp::stereo_t>* stream);
|
||||
|
||||
void loadSinksFromConfig();
|
||||
void showMenu();
|
||||
|
||||
std::vector<std::string> getStreamNames();
|
||||
|
||||
private:
|
||||
void loadStreamConfig(std::string name);
|
||||
void saveStreamConfig(std::string name);
|
||||
|
||||
std::map<std::string, SinkProvider> providers;
|
||||
std::map<std::string, Stream*> streams;
|
||||
std::vector<std::string> providerNames;
|
||||
std::vector<std::string> streamNames;
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user