#include #include #include #include #include #include #include #include #define CONCAT(a, b) ((std::string(a) + b).c_str()) SDRPP_MOD_INFO { /* Name: */ "file_source", /* Description: */ "Wav file source module for SDR++", /* Author: */ "Ryzerth", /* Version: */ 0, 1, 1, /* Max instances */ 1 }; class FileSourceModule : public ModuleManager::Instance { public: FileSourceModule(std::string name) : fileSelect("") { this->name = name; handler.ctx = this; handler.selectHandler = menuSelected; handler.deselectHandler = menuDeselected; handler.menuHandler = menuHandler; handler.startHandler = start; handler.stopHandler = stop; handler.tuneHandler = tune; handler.stream = &stream; sigpath::sourceManager.registerSource("File", &handler); spdlog::info("FileSourceModule '{0}': Instance created!", name); } ~FileSourceModule() { spdlog::info("FileSourceModule '{0}': Instance deleted!", name); } void enable() { enabled = true; } void disable() { enabled = false; } bool isEnabled() { return enabled; } private: static void menuSelected(void* ctx) { FileSourceModule* _this = (FileSourceModule*)ctx; core::setInputSampleRate(_this->sampleRate); spdlog::info("FileSourceModule '{0}': Menu Select!", _this->name); } static void menuDeselected(void* ctx) { FileSourceModule* _this = (FileSourceModule*)ctx; spdlog::info("FileSourceModule '{0}': Menu Deselect!", _this->name); } static void start(void* ctx) { FileSourceModule* _this = (FileSourceModule*)ctx; if (_this->running) { return; } if (_this->reader == NULL) { return; } _this->running = true; _this->workerThread = std::thread(worker, _this); spdlog::info("FileSourceModule '{0}': Start!", _this->name); } static void stop(void* ctx) { FileSourceModule* _this = (FileSourceModule*)ctx; if (!_this->running) { return; } if (_this->reader == NULL) { return; } _this->stream.stopWriter(); _this->workerThread.join(); _this->stream.clearWriteStop(); _this->running = false; _this->reader->rewind(); spdlog::info("FileSourceModule '{0}': Stop!", _this->name); } static void tune(double freq, void* ctx) { FileSourceModule* _this = (FileSourceModule*)ctx; spdlog::info("FileSourceModule '{0}': Tune: {1}!", _this->name, freq); } static void menuHandler(void* ctx) { FileSourceModule* _this = (FileSourceModule*)ctx; if (_this->fileSelect.render("##file_source_" + _this->name)) { if (_this->fileSelect.pathIsValid()) { if (_this->reader != NULL) { _this->reader->close(); delete _this->reader; } try { _this->reader = new WavReader(_this->fileSelect.path); if (_this->reader->isValid() && _this->reader->getBitDepth() == 16 && _this->reader->getChannelCount() == 2) { _this->sampleRate = _this->reader->getSampleRate(); core::setInputSampleRate(_this->sampleRate); } else { _this->reader->close(); delete _this->reader; } } catch (std::exception e) {} } } } static void worker(void* ctx) { FileSourceModule* _this = (FileSourceModule*)ctx; double sampleRate = _this->reader->getSampleRate(); int blockSize = sampleRate / 200.0f; int16_t* inBuf = new int16_t[blockSize * 2]; while (true) { _this->reader->readSamples(inBuf, blockSize * 2 * sizeof(int16_t)); for (int i = 0; i < blockSize; i++) { _this->stream.writeBuf[i].q = (float)inBuf[i * 2] / (float)0x7FFF; _this->stream.writeBuf[i].i = (float)inBuf[(i * 2) + 1] / (float)0x7FFF; } if (!_this->stream.swap(blockSize)) { break; }; } delete[] inBuf; } FileSelect fileSelect; std::string name; dsp::stream stream; SourceManager::SourceHandler handler; WavReader* reader = NULL; bool running = false; bool enabled = true; float sampleRate = 48000; std::thread workerThread; }; MOD_EXPORT void _INIT_() { // Do your one time init here } MOD_EXPORT void* _CREATE_INSTANCE_(std::string name) { return new FileSourceModule(name); } MOD_EXPORT void _DELETE_INSTANCE_(void* instance) { delete (FileSourceModule*)instance; } MOD_EXPORT void _END_() { // Do your one shutdown here }