Пример #1
0
void SDRPostThread::run() {
#ifdef __APPLE__
    pthread_t tID = pthread_self();  // ID of this thread
    int priority = sched_get_priority_max( SCHED_FIFO);
    sched_param prio = {priority}; // scheduling priority of thread
    pthread_setschedparam(tID, SCHED_FIFO, &prio);
#endif

//    std::cout << "SDR post-processing thread started.." << std::endl;

    iqDataInQueue = static_cast<SDRThreadIQDataQueue*>(getInputQueue("IQDataInput"));
    iqDataOutQueue = static_cast<DemodulatorThreadInputQueue*>(getOutputQueue("IQDataOutput"));
    iqVisualQueue = static_cast<DemodulatorThreadInputQueue*>(getOutputQueue("IQVisualDataOutput"));
    iqActiveDemodVisualQueue = static_cast<DemodulatorThreadInputQueue*>(getOutputQueue("IQActiveDemodVisualDataOutput"));
    
    while (!stopping) {
        SDRThreadIQData *data_in;
        
        iqDataInQueue->pop(data_in);
        //        std::lock_guard < std::mutex > lock(data_in->m_mutex);

        std::lock_guard < std::mutex > lock(busy_demod);

        if (data_in && data_in->data.size()) {
            if(data_in->numChannels > 1) {
                runPFBCH(data_in);
            } else {
                runSingleCH(data_in);
            }
        }

        if (data_in) {
            data_in->decRefCount();   
        }

        bool doUpdate = false;
        for (size_t j = 0; j < nRunDemods; j++) {
            DemodulatorInstance *demod = runDemods[j];
            if (abs(frequency - demod->getFrequency()) > (sampleRate / 2)) {
                doUpdate = true;
            }
        }
        
        //Only update the list of demodulators here
        if (doUpdate) {
            updateActiveDemodulators();
        }
    } //end while
    
    //Be safe, remove as many elements as possible
    DemodulatorThreadIQData *visualDataDummy;
    while (iqVisualQueue && iqVisualQueue->try_pop(visualDataDummy)) {
        visualDataDummy->decRefCount();        
    }

    //    buffers.purge();
    //    visualDataBuffers.purge();

//    std::cout << "SDR post-processing thread done." << std::endl;
}
void *DemodulatorPreThread::threadMain() {
#else
void DemodulatorPreThread::threadMain() {
#endif
#ifdef __APPLE__
    pthread_t tID = pthread_self();  // ID of this thread
    int priority = sched_get_priority_max( SCHED_FIFO) - 1;
    sched_param prio = {priority}; // scheduling priority of thread
    pthread_setschedparam(tID, SCHED_FIFO, &prio);
#endif

    if (!initialized) {
        initialize();
    }

    std::cout << "Demodulator preprocessor thread started.." << std::endl;

    std::deque<DemodulatorThreadPostIQData *> buffers;
    std::deque<DemodulatorThreadPostIQData *>::iterator buffers_i;

    std::vector<liquid_float_complex> in_buf_data;
    std::vector<liquid_float_complex> out_buf_data;
//    liquid_float_complex carrySample;   // Keep the stream count even to simplify some demod operations
//    bool carrySampleFlag = false;

    terminated = false;

    while (!terminated) {
        DemodulatorThreadIQData *inp;
        iqInputQueue->pop(inp);

        bool bandwidthChanged = false;
        bool rateChanged = false;
        DemodulatorThreadParameters tempParams = params;

        if (!commandQueue->empty()) {
            while (!commandQueue->empty()) {
                DemodulatorThreadCommand command;
                commandQueue->pop(command);
                switch (command.cmd) {
                case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH:
                    if (command.llong_value < 1500) {
                        command.llong_value = 1500;
                    }
                    if (command.llong_value > params.sampleRate) {
                        tempParams.bandwidth = params.sampleRate;
                    } else {
                        tempParams.bandwidth = command.llong_value;
                    }
                    bandwidthChanged = true;
                    break;
                case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY:
                    params.frequency = tempParams.frequency = command.llong_value;
                    break;
                case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_AUDIO_RATE:
                    tempParams.audioSampleRate = (int)command.llong_value;
                    rateChanged = true;
                    break;
                default:
                    break;
                }
            }
        }

        if (inp->sampleRate != tempParams.sampleRate && inp->sampleRate) {
            tempParams.sampleRate = inp->sampleRate;
            rateChanged = true;
        }

        if (bandwidthChanged || rateChanged) {
            DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS);
            command.sampleRate = tempParams.sampleRate;
            command.audioSampleRate = tempParams.audioSampleRate;
            command.bandwidth = tempParams.bandwidth;
            command.frequency = tempParams.frequency;

            workerQueue->push(command);
        }

        if (!initialized) {
            continue;
        }

        // Requested frequency is not center, shift it into the center!
        if ((params.frequency - inp->frequency) != shiftFrequency || rateChanged) {
            shiftFrequency = params.frequency - inp->frequency;
            if (abs(shiftFrequency) <= (int) ((double) (wxGetApp().getSampleRate() / 2) * 1.5)) {
                nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) wxGetApp().getSampleRate())));
            }
        }

        if (abs(shiftFrequency) > (int) ((double) (wxGetApp().getSampleRate() / 2) * 1.5)) {
            continue;
        }

//        std::lock_guard < std::mutex > lock(inp->m_mutex);
        std::vector<liquid_float_complex> *data = &inp->data;
        if (data->size() && (inp->sampleRate == params.sampleRate)) {
            int bufSize = data->size();

            if (in_buf_data.size() != bufSize) {
                if (in_buf_data.capacity() < bufSize) {
                    in_buf_data.reserve(bufSize);
                    out_buf_data.reserve(bufSize);
                }
                in_buf_data.resize(bufSize);
                out_buf_data.resize(bufSize);
            }

            in_buf_data.assign(inp->data.begin(), inp->data.end());

            liquid_float_complex *in_buf = &in_buf_data[0];
            liquid_float_complex *out_buf = &out_buf_data[0];
            liquid_float_complex *temp_buf = NULL;

            if (shiftFrequency != 0) {
                if (shiftFrequency < 0) {
                    nco_crcf_mix_block_up(freqShifter, in_buf, out_buf, bufSize);
                } else {
                    nco_crcf_mix_block_down(freqShifter, in_buf, out_buf, bufSize);
                }
                temp_buf = in_buf;
                in_buf = out_buf;
                out_buf = temp_buf;
            }

            DemodulatorThreadPostIQData *resamp = NULL;

            for (buffers_i = buffers.begin(); buffers_i != buffers.end(); buffers_i++) {
                if ((*buffers_i)->getRefCount() <= 0) {
                    resamp = (*buffers_i);
                    break;
                }
            }

            if (resamp == NULL) {
                resamp = new DemodulatorThreadPostIQData;
                buffers.push_back(resamp);
            }

            int out_size = ceil((double) (bufSize) * iqResampleRatio) + 512;

            if (resampledData.size() != out_size) {
                if (resampledData.capacity() < out_size) {
                    resampledData.reserve(out_size);
                }
                resampledData.resize(out_size);
            }

            unsigned int numWritten;
            msresamp_crcf_execute(iqResampler, in_buf, bufSize, &resampledData[0], &numWritten);

            resamp->setRefCount(1);

            resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten);

//            bool uneven = (numWritten % 2 != 0);

//            if (!carrySampleFlag && !uneven) {
//                resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten);
//                carrySampleFlag = false;
//            } else if (!carrySampleFlag && uneven) {
//                resamp->data.assign(resampledData.begin(), resampledData.begin() + (numWritten-1));
//                carrySample = resampledData.back();
//                carrySampleFlag = true;
//            } else if (carrySampleFlag && uneven) {
//                resamp->data.resize(numWritten+1);
//                resamp->data[0] = carrySample;
//                memcpy(&resamp->data[1],&resampledData[0],sizeof(liquid_float_complex)*numWritten);
//                carrySampleFlag = false;
//            } else if (carrySampleFlag && !uneven) {
//                resamp->data.resize(numWritten);
//                resamp->data[0] = carrySample;
//                memcpy(&resamp->data[1],&resampledData[0],sizeof(liquid_float_complex)*(numWritten-1));
//                carrySample = resampledData.back();
//                carrySampleFlag = true;
//            }



            resamp->audioResampleRatio = audioResampleRatio;
            resamp->audioResampler = audioResampler;
            resamp->audioSampleRate = params.audioSampleRate;
            resamp->stereoResampler = stereoResampler;
            resamp->firStereoLeft = firStereoLeft;
            resamp->firStereoRight = firStereoRight;
            resamp->iirStereoPilot = iirStereoPilot;
            resamp->sampleRate = params.bandwidth;

            iqOutputQueue->push(resamp);
        }

        inp->decRefCount();

        if (!workerResults->empty()) {
            while (!workerResults->empty()) {
                DemodulatorWorkerThreadResult result;
                workerResults->pop(result);

                switch (result.cmd) {
                case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS:
                    msresamp_crcf_destroy(iqResampler);

                    if (result.iqResampler) {
                        iqResampler = result.iqResampler;
                        iqResampleRatio = result.iqResampleRatio;
                    }

                    if (result.firStereoLeft) {
                        firStereoLeft = result.firStereoLeft;
                    }

                    if (result.firStereoRight) {
                        firStereoRight = result.firStereoRight;
                    }

                    if (result.iirStereoPilot) {
                        iirStereoPilot = result.iirStereoPilot;
                    }
                    
                    if (result.audioResampler) {
                        audioResampler = result.audioResampler;
                        audioResampleRatio = result.audioResamplerRatio;
                        stereoResampler = result.stereoResampler;
                    }

                    if (result.audioSampleRate) {
                        params.audioSampleRate = result.audioSampleRate;
                    }

                    if (result.bandwidth) {
                        params.bandwidth = result.bandwidth;
                    }

                    if (result.sampleRate) {
                        params.sampleRate = result.sampleRate;
                    }
                    break;
                default:
                    break;
                }
            }
        }
    }

    while (!buffers.empty()) {
        DemodulatorThreadPostIQData *iqDataDel = buffers.front();
        buffers.pop_front();
        delete iqDataDel;
    }

    DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED);
    tCmd.context = this;
    threadQueueNotify->push(tCmd);
    std::cout << "Demodulator preprocessor thread done." << std::endl;

#ifdef __APPLE__
    return this;
#endif
}
Пример #3
0
void SDRPostThread::run() {
#ifdef __APPLE__
    pthread_t tID = pthread_self();  // ID of this thread
    int priority = sched_get_priority_max( SCHED_FIFO) - 1;
    sched_param prio = {priority}; // scheduling priority of thread
    pthread_setschedparam(tID, SCHED_FIFO, &prio);
#endif

    dcFilter = iirfilt_crcf_create_dc_blocker(0.0005);

    std::cout << "SDR post-processing thread started.." << std::endl;

    iqDataInQueue = (SDRThreadIQDataQueue*)getInputQueue("IQDataInput");
    iqDataOutQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQDataOutput");
    iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOutput");
    
    ReBuffer<DemodulatorThreadIQData> buffers;
    std::vector<liquid_float_complex> fpData;
    std::vector<liquid_float_complex> dataOut;
    
    iqDataInQueue->set_max_num_items(0);
    
    while (!terminated) {
        SDRThreadIQData *data_in;
        
        iqDataInQueue->pop(data_in);
        //        std::lock_guard < std::mutex > lock(data_in->m_mutex);
        
        if (data_in && data_in->data.size()) {
            int dataSize = data_in->data.size()/2;
            if (dataSize > fpData.capacity()) {
                fpData.reserve(dataSize);
                dataOut.reserve(dataSize);
            }
            if (dataSize != fpData.size()) {
                fpData.resize(dataSize);
                dataOut.resize(dataSize);
            }
            
            if (swapIQ) {
                for (int i = 0; i < dataSize; i++) {
                    fpData[i] = _lut_swap[*((uint16_t*)&data_in->data[2*i])];
                }
            } else {
                for (int i = 0; i < dataSize; i++) {
                    fpData[i] = _lut[*((uint16_t*)&data_in->data[2*i])];
                }
            }
            
            iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]);
            
            if (iqVisualQueue != NULL && !iqVisualQueue->full()) {
                DemodulatorThreadIQData *visualDataOut = visualDataBuffers.getBuffer();
                visualDataOut->setRefCount(1);
                
                int num_vis_samples = dataOut.size();

//                if (visualDataOut->data.size() < num_vis_samples) {
//                    if (visualDataOut->data.capacity() < num_vis_samples) {
//                        visualDataOut->data.reserve(num_vis_samples);
//                    }
//                    visualDataOut->data.resize(num_vis_samples);
//                }
//
                visualDataOut->frequency = data_in->frequency;
                visualDataOut->sampleRate = data_in->sampleRate;
                visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples);
                
                iqVisualQueue->push(visualDataOut);
            }
            
            busy_demod.lock();
            
            int activeDemods = 0;
            bool pushedData = false;
            
            if (demodulators.size() || iqDataOutQueue != NULL) {
                std::vector<DemodulatorInstance *>::iterator demod_i;
                for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) {
                    DemodulatorInstance *demod = *demod_i;
                    if (demod->getFrequency() != data_in->frequency
                        && abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
                        continue;
                    }
                    activeDemods++;
                }
                
                if (iqDataOutQueue != NULL) {
                    activeDemods++;
                }
                
                DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
                
                //                    std::lock_guard < std::mutex > lock(demodDataOut->m_mutex);
                demodDataOut->frequency = data_in->frequency;
                demodDataOut->sampleRate = data_in->sampleRate;
                demodDataOut->setRefCount(activeDemods);
                demodDataOut->data.assign(dataOut.begin(), dataOut.end());
                
                for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) {
                    DemodulatorInstance *demod = *demod_i;
                    DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe();
                    
                    if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
                        if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
                            demod->setActive(false);
                            DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;
                            dummyDataOut->frequency = data_in->frequency;
                            dummyDataOut->sampleRate = data_in->sampleRate;
                            demodQueue->push(dummyDataOut);
                        }
                        
                        if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) {
                            wxGetApp().setFrequency(demod->getFrequency());
                        }
                    } else if (!demod->isActive()) {
                        demod->setActive(true);
                        if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) {
                            wxGetApp().getDemodMgr().setActiveDemodulator(demod);
                        }
                    }
                    
                    if (!demod->isActive()) {
                        continue;
                    }
                    if (demod->isFollow()) {
                        demod->setFollow(false);
                    }
                    
                    demodQueue->push(demodDataOut);
                    pushedData = true;
                }
                
                if (iqDataOutQueue != NULL) {
                    if (!iqDataOutQueue->full()) {
                        iqDataOutQueue->push(demodDataOut);
                        pushedData = true;
                    } else {
                        demodDataOut->decRefCount();
                    }
                }
                
                if (!pushedData && iqDataOutQueue == NULL) {
                    demodDataOut->setRefCount(0);
                }
            }
            
            busy_demod.unlock();
        }
        data_in->decRefCount();
    }

//    buffers.purge();
    
    if (iqVisualQueue && !iqVisualQueue->empty()) {
        DemodulatorThreadIQData *visualDataDummy;
        iqVisualQueue->pop(visualDataDummy);
    }

//    visualDataBuffers.purge();

    std::cout << "SDR post-processing thread done." << std::endl;
}
Пример #4
0
void SDRPostThread::runPFBCH(SDRThreadIQData *data_in) {
    if (numChannels != data_in->numChannels || sampleRate != data_in->sampleRate) {
        numChannels = data_in->numChannels;
        sampleRate = data_in->sampleRate;
        initPFBChannelizer();
        doRefresh.store(true);
    }
    
    size_t dataSize = data_in->data.size();
    size_t outSize = data_in->data.size();
    
    if (outSize > dataOut.capacity()) {
        dataOut.reserve(outSize);
    }
    if (outSize != dataOut.size()) {
        dataOut.resize(outSize);
    }
    
    if (iqDataOutQueue != NULL && !iqDataOutQueue->full()) {
        DemodulatorThreadIQData *iqDataOut = visualDataBuffers.getBuffer();
        
        bool doVis = false;
        
        if (iqVisualQueue != NULL && !iqVisualQueue->full()) {
            doVis = true;
        }
        
        iqDataOut->setRefCount(1 + (doVis?1:0));
        
        iqDataOut->frequency = data_in->frequency;
        iqDataOut->sampleRate = data_in->sampleRate;
        iqDataOut->data.assign(data_in->data.begin(), data_in->data.begin() + dataSize);
        
        iqDataOutQueue->push(iqDataOut);
        if (doVis) {
            iqVisualQueue->push(iqDataOut);
        }
    }
    
    if (frequency != data_in->frequency) {
        frequency = data_in->frequency;
        doRefresh.store(true);
    }
    
    if (doRefresh.load()) {
        updateActiveDemodulators();
        updateChannels();
        doRefresh.store(false);
    }
    
    DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
    int activeDemodChannel = -1;
    
    // Find active demodulators
    if (nRunDemods) {
        
        // channelize data
        // firpfbch output rate is (input rate / channels)
        for (int i = 0, iMax = dataSize; i < iMax; i+=numChannels) {
            firpfbch_crcf_analyzer_execute(channelizer, &data_in->data[i], &dataOut[i]);
        }
        
        for (int i = 0, iMax = numChannels+1; i < iMax; i++) {
            demodChannelActive[i] = 0;
        }
        
        // Find nearest channel for each demodulator
        for (size_t i = 0; i < nRunDemods; i++) {
            DemodulatorInstance *demod = runDemods[i];
            demodChannel[i] = getChannelAt(demod->getFrequency());
            if (demod == activeDemod) {
                activeDemodChannel = demodChannel[i];
            }
        }
        
        for (size_t i = 0; i < nRunDemods; i++) {
            // cache channel usage refcounts
            if (demodChannel[i] >= 0) {
                demodChannelActive[demodChannel[i]]++;
            }
        }
        
        // Run channels
        for (int i = 0; i < numChannels+1; i++) {
            int doDemodVis = ((activeDemodChannel == i) && (iqActiveDemodVisualQueue != NULL) && !iqActiveDemodVisualQueue->full())?1:0;
            
            if (!doDemodVis && demodChannelActive[i] == 0) {
                continue;
            }
            
            DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
            demodDataOut->setRefCount(demodChannelActive[i] + doDemodVis);
            demodDataOut->frequency = chanCenters[i];
            demodDataOut->sampleRate = chanBw;
            
            // Calculate channel buffer size
            size_t chanDataSize = (outSize/numChannels);
            
            if (demodDataOut->data.size() != chanDataSize) {
                if (demodDataOut->data.capacity() < chanDataSize) {
                    demodDataOut->data.reserve(chanDataSize);
                }
                demodDataOut->data.resize(chanDataSize);
            }
            
            int idx = i;
            
            // Extra channel wraps lower side band of lowest channel
            // to fix frequency gap on upper side of spectrum
            if (i == numChannels) {
                idx = (numChannels/2);
            }
            
            // prepare channel data buffer
            if (i == 0) {   // Channel 0 requires DC correction
                if (dcBuf.size() != chanDataSize) {
                    dcBuf.resize(chanDataSize);
                }
                for (size_t j = 0; j < chanDataSize; j++) {
                    dcBuf[j] = dataOut[idx];
                    idx += numChannels;
                }
                iirfilt_crcf_execute_block(dcFilter, &dcBuf[0], chanDataSize, &demodDataOut->data[0]);
            } else {
                for (size_t j = 0; j < chanDataSize; j++) {
                    demodDataOut->data[j] = dataOut[idx];
                    idx += numChannels;
                }
            }
            
            if (doDemodVis) {
                iqActiveDemodVisualQueue->push(demodDataOut);
            }
            
            for (size_t j = 0; j < nRunDemods; j++) {
                if (demodChannel[j] == i) {
                    DemodulatorInstance *demod = runDemods[j];
                    demod->getIQInputDataPipe()->push(demodDataOut);
                }
            }
        }
    }
}
Пример #5
0
void SDRPostThread::runSingleCH(SDRThreadIQData *data_in) {
    if (sampleRate != data_in->sampleRate) {
        sampleRate = data_in->sampleRate;
        numChannels = 1;
        doRefresh.store(true);
    }
    
    size_t dataSize = data_in->data.size();
    size_t outSize = data_in->data.size();
    
    if (outSize > dataOut.capacity()) {
        dataOut.reserve(outSize);
    }
    if (outSize != dataOut.size()) {
        dataOut.resize(outSize);
    }
    
    if (frequency != data_in->frequency) {
        frequency = data_in->frequency;
        doRefresh.store(true);
    }
    
    if (doRefresh.load()) {
        updateActiveDemodulators();
        doRefresh.store(false);
    }
    
    size_t refCount = nRunDemods;
    bool doIQDataOut = (iqDataOutQueue != NULL && !iqDataOutQueue->full());
    bool doDemodVisOut = (nRunDemods && iqActiveDemodVisualQueue != NULL && !iqActiveDemodVisualQueue->full());
    bool doVisOut = (iqVisualQueue != NULL && !iqVisualQueue->full());
    
    if (doIQDataOut) {
        refCount++;
    }
    if (doDemodVisOut) {
        refCount++;
    }
    if (doVisOut) {
        refCount++;
    }
    
    if (refCount) {
        DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
        demodDataOut->setRefCount(refCount);
        demodDataOut->frequency = frequency;
        demodDataOut->sampleRate = sampleRate;
        
        if (demodDataOut->data.size() != dataSize) {
            if (demodDataOut->data.capacity() < dataSize) {
                demodDataOut->data.reserve(dataSize);
            }
            demodDataOut->data.resize(dataSize);
        }
        
        iirfilt_crcf_execute_block(dcFilter, &data_in->data[0], dataSize, &demodDataOut->data[0]);

        if (doDemodVisOut) {
            iqActiveDemodVisualQueue->push(demodDataOut);
        }
        
        if (doIQDataOut) {
            iqDataOutQueue->push(demodDataOut);
        }

        if (doVisOut) {
            iqVisualQueue->push(demodDataOut);
        }
        
        for (size_t i = 0; i < nRunDemods; i++) {
            runDemods[i]->getIQInputDataPipe()->push(demodDataOut);
        }
    }
}
Пример #6
0
void FFTDataDistributor::process() {
	while (!input->empty()) {
		if (!isAnyOutputEmpty()) {
			return;
		}
		DemodulatorThreadIQData *inp;
		input->pop(inp);

		if (inp) {
			if (inputBuffer.sampleRate != inp->sampleRate || inputBuffer.frequency != inp->frequency) {
                
                bufferMax = inp->sampleRate / 4;
//                std::cout << "Buffer Max: " << bufferMax << std::endl;
                bufferOffset = 0;
                
				inputBuffer.sampleRate = inp->sampleRate;
				inputBuffer.frequency = inp->frequency;
                inputBuffer.data.resize(bufferMax);
			}
            if ((bufferOffset + bufferedItems + inp->data.size()) > bufferMax) {
                memmove(&inputBuffer.data[0], &inputBuffer.data[bufferOffset], bufferedItems*sizeof(liquid_float_complex));
                bufferOffset = 0;
            } else {
                memcpy(&inputBuffer.data[bufferOffset+bufferedItems],&inp->data[0],inp->data.size()*sizeof(liquid_float_complex));
                bufferedItems += inp->data.size();
            }
			inp->decRefCount();
		} else {
			continue;
		}

		// number of seconds contained in input
		double inputTime = (double)bufferedItems / (double)inputBuffer.sampleRate;
		// number of lines in input
		double inputLines = (double)bufferedItems / (double)fftSize;

		// ratio required to achieve the desired rate
		double lineRateStep = ((double)linesPerSecond * inputTime)/(double)inputLines;

		if (bufferedItems >= fftSize) {
			int numProcessed = 0;

			if (lineRateAccum + (lineRateStep * ((double)bufferedItems/(double)fftSize)) < 1.0) {
				// move along, nothing to see here..
				lineRateAccum += (lineRateStep * ((double)bufferedItems/(double)fftSize));
				numProcessed = bufferedItems;
			} else {
				for (int i = 0, iMax = bufferedItems; i < iMax; i += fftSize) {
					if ((i + fftSize) > iMax) {
						break;
					}
					lineRateAccum += lineRateStep;

					if (lineRateAccum >= 1.0) {
						DemodulatorThreadIQData *outp = outputBuffers.getBuffer();
						outp->frequency = inputBuffer.frequency;
						outp->sampleRate = inputBuffer.sampleRate;
						outp->data.assign(inputBuffer.data.begin()+bufferOffset+i,inputBuffer.data.begin()+bufferOffset+i+fftSize);
						distribute(outp);

						while (lineRateAccum >= 1.0) {
							lineRateAccum -= 1.0;
						}
					}

					numProcessed += fftSize;
				}
			}
			if (numProcessed) {
                bufferedItems -= numProcessed;
                bufferOffset += numProcessed;
            }
            if (bufferedItems <= 0) {
                bufferedItems = 0;
                bufferOffset = 0;
            }
		}
	}
}
Пример #7
0
void SpectrumVisualProcessor::process() {
    if (!isOutputEmpty()) {
        return;
    }
    if (!input || input->empty()) {
        return;
    }
    
    if (fftSizeChanged.load()) {
        setup(newFFTSize);
        fftSizeChanged.store(false);
    }

    DemodulatorThreadIQData *iqData;
    
    input->pop(iqData);
    
    if (!iqData) {
        return;
    }

   
    //Start by locking concurrent access to iqData
    std::lock_guard < std::recursive_mutex > lock(iqData->getMonitor());

    //then get the busy_lock
    std::lock_guard < std::mutex > busy_lock(busy_run);    


   
    bool doPeak = peakHold.load() && (peakReset.load() == 0);
    
    if (fft_result.size() != fftSizeInternal) {
        if (fft_result.capacity() < fftSizeInternal) {
            fft_result.reserve(fftSizeInternal);
            fft_result_ma.reserve(fftSizeInternal);
            fft_result_maa.reserve(fftSizeInternal);
            fft_result_peak.reserve(fftSizeInternal);
        }
        fft_result.resize(fftSizeInternal);
        fft_result_ma.resize(fftSizeInternal);
        fft_result_maa.resize(fftSizeInternal);
        fft_result_temp.resize(fftSizeInternal);
        fft_result_peak.resize(fftSizeInternal);
    }
    
    if (peakReset.load() != 0) {
        peakReset--;
        if (peakReset.load() == 0) {
            for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
                fft_result_peak[i] = fft_floor_maa;
            }
            fft_ceil_peak = fft_floor_maa;
            fft_floor_peak = fft_ceil_maa;
        }
    }
    
    std::vector<liquid_float_complex> *data = &iqData->data;
    
    if (data && data->size()) {
        unsigned int num_written;
        long resampleBw = iqData->sampleRate;
        bool newResampler = false;
        int bwDiff;
        
        if (is_view.load()) {
            if (!iqData->sampleRate) {
                iqData->decRefCount();
               
                return;
            }
            
            while (resampleBw / SPECTRUM_VZM >= bandwidth) {
                resampleBw /= SPECTRUM_VZM;
            }
            
            resamplerRatio = (double) (resampleBw) / (double) iqData->sampleRate;
            
            size_t desired_input_size = fftSizeInternal / resamplerRatio;
            
            this->desiredInputSize.store(desired_input_size);
            
            if (iqData->data.size() < desired_input_size) {
                //                std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
                desired_input_size = iqData->data.size();
            }
            
            if (centerFreq != iqData->frequency) {
                if ((centerFreq - iqData->frequency) != shiftFrequency || lastInputBandwidth != iqData->sampleRate) {
                    if (abs(iqData->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) {
                        long lastShiftFrequency = shiftFrequency;
                        shiftFrequency = centerFreq - iqData->frequency;
                        nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) iqData->sampleRate)));
                        
                        if (is_view.load()) {
                            long freqDiff = shiftFrequency - lastShiftFrequency;
                            
                            if (lastBandwidth!=0) {
                                double binPerHz = double(lastBandwidth) / double(fftSizeInternal);
                                
                                unsigned int numShift = floor(double(abs(freqDiff)) / binPerHz);
                                
                                if (numShift < fftSizeInternal/2 && numShift) {
                                    if (freqDiff > 0) {
                                        memmove(&fft_result_ma[0], &fft_result_ma[numShift], (fftSizeInternal-numShift) * sizeof(double));
                                        memmove(&fft_result_maa[0], &fft_result_maa[numShift], (fftSizeInternal-numShift) * sizeof(double));
//                                        memmove(&fft_result_peak[0], &fft_result_peak[numShift], (fftSizeInternal-numShift) * sizeof(double));
//                                        memset(&fft_result_peak[fftSizeInternal-numShift], 0, numShift * sizeof(double));
                                    } else {
                                        memmove(&fft_result_ma[numShift], &fft_result_ma[0], (fftSizeInternal-numShift) * sizeof(double));
                                        memmove(&fft_result_maa[numShift], &fft_result_maa[0], (fftSizeInternal-numShift) * sizeof(double));
//                                        memmove(&fft_result_peak[numShift], &fft_result_peak[0], (fftSizeInternal-numShift) * sizeof(double));
//                                        memset(&fft_result_peak[0], 0, numShift * sizeof(double));
                                    }
                                }
                            }
                        }
                    }
                    peakReset.store(PEAK_RESET_COUNT);
                }
                
                if (shiftBuffer.size() != desired_input_size) {
                    if (shiftBuffer.capacity() < desired_input_size) {
                        shiftBuffer.reserve(desired_input_size);
                    }
                    shiftBuffer.resize(desired_input_size);
                }
                
                if (shiftFrequency < 0) {
                    nco_crcf_mix_block_up(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
                } else {
                    nco_crcf_mix_block_down(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
                }
            } else {
                shiftBuffer.assign(iqData->data.begin(), iqData->data.begin()+desired_input_size);
            }
            
            if (!resampler || resampleBw != lastBandwidth || lastInputBandwidth != iqData->sampleRate) {
                float As = 60.0f;
                
                if (resampler) {
                    msresamp_crcf_destroy(resampler);
                }
                
                resampler = msresamp_crcf_create(resamplerRatio, As);
                
                bwDiff = resampleBw-lastBandwidth;
                lastBandwidth = resampleBw;
                lastInputBandwidth = iqData->sampleRate;
                newResampler = true;
                peakReset.store(PEAK_RESET_COUNT);
            }
            
            
            unsigned int out_size = ceil((double) (desired_input_size) * resamplerRatio) + 512;
            
            if (resampleBuffer.size() != out_size) {
                if (resampleBuffer.capacity() < out_size) {
                    resampleBuffer.reserve(out_size);
                }
                resampleBuffer.resize(out_size);
            }
            
            msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written);
            
            if (num_written < fftSizeInternal) {
                memcpy(fftInData, resampleBuffer.data(), num_written * sizeof(liquid_float_complex));
                memset(&(fftInData[num_written]), 0, (fftSizeInternal-num_written) * sizeof(liquid_float_complex));
            } else {
                memcpy(fftInData, resampleBuffer.data(), fftSizeInternal * sizeof(liquid_float_complex));
            }
        } else {
            this->desiredInputSize.store(fftSizeInternal);

            num_written = data->size();
            if (data->size() < fftSizeInternal) {
                memcpy(fftInData, data->data(), data->size() * sizeof(liquid_float_complex));
                memset(&fftInData[data->size()], 0, (fftSizeInternal - data->size()) * sizeof(liquid_float_complex));
            } else {
                memcpy(fftInData, data->data(), fftSizeInternal * sizeof(liquid_float_complex));
            }
        }
        
        bool execute = false;

        if (num_written >= fftSizeInternal) {
            execute = true;
            memcpy(fftInput, fftInData, fftSizeInternal * sizeof(liquid_float_complex));
            memcpy(fftLastData, fftInput, fftSizeInternal * sizeof(liquid_float_complex));
            
        } else {
            if (lastDataSize + num_written < fftSizeInternal) { // priming
                unsigned int num_copy = fftSizeInternal - lastDataSize;
                if (num_written > num_copy) {
                    num_copy = num_written;
                }
                memcpy(fftLastData, fftInData, num_copy * sizeof(liquid_float_complex));
                lastDataSize += num_copy;
            } else {
                unsigned int num_last = (fftSizeInternal - num_written);
                memcpy(fftInput, fftLastData + (lastDataSize - num_last), num_last * sizeof(liquid_float_complex));
                memcpy(fftInput + num_last, fftInData, num_written * sizeof(liquid_float_complex));
                memcpy(fftLastData, fftInput, fftSizeInternal * sizeof(liquid_float_complex));
                execute = true;
            }
        }
        
        if (execute) {
            SpectrumVisualData *output = outputBuffers.getBuffer();
            
            if (output->spectrum_points.size() != fftSize * 2) {
                output->spectrum_points.resize(fftSize * 2);
            }
            if (doPeak) {
                if (output->spectrum_hold_points.size() != fftSize * 2) {
                    output->spectrum_hold_points.resize(fftSize * 2);
                }
            } else {
                output->spectrum_hold_points.resize(0);
            }
            
            float fft_ceil = 0, fft_floor = 1;

            fft_execute(fftPlan);
            
            for (int i = 0, iMax = fftSizeInternal / 2; i < iMax; i++) {
                float a = fftOutput[i].real;
                float b = fftOutput[i].imag;
                float c = sqrt(a * a + b * b);
                
                float x = fftOutput[fftSizeInternal / 2 + i].real;
                float y = fftOutput[fftSizeInternal / 2 + i].imag;
                float z = sqrt(x * x + y * y);
                
                fft_result[i] = (z);
                fft_result[fftSizeInternal / 2 + i] = (c);
            }
            
            if (newResampler && lastView) {
                if (bwDiff < 0) {
                    for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
                        fft_result_temp[i] = fft_result_ma[(fftSizeInternal/4) + (i/2)];
                    }
                    for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
                        fft_result_ma[i] = fft_result_temp[i];
                        
                        fft_result_temp[i] = fft_result_maa[(fftSizeInternal/4) + (i/2)];
                    }
                    for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
                        fft_result_maa[i] = fft_result_temp[i];
                    }
                } else {
                    for (size_t i = 0, iMax = fftSizeInternal; i < iMax; i++) {
                        if (i < fftSizeInternal/4) {
                            fft_result_temp[i] = 0; // fft_result_ma[fftSizeInternal/4];
                        } else if (i >= fftSizeInternal - fftSizeInternal/4) {
                            fft_result_temp[i] = 0; // fft_result_ma[fftSizeInternal - fftSizeInternal/4-1];
                        } else {
                            fft_result_temp[i] = fft_result_ma[(i-fftSizeInternal/4)*2];
                        }
                    }
                    for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
                        fft_result_ma[i] = fft_result_temp[i];
                        
                        if (i < fftSizeInternal/4) {
                            fft_result_temp[i] = 0; //fft_result_maa[fftSizeInternal/4];
                        } else if (i >= fftSizeInternal - fftSizeInternal/4) {
                            fft_result_temp[i] = 0; // fft_result_maa[fftSizeInternal - fftSizeInternal/4-1];
                        } else {
                            fft_result_temp[i] = fft_result_maa[(i-fftSizeInternal/4)*2];
                        }
                    }
                    for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
                        fft_result_maa[i] = fft_result_temp[i];
                    }
                }
            }
            
            for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
                if (fft_result_maa[i] != fft_result_maa[i]) fft_result_maa[i] = fft_result[i];
                fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
                if (fft_result_ma[i] != fft_result_ma[i]) fft_result_ma[i] = fft_result[i];
                fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
                
                if (fft_result_maa[i] > fft_ceil || fft_ceil != fft_ceil) {
                    fft_ceil = fft_result_maa[i];
                }
                if (fft_result_maa[i] < fft_floor || fft_floor != fft_floor) {
                    fft_floor = fft_result_maa[i];
                }
                if (doPeak) {
                    if (fft_result_maa[i] > fft_result_peak[i]) {
                        fft_result_peak[i] = fft_result_maa[i];
                    }
                }
            }
            
            if (fft_ceil_ma != fft_ceil_ma) fft_ceil_ma = fft_ceil;
            fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05;
            if (fft_ceil_maa != fft_ceil_maa) fft_ceil_maa = fft_ceil;
            fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05;
            
            if (fft_floor_ma != fft_floor_ma) fft_floor_ma = fft_floor;
            fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05;
            if (fft_floor_maa != fft_floor_maa) fft_floor_maa = fft_floor;
            fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05;

            if (doPeak) {
                if (fft_ceil_maa > fft_ceil_peak) {
                    fft_ceil_peak = fft_ceil_maa;
                }
                if (fft_floor_maa < fft_floor_peak) {
                    fft_floor_peak = fft_floor_maa;
                }
            }
            
            float sf = scaleFactor.load();
 
            double visualRatio = (double(bandwidth) / double(resampleBw));
            double visualStart = (double(fftSizeInternal) / 2.0) - (double(fftSizeInternal) * (visualRatio / 2.0));
            double visualAccum = 0;
            double peak_acc = 0, acc = 0, accCount = 0, i = 0;
   
            double point_ceil = doPeak?fft_ceil_peak:fft_ceil_maa;
            double point_floor = doPeak?fft_floor_peak:fft_floor_maa;
            
            for (int x = 0, xMax = output->spectrum_points.size() / 2; x < xMax; x++) {
                visualAccum += visualRatio * double(SPECTRUM_VZM);

                while (visualAccum >= 1.0) {
                    unsigned int idx = round(visualStart+i);
                    if (idx > 0 && idx < fftSizeInternal) {
                        acc += fft_result_maa[idx];
                        if (doPeak) {
                            peak_acc += fft_result_peak[idx];
                        }
                    } else {
                        acc += fft_floor_maa;
                        if (doPeak) {
                            peak_acc += fft_floor_maa;
                        }
                    }
                    accCount += 1.0;
                    visualAccum -= 1.0;
                    i++;
                }

                output->spectrum_points[x * 2] = ((float) x / (float) xMax);
                if (doPeak) {
                    output->spectrum_hold_points[x * 2] = ((float) x / (float) xMax);
                }
                if (accCount) {
                    output->spectrum_points[x * 2 + 1] = ((log10((acc/accCount)+0.25 - (point_floor-0.75)) / log10((point_ceil+0.25) - (point_floor-0.75))))*sf;
                    acc = 0.0;
                    if (doPeak) {
                        output->spectrum_hold_points[x * 2 + 1] = ((log10((peak_acc/accCount)+0.25 - (point_floor-0.75)) / log10((point_ceil+0.25) - (point_floor-0.75))))*sf;
                        peak_acc = 0.0;
                    }
                    accCount = 0.0;
                }
            }
            
            if (hideDC.load()) { // DC-spike removal
                long long freqMin = centerFreq-(bandwidth/2);
                long long freqMax = centerFreq+(bandwidth/2);
                long long zeroPt = (iqData->frequency-freqMin);
                
                if (freqMin < iqData->frequency && freqMax > iqData->frequency) {
                    int freqRange = int(freqMax-freqMin);
                    int freqStep = freqRange/fftSize;
                    int fftStart = (zeroPt/freqStep)-(2000/freqStep);
                    int fftEnd = (zeroPt/freqStep)+(2000/freqStep);
                    
//                    std::cout << "range:" << freqRange << ", step: " << freqStep << ", start: " << fftStart << ", end: " << fftEnd << std::endl;
                    
                    if (fftEnd-fftStart < 2) {
                        fftEnd++;
                        fftStart--;
                    }
                    
                    int numSteps = (fftEnd-fftStart);
                    int halfWay = fftStart+(numSteps/2);

                    if ((fftEnd+numSteps/2+1 < (long long) fftSize) && (fftStart-numSteps/2-1 >= 0) && (fftEnd > fftStart)) {
                        int n = 1;
                        for (int i = fftStart; i < halfWay; i++) {
                            output->spectrum_points[i * 2 + 1] = output->spectrum_points[(fftStart - n) * 2 + 1];
                            n++;
                        }
                        n = 1;
                        for (int i = halfWay; i < fftEnd; i++) {
                            output->spectrum_points[i * 2 + 1] = output->spectrum_points[(fftEnd + n) * 2 + 1];
                            n++;
                        }
                        if (doPeak) {
                            int n = 1;
                            for (int i = fftStart; i < halfWay; i++) {
                                output->spectrum_hold_points[i * 2 + 1] = output->spectrum_hold_points[(fftStart - n) * 2 + 1];
                                n++;
                            }
                            n = 1;
                            for (int i = halfWay; i < fftEnd; i++) {
                                output->spectrum_hold_points[i * 2 + 1] = output->spectrum_hold_points[(fftEnd + n) * 2 + 1];
                                n++;
                            }
                        }
                    }
                }
            }
            
            output->fft_ceiling = point_ceil/sf;
            output->fft_floor = point_floor;

            output->centerFreq = centerFreq;
            output->bandwidth = bandwidth;

            distribute(output);
        }
    }
 
    iqData->decRefCount();
   
    
    lastView = is_view.load();
}
void SpectrumVisualProcessor::process() {
    if (!isOutputEmpty()) {
        return;
    }
    if (!input || input->empty()) {
        return;
    }
    
    DemodulatorThreadIQData *iqData;
    
    input->pop(iqData);
    
    if (!iqData) {
        return;
    }
    
    iqData->busy_rw.lock();
    busy_run.lock();
    
    std::vector<liquid_float_complex> *data = &iqData->data;
    
    if (data && data->size()) {
        SpectrumVisualData *output = outputBuffers.getBuffer();
        
        if (output->spectrum_points.size() < fftSize * 2) {
            output->spectrum_points.resize(fftSize * 2);
        }
        
        unsigned int num_written;
        
        if (is_view.load()) {
            if (!iqData->frequency || !iqData->sampleRate) {
                iqData->decRefCount();
                iqData->busy_rw.unlock();
                busy_run.unlock();
                return;
            }
            
            resamplerRatio = (double) (bandwidth) / (double) iqData->sampleRate;
            
            int desired_input_size = fftSize / resamplerRatio;
            
            this->desiredInputSize.store(desired_input_size);
            
            if (iqData->data.size() < desired_input_size) {
                //                std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
                desired_input_size = iqData->data.size();
            }
            
            if (centerFreq != iqData->frequency) {
                if ((centerFreq - iqData->frequency) != shiftFrequency || lastInputBandwidth != iqData->sampleRate) {
                    if (abs(iqData->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) {
                        shiftFrequency = centerFreq - iqData->frequency;
                        nco_crcf_reset(freqShifter);
                        nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) iqData->sampleRate)));
                    }
                }
                
                if (shiftBuffer.size() != desired_input_size) {
                    if (shiftBuffer.capacity() < desired_input_size) {
                        shiftBuffer.reserve(desired_input_size);
                    }
                    shiftBuffer.resize(desired_input_size);
                }
                
                if (shiftFrequency < 0) {
                    nco_crcf_mix_block_up(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
                } else {
                    nco_crcf_mix_block_down(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
                }
            } else {
                shiftBuffer.assign(iqData->data.begin(), iqData->data.end());
            }
            
            if (!resampler || bandwidth != lastBandwidth || lastInputBandwidth != iqData->sampleRate) {
                float As = 60.0f;
                
                if (resampler) {
                    msresamp_crcf_destroy(resampler);
                }
                resampler = msresamp_crcf_create(resamplerRatio, As);
                
                lastBandwidth = bandwidth;
                lastInputBandwidth = iqData->sampleRate;
            }
            
            
            int out_size = ceil((double) (desired_input_size) * resamplerRatio) + 512;
            
            if (resampleBuffer.size() != out_size) {
                if (resampleBuffer.capacity() < out_size) {
                    resampleBuffer.reserve(out_size);
                }
                resampleBuffer.resize(out_size);
            }
            
            
            msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written);
            
            resampleBuffer.resize(fftSize);
            
            if (num_written < fftSize) {
                for (int i = 0; i < num_written; i++) {
                    fftInData[i][0] = resampleBuffer[i].real;
                    fftInData[i][1] = resampleBuffer[i].imag;
                }
                for (int i = num_written; i < fftSize; i++) {
                    fftInData[i][0] = 0;
                    fftInData[i][1] = 0;
                }
            } else {
                for (int i = 0; i < fftSize; i++) {
                    fftInData[i][0] = resampleBuffer[i].real;
                    fftInData[i][1] = resampleBuffer[i].imag;
                }
            }
        } else {
            num_written = data->size();
            if (data->size() < fftSize) {
                for (int i = 0, iMax = data->size(); i < iMax; i++) {
                    fftInData[i][0] = (*data)[i].real;
                    fftInData[i][1] = (*data)[i].imag;
                }
                for (int i = data->size(); i < fftSize; i++) {
                    fftInData[i][0] = 0;
                    fftInData[i][1] = 0;
                }
            } else {
                for (int i = 0; i < fftSize; i++) {
                    fftInData[i][0] = (*data)[i].real;
                    fftInData[i][1] = (*data)[i].imag;
                }
            }
        }
        
        bool execute = false;
        
        if (num_written >= fftSize) {
            execute = true;
            memcpy(fftwInput, fftInData, fftSize * sizeof(fftwf_complex));
            memcpy(fftLastData, fftwInput, fftSize * sizeof(fftwf_complex));
            
        } else {
            if (lastDataSize + num_written < fftSize) { // priming
                unsigned int num_copy = fftSize - lastDataSize;
                if (num_written > num_copy) {
                    num_copy = num_written;
                }
                memcpy(fftLastData, fftInData, num_copy * sizeof(fftwf_complex));
                lastDataSize += num_copy;
            } else {
                unsigned int num_last = (fftSize - num_written);
                memcpy(fftwInput, fftLastData + (lastDataSize - num_last), num_last * sizeof(fftwf_complex));
                memcpy(fftwInput + num_last, fftInData, num_written * sizeof(fftwf_complex));
                memcpy(fftLastData, fftwInput, fftSize * sizeof(fftwf_complex));
                execute = true;
            }
        }
        
        if (execute) {
            fftwf_execute(fftw_plan);
            
            float fft_ceil = 0, fft_floor = 1;
            
            if (fft_result.size() < fftSize) {
                fft_result.resize(fftSize);
                fft_result_ma.resize(fftSize);
                fft_result_maa.resize(fftSize);
            }
            
            for (int i = 0, iMax = fftSize / 2; i < iMax; i++) {
                float a = fftwOutput[i][0];
                float b = fftwOutput[i][1];
                float c = sqrt(a * a + b * b);
                
                float x = fftwOutput[fftSize / 2 + i][0];
                float y = fftwOutput[fftSize / 2 + i][1];
                float z = sqrt(x * x + y * y);
                
                fft_result[i] = (z);
                fft_result[fftSize / 2 + i] = (c);
            }
            
            for (int i = 0, iMax = fftSize; i < iMax; i++) {
                if (is_view.load()) {
                    fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
                    fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
                } else {
                    fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
                    fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
                }
                
                if (fft_result_maa[i] > fft_ceil) {
                    fft_ceil = fft_result_maa[i];
                }
                if (fft_result_maa[i] < fft_floor) {
                    fft_floor = fft_result_maa[i];
                }
            }
            
            fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05;
            fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05;
            
            fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05;
            fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05;
            
            float sf = scaleFactor.load();
            
            for (int i = 0, iMax = fftSize; i < iMax; i++) {
                float v = (log10(fft_result_maa[i]+0.25 - (fft_floor_maa-0.75)) / log10((fft_ceil_maa+0.25) - (fft_floor_maa-0.75)));
                output->spectrum_points[i * 2] = ((float) i / (float) iMax);
                output->spectrum_points[i * 2 + 1] = v*sf;
            }
                
            if (hideDC.load()) { // DC-spike removal
                long long freqMin = centerFreq-(bandwidth/2);
                long long freqMax = centerFreq+(bandwidth/2);
                long long zeroPt = (iqData->frequency-freqMin);
                
                if (freqMin < iqData->frequency && freqMax > iqData->frequency) {
                    int freqRange = int(freqMax-freqMin);
                    int freqStep = freqRange/fftSize;
                    int fftStart = (zeroPt/freqStep)-(2000/freqStep);
                    int fftEnd = (zeroPt/freqStep)+(2000/freqStep);
                    
//                    std::cout << "range:" << freqRange << ", step: " << freqStep << ", start: " << fftStart << ", end: " << fftEnd << std::endl;
                    
                    if (fftEnd-fftStart < 2) {
                        fftEnd++;
                        fftStart--;
                    }
                    
                    int numSteps = (fftEnd-fftStart);
                    int halfWay = fftStart+(numSteps/2);

                    if ((fftEnd+numSteps/2+1 < fftSize) && (fftStart-numSteps/2-1 >= 0) && (fftEnd > fftStart)) {
                        int n = 1;
                        for (int i = fftStart; i < halfWay; i++) {
                            output->spectrum_points[i * 2 + 1] = output->spectrum_points[(fftStart - n) * 2 + 1];
                            n++;
                        }
                        n = 1;
                        for (int i = halfWay; i < fftEnd; i++) {
                            output->spectrum_points[i * 2 + 1] = output->spectrum_points[(fftEnd + n) * 2 + 1];
                            n++;
                        }
                    }
                }
            }
            
            output->fft_ceiling = fft_ceil_maa/sf;
            output->fft_floor = fft_floor_maa;
        }
        
        distribute(output);
    }
 
    iqData->decRefCount();
    iqData->busy_rw.unlock();
    busy_run.unlock();
}