1 /*-
2  * Copyright (c) 2016-2021 Hans Petter Selasky. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #ifndef _QAUDIOSONAR_H_
27 #define	_QAUDIOSONAR_H_
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <err.h>
36 #include <math.h>
37 #include <pthread.h>
38 #include <sysexits.h>
39 #include <signal.h>
40 
41 #include <sys/ioctl.h>
42 #include <sys/filio.h>
43 #include <sys/queue.h>
44 
45 #include <portaudio.h>
46 
47 #include <QApplication>
48 #include <QPushButton>
49 #include <QLineEdit>
50 #include <QGridLayout>
51 #include <QLabel>
52 #include <QWidget>
53 #include <QPainter>
54 #include <QColor>
55 #include <QTimer>
56 #include <QScrollBar>
57 #include <QSpinBox>
58 #include <QMouseEvent>
59 #include <QPlainTextEdit>
60 #include <QGroupBox>
61 #include <QImage>
62 #include <QSlider>
63 
64 #define	QAS_WINDOW_TITLE	"Quick Audio Sonar v1.7.4"
65 #define	QAS_WINDOW_ICON		":/qaudiosonar.png"
66 
67 #define	QAS_SAMPLES_MAX	48000
68 #define	QAS_MIDI_BUFSIZE 1024
69 #define	QAS_MUL_ORDER	10
70 #define	QAS_MUL_SIZE	(1U << QAS_MUL_ORDER) /* samples */
71 #define	QAS_BUFFER_SIZE ((QAS_SAMPLES_MAX / 8) - ((QAS_SAMPLES_MAX / 8) % QAS_MUL_SIZE)) /* samples */
72 #define	QAS_DSP_SIZE	((QAS_SAMPLES_MAX / 16) - ((QAS_SAMPLES_MAX / 16) % QAS_MUL_SIZE)) /* samples */
73 #define	QAS_WAVE_STEP (1U << QAS_WAVE_STEP_LOG2)
74 #define	QAS_WAVE_STEP_LOG2 8
75 
76 #define	QAS_FREQ_TABLE_ROUNDED(band) \
77     ((double)(((int64_t)(1000.0 * qas_freq_table[band])) / 1000.0))
78 
79 #if (QAS_DSP_SIZE == 0 || QAS_BUFFER_SIZE == 0)
80 #error "Invalid parameters"
81 #endif
82 
83 class QasBandPassBox : public QGroupBox {
84 	Q_OBJECT;
85 public:
86 	QasBandPassBox();
~QasBandPassBox()87 	~QasBandPassBox() {};
88 
89 	QScrollBar *pSB;
90 	QGridLayout *grid;
91 
92 signals:
93 	void valueChanged(int);
94 
95 public slots:
96 	void handle_value_changed(int);
97 };
98 
99 class QasBandWidthBox : public QGroupBox {
100 	Q_OBJECT;
101 public:
102 	QasBandWidthBox();
~QasBandWidthBox()103 	~QasBandWidthBox() {};
104 
105 	QScrollBar *pSB;
106 	QGridLayout *grid;
107 
108 signals:
109 	void valueChanged(int);
110 
111 public slots:
112 	void handle_value_changed(int);
113 };
114 
115 class QasNoiselevelBox : public QGroupBox {
116 	Q_OBJECT;
117 public:
118 	QasNoiselevelBox();
~QasNoiselevelBox()119 	~QasNoiselevelBox() {};
120 
121 	QScrollBar *pSB;
122 	QGridLayout *grid;
123 
124 signals:
125 	void valueChanged(int);
126 
127 public slots:
128 	void handle_value_changed(int);
129 };
130 
131 class QasMainWindow;
132 class QasButtonMap;
133 class QasConfig : public QWidget {
134 	Q_OBJECT
135 public:
136 	QasConfig(QasMainWindow *);
~QasConfig()137 	~QasConfig() { };
138 
139 	QasMainWindow *mw;
140 
141 	QGridLayout *gl;
142 
143 	QasButtonMap *map_source_0;
144 	QasButtonMap *map_source_1;
145 	QasButtonMap *map_output_0;
146 	QasButtonMap *map_output_1;
147 	QasBandPassBox *bp_box_0;
148 	QasBandWidthBox *bw_box_0;
149 	QasNoiselevelBox *nl_box_0;
150 	QPushButton *bp_close;
151 
152 public slots:
153 	void handle_source_0(int);
154 	void handle_source_1(int);
155 	void handle_output_0(int);
156 	void handle_output_1(int);
157 	void handle_filter_0(int);
158 	void handle_close(void);
159 };
160 
161 class QasView : public QWidget {
162 	Q_OBJECT
163 public:
164 	QasView(QasMainWindow *);
~QasView()165 	~QasView() { };
166 
167 	QasMainWindow *mw;
168 
169 	QGridLayout *gl;
170 
171 	QasButtonMap *map_decay_0;
172 	QPushButton *bp_close;
173 
174 public slots:
175 	void handle_decay_0(int);
176 	void handle_close();
177 };
178 
179 class QasBand : public QWidget {
180 	Q_OBJECT
181 public:
182 	enum { BAND_MAX = 12 };
183 	QasBand(QasMainWindow *);
~QasBand()184 	~QasBand() { };
185 	QasMainWindow *mw;
186 	QTimer *watchdog;
187 
188 	QString getText(QMouseEvent *);
189 	QString getFullText(int);
190 
191 	void paintEvent(QPaintEvent *);
192 	void mousePressEvent(QMouseEvent *);
193 	void mouseMoveEvent(QMouseEvent *);
194 
195 public slots:
196 	void handle_watchdog();
197 };
198 
199 class QasGraph : public QWidget {
200 	Q_OBJECT
201 public:
202 	QasGraph(QasMainWindow *);
203 	~QasGraph();
204 	QasMainWindow *mw;
205 	QTimer *watchdog;
206 	double *mon_index;
207 
208 	QString getText(QMouseEvent *);
209 
210 	void paintEvent(QPaintEvent *);
211 	void mousePressEvent(QMouseEvent *);
212 	void mouseMoveEvent(QMouseEvent *);
213 
214 public slots:
215 	void handle_watchdog();
216 };
217 
218 class QasMainWindow : public QWidget {
219 	Q_OBJECT
220 public:
221 	QasMainWindow();
~QasMainWindow()222 	~QasMainWindow() { };
223 
paName(PaDeviceIndex index)224 	QString paName(PaDeviceIndex index) {
225 		return QString("PortAudio #%1").arg(index);
226 	};
227 
closeEvent(QCloseEvent * event)228 	void closeEvent (QCloseEvent *event) {
229 		QCoreApplication::exit();
230 	};
231 
232 	QasConfig *qc;
233 	QasView *qv;
234 	QGridLayout *gl;
235 	QGridLayout *glb;
236 	QScrollBar *sb_zoom;
237 	QLabel *lbl_max;
238 	QWidget *qbw;
239 	QasBand *qb;
240 	QasGraph *qg;
241 	QLineEdit *led_dsp_read;
242 	QLineEdit *led_dsp_write;
243 	QLineEdit *led_midi_write;
244 	QPlainTextEdit *edit;
245 	QSpinBox *tuning;
246 	QSlider *sensitivity;
247 	QPushButton *but_dsp_rx;
248 	QPushButton *but_dsp_tx;
249 	QPushButton *but_midi_tx;
250 
251 	PaDeviceIndex pa_max_index;
252 signals:
253 	void handle_append_text(const QString);
254 
255 public slots:
256 	void handle_apply();
257 	void handle_reset();
258 	void handle_tog_freeze();
259 	void handle_tog_record();
260 	void handle_slider(int);
261 	void handle_config();
262 	void handle_view();
263 	void handle_tuning();
264 	void handle_sensitivity();
265 	void handle_dsp_rx();
266 	void handle_dsp_tx();
267 };
268 
269 /* ============== GENERIC SUPPORT ============== */
270 
271 extern int qas_num_workers;
272 extern size_t qas_in_sequence_number;
273 extern size_t qas_out_sequence_number;
274 extern size_t qas_window_size;
275 extern int qas_sample_rate;
276 extern int qas_source_0;
277 extern int qas_source_1;
278 extern int qas_output_0;
279 extern int qas_output_1;
280 extern int qas_freeze;
281 extern int qas_record;
282 extern int qas_sensitivity;
283 extern double qas_view_decay;
284 extern QasMainWindow *qas_mw;
285 extern double qas_low_octave;
286 extern const double qas_base_freq;
287 extern size_t qas_mon_size;
288 
289 void atomic_lock();
290 void atomic_unlock();
291 void atomic_graph_lock();
292 void atomic_graph_unlock();
293 void atomic_wait();
294 void atomic_wakeup();
295 
296 /* ============== MULTIPLY SUPPORT ============== */
297 
298 void qas_x3_multiply_double(double *, double *, double *, const size_t);
299 
300 /* ============== WAVE SUPPORT ============== */
301 
302 extern double qas_tuning;
303 extern double *qas_freq_table;
304 extern uint8_t *qas_iso_table;
305 extern size_t qas_num_bands;
306 extern QString *qas_descr_table;
307 
308 struct qas_wave_job {
309 	TAILQ_ENTRY(qas_wave_job) entry;
310 	size_t band_start;
311 	struct qas_corr_data *data;
312 };
313 
314 extern struct qas_wave_job *qas_wave_job_alloc();
315 extern void qas_wave_job_insert(struct qas_wave_job *);
316 extern struct qas_wave_job *qas_wave_job_dequeue();
317 extern void qas_wave_job_free(qas_wave_job *);
318 extern void qas_wave_signal();
319 extern void qas_wave_wait();
320 extern void qas_wave_lock();
321 extern void qas_wave_unlock();
322 extern void qas_wave_init();
323 
324 /* ============== CORRELATION SUPPORT ============== */
325 
326 #define	QAS_CORR_SIZE QAS_MUL_SIZE
327 
328 struct qas_corr_data {
329 	TAILQ_ENTRY(qas_corr_data) entry;
330 	size_t sequence_number;
331 	size_t refcount;
332 	size_t state;
333 #define	QAS_STATE_1ST_SCAN 0
334 #define	QAS_STATE_2ND_SCAN 1
335 	double *monitor_data;
336 	double *input_data;
337 	double *corr_data;
338 	double *band_data;
339 	double internal_data[];
340 };
341 
342 extern double *qas_mon_decay;
343 extern struct qas_corr_data *qas_corr_alloc(void);
344 extern void qas_corr_free(struct qas_corr_data *);
345 extern void qas_corr_insert(struct qas_corr_data *);
346 extern struct qas_corr_data *qas_corr_job_dequeue();
347 extern void qas_corr_signal();
348 extern void qas_corr_wait();
349 extern void qas_corr_lock();
350 extern void qas_corr_unlock();
351 extern void qas_corr_init();
352 
353 /* ============== DISPLAY SUPPORT ============== */
354 
355 extern double *qas_display_data;
356 extern double *qas_display_band;
357 extern size_t qas_display_hist_max;	/* power of two */
358 
359 extern void qas_display_job_insert(struct qas_wave_job *);
360 extern struct qas_wave_job *qas_display_job_dequeue();
361 extern void qas_display_signal();
362 extern void qas_display_wait();
363 extern void qas_display_lock();
364 extern void qas_display_unlock();
365 extern void qas_display_init();
366 extern double *qas_display_get_line(size_t);
367 extern size_t qas_display_width();
368 extern double *qas_display_get_band(size_t);
369 extern size_t qas_display_band_width();
370 extern size_t qas_display_height();
371 extern size_t qas_display_lag();
372 
373 /* ============== ISO SUPPORT ============== */
374 
375 #define	QAS_STANDARD_AUDIO_BANDS 31
376 
377 extern const double qas_iso_freq_table[QAS_STANDARD_AUDIO_BANDS];
378 extern uint8_t qas_find_iso(double cf);
379 
380 /* ============== OSS DSP SUPPORT ============== */
381 
382 struct dsp_buffer {
383 	double buffer[QAS_BUFFER_SIZE];
384 	unsigned in_off;
385 	unsigned mon_off;
386 	unsigned out_off;
387 };
388 
389 extern PaDeviceIndex qas_rx_device;
390 extern PaDeviceIndex qas_tx_device;
391 extern double qas_band_pass_filter[QAS_CORR_SIZE];
392 
393 extern void qas_dsp_init();
394 extern void dsp_put_sample(struct dsp_buffer *, double);
395 extern double dsp_get_sample(struct dsp_buffer *);
396 extern double dsp_get_monitor_sample(struct dsp_buffer *);
397 extern unsigned dsp_write_space(struct dsp_buffer *);
398 extern unsigned dsp_read_space(struct dsp_buffer *);
399 extern unsigned dsp_monitor_space(struct dsp_buffer *);
400 extern void qas_dsp_sync(void);
401 
402 /* ============== MIDI SUPPORT ============== */
403 
404 extern char midi_write_device[1024];
405 extern double qas_noise_level;
406 
407 extern void qas_midi_init();
408 extern void qas_midi_key_send(uint8_t, uint8_t, uint8_t, uint8_t);
409 extern void qas_midi_delay_send(uint8_t);
410 
411 /* ============== FTT SUPPORT ============== */
412 
413 extern double qas_ftt_cos(double);
414 extern double qas_ftt_sin(double);
415 
416 #endif			/* _QAUDIOSONAR_H_ */
417