Browse Source

Add initial gui code

Signed-off-by: falkTX <falktx@falktx.com>
tags/v1.0.0
falkTX 1 year ago
parent
commit
3f750773c4
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
6 changed files with 644 additions and 0 deletions
  1. +1
    -0
      .gitignore
  2. +54
    -0
      gui/Makefile
  3. +156
    -0
      gui/settings.py
  4. +260
    -0
      gui/settings.ui
  5. +163
    -0
      gui/ui_settings.py
  6. +10
    -0
      gui/wineasio-settings

+ 1
- 0
.gitignore View File

@@ -1,3 +1,4 @@
*~
*.o
*.so
__pycache__

+ 54
- 0
gui/Makefile View File

@@ -0,0 +1,54 @@
#!/usr/bin/make -f
# Makefile for WineASIO Settings GUI #
# ---------------------------------- #
# Created by falkTX
#

PREFIX = /usr

PYUIC ?= pyuic5
PYRCC ?= pyrcc5

# ---------------------------------------------------------------------------------------------------------------------

all:

# ---------------------------------------------------------------------------------------------------------------------
# UI code

regen: ui_settings.py

ui_%.py: %.ui
$(PYUIC) $< -o $@

# ---------------------------------------------------------------------------------------------------------------------

clean:
rm -f *~ *.pyc ui_*.py

# ---------------------------------------------------------------------------------------------------------------------

install:
# Create directories
install -d $(DESTDIR)$(PREFIX)/bin/
install -d $(DESTDIR)$(PREFIX)/share/wineasio/

# Install script files and binaries
install -m 755 \
wineasio-settings \
$(DESTDIR)$(PREFIX)/bin/

# Adjust PREFIX value in script files
sed -i "s?X-PREFIX-X?$(PREFIX)?" \
$(DESTDIR)$(PREFIX)/bin/wineasio-settings

# Install code
install -m 644 *.py $(DESTDIR)$(PREFIX)/share/wineasio/

# ---------------------------------------------------------------------------------------------------------------------

uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/wineasio-settings
rm -rf $(DESTDIR)$(PREFIX)/share/wineasio/

# ---------------------------------------------------------------------------------------------------------------------

+ 156
- 0
gui/settings.py View File

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

# WineASIO Settings GUI
# Copyright (C) 2020 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

# ---------------------------------------------------------------------------------------------------------------------

import os
import sys

from PyQt5.QtCore import pyqtSlot, QDir
from PyQt5.QtWidgets import QApplication, QDialog

# ---------------------------------------------------------------------------------------------------------------------

from ui_settings import Ui_WineASIOSettings

# ---------------------------------------------------------------------------------------------------------------------

BUFFER_SIZE_LIST = (16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192)

HOME = QDir.homePath()

WINEPREFIX = os.getenv("WINEPREFIX")
if not WINEPREFIX:
WINEPREFIX = os.path.join(HOME, ".wine")

WINEASIO_PREFIX = "HKEY_CURRENT_USER\Software\Wine\WineASIO"

# ---------------------------------------------------------------------------------------------------------------------

def getWineASIOKeyValue(key: str, default: str):
wineFile = os.path.join(WINEPREFIX, "user.reg")

if not os.path.exists(wineFile):
return default

wineDumpF = open(wineFile, "r")
wineDump = wineDumpF.read()
wineDumpF.close()

wineDumpSplit = wineDump.split("[Software\\\\Wine\\\\WineASIO]")

if len(wineDumpSplit) <= 1:
return default

wineDumpSmall = wineDumpSplit[1].split("[")[0]
keyDumpSplit = wineDumpSmall.split('"%s"' % key)

if len(keyDumpSplit) <= 1:
return default

keyDumpSmall = keyDumpSplit[1].split(":")[1].split("\n")[0]
return keyDumpSmall

def smartHex(value: str, length: int):
hexStr = hex(value).replace("0x","")

if len(hexStr) < length:
zeroCount = length - len(hexStr)
hexStr = "%s%s" % ("0"*zeroCount, hexStr)

return hexStr

# ---------------------------------------------------------------------------------------------------------------------
# Set-up GUI (Tweaks, WineASIO)

# Force Restart Dialog
class WineASIOSettingsDialog(QDialog, Ui_WineASIOSettings):
def __init__(self):
QDialog.__init__(self, None)
self.setupUi(self)

self.changed = False
self.loadSettings()

self.accepted.connect(self.slot_saveSettings)
self.sb_ports_in.valueChanged.connect(self.slot_flagChanged)
self.sb_ports_out.valueChanged.connect(self.slot_flagChanged)
self.cb_ports_connect_hw.clicked.connect(self.slot_flagChanged)
self.cb_jack_autostart.clicked.connect(self.slot_flagChanged)
self.cb_jack_fixed_bsize.clicked.connect(self.slot_flagChanged)
self.cb_jack_buffer_size.currentIndexChanged[int].connect(self.slot_flagChanged)

def loadSettings(self):
ins = int(getWineASIOKeyValue("Number of inputs", "00000010"), 16)
outs = int(getWineASIOKeyValue("Number of outputs", "00000010"), 16)
hw = bool(int(getWineASIOKeyValue("Connect to hardware", "00000001"), 10))

autostart = bool(int(getWineASIOKeyValue("Autostart server", "00000000"), 10))
fixed_bsize = bool(int(getWineASIOKeyValue("Fixed buffersize", "00000001"), 10))
prefer_bsize = int(getWineASIOKeyValue("Preferred buffersize", "00000400"), 16)

for bsize in BUFFER_SIZE_LIST:
self.cb_jack_buffer_size.addItem(str(bsize))
if bsize == prefer_bsize:
self.cb_jack_buffer_size.setCurrentIndex(self.cb_jack_buffer_size.count()-1)

self.sb_ports_in.setValue(ins)
self.sb_ports_out.setValue(outs)
self.cb_ports_connect_hw.setChecked(hw)

self.cb_jack_autostart.setChecked(autostart)
self.cb_jack_fixed_bsize.setChecked(fixed_bsize)

@pyqtSlot()
def slot_flagChanged(self):
self.changed = True

@pyqtSlot()
def slot_saveSettings(self):
REGFILE = 'REGEDIT4\n'
REGFILE += '\n'
REGFILE += '[HKEY_CURRENT_USER\Software\Wine\WineASIO]\n'
REGFILE += '"Autostart server"=dword:0000000%i\n' % int(1 if self.cb_jack_autostart.isChecked() else 0)
REGFILE += '"Connect to hardware"=dword:0000000%i\n' % int(1 if self.cb_ports_connect_hw.isChecked() else 0)
REGFILE += '"Fixed buffersize"=dword:0000000%i\n' % int(1 if self.cb_jack_fixed_bsize.isChecked() else 0)
REGFILE += '"Number of inputs"=dword:000000%s\n' % smartHex(self.sb_ports_in.value(), 2)
REGFILE += '"Number of outputs"=dword:000000%s\n' % smartHex(self.sb_ports_out.value(), 2)
REGFILE += '"Preferred buffersize"=dword:0000%s\n' % smartHex(int(self.cb_jack_buffer_size.currentText()), 4)

with open("/tmp/wineasio-settings.reg", "w") as fh:
fh.write(REGFILE)

os.system("regedit /tmp/wineasio-settings.reg")

# ---------------------------------------------------------------------------------------------------------------------

if __name__ == '__main__':
# App initialization
app = QApplication(sys.argv)
app.setApplicationName("WineASIO Settings")
app.setApplicationVersion("1.0.0")
app.setOrganizationName("falkTX")

# Show GUI
gui = WineASIOSettingsDialog()
gui.show()

# Exit properly
sys.exit(app.exec_())

# ---------------------------------------------------------------------------------------------------------------------

+ 260
- 0
gui/settings.ui View File

@@ -0,0 +1,260 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WineASIOSettings</class>
<widget class="QDialog" name="WineASIOSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>310</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="group_ports">
<property name="title">
<string>Audio Ports</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_22">
<item>
<layout class="QHBoxLayout" name="layout_ports_in">
<item>
<widget class="QLabel" name="label_ports_in">
<property name="toolTip">
<string>Number of jack ports that wineasio will try to open.
Default is 16</string>
</property>
<property name="text">
<string>Number of inputs:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sb_ports_in">
<property name="toolTip">
<string>Number of jack ports that wineasio will try to open.
Default is 16</string>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="singleStep">
<number>2</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layout_ports_out">
<item>
<widget class="QLabel" name="label_ports_out">
<property name="toolTip">
<string>Number of jack ports that wineasio will try to open.
Default is 16</string>
</property>
<property name="text">
<string>Number of outputs:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sb_ports_out">
<property name="toolTip">
<string>Number of jack ports that wineasio will try to open.
Default is 16</string>
</property>
<property name="minimum">
<number>2</number>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="singleStep">
<number>2</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layout_ports_connect_hw">
<item>
<spacer name="spacer_ports_connect_hw">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>150</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="cb_ports_connect_hw">
<property name="toolTip">
<string>Try to connect the asio channels to the
physical I/O ports on your hardware.
Default is on</string>
</property>
<property name="text">
<string>Connect to hardware</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="group_jack">
<property name="title">
<string>JACK Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_23">
<item>
<layout class="QHBoxLayout" name="layout_jack_autostart">
<item>
<spacer name="spacer_jack_autostart">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>150</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="cb_jack_autostart">
<property name="toolTip">
<string>Enable wineasio to launch the jack server.
Default is off</string>
</property>
<property name="text">
<string>Autostart server</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layout_jack_fixed_bsize">
<item>
<spacer name="spacer_jack_fixed_bsize">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>150</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="cb_jack_fixed_bsize">
<property name="toolTip">
<string>When on, an asio app will be able to change the jack buffer size.
Default is off</string>
</property>
<property name="text">
<string>Fixed buffersize</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layout_jack_buffer_size">
<item>
<widget class="QLabel" name="label_jack_buffer_size">
<property name="text">
<string>Preferred buffersize:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cb_jack_buffer_size"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>WineASIOSettings</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>WineASIOSettings</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

+ 163
- 0
gui/ui_settings.py View File

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

# WineASIO Settings GUI
# Copyright (C) 2020 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

# ---------------------------------------------------------------------------------------------------------------------

from PyQt5.QtCore import Qt, QCoreApplication, QMetaObject
from PyQt5.QtWidgets import QCheckBox, QComboBox, QDialogButtonBox, QLabel, QGroupBox, QSpinBox
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy

# ---------------------------------------------------------------------------------------------------------------------

class Ui_WineASIOSettings(object):
OBJECT_NAME = "WineASIOSettings"

def setupUi(self, WineASIOSettings):
WineASIOSettings.setObjectName(self.OBJECT_NAME)
WineASIOSettings.resize(400, 310)
self.verticalLayout = QVBoxLayout(WineASIOSettings)
self.verticalLayout.setObjectName("verticalLayout")
self.group_ports = QGroupBox(WineASIOSettings)
self.group_ports.setObjectName("group_ports")
self.verticalLayout_22 = QVBoxLayout(self.group_ports)
self.verticalLayout_22.setObjectName("verticalLayout_22")
self.layout_ports_in = QHBoxLayout()
self.layout_ports_in.setObjectName("layout_ports_in")
self.label_ports_in = QLabel(self.group_ports)
self.label_ports_in.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
self.label_ports_in.setObjectName("label_ports_in")
self.layout_ports_in.addWidget(self.label_ports_in)
self.sb_ports_in = QSpinBox(self.group_ports)
self.sb_ports_in.setMaximum(128)
self.sb_ports_in.setSingleStep(2)
self.sb_ports_in.setObjectName("sb_ports_in")
self.layout_ports_in.addWidget(self.sb_ports_in)
self.verticalLayout_22.addLayout(self.layout_ports_in)
self.layout_ports_out = QHBoxLayout()
self.layout_ports_out.setObjectName("layout_ports_out")
self.label_ports_out = QLabel(self.group_ports)
self.label_ports_out.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
self.label_ports_out.setObjectName("label_ports_out")
self.layout_ports_out.addWidget(self.label_ports_out)
self.sb_ports_out = QSpinBox(self.group_ports)
self.sb_ports_out.setMinimum(2)
self.sb_ports_out.setMaximum(128)
self.sb_ports_out.setSingleStep(2)
self.sb_ports_out.setObjectName("sb_ports_out")
self.layout_ports_out.addWidget(self.sb_ports_out)
self.verticalLayout_22.addLayout(self.layout_ports_out)
self.layout_ports_connect_hw = QHBoxLayout()
self.layout_ports_connect_hw.setObjectName("layout_ports_connect_hw")
spacerItem = QSpacerItem(150, 20, QSizePolicy.Fixed, QSizePolicy.Minimum)
self.layout_ports_connect_hw.addItem(spacerItem)
self.cb_ports_connect_hw = QCheckBox(self.group_ports)
self.cb_ports_connect_hw.setObjectName("cb_ports_connect_hw")
self.layout_ports_connect_hw.addWidget(self.cb_ports_connect_hw)
self.verticalLayout_22.addLayout(self.layout_ports_connect_hw)
self.verticalLayout.addWidget(self.group_ports)
self.group_jack = QGroupBox(WineASIOSettings)
self.group_jack.setObjectName("group_jack")
self.verticalLayout_23 = QVBoxLayout(self.group_jack)
self.verticalLayout_23.setObjectName("verticalLayout_23")
self.layout_jack_autostart = QHBoxLayout()
self.layout_jack_autostart.setObjectName("layout_jack_autostart")
spacerItem1 = QSpacerItem(150, 20, QSizePolicy.Fixed, QSizePolicy.Minimum)
self.layout_jack_autostart.addItem(spacerItem1)
self.cb_jack_autostart = QCheckBox(self.group_jack)
self.cb_jack_autostart.setObjectName("cb_jack_autostart")
self.layout_jack_autostart.addWidget(self.cb_jack_autostart)
self.verticalLayout_23.addLayout(self.layout_jack_autostart)
self.layout_jack_fixed_bsize = QHBoxLayout()
self.layout_jack_fixed_bsize.setObjectName("layout_jack_fixed_bsize")
spacerItem2 = QSpacerItem(150, 20, QSizePolicy.Fixed, QSizePolicy.Minimum)
self.layout_jack_fixed_bsize.addItem(spacerItem2)
self.cb_jack_fixed_bsize = QCheckBox(self.group_jack)
self.cb_jack_fixed_bsize.setObjectName("cb_jack_fixed_bsize")
self.layout_jack_fixed_bsize.addWidget(self.cb_jack_fixed_bsize)
self.verticalLayout_23.addLayout(self.layout_jack_fixed_bsize)
self.layout_jack_buffer_size = QHBoxLayout()
self.layout_jack_buffer_size.setObjectName("layout_jack_buffer_size")
self.label_jack_buffer_size = QLabel(self.group_jack)
self.label_jack_buffer_size.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
self.label_jack_buffer_size.setObjectName("label_jack_buffer_size")
self.layout_jack_buffer_size.addWidget(self.label_jack_buffer_size)
self.cb_jack_buffer_size = QComboBox(self.group_jack)
self.cb_jack_buffer_size.setObjectName("cb_jack_buffer_size")
self.layout_jack_buffer_size.addWidget(self.cb_jack_buffer_size)
self.verticalLayout_23.addLayout(self.layout_jack_buffer_size)
self.verticalLayout.addWidget(self.group_jack)
self.buttonBox = QDialogButtonBox(WineASIOSettings)
self.buttonBox.setOrientation(Qt.Horizontal)
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok|QDialogButtonBox.RestoreDefaults)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout.addWidget(self.buttonBox)

self.retranslateUi(WineASIOSettings)
self.buttonBox.accepted.connect(WineASIOSettings.accept)
self.buttonBox.rejected.connect(WineASIOSettings.reject)
QMetaObject.connectSlotsByName(WineASIOSettings)

# ---------------------------------------------------------------------------------------------------------------------

def retranslateUi(self, WineASIOSettings):
_tr = QCoreApplication.translate
WineASIOSettings.setWindowTitle(_tr(self.OBJECT_NAME, "WineASIO Settings"))

# Audio Ports
self.group_ports.setTitle(_tr(self.OBJECT_NAME, "Audio Ports"))

self.label_ports_in.setText(_tr(self.OBJECT_NAME, "Number of inputs:"))
self.label_ports_in.setToolTip(_tr(self.OBJECT_NAME,
"Number of jack ports that wineasio will try to open.\n"
"Default is 16"))

self.sb_ports_in.setToolTip(_tr(self.OBJECT_NAME,
"Number of jack ports that wineasio will try to open.\n"
"Default is 16"))

self.label_ports_out.setText(_tr(self.OBJECT_NAME, "Number of outputs:"))
self.label_ports_out.setToolTip(_tr(self.OBJECT_NAME,
"Number of jack ports that wineasio will try to open.\n"
"Default is 16"))

self.sb_ports_out.setToolTip(_tr(self.OBJECT_NAME,
"Number of jack ports that wineasio will try to open.\n"
"Default is 16"))

self.cb_ports_connect_hw.setText(_tr(self.OBJECT_NAME, "Connect to hardware"))
self.cb_ports_connect_hw.setToolTip(_tr(self.OBJECT_NAME,
"Try to connect the asio channels to the\n"
"physical I/O ports on your hardware.\n"
"Default is on"))

# JACK Options
self.group_jack.setTitle(_tr(self.OBJECT_NAME, "JACK Options"))

self.cb_jack_autostart.setText(_tr(self.OBJECT_NAME, "Autostart server"))
self.cb_jack_autostart.setToolTip(_tr(self.OBJECT_NAME,
"Enable wineasio to launch the jack server.\n"
"Default is off"))

self.cb_jack_fixed_bsize.setText(_tr(self.OBJECT_NAME, "Fixed buffersize"))
self.cb_jack_fixed_bsize.setToolTip(_tr(self.OBJECT_NAME,
"When on, an asio app will be able to change the jack buffer size.\n"
"Default is off"))

self.label_jack_buffer_size.setText(_tr(self.OBJECT_NAME, "Preferred buffersize:"))

# ---------------------------------------------------------------------------------------------------------------------

+ 10
- 0
gui/wineasio-settings View File

@@ -0,0 +1,10 @@
#!/bin/bash

if [ -f /usr/bin/python3 ]; then
PYTHON=/usr/bin/python3
else
PYTHON=python
fi

PREFIX="X-PREFIX-X"
exec ${PYTHON} ${PREFIX}/share/wineasio/settings.py "$@"

Loading…
Cancel
Save