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