| @@ -2,6 +2,7 @@ | |||||
| .directory | .directory | ||||
| .fuse-* | .fuse-* | ||||
| .*.kate-swp | .*.kate-swp | ||||
| .kdev_include_paths | |||||
| .kdev4/ | .kdev4/ | ||||
| # Temp files | # Temp files | ||||
| @@ -29,10 +30,12 @@ ui_*.h | |||||
| # Python files | # Python files | ||||
| *.pyc | *.pyc | ||||
| ui_*.py | ui_*.py | ||||
| # Resource files | |||||
| src/resources_rc.py | |||||
| qrc_resources*.cpp | |||||
| source/digitalpeakmeter.py | |||||
| source/ledbutton.py | |||||
| source/paramspinbox.py | |||||
| source/pixmapdial.py | |||||
| source/pixmapkeyboard.py | |||||
| source/resources_rc.py | |||||
| # Binaries | # Binaries | ||||
| carla-bridge-qtcreator | carla-bridge-qtcreator | ||||
| @@ -0,0 +1,61 @@ | |||||
| # --- INSTALL for Carla --- | |||||
| To install Carla, simply run as usual: <br/> | |||||
| `$ make` <br/> | |||||
| `$ [sudo] make install` | |||||
| You can run it without installing, by using instead: <br/> | |||||
| `$ make` <br/> | |||||
| `$ python3 source/carla.py` | |||||
| Packagers can make use of the 'PREFIX' and 'DESTDIR' variable during install, like this: <br/> | |||||
| `$ make install PREFIX=/usr DESTDIR=./test-dir` | |||||
| <br/> | |||||
| ===== BUILD DEPENDENCIES ===== | |||||
| -------------------------------- | |||||
| The required build dependencies are: <i>(devel packages of these)</i> | |||||
| - JACK | |||||
| - liblo | |||||
| - Qt4 | |||||
| - PyQt4 | |||||
| - OpenGL | |||||
| Optional but recommended: | |||||
| - FluidSynth | |||||
| - LinuxSampler | |||||
| Optional for extended LV2 UIs support: | |||||
| - Gtk2 | |||||
| - Gtk3 | |||||
| - Suil | |||||
| Optional for native zynaddsubfx plugin: | |||||
| - fftw3 | |||||
| - mxml | |||||
| On Debian and Ubuntu, use these commands to install all dependencies: <br/> | |||||
| `$ sudo apt-get install libjack-dev liblo-dev libqt4-dev libfluidsynth-dev qt4-dev-tools` <br/> | |||||
| `$ sudo apt-get install libgtk2.0-dev libgtk-3-dev libsuil-dev` <br/> | |||||
| `$ sudo apt-get install libfftw3-dev libmxml-dev` <br/> | |||||
| `$ sudo apt-get install python3-pyqt4 pyqt4-dev-tools` | |||||
| NOTE: linuxsampler is not packaged in either Debian or Ubuntu, but it's available in KXStudio. <br/> | |||||
| <br/> | |||||
| To run all the Carla-Control, you'll additionally need: | |||||
| - python3-liblo | |||||
| Optional but recommended: | |||||
| - python3-rdflib (for LADSPA-RDF support) | |||||
| The python version used and tested is python3.2. <br/> | |||||
| After install, Carla will still work on distros with python2 as default, without any additional work. | |||||
| <br/> | |||||
| @@ -0,0 +1,166 @@ | |||||
| #!/usr/bin/make -f | |||||
| # Makefile for Carla # | |||||
| # ---------------------- # | |||||
| # Created by falkTX | |||||
| # | |||||
| PREFIX = /usr/local | |||||
| DESTDIR = | |||||
| SED_PREFIX = $(shell echo $(PREFIX) | sed "s/\//\\\\\\\\\//g") | |||||
| LINK = ln -s | |||||
| PYUIC = pyuic4 | |||||
| PYRCC = pyrcc4 -py3 | |||||
| all: CPP RES UI WIDGETS | |||||
| # ------------------------------------------------------------------------------------------------------------------------------------------------------ | |||||
| CPP: discovery | |||||
| discovery: | |||||
| $(MAKE) -C source/discovery | |||||
| # ------------------------------------------------------------------------------------------------------------------------------------------------------ | |||||
| RES = source/resources_rc.py | |||||
| RES: $(RES) | |||||
| source/resources_rc.py: resources/resources.qrc | |||||
| $(PYRCC) $< -o $@ | |||||
| # ------------------------------------------------------------------------------------------------------------------------------------------------------ | |||||
| UIs = source/ui_carla.py source/ui_carla_control.py\ | |||||
| source/ui_carla_about.py source/ui_carla_database.py source/ui_carla_edit.py source/ui_carla_parameter.py source/ui_carla_plugin.py source/ui_carla_refresh.py \ | |||||
| source/ui_inputdialog_value.py | |||||
| UI: $(UIs) | |||||
| source/ui_%.py: resources/ui/%.ui | |||||
| $(PYUIC) $< -o $@ | |||||
| # ------------------------------------------------------------------------------------------------------------------------------------------------------ | |||||
| WIDGETS = source/digitalpeakmeter.py source/ledbutton.py source/paramspinbox.py source/pixmapdial.py source/pixmapkeyboard.py | |||||
| WIDGETS: $(WIDGETS) | |||||
| source/%.py: source/widgets/%.py | |||||
| $(LINK) widgets/$*.py $@ | |||||
| # ------------------------------------------------------------------------------------------------------------------------------------------------------ | |||||
| debug: | |||||
| $(MAKE) DEBUG=true | |||||
| # doxygen: | |||||
| # $(MAKE) doxygen -C source/backend | |||||
| # ------------------------------------------------------------------------------------------------------------------------------------------------------ | |||||
| posix32: | |||||
| $(MAKE) -C source/bridge posix32 | |||||
| $(MAKE) -C source/discovery posix32 | |||||
| posix64: | |||||
| $(MAKE) -C source/bridge posix64 | |||||
| $(MAKE) -C source/discovery posix64 | |||||
| win32: | |||||
| $(MAKE) -C source/bridge win32 | |||||
| $(MAKE) -C source/discovery win32 | |||||
| win64: | |||||
| $(MAKE) -C source/bridge win64 | |||||
| $(MAKE) -C source/discovery win64 | |||||
| wine32: | |||||
| $(MAKE) -C source/jackbridge wine32 | |||||
| $(LINK) source/libs/jackbridge/libcarla-jackbridge-win32.dll.so source/bridge/libcarla-jackbridge-win32.dll | |||||
| wine64: | |||||
| $(MAKE) -C source/jackbridge wine64 | |||||
| $(LINK) source/libs/jackbridge/libcarla-jackbridge-win64.dll.so source/bridge/libcarla-jackbridge-win64.dll | |||||
| # ------------------------------------------------------------------------------------------------------------------------------------------------------ | |||||
| clean: | |||||
| $(MAKE) clean -C source/discovery | |||||
| rm -f $(RES) | |||||
| rm -f $(UIs) | |||||
| rm -f $(WIDGETS) | |||||
| rm -f *~ source/*~ source/*.pyc | |||||
| # rm -rf source/*/doxygen | |||||
| install: | |||||
| # Create directories | |||||
| install -d $(DESTDIR)$(PREFIX)/bin/ | |||||
| install -d $(DESTDIR)$(PREFIX)/lib/carla/ | |||||
| install -d $(DESTDIR)$(PREFIX)/share/applications/ | |||||
| install -d $(DESTDIR)$(PREFIX)/share/icons/hicolor/16x16/apps/ | |||||
| install -d $(DESTDIR)$(PREFIX)/share/icons/hicolor/48x48/apps/ | |||||
| install -d $(DESTDIR)$(PREFIX)/share/icons/hicolor/128x128/apps/ | |||||
| install -d $(DESTDIR)$(PREFIX)/share/icons/hicolor/256x256/apps/ | |||||
| install -d $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/ | |||||
| install -d $(DESTDIR)$(PREFIX)/share/carla/ | |||||
| # Install script files and binaries | |||||
| install -m 755 \ | |||||
| data/carla \ | |||||
| data/carla-control \ | |||||
| data/carla-standalone \ | |||||
| $(DESTDIR)$(PREFIX)/bin/ | |||||
| # Install desktop files | |||||
| install -m 644 data/*.desktop $(DESTDIR)$(PREFIX)/share/applications/ | |||||
| # Install icons, 16x16 | |||||
| install -m 644 resources/16x16/carla.png $(DESTDIR)$(PREFIX)/share/icons/hicolor/16x16/apps/ | |||||
| install -m 644 resources/16x16/carla-control.png $(DESTDIR)$(PREFIX)/share/icons/hicolor/16x16/apps/ | |||||
| # Install icons, 48x48 | |||||
| install -m 644 resources/48x48/carla.png $(DESTDIR)$(PREFIX)/share/icons/hicolor/48x48/apps/ | |||||
| install -m 644 resources/48x48/carla-control.png $(DESTDIR)$(PREFIX)/share/icons/hicolor/48x48/apps/ | |||||
| # Install icons, 128x128 | |||||
| install -m 644 resources/128x128/carla.png $(DESTDIR)$(PREFIX)/share/icons/hicolor/128x128/apps/ | |||||
| install -m 644 resources/128x128/carla-control.png $(DESTDIR)$(PREFIX)/share/icons/hicolor/128x128/apps/ | |||||
| # Install icons, 256x256 | |||||
| install -m 644 resources/256x256/carla.png $(DESTDIR)$(PREFIX)/share/icons/hicolor/256x256/apps/ | |||||
| install -m 644 resources/256x256/carla-control.png $(DESTDIR)$(PREFIX)/share/icons/hicolor/256x256/apps/ | |||||
| # Install icons, scalable | |||||
| install -m 644 resources/scalable/carla.svg $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/ | |||||
| install -m 644 resources/scalable/carla-control.svg $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/ | |||||
| # Install main code | |||||
| install -m 755 source/*.py $(DESTDIR)$(PREFIX)/share/carla/ | |||||
| install -m 755 \ | |||||
| source/backend/*.so \ | |||||
| source/bridge/carla-bridge-* \ | |||||
| source/discovery/carla-discovery-* \ | |||||
| $(DESTDIR)$(PREFIX)/lib/cadence/ | |||||
| # Adjust PREFIX value in script files | |||||
| sed -i "s/X-PREFIX-X/$(SED_PREFIX)/" \ | |||||
| $(DESTDIR)$(PREFIX)/bin/carla \ | |||||
| $(DESTDIR)$(PREFIX)/bin/carla-control \ | |||||
| $(DESTDIR)$(PREFIX)/bin/carla-standalone \ | |||||
| uninstall: | |||||
| rm -f $(DESTDIR)$(PREFIX)/bin/carla* | |||||
| rm -f $(DESTDIR)$(PREFIX)/share/applications/carla.desktop | |||||
| rm -f $(DESTDIR)$(PREFIX)/share/applications/carla-control.desktop | |||||
| rm -f $(DESTDIR)$(PREFIX)/share/icons/hicolor/*/apps/carla.png | |||||
| rm -f $(DESTDIR)$(PREFIX)/share/icons/hicolor/*/apps/carla-control.png | |||||
| rm -f $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/carla.svg | |||||
| rm -f $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/carla-control.svg | |||||
| rm -rf $(DESTDIR)$(PREFIX)/lib/carla/ | |||||
| rm -rf $(DESTDIR)$(PREFIX)/share/carla/ | |||||
| @@ -0,0 +1,12 @@ | |||||
| # --- README for Carla --- | |||||
| Carla is an audio plugin host, with support for many audio drivers and plugin formats. <br/> | |||||
| It's being developed by falkTX, using C++, Python3 and Qt4. | |||||
| It has some nice features like automation of parameters via MIDI CCs (and send control outputs back to MIDI too) and full OSC control. <br/> | |||||
| Currently supports LADSPA (including LRDF), DSSI, LV2, and VST plugin formats, with additional GIG, SF2 and SFZ file support via FluidSynth and LinuxSampler. | |||||
| It uses JACK as the default and preferred audio driver, but also supports native system drivers by using RtAudio+RtMidi. | |||||
| Carla-Control is an OSC Control GUI for Carla (you get the OSC address from the Carla's about dialog, and connect to it).<br/> | |||||
| Supports controlling main UI components (Dry/Wet, Volume and Balance), and all plugins parameters. <br/> | |||||
| Peak values and control outputs are displayed as well. | |||||
| @@ -0,0 +1,9 @@ | |||||
| [Project] | |||||
| Manager=KDevGenericManager | |||||
| Name=Carla | |||||
| [Filters] | |||||
| Excludes=*/.*,*/*~,*/*.pyc,*/ui_*.py,*/__pycache__/ | |||||
| [Project] | |||||
| VersionControlSupport=kdevgit | |||||
| @@ -0,0 +1,520 @@ | |||||
| #!/usr/bin/env python3 | |||||
| # -*- coding: utf-8 -*- | |||||
| # Common Carla code | |||||
| # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.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) | |||||
| import os | |||||
| #import platform | |||||
| import sys | |||||
| from codecs import open as codecopen | |||||
| from copy import deepcopy | |||||
| #from decimal import Decimal | |||||
| from PyQt4.QtCore import qWarning | |||||
| #pyqtSlot, qFatal, Qt, QSettings, QTimer | |||||
| #from PyQt4.QtGui import QColor, QCursor, QDialog, QFontMetrics, QFrame, QGraphicsScene, QInputDialog, QLinearGradient, QMenu, QPainter, QPainterPath, QVBoxLayout, QWidget | |||||
| #from PyQt4.QtXml import QDomDocument | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Imports (Custom) | |||||
| #import ui_carla_about | |||||
| #import ui_carla_edit | |||||
| #import ui_carla_parameter | |||||
| #import ui_carla_plugin | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Try Import Signal | |||||
| try: | |||||
| from signal import signal, SIGINT, SIGTERM, SIGUSR1, SIGUSR2 | |||||
| haveSignal = True | |||||
| except: | |||||
| haveSignal = False | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Set Platform | |||||
| if sys.platform == "darwin": | |||||
| from PyQt4.QtGui import qt_mac_set_menubar_icons | |||||
| qt_mac_set_menubar_icons(False) | |||||
| HAIKU = False | |||||
| LINUX = False | |||||
| MACOS = True | |||||
| WINDOWS = False | |||||
| elif "haiku" in sys.platform: | |||||
| HAIKU = True | |||||
| LINUX = False | |||||
| MACOS = False | |||||
| WINDOWS = False | |||||
| elif "linux" in sys.platform: | |||||
| HAIKU = False | |||||
| LINUX = True | |||||
| MACOS = False | |||||
| WINDOWS = False | |||||
| elif sys.platform in ("win32", "win64", "cygwin"): | |||||
| WINDIR = os.getenv("WINDIR") | |||||
| HAIKU = False | |||||
| LINUX = False | |||||
| MACOS = False | |||||
| WINDOWS = True | |||||
| else: | |||||
| HAIKU = False | |||||
| LINUX = False | |||||
| MACOS = False | |||||
| WINDOWS = False | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Set Version | |||||
| VERSION = "0.5.0" | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Set TMP | |||||
| TMP = os.getenv("TMP") | |||||
| if TMP is None: | |||||
| if WINDOWS: | |||||
| qWarning("TMP variable not set") | |||||
| TMP = os.path.join(WINDIR, "temp") | |||||
| else: | |||||
| TMP = "/tmp" | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Set HOME | |||||
| HOME = os.getenv("HOME") | |||||
| if HOME is None: | |||||
| HOME = os.path.expanduser("~") | |||||
| if LINUX or MACOS: | |||||
| qWarning("HOME variable not set") | |||||
| if not os.path.exists(HOME): | |||||
| qWarning("HOME does not exist") | |||||
| HOME = TMP | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Set PATH | |||||
| PATH = os.getenv("PATH") | |||||
| if PATH is None: | |||||
| qWarning("PATH variable not set") | |||||
| if MACOS: | |||||
| PATH = ("/opt/local/bin", "/usr/local/bin", "/usr/bin", "/bin") | |||||
| elif WINDOWS: | |||||
| PATH = (os.path.join(WINDIR, "system32"), WINDIR) | |||||
| else: | |||||
| PATH = ("/usr/local/bin", "/usr/bin", "/bin") | |||||
| else: | |||||
| PATH = PATH.split(os.pathsep) | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # 64bit check | |||||
| is64bit = False #bool(platform.architecture()[0] == "64bit" and sys.maxsize > 2**32) | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Check if a value is a number (float support) | |||||
| def isNumber(value): | |||||
| try: | |||||
| float(value) | |||||
| return True | |||||
| except: | |||||
| return False | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Unicode open | |||||
| def uopen(filename, mode="r"): | |||||
| return codecopen(filename, encoding="utf-8", mode=mode) | |||||
| # ------------------------------------------------------------------------------------------------ | |||||
| # Backend defines | |||||
| MAX_DEFAULT_PLUGINS = 99 | |||||
| MAX_RACK_PLUGINS = 16 | |||||
| MAX_PATCHBAY_PLUGINS = 999 | |||||
| MAX_DEFAULT_PARAMETERS = 200 | |||||
| # Plugin Hints | |||||
| PLUGIN_IS_BRIDGE = 0x001 | |||||
| PLUGIN_IS_RTSAFE = 0x002 | |||||
| PLUGIN_IS_SYNTH = 0x004 | |||||
| PLUGIN_HAS_GUI = 0x010 | |||||
| PLUGIN_USES_CHUNKS = 0x020 | |||||
| PLUGIN_USES_SINGLE_THREAD = 0x040 | |||||
| PLUGIN_CAN_DRYWET = 0x100 | |||||
| PLUGIN_CAN_VOLUME = 0x200 | |||||
| PLUGIN_CAN_BALANCE = 0x400 | |||||
| PLUGIN_CAN_FORCE_STEREO = 0x800 | |||||
| # Parameter Hints | |||||
| PARAMETER_IS_BOOLEAN = 0x01 | |||||
| PARAMETER_IS_INTEGER = 0x02 | |||||
| PARAMETER_IS_LOGARITHMIC = 0x04 | |||||
| PARAMETER_IS_ENABLED = 0x08 | |||||
| PARAMETER_IS_AUTOMABLE = 0x10 | |||||
| PARAMETER_USES_SAMPLERATE = 0x20 | |||||
| PARAMETER_USES_SCALEPOINTS = 0x40 | |||||
| PARAMETER_USES_CUSTOM_TEXT = 0x80 | |||||
| # FIXME | |||||
| # Custom Data types | |||||
| CUSTOM_DATA_INVALID = None | |||||
| CUSTOM_DATA_CHUNK = "http://kxstudio.sf.net/ns/carla/chunk" | |||||
| CUSTOM_DATA_STRING = "http://kxstudio.sf.net/ns/carla/string" | |||||
| # Binary Type | |||||
| BINARY_NONE = 0 | |||||
| BINARY_POSIX32 = 1 | |||||
| BINARY_POSIX64 = 2 | |||||
| BINARY_WIN32 = 3 | |||||
| BINARY_WIN64 = 4 | |||||
| BINARY_OTHER = 5 | |||||
| # Plugin Type | |||||
| PLUGIN_NONE = 0 | |||||
| PLUGIN_INTERNAL = 1 | |||||
| PLUGIN_LADSPA = 2 | |||||
| PLUGIN_DSSI = 3 | |||||
| PLUGIN_LV2 = 4 | |||||
| PLUGIN_VST = 5 | |||||
| PLUGIN_GIG = 6 | |||||
| PLUGIN_SF2 = 7 | |||||
| PLUGIN_SFZ = 8 | |||||
| # Plugin Category | |||||
| PLUGIN_CATEGORY_NONE = 0 | |||||
| PLUGIN_CATEGORY_SYNTH = 1 | |||||
| PLUGIN_CATEGORY_DELAY = 2 # also Reverb | |||||
| PLUGIN_CATEGORY_EQ = 3 | |||||
| PLUGIN_CATEGORY_FILTER = 4 | |||||
| PLUGIN_CATEGORY_DYNAMICS = 5 # Amplifier, Compressor, Gate | |||||
| PLUGIN_CATEGORY_MODULATOR = 6 # Chorus, Flanger, Phaser | |||||
| PLUGIN_CATEGORY_UTILITY = 7 # Analyzer, Converter, Mixer | |||||
| PLUGIN_CATEGORY_OTHER = 8 # used to check if a plugin has a category | |||||
| # Parameter Type | |||||
| PARAMETER_UNKNOWN = 0 | |||||
| PARAMETER_INPUT = 1 | |||||
| PARAMETER_OUTPUT = 2 | |||||
| PARAMETER_LATENCY = 3 | |||||
| PARAMETER_SAMPLE_RATE = 4 | |||||
| PARAMETER_LV2_FREEWHEEL = 5 | |||||
| PARAMETER_LV2_TIME = 6 | |||||
| # Internal Parameters Index | |||||
| PARAMETER_NULL = -1 | |||||
| PARAMETER_ACTIVE = -2 | |||||
| PARAMETER_DRYWET = -3 | |||||
| PARAMETER_VOLUME = -4 | |||||
| PARAMETER_BALANCE_LEFT = -5 | |||||
| PARAMETER_BALANCE_RIGHT = -6 | |||||
| PARAMETER_PANNING = -7 | |||||
| # Options Type | |||||
| OPTION_PROCESS_NAME = 0 | |||||
| OPTION_PROCESS_MODE = 1 | |||||
| OPTION_PROCESS_HIGH_PRECISION = 2 | |||||
| OPTION_FORCE_STEREO = 3 | |||||
| OPTION_PREFER_PLUGIN_BRIDGES = 4 | |||||
| OPTION_PREFER_UI_BRIDGES = 5 | |||||
| OPTION_USE_DSSI_VST_CHUNKS = 6 | |||||
| OPTION_MAX_PARAMETERS = 7 | |||||
| OPTION_OSC_UI_TIMEOUT = 8 | |||||
| OPTION_PREFERRED_BUFFER_SIZE = 9 | |||||
| OPTION_PREFERRED_SAMPLE_RATE = 10 | |||||
| OPTION_PATH_BRIDGE_NATIVE = 11 | |||||
| OPTION_PATH_BRIDGE_POSIX32 = 12 | |||||
| OPTION_PATH_BRIDGE_POSIX64 = 13 | |||||
| OPTION_PATH_BRIDGE_WIN32 = 14 | |||||
| OPTION_PATH_BRIDGE_WIN64 = 15 | |||||
| OPTION_PATH_BRIDGE_LV2_GTK2 = 16 | |||||
| OPTION_PATH_BRIDGE_LV2_GTK3 = 17 | |||||
| OPTION_PATH_BRIDGE_LV2_QT4 = 18 | |||||
| OPTION_PATH_BRIDGE_LV2_QT5 = 19 | |||||
| OPTION_PATH_BRIDGE_LV2_COCOA = 20 | |||||
| OPTION_PATH_BRIDGE_LV2_WINDOWS = 21 | |||||
| OPTION_PATH_BRIDGE_LV2_X11 = 22 | |||||
| OPTION_PATH_BRIDGE_VST_COCOA = 23 | |||||
| OPTION_PATH_BRIDGE_VST_HWND = 24 | |||||
| OPTION_PATH_BRIDGE_VST_X11 = 25 | |||||
| # Callback Type | |||||
| CALLBACK_DEBUG = 0 | |||||
| CALLBACK_PARAMETER_VALUE_CHANGED = 1 | |||||
| CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED = 2 | |||||
| CALLBACK_PARAMETER_MIDI_CC_CHANGED = 3 | |||||
| CALLBACK_PROGRAM_CHANGED = 4 | |||||
| CALLBACK_MIDI_PROGRAM_CHANGED = 5 | |||||
| CALLBACK_NOTE_ON = 6 | |||||
| CALLBACK_NOTE_OFF = 7 | |||||
| CALLBACK_SHOW_GUI = 8 | |||||
| CALLBACK_UPDATE = 9 | |||||
| CALLBACK_RELOAD_INFO = 10 | |||||
| CALLBACK_RELOAD_PARAMETERS = 11 | |||||
| CALLBACK_RELOAD_PROGRAMS = 12 | |||||
| CALLBACK_RELOAD_ALL = 13 | |||||
| CALLBACK_NSM_ANNOUNCE = 14 | |||||
| CALLBACK_NSM_OPEN1 = 15 | |||||
| CALLBACK_NSM_OPEN2 = 16 | |||||
| CALLBACK_NSM_SAVE = 17 | |||||
| CALLBACK_ERROR = 18 | |||||
| CALLBACK_QUIT = 19 | |||||
| # Process Mode Type | |||||
| PROCESS_MODE_SINGLE_CLIENT = 0 | |||||
| PROCESS_MODE_MULTIPLE_CLIENTS = 1 | |||||
| PROCESS_MODE_CONTINUOUS_RACK = 2 | |||||
| PROCESS_MODE_PATCHBAY = 3 | |||||
| # Set BINARY_NATIVE | |||||
| if HAIKU or LINUX or MACOS: | |||||
| BINARY_NATIVE = BINARY_POSIX64 if is64bit else BINARY_POSIX32 | |||||
| elif WINDOWS: | |||||
| BINARY_NATIVE = BINARY_WIN64 if is64bit else BINARY_WIN32 | |||||
| else: | |||||
| BINARY_NATIVE = BINARY_OTHER | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Carla Host object | |||||
| class CarlaHostObject(object): | |||||
| __slots__ = [ | |||||
| 'host', | |||||
| 'gui', | |||||
| 'isControl', | |||||
| 'processMode', | |||||
| 'maxParameters' | |||||
| ] | |||||
| Carla = CarlaHostObject() | |||||
| Carla.host = None | |||||
| Carla.gui = None | |||||
| Carla.isControl = False | |||||
| Carla.processMode = PROCESS_MODE_CONTINUOUS_RACK | |||||
| Carla.maxParameters = MAX_RACK_PLUGINS | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Carla GUI stuff | |||||
| ICON_STATE_NULL = 0 | |||||
| ICON_STATE_WAIT = 1 | |||||
| ICON_STATE_OFF = 2 | |||||
| ICON_STATE_ON = 3 | |||||
| PALETTE_COLOR_NONE = 0 | |||||
| PALETTE_COLOR_WHITE = 1 | |||||
| PALETTE_COLOR_RED = 2 | |||||
| PALETTE_COLOR_GREEN = 3 | |||||
| PALETTE_COLOR_BLUE = 4 | |||||
| PALETTE_COLOR_YELLOW = 5 | |||||
| PALETTE_COLOR_ORANGE = 6 | |||||
| PALETTE_COLOR_BROWN = 7 | |||||
| PALETTE_COLOR_PINK = 8 | |||||
| CarlaStateParameter = { | |||||
| 'index': 0, | |||||
| 'name': "", | |||||
| 'symbol': "", | |||||
| 'value': 0.0, | |||||
| 'midiChannel': 1, | |||||
| 'midiCC': -1 | |||||
| } | |||||
| CarlaStateCustomData = { | |||||
| 'type': CUSTOM_DATA_INVALID, | |||||
| 'key': "", | |||||
| 'value': "" | |||||
| } | |||||
| CarlaSaveState = { | |||||
| 'type': "", | |||||
| 'name': "", | |||||
| 'label': "", | |||||
| 'binary': "", | |||||
| 'uniqueId': 0, | |||||
| 'active': False, | |||||
| 'dryWet': 1.0, | |||||
| 'volume': 1.0, | |||||
| 'balanceLeft': -1.0, | |||||
| 'balanceRight': 1.0, | |||||
| 'pannning': 0.0, | |||||
| 'parameterList': [], | |||||
| 'currentProgramIndex': -1, | |||||
| 'currentProgramName': "", | |||||
| 'currentMidiBank': -1, | |||||
| 'currentMidiProgram': -1, | |||||
| 'customDataList': [], | |||||
| 'chunk': None | |||||
| } | |||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Carla XML helpers | |||||
| def getSaveStateDictFromXML(xmlNode): | |||||
| saveState = deepcopy(CarlaSaveState) | |||||
| node = xmlNode.firstChild() | |||||
| while not node.isNull(): | |||||
| # ------------------------------------------------------ | |||||
| # Info | |||||
| if node.toElement().tagName() == "Info": | |||||
| xmlInfo = node.toElement().firstChild() | |||||
| while not xmlInfo.isNull(): | |||||
| tag = xmlInfo.toElement().tagName() | |||||
| text = xmlInfo.toElement().text().strip() | |||||
| if tag == "Type": | |||||
| saveState["type"] = text | |||||
| elif tag == "Name": | |||||
| saveState["name"] = xmlSafeString(text, False) | |||||
| elif tag in ("Label", "URI"): | |||||
| saveState["label"] = xmlSafeString(text, False) | |||||
| elif tag == "Binary": | |||||
| saveState["binary"] = xmlSafeString(text, False) | |||||
| elif tag == "UniqueID": | |||||
| if text.isdigit(): saveState["uniqueId"] = int(text) | |||||
| xmlInfo = xmlInfo.nextSibling() | |||||
| # ------------------------------------------------------ | |||||
| # Data | |||||
| elif node.toElement().tagName() == "Data": | |||||
| xmlData = node.toElement().firstChild() | |||||
| while not xmlData.isNull(): | |||||
| tag = xmlData.toElement().tagName() | |||||
| text = xmlData.toElement().text().strip() | |||||
| # ---------------------------------------------- | |||||
| # Internal Data | |||||
| if tag == "Active": | |||||
| saveState['active'] = bool(text == "Yes") | |||||
| elif tag == "DryWet": | |||||
| if isNumber(text): saveState["dryWet"] = float(text) | |||||
| elif tag == "Volume": | |||||
| if isNumber(text): saveState["volume"] = float(text) | |||||
| elif tag == "Balance-Left": | |||||
| if isNumber(text): saveState["balanceLeft"] = float(text) | |||||
| elif tag == "Balance-Right": | |||||
| if isNumber(text): saveState["balanceRight"] = float(text) | |||||
| elif tag == "Panning": | |||||
| if isNumber(text): saveState["pannning"] = float(text) | |||||
| # ---------------------------------------------- | |||||
| # Program (current) | |||||
| elif tag == "CurrentProgramIndex": | |||||
| if text.isdigit(): saveState["currentProgramIndex"] = int(text) | |||||
| elif tag == "CurrentProgramName": | |||||
| saveState["currentProgramName"] = xmlSafeString(text, False) | |||||
| # ---------------------------------------------- | |||||
| # Midi Program (current) | |||||
| elif tag == "CurrentMidiBank": | |||||
| if text.isdigit(): saveState["currentMidiBank"] = int(text) | |||||
| elif tag == "CurrentMidiProgram": | |||||
| if text.isdigit(): saveState["currentMidiProgram"] = int(text) | |||||
| # ---------------------------------------------- | |||||
| # Parameters | |||||
| elif tag == "Parameter": | |||||
| stateParameter = deepcopy(CarlaStateParameter) | |||||
| xmlSubData = xmlData.toElement().firstChild() | |||||
| while not xmlSubData.isNull(): | |||||
| pTag = xmlSubData.toElement().tagName() | |||||
| pText = xmlSubData.toElement().text().strip() | |||||
| if pTag == "Index": | |||||
| if pText.isdigit(): stateParameter["index"] = int(pText) | |||||
| elif pTag == "Name": | |||||
| stateParameter["name"] = xmlSafeString(pText, False) | |||||
| elif pTag == "Symbol": | |||||
| stateParameter["symbol"] = xmlSafeString(pText, False) | |||||
| elif pTag == "Value": | |||||
| if isNumber(pText): stateParameter["value"] = float(pText) | |||||
| elif pTag == "MidiChannel": | |||||
| if pText.isdigit(): stateParameter["midiChannel"] = int(pText) | |||||
| elif pTag == "MidiCC": | |||||
| if pText.isdigit(): stateParameter["midiCC"] = int(pText) | |||||
| xmlSubData = xmlSubData.nextSibling() | |||||
| saveState["parameterList"].append(stateParameter) | |||||
| # ---------------------------------------------- | |||||
| # Custom Data | |||||
| elif tag == "CustomData": | |||||
| stateCustomData = deepcopy(CarlaStateCustomData) | |||||
| xmlSubData = xmlData.toElement().firstChild() | |||||
| while not xmlSubData.isNull(): | |||||
| cTag = xmlSubData.toElement().tagName() | |||||
| cText = xmlSubData.toElement().text().strip() | |||||
| if cTag == "Type": | |||||
| stateCustomData["type"] = xmlSafeString(cText, False) | |||||
| elif cTag == "Key": | |||||
| stateCustomData["key"] = xmlSafeString(cText, False) | |||||
| elif cTag == "Value": | |||||
| stateCustomData["value"] = xmlSafeString(cText, False) | |||||
| xmlSubData = xmlSubData.nextSibling() | |||||
| saveState["customDataList"].append(stateCustomData) | |||||
| # ---------------------------------------------- | |||||
| # Chunk | |||||
| elif tag == "Chunk": | |||||
| saveState["chunk"] = xmlSafeString(text, False) | |||||
| # ---------------------------------------------- | |||||
| xmlData = xmlData.nextSibling() | |||||
| # ------------------------------------------------------ | |||||
| node = node.nextSibling() | |||||
| return saveState | |||||
| def xmlSafeString(string, toXml): | |||||
| if toXml: | |||||
| return string.replace("&", "&").replace("<","<").replace(">",">").replace("'","'").replace("\"",""") | |||||
| else: | |||||
| return string.replace("&", "&").replace("<","<").replace(">",">").replace("'","'").replace(""","\"") | |||||
| @@ -188,7 +188,7 @@ intptr_t VSTCALLBACK vstHostCallback(AEffect* const effect, const int32_t opcode | |||||
| break; | break; | ||||
| case audioMasterGetNumAutomatableParameters: | case audioMasterGetNumAutomatableParameters: | ||||
| ret = carla_min<int32_t>(effect->numParams, MAX_PARAMETERS, 0); | |||||
| ret = carla_min<int32_t>(effect->numParams, MAX_DEFAULT_PARAMETERS, 0); | |||||
| break; | break; | ||||
| case audioMasterGetParameterQuantization: | case audioMasterGetParameterQuantization: | ||||
| @@ -2,7 +2,7 @@ | |||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
| # Digital Peak Meter, a custom Qt4 widget | # Digital Peak Meter, a custom Qt4 widget | ||||
| # Copyright (C) 2011-2012 Filipe Coelho <falktx@falktx.com> | |||||
| # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com> | |||||
| # | # | ||||
| # This program is free software; you can redistribute it and/or modify | # 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 | # it under the terms of the GNU General Public License as published by | ||||
| @@ -11,16 +11,20 @@ | |||||
| # | # | ||||
| # This program is distributed in the hope that it will be useful, | # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # GNU General Public License for more details. | # GNU General Public License for more details. | ||||
| # | # | ||||
| # 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 qCritical, Qt, QTimer, QSize | from PyQt4.QtCore import qCritical, Qt, QTimer, QSize | ||||
| from PyQt4.QtGui import QColor, QLinearGradient, QPainter, QWidget | from PyQt4.QtGui import QColor, QLinearGradient, QPainter, QWidget | ||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Widget Class | # Widget Class | ||||
| class DigitalPeakMeter(QWidget): | class DigitalPeakMeter(QWidget): | ||||
| # enum Orientation | # enum Orientation | ||||
| HORIZONTAL = 1 | HORIZONTAL = 1 | ||||
| @@ -60,7 +64,7 @@ class DigitalPeakMeter(QWidget): | |||||
| self.m_channelsData[meter-1] = level | self.m_channelsData[meter-1] = level | ||||
| def setChannels(self, channels): | def setChannels(self, channels): | ||||
| if (channels < 0): | |||||
| if channels < 0: | |||||
| return qCritical("DigitalPeakMeter::setChannels(%i) - 'channels' must be a positive integer" % channels) | return qCritical("DigitalPeakMeter::setChannels(%i) - 'channels' must be a positive integer" % channels) | ||||
| self.m_channels = channels | self.m_channels = channels | ||||
| @@ -228,6 +232,8 @@ class DigitalPeakMeter(QWidget): | |||||
| painter.setPen(QColor(110, 15, 15, 100)) | painter.setPen(QColor(110, 15, 15, 100)) | ||||
| painter.drawLine(2, lsmall - (lsmall * 0.96), lfull-2, lsmall - (lsmall * 0.96)) | painter.drawLine(2, lsmall - (lsmall * 0.96), lfull-2, lsmall - (lsmall * 0.96)) | ||||
| event.accept() | |||||
| def resizeEvent(self, event): | def resizeEvent(self, event): | ||||
| self.updateSizes() | self.updateSizes() | ||||
| QWidget.resizeEvent(self, event) | QWidget.resizeEvent(self, event) | ||||
| @@ -2,7 +2,7 @@ | |||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
| # Pixmap Button, a custom Qt4 widget | # Pixmap Button, a custom Qt4 widget | ||||
| # Copyright (C) 2011-2012 Filipe Coelho <falktx@falktx.com> | |||||
| # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com> | |||||
| # | # | ||||
| # This program is free software; you can redistribute it and/or modify | # 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 | # it under the terms of the GNU General Public License as published by | ||||
| @@ -11,16 +11,20 @@ | |||||
| # | # | ||||
| # This program is distributed in the hope that it will be useful, | # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # GNU General Public License for more details. | # GNU General Public License for more details. | ||||
| # | # | ||||
| # 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 qCritical, QRectF | from PyQt4.QtCore import qCritical, QRectF | ||||
| from PyQt4.QtGui import QPainter, QPixmap, QPushButton | from PyQt4.QtGui import QPainter, QPixmap, QPushButton | ||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Widget Class | # Widget Class | ||||
| class LEDButton(QPushButton): | class LEDButton(QPushButton): | ||||
| BLUE = 1 | BLUE = 1 | ||||
| GREEN = 2 | GREEN = 2 | ||||
| @@ -32,7 +36,7 @@ class LEDButton(QPushButton): | |||||
| QPushButton.__init__(self, parent) | QPushButton.__init__(self, parent) | ||||
| self.m_pixmap = QPixmap() | self.m_pixmap = QPixmap() | ||||
| self.m_pixmap_rect = QRectF(0, 0, 0, 0) | |||||
| self.m_pixmapRect = QRectF(0, 0, 0, 0) | |||||
| self.setCheckable(True) | self.setCheckable(True) | ||||
| self.setText("") | self.setText("") | ||||
| @@ -52,7 +56,7 @@ class LEDButton(QPushButton): | |||||
| self.setPixmapSize(size) | self.setPixmapSize(size) | ||||
| def setPixmapSize(self, size): | def setPixmapSize(self, size): | ||||
| self.m_pixmap_rect = QRectF(0, 0, size, size) | |||||
| self.m_pixmapRect = QRectF(0, 0, size, size) | |||||
| self.setMinimumWidth(size) | self.setMinimumWidth(size) | ||||
| self.setMaximumWidth(size) | self.setMaximumWidth(size) | ||||
| @@ -83,4 +87,6 @@ class LEDButton(QPushButton): | |||||
| else: | else: | ||||
| return | return | ||||
| painter.drawPixmap(self.m_pixmap_rect, self.m_pixmap, self.m_pixmap_rect) | |||||
| painter.drawPixmap(self.m_pixmapRect, self.m_pixmap, self.m_pixmapRect) | |||||
| event.accept() | |||||
| @@ -1,13 +1,32 @@ | |||||
| #!/usr/bin/env python | #!/usr/bin/env python | ||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
| # Parameter SpinBox, a custom Qt4 widget | |||||
| # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.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) | # Imports (Global) | ||||
| from PyQt4.QtCore import pyqtSlot, Qt, QTimer, SIGNAL, SLOT | from PyQt4.QtCore import pyqtSlot, Qt, QTimer, SIGNAL, SLOT | ||||
| from PyQt4.QtGui import QAbstractSpinBox, QComboBox, QCursor, QDialog, QInputDialog, QMenu, QPainter, QProgressBar, QValidator | from PyQt4.QtGui import QAbstractSpinBox, QComboBox, QCursor, QDialog, QInputDialog, QMenu, QPainter, QProgressBar, QValidator | ||||
| from PyQt4.QtGui import QStyleFactory | from PyQt4.QtGui import QStyleFactory | ||||
| from math import isnan | from math import isnan | ||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Imports (Custom) | # Imports (Custom) | ||||
| import ui_inputdialog_value | import ui_inputdialog_value | ||||
| def fix_value(value, minimum, maximum): | def fix_value(value, minimum, maximum): | ||||
| @@ -25,7 +44,9 @@ def fix_value(value, minimum, maximum): | |||||
| #QPlastiqueStyle = QStyleFactory.create("Plastique") | #QPlastiqueStyle = QStyleFactory.create("Plastique") | ||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Custom InputDialog with Scale Points support | # Custom InputDialog with Scale Points support | ||||
| class CustomInputDialog(QDialog, ui_inputdialog_value.Ui_Dialog): | class CustomInputDialog(QDialog, ui_inputdialog_value.Ui_Dialog): | ||||
| def __init__(self, parent, label, current, minimum, maximum, step, scalePoints): | def __init__(self, parent, label, current, minimum, maximum, step, scalePoints): | ||||
| QDialog.__init__(self, parent) | QDialog.__init__(self, parent) | ||||
| @@ -59,7 +80,9 @@ class CustomInputDialog(QDialog, ui_inputdialog_value.Ui_Dialog): | |||||
| QDialog.done(self, r) | QDialog.done(self, r) | ||||
| self.close() | self.close() | ||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Progress-Bar used for ParamSpinBox | # Progress-Bar used for ParamSpinBox | ||||
| class ParamProgressBar(QProgressBar): | class ParamProgressBar(QProgressBar): | ||||
| def __init__(self, parent): | def __init__(self, parent): | ||||
| QProgressBar.__init__(self, parent) | QProgressBar.__init__(self, parent) | ||||
| @@ -138,7 +161,9 @@ class ParamProgressBar(QProgressBar): | |||||
| QProgressBar.paintEvent(self, event) | QProgressBar.paintEvent(self, event) | ||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Special SpinBox used for parameters | # Special SpinBox used for parameters | ||||
| class ParamSpinBox(QAbstractSpinBox): | class ParamSpinBox(QAbstractSpinBox): | ||||
| def __init__(self, parent): | def __init__(self, parent): | ||||
| QAbstractSpinBox.__init__(self, parent) | QAbstractSpinBox.__init__(self, parent) | ||||
| @@ -205,7 +230,7 @@ class ParamSpinBox(QAbstractSpinBox): | |||||
| self._step = 0.001 | self._step = 0.001 | ||||
| else: | else: | ||||
| self._step = value | self._step = value | ||||
| if self._step_small > value: | if self._step_small > value: | ||||
| self._step_small = value | self._step_small = value | ||||
| if self._step_large < value: | if self._step_large < value: | ||||
| @@ -2,7 +2,7 @@ | |||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
| # Pixmap Dial, a custom Qt4 widget | # Pixmap Dial, a custom Qt4 widget | ||||
| # Copyright (C) 2011-2012 Filipe Coelho <falktx@falktx.com> | |||||
| # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com> | |||||
| # | # | ||||
| # This program is free software; you can redistribute it and/or modify | # 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 | # it under the terms of the GNU General Public License as published by | ||||
| @@ -11,17 +11,21 @@ | |||||
| # | # | ||||
| # This program is distributed in the hope that it will be useful, | # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # GNU General Public License for more details. | # GNU General Public License for more details. | ||||
| # | # | ||||
| # 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 math import floor | from math import floor | ||||
| from PyQt4.QtCore import Qt, QPointF, QRectF, QTimer, QSize, SLOT | from PyQt4.QtCore import Qt, QPointF, QRectF, QTimer, QSize, SLOT | ||||
| from PyQt4.QtGui import QColor, QConicalGradient, QDial, QFontMetrics, QLinearGradient, QPainter, QPainterPath, QPen, QPixmap | from PyQt4.QtGui import QColor, QConicalGradient, QDial, QFontMetrics, QLinearGradient, QPainter, QPainterPath, QPen, QPixmap | ||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # Widget Class | # Widget Class | ||||
| class PixmapDial(QDial): | class PixmapDial(QDial): | ||||
| # enum Orientation | # enum Orientation | ||||
| HORIZONTAL = 0 | HORIZONTAL = 0 | ||||
| @@ -41,11 +45,11 @@ class PixmapDial(QDial): | |||||
| QDial.__init__(self, parent) | QDial.__init__(self, parent) | ||||
| self.m_pixmap = QPixmap(":/bitmaps/dial_01d.png") | self.m_pixmap = QPixmap(":/bitmaps/dial_01d.png") | ||||
| self.m_pixmap_n_str = "01" | |||||
| self.m_custom_paint = self.CUSTOM_PAINT_NULL | |||||
| self.m_pixmapNum = "01" | |||||
| self.m_customPaint = self.CUSTOM_PAINT_NULL | |||||
| self.m_hovered = False | |||||
| self.m_hover_step = self.HOVER_MIN | |||||
| self.m_hovered = False | |||||
| self.m_hoverStep = self.HOVER_MIN | |||||
| if self.m_pixmap.width() > self.m_pixmap.height(): | if self.m_pixmap.width() > self.m_pixmap.height(): | ||||
| self.m_orientation = self.HORIZONTAL | self.m_orientation = self.HORIZONTAL | ||||
| @@ -53,10 +57,10 @@ class PixmapDial(QDial): | |||||
| self.m_orientation = self.VERTICAL | self.m_orientation = self.VERTICAL | ||||
| self.m_label = "" | self.m_label = "" | ||||
| self.m_label_pos = QPointF(0.0, 0.0) | |||||
| self.m_label_width = 0 | |||||
| self.m_label_height = 0 | |||||
| self.m_label_gradient = QLinearGradient(0, 0, 0, 1) | |||||
| self.m_labelPos = QPointF(0.0, 0.0) | |||||
| self.m_labelWidth = 0 | |||||
| self.m_labelHeight = 0 | |||||
| self.m_labelGradient = QLinearGradient(0, 0, 0, 1) | |||||
| if self.palette().window().color().lightness() > 100: | if self.palette().window().color().lightness() > 100: | ||||
| # Light background | # Light background | ||||
| @@ -76,12 +80,12 @@ class PixmapDial(QDial): | |||||
| return self.p_size | return self.p_size | ||||
| def setCustomPaint(self, paint): | def setCustomPaint(self, paint): | ||||
| self.m_custom_paint = paint | |||||
| self.m_customPaint = paint | |||||
| self.update() | self.update() | ||||
| def setEnabled(self, enabled): | def setEnabled(self, enabled): | ||||
| if self.isEnabled() != enabled: | if self.isEnabled() != enabled: | ||||
| self.m_pixmap.load(":/bitmaps/dial_%s%s.png" % (self.m_pixmap_n_str, "" if enabled else "d")) | |||||
| self.m_pixmap.load(":/bitmaps/dial_%s%s.png" % (self.m_pixmapNum, "" if enabled else "d")) | |||||
| self.updateSizes() | self.updateSizes() | ||||
| self.update() | self.update() | ||||
| QDial.setEnabled(self, enabled) | QDial.setEnabled(self, enabled) | ||||
| @@ -89,25 +93,25 @@ class PixmapDial(QDial): | |||||
| def setLabel(self, label): | def setLabel(self, label): | ||||
| self.m_label = label | self.m_label = label | ||||
| self.m_label_width = QFontMetrics(self.font()).width(label) | |||||
| self.m_label_height = QFontMetrics(self.font()).height() | |||||
| self.m_labelWidth = QFontMetrics(self.font()).width(label) | |||||
| self.m_labelHeight = QFontMetrics(self.font()).height() | |||||
| self.m_label_pos.setX(float(self.p_size)/2 - float(self.m_label_width)/2) | |||||
| self.m_label_pos.setY(self.p_size + self.m_label_height) | |||||
| self.m_labelPos.setX(float(self.p_size)/2 - float(self.m_labelWidth)/2) | |||||
| self.m_labelPos.setY(self.p_size + self.m_labelHeight) | |||||
| self.m_label_gradient.setColorAt(0.0, self.m_color1) | |||||
| self.m_label_gradient.setColorAt(0.6, self.m_color1) | |||||
| self.m_label_gradient.setColorAt(1.0, self.m_color2) | |||||
| self.m_labelGradient.setColorAt(0.0, self.m_color1) | |||||
| self.m_labelGradient.setColorAt(0.6, self.m_color1) | |||||
| self.m_labelGradient.setColorAt(1.0, self.m_color2) | |||||
| self.m_label_gradient.setStart(0, float(self.p_size)/2) | |||||
| self.m_label_gradient.setFinalStop(0, self.p_size + self.m_label_height + 5) | |||||
| self.m_labelGradient.setStart(0, float(self.p_size)/2) | |||||
| self.m_labelGradient.setFinalStop(0, self.p_size + self.m_labelHeight + 5) | |||||
| self.m_label_gradient_rect = QRectF(float(self.p_size)/8, float(self.p_size)/2, float(self.p_size)*6/8, self.p_size+self.m_label_height+5) | |||||
| self.m_labelGradient_rect = QRectF(float(self.p_size)/8, float(self.p_size)/2, float(self.p_size)*6/8, self.p_size+self.m_labelHeight+5) | |||||
| self.update() | self.update() | ||||
| def setPixmap(self, pixmapId): | def setPixmap(self, pixmapId): | ||||
| self.m_pixmap_n_str = "%02i" % pixmapId | |||||
| self.m_pixmap.load(":/bitmaps/dial_%s%s.png" % (self.m_pixmap_n_str, "" if self.isEnabled() else "d")) | |||||
| self.m_pixmapNum = "%02i" % pixmapId | |||||
| self.m_pixmap.load(":/bitmaps/dial_%s%s.png" % (self.m_pixmapNum, "" if self.isEnabled() else "d")) | |||||
| if self.m_pixmap.width() > self.m_pixmap.height(): | if self.m_pixmap.width() > self.m_pixmap.height(): | ||||
| self.m_orientation = self.HORIZONTAL | self.m_orientation = self.HORIZONTAL | ||||
| @@ -140,19 +144,19 @@ class PixmapDial(QDial): | |||||
| self.p_size = self.p_width | self.p_size = self.p_width | ||||
| self.p_count = self.p_height / self.p_width | self.p_count = self.p_height / self.p_width | ||||
| self.setMinimumSize(self.p_size, self.p_size + self.m_label_height + 5) | |||||
| self.setMaximumSize(self.p_size, self.p_size + self.m_label_height + 5) | |||||
| self.setMinimumSize(self.p_size, self.p_size + self.m_labelHeight + 5) | |||||
| self.setMaximumSize(self.p_size, self.p_size + self.m_labelHeight + 5) | |||||
| def enterEvent(self, event): | def enterEvent(self, event): | ||||
| self.m_hovered = True | self.m_hovered = True | ||||
| if self.m_hover_step == self.HOVER_MIN: | |||||
| self.m_hover_step += 1 | |||||
| if self.m_hoverStep == self.HOVER_MIN: | |||||
| self.m_hoverStep += 1 | |||||
| QDial.enterEvent(self, event) | QDial.enterEvent(self, event) | ||||
| def leaveEvent(self, event): | def leaveEvent(self, event): | ||||
| self.m_hovered = False | self.m_hovered = False | ||||
| if self.m_hover_step == self.HOVER_MAX: | |||||
| self.m_hover_step -= 1 | |||||
| if self.m_hoverStep == self.HOVER_MAX: | |||||
| self.m_hoverStep -= 1 | |||||
| QDial.leaveEvent(self, event) | QDial.leaveEvent(self, event) | ||||
| def paintEvent(self, event): | def paintEvent(self, event): | ||||
| @@ -161,11 +165,11 @@ class PixmapDial(QDial): | |||||
| if self.m_label: | if self.m_label: | ||||
| painter.setPen(self.m_color2) | painter.setPen(self.m_color2) | ||||
| painter.setBrush(self.m_label_gradient) | |||||
| painter.drawRect(self.m_label_gradient_rect) | |||||
| painter.setBrush(self.m_labelGradient) | |||||
| painter.drawRect(self.m_labelGradient_rect) | |||||
| painter.setPen(self.m_colorT[0 if self.isEnabled() else 1]) | painter.setPen(self.m_colorT[0 if self.isEnabled() else 1]) | ||||
| painter.drawText(self.m_label_pos, self.m_label) | |||||
| painter.drawText(self.m_labelPos, self.m_label) | |||||
| if self.isEnabled(): | if self.isEnabled(): | ||||
| current = float(self.value() - self.minimum()) | current = float(self.value() - self.minimum()) | ||||
| @@ -190,10 +194,10 @@ class PixmapDial(QDial): | |||||
| painter.drawPixmap(target, self.m_pixmap, source) | painter.drawPixmap(target, self.m_pixmap, source) | ||||
| # Custom knobs (Dry/Wet and Volume) | # Custom knobs (Dry/Wet and Volume) | ||||
| if self.m_custom_paint in (self.CUSTOM_PAINT_CARLA_WET, self.CUSTOM_PAINT_CARLA_VOL): | |||||
| if self.m_customPaint in (self.CUSTOM_PAINT_CARLA_WET, self.CUSTOM_PAINT_CARLA_VOL): | |||||
| # knob color | # knob color | ||||
| colorGreen = QColor(0x5D, 0xE7, 0x3D, 191 + self.m_hover_step*7) | |||||
| colorBlue = QColor(0x3E, 0xB8, 0xBE, 191 + self.m_hover_step*7) | |||||
| colorGreen = QColor(0x5D, 0xE7, 0x3D, 191 + self.m_hoverStep*7) | |||||
| colorBlue = QColor(0x3E, 0xB8, 0xBE, 191 + self.m_hoverStep*7) | |||||
| # draw small circle | # draw small circle | ||||
| ballRect = QRectF(8.0, 8.0, 15.0, 15.0) | ballRect = QRectF(8.0, 8.0, 15.0, 15.0) | ||||
| @@ -208,7 +212,7 @@ class PixmapDial(QDial): | |||||
| startAngle = 216*16 | startAngle = 216*16 | ||||
| spanAngle = -252*16*value | spanAngle = -252*16*value | ||||
| if self.m_custom_paint == self.CUSTOM_PAINT_CARLA_WET: | |||||
| if self.m_customPaint == self.CUSTOM_PAINT_CARLA_WET: | |||||
| painter.setBrush(colorBlue) | painter.setBrush(colorBlue) | ||||
| painter.setPen(QPen(colorBlue, 0)) | painter.setPen(QPen(colorBlue, 0)) | ||||
| painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2)) | painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2)) | ||||
| @@ -234,9 +238,9 @@ class PixmapDial(QDial): | |||||
| painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle) | painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle) | ||||
| # Custom knobs (L and R) | # Custom knobs (L and R) | ||||
| elif self.m_custom_paint in (self.CUSTOM_PAINT_CARLA_L, self.CUSTOM_PAINT_CARLA_R): | |||||
| elif self.m_customPaint in (self.CUSTOM_PAINT_CARLA_L, self.CUSTOM_PAINT_CARLA_R): | |||||
| # knob color | # knob color | ||||
| color = QColor(0xAD + self.m_hover_step*5, 0xD5 + self.m_hover_step*4, 0x4B + self.m_hover_step*5) | |||||
| color = QColor(0xAD + self.m_hoverStep*5, 0xD5 + self.m_hoverStep*4, 0x4B + self.m_hoverStep*5) | |||||
| # draw small circle | # draw small circle | ||||
| ballRect = QRectF(7.0, 8.0, 11.0, 12.0) | ballRect = QRectF(7.0, 8.0, 11.0, 12.0) | ||||
| @@ -252,10 +256,10 @@ class PixmapDial(QDial): | |||||
| painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0)) | painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0)) | ||||
| # draw arc | # draw arc | ||||
| if self.m_custom_paint == self.CUSTOM_PAINT_CARLA_L: | |||||
| if self.m_customPaint == self.CUSTOM_PAINT_CARLA_L: | |||||
| startAngle = 216*16 | startAngle = 216*16 | ||||
| spanAngle = -252.0*16*value | spanAngle = -252.0*16*value | ||||
| elif self.m_custom_paint == self.CUSTOM_PAINT_CARLA_R: | |||||
| elif self.m_customPaint == self.CUSTOM_PAINT_CARLA_R: | |||||
| startAngle = 324.0*16 | startAngle = 324.0*16 | ||||
| spanAngle = 252.0*16*(1.0-value) | spanAngle = 252.0*16*(1.0-value) | ||||
| else: | else: | ||||
| @@ -264,14 +268,16 @@ class PixmapDial(QDial): | |||||
| painter.setPen(QPen(color, 2)) | painter.setPen(QPen(color, 2)) | ||||
| painter.drawArc(3.5, 4.5, 22.0, 22.0, startAngle, spanAngle) | painter.drawArc(3.5, 4.5, 22.0, 22.0, startAngle, spanAngle) | ||||
| if self.HOVER_MIN < self.m_hover_step < self.HOVER_MAX: | |||||
| self.m_hover_step += 1 if self.m_hovered else -1 | |||||
| if self.HOVER_MIN < self.m_hoverStep < self.HOVER_MAX: | |||||
| self.m_hoverStep += 1 if self.m_hovered else -1 | |||||
| QTimer.singleShot(20, self, SLOT("update()")) | QTimer.singleShot(20, self, SLOT("update()")) | ||||
| else: | else: | ||||
| target = QRectF(0.0, 0.0, self.p_size, self.p_size) | target = QRectF(0.0, 0.0, self.p_size, self.p_size) | ||||
| painter.drawPixmap(target, self.m_pixmap, target) | painter.drawPixmap(target, self.m_pixmap, target) | ||||
| event.accept() | |||||
| def resizeEvent(self, event): | def resizeEvent(self, event): | ||||
| self.updateSizes() | self.updateSizes() | ||||
| QDial.resizeEvent(self, event) | QDial.resizeEvent(self, event) | ||||
| @@ -2,7 +2,7 @@ | |||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
| # Pixmap Keyboard, a custom Qt4 widget | # Pixmap Keyboard, a custom Qt4 widget | ||||
| # Copyright (C) 2011-2012 Filipe Coelho <falktx@falktx.com> | |||||
| # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com> | |||||
| # | # | ||||
| # This program is free software; you can redistribute it and/or modify | # 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 | # it under the terms of the GNU General Public License as published by | ||||
| @@ -11,15 +11,19 @@ | |||||
| # | # | ||||
| # This program is distributed in the hope that it will be useful, | # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # GNU General Public License for more details. | # GNU General Public License for more details. | ||||
| # | # | ||||
| # 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, qCritical, Qt, QPointF, QRectF, QTimer, SIGNAL, SLOT | from PyQt4.QtCore import pyqtSlot, qCritical, Qt, QPointF, QRectF, QTimer, SIGNAL, SLOT | ||||
| from PyQt4.QtGui import QFont, QPainter, QPixmap, QWidget | from PyQt4.QtGui import QFont, QPainter, QPixmap, QWidget | ||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| midi_key2rect_map_horizontal = { | midi_key2rect_map_horizontal = { | ||||
| '0': QRectF(0, 0, 18, 64), # C | '0': QRectF(0, 0, 18, 64), # C | ||||
| '1': QRectF(13, 0, 11, 42), # C# | '1': QRectF(13, 0, 11, 42), # C# | ||||
| @@ -79,7 +83,9 @@ midi_keyboard2key_map = { | |||||
| '%i' % Qt.Key_U: 71, | '%i' % Qt.Key_U: 71, | ||||
| } | } | ||||
| # ------------------------------------------------------------------------------------------------------------ | |||||
| # MIDI Keyboard, using a pixmap for painting | # MIDI Keyboard, using a pixmap for painting | ||||
| class PixmapKeyboard(QWidget): | class PixmapKeyboard(QWidget): | ||||
| # enum Color | # enum Color | ||||
| COLOR_CLASSIC = 0 | COLOR_CLASSIC = 0 | ||||
| @@ -146,15 +152,15 @@ class PixmapKeyboard(QWidget): | |||||
| return self.setMode(mode) | return self.setMode(mode) | ||||
| if mode == self.HORIZONTAL: | if mode == self.HORIZONTAL: | ||||
| self.m_midi_map = midi_key2rect_map_horizontal | |||||
| self.m_midiMap = midi_key2rect_map_horizontal | |||||
| self.m_pixmap.load(":/bitmaps/kbd_h_%s.png" % self.m_colorStr) | self.m_pixmap.load(":/bitmaps/kbd_h_%s.png" % self.m_colorStr) | ||||
| self.m_pixmap_mode = self.HORIZONTAL | |||||
| self.m_pixmapMode = self.HORIZONTAL | |||||
| self.p_width = self.m_pixmap.width() | self.p_width = self.m_pixmap.width() | ||||
| self.p_height = self.m_pixmap.height() / 2 | self.p_height = self.m_pixmap.height() / 2 | ||||
| elif mode == self.VERTICAL: | elif mode == self.VERTICAL: | ||||
| self.m_midi_map = midi_key2rect_map_vertical | |||||
| self.m_midiMap = midi_key2rect_map_vertical | |||||
| self.m_pixmap.load(":/bitmaps/kbd_v_%s.png" % self.m_colorStr) | self.m_pixmap.load(":/bitmaps/kbd_v_%s.png" % self.m_colorStr) | ||||
| self.m_pixmap_mode = self.VERTICAL | |||||
| self.m_pixmapMode = self.VERTICAL | |||||
| self.p_width = self.m_pixmap.width() / 2 | self.p_width = self.m_pixmap.width() / 2 | ||||
| self.p_height = self.m_pixmap.height() | self.p_height = self.m_pixmap.height() | ||||
| else: | else: | ||||
| @@ -170,23 +176,23 @@ class PixmapKeyboard(QWidget): | |||||
| octaves = 8 | octaves = 8 | ||||
| self.m_octaves = octaves | self.m_octaves = octaves | ||||
| if self.m_pixmap_mode == self.HORIZONTAL: | |||||
| if self.m_pixmapMode == self.HORIZONTAL: | |||||
| self.setMinimumSize(self.p_width * self.m_octaves, self.p_height) | self.setMinimumSize(self.p_width * self.m_octaves, self.p_height) | ||||
| self.setMaximumSize(self.p_width * self.m_octaves, self.p_height) | self.setMaximumSize(self.p_width * self.m_octaves, self.p_height) | ||||
| elif self.m_pixmap_mode == self.VERTICAL: | |||||
| elif self.m_pixmapMode == self.VERTICAL: | |||||
| self.setMinimumSize(self.p_width, self.p_height * self.m_octaves) | self.setMinimumSize(self.p_width, self.p_height * self.m_octaves) | ||||
| self.setMaximumSize(self.p_width, self.p_height * self.m_octaves) | self.setMaximumSize(self.p_width, self.p_height * self.m_octaves) | ||||
| self.update() | self.update() | ||||
| def handleMousePos(self, pos): | def handleMousePos(self, pos): | ||||
| if self.m_pixmap_mode == self.HORIZONTAL: | |||||
| if self.m_pixmapMode == self.HORIZONTAL: | |||||
| if pos.x() < 0 or pos.x() > self.m_octaves * 144: | if pos.x() < 0 or pos.x() > self.m_octaves * 144: | ||||
| return | return | ||||
| posX = pos.x() - 1 | posX = pos.x() - 1 | ||||
| octave = int(posX / self.p_width) | octave = int(posX / self.p_width) | ||||
| n_pos = QPointF(posX % self.p_width, pos.y()) | n_pos = QPointF(posX % self.p_width, pos.y()) | ||||
| elif self.m_pixmap_mode == self.VERTICAL: | |||||
| elif self.m_pixmapMode == self.VERTICAL: | |||||
| if pos.y() < 0 or pos.y() > self.m_octaves * 144: | if pos.y() < 0 or pos.y() > self.m_octaves * 144: | ||||
| return | return | ||||
| posY = pos.y() - 1 | posY = pos.y() - 1 | ||||
| @@ -197,29 +203,29 @@ class PixmapKeyboard(QWidget): | |||||
| octave += 3 | octave += 3 | ||||
| if self.m_midi_map['1'].contains(n_pos): # C# | |||||
| if self.m_midiMap['1'].contains(n_pos): # C# | |||||
| note = 1 | note = 1 | ||||
| elif self.m_midi_map['3'].contains(n_pos): # D# | |||||
| elif self.m_midiMap['3'].contains(n_pos): # D# | |||||
| note = 3 | note = 3 | ||||
| elif self.m_midi_map['6'].contains(n_pos): # F# | |||||
| elif self.m_midiMap['6'].contains(n_pos): # F# | |||||
| note = 6 | note = 6 | ||||
| elif self.m_midi_map['8'].contains(n_pos): # G# | |||||
| elif self.m_midiMap['8'].contains(n_pos): # G# | |||||
| note = 8 | note = 8 | ||||
| elif self.m_midi_map['10'].contains(n_pos):# A# | |||||
| elif self.m_midiMap['10'].contains(n_pos):# A# | |||||
| note = 10 | note = 10 | ||||
| elif self.m_midi_map['0'].contains(n_pos): # C | |||||
| elif self.m_midiMap['0'].contains(n_pos): # C | |||||
| note = 0 | note = 0 | ||||
| elif self.m_midi_map['2'].contains(n_pos): # D | |||||
| elif self.m_midiMap['2'].contains(n_pos): # D | |||||
| note = 2 | note = 2 | ||||
| elif self.m_midi_map['4'].contains(n_pos): # E | |||||
| elif self.m_midiMap['4'].contains(n_pos): # E | |||||
| note = 4 | note = 4 | ||||
| elif self.m_midi_map['5'].contains(n_pos): # F | |||||
| elif self.m_midiMap['5'].contains(n_pos): # F | |||||
| note = 5 | note = 5 | ||||
| elif self.m_midi_map['7'].contains(n_pos): # G | |||||
| elif self.m_midiMap['7'].contains(n_pos): # G | |||||
| note = 7 | note = 7 | ||||
| elif self.m_midi_map['9'].contains(n_pos): # A | |||||
| elif self.m_midiMap['9'].contains(n_pos): # A | |||||
| note = 9 | note = 9 | ||||
| elif self.m_midi_map['11'].contains(n_pos):# B | |||||
| elif self.m_midiMap['11'].contains(n_pos):# B | |||||
| note = 11 | note = 11 | ||||
| else: | else: | ||||
| note = -1 | note = -1 | ||||
| @@ -271,9 +277,9 @@ class PixmapKeyboard(QWidget): | |||||
| # Paint clean keys (as background) | # Paint clean keys (as background) | ||||
| for octave in range(self.m_octaves): | for octave in range(self.m_octaves): | ||||
| if self.m_pixmap_mode == self.HORIZONTAL: | |||||
| if self.m_pixmapMode == self.HORIZONTAL: | |||||
| target = QRectF(self.p_width * octave, 0, self.p_width, self.p_height) | target = QRectF(self.p_width * octave, 0, self.p_width, self.p_height) | ||||
| elif self.m_pixmap_mode == self.VERTICAL: | |||||
| elif self.m_pixmapMode == self.VERTICAL: | |||||
| target = QRectF(0, self.p_height * octave, self.p_width, self.p_height) | target = QRectF(0, self.p_height * octave, self.p_width, self.p_height) | ||||
| else: | else: | ||||
| return | return | ||||
| @@ -316,13 +322,13 @@ class PixmapKeyboard(QWidget): | |||||
| # cannot paint this note either | # cannot paint this note either | ||||
| continue | continue | ||||
| if self.m_pixmap_mode == self.VERTICAL: | |||||
| if self.m_pixmapMode == self.VERTICAL: | |||||
| octave = self.m_octaves - octave - 1 | octave = self.m_octaves - octave - 1 | ||||
| if self.m_pixmap_mode == self.HORIZONTAL: | |||||
| if self.m_pixmapMode == self.HORIZONTAL: | |||||
| target = QRectF(pos.x() + (self.p_width * octave), 0, pos.width(), pos.height()) | target = QRectF(pos.x() + (self.p_width * octave), 0, pos.width(), pos.height()) | ||||
| source = QRectF(pos.x(), self.p_height, pos.width(), pos.height()) | source = QRectF(pos.x(), self.p_height, pos.width(), pos.height()) | ||||
| elif self.m_pixmap_mode == self.VERTICAL: | |||||
| elif self.m_pixmapMode == self.VERTICAL: | |||||
| target = QRectF(pos.x(), pos.y() + (self.p_height * octave), pos.width(), pos.height()) | target = QRectF(pos.x(), pos.y() + (self.p_height * octave), pos.width(), pos.height()) | ||||
| source = QRectF(self.p_width, pos.y(), pos.width(), pos.height()) | source = QRectF(self.p_width, pos.y(), pos.width(), pos.height()) | ||||
| else: | else: | ||||
| @@ -338,10 +344,10 @@ class PixmapKeyboard(QWidget): | |||||
| for octave in range(self.m_octaves): | for octave in range(self.m_octaves): | ||||
| for note in (1, 3, 6, 8, 10): | for note in (1, 3, 6, 8, 10): | ||||
| pos = self._getRectFromMidiNote(note) | pos = self._getRectFromMidiNote(note) | ||||
| if self.m_pixmap_mode == self.HORIZONTAL: | |||||
| if self.m_pixmapMode == self.HORIZONTAL: | |||||
| target = QRectF(pos.x() + (self.p_width * octave), 0, pos.width(), pos.height()) | target = QRectF(pos.x() + (self.p_width * octave), 0, pos.width(), pos.height()) | ||||
| source = QRectF(pos.x(), 0, pos.width(), pos.height()) | source = QRectF(pos.x(), 0, pos.width(), pos.height()) | ||||
| elif self.m_pixmap_mode == self.VERTICAL: | |||||
| elif self.m_pixmapMode == self.VERTICAL: | |||||
| target = QRectF(pos.x(), pos.y() + (self.p_height * octave), pos.width(), pos.height()) | target = QRectF(pos.x(), pos.y() + (self.p_height * octave), pos.width(), pos.height()) | ||||
| source = QRectF(0, pos.y(), pos.width(), pos.height()) | source = QRectF(0, pos.y(), pos.width(), pos.height()) | ||||
| else: | else: | ||||
| @@ -382,13 +388,13 @@ class PixmapKeyboard(QWidget): | |||||
| # cannot paint this note either | # cannot paint this note either | ||||
| continue | continue | ||||
| if self.m_pixmap_mode == self.VERTICAL: | |||||
| if self.m_pixmapMode == self.VERTICAL: | |||||
| octave = self.m_octaves - octave - 1 | octave = self.m_octaves - octave - 1 | ||||
| if self.m_pixmap_mode == self.HORIZONTAL: | |||||
| if self.m_pixmapMode == self.HORIZONTAL: | |||||
| target = QRectF(pos.x() + (self.p_width * octave), 0, pos.width(), pos.height()) | target = QRectF(pos.x() + (self.p_width * octave), 0, pos.width(), pos.height()) | ||||
| source = QRectF(pos.x(), self.p_height, pos.width(), pos.height()) | source = QRectF(pos.x(), self.p_height, pos.width(), pos.height()) | ||||
| elif self.m_pixmap_mode == self.VERTICAL: | |||||
| elif self.m_pixmapMode == self.VERTICAL: | |||||
| target = QRectF(pos.x(), pos.y() + (self.p_height * octave), pos.width(), pos.height()) | target = QRectF(pos.x(), pos.y() + (self.p_height * octave), pos.width(), pos.height()) | ||||
| source = QRectF(self.p_width, pos.y(), pos.width(), pos.height()) | source = QRectF(self.p_width, pos.y(), pos.width(), pos.height()) | ||||
| else: | else: | ||||
| @@ -401,11 +407,13 @@ class PixmapKeyboard(QWidget): | |||||
| painter.setPen(Qt.black) | painter.setPen(Qt.black) | ||||
| for i in range(self.m_octaves): | for i in range(self.m_octaves): | ||||
| if self.m_pixmap_mode == self.HORIZONTAL: | |||||
| if self.m_pixmapMode == self.HORIZONTAL: | |||||
| painter.drawText(i * 144, 48, 18, 18, Qt.AlignCenter, "C%i" % int(i + 2)) | painter.drawText(i * 144, 48, 18, 18, Qt.AlignCenter, "C%i" % int(i + 2)) | ||||
| elif self.m_pixmap_mode == self.VERTICAL: | |||||
| elif self.m_pixmapMode == self.VERTICAL: | |||||
| painter.drawText(45, (self.m_octaves * 144) - (i * 144) - 16, 18, 18, Qt.AlignCenter, "C%i" % int(i + 2)) | painter.drawText(45, (self.m_octaves * 144) - (i * 144) - 16, 18, 18, Qt.AlignCenter, "C%i" % int(i + 2)) | ||||
| event.accept() | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_updateOnce(self): | def slot_updateOnce(self): | ||||
| if self.m_needsUpdate: | if self.m_needsUpdate: | ||||
| @@ -417,4 +425,4 @@ class PixmapKeyboard(QWidget): | |||||
| return bool(baseNote in (1, 3, 6, 8, 10)) | return bool(baseNote in (1, 3, 6, 8, 10)) | ||||
| def _getRectFromMidiNote(self, note): | def _getRectFromMidiNote(self, note): | ||||
| return self.m_midi_map.get(str(note % 12)) | |||||
| return self.m_midiMap.get(str(note % 12)) | |||||