diff --git a/.gitignore b/.gitignore index b4469ae1..ae69b7ea 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ build/ *.dll *.exe *.zip +*.wav .DS_Store diff --git a/audio_sink/src/main.cpp b/audio_sink/src/main.cpp index aa6b513a..dd05a4c6 100644 --- a/audio_sink/src/main.cpp +++ b/audio_sink/src/main.cpp @@ -22,10 +22,9 @@ public: AudioSink(SinkManager::Stream* stream, std::string streamName) { _stream = stream; _streamName = streamName; - audioStream = _stream->bindStream(); - s2m.init(audioStream); + s2m.init(_stream->sinkOut); monoRB.init(&s2m.out); - stereoRB.init(audioStream); + stereoRB.init(_stream->sinkOut); // Initialize PortAudio Pa_Initialize(); @@ -68,7 +67,11 @@ public: defaultDev = devListId; } dev.srId = 0; - devices.push_back(dev); + + AudioDevice_t* _dev = new AudioDevice_t; + *_dev = dev; + devices.push_back(_dev); + deviceNames.push_back(deviceInfo->name); txtDevList += deviceInfo->name; txtDevList += '\0'; @@ -78,7 +81,9 @@ public: } ~AudioSink() { - + for (auto const& dev : devices) { + delete dev; + } } void start() { @@ -98,6 +103,9 @@ public: } void menuHandler() { + float menuWidth = ImGui::GetContentRegionAvailWidth(); + + ImGui::SetNextItemWidth(menuWidth); if (ImGui::Combo(("##_audio_sink_dev_"+_streamName).c_str(), &devListId, txtDevList.c_str())) { // TODO: Load SR from config if (running) { @@ -107,9 +115,11 @@ public: // TODO: Save to config } - AudioDevice_t dev = devices[devListId]; + AudioDevice_t* dev = devices[devListId]; - if (ImGui::Combo(("##_audio_sink_sr_"+_streamName).c_str(), &dev.srId, txtDevList.c_str())) { + ImGui::SetNextItemWidth(menuWidth); + if (ImGui::Combo(("##_audio_sink_sr_"+_streamName).c_str(), &dev->srId, dev->txtSampleRates.c_str())) { + _stream->setSampleRate(dev->sampleRates[dev->srId]); if (running) { doStop(); doStart(); @@ -121,25 +131,27 @@ public: private: void doStart() { const PaDeviceInfo *deviceInfo; - AudioDevice_t dev = devices[devListId]; + AudioDevice_t* dev = devices[devListId]; PaStreamParameters outputParams; - deviceInfo = Pa_GetDeviceInfo(dev.index); + deviceInfo = Pa_GetDeviceInfo(dev->index); outputParams.channelCount = 2; outputParams.sampleFormat = paFloat32; outputParams.hostApiSpecificStreamInfo = NULL; - outputParams.device = dev.index; + outputParams.device = dev->index; outputParams.suggestedLatency = Pa_GetDeviceInfo(outputParams.device)->defaultLowOutputLatency; PaError err; - float sampleRate = dev.sampleRates[dev.srId]; + float sampleRate = dev->sampleRates[dev->srId]; int bufferSize = sampleRate / 60.0f; - if (dev.channels == 2) { + if (dev->channels == 2) { stereoRB.data.setMaxLatency(bufferSize * 2); + stereoRB.start(); err = Pa_OpenStream(&stream, NULL, &outputParams, sampleRate, bufferSize, 0, _stereo_cb, this); } else { monoRB.data.setMaxLatency(bufferSize * 2); + monoRB.start(); err = Pa_OpenStream(&stream, NULL, &outputParams, sampleRate, bufferSize, 0, _mono_cb, this); } @@ -158,6 +170,8 @@ private: } void doStop() { + monoRB.stop(); + stereoRB.stop(); monoRB.data.stopReader(); stereoRB.data.stopReader(); Pa_StopStream(stream); @@ -181,7 +195,6 @@ private: } SinkManager::Stream* _stream; - dsp::stream* audioStream; dsp::StereoToMono s2m; dsp::RingBufferSink monoRB; dsp::RingBufferSink stereoRB; @@ -204,7 +217,7 @@ private: 11025.0f }; - std::vector devices; + std::vector devices; std::vector deviceNames; std::string txtDevList; diff --git a/core/src/dsp/processing.h b/core/src/dsp/processing.h index fa3d5fc7..ee1557f1 100644 --- a/core/src/dsp/processing.h +++ b/core/src/dsp/processing.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include namespace dsp { @@ -127,4 +128,85 @@ namespace dsp { stream* _in; }; + + template + class Volume : public generic_block> { + public: + Volume() {} + + Volume(stream* in, float volume) { init(in, volume); } + + ~Volume() { generic_block>::stop(); } + + void init(stream* in, float volume) { + _in = in; + _volume = volume; + generic_block>::registerInput(_in); + generic_block>::registerOutput(&out); + } + + void setInputSize(stream* in) { + std::lock_guard lck(generic_block>::ctrlMtx); + generic_block>::tempStop(); + generic_block>::unregisterInput(_in); + _in = in; + generic_block>::registerInput(_in); + generic_block>::tempStart(); + } + + void setVolume(float volume) { + _volume = volume; + level = powf(_volume, 2); + } + + float getVolume() { + return _volume; + } + + void setMuted(bool muted) { + _muted = muted; + } + + bool getMuted() { + return _muted; + } + + int run() { + count = _in->read(); + if (count < 0) { return -1; } + + if (out.aquire() < 0) { return -1; } + + if (_muted) { + if constexpr (std::is_same_v) { + memset(out.data, 0, sizeof(stereo_t) * count); + } + else { + memset(out.data, 0, sizeof(float) * count); + } + } + else { + if constexpr (std::is_same_v) { + volk_32f_s32f_multiply_32f((float*)out.data, (float*)_in->data, level, count * 2); + } + else { + volk_32f_s32f_multiply_32f((float*)out.data, (float*)_in->data, level, count); + } + } + + _in->flush(); + out.write(count); + return count; + } + + stream out; + + private: + int count; + float level = 1.0f; + float _volume = 1.0f; + bool _muted = false; + stream* _in; + + }; } \ No newline at end of file diff --git a/core/src/event.h b/core/src/event.h index 5adea8f4..594470e1 100644 --- a/core/src/event.h +++ b/core/src/event.h @@ -9,6 +9,7 @@ public: ~Event() {} struct EventHandler { + EventHandler() {} EventHandler(void (*handler)(T, void*), void* ctx) { this->handler = handler; this->ctx = ctx; diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index 91f19a46..8633ab5c 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -27,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -68,8 +66,6 @@ void fftHandler(dsp::complex_t* samples, int count, void* ctx) { watcher freq((uint64_t)90500000); watcher vfoFreq(92000000.0); -float dummyVolume = 1.0; -float* volume = &dummyVolume; float fftMin = -70.0; float fftMax = 0.0; watcher offset(0.0, true); @@ -97,7 +93,6 @@ void windowInit() { gui::menu.registerEntry("Source", sourecmenu::draw, NULL); gui::menu.registerEntry("Sinks", sinkmenu::draw, NULL); - gui::menu.registerEntry("Audio", audiomenu::draw, NULL); gui::menu.registerEntry("Scripting", scriptingmenu::draw, NULL); gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL); gui::menu.registerEntry("Display", displaymenu::draw, NULL); @@ -120,7 +115,6 @@ void windowInit() { sourecmenu::init(); sinkmenu::init(); - audiomenu::init(); scriptingmenu::init(); bandplanmenu::init(); displaymenu::init(); @@ -271,10 +265,6 @@ void drawWindow() { gui::waterfall.selectedVFOChanged = false; gui::freqSelect.setFrequency(vfo->generalOffset + gui::waterfall.getCenterFrequency()); gui::freqSelect.frequencyChanged = false; - audioStreamName = audio::getNameFromVFO(gui::waterfall.selectedVFO); - if (audioStreamName != "") { - volume = &audio::streams[audioStreamName]->volume; - } core::configManager.aquire(); core::configManager.conf["frequency"] = gui::freqSelect.frequency; core::configManager.release(true); @@ -339,19 +329,7 @@ void drawWindow() { ImGui::SameLine(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 8); - ImGui::SetNextItemWidth(200); - if (ImGui::SliderFloat("##_2_", volume, 0.0, 1.0, "")) { - if (audioStreamName != "") { - core::configManager.aquire(); - if (!core::configManager.conf["audio"].contains(audioStreamName)) { - //saveAudioConfig(audioStreamName); - // TODO: FIX THIS SHIT - } - audio::streams[audioStreamName]->audio->setVolume(*volume); - core::configManager.conf["audio"][audioStreamName]["volume"] = *volume; - core::configManager.release(true); - } - } + sigpath::sinkManager.showVolumeSlider(gui::waterfall.selectedVFO, "##_sdrpp_main_volume_", 200); ImGui::SameLine(); diff --git a/core/src/gui/menus/audio.cpp b/core/src/gui/menus/audio.cpp deleted file mode 100644 index 71cd1c6c..00000000 --- a/core/src/gui/menus/audio.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include -#include -#include -#include -#include - -namespace audiomenu { - // Note: Those are supposed to be the ones from the volume slider - std::string audioStreamName; - float* volume; - - void loadAudioConfig(std::string name) { - json audioSettings = core::configManager.conf["audio"][name]; - std::string devName = audioSettings["device"]; - auto _devIt = std::find(audio::streams[name]->audio->deviceNames.begin(), audio::streams[name]->audio->deviceNames.end(), devName); - - // If audio device doesn't exist anymore - if (_devIt == audio::streams[name]->audio->deviceNames.end()) { - audio::streams[name]->audio->setToDefault(); - int deviceId = audio::streams[name]->audio->getDeviceId(); - audio::setAudioDevice(name, deviceId, audio::streams[name]->audio->devices[deviceId].sampleRates[0]); - audio::streams[name]->sampleRateId = 0; - audio::streams[name]->volume = audioSettings["volume"]; - audio::streams[name]->audio->setVolume(audio::streams[name]->volume); - return; - } - int deviceId = std::distance(audio::streams[name]->audio->deviceNames.begin(), _devIt); - float sr = audioSettings["sampleRate"]; - auto _srIt = std::find(audio::streams[name]->audio->devices[deviceId].sampleRates.begin(), audio::streams[name]->audio->devices[deviceId].sampleRates.end(), sr); - - // If sample rate doesn't exist anymore - if (_srIt == audio::streams[name]->audio->devices[deviceId].sampleRates.end()) { - audio::streams[name]->sampleRateId = 0; - audio::setAudioDevice(name, deviceId, audio::streams[name]->audio->devices[deviceId].sampleRates[0]); - audio::streams[name]->volume = audioSettings["volume"]; - audio::streams[name]->audio->setVolume(audio::streams[name]->volume); - return; - } - - int samplerateId = std::distance(audio::streams[name]->audio->devices[deviceId].sampleRates.begin(), _srIt); - audio::streams[name]->sampleRateId = samplerateId; - audio::setAudioDevice(name, deviceId, audio::streams[name]->audio->devices[deviceId].sampleRates[samplerateId]); - audio::streams[name]->deviceId = deviceId; - audio::streams[name]->volume = audioSettings["volume"]; - audio::streams[name]->audio->setVolume(audio::streams[name]->volume); - } - - void saveAudioConfig(std::string name) { - core::configManager.conf["audio"][name]["device"] = audio::streams[name]->audio->deviceNames[audio::streams[name]->deviceId]; - core::configManager.conf["audio"][name]["volume"] = audio::streams[name]->volume; - core::configManager.conf["audio"][name]["sampleRate"] = audio::streams[name]->sampleRate; - } - - void init() { - for (auto [name, stream] : audio::streams) { - if (core::configManager.conf["audio"].contains(name)) { - bool running = audio::streams[name]->running; - audio::stopStream(name); - loadAudioConfig(name); - if (running) { - audio::startStream(name); - } - } - } - - audioStreamName = audio::getNameFromVFO(gui::waterfall.selectedVFO); - if (audioStreamName != "") { - volume = &audio::streams[audioStreamName]->volume; - } - } - - void draw(void* ctx) { - float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); - int count = 0; - int maxCount = audio::streams.size(); - for (auto const& [name, stream] : audio::streams) { - int deviceId; - float vol = 1.0f; - deviceId = stream->audio->getDeviceId(); - - ImGui::SetCursorPosX((menuColumnWidth / 2.0f) - (ImGui::CalcTextSize(name.c_str()).x / 2.0f)); - ImGui::Text("%s", name.c_str()); - - ImGui::PushItemWidth(menuColumnWidth); - bool running = stream->running; - if (ImGui::Combo(("##_audio_dev_0_"+ name).c_str(), &stream->deviceId, stream->audio->devTxtList.c_str())) { - audio::stopStream(name); - audio::setAudioDevice(name, stream->deviceId, stream->audio->devices[deviceId].sampleRates[0]); - if (running) { - audio::startStream(name); - } - stream->sampleRateId = 0; - - // Create config if it doesn't exist - core::configManager.aquire(); - if (!core::configManager.conf["audio"].contains(name)) { - saveAudioConfig(name); - } - core::configManager.conf["audio"][name]["device"] = stream->audio->deviceNames[stream->deviceId]; - core::configManager.conf["audio"][name]["sampleRate"] = stream->audio->devices[stream->deviceId].sampleRates[0]; - core::configManager.release(true); - } - if (ImGui::Combo(("##_audio_sr_0_" + name).c_str(), &stream->sampleRateId, stream->audio->devices[deviceId].txtSampleRates.c_str())) { - audio::stopStream(name); - audio::setSampleRate(name, stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]); - if (running) { - audio::startStream(name); - } - - // Create config if it doesn't exist - core::configManager.aquire(); - if (!core::configManager.conf["audio"].contains(name)) { - saveAudioConfig(name); - } - core::configManager.conf["audio"][name]["sampleRate"] = stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]; - core::configManager.release(true); - } - if (ImGui::SliderFloat(("##_audio_vol_0_" + name).c_str(), &stream->volume, 0.0f, 1.0f, "")) { - stream->audio->setVolume(stream->volume); - - // Create config if it doesn't exist - core::configManager.aquire(); - if (!core::configManager.conf["audio"].contains(name)) { - saveAudioConfig(name); - } - core::configManager.conf["audio"][name]["volume"] = stream->volume; - core::configManager.release(true); - } - ImGui::PopItemWidth(); - count++; - if (count < maxCount) { - ImGui::Spacing(); - ImGui::Separator(); - } - ImGui::Spacing(); - } - } -}; \ No newline at end of file diff --git a/core/src/gui/menus/audio.h b/core/src/gui/menus/audio.h deleted file mode 100644 index bc66241e..00000000 --- a/core/src/gui/menus/audio.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -namespace audiomenu { - void init(); - void draw(void* ctx); -}; \ No newline at end of file diff --git a/core/src/gui/menus/sink.cpp b/core/src/gui/menus/sink.cpp index 3bfb4f0b..b6f79dea 100644 --- a/core/src/gui/menus/sink.cpp +++ b/core/src/gui/menus/sink.cpp @@ -1,9 +1,12 @@ #include #include +#include namespace sinkmenu { void init() { - + core::configManager.aquire(); + sigpath::sinkManager.loadSinksFromConfig(); + core::configManager.release(); } void draw(void* ctx) { diff --git a/core/src/gui/menus/source.cpp b/core/src/gui/menus/source.cpp index 2bccaa56..fe640892 100644 --- a/core/src/gui/menus/source.cpp +++ b/core/src/gui/menus/source.cpp @@ -9,12 +9,21 @@ namespace sourecmenu { double freqOffset = 0.0; void init() { - // Select default - // TODO: Replace by setting - if (sigpath::sourceManager.sourceNames.size() > 0) { + core::configManager.aquire(); + std::string name = core::configManager.conf["source"]; + auto it = std::find(sigpath::sourceManager.sourceNames.begin(), sigpath::sourceManager.sourceNames.end(), name); + if (it != sigpath::sourceManager.sourceNames.end()) { + sigpath::sourceManager.selectSource(name); + sourceId = std::distance(sigpath::sourceManager.sourceNames.begin(), it); + } + else if (sigpath::sourceManager.sourceNames.size() > 0) { sigpath::sourceManager.selectSource(sigpath::sourceManager.sourceNames[0]); } - sigpath::sourceManager.setTuningOffset(0); + else { + spdlog::warn("No source available..."); + } + sigpath::sourceManager.setTuningOffset(core::configManager.conf["offset"]); + core::configManager.release(); } void draw(void* ctx) { @@ -28,12 +37,18 @@ namespace sourecmenu { ImGui::SetNextItemWidth(itemWidth); if (ImGui::Combo("##source", &sourceId, items.c_str())) { sigpath::sourceManager.selectSource(sigpath::sourceManager.sourceNames[sourceId]); + core::configManager.aquire(); + core::configManager.conf["source"] = sigpath::sourceManager.sourceNames[sourceId]; + core::configManager.release(true); } sigpath::sourceManager.showSelectedMenu(); ImGui::SetNextItemWidth(itemWidth - ImGui::CalcTextSize("Offset (Hz)").x - 10); if (ImGui::InputDouble("Offset (Hz)##freq_offset", &freqOffset, 1.0, 100.0)) { sigpath::sourceManager.setTuningOffset(freqOffset); + core::configManager.aquire(); + core::configManager.conf["offset"] = freqOffset; + core::configManager.release(true); } } } \ No newline at end of file diff --git a/core/src/io/audio.h b/core/src/io/audio.h deleted file mode 100644 index 09be58ad..00000000 --- a/core/src/io/audio.h +++ /dev/null @@ -1,311 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -namespace io { - class AudioSink { - public: - enum { - MONO, - STEREO, - _TYPE_COUNT - }; - - struct AudioDevice_t { - std::string name; - int index; - int channels; - std::vector sampleRates; - std::string txtSampleRates; - }; - - AudioSink() { - - } - - AudioSink(int bufferSize) { init(bufferSize); } - - void init(int bufferSize) { - _bufferSize = bufferSize; - monoBuffer = new float[_bufferSize]; - stereoBuffer = new dsp::stereo_t[_bufferSize]; - _volume = 1.0f; - - monoSink.init(&monoDummy); - stereoSink.init(&stereoDummy); - - Pa_Initialize(); - - devTxtList = ""; - int devCount = Pa_GetDeviceCount(); - devIndex = Pa_GetDefaultOutputDevice(); - const PaDeviceInfo *deviceInfo; - PaStreamParameters outputParams; - outputParams.sampleFormat = paFloat32; - outputParams.hostApiSpecificStreamInfo = NULL; - for(int i = 0; i < devCount; i++) { - deviceInfo = Pa_GetDeviceInfo(i); - if (deviceInfo->maxOutputChannels < 1) { - continue; - } - AudioDevice_t dev; - dev.name = deviceInfo->name; - dev.index = i; - dev.channels = std::min(deviceInfo->maxOutputChannels, 2); - dev.sampleRates.clear(); - dev.txtSampleRates = ""; - for (int j = 0; j < 6; j++) { - outputParams.channelCount = dev.channels; - outputParams.device = dev.index; - outputParams.suggestedLatency = deviceInfo->defaultLowOutputLatency; - PaError err = Pa_IsFormatSupported(NULL, &outputParams, POSSIBLE_SAMP_RATE[j]); - if (err != paFormatIsSupported) { - continue; - } - dev.sampleRates.push_back(POSSIBLE_SAMP_RATE[j]); - dev.txtSampleRates += std::to_string((int)POSSIBLE_SAMP_RATE[j]); - dev.txtSampleRates += '\0'; - } - if (dev.sampleRates.size() == 0) { - continue; - } - if (i == devIndex) { - devListIndex = devices.size(); - defaultDev = devListIndex; - } - devices.push_back(dev); - deviceNames.push_back(deviceInfo->name); - devTxtList += deviceInfo->name; - devTxtList += '\0'; - } - } - - void setMonoInput(dsp::stream* input) { - monoSink.setInput(input); - } - - void setStereoInput(dsp::stream* input) { - stereoSink.setInput(input); - } - - void setVolume(float volume) { - _volume = volume; - } - - void start() { - if (running) { - return; - } - const PaDeviceInfo *deviceInfo; - AudioDevice_t dev = devices[devListIndex]; - PaStreamParameters outputParams; - deviceInfo = Pa_GetDeviceInfo(dev.index); - outputParams.channelCount = 2; - outputParams.sampleFormat = paFloat32; - outputParams.hostApiSpecificStreamInfo = NULL; - outputParams.device = dev.index; - outputParams.suggestedLatency = Pa_GetDeviceInfo(outputParams.device)->defaultLowOutputLatency; - PaError err; - if (streamType == MONO) { - err = Pa_OpenStream(&stream, NULL, &outputParams, _sampleRate, _bufferSize, 0, - (dev.channels == 2) ? _mono_to_stereo_callback : _mono_to_mono_callback, this); - monoSink.start(); - } - else { - err = Pa_OpenStream(&stream, NULL, &outputParams, _sampleRate, _bufferSize, 0, - (dev.channels == 2) ? _stereo_to_stereo_callback : _stereo_to_mono_callback, this); - stereoSink.start(); - } - - if (err != 0) { - spdlog::error("Error while opening audio stream: ({0}) => {1}", err, Pa_GetErrorText(err)); - return; - } - err = Pa_StartStream(stream); - if (err != 0) { - spdlog::error("Error while starting audio stream: ({0}) => {1}", err, Pa_GetErrorText(err)); - return; - } - spdlog::info("Audio device open."); - running = true; - } - - void stop() { - if (!running) { - return; - } - if (streamType == MONO) { - monoSink.stop(); - monoSink.data.stopReader(); - } - else { - stereoSink.stop(); - stereoSink.data.stopReader(); - } - Pa_StopStream(stream); - Pa_CloseStream(stream); - if (streamType == MONO) { - monoSink.data.clearReadStop(); - } - else { - stereoSink.data.clearReadStop(); - } - running = false; - } - - void setBlockSize(int blockSize) { - if (running) { - return; - } - _bufferSize = blockSize; - delete[] monoBuffer; - delete[] stereoBuffer; - monoBuffer = new float[_bufferSize]; - stereoBuffer = new dsp::stereo_t[_bufferSize]; - } - - void setSampleRate(float sampleRate) { - _sampleRate = sampleRate; - } - - void setDevice(int id) { - if (devListIndex == id) { - return; - } - if (running) { - return; - } - devListIndex = id; - devIndex = devices[id].index; - } - - void setToDefault() { - setDevice(defaultDev); - } - - int getDeviceId() { - return devListIndex; - } - - void setStreamType(int type) { - streamType = type; - } - - std::string devTxtList; - std::vector devices; - std::vector deviceNames; - - private: - static int _mono_to_mono_callback(const void *input, - void *output, - unsigned long frameCount, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, void *userData ) { - AudioSink* _this = (AudioSink*)userData; - float* outbuf = (float*)output; - if (_this->monoSink.data.read(_this->monoBuffer, frameCount) < 0) { - memset(outbuf, 0, sizeof(float) * frameCount); - return 0; - } - - float vol = powf(_this->_volume, 2); - for (int i = 0; i < frameCount; i++) { - outbuf[i] = _this->monoBuffer[i] * vol; - } - return 0; - } - - static int _stereo_to_stereo_callback(const void *input, - void *output, - unsigned long frameCount, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, void *userData ) { - AudioSink* _this = (AudioSink*)userData; - dsp::stereo_t* outbuf = (dsp::stereo_t*)output; - if (_this->stereoSink.data.read(_this->stereoBuffer, frameCount) < 0) { - memset(outbuf, 0, sizeof(dsp::stereo_t) * frameCount); - return 0; - } - - // Note: Calculate the power in the UI instead of here - - float vol = powf(_this->_volume, 2); - for (int i = 0; i < frameCount; i++) { - outbuf[i].l = _this->stereoBuffer[i].l * vol; - outbuf[i].r = _this->stereoBuffer[i].r * vol; - } - return 0; - } - - static int _mono_to_stereo_callback(const void *input, - void *output, - unsigned long frameCount, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, void *userData ) { - AudioSink* _this = (AudioSink*)userData; - dsp::stereo_t* outbuf = (dsp::stereo_t*)output; - if (_this->monoSink.data.read(_this->monoBuffer, frameCount) < 0) { - memset(outbuf, 0, sizeof(dsp::stereo_t) * frameCount); - return 0; - } - - float vol = powf(_this->_volume, 2); - for (int i = 0; i < frameCount; i++) { - outbuf[i].l = _this->monoBuffer[i] * vol; - outbuf[i].r = _this->monoBuffer[i] * vol; - } - return 0; - } - - static int _stereo_to_mono_callback(const void *input, - void *output, - unsigned long frameCount, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, void *userData ) { - AudioSink* _this = (AudioSink*)userData; - float* outbuf = (float*)output; - if (_this->stereoSink.data.read(_this->stereoBuffer, frameCount) < 0) { - memset(outbuf, 0, sizeof(float) * frameCount); - return 0; - } - - // Note: Calculate the power in the UI instead of here - - float vol = powf(_this->_volume, 2); - for (int i = 0; i < frameCount; i++) { - outbuf[i] = ((_this->stereoBuffer[i].l + _this->stereoBuffer[i].r) / 2.0f) * vol; - } - return 0; - } - - double POSSIBLE_SAMP_RATE[6] = { - 48000.0f, - 44100.0f, - 24000.0f, - 22050.0f, - 12000.0f, - 11025.0f - }; - - int streamType; - int devIndex; - int devListIndex; - int defaultDev; - double _sampleRate; - int _bufferSize; - dsp::stream monoDummy; - dsp::stream stereoDummy; - dsp::RingBufferSink monoSink; - dsp::RingBufferSink stereoSink; - float* monoBuffer; - dsp::stereo_t* stereoBuffer; - float _volume = 1.0f; - PaStream *stream; - bool running = false; - }; -}; \ No newline at end of file diff --git a/core/src/signal_path/audio.cpp b/core/src/signal_path/audio.cpp deleted file mode 100644 index e00b06c0..00000000 --- a/core/src/signal_path/audio.cpp +++ /dev/null @@ -1,314 +0,0 @@ -#include - -namespace audio { - std::map streams; - - double registerMonoStream(dsp::stream* 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; - 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(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* 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; - 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(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* 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; - 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; - 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* 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; - 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; - 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* 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* 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 getStreamNameList() { - std::vector list; - for (auto [name, stream] : streams) { - list.push_back(name); - } - return list; - } -}; - diff --git a/core/src/signal_path/audio.h b/core/src/signal_path/audio.h deleted file mode 100644 index 5f5d13c3..00000000 --- a/core/src/signal_path/audio.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -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* monoStream; - dsp::stream* 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* monoAudioStream; - dsp::stream* stereoAudioStream; - std::vector boundStreams; - dsp::stream* monoStream; - dsp::Splitter* monoDynSplit; - dsp::stream* stereoStream; - dsp::Splitter* 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 streams; - - double registerMonoStream(dsp::stream* stream, std::string name, std::string vfoName, int (*sampleRateChangeHandler)(void* ctx, double sampleRate), void* ctx); - double registerStereoStream(dsp::stream* 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* bindToStreamMono(std::string name, void (*streamRemovedHandler)(void* ctx), void (*sampleRateChangeHandler)(void* ctx, double sampleRate, int blockSize), void* ctx); - dsp::stream* 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* stream); - void unbindFromStreamStereo(std::string name, dsp::stream* 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 getStreamNameList(); -}; - diff --git a/core/src/signal_path/sink.cpp b/core/src/signal_path/sink.cpp index c4e06e0e..1922d61a 100644 --- a/core/src/signal_path/sink.cpp +++ b/core/src/signal_path/sink.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #define CONCAT(a, b) ((std::string(a) + b).c_str()) @@ -12,16 +14,26 @@ SinkManager::SinkManager() { } SinkManager::Stream::Stream(dsp::stream* in, const Event::EventHandler& srChangeHandler, float sampleRate) { + init(in, srChangeHandler, sampleRate); +} + +void SinkManager::Stream::init(dsp::stream* in, const Event::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* in) { std::lock_guard 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* 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* 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 SinkManager::getStreamNames() { + return streamNames; } \ No newline at end of file diff --git a/core/src/signal_path/sink.h b/core/src/signal_path/sink.h index 77a8f1a6..d9840290 100644 --- a/core/src/signal_path/sink.h +++ b/core/src/signal_path/sink.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -22,11 +23,20 @@ public: class Stream { public: + Stream() {} Stream(dsp::stream* in, const Event::EventHandler& srChangeHandler, float sampleRate); + void init(dsp::stream* in, const Event::EventHandler& srChangeHandler, float sampleRate); + void start(); void stop(); + void setVolume(float volume); + float getVolume(); + + void setSampleRate(float sampleRate); + float getSampleRate(); + void setInput(dsp::stream* in); dsp::stream* bindStream(); @@ -35,18 +45,22 @@ public: friend SinkManager; friend SinkManager::Sink; + dsp::stream* sinkOut; + Event srChange; private: - void setSampleRate(float sampleRate); - dsp::stream* _in; dsp::Splitter splitter; SinkManager::Sink* sink; + dsp::stream volumeInput; + dsp::Volume 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 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* bindStream(std::string name); void unbindStream(std::string name, dsp::stream* stream); + void loadSinksFromConfig(); void showMenu(); + std::vector getStreamNames(); + private: + void loadStreamConfig(std::string name); + void saveStreamConfig(std::string name); + std::map providers; std::map streams; std::vector providerNames; + std::vector streamNames; }; \ No newline at end of file diff --git a/radio/src/main.cpp b/radio/src/main.cpp index 6b5e6e66..0f29e67d 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -23,7 +23,7 @@ public: bandWidth = 200000; bandWidthMin = 100000; bandWidthMax = 200000; - sigPath.init(name, 200000, 1000); + sigPath.init(name); sigPath.start(); sigPath.setDemodulator(SigPath::DEMOD_FM, bandWidth); sigPath.vfo->setSnapInterval(100000.0); diff --git a/radio/src/path.cpp b/radio/src/path.cpp index 1dbea4a4..b87e4a6d 100644 --- a/radio/src/path.cpp +++ b/radio/src/path.cpp @@ -1,33 +1,28 @@ #include -#include #include SigPath::SigPath() { } -int SigPath::sampleRateChangeHandler(void* ctx, double sampleRate) { +void SigPath::sampleRateChangeHandler(float _sampleRate, void* ctx) { SigPath* _this = (SigPath*)ctx; - _this->outputSampleRate = sampleRate; + _this->outputSampleRate = _sampleRate; _this->audioResamp.stop(); _this->deemp.stop(); - float bw = std::min(_this->bandwidth, sampleRate / 2.0f); + float bw = std::min(_this->bandwidth, _sampleRate / 2.0f); - _this->audioResamp.setOutSampleRate(sampleRate); - _this->audioWin.setSampleRate(_this->sampleRate * _this->audioResamp.getInterpolation()); + _this->audioResamp.setOutSampleRate(_sampleRate); + _this->audioWin.setSampleRate(_this->demodOutputSamplerate * _this->audioResamp.getInterpolation()); _this->audioResamp.updateWindow(&_this->audioWin); - _this->deemp.setSampleRate(sampleRate); + _this->deemp.setSampleRate(_sampleRate); _this->audioResamp.start(); _this->deemp.start(); - // Note: returning a block size should not be needed anymore - return 1; } -void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize) { - this->sampleRate = sampleRate; - this->blockSize = blockSize; +void SigPath::init(std::string vfoName) { this->vfoName = vfoName; vfo = sigpath::vfoManager.createVFO(vfoName, ImGui::WaterfallVFO::REF_CENTER, 0, 200000, 200000, 1000); @@ -36,6 +31,7 @@ void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize) { _deemp = DEEMP_50US; bandwidth = 200000; demodOutputSamplerate = 200000; + outputSampleRate = 48000; // TODO: Set default VFO options // TODO: ajust deemphasis for different output sample rates @@ -53,16 +49,16 @@ void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize) { audioResamp.updateWindow(&audioWin); deemp.init(&audioResamp.out, 48000, 50e-6); - - outputSampleRate = audio::registerMonoStream(&deemp.out, vfoName, vfoName, sampleRateChangeHandler, this); - setDemodulator(_demod, bandwidth); -} + m2s.setInput(&deemp.out); -void SigPath::setSampleRate(float sampleRate) { - this->sampleRate = sampleRate; + Event::EventHandler evHandler; + evHandler.handler = sampleRateChangeHandler; + evHandler.ctx = this; + stream.init(&m2s.out, evHandler, outputSampleRate); + + sigpath::sinkManager.registerStream(vfoName, &stream); - // Reset the demodulator and audio systems setDemodulator(_demod, bandwidth); } @@ -215,10 +211,6 @@ void SigPath::setDemodulator(int demId, float bandWidth) { deemp.start(); } -void SigPath::updateBlockSize() { - setDemodulator(_demod, bandwidth); -} - void SigPath::setDeemphasis(int deemph) { _deemp = deemph; deemp.stop(); @@ -290,6 +282,6 @@ void SigPath::start() { demod.start(); audioResamp.start(); deemp.start(); - //ns.start(); - audio::startStream(vfoName); + m2s.start(); + stream.start(); } \ No newline at end of file diff --git a/radio/src/path.h b/radio/src/path.h index f6c8e8f4..627c7c04 100644 --- a/radio/src/path.h +++ b/radio/src/path.h @@ -4,19 +4,16 @@ #include #include #include -#include #include #include #include +#include class SigPath { public: SigPath(); - void init(std::string vfoName, uint64_t sampleRate, int blockSize); + void init(std::string vfoName); void start(); - void setSampleRate(float sampleRate); - void setVFOFrequency(uint64_t frequency); - void updateBlockSize(); void setDemodulator(int demod, float bandWidth); void setDeemphasis(int deemph); void setBandwidth(float bandWidth); @@ -44,7 +41,7 @@ public: VFOManager::VFO* vfo; private: - static int sampleRateChangeHandler(void* ctx, double sampleRate); + static void sampleRateChangeHandler(float _sampleRate, void* ctx); dsp::stream input; @@ -57,17 +54,17 @@ private: dsp::AGC agc; // Audio output - dsp::MonoToStereo m2s; dsp::filter_window::BlackmanWindow audioWin; dsp::PolyphaseResampler audioResamp; + dsp::MonoToStereo m2s; + SinkManager::Stream stream; std::string vfoName; - float sampleRate; + // TODO: FIx all this sample rate BS (multiple names for same thing) float bandwidth; float demodOutputSamplerate; float outputSampleRate; - int blockSize; int _demod; int _deemp; float audioBw; diff --git a/recorder/src/main.cpp b/recorder/src/main.cpp index c12676c0..2a5c6cd2 100644 --- a/recorder/src/main.cpp +++ b/recorder/src/main.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -51,7 +50,7 @@ private: RecorderModule* _this = (RecorderModule*)ctx; float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); - std::vector streamNames = audio::getStreamNameList(); + std::vector streamNames = sigpath::sinkManager.getStreamNames(); std::string nameList; for (std::string name : streamNames) { nameList += name; @@ -147,9 +146,9 @@ private: if (!_this->recording) { if (ImGui::Button("Record", ImVec2(menuColumnWidth, 0))) { _this->samplesWritten = 0; - _this->sampleRate = 48000; - _this->writer = new WavWriter(ROOT_DIR "/recordings/" + genFileName("audio_"), 16, 2, 48000); - _this->audioStream = audio::bindToStreamStereo(_this->selectedStreamName, streamRemovedHandler, sampleRateChanged, _this); + _this->sampleRate = sigpath::sinkManager.getStreamSampleRate(_this->selectedStreamName); + _this->writer = new WavWriter(ROOT_DIR "/recordings/" + genFileName("audio_"), 16, 2, _this->sampleRate); + _this->audioStream = sigpath::sinkManager.bindStream(_this->selectedStreamName); _this->workerThread = std::thread(_audioWriteWorker, _this); _this->recording = true; _this->startTime = time(0); @@ -161,7 +160,7 @@ private: _this->audioStream->stopReader(); _this->workerThread.join(); _this->audioStream->clearReadStop(); - audio::unbindFromStreamStereo(_this->selectedStreamName, _this->audioStream); + sigpath::sinkManager.unbindStream(_this->selectedStreamName, _this->audioStream); _this->writer->close(); delete _this->writer; _this->recording = false; diff --git a/root_dev/config.json b/root_dev/config.json index 567e3397..9cccba4b 100644 --- a/root_dev/config.json +++ b/root_dev/config.json @@ -18,7 +18,6 @@ }, "bandPlan": "General", "bandPlanEnabled": true, - "defaultSink": "Audio", "fftHeight": 296, "frequency": 99000000, "max": 0.0, @@ -35,9 +34,17 @@ ], "menuWidth": 300, "min": -70.5882339477539, + "offset": 0.0, "showWaterfall": true, - "source": "", + "source": "PlutoSDR", "sourceSettings": {}, + "streams": { + "Radio": { + "muted": false, + "sink": "Audio", + "volume": 0.65625 + } + }, "windowSize": { "h": 720, "w": 1280 diff --git a/root_dev/recordings/baseband_20-36-00_12-11-2020.wav b/root_dev/recordings/baseband_20-36-00_12-11-2020.wav deleted file mode 100644 index 4040697a..00000000 Binary files a/root_dev/recordings/baseband_20-36-00_12-11-2020.wav and /dev/null differ