b27718bd760e538d4d22a12ada7ab63cfa5cf39f
[debian/gnuradio] / gr-qtgui / src / lib / qtgui_sink_f.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2008 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <qtgui_sink_f.h>
28 #include <gr_io_signature.h>
29 #include <string.h>
30
31 #include <QTimer>
32
33 qtgui_sink_f_sptr
34 qtgui_make_sink_f (int fftsize, const std::vector<float> &window,
35                    float fmin, float fmax, const std::string &name)
36 {
37   return qtgui_sink_f_sptr (new qtgui_sink_f (fftsize, window, fmin, fmax, name));
38 }
39
40 qtgui_sink_f::qtgui_sink_f (int fftsize, const std::vector<float> &window,
41                             float fmin, float fmax, const std::string &name)
42   : gr_block ("sink_f",
43               gr_make_io_signature (1, 1, sizeof(float)),
44               gr_make_io_signature (0, 0, 0)),
45     d_fftsize(fftsize), d_window(window), 
46     d_fmin(fmin), d_fmax(fmax), d_name(name)
47 {
48   d_main_gui = NULL;
49   pthread_mutex_init(&d_pmutex, NULL);
50   lock();
51
52   d_shift = true;  // Perform fftshift operation; this is usually desired when plotting
53
54   d_fft = new gri_fft_complex (d_fftsize, true);
55
56   fftdata = new gr_complex[d_fftsize];
57
58   d_index = 0;
59   d_residbuf = new float[d_fftsize];
60 }
61
62 qtgui_sink_f::~qtgui_sink_f()
63 {
64   delete [] fftdata;
65   delete [] d_residbuf;
66   delete d_main_gui;
67   delete d_fft;
68 }
69
70 void qtgui_sink_f::lock()
71 {
72   pthread_mutex_lock(&d_pmutex);
73 }
74
75 void qtgui_sink_f::unlock()
76 {
77   pthread_mutex_unlock(&d_pmutex);
78 }
79
80 void
81 qtgui_sink_f::start_app()
82 {
83   d_qApplication = new QApplication(0, NULL);
84
85   uint64_t maxBufferSize = 32768;
86   d_main_gui = new SpectrumGUIClass(maxBufferSize, d_fftsize, d_fmin, d_fmax);
87   d_main_gui->SetDisplayTitle(d_name);
88   d_main_gui->OpenSpectrumWindow(NULL);
89
90   qtgui_obj object(d_qApplication);
91   qApp->postEvent(&object, new qtgui_event(&d_pmutex));
92
93   d_qApplication->exec();
94 }
95
96
97 void
98 qtgui_sink_f::fft(const float *data_in, int size, gr_complex *data_out)
99 {
100   if (d_window.size()) {
101     gr_complex *dst = d_fft->get_inbuf();
102     for (int i = 0; i < size; i++)              // apply window
103       dst[i] = data_in[i] * d_window[i];
104   }
105   else {
106       gr_complex *dst = d_fft->get_inbuf();
107       for (unsigned int i = 0; i < size; i++)           // float to complex conversion
108         dst[i] = data_in[i];
109   }
110   
111   d_fft->execute ();     // compute the fft
112
113   for(int i=0; i < size; i++) {
114     d_fft->get_outbuf()[i] /= size;
115   }
116
117   // copy result to our output
118   if(d_shift) {  // apply a fft shift on the data
119     unsigned int len = (unsigned int)(ceil(size/2.0));
120     memcpy(&data_out[0], &d_fft->get_outbuf()[len], sizeof(gr_complex)*(size - len));
121     memcpy(&data_out[size - len], &d_fft->get_outbuf()[0], sizeof(gr_complex)*len);
122   }
123   else {
124     memcpy(data_out, d_fft->get_outbuf(), sizeof(gr_complex)*size);
125   }
126 }
127
128
129 int
130 qtgui_sink_f::general_work (int noutput_items,
131                             gr_vector_int &ninput_items,
132                             gr_vector_const_void_star &input_items,
133                             gr_vector_void_star &output_items)
134 {
135   int i=0, j=0;
136   const float *in = (const float*)input_items[0];
137
138   pthread_mutex_lock(&d_pmutex);
139
140   if(d_index) {
141     int filler = std::min(d_fftsize - d_index, noutput_items);
142     memcpy(&d_residbuf[d_index], &in[0], sizeof(float)*filler);
143     d_index += filler;
144     i = filler;
145     j = filler;
146   }
147
148   if(d_index == d_fftsize) {
149     d_index = 0;
150     fft(d_residbuf, d_fftsize, fftdata);
151     
152     d_main_gui->UpdateWindow(true, fftdata, d_fftsize, d_residbuf, d_fftsize, NULL, 0,
153                              1.0/4.0, convert_to_timespec(0.0), true);
154   }
155   
156   for(; i < noutput_items; i+=d_fftsize) {
157     if(noutput_items - i > d_fftsize) {
158       j += d_fftsize;
159       fft(&in[i], d_fftsize, fftdata);
160       
161       d_main_gui->UpdateWindow(true, fftdata, d_fftsize, &in[i], d_fftsize, NULL, 0,
162                                1.0/4.0, convert_to_timespec(0.0), true);
163     }
164   }
165
166   if(noutput_items > j) {
167     d_index = noutput_items - j;
168     memcpy(d_residbuf, &in[j], sizeof(float)*d_index);
169   }
170
171   pthread_mutex_unlock(&d_pmutex);
172
173   consume_each(noutput_items);
174   return noutput_items;
175 }