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.

623 lines
22KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # XY Controller for JACK, using jacklib
  4. # Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the COPYING file
  17. # Imports (Global)
  18. from PyQt4.QtCore import pyqtSlot, Qt, QPointF, QRectF, QSettings, QTimer, QVariant
  19. from PyQt4.QtGui import QApplication, QColor, QIcon, QPainter, QPen, QGraphicsItem, QGraphicsScene, QMainWindow
  20. from queue import Queue, Empty as QuequeEmpty
  21. # Imports (Custom)
  22. import ui_xycontroller
  23. from shared import *
  24. from jacklib_helpers import *
  25. # Globals
  26. global jack_client, jack_midi_in_port, jack_midi_out_port, jack_midi_in_data, jack_midi_out_data
  27. jack_client = None
  28. jack_midi_in_port = None
  29. jack_midi_out_port = None
  30. jack_midi_in_data = Queue(512)
  31. jack_midi_out_data = Queue(512)
  32. # XY Controller Scene
  33. class XYGraphicsScene(QGraphicsScene):
  34. def __init__(self, parent):
  35. QGraphicsScene.__init__(self, parent)
  36. self.cc_x = 1
  37. self.cc_y = 2
  38. self.m_channels = []
  39. self.m_mouseLock = False
  40. self.m_smooth = False
  41. self.m_smooth_x = 0
  42. self.m_smooth_y = 0
  43. self.setBackgroundBrush(Qt.black)
  44. cursorPen = QPen(QColor(255,255,255), 2)
  45. cursorBrush = QColor(255,255,255,50)
  46. self.m_cursor = self.addEllipse(QRectF(-10, -10, 20, 20), cursorPen, cursorBrush)
  47. linePen = QPen(QColor(200,200,200,100), 1, Qt.DashLine)
  48. self.m_lineH = self.addLine(-9999, 0, 9999, 0, linePen)
  49. self.m_lineV = self.addLine(0, -9999, 0, 9999, linePen)
  50. self.p_size = QRectF(-100, -100, 100, 100)
  51. def setControlX(self, x):
  52. self.cc_x = x
  53. def setControlY(self, y):
  54. self.cc_y = y
  55. def setChannels(self, channels):
  56. self.m_channels = channels
  57. def setPosX(self, x, forward=True):
  58. if (self.m_mouseLock == False):
  59. pos_x = x*(self.p_size.x()+self.p_size.width())
  60. self.m_cursor.setPos(pos_x, self.m_cursor.y())
  61. self.m_lineV.setX(pos_x)
  62. if (forward):
  63. self.sendMIDI(pos_x/(self.p_size.x()+self.p_size.width()), None)
  64. else:
  65. self.m_smooth_x = pos_x
  66. def setPosY(self, y, forward=True):
  67. if (self.m_mouseLock == False):
  68. pos_y = y*(self.p_size.y()+self.p_size.height())
  69. self.m_cursor.setPos(self.m_cursor.x(), pos_y)
  70. self.m_lineH.setY(pos_y)
  71. if (forward):
  72. self.sendMIDI(None, pos_y/(self.p_size.y()+self.p_size.height()))
  73. else:
  74. self.m_smooth_y = pos_y
  75. def setSmooth(self, smooth):
  76. self.m_smooth = smooth
  77. def setSmoothValues(self, x, y):
  78. self.m_smooth_x = x*(self.p_size.x()+self.p_size.width())
  79. self.m_smooth_y = y*(self.p_size.y()+self.p_size.height())
  80. def handleCC(self, param, value):
  81. sendUpdate = False
  82. if (param == self.cc_x):
  83. sendUpdate = True
  84. xp = (float(value)/63)-1.0
  85. yp = self.m_cursor.y()/(self.p_size.y()+self.p_size.height())
  86. if (xp < -1.0):
  87. xp = -1.0
  88. elif (xp > 1.0):
  89. xp = 1.0
  90. self.setPosX(xp, False)
  91. if (param == self.cc_y):
  92. sendUpdate = True
  93. xp = self.m_cursor.x()/(self.p_size.x()+self.p_size.width())
  94. yp = (float(value)/63)-1.0
  95. if (yp < -1.0):
  96. yp = -1.0
  97. elif (yp > 1.0):
  98. yp = 1.0
  99. self.setPosY(yp, False)
  100. if (sendUpdate):
  101. self.emit(SIGNAL("cursorMoved(double, double)"), xp, yp)
  102. def handleMousePos(self, pos):
  103. if (not self.p_size.contains(pos)):
  104. if (pos.x() < self.p_size.x()):
  105. pos.setX(self.p_size.x())
  106. elif (pos.x() > self.p_size.x()+self.p_size.width()):
  107. pos.setX(self.p_size.x()+self.p_size.width())
  108. if (pos.y() < self.p_size.y()):
  109. pos.setY(self.p_size.y())
  110. elif (pos.y() > self.p_size.y()+self.p_size.height()):
  111. pos.setY(self.p_size.y()+self.p_size.height())
  112. self.m_smooth_x = pos.x()
  113. self.m_smooth_y = pos.y()
  114. if (self.m_smooth == False):
  115. self.m_cursor.setPos(pos)
  116. self.m_lineH.setY(pos.y())
  117. self.m_lineV.setX(pos.x())
  118. xp = pos.x()/(self.p_size.x()+self.p_size.width())
  119. yp = pos.y()/(self.p_size.y()+self.p_size.height())
  120. self.sendMIDI(xp, yp)
  121. self.emit(SIGNAL("cursorMoved(double, double)"), xp, yp)
  122. def sendMIDI(self, xp=None, yp=None):
  123. global jack_midi_out_data
  124. rate = float(0xff)/4
  125. if (xp != None):
  126. value = int((xp*rate)+rate)
  127. for channel in self.m_channels:
  128. jack_midi_out_data.put_nowait((0xB0+channel-1, self.cc_x, value))
  129. if (yp != None):
  130. value = int((yp*rate)+rate)
  131. for channel in self.m_channels:
  132. jack_midi_out_data.put_nowait((0xB0+channel-1, self.cc_y, value))
  133. def updateSize(self, size):
  134. self.p_size.setRect(-(size.width()/2), -(size.height()/2), size.width(), size.height())
  135. def updateSmooth(self):
  136. if (self.m_smooth):
  137. if (self.m_cursor.x() != self.m_smooth_x or self.m_cursor.y() != self.m_smooth_y):
  138. new_x = (self.m_smooth_x+self.m_cursor.x()*3)/4
  139. new_y = (self.m_smooth_y+self.m_cursor.y()*3)/4
  140. pos = QPointF(new_x, new_y)
  141. self.m_cursor.setPos(pos)
  142. self.m_lineH.setY(pos.y())
  143. self.m_lineV.setX(pos.x())
  144. xp = pos.x()/(self.p_size.x()+self.p_size.width())
  145. yp = pos.y()/(self.p_size.y()+self.p_size.height())
  146. self.sendMIDI(xp, yp)
  147. self.emit(SIGNAL("cursorMoved(double, double)"), xp, yp)
  148. def keyPressEvent(self, event):
  149. event.accept()
  150. def wheelEvent(self, event):
  151. event.accept()
  152. def mousePressEvent(self, event):
  153. self.m_mouseLock = True
  154. self.handleMousePos(event.scenePos())
  155. QGraphicsScene.mousePressEvent(self, event)
  156. def mouseMoveEvent(self, event):
  157. self.handleMousePos(event.scenePos())
  158. QGraphicsScene.mouseMoveEvent(self, event)
  159. def mouseReleaseEvent(self, event):
  160. self.m_mouseLock = False
  161. QGraphicsScene.mouseReleaseEvent(self, event)
  162. # XY Controller Window
  163. class XYControllerW(QMainWindow, ui_xycontroller.Ui_XYControllerW):
  164. def __init__(self, parent=None):
  165. QMainWindow.__init__(self, parent)
  166. self.setupUi(self)
  167. # -------------------------------------------------------------
  168. # Internal stuff
  169. self.cc_x = 1
  170. self.cc_y = 2
  171. self.m_channels = []
  172. # -------------------------------------------------------------
  173. # Set-up GUI stuff
  174. self.dial_x.setPixmap(2)
  175. self.dial_y.setPixmap(2)
  176. self.dial_x.setLabel("X")
  177. self.dial_y.setLabel("Y")
  178. self.keyboard.setOctaves(6)
  179. self.scene = XYGraphicsScene(self)
  180. self.graphicsView.setScene(self.scene)
  181. self.graphicsView.setRenderHints(QPainter.Antialiasing)
  182. for MIDI_CC in MIDI_CC_LIST:
  183. self.cb_control_x.addItem(MIDI_CC)
  184. self.cb_control_y.addItem(MIDI_CC)
  185. # -------------------------------------------------------------
  186. # Load Settings
  187. self.settings = QSettings("Cadence", "XY-Controller")
  188. self.loadSettings()
  189. # -------------------------------------------------------------
  190. # Connect actions to functions
  191. self.connect(self.keyboard, SIGNAL("noteOn(int)"), SLOT("slot_noteOn(int)"))
  192. self.connect(self.keyboard, SIGNAL("noteOff(int)"), SLOT("slot_noteOff(int)"))
  193. self.connect(self.cb_smooth, SIGNAL("clicked(bool)"), SLOT("slot_setSmooth(bool)"))
  194. self.connect(self.dial_x, SIGNAL("valueChanged(int)"), SLOT("slot_updateSceneX(int)"))
  195. self.connect(self.dial_y, SIGNAL("valueChanged(int)"), SLOT("slot_updateSceneY(int)"))
  196. self.connect(self.cb_control_x, SIGNAL("currentIndexChanged(QString)"), SLOT("slot_checkCC_X(QString)"))
  197. self.connect(self.cb_control_y, SIGNAL("currentIndexChanged(QString)"), SLOT("slot_checkCC_Y(QString)"))
  198. self.connect(self.scene, SIGNAL("cursorMoved(double, double)"), SLOT("slot_sceneCursorMoved(double, double)"))
  199. self.connect(self.act_ch_01, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  200. self.connect(self.act_ch_02, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  201. self.connect(self.act_ch_03, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  202. self.connect(self.act_ch_04, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  203. self.connect(self.act_ch_05, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  204. self.connect(self.act_ch_06, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  205. self.connect(self.act_ch_07, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  206. self.connect(self.act_ch_08, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  207. self.connect(self.act_ch_09, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  208. self.connect(self.act_ch_10, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  209. self.connect(self.act_ch_11, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  210. self.connect(self.act_ch_12, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  211. self.connect(self.act_ch_13, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  212. self.connect(self.act_ch_14, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  213. self.connect(self.act_ch_15, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  214. self.connect(self.act_ch_16, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
  215. self.connect(self.act_ch_all, SIGNAL("triggered()"), SLOT("slot_checkChannel_all()"))
  216. self.connect(self.act_ch_none, SIGNAL("triggered()"), SLOT("slot_checkChannel_none()"))
  217. self.connect(self.act_show_keyboard, SIGNAL("triggered(bool)"), SLOT("slot_showKeyboard(bool)"))
  218. self.connect(self.act_about, SIGNAL("triggered()"), SLOT("slot_about()"))
  219. # -------------------------------------------------------------
  220. # Final stuff
  221. self.m_midiInTimerId = self.startTimer(50)
  222. QTimer.singleShot(0, self, SLOT("slot_updateScreen()"))
  223. def updateScreen(self):
  224. self.scene.updateSize(self.graphicsView.size())
  225. self.graphicsView.centerOn(0, 0)
  226. dial_x = self.dial_x.value()
  227. dial_y = self.dial_y.value()
  228. self.slot_updateSceneX(dial_x)
  229. self.slot_updateSceneY(dial_y)
  230. self.scene.setSmoothValues(float(dial_x)/100, float(dial_y)/100)
  231. @pyqtSlot(int)
  232. def slot_noteOn(self, note):
  233. global jack_midi_out_data
  234. for channel in self.m_channels:
  235. jack_midi_out_data.put_nowait((0x90+channel-1, note, 100))
  236. @pyqtSlot(int)
  237. def slot_noteOff(self, note):
  238. global jack_midi_out_data
  239. for channel in self.m_channels:
  240. jack_midi_out_data.put_nowait((0x80+channel-1, note, 0))
  241. @pyqtSlot(int)
  242. def slot_updateSceneX(self, x):
  243. self.scene.setPosX(float(x)/100, not self.dial_x.isSliderDown())
  244. @pyqtSlot(int)
  245. def slot_updateSceneY(self, y):
  246. self.scene.setPosY(float(y)/100, not self.dial_y.isSliderDown())
  247. @pyqtSlot(str)
  248. def slot_checkCC_X(self, text):
  249. if (text):
  250. self.cc_x = int(text.split(" ")[0], 16)
  251. self.scene.setControlX(self.cc_x)
  252. @pyqtSlot(str)
  253. def slot_checkCC_Y(self, text):
  254. if (text):
  255. self.cc_y = int(text.split(" ")[0], 16)
  256. self.scene.setControlY(self.cc_y)
  257. @pyqtSlot(bool)
  258. def slot_checkChannel(self, clicked):
  259. channel = int(self.sender().text())
  260. if (clicked and channel not in self.m_channels):
  261. self.m_channels.append(channel)
  262. elif (not clicked and channel in self.m_channels):
  263. self.m_channels.remove(channel)
  264. self.scene.setChannels(self.m_channels)
  265. @pyqtSlot()
  266. def slot_checkChannel_all(self):
  267. self.act_ch_01.setChecked(True)
  268. self.act_ch_02.setChecked(True)
  269. self.act_ch_03.setChecked(True)
  270. self.act_ch_04.setChecked(True)
  271. self.act_ch_05.setChecked(True)
  272. self.act_ch_06.setChecked(True)
  273. self.act_ch_07.setChecked(True)
  274. self.act_ch_08.setChecked(True)
  275. self.act_ch_09.setChecked(True)
  276. self.act_ch_10.setChecked(True)
  277. self.act_ch_11.setChecked(True)
  278. self.act_ch_12.setChecked(True)
  279. self.act_ch_13.setChecked(True)
  280. self.act_ch_14.setChecked(True)
  281. self.act_ch_15.setChecked(True)
  282. self.act_ch_16.setChecked(True)
  283. self.m_channels = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
  284. self.scene.setChannels(self.m_channels)
  285. @pyqtSlot()
  286. def slot_checkChannel_none(self):
  287. self.act_ch_01.setChecked(False)
  288. self.act_ch_02.setChecked(False)
  289. self.act_ch_03.setChecked(False)
  290. self.act_ch_04.setChecked(False)
  291. self.act_ch_05.setChecked(False)
  292. self.act_ch_06.setChecked(False)
  293. self.act_ch_07.setChecked(False)
  294. self.act_ch_08.setChecked(False)
  295. self.act_ch_09.setChecked(False)
  296. self.act_ch_10.setChecked(False)
  297. self.act_ch_11.setChecked(False)
  298. self.act_ch_12.setChecked(False)
  299. self.act_ch_13.setChecked(False)
  300. self.act_ch_14.setChecked(False)
  301. self.act_ch_15.setChecked(False)
  302. self.act_ch_16.setChecked(False)
  303. self.m_channels = []
  304. self.scene.setChannels(self.m_channels)
  305. @pyqtSlot(bool)
  306. def slot_setSmooth(self, yesno):
  307. self.scene.setSmooth(yesno)
  308. @pyqtSlot(float, float)
  309. def slot_sceneCursorMoved(self, xp, yp):
  310. self.dial_x.setValue(xp*100)
  311. self.dial_y.setValue(yp*100)
  312. @pyqtSlot(bool)
  313. def slot_showKeyboard(self, yesno):
  314. self.scrollArea.setVisible(yesno)
  315. QTimer.singleShot(0, self, SLOT("slot_updateScreen()"))
  316. @pyqtSlot()
  317. def slot_about(self):
  318. QMessageBox.about(self, self.tr("About XY Controller"), self.tr("<h3>XY Controller</h3>"
  319. "<br>Version %s"
  320. "<br>XY Controller is a simple XY widget that sends and receives data from Jack MIDI.<br>"
  321. "<br>Copyright (C) 2012 falkTX" % (VERSION)))
  322. @pyqtSlot()
  323. def slot_updateScreen(self):
  324. self.updateScreen()
  325. def saveSettings(self):
  326. self.settings.setValue("Geometry", self.saveGeometry())
  327. self.settings.setValue("ShowKeyboard", self.scrollArea.isVisible())
  328. self.settings.setValue("Smooth", self.cb_smooth.isChecked())
  329. self.settings.setValue("DialX", self.dial_x.value())
  330. self.settings.setValue("DialY", self.dial_y.value())
  331. self.settings.setValue("ControlX", self.cc_x)
  332. self.settings.setValue("ControlY", self.cc_y)
  333. self.settings.setValue("Channels", self.m_channels)
  334. def loadSettings(self):
  335. self.restoreGeometry(self.settings.value("Geometry", ""))
  336. showKeyboard = self.settings.value("ShowKeyboard", False, type=bool)
  337. self.act_show_keyboard.setChecked(showKeyboard)
  338. self.scrollArea.setVisible(showKeyboard)
  339. smooth = self.settings.value("Smooth", False, type=bool)
  340. self.cb_smooth.setChecked(smooth)
  341. self.scene.setSmooth(smooth)
  342. self.dial_x.setValue(self.settings.value("DialX", 50, type=int))
  343. self.dial_y.setValue(self.settings.value("DialY", 50, type=int))
  344. self.cc_x = self.settings.value("ControlX", 1, type=int)
  345. self.cc_y = self.settings.value("ControlY", 2, type=int)
  346. self.scene.setControlX(self.cc_x)
  347. self.scene.setControlY(self.cc_y)
  348. self.m_channels = toList(self.settings.value("Channels", [1]))
  349. for i in range(len(self.m_channels)):
  350. self.m_channels[i] = int(self.m_channels[i])
  351. self.scene.setChannels(self.m_channels)
  352. for i in range(len(MIDI_CC_LIST)):
  353. cc = int(MIDI_CC_LIST[i].split(" ")[0], 16)
  354. if (self.cc_x == cc):
  355. self.cb_control_x.setCurrentIndex(i)
  356. if (self.cc_y == cc):
  357. self.cb_control_y.setCurrentIndex(i)
  358. if (1 in self.m_channels):
  359. self.act_ch_01.setChecked(True)
  360. if (2 in self.m_channels):
  361. self.act_ch_02.setChecked(True)
  362. if (3 in self.m_channels):
  363. self.act_ch_03.setChecked(True)
  364. if (4 in self.m_channels):
  365. self.act_ch_04.setChecked(True)
  366. if (5 in self.m_channels):
  367. self.act_ch_05.setChecked(True)
  368. if (6 in self.m_channels):
  369. self.act_ch_06.setChecked(True)
  370. if (7 in self.m_channels):
  371. self.act_ch_07.setChecked(True)
  372. if (8 in self.m_channels):
  373. self.act_ch_08.setChecked(True)
  374. if (9 in self.m_channels):
  375. self.act_ch_09.setChecked(True)
  376. if (10 in self.m_channels):
  377. self.act_ch_10.setChecked(True)
  378. if (11 in self.m_channels):
  379. self.act_ch_11.setChecked(True)
  380. if (12 in self.m_channels):
  381. self.act_ch_12.setChecked(True)
  382. if (13 in self.m_channels):
  383. self.act_ch_13.setChecked(True)
  384. if (14 in self.m_channels):
  385. self.act_ch_14.setChecked(True)
  386. if (15 in self.m_channels):
  387. self.act_ch_15.setChecked(True)
  388. if (16 in self.m_channels):
  389. self.act_ch_16.setChecked(True)
  390. def timerEvent(self, event):
  391. if (event.timerId() == self.m_midiInTimerId):
  392. global jack_midi_in_data
  393. if (jack_midi_in_data.empty() == False):
  394. while (True):
  395. try:
  396. data1, data2, data3 = jack_midi_in_data.get_nowait()
  397. except QuequeEmpty:
  398. break
  399. channel = (data1 & 0x0F)+1
  400. mode = data1 & 0xF0
  401. if (channel in self.m_channels):
  402. if (mode == 0x80):
  403. self.keyboard.noteOff(data2, False)
  404. elif (mode == 0x90):
  405. self.keyboard.noteOn(data2, False)
  406. elif (mode == 0xB0):
  407. self.scene.handleCC(data2, data3)
  408. jack_midi_in_data.task_done()
  409. self.scene.updateSmooth()
  410. QMainWindow.timerEvent(self, event)
  411. def resizeEvent(self, event):
  412. self.updateScreen()
  413. QMainWindow.resizeEvent(self, event)
  414. def closeEvent(self, event):
  415. self.saveSettings()
  416. QMainWindow.closeEvent(self, event)
  417. # -------------------------------------------------------------
  418. # JACK Stuff
  419. static_event = jacklib.jack_midi_event_t()
  420. static_mtype = jacklib.c_ubyte*3
  421. def jack_process_callback(nframes, arg):
  422. global jack_midi_in_port, jack_midi_out_port, jack_midi_in_data, jack_midi_out_data
  423. # MIDI In
  424. midi_in_buffer = jacklib.port_get_buffer(jack_midi_in_port, nframes)
  425. if (midi_in_buffer):
  426. event_count = jacklib.midi_get_event_count(midi_in_buffer)
  427. for i in range(event_count):
  428. if (jacklib.midi_event_get(jacklib.pointer(static_event), midi_in_buffer, i) == 0):
  429. if (static_event.size == 1):
  430. jack_midi_in_data.put_nowait((static_event.buffer[0], 0, 0))
  431. elif (static_event.size == 2):
  432. jack_midi_in_data.put_nowait((static_event.buffer[0], static_event.buffer[1], 0))
  433. elif (static_event.size >= 3):
  434. jack_midi_in_data.put_nowait((static_event.buffer[0], static_event.buffer[1], static_event.buffer[2]))
  435. if (jack_midi_in_data.full()):
  436. break
  437. # MIDI Out
  438. midi_out_buffer = jacklib.port_get_buffer(jack_midi_out_port, nframes)
  439. if (midi_out_buffer):
  440. jacklib.midi_clear_buffer(midi_out_buffer)
  441. if (jack_midi_out_data.empty() == False):
  442. while (True):
  443. try:
  444. mode, note, velo = jack_midi_out_data.get_nowait()
  445. except QuequeEmpty:
  446. break
  447. data = static_mtype(mode, note, velo)
  448. jacklib.midi_event_write(midi_out_buffer, 0, data, 3)
  449. jack_midi_out_data.task_done()
  450. return 0
  451. def jack_session_callback(event, arg):
  452. if (WINDOWS):
  453. filepath = os.path.join(sys.argv[0])
  454. else:
  455. if (sys.argv[0].startswith("/")):
  456. filepath = "jack_xycontroller"
  457. else:
  458. filepath = os.path.join(sys.path[0], "xycontroller.py")
  459. event.command_line = str(filepath).encode("ascii")
  460. jacklib.session_reply(jack_client, event)
  461. if (event.type == jacklib.JackSessionSaveAndQuit):
  462. app.quit()
  463. #jacklib.session_event_free(event)
  464. #--------------- main ------------------
  465. if __name__ == '__main__':
  466. # App initialization
  467. app = QApplication(sys.argv)
  468. app.setApplicationName("XY-Controller")
  469. app.setApplicationVersion(VERSION)
  470. app.setOrganizationName("falkTX")
  471. #app.setWindowIcon(QIcon(":/48x48/xy-controller.png"))
  472. # Start jack
  473. jack_status = jacklib.jack_status_t(0)
  474. jack_client = jacklib.client_open("XY-Controller", jacklib.JackSessionID, jacklib.pointer(jack_status))
  475. if not jack_client:
  476. QMessageBox.critical(None, app.translate("XYControllerW", "Error"), app.translate("XYControllerW", "Could not connect to JACK, possible errors:\n%s" % (get_jack_status_error_string(jack_status))))
  477. sys.exit(1)
  478. jack_midi_in_port = jacklib.port_register(jack_client, "midi_in", jacklib.JACK_DEFAULT_MIDI_TYPE, jacklib.JackPortIsInput, 0)
  479. jack_midi_out_port = jacklib.port_register(jack_client, "midi_out", jacklib.JACK_DEFAULT_MIDI_TYPE, jacklib.JackPortIsOutput, 0)
  480. jacklib.set_session_callback(jack_client, jack_session_callback, None)
  481. jacklib.set_process_callback(jack_client, jack_process_callback, None)
  482. jacklib.activate(jack_client)
  483. # Show GUI
  484. gui = XYControllerW()
  485. gui.show()
  486. # Set-up custom signal handling
  487. set_up_signals(gui)
  488. # App-Loop
  489. ret = app.exec_()
  490. # Close Jack
  491. if (jack_client):
  492. jacklib.deactivate(jack_client)
  493. jacklib.client_close(jack_client)
  494. # Exit properly
  495. sys.exit(ret)