Browse Source

Added xycontroller; Force python3 in headers

tags/v0.9.0
falkTX 13 years ago
parent
commit
20f64b2786
13 changed files with 1111 additions and 22 deletions
  1. +1
    -1
      src/clickablelabel.py
  2. +1
    -1
      src/digitalpeakmeter.py
  3. +1
    -1
      src/jacklib.py
  4. +1
    -1
      src/jacklib_helpers.py
  5. +3
    -3
      src/jackmeter.py
  6. +1
    -1
      src/ladspa_rdf.py
  7. +2
    -2
      src/logs.py
  8. +1
    -1
      src/pixmapdial.py
  9. +2
    -2
      src/pixmapkeyboard.py
  10. +5
    -5
      src/render.py
  11. +13
    -4
      src/shared.py
  12. +499
    -0
      src/ui/xycontroller.ui
  13. +581
    -0
      src/xycontroller.py

+ 1
- 1
src/clickablelabel.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Clickable Label, a custom Qt4 widget


+ 1
- 1
src/digitalpeakmeter.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Digital Peak Meter, a custom Qt4 widget


+ 1
- 1
src/jacklib.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# JACK ctypes definitions for usage in python applications


+ 1
- 1
src/jacklib_helpers.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Helper functions for extra jacklib functionality


+ 3
- 3
src/jackmeter.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Simple JACK Audio Meter
@@ -75,7 +75,7 @@ def reconnect_inputs():
need_reconnect = False

class MeterW(DigitalPeakMeter):
def __init__(self, parent):
def __init__(self, parent=None):
DigitalPeakMeter.__init__(self, parent)

client_name = str(jacklib.get_client_name(client), encoding="ascii")
@@ -125,7 +125,7 @@ if __name__ == '__main__':
reconnect_inputs()

# Show GUI
gui = MeterW(None)
gui = MeterW()
gui.resize(70, 600)
gui.show()



+ 1
- 1
src/ladspa_rdf.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# LADSPA RDF python support


+ 2
- 2
src/logs.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# JACK, A2J, LASH and LADISH Logs Viewer
@@ -360,7 +360,7 @@ if __name__ == '__main__':
app = QApplication(sys.argv)

# Show GUI
gui = LogsW(None, Qt.WindowFlags())
gui = LogsW(None)
gui.show()

set_up_signals(gui)


+ 1
- 1
src/pixmapdial.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Pixmap Dial, a custom Qt4 widget


+ 2
- 2
src/pixmapkeyboard.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Pixmap Keyboard, a custom Qt4 widget
@@ -92,7 +92,7 @@ class PixmapKeyboard(QWidget):
VERTICAL = 1

def __init__(self, parent):
super(PixmapKeyboard, self).__init__(parent)
QWidget.__init__(self, parent)

self.m_octaves = 6
self.m_lastMouseNote = -1


+ 5
- 5
src/render.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# JACK-Capture frontend, with freewheel and transport support
@@ -17,7 +17,7 @@
# For a full copy of the GNU General Public License see the COPYING file

# Imports (Global)
from PyQt4.QtCore import pyqtSlot, Qt, QProcess, QTime, QTimer
from PyQt4.QtCore import pyqtSlot, QProcess, QTime, QTimer
from PyQt4.QtGui import QDialog
from time import sleep

@@ -31,8 +31,8 @@ jack_client = None

# Render Window
class RenderW(QDialog, ui_render.Ui_RenderW):
def __init__(self, parent, flags):
QDialog.__init__(self, parent, flags)
def __init__(self, parent):
QDialog.__init__(self, parent)
self.setupUi(self)

# -------------------------------------------------------------
@@ -290,7 +290,7 @@ if __name__ == '__main__':
sys.exit(1)

# Show GUI
gui = RenderW(None, Qt.WindowFlags())
gui = RenderW(None)
gui.setWindowIcon(getIcon("media-record", 48))
gui.show()



+ 13
- 4
src/shared.py View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Common/Shared code
@@ -56,7 +56,7 @@ if (PATH_env == None):
PATH = ("/bin", "/sbin", "/usr/local/bin", "/usr/local/sbin", "/usr/bin", "/usr/sbin", "/usr/games")
else:
PATH = PATH_env.split(os.pathsep)
del PATH_env
del PATH_env

MIDI_CC_LIST = (
#"0x00 Bank Select",
@@ -151,6 +151,15 @@ MIDI_CC_LIST = (
"0x5F FX 5 Depth [Phaser]"
)

# Convert a value to a list
def toList(value):
if value is None:
return []
elif not isinstance(value, list):
return [value]
else:
return value

# Get Icon from user theme, using our own as backup (Oxygen)
def getIcon(icon, size=16):
return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.png" % (size, size, icon)))
@@ -163,12 +172,12 @@ def getAndSetPath(self, currentPath, lineEdit):
return newPath

# Custom MessageBox
def CustomMessageBox(self, icon, title, text, extra_text="", buttons=QMessageBox.Yes|QMessageBox.No, defButton=QMessageBox.No):
def CustomMessageBox(self, icon, title, text, extraText="", buttons=QMessageBox.Yes|QMessageBox.No, defButton=QMessageBox.No):
msgBox = QMessageBox(self)
msgBox.setIcon(icon)
msgBox.setWindowTitle(title)
msgBox.setText(text)
msgBox.setInformativeText(extra_text)
msgBox.setInformativeText(extraText)
msgBox.setStandardButtons(buttons)
msgBox.setDefaultButton(defButton)
return msgBox.exec_()


+ 499
- 0
src/ui/xycontroller.ui View File

@@ -0,0 +1,499 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>XYControllerW</class>
<widget class="QMainWindow" name="XYControllerW">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>588</width>
<height>498</height>
</rect>
</property>
<property name="windowTitle">
<string>XY Controller</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QGraphicsView" name="graphicsView">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="PixmapDial" name="dial_x">
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>30</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="PixmapDial" name="dial_y">
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_x_controls">
<property name="text">
<string>X Controls:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cb_control_x"/>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_y_controls">
<property name="text">
<string>Y Controls:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cb_control_y"/>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cb_smooth">
<property name="text">
<string>Smooth</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>70</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>6</y>
<width>864</width>
<height>64</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>864</width>
<height>64</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>864</width>
<height>64</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="PixmapKeyboard" name="keyboard" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>864</width>
<height>64</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>864</width>
<height>64</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>588</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="act_quit"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="act_about"/>
</widget>
<widget class="QMenu" name="menu_Settings">
<property name="title">
<string>&amp;Settings</string>
</property>
<widget class="QMenu" name="menu_Channels">
<property name="title">
<string>Channels</string>
</property>
<addaction name="act_ch_01"/>
<addaction name="act_ch_02"/>
<addaction name="act_ch_03"/>
<addaction name="act_ch_04"/>
<addaction name="act_ch_05"/>
<addaction name="act_ch_06"/>
<addaction name="act_ch_07"/>
<addaction name="act_ch_08"/>
<addaction name="act_ch_09"/>
<addaction name="act_ch_10"/>
<addaction name="act_ch_11"/>
<addaction name="act_ch_12"/>
<addaction name="act_ch_13"/>
<addaction name="act_ch_14"/>
<addaction name="act_ch_15"/>
<addaction name="act_ch_16"/>
<addaction name="separator"/>
<addaction name="act_ch_all"/>
<addaction name="act_ch_none"/>
</widget>
<addaction name="menu_Channels"/>
<addaction name="act_show_keyboard"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_Settings"/>
<addaction name="menu_Help"/>
</widget>
<action name="act_about">
<property name="text">
<string>&amp;About</string>
</property>
</action>
<action name="act_show_keyboard">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show MIDI &amp;Keyboard</string>
</property>
</action>
<action name="act_ch_all">
<property name="text">
<string>(All)</string>
</property>
</action>
<action name="act_ch_01">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>1</string>
</property>
</action>
<action name="act_ch_02">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>2</string>
</property>
</action>
<action name="act_ch_03">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>3</string>
</property>
</action>
<action name="act_ch_04">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>4</string>
</property>
</action>
<action name="act_ch_05">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>5</string>
</property>
</action>
<action name="act_ch_06">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>6</string>
</property>
</action>
<action name="act_ch_07">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>7</string>
</property>
</action>
<action name="act_ch_08">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>8</string>
</property>
</action>
<action name="act_ch_09">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>9</string>
</property>
</action>
<action name="act_ch_10">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>10</string>
</property>
</action>
<action name="act_ch_11">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>11</string>
</property>
</action>
<action name="act_ch_12">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>12</string>
</property>
</action>
<action name="act_ch_13">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>13</string>
</property>
</action>
<action name="act_ch_14">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>14</string>
</property>
</action>
<action name="act_ch_15">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>15</string>
</property>
</action>
<action name="act_ch_16">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>16</string>
</property>
</action>
<action name="act_new">
<property name="text">
<string>&amp;New</string>
</property>
</action>
<action name="act_open">
<property name="text">
<string>&amp;Open...</string>
</property>
</action>
<action name="act_save">
<property name="text">
<string>&amp;Save</string>
</property>
</action>
<action name="act_save_as">
<property name="text">
<string>Save &amp;As...</string>
</property>
</action>
<action name="act_quit">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/16x16/application-exit.png</normaloff>:/16x16/application-exit.png</iconset>
</property>
<property name="text">
<string>&amp;Quit</string>
</property>
</action>
<action name="act_ch_none">
<property name="text">
<string>(None)</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>PixmapKeyboard</class>
<extends>QWidget</extends>
<header>pixmapkeyboard.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>PixmapDial</class>
<extends>QDial</extends>
<header>pixmapdial.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../icons/icons.qrc"/>
</resources>
<connections>
<connection>
<sender>act_quit</sender>
<signal>triggered()</signal>
<receiver>XYControllerW</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>239</x>
<y>222</y>
</hint>
</hints>
</connection>
</connections>
</ui>

+ 581
- 0
src/xycontroller.py View File

@@ -0,0 +1,581 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# XY Controller for JACK, using jacklib
# Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the COPYING file

# Imports (Global)
from PyQt4.QtCore import pyqtSlot, Qt, QPointF, QRectF, QSettings, QTimer, QVariant
from PyQt4.QtGui import QApplication, QColor, QIcon, QPainter, QPen, QGraphicsItem, QGraphicsScene, QMainWindow
from queue import Queue, Empty as QuequeEmpty

# Imports (Custom)
import ui_xycontroller
from shared import *
from jacklib_helpers import *

# Globals
global jack_client, jack_midi_in_port, jack_midi_out_port, jack_midi_in_data, jack_midi_out_data
jack_client = None
jack_midi_in_port = None
jack_midi_out_port = None
jack_midi_in_data = Queue(512)
jack_midi_out_data = Queue(512)

# XY Controller Scene
class XYGraphicsScene(QGraphicsScene):
def __init__(self, parent):
QGraphicsScene.__init__(self, parent)

self.cc_x = 1
self.cc_y = 2
self.m_channels = []
self.m_mouseLock = False
self.m_smooth = False
self.m_smooth_x = 0
self.m_smooth_y = 0

self.setBackgroundBrush(Qt.black)

cursorPen = QPen(QColor(255,255,255), 2)
cursorBrush = QColor(255,255,255,50)
self.m_cursor = self.addEllipse(QRectF(-10, -10, 20, 20), cursorPen, cursorBrush)

linePen = QPen(QColor(200,200,200,100), 1, Qt.DashLine)
self.m_lineH = self.addLine(-9999, 0, 9999, 0, linePen)
self.m_lineV = self.addLine(0, -9999, 0, 9999, linePen)

self.p_size = QRectF(-100, -100, 100, 100)

def setControlX(self, x):
self.cc_x = x

def setControlY(self, y):
self.cc_y = y

def setChannels(self, channels):
self.m_channels = channels

def setPosX(self, x, forward=True):
if (self.m_mouseLock == False):
pos_x = x*(self.p_size.x()+self.p_size.width())
self.m_cursor.setPos(pos_x, self.m_cursor.y())
self.m_lineV.setX(pos_x)

if (forward):
self.sendMIDI(pos_x/(self.p_size.x()+self.p_size.width()), None)
else:
self.m_smooth_x = pos_x

def setPosY(self, y, forward=True):
if (self.m_mouseLock == False):
pos_y = y*(self.p_size.y()+self.p_size.height())
self.m_cursor.setPos(self.m_cursor.x(), pos_y)
self.m_lineH.setY(pos_y)

if (forward):
self.sendMIDI(None, pos_y/(self.p_size.y()+self.p_size.height()))
else:
self.m_smooth_y = pos_y

def setSmooth(self, smooth):
self.m_smooth = smooth

def handleCC(self, param, value):
if (param == self.cc_x):
xp = (float(value)/63)-1.025
yp = self.m_cursor.y()/(self.p_size.y()+self.p_size.height())
self.setPosX(xp, False)

elif (param == self.cc_y):
xp = self.m_cursor.x()/(self.p_size.x()+self.p_size.width())
yp = (float(value)/63)-1.025
self.setPosY(yp, False)

else:
return

self.emit(SIGNAL("cursorMoved(float, float)"), xp, yp)

def handleMousePos(self, pos):
if (not self.p_size.contains(pos)):
if (pos.x() < self.p_size.x()):
pos.setX(self.p_size.x())
elif (pos.x() > self.p_size.x()+self.p_size.width()):
pos.setX(self.p_size.x()+self.p_size.width())

if (pos.y() < self.p_size.y()):
pos.setY(self.p_size.y())
elif (pos.y() > self.p_size.y()+self.p_size.height()):
pos.setY(self.p_size.y()+self.p_size.height())

self.m_smooth_x = pos.x()
self.m_smooth_y = pos.y()

if (self.m_smooth == False):
self.m_cursor.setPos(pos)
self.m_lineH.setY(pos.y())
self.m_lineV.setX(pos.x())

xp = pos.x()/(self.p_size.x()+self.p_size.width())
yp = pos.y()/(self.p_size.y()+self.p_size.height())

self.sendMIDI(xp, yp)
self.emit(SIGNAL("cursorMoved(float, float)"), xp, yp)

def sendMIDI(self, xp=None, yp=None):
global jack_midi_out_data
rate = float(0xff)/4

if (xp != None):
value = int((xp*rate)+rate)
for channel in self.m_channels:
jack_midi_out_data.put_nowait((0xB0+channel-1, self.cc_x, value))

if (yp != None):
value = int((yp*rate)+rate)
for channel in self.m_channels:
jack_midi_out_data.put_nowait((0xB0+channel-1, self.cc_y, value))

def updateSize(self, size):
self.p_size.setRect(-(size.width()/2), -(size.height()/2), size.width(), size.height())

def updateSmooth(self):
if (self.m_smooth):
if (self.m_cursor.x() != self.m_smooth_x or self.m_cursor.y() != self.m_smooth_y):
new_x = (self.m_smooth_x+self.m_cursor.x()*3)/4
new_y = (self.m_smooth_y+self.m_cursor.y()*3)/4
pos = QPointF(new_x, new_y)

self.m_cursor.setPos(pos)
self.m_lineH.setY(pos.y())
self.m_lineV.setX(pos.x())

xp = pos.x()/(self.p_size.x()+self.p_size.width())
yp = pos.y()/(self.p_size.y()+self.p_size.height())

self.sendMIDI(xp, yp)
self.emit(SIGNAL("cursorMoved(float, float)"), xp, yp)

def keyPressEvent(self, event):
event.accept()

def wheelEvent(self, event):
event.accept()

def mousePressEvent(self, event):
self.m_mouseLock = True
self.handleMousePos(event.scenePos())
QGraphicsScene.mousePressEvent(self, event)

def mouseMoveEvent(self, event):
self.handleMousePos(event.scenePos())
QGraphicsScene.mouseMoveEvent(self, event)

def mouseReleaseEvent(self, event):
self.m_mouseLock = False
QGraphicsScene.mouseReleaseEvent(self, event)

# XY Controller Window
class XYControllerW(QMainWindow, ui_xycontroller.Ui_XYControllerW):
def __init__(self, parent):
QMainWindow.__init__(self, parent)
self.setupUi(self)

# -------------------------------------------------------------
# Internal stuff

self.cc_x = 1
self.cc_y = 2
self.m_channels = []

# -------------------------------------------------------------
# Set-up GUI stuff

self.dial_x.setPixmap(2)
self.dial_y.setPixmap(2)
self.dial_x.setLabel("X")
self.dial_y.setLabel("Y")
self.keyboard.setOctaves(6)

self.scene = XYGraphicsScene(self)
self.graphicsView.setScene(self.scene)
self.graphicsView.setRenderHints(QPainter.Antialiasing)

for MIDI_CC in MIDI_CC_LIST:
self.cb_control_x.addItem(MIDI_CC)
self.cb_control_y.addItem(MIDI_CC)

# -------------------------------------------------------------
# Load Settings

self.settings = QSettings("Cadence", "XY-Controller")
self.loadSettings()

# -------------------------------------------------------------
# Connect actions to functions

self.connect(self.keyboard, SIGNAL("noteOn(int)"), SLOT("slot_noteOn(int)"))
self.connect(self.keyboard, SIGNAL("noteOff(int)"), SLOT("slot_noteOff(int)"))

self.connect(self.cb_smooth, SIGNAL("clicked(bool)"), SLOT("slot_setSmooth(bool)"))

self.connect(self.dial_x, SIGNAL("valueChanged(int)"), SLOT("slot_updateSceneX(int)"))
self.connect(self.dial_y, SIGNAL("valueChanged(int)"), SLOT("slot_updateSceneY(int)"))

self.connect(self.cb_control_x, SIGNAL("currentIndexChanged(QString)"), SLOT("slot_checkCC_X(QString)"))
self.connect(self.cb_control_y, SIGNAL("currentIndexChanged(QString)"), SLOT("slot_checkCC_Y(QString)"))

# FIXME
self.connect(self.scene, SIGNAL("cursorMoved(float, float)"), self.slot_sceneCursorMoved)
#self.connect(self.scene, SIGNAL("cursorMoved(float, float)"), SLOT("slot_sceneCursorMoved(float, float)"))

self.connect(self.act_ch_01, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_02, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_03, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_04, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_05, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_06, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_07, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_08, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_09, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_10, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_11, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_12, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_13, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_14, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_15, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_16, SIGNAL("triggered(bool)"), SLOT("slot_checkChannel(bool)"))
self.connect(self.act_ch_all, SIGNAL("triggered()"), SLOT("slot_checkChannel_all()"))
self.connect(self.act_ch_none, SIGNAL("triggered()"), SLOT("slot_checkChannel_none()"))

self.connect(self.act_show_keyboard, SIGNAL("triggered(bool)"), SLOT("slot_showKeyboard(bool)"))
self.connect(self.act_about, SIGNAL("triggered()"), SLOT("slot_about()"))

# -------------------------------------------------------------
# Final stuff

self.m_midiInTimerId = self.startTimer(50)
QTimer.singleShot(0, self, SLOT("slot_updateScreen()"))

def updateScreen(self):
self.scene.updateSize(self.graphicsView.size())
self.graphicsView.centerOn(0, 0)

self.slot_updateSceneX(self.dial_x.value())
self.slot_updateSceneY(self.dial_y.value())

@pyqtSlot(int)
def slot_noteOn(self, note):
global jack_midi_out_data
for channel in self.m_channels:
jack_midi_out_data.put_nowait((0x90+channel-1, note, 100))

@pyqtSlot(int)
def slot_noteOff(self, note):
global jack_midi_out_data
for channel in self.m_channels:
jack_midi_out_data.put_nowait((0x80+channel-1, note, 0))

@pyqtSlot(int)
def slot_updateSceneX(self, x):
self.scene.setPosX(float(x)/100)

@pyqtSlot(int)
def slot_updateSceneY(self, y):
self.scene.setPosY(float(y)/100)

@pyqtSlot(str)
def slot_checkCC_X(self, text):
if (text):
self.cc_x = int(text.split(" ")[0], 16)
self.scene.setControlX(self.cc_x)

@pyqtSlot(str)
def slot_checkCC_Y(self, text):
if (text):
self.cc_y = int(text.split(" ")[0], 16)
self.scene.setControlY(self.cc_y)

@pyqtSlot(bool)
def slot_checkChannel(self, clicked):
channel = int(self.sender().text())
if (clicked and channel not in self.m_channels):
self.m_channels.append(channel)
elif (not clicked and channel in self.m_channels):
self.m_channels.remove(channel)
self.scene.setChannels(self.m_channels)

@pyqtSlot()
def slot_checkChannel_all(self):
self.act_ch_01.setChecked(True)
self.act_ch_02.setChecked(True)
self.act_ch_03.setChecked(True)
self.act_ch_04.setChecked(True)
self.act_ch_05.setChecked(True)
self.act_ch_06.setChecked(True)
self.act_ch_07.setChecked(True)
self.act_ch_08.setChecked(True)
self.act_ch_09.setChecked(True)
self.act_ch_10.setChecked(True)
self.act_ch_11.setChecked(True)
self.act_ch_12.setChecked(True)
self.act_ch_13.setChecked(True)
self.act_ch_14.setChecked(True)
self.act_ch_15.setChecked(True)
self.act_ch_16.setChecked(True)
self.m_channels = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
self.scene.setChannels(self.m_channels)

@pyqtSlot()
def slot_checkChannel_none(self):
self.act_ch_01.setChecked(False)
self.act_ch_02.setChecked(False)
self.act_ch_03.setChecked(False)
self.act_ch_04.setChecked(False)
self.act_ch_05.setChecked(False)
self.act_ch_06.setChecked(False)
self.act_ch_07.setChecked(False)
self.act_ch_08.setChecked(False)
self.act_ch_09.setChecked(False)
self.act_ch_10.setChecked(False)
self.act_ch_11.setChecked(False)
self.act_ch_12.setChecked(False)
self.act_ch_13.setChecked(False)
self.act_ch_14.setChecked(False)
self.act_ch_15.setChecked(False)
self.act_ch_16.setChecked(False)
self.m_channels = []
self.scene.setChannels(self.m_channels)

@pyqtSlot(bool)
def slot_setSmooth(self, yesno):
self.scene.setSmooth(yesno)

@pyqtSlot(float, float)
def slot_sceneCursorMoved(self, xp, yp):
self.dial_x.setValue(xp*100)
self.dial_y.setValue(yp*100)

@pyqtSlot(bool)
def slot_showKeyboard(self, yesno):
self.scrollArea.setVisible(yesno)
QTimer.singleShot(0, self, SLOT("slot_updateScreen()"))

@pyqtSlot()
def slot_about(self):
QMessageBox.about(self, self.tr("About XY Controller"), self.tr("<h3>XY Controller</h3>"
"<br>Version %s"
"<br>XY Controller is a simple XY widget that sends and receives data from Jack MIDI.<br>"
"<br>Copyright (C) 2012 falkTX" % (VERSION)))

@pyqtSlot()
def slot_updateScreen(self):
self.updateScreen()

def saveSettings(self):
self.settings.setValue("Geometry", self.saveGeometry())
self.settings.setValue("ShowKeyboard", self.scrollArea.isVisible())
self.settings.setValue("Smooth", self.cb_smooth.isChecked())
self.settings.setValue("DialX", self.dial_x.value())
self.settings.setValue("DialY", self.dial_y.value())
self.settings.setValue("ControlX", self.cc_x)
self.settings.setValue("ControlY", self.cc_y)
self.settings.setValue("Channels", self.m_channels)

def loadSettings(self):
self.restoreGeometry(self.settings.value("Geometry", ""))

showKeyboard = self.settings.value("ShowKeyboard", False, type=bool)
self.act_show_keyboard.setChecked(showKeyboard)
self.scrollArea.setVisible(showKeyboard)

smooth = self.settings.value("Smooth", False, type=bool)
self.cb_smooth.setChecked(smooth)
self.scene.setSmooth(smooth)

self.dial_x.setValue(self.settings.value("DialX", 50, type=int))
self.dial_y.setValue(self.settings.value("DialY", 50, type=int))
self.cc_x = self.settings.value("ControlX", 1, type=int)
self.cc_y = self.settings.value("ControlY", 2, type=int)
self.m_channels = toList(self.settings.value("Channels", [1]))

for i in range(len(self.m_channels)):
self.m_channels[i] = int(self.m_channels[i])

self.scene.setChannels(self.m_channels)

for i in range(len(MIDI_CC_LIST)):
cc = int(MIDI_CC_LIST[i].split(" ")[0], 16)
if (self.cc_x == cc):
self.cb_control_x.setCurrentIndex(i)
if (self.cc_y == cc):
self.cb_control_y.setCurrentIndex(i)

if (1 in self.m_channels):
self.act_ch_01.setChecked(True)
if (2 in self.m_channels):
self.act_ch_02.setChecked(True)
if (3 in self.m_channels):
self.act_ch_03.setChecked(True)
if (4 in self.m_channels):
self.act_ch_04.setChecked(True)
if (5 in self.m_channels):
self.act_ch_05.setChecked(True)
if (6 in self.m_channels):
self.act_ch_06.setChecked(True)
if (7 in self.m_channels):
self.act_ch_07.setChecked(True)
if (8 in self.m_channels):
self.act_ch_08.setChecked(True)
if (9 in self.m_channels):
self.act_ch_09.setChecked(True)
if (10 in self.m_channels):
self.act_ch_10.setChecked(True)
if (11 in self.m_channels):
self.act_ch_11.setChecked(True)
if (12 in self.m_channels):
self.act_ch_12.setChecked(True)
if (13 in self.m_channels):
self.act_ch_13.setChecked(True)
if (14 in self.m_channels):
self.act_ch_14.setChecked(True)
if (15 in self.m_channels):
self.act_ch_15.setChecked(True)
if (16 in self.m_channels):
self.act_ch_16.setChecked(True)

def timerEvent(self, event):
if (event.timerId() == self.m_midiInTimerId):
global jack_midi_in_data
if (jack_midi_in_data.empty() == False):
while (True):
try:
mode, note, velo = jack_midi_in_data.get_nowait()
except QuequeEmpty:
break

# TODO - filter by channel here
#channel = mode - 0xB0+1
#if (channel in self.m_channels):
if (0x80 <= mode and mode <= 0x8F):
self.keyboard.noteOff(note, False)
elif (0x90 <= mode and mode < 0x9F):
self.keyboard.noteOn(note, False)
elif (0xB0 <= mode and mode < 0xBF):
self.scene.handleCC(note, velo)

jack_midi_in_data.task_done()

self.scene.updateSmooth()

QMainWindow.timerEvent(self, event)

def resizeEvent(self, event):
self.updateScreen()
QMainWindow.resizeEvent(self, event)

def closeEvent(self, event):
self.saveSettings()
QMainWindow.closeEvent(self, event)

# -------------------------------------------------------------
# JACK Stuff

static_event = jacklib.jack_midi_event_t()
static_mtype = jacklib.c_ubyte*3

def jack_process_callback(nframes, arg):
global jack_midi_in_port, jack_midi_out_port, jack_midi_in_data, jack_midi_out_data

# MIDI In
midi_in_buffer = jacklib.port_get_buffer(jack_midi_in_port, nframes)

if (midi_in_buffer):
event_count = jacklib.midi_get_event_count(midi_in_buffer)

for i in range(event_count):
if (jacklib.midi_event_get(jacklib.pointer(static_event), midi_in_buffer, i) == 0):
if (static_event.size == 1):
jack_midi_in_data.put_nowait((static_event.buffer[0], 0, 0))
elif (static_event.size == 2):
jack_midi_in_data.put_nowait((static_event.buffer[0], static_event.buffer[1], 0))
elif (static_event.size >= 3):
jack_midi_in_data.put_nowait((static_event.buffer[0], static_event.buffer[1], static_event.buffer[2]))

if (jack_midi_in_data.full()):
break

# MIDI Out
midi_out_buffer = jacklib.port_get_buffer(jack_midi_out_port, nframes)

if (midi_out_buffer):
jacklib.midi_clear_buffer(midi_out_buffer)

if (jack_midi_out_data.empty() == False):
while (True):
try:
mode, note, velo = jack_midi_out_data.get_nowait()
except QuequeEmpty:
break

data = static_mtype(mode, note, velo)
jacklib.midi_event_write(midi_out_buffer, 0, data, 3)

jack_midi_out_data.task_done()

return 0


#--------------- main ------------------
if __name__ == '__main__':

# App initialization
app = QApplication(sys.argv)
app.setApplicationName("XY-Controller")
app.setApplicationVersion(VERSION)
app.setOrganizationName("falkTX")
#app.setWindowIcon(QIcon(":/48x48/xy-controller.png"))

# Start jack
jack_status = jacklib.jack_status_t(0)
jack_client = jacklib.client_open("XY-Controller", jacklib.JackNullOption, jacklib.pointer(jack_status))

if not jack_client:
QMessageBox.critical(None, app.translate("RenderW", "Error"), app.translate("RenderW", "Could not connect to JACK, possible errors:\n%s" % (get_jack_status_error_string(jack_status))))
sys.exit(1)

jack_midi_in_port = jacklib.port_register(jack_client, "midi_in", jacklib.JACK_DEFAULT_MIDI_TYPE, jacklib.JackPortIsInput, 0)
jack_midi_out_port = jacklib.port_register(jack_client, "midi_out", jacklib.JACK_DEFAULT_MIDI_TYPE, jacklib.JackPortIsOutput, 0)
jacklib.set_process_callback(jack_client, jack_process_callback, None)
jacklib.activate(jack_client)

# Show GUI
gui = XYControllerW(None)
gui.show()

# Set-up custom signal handling
set_up_signals(gui)

# App-Loop
ret = app.exec_()

# Close Jack
if (jack_client):
jacklib.deactivate(jack_client)
jacklib.client_close(jack_client)

# Exit properly
sys.exit(ret)

Loading…
Cancel
Save