mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-11-06 10:47:34 +01:00
New alpha version
This commit is contained in:
parent
a7a0be1b83
commit
94074bea98
@ -6,6 +6,9 @@ set(CMAKE_BUILD_TYPE "RelWithDebInfo")
|
||||
# Compiler config
|
||||
set(CMAKE_CXX_FLAGS "-O2 /std:c++17")
|
||||
|
||||
# PothosSDR
|
||||
link_directories(sdrpp "C:/Program Files/PothosSDR/lib/")
|
||||
|
||||
# Volk
|
||||
include_directories(sdrpp "C:/Program Files/PothosSDR/include/volk/")
|
||||
link_libraries(volk)
|
||||
|
14
readme.md
14
readme.md
@ -20,7 +20,19 @@ SDR++ is a cross-platform and open source SDR software with the aim of being blo
|
||||
* Recording
|
||||
* Light theme (I know you weirdos exist lol)
|
||||
* Waterfall color scheme editor
|
||||
*
|
||||
* Switchable fft size
|
||||
* Bias-T enable/disable
|
||||
* other small customisation options
|
||||
* Save waterfall and demod settings between sessions
|
||||
* "Hide sidebar" option
|
||||
|
||||
## Known issues (please check before reporting)
|
||||
* Random crashes (yikes)
|
||||
* Gains aren't stepped
|
||||
* The default gains might contain a bogus value before being adjusted
|
||||
* Clicks in the audio
|
||||
* In some cases, it takes a long time to select a device (RTL-SDR in perticular)
|
||||
* Min and Max buttons can get unachievable values (eg. min > max or min = max);
|
||||
|
||||
# Building on Windows
|
||||
## Requirements
|
||||
|
@ -196,9 +196,9 @@ namespace dsp {
|
||||
max = outBuf[i];
|
||||
}
|
||||
}
|
||||
amp = (max - min);
|
||||
amp = (max - min) / 2.0f;
|
||||
for (int i = 0; i < _this->_blockSize; i++) {
|
||||
outBuf[i] = (outBuf[i] - min) / (max - min);
|
||||
outBuf[i] = (outBuf[i] - min - amp) / amp;
|
||||
}
|
||||
if (_this->output.write(outBuf, _this->_blockSize) < 0) { break; };
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ namespace io {
|
||||
public:
|
||||
SoapyWrapper() {
|
||||
output.init(64000);
|
||||
currentGains = new float[1];
|
||||
refresh();
|
||||
setDevice(devList[0]);
|
||||
}
|
||||
@ -60,6 +61,18 @@ namespace io {
|
||||
txtSampleRateList += std::to_string((int)sampleRates[i]);
|
||||
txtSampleRateList += '\0';
|
||||
}
|
||||
|
||||
gainList = dev->listGains(SOAPY_SDR_RX, 0);
|
||||
gainRanges.clear();
|
||||
if (gainList.size() == 0) {
|
||||
return;
|
||||
}
|
||||
delete[] currentGains;
|
||||
currentGains = new float[gainList.size()];
|
||||
for (int i = 0; i < gainList.size(); i++) {
|
||||
gainRanges.push_back(dev->getGainRange(SOAPY_SDR_RX, 0, gainList[i]));
|
||||
currentGains[i] = dev->getGain(SOAPY_SDR_RX, 0, gainList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void setSampleRate(float sampleRate) {
|
||||
@ -74,6 +87,11 @@ namespace io {
|
||||
dev->setFrequency(SOAPY_SDR_RX, 0, freq);
|
||||
}
|
||||
|
||||
void setGain(int gainId, float gain) {
|
||||
currentGains[gainId] = gain;
|
||||
dev->setGain(SOAPY_SDR_RX, 0, gainList[gainId], gain);
|
||||
}
|
||||
|
||||
bool isRunning() {
|
||||
return running;
|
||||
}
|
||||
@ -83,6 +101,10 @@ namespace io {
|
||||
std::vector<double> sampleRates;
|
||||
std::string txtSampleRateList;
|
||||
|
||||
std::vector<std::string> gainList;
|
||||
std::vector<SoapySDR::Range> gainRanges;
|
||||
float* currentGains;
|
||||
|
||||
dsp::stream<dsp::complex_t> output;
|
||||
|
||||
private:
|
||||
|
@ -21,6 +21,8 @@ FrequencySelect fSel;
|
||||
fftwf_complex *fft_in, *fft_out;
|
||||
fftwf_plan p;
|
||||
float* tempData;
|
||||
float* uiGains;
|
||||
char buf[1024];
|
||||
|
||||
int fftSize = 8192 * 8;
|
||||
|
||||
@ -66,6 +68,8 @@ void windowInit() {
|
||||
|
||||
sigPath.init(sampleRate, 20, fftSize, &soapy.output, (dsp::complex_t*)fft_in, fftHandler);
|
||||
sigPath.start();
|
||||
|
||||
uiGains = new float[1];
|
||||
}
|
||||
|
||||
int devId = 0;
|
||||
@ -79,7 +83,7 @@ bool showExample = false;
|
||||
long freq = 90500000;
|
||||
long _freq = 90500000;
|
||||
|
||||
int demod = 0;
|
||||
int demod = 1;
|
||||
|
||||
bool state = false;
|
||||
bool mulstate = true;
|
||||
@ -220,6 +224,17 @@ void drawWindow() {
|
||||
if (devId != _devId) {
|
||||
_devId = devId;
|
||||
soapy.setDevice(soapy.devList[devId]);
|
||||
srId = 0;
|
||||
_srId = -1;
|
||||
soapy.setSampleRate(soapy.sampleRates[0]);
|
||||
if (soapy.gainList.size() == 0) {
|
||||
return;
|
||||
}
|
||||
delete[] uiGains;
|
||||
uiGains = new float[soapy.gainList.size()];
|
||||
for (int i = 0; i < soapy.gainList.size(); i++) {
|
||||
uiGains[i] = soapy.currentGains[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (srId != _srId) {
|
||||
@ -269,11 +284,6 @@ void drawWindow() {
|
||||
|
||||
fSel.draw();
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 8);
|
||||
ImGui::SameLine(ImGui::GetWindowWidth() - 40);
|
||||
ImGui::Image(icons::LOGO, ImVec2(30, 30));
|
||||
|
||||
|
||||
ImGui::Columns(3, "WindowColumns", false);
|
||||
ImVec2 winSize = ImGui::GetWindowSize();
|
||||
ImGui::SetColumnWidth(0, 300);
|
||||
@ -287,17 +297,34 @@ void drawWindow() {
|
||||
ImGui::PushItemWidth(ImGui::GetWindowSize().x);
|
||||
ImGui::Combo("##_0_", &devId, soapy.txtDevList.c_str());
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
if (!playing) {
|
||||
ImGui::Combo("##_1_", &srId, soapy.txtSampleRateList.c_str());
|
||||
}
|
||||
else {
|
||||
ImGui::Text("%s Samples/s", soapy.txtSampleRateList.c_str());
|
||||
}
|
||||
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Refresh")) {
|
||||
soapy.refresh();
|
||||
}
|
||||
|
||||
for (int i = 0; i < soapy.gainList.size(); i++) {
|
||||
ImGui::Text("%s gain", soapy.gainList[i].c_str());
|
||||
ImGui::SameLine();
|
||||
sprintf(buf, "##_gain_slide_%d_", i);
|
||||
ImGui::SliderFloat(buf, &uiGains[i], soapy.gainRanges[i].minimum(), soapy.gainRanges[i].maximum());
|
||||
|
||||
// float step = soapy.gainRanges[i].step();
|
||||
// printf("%f\n", step);
|
||||
|
||||
// uiGains[i] = roundf(uiGains[i] / soapy.gainRanges[i].step()) * soapy.gainRanges[i].step();
|
||||
|
||||
if (uiGains[i] != soapy.currentGains[i]) {
|
||||
soapy.setGain(i, uiGains[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Radio")) {
|
||||
@ -370,7 +397,7 @@ void drawWindow() {
|
||||
ImGui::NextColumn();
|
||||
|
||||
ImGui::Text("Zoom");
|
||||
ImGui::VSliderFloat("##_7_", ImVec2(20.0f, 150.0f), &bw, 1000.0f, sampleRate, "");
|
||||
ImGui::VSliderFloat("##_7_", ImVec2(20.0f, 150.0f), &bw, sampleRate, 1000.0f, "");
|
||||
|
||||
ImGui::NewLine();
|
||||
|
||||
|
@ -160,4 +160,8 @@ void SignalPath::start() {
|
||||
|
||||
audioResamp.start();
|
||||
audio.start();
|
||||
}
|
||||
|
||||
void SignalPath::setDCBiasCorrection(bool enabled) {
|
||||
dcBiasRemover.bypass = !enabled;
|
||||
}
|
@ -35,6 +35,7 @@ void doZoom(int offset, int width, int outWidth, std::vector<float> data, float*
|
||||
}
|
||||
|
||||
float freq_ranges[] = {
|
||||
1.0f, 2.0f, 2.5f, 5.0f,
|
||||
10.0f, 20.0f, 25.0f, 50.0f,
|
||||
100.0f, 200.0f, 250.0f, 500.0f,
|
||||
1000.0f, 2000.0f, 2500.0f, 5000.0f,
|
||||
@ -44,9 +45,9 @@ float freq_ranges[] = {
|
||||
10000000.0f, 20000000.0f, 25000000.0f, 50000000.0f
|
||||
};
|
||||
|
||||
float findBestFreqRange(float bandwidth) {
|
||||
for (int i = 0; i < 28; i++) {
|
||||
if (bandwidth / freq_ranges[i] < 25.0f) {
|
||||
float findBestRange(float bandwidth, int maxSteps) {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (bandwidth / freq_ranges[i] < (float)maxSteps) {
|
||||
return freq_ranges[i];
|
||||
}
|
||||
}
|
||||
@ -104,14 +105,14 @@ namespace ImGui {
|
||||
|
||||
void WaterFall::drawFFT() {
|
||||
// Calculate scaling factor
|
||||
float startLine = floorf(fftMax / 10.0f) * 10.0f;
|
||||
float startLine = floorf(fftMax / vRange) * vRange;
|
||||
float vertRange = fftMax - fftMin;
|
||||
float scaleFactor = fftHeight / vertRange;
|
||||
char buf[100];
|
||||
|
||||
|
||||
// Vertical scale
|
||||
for (float line = startLine; line > fftMin; line -= 10.0f) {
|
||||
for (float line = startLine; line > fftMin; line -= vRange) {
|
||||
float yPos = widgetPos.y + fftHeight + 10 - ((line - fftMin) * scaleFactor);
|
||||
window->DrawList->AddLine(ImVec2(widgetPos.x + 50, roundf(yPos)),
|
||||
ImVec2(widgetPos.x + dataWidth + 50, roundf(yPos)),
|
||||
@ -177,7 +178,7 @@ namespace ImGui {
|
||||
|
||||
void WaterFall::drawVFO() {
|
||||
float width = (vfoBandwidth / viewBandwidth) * (float)dataWidth;
|
||||
int center = (((vfoOffset - viewOffset) / (viewBandwidth / 2.0f)) + 1.0f) * ((float)dataWidth / 2.0f);
|
||||
int center = roundf((((vfoOffset - viewOffset) / (viewBandwidth / 2.0f)) + 1.0f) * ((float)dataWidth / 2.0f));
|
||||
int left;
|
||||
int right;
|
||||
|
||||
@ -316,6 +317,13 @@ namespace ImGui {
|
||||
freqAreaMin = ImVec2(widgetPos.x + 50, widgetPos.y + fftHeight + 11);
|
||||
freqAreaMax = ImVec2(widgetPos.x + dataWidth + 50, widgetPos.y + fftHeight + 50);
|
||||
|
||||
maxHSteps = dataWidth / 50;
|
||||
maxVSteps = fftHeight / 15;
|
||||
|
||||
range = findBestRange(viewBandwidth, maxHSteps);
|
||||
vRange = findBestRange(fftMax - fftMin, maxVSteps);
|
||||
vRange = 10.0f;
|
||||
|
||||
printf("Resized: %d %d\n", dataWidth, waterfallHeight);
|
||||
|
||||
updateWaterfallFb();
|
||||
@ -461,7 +469,7 @@ namespace ImGui {
|
||||
viewBandwidth = bandWidth;
|
||||
lowerFreq = (centerFreq + viewOffset) - (viewBandwidth / 2.0f);
|
||||
upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f);
|
||||
range = findBestFreqRange(bandWidth);
|
||||
range = findBestRange(bandWidth, maxHSteps);
|
||||
updateWaterfallFb();
|
||||
}
|
||||
|
||||
@ -491,6 +499,7 @@ namespace ImGui {
|
||||
|
||||
void WaterFall::setFFTMin(float min) {
|
||||
fftMin = min;
|
||||
vRange = findBestRange(fftMax - fftMin, maxVSteps);
|
||||
}
|
||||
|
||||
float WaterFall::getFFTMin() {
|
||||
@ -499,6 +508,7 @@ namespace ImGui {
|
||||
|
||||
void WaterFall::setFFTMax(float max) {
|
||||
fftMax = max;
|
||||
vRange = findBestRange(fftMax - fftMin, maxVSteps);
|
||||
}
|
||||
|
||||
float WaterFall::getFFTMax() {
|
||||
|
@ -100,6 +100,11 @@ namespace ImGui {
|
||||
|
||||
std::mutex buf_mtx;
|
||||
|
||||
float vRange;
|
||||
|
||||
int maxVSteps;
|
||||
int maxHSteps;
|
||||
|
||||
int dataWidth; // Width of the FFT and waterfall
|
||||
int fftHeight; // Height of the fft graph
|
||||
int waterfallHeight; // Height of the waterfall
|
||||
|
Loading…
Reference in New Issue
Block a user