Collection of tools useful for audio production
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

937 lines
27KB

  1. /*
  2. * Simple JACK Audio Meter
  3. * Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the COPYING file
  16. */
  17. #include <QtCore/Qt>
  18. #ifndef Q_COMPILER_LAMBDA
  19. # define nullptr (0)
  20. #endif
  21. #define VERSION "0.5.0"
  22. //#include "../jack_utils.h"
  23. #include "ui_xycontroller.h"
  24. //#include <QtCore/QMutex>
  25. #include <QtCore/QSettings>
  26. #include <QtCore/QTimer>
  27. #include <QtGui/QApplication>
  28. #include <QtGui/QGraphicsItem>
  29. #include <QtGui/QGraphicsScene>
  30. #include <QtGui/QGraphicsSceneEvent>
  31. #include <QtGui/QKeyEvent>
  32. #include <QtGui/QMainWindow>
  33. #include <QtGui/QMessageBox>
  34. // -------------------------------
  35. class Queue {
  36. public:
  37. Queue(int size_) :
  38. size(size_)
  39. {
  40. }
  41. ~Queue()
  42. {
  43. }
  44. void put_nowait(int, int, int)
  45. {
  46. //const QMutexLocker m(&mutex);
  47. }
  48. private:
  49. const int size;
  50. //QMutex mutex;
  51. };
  52. qreal abs_q(const qreal value)
  53. {
  54. if (value < 1.0)
  55. return -value;
  56. return value;
  57. }
  58. #if 0
  59. jack_client_t* jack_client = nullptr;
  60. jack_port_t* jack_midi_in_port = nullptr;
  61. jack_port_t* jack_midi_out_port = nullptr;
  62. #endif
  63. Queue jack_midi_in_data = Queue(512);
  64. Queue jack_midi_out_data = Queue(512);
  65. QVector<QString> MIDI_CC_LIST;
  66. void MIDI_CC_LIST__init()
  67. {
  68. //MIDI_CC_LIST << "0x00 Bank Select";
  69. MIDI_CC_LIST << "0x01 Modulation";
  70. MIDI_CC_LIST << "0x02 Breath";
  71. MIDI_CC_LIST << "0x03 (Undefined)";
  72. MIDI_CC_LIST << "0x04 Foot";
  73. MIDI_CC_LIST << "0x05 Portamento";
  74. //MIDI_CC_LIST << "0x06 (Data Entry MSB)";
  75. MIDI_CC_LIST << "0x07 Volume";
  76. MIDI_CC_LIST << "0x08 Balance";
  77. MIDI_CC_LIST << "0x09 (Undefined)";
  78. MIDI_CC_LIST << "0x0A Pan";
  79. MIDI_CC_LIST << "0x0B Expression";
  80. MIDI_CC_LIST << "0x0C FX Control 1";
  81. MIDI_CC_LIST << "0x0D FX Control 2";
  82. MIDI_CC_LIST << "0x0E (Undefined)";
  83. MIDI_CC_LIST << "0x0F (Undefined)";
  84. MIDI_CC_LIST << "0x10 General Purpose 1";
  85. MIDI_CC_LIST << "0x11 General Purpose 2";
  86. MIDI_CC_LIST << "0x12 General Purpose 3";
  87. MIDI_CC_LIST << "0x13 General Purpose 4";
  88. MIDI_CC_LIST << "0x14 (Undefined)";
  89. MIDI_CC_LIST << "0x15 (Undefined)";
  90. MIDI_CC_LIST << "0x16 (Undefined)";
  91. MIDI_CC_LIST << "0x17 (Undefined)";
  92. MIDI_CC_LIST << "0x18 (Undefined)";
  93. MIDI_CC_LIST << "0x19 (Undefined)";
  94. MIDI_CC_LIST << "0x1A (Undefined)";
  95. MIDI_CC_LIST << "0x1B (Undefined)";
  96. MIDI_CC_LIST << "0x1C (Undefined)";
  97. MIDI_CC_LIST << "0x1D (Undefined)";
  98. MIDI_CC_LIST << "0x1E (Undefined)";
  99. MIDI_CC_LIST << "0x1F (Undefined)";
  100. //MIDI_CC_LIST << "0x20 *Bank Select";
  101. //MIDI_CC_LIST << "0x21 *Modulation";
  102. //MIDI_CC_LIST << "0x22 *Breath";
  103. //MIDI_CC_LIST << "0x23 *(Undefined)";
  104. //MIDI_CC_LIST << "0x24 *Foot";
  105. //MIDI_CC_LIST << "0x25 *Portamento";
  106. //MIDI_CC_LIST << "0x26 *(Data Entry MSB)";
  107. //MIDI_CC_LIST << "0x27 *Volume";
  108. //MIDI_CC_LIST << "0x28 *Balance";
  109. //MIDI_CC_LIST << "0x29 *(Undefined)";
  110. //MIDI_CC_LIST << "0x2A *Pan";
  111. //MIDI_CC_LIST << "0x2B *Expression";
  112. //MIDI_CC_LIST << "0x2C *FX *Control 1";
  113. //MIDI_CC_LIST << "0x2D *FX *Control 2";
  114. //MIDI_CC_LIST << "0x2E *(Undefined)";
  115. //MIDI_CC_LIST << "0x2F *(Undefined)";
  116. //MIDI_CC_LIST << "0x30 *General Purpose 1";
  117. //MIDI_CC_LIST << "0x31 *General Purpose 2";
  118. //MIDI_CC_LIST << "0x32 *General Purpose 3";
  119. //MIDI_CC_LIST << "0x33 *General Purpose 4";
  120. //MIDI_CC_LIST << "0x34 *(Undefined)";
  121. //MIDI_CC_LIST << "0x35 *(Undefined)";
  122. //MIDI_CC_LIST << "0x36 *(Undefined)";
  123. //MIDI_CC_LIST << "0x37 *(Undefined)";
  124. //MIDI_CC_LIST << "0x38 *(Undefined)";
  125. //MIDI_CC_LIST << "0x39 *(Undefined)";
  126. //MIDI_CC_LIST << "0x3A *(Undefined)";
  127. //MIDI_CC_LIST << "0x3B *(Undefined)";
  128. //MIDI_CC_LIST << "0x3C *(Undefined)";
  129. //MIDI_CC_LIST << "0x3D *(Undefined)";
  130. //MIDI_CC_LIST << "0x3E *(Undefined)";
  131. //MIDI_CC_LIST << "0x3F *(Undefined)";
  132. //MIDI_CC_LIST << "0x40 Damper On/Off"; // <63 off, >64 on
  133. //MIDI_CC_LIST << "0x41 Portamento On/Off"; // <63 off, >64 on
  134. //MIDI_CC_LIST << "0x42 Sostenuto On/Off"; // <63 off, >64 on
  135. //MIDI_CC_LIST << "0x43 Soft Pedal On/Off"; // <63 off, >64 on
  136. //MIDI_CC_LIST << "0x44 Legato Footswitch"; // <63 Normal, >64 Legato
  137. //MIDI_CC_LIST << "0x45 Hold 2"; // <63 off, >64 on
  138. MIDI_CC_LIST << "0x46 Control 1 [Variation]";
  139. MIDI_CC_LIST << "0x47 Control 2 [Timbre]";
  140. MIDI_CC_LIST << "0x48 Control 3 [Release]";
  141. MIDI_CC_LIST << "0x49 Control 4 [Attack]";
  142. MIDI_CC_LIST << "0x4A Control 5 [Brightness]";
  143. MIDI_CC_LIST << "0x4B Control 6 [Decay]";
  144. MIDI_CC_LIST << "0x4C Control 7 [Vib Rate]";
  145. MIDI_CC_LIST << "0x4D Control 8 [Vib Depth]";
  146. MIDI_CC_LIST << "0x4E Control 9 [Vib Delay]";
  147. MIDI_CC_LIST << "0x4F Control 10 [Undefined]";
  148. MIDI_CC_LIST << "0x50 General Purpose 5";
  149. MIDI_CC_LIST << "0x51 General Purpose 6";
  150. MIDI_CC_LIST << "0x52 General Purpose 8";
  151. MIDI_CC_LIST << "0x53 General Purpose 9";
  152. MIDI_CC_LIST << "0x54 Portamento Control";
  153. MIDI_CC_LIST << "0x5B FX 1 Depth [Reverb]";
  154. MIDI_CC_LIST << "0x5C FX 2 Depth [Tremolo]";
  155. MIDI_CC_LIST << "0x5D FX 3 Depth [Chorus]";
  156. MIDI_CC_LIST << "0x5E FX 4 Depth [Detune]";
  157. MIDI_CC_LIST << "0x5F FX 5 Depth [Phaser]";
  158. }
  159. // -------------------------------
  160. // XY Controller Scene
  161. class XYGraphicsScene : public QGraphicsScene
  162. {
  163. Q_OBJECT
  164. public:
  165. XYGraphicsScene(QWidget* parent) : QGraphicsScene(parent), m_parent(parent)
  166. {
  167. cc_x = 1;
  168. cc_y = 2;
  169. m_mouseLock = false;
  170. m_smooth = false;
  171. m_smooth_x = 0;
  172. m_smooth_y = 0;
  173. setBackgroundBrush(Qt::black);
  174. QPen cursorPen(QColor(255, 255, 255), 2);
  175. QColor cursorBrush(255, 255, 255, 50);
  176. m_cursor = addEllipse(QRectF(-10, -10, 20, 20), cursorPen, cursorBrush);
  177. QPen linePen(QColor(200, 200, 200, 100), 1, Qt::DashLine);
  178. m_lineH = addLine(-9999, 0, 9999, 0, linePen);
  179. m_lineV = addLine(0, -9999, 0, 9999, linePen);
  180. p_size = QRectF(-100, -100, 100, 100);
  181. }
  182. ~XYGraphicsScene()
  183. {
  184. }
  185. void setControlX(int x)
  186. {
  187. cc_x = x;
  188. }
  189. void setControlY(int y)
  190. {
  191. cc_y = y;
  192. }
  193. void setChannels(QList<int> channels)
  194. {
  195. m_channels = channels;
  196. }
  197. void setPosX(qreal x, bool forward=true)
  198. {
  199. if (! m_mouseLock)
  200. {
  201. qreal pos_x = x * (p_size.x() + p_size.width());
  202. m_cursor->setPos(pos_x, m_cursor->y());
  203. m_lineV->setX(pos_x);
  204. if (forward)
  205. {
  206. qreal value = pos_x / (p_size.x() + p_size.width());
  207. sendMIDI(&value, nullptr);
  208. }
  209. else
  210. m_smooth_x = pos_x;
  211. }
  212. }
  213. void setPosY(qreal y, bool forward=true)
  214. {
  215. if (! m_mouseLock)
  216. {
  217. qreal pos_y = y * (p_size.y() + p_size.height());
  218. m_cursor->setPos(m_cursor->x(), pos_y);
  219. m_lineH->setY(pos_y);
  220. if (forward)
  221. {
  222. qreal value = pos_y / (p_size.y() + p_size.height());
  223. sendMIDI(nullptr, &value);
  224. }
  225. else
  226. m_smooth_y = pos_y;
  227. }
  228. }
  229. void setSmooth(bool smooth)
  230. {
  231. m_smooth = smooth;
  232. }
  233. void setSmoothValues(int x, int y)
  234. {
  235. m_smooth_x = x * (p_size.x() + p_size.width());
  236. m_smooth_y = y * (p_size.y() + p_size.height());
  237. }
  238. void handleCC(int param, int value)
  239. {
  240. bool sendUpdate = false;
  241. qreal xp, yp;
  242. xp = yp = 0.0;
  243. if (param == cc_x)
  244. {
  245. sendUpdate = true;
  246. xp = (float(value) / 63) - 1.0;
  247. yp = m_cursor->y() / (p_size.y() + p_size.height());
  248. if (xp < -1.0)
  249. xp = -1.0;
  250. else if (xp > 1.0)
  251. xp = 1.0;
  252. setPosX(xp, false);
  253. }
  254. if (param == cc_y)
  255. {
  256. sendUpdate = true;
  257. xp = m_cursor->x() / (p_size.x() + p_size.width());
  258. yp = (float(value) / 63) - 1.0;
  259. if (yp < -1.0)
  260. yp = -1.0;
  261. else if (yp > 1.0)
  262. yp = 1.0;
  263. setPosY(yp, false);
  264. }
  265. if (sendUpdate)
  266. emit cursorMoved(xp, yp);
  267. }
  268. void updateSize(QSize size)
  269. {
  270. p_size.setRect(-(size.width() / 2), -(size.height() / 2), size.width(), size.height());
  271. }
  272. void updateSmooth()
  273. {
  274. if (! m_smooth)
  275. return;
  276. if (m_cursor->x() != m_smooth_x || m_cursor->y() != m_smooth_y)
  277. {
  278. if (abs(m_cursor->x() - m_smooth_x) <= 0.001)
  279. {
  280. m_smooth_x = m_cursor->x();
  281. return;
  282. }
  283. else if (abs(m_cursor->y() - m_smooth_y) <= 0.001)
  284. {
  285. m_smooth_y = m_cursor->y();
  286. return;
  287. }
  288. qreal new_x = (m_smooth_x + m_cursor->x() * 3) / 4;
  289. qreal new_y = (m_smooth_y + m_cursor->y() * 3) / 4;
  290. QPointF pos(new_x, new_y);
  291. m_cursor->setPos(pos);
  292. m_lineH->setY(pos.y());
  293. m_lineV->setX(pos.x());
  294. qreal xp = pos.x() / (p_size.x() + p_size.width());
  295. qreal yp = pos.y() / (p_size.y() + p_size.height());
  296. sendMIDI(&xp, &yp);
  297. emit cursorMoved(xp, yp);
  298. }
  299. }
  300. protected:
  301. void handleMousePos(QPointF pos)
  302. {
  303. if (! p_size.contains(pos))
  304. {
  305. if (pos.x() < p_size.x())
  306. pos.setX(p_size.x());
  307. else if (pos.x() > p_size.x() + p_size.width())
  308. pos.setX(p_size.x() + p_size.width());
  309. if (pos.y() < p_size.y())
  310. pos.setY(p_size.y());
  311. else if (pos.y() > p_size.y() + p_size.height())
  312. pos.setY(p_size.y() + p_size.height());
  313. }
  314. m_smooth_x = pos.x();
  315. m_smooth_y = pos.y();
  316. if (! m_smooth)
  317. {
  318. m_cursor->setPos(pos);
  319. m_lineH->setY(pos.y());
  320. m_lineV->setX(pos.x());
  321. qreal xp = pos.x() / (p_size.x() + p_size.width());
  322. qreal yp = pos.y() / (p_size.y() + p_size.height());
  323. sendMIDI(&xp, &yp);
  324. emit cursorMoved(xp, yp);
  325. }
  326. }
  327. void sendMIDI(qreal* xp=nullptr, qreal* yp=nullptr)
  328. {
  329. qreal rate = qreal(0xff) / 4;
  330. if (xp != nullptr)
  331. {
  332. int value = *xp * rate + rate;
  333. foreach (const int& channel, m_channels)
  334. jack_midi_out_data.put_nowait(0xB0 + channel - 1, cc_x, value);
  335. }
  336. if (yp != nullptr)
  337. {
  338. int value = *yp * rate + rate;
  339. foreach (const int& channel, m_channels)
  340. jack_midi_out_data.put_nowait(0xB0 + channel - 1, cc_y, value);
  341. }
  342. }
  343. void keyPressEvent(QKeyEvent* event)
  344. {
  345. event->accept();
  346. }
  347. void wheelEvent(QGraphicsSceneWheelEvent* event)
  348. {
  349. event->accept();
  350. }
  351. void mousePressEvent(QGraphicsSceneMouseEvent* event)
  352. {
  353. m_mouseLock = true;
  354. handleMousePos(event->scenePos());
  355. parent()->setCursor(Qt::CrossCursor);
  356. QGraphicsScene::mousePressEvent(event);
  357. }
  358. void mouseMoveEvent(QGraphicsSceneMouseEvent* event)
  359. {
  360. handleMousePos(event->scenePos());
  361. QGraphicsScene::mouseMoveEvent(event);
  362. }
  363. void mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
  364. {
  365. m_mouseLock = false;
  366. parent()->setCursor(Qt::ArrowCursor);
  367. QGraphicsScene::mouseReleaseEvent(event);
  368. }
  369. QWidget* parent() const
  370. {
  371. return m_parent;
  372. }
  373. signals:
  374. void cursorMoved(qreal, qreal);
  375. private:
  376. int cc_x;
  377. int cc_y;
  378. QList<int> m_channels;
  379. bool m_mouseLock;
  380. bool m_smooth;
  381. int m_smooth_x;
  382. int m_smooth_y;
  383. QGraphicsEllipseItem* m_cursor;
  384. QGraphicsLineItem* m_lineH;
  385. QGraphicsLineItem* m_lineV;
  386. QRectF p_size;
  387. QWidget* const m_parent;
  388. };
  389. // -------------------------------
  390. // XY Controller Window
  391. namespace Ui {
  392. class XYControllerW;
  393. }
  394. class XYControllerW : public QMainWindow
  395. {
  396. Q_OBJECT
  397. public:
  398. XYControllerW() :
  399. QMainWindow(nullptr),
  400. scene(this),
  401. settings("Cadence", "XY-Controller"),
  402. ui(new Ui::XYControllerW)
  403. {
  404. ui->setupUi(this);
  405. // -------------------------------------------------------------
  406. // Internal stuff
  407. cc_x = 1;
  408. cc_y = 2;
  409. // -------------------------------------------------------------
  410. // Set-up GUI stuff
  411. ui->dial_x->setPixmap(2);
  412. ui->dial_y->setPixmap(2);
  413. ui->dial_x->setLabel("X");
  414. ui->dial_y->setLabel("Y");
  415. ui->keyboard->setOctaves(6);
  416. ui->graphicsView->setScene(&scene);
  417. ui->graphicsView->setRenderHints(QPainter::Antialiasing);
  418. foreach (const QString& MIDI_CC, MIDI_CC_LIST)
  419. {
  420. ui->cb_control_x->addItem(MIDI_CC);
  421. ui->cb_control_y->addItem(MIDI_CC);
  422. }
  423. // -------------------------------------------------------------
  424. // Load Settings
  425. loadSettings();
  426. // -------------------------------------------------------------
  427. // Connect actions to functions
  428. connect(ui->keyboard, SIGNAL(noteOn(int)), SLOT(noteOn(int)));
  429. connect(ui->keyboard, SIGNAL(noteOff(int)), SLOT(noteOff(int)));
  430. connect(ui->cb_smooth, SIGNAL(clicked(bool)), SLOT(setSmooth(bool)));
  431. connect(ui->dial_x, SIGNAL(valueChanged(int)), SLOT(updateSceneX(int)));
  432. connect(ui->dial_y, SIGNAL(valueChanged(int)), SLOT(updateSceneY(int)));
  433. connect(ui->cb_control_x, SIGNAL(currentIndexChanged(QString)), SLOT(checkCC_X(QString)));
  434. connect(ui->cb_control_y, SIGNAL(currentIndexChanged(QString)), SLOT(checkCC_Y(QString)));
  435. connect(&scene, SIGNAL(cursorMoved(qreal, qreal)), SLOT(sceneCursorMoved(qreal, qreal)));
  436. connect(ui->act_ch_01, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  437. connect(ui->act_ch_02, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  438. connect(ui->act_ch_03, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  439. connect(ui->act_ch_04, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  440. connect(ui->act_ch_05, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  441. connect(ui->act_ch_06, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  442. connect(ui->act_ch_07, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  443. connect(ui->act_ch_08, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  444. connect(ui->act_ch_09, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  445. connect(ui->act_ch_10, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  446. connect(ui->act_ch_11, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  447. connect(ui->act_ch_12, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  448. connect(ui->act_ch_13, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  449. connect(ui->act_ch_14, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  450. connect(ui->act_ch_15, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  451. connect(ui->act_ch_16, SIGNAL(triggered(bool)), SLOT(checkChannel(bool)));
  452. connect(ui->act_ch_all, SIGNAL(triggered()), SLOT(checkChannel_all()));
  453. connect(ui->act_ch_none, SIGNAL(triggered()), SLOT(checkChannel_none()));
  454. connect(ui->act_show_keyboard, SIGNAL(triggered(bool)), SLOT(showKeyboard(bool)));
  455. connect(ui->act_about, SIGNAL(triggered()), SLOT(about()));
  456. // -------------------------------------------------------------
  457. // Final stuff
  458. m_midiInTimerId = startTimer(50);
  459. QTimer::singleShot(0, this, SLOT(updateScreen()));
  460. }
  461. protected slots:
  462. void noteOn(int note)
  463. {
  464. foreach (const int& channel, m_channels)
  465. jack_midi_out_data.put_nowait(0x90 + channel - 1, note, 100);
  466. }
  467. void noteOff(int note)
  468. {
  469. foreach (const int& channel, m_channels)
  470. jack_midi_out_data.put_nowait(0x80 + channel - 1, note, 0);
  471. }
  472. void updateSceneX(int x)
  473. {
  474. scene.setPosX(float(x) / 100, bool(sender()));
  475. }
  476. void updateSceneY(int y)
  477. {
  478. scene.setPosY(float(y) / 100, bool(sender()));
  479. }
  480. void checkCC_X(QString text)
  481. {
  482. if (! text.isEmpty())
  483. {
  484. bool ok;
  485. int tmp_cc_x = text.split(" ").at(0).toInt(&ok, 16);
  486. if (ok)
  487. {
  488. cc_x = tmp_cc_x;
  489. scene.setControlX(cc_x);
  490. }
  491. }
  492. }
  493. void checkCC_Y(QString text)
  494. {
  495. if (! text.isEmpty())
  496. {
  497. bool ok;
  498. int tmp_cc_y = text.split(" ").at(0).toInt(&ok, 16);
  499. if (ok)
  500. {
  501. cc_y = tmp_cc_y;
  502. scene.setControlY(cc_y);
  503. }
  504. }
  505. }
  506. void checkChannel(bool clicked)
  507. {
  508. if (! sender())
  509. return;
  510. bool ok;
  511. int channel = ((QAction*)sender())->text().toInt(&ok);
  512. if (ok)
  513. {
  514. if (clicked && ! m_channels.contains(channel))
  515. m_channels.append(channel);
  516. else if ((! clicked) && m_channels.contains(channel))
  517. m_channels.removeOne(channel);
  518. scene.setChannels(m_channels);
  519. }
  520. }
  521. void checkChannel_all()
  522. {
  523. ui->act_ch_01->setChecked(true);
  524. ui->act_ch_02->setChecked(true);
  525. ui->act_ch_03->setChecked(true);
  526. ui->act_ch_04->setChecked(true);
  527. ui->act_ch_05->setChecked(true);
  528. ui->act_ch_06->setChecked(true);
  529. ui->act_ch_07->setChecked(true);
  530. ui->act_ch_08->setChecked(true);
  531. ui->act_ch_09->setChecked(true);
  532. ui->act_ch_10->setChecked(true);
  533. ui->act_ch_11->setChecked(true);
  534. ui->act_ch_12->setChecked(true);
  535. ui->act_ch_13->setChecked(true);
  536. ui->act_ch_14->setChecked(true);
  537. ui->act_ch_15->setChecked(true);
  538. ui->act_ch_16->setChecked(true);
  539. #ifdef Q_COMPILER_INITIALIZER_LISTS
  540. m_channels = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
  541. #else
  542. m_channels.clear();
  543. for (int i=1; i <= 16; i++)
  544. m_channels << i;
  545. #endif
  546. scene.setChannels(m_channels);
  547. }
  548. void checkChannel_none()
  549. {
  550. ui->act_ch_01->setChecked(false);
  551. ui->act_ch_02->setChecked(false);
  552. ui->act_ch_03->setChecked(false);
  553. ui->act_ch_04->setChecked(false);
  554. ui->act_ch_05->setChecked(false);
  555. ui->act_ch_06->setChecked(false);
  556. ui->act_ch_07->setChecked(false);
  557. ui->act_ch_08->setChecked(false);
  558. ui->act_ch_09->setChecked(false);
  559. ui->act_ch_10->setChecked(false);
  560. ui->act_ch_11->setChecked(false);
  561. ui->act_ch_12->setChecked(false);
  562. ui->act_ch_13->setChecked(false);
  563. ui->act_ch_14->setChecked(false);
  564. ui->act_ch_15->setChecked(false);
  565. ui->act_ch_16->setChecked(false);
  566. m_channels.clear();
  567. scene.setChannels(m_channels);
  568. }
  569. void setSmooth(bool yesno)
  570. {
  571. scene.setSmooth(yesno);
  572. }
  573. void sceneCursorMoved(qreal xp, qreal yp)
  574. {
  575. ui->dial_x->blockSignals(true);
  576. ui->dial_y->blockSignals(true);
  577. ui->dial_x->setValue(xp * 100);
  578. ui->dial_y->setValue(yp * 100);
  579. ui->dial_x->blockSignals(false);
  580. ui->dial_y->blockSignals(false);
  581. }
  582. void showKeyboard(bool yesno)
  583. {
  584. ui->scrollArea->setVisible(yesno);
  585. QTimer::singleShot(0, this, SLOT(updateScreen()));
  586. }
  587. void about()
  588. {
  589. QMessageBox::about(this, tr("About XY Controller"), tr("<h3>XY Controller</h3>"
  590. "<br>Version %1"
  591. "<br>XY Controller is a simple XY widget that sends and receives data from Jack MIDI.<br>"
  592. "<br>Copyright (C) 2012 falkTX").arg(VERSION));
  593. }
  594. void updateScreen()
  595. {
  596. scene.updateSize(ui->graphicsView->size());
  597. ui->graphicsView->centerOn(0, 0);
  598. int dial_x = ui->dial_x->value();
  599. int dial_y = ui->dial_y->value();
  600. updateSceneX(dial_x);
  601. updateSceneY(dial_y);
  602. scene.setSmoothValues(float(dial_x) / 100, float(dial_y) / 100);
  603. }
  604. protected:
  605. void saveSettings()
  606. {
  607. QVariantList varChannelList;
  608. foreach (const int& channel, m_channels)
  609. varChannelList << channel;
  610. settings.setValue("Geometry", saveGeometry());
  611. settings.setValue("ShowKeyboard", ui->scrollArea->isVisible());
  612. settings.setValue("Smooth", ui->cb_smooth->isChecked());
  613. settings.setValue("DialX", ui->dial_x->value());
  614. settings.setValue("DialY", ui->dial_y->value());
  615. settings.setValue("ControlX", cc_x);
  616. settings.setValue("ControlY", cc_y);
  617. settings.setValue("Channels", varChannelList);
  618. }
  619. void loadSettings()
  620. {
  621. restoreGeometry(settings.value("Geometry").toByteArray());
  622. bool showKeyboard = settings.value("ShowKeyboard", false).toBool();
  623. ui->act_show_keyboard->setChecked(showKeyboard);
  624. ui->scrollArea->setVisible(showKeyboard);
  625. bool smooth = settings.value("Smooth", false).toBool();
  626. ui->cb_smooth->setChecked(smooth);
  627. scene.setSmooth(smooth);
  628. ui->dial_x->setValue(settings.value("DialX", 50).toInt());
  629. ui->dial_y->setValue(settings.value("DialY", 50).toInt());
  630. cc_x = settings.value("ControlX", 1).toInt();
  631. cc_y = settings.value("ControlY", 2).toInt();
  632. scene.setControlX(cc_x);
  633. scene.setControlY(cc_y);
  634. m_channels.clear();
  635. if (settings.contains("Channels"))
  636. {
  637. QVariantList channels = settings.value("Channels").toList();
  638. foreach (const QVariant& var, channels)
  639. {
  640. bool ok;
  641. int channel = var.toInt(&ok);
  642. if (ok)
  643. m_channels.append(channel);
  644. }
  645. }
  646. else
  647. #ifdef Q_COMPILER_INITIALIZER_LISTS
  648. m_channels = { 1 };
  649. #else
  650. m_channels << 1;
  651. #endif
  652. scene.setChannels(m_channels);
  653. for (int i=0; i < MIDI_CC_LIST.size(); i++)
  654. {
  655. bool ok;
  656. int cc = MIDI_CC_LIST[i].split(" ").at(0).toInt(&ok, 16);
  657. if (ok)
  658. {
  659. if (cc_x == cc)
  660. ui->cb_control_x->setCurrentIndex(i);
  661. if (cc_y == cc)
  662. ui->cb_control_y->setCurrentIndex(i);
  663. }
  664. }
  665. if (m_channels.contains(1))
  666. ui->act_ch_01->setChecked(true);
  667. if (m_channels.contains(2))
  668. ui->act_ch_02->setChecked(true);
  669. if (m_channels.contains(3))
  670. ui->act_ch_03->setChecked(true);
  671. if (m_channels.contains(4))
  672. ui->act_ch_04->setChecked(true);
  673. if (m_channels.contains(5))
  674. ui->act_ch_05->setChecked(true);
  675. if (m_channels.contains(6))
  676. ui->act_ch_06->setChecked(true);
  677. if (m_channels.contains(7))
  678. ui->act_ch_07->setChecked(true);
  679. if (m_channels.contains(8))
  680. ui->act_ch_08->setChecked(true);
  681. if (m_channels.contains(9))
  682. ui->act_ch_09->setChecked(true);
  683. if (m_channels.contains(10))
  684. ui->act_ch_10->setChecked(true);
  685. if (m_channels.contains(11))
  686. ui->act_ch_11->setChecked(true);
  687. if (m_channels.contains(12))
  688. ui->act_ch_12->setChecked(true);
  689. if (m_channels.contains(13))
  690. ui->act_ch_13->setChecked(true);
  691. if (m_channels.contains(14))
  692. ui->act_ch_14->setChecked(true);
  693. if (m_channels.contains(15))
  694. ui->act_ch_15->setChecked(true);
  695. if (m_channels.contains(16))
  696. ui->act_ch_16->setChecked(true);
  697. }
  698. void timerEvent(QTimerEvent* event)
  699. {
  700. if (event->timerId() == m_midiInTimerId)
  701. {
  702. //if not jack_midi_in_data.empty():
  703. //while True:
  704. //try:
  705. // data1, data2, data3 = jack_midi_in_data.get_nowait()
  706. //except QuequeEmpty:
  707. // break
  708. //channel = (data1 & 0x0F) + 1
  709. //mode = data1 & 0xF0
  710. //if channel in self.m_channels:
  711. // if mode == 0x80:
  712. // self.keyboard.sendNoteOff(data2, False)
  713. // elif mode == 0x90:
  714. // self.keyboard.sendNoteOn(data2, False)
  715. // elif mode == 0xB0:
  716. // self.scene.handleCC(data2, data3)
  717. //jack_midi_in_data.task_done()
  718. scene.updateSmooth();
  719. }
  720. QMainWindow::timerEvent(event);
  721. }
  722. void resizeEvent(QResizeEvent* event)
  723. {
  724. updateScreen();
  725. QMainWindow::resizeEvent(event);
  726. }
  727. void closeEvent(QCloseEvent* event)
  728. {
  729. saveSettings();
  730. QMainWindow::closeEvent(event);
  731. }
  732. private:
  733. int cc_x;
  734. int cc_y;
  735. QList<int> m_channels;
  736. int m_midiInTimerId;
  737. XYGraphicsScene scene;
  738. QSettings settings;
  739. Ui::XYControllerW* ui;
  740. };
  741. #include "xycontroller.moc"
  742. // -------------------------------
  743. // -------------------------------
  744. int main(int argc, char* argv[])
  745. {
  746. MIDI_CC_LIST__init();
  747. QApplication app(argc, argv);
  748. app.setApplicationName("XY-Controller");
  749. app.setApplicationVersion(VERSION);
  750. app.setOrganizationName("Cadence");
  751. //app.setWindowIcon(QIcon(":/48x48/xy-controller.png"));
  752. #if 0
  753. // JACK initialization
  754. jack_status_t jStatus;
  755. jack_options_t jOptions = static_cast<JackOptions>(JackNoStartServer/*|JackSessionID*/);
  756. jack_client = jack_client_open("XY-Controller", jOptions, &jStatus);
  757. if (! jack_client)
  758. {
  759. std::string errorString(jack_status_get_error_string(jStatus));
  760. QMessageBox::critical(nullptr, app.translate("XY-Controller", "Error"), app.translate("XY-Controller",
  761. "Could not connect to JACK, possible reasons:\n"
  762. "%1").arg(QString::fromStdString(errorString)));
  763. return 1;
  764. }
  765. jack_midi_in_port = jack_port_register(jack_client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
  766. jack_midi_out_port = jack_port_register(jack_client, "midi_out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
  767. //jack_set_process_callback(jClient, process_callback, nullptr);
  768. //jack_set_port_connect_callback(jClient, port_callback, nullptr);
  769. //jack_set_session_callback(jClient, session_callback, argv[0]);
  770. jack_activate(jack_client);
  771. #endif
  772. // Show GUI
  773. XYControllerW gui;
  774. gui.show();
  775. // App-Loop
  776. int ret = app.exec();
  777. #if 0
  778. jack_deactivate(jack_client);
  779. jack_client_close(jack_client);
  780. #endif
  781. return ret;
  782. }