forked from shajen/rtl-sdr-scanner-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
shajen
authored and
Borys Dyczko
committed
Aug 27, 2021
1 parent
64dca1b
commit 8d67b78
Showing
17 changed files
with
352 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 1,4 @@ | ||
CMakeLists.txt.user | ||
build | ||
*.wav | ||
todo.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,13 @@ | ||
#!/bin/bash | ||
|
||
TYPE=${1:-'Release'} | ||
echo "build type: $TYPE" | ||
|
||
rm -rf build | ||
mkdir -p build | ||
pushd build | ||
|
||
cmake .. -DCMAKE_BUILD_TYPE=$TYPE | ||
make -j4 | ||
|
||
popd |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,18 @@ | ||
#include "spectrogram.h" | ||
|
||
Spectrogram::Spectrogram(uint32_t size) : m_size(size), m_buffer(size), m_signals(size), m_spectrogram(spgramcf_create_default(size)) {} | ||
|
||
Spectrogram::~Spectrogram() { spgramcf_destroy(m_spectrogram); } | ||
|
||
const std::vector<Signal>& Spectrogram::psd(uint32_t centerFrequency, uint32_t bandwidth, std::vector<std::complex<float>>& buffer, uint32_t size) { | ||
spgramcf_reset(m_spectrogram); | ||
spgramcf_write(m_spectrogram, toLiquidComplext(buffer.data()), size); | ||
spgramcf_get_psd(m_spectrogram, m_buffer.data()); | ||
|
||
for (int i = 0; i < m_size; i) { | ||
m_signals[i].power = m_buffer[i]; | ||
m_signals[i].frequency.frequency = (centerFrequency - bandwidth / 2) static_cast<uint64_t>(i) * bandwidth / m_size; | ||
} | ||
|
||
return m_signals; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,21 @@ | ||
#pragma once | ||
|
||
#include <config.h> | ||
#include <liquid/liquid.h> | ||
#include <utils.h> | ||
|
||
#include <complex> | ||
#include <vector> | ||
|
||
class Spectrogram { | ||
public: | ||
Spectrogram(uint32_t size); | ||
virtual ~Spectrogram(); | ||
const std::vector<Signal>& psd(uint32_t centerFrequency, uint32_t bandwidth, std::vector<std::complex<float>>& buffer, uint32_t size); | ||
|
||
private: | ||
const uint32_t m_size; | ||
std::vector<float> m_buffer; | ||
std::vector<Signal> m_signals; | ||
spgramcf m_spectrogram; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,71 @@ | ||
#include "mp3_writer.h" | ||
|
||
#include <config.h> | ||
|
||
#include <filesystem> | ||
|
||
std::string getPath(const Frequency& frequency) { | ||
time_t rawtime = time(nullptr); | ||
struct tm* tm = localtime(&rawtime); | ||
|
||
char dir[4096]; | ||
sprintf(dir, "%s/d-d-d/", MP3_OUTPUT_DIRECTORY.c_str(), tm->tm_year 1900, tm->tm_mon 1, tm->tm_mday); | ||
std::filesystem::create_directories(dir); | ||
|
||
char filename[4096]; | ||
const auto f1 = frequency.frequency / 1000000; | ||
const auto f2 = (frequency.frequency / 1000) % 1000; | ||
const auto f3 = frequency.frequency % 1000; | ||
sprintf(filename, "d:d:d =_d_d.mp3", tm->tm_hour, tm->tm_min, tm->tm_sec, f1, f2, f3); | ||
return std::string(dir) std::string(filename); | ||
} | ||
|
||
sox_signalinfo_t config() { | ||
sox_signalinfo_t c; | ||
c.channels = 1; | ||
c.rate = MP3_SAMPLE_RATE; | ||
return c; | ||
} | ||
|
||
Mp3Writer::Mp3Writer(const Frequency& frequency, uint32_t sampleRate) | ||
: m_path(getPath(frequency)), | ||
m_sampleRate(sampleRate), | ||
m_samples(0), | ||
m_resampler(soxr_create(sampleRate, MP3_SAMPLE_RATE, 1, nullptr, nullptr, nullptr, nullptr)), | ||
m_mp3Info(config()), | ||
m_mp3File(sox_open_write(m_path.c_str(), &m_mp3Info, nullptr, nullptr, nullptr, nullptr)) {} | ||
|
||
Mp3Writer::~Mp3Writer() { | ||
soxr_delete(m_resampler); | ||
sox_close(m_mp3File); | ||
const auto duration = std::chrono::milliseconds(1000 * m_samples / m_sampleRate); | ||
if (duration < MIN_RECORDING_TIME) { | ||
spdlog::info("recording time: {:.2f} s, too short, removing", duration.count() / 1000.0); | ||
std::filesystem::remove(m_path); | ||
} else { | ||
spdlog::info("recording time: {:.2f} s", duration.count() / 1000.0); | ||
} | ||
} | ||
|
||
void Mp3Writer::appendSamples(const std::vector<float>& samples) { | ||
m_samples = samples.size(); | ||
if (m_resamplerBuffer.size() < samples.size()) { | ||
m_resamplerBuffer.resize(samples.size()); | ||
} | ||
if (m_mp3Buffer.size() < samples.size()) { | ||
m_mp3Buffer.resize(samples.size()); | ||
} | ||
size_t read{0}; | ||
size_t write{0}; | ||
soxr_process(m_resampler, samples.data(), samples.size(), &read, m_resamplerBuffer.data(), m_resamplerBuffer.size(), &write); | ||
|
||
if (read > 0 && write > 0) { | ||
spdlog::debug("recording resampling, in rate/samples: {}/{}, out rate/samples: {}/{}", m_sampleRate, read, MP3_SAMPLE_RATE, write); | ||
for (int i = 0; i < write; i) { | ||
m_mp3Buffer[i] = m_resamplerBuffer[i] * 1000000000; | ||
} | ||
sox_write(m_mp3File, m_mp3Buffer.data(), write); | ||
} else { | ||
throw std::runtime_error("recording resampling error"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,25 @@ | ||
#pragma once | ||
|
||
#include <sox.h> | ||
#include <soxr.h> | ||
#include <utils.h> | ||
|
||
#include <string> | ||
|
||
class Mp3Writer { | ||
public: | ||
Mp3Writer(const Frequency& frequency, uint32_t sampleRate); | ||
~Mp3Writer(); | ||
|
||
void appendSamples(const std::vector<float>& samples); | ||
|
||
private: | ||
const std::string m_path; | ||
const uint32_t m_sampleRate; | ||
std::vector<float> m_resamplerBuffer; | ||
std::vector<sox_sample_t> m_mp3Buffer; | ||
uint64_t m_samples; | ||
soxr_t m_resampler; | ||
sox_signalinfo_t m_mp3Info; | ||
sox_format_t* m_mp3File; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 1,89 @@ | ||
#include "recorder.h" | ||
|
||
#include <config.h> | ||
#include <math.h> | ||
#include <spdlog/spdlog.h> | ||
|
||
Recorder::Recorder() : m_startDataTime(time()), m_lastActiveDataTime(time()), m_lastDataTime(time()) {} | ||
#include <map> | ||
|
||
constexpr auto DOWNSAMPLE = 10; | ||
constexpr auto DOWNSAMPLE_FILTER_LENGTH = 10; | ||
|
||
Recorder::Recorder(Signal signal, uint32_t centerFrequency, uint32_t bandwidth, uint32_t sampleRate, Spectrogram& Spectrogram) | ||
: m_centerFrequency(centerFrequency), | ||
m_bandwidth(bandwidth), | ||
m_sampleRate(sampleRate), | ||
m_spectrogram(Spectrogram), | ||
m_fmDemodulator(freqdem_create(0.5f)), | ||
m_Mp3Writer(signal.frequency, sampleRate / DOWNSAMPLE), | ||
m_decimator(iirdecim_crcf_create_default(DOWNSAMPLE, DOWNSAMPLE_FILTER_LENGTH)), | ||
m_startDataTime(time()), | ||
m_lastActiveDataTime(time()), | ||
m_lastDataTime(time()) {} | ||
|
||
Recorder::~Recorder() { | ||
const auto duration = (m_lastDataTime - m_startDataTime).count() / 1000.0; | ||
const auto rawDataSize = m_samples.size() * sizeof(std::complex<float>) / 1024.0 / 1024.0; | ||
spdlog::info("recording, time: {:.2f} s, best signals: {}, samples: {}, rawDataSize: {:.2f} MB", duration, m_bestSignals.size(), m_samples.size(), rawDataSize); | ||
processSamples(); | ||
iirdecim_crcf_destroy(m_decimator); | ||
freqdem_destroy(m_fmDemodulator); | ||
spdlog::debug("close recording"); | ||
} | ||
|
||
void Recorder::appendSamples(const Signal &bestSignal, bool active, std::vector<std::complex<float> > &buffer, const uint32_t samples) { | ||
void Recorder::appendSamples(const Signal& bestSignal, bool active, std::vector<std::complex<float>>& buffer, const uint32_t samples) { | ||
std::unique_lock<std::mutex> lock(m_mutex); | ||
m_lastDataTime = time(); | ||
if (active) { | ||
m_lastActiveDataTime = time(); | ||
m_bestSignals.push_back(bestSignal); | ||
m_frequency[bestSignal.frequency.frequency] ; | ||
for (const auto& noisedSample : m_noisedSamples) { | ||
m_samples.push_back(noisedSample); | ||
} | ||
m_noisedSamples.clear(); | ||
for (int i = 0; i < samples; i) { | ||
m_noisedSamples.push_back(buffer[i]); | ||
} | ||
} else { | ||
for (int i = 0; i < samples; i) { | ||
m_noisedSamples.push_back(buffer[i]); | ||
} | ||
} | ||
for (int i = 0; i < samples; i) { | ||
m_samples.push_back(buffer[i]); | ||
|
||
if (m_sampleRate <= m_samples.size()) { | ||
processSamples(); | ||
} | ||
} | ||
|
||
bool Recorder::isFinished() const { return m_lastActiveDataTime MAX_SILENCE_TIME < time(); } | ||
|
||
void Recorder::processSamples() { | ||
if (m_samples.size() <= 1 || m_frequency.empty()) { | ||
return; | ||
} | ||
const auto duration = (m_lastDataTime - m_startDataTime).count() / 1000.0; | ||
const auto bestFrequency = getBestFrequency(); | ||
spdlog::debug("processing partial recording, time: {:.2f} s, best {}", duration, bestFrequency.toString()); | ||
shift(m_samples, m_centerFrequency - bestFrequency.frequency, m_sampleRate, m_samples.size()); | ||
|
||
std::vector<std::complex<float>> downSamples; | ||
if (m_lastSample.has_value()) { | ||
downSamples.push_back(m_lastSample.value()); | ||
downSamples.resize(m_samples.size() / DOWNSAMPLE 1); | ||
iirdecim_crcf_execute_block(m_decimator, reinterpret_cast<liquid_float_complex*>(m_samples.data()), m_samples.size() / DOWNSAMPLE, reinterpret_cast<liquid_float_complex*>(downSamples.data() 1)); | ||
} else { | ||
downSamples.resize(m_samples.size() / DOWNSAMPLE); | ||
iirdecim_crcf_execute_block(m_decimator, toLiquidComplext(m_samples.data()), m_samples.size() / DOWNSAMPLE, toLiquidComplext(downSamples.data())); | ||
} | ||
|
||
std::vector<float> fm; | ||
fm.resize(downSamples.size() - 1); | ||
freqdem_demodulate_block(m_fmDemodulator, toLiquidComplext(downSamples.data()), downSamples.size(), fm.data()); | ||
m_Mp3Writer.appendSamples(fm); | ||
|
||
m_lastSample = downSamples.back(); | ||
m_samples.clear(); | ||
spdlog::debug("finish partial processing recording"); | ||
} | ||
|
||
Frequency Recorder::getBestFrequency() const { | ||
auto max = std::max_element(m_frequency.begin(), m_frequency.end(), [](const auto& x, const auto& y) { return x.second < y.second; }); | ||
return {max->first}; | ||
} |
Oops, something went wrong.