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 -*- # -*- coding: utf-8 -*-


# Clickable Label, a custom Qt4 widget # 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 -*- # -*- coding: utf-8 -*-


# Digital Peak Meter, a custom Qt4 widget # 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 -*- # -*- coding: utf-8 -*-


# JACK ctypes definitions for usage in python applications # 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 -*- # -*- coding: utf-8 -*-


# Helper functions for extra jacklib functionality # 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 -*- # -*- coding: utf-8 -*-


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


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


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


# Show GUI # Show GUI
gui = MeterW(None)
gui = MeterW()
gui.resize(70, 600) gui.resize(70, 600)
gui.show() 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 -*- # -*- coding: utf-8 -*-


# LADSPA RDF python support # 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 -*- # -*- coding: utf-8 -*-


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


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


set_up_signals(gui) 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 -*- # -*- coding: utf-8 -*-


# Pixmap Dial, a custom Qt4 widget # 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 -*- # -*- coding: utf-8 -*-


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


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


self.m_octaves = 6 self.m_octaves = 6
self.m_lastMouseNote = -1 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 -*- # -*- coding: utf-8 -*-


# JACK-Capture frontend, with freewheel and transport support # 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 # For a full copy of the GNU General Public License see the COPYING file


# Imports (Global) # 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 PyQt4.QtGui import QDialog
from time import sleep from time import sleep


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


# Render Window # Render Window
class RenderW(QDialog, ui_render.Ui_RenderW): 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) self.setupUi(self)


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


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




+ 13
- 4
src/shared.py View File

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


# Common/Shared code # 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") PATH = ("/bin", "/sbin", "/usr/local/bin", "/usr/local/sbin", "/usr/bin", "/usr/sbin", "/usr/games")
else: else:
PATH = PATH_env.split(os.pathsep) PATH = PATH_env.split(os.pathsep)
del PATH_env
del PATH_env


MIDI_CC_LIST = ( MIDI_CC_LIST = (
#"0x00 Bank Select", #"0x00 Bank Select",
@@ -151,6 +151,15 @@ MIDI_CC_LIST = (
"0x5F FX 5 Depth [Phaser]" "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) # Get Icon from user theme, using our own as backup (Oxygen)
def getIcon(icon, size=16): def getIcon(icon, size=16):
return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.png" % (size, size, icon))) return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.png" % (size, size, icon)))
@@ -163,12 +172,12 @@ def getAndSetPath(self, currentPath, lineEdit):
return newPath return newPath


# Custom MessageBox # 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 = QMessageBox(self)
msgBox.setIcon(icon) msgBox.setIcon(icon)
msgBox.setWindowTitle(title) msgBox.setWindowTitle(title)
msgBox.setText(text) msgBox.setText(text)
msgBox.setInformativeText(extra_text)
msgBox.setInformativeText(extraText)
msgBox.setStandardButtons(buttons) msgBox.setStandardButtons(buttons)
msgBox.setDefaultButton(defButton) msgBox.setDefaultButton(defButton)
return msgBox.exec_() 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