Sundpood v1.3

- Using pynput instead keyboard module (better working)
- Add settings of overlay control
This commit is contained in:
Ninnjah 2020-10-28 00:40:07 +03:00 committed by GitHub
parent a72c4d88a1
commit 3c30a81585
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

243
main.py
View file

@ -2,15 +2,16 @@ import os
import sys import sys
import json import json
import threading import threading
import keyboard
from pynput.keyboard import Listener
import soundfile as sf import soundfile as sf
import sounddevice as sd import sounddevice as sd
from pynput.keyboard import Listener
from PyQt5 import QtWidgets, QtGui, QtCore from PyQt5 import QtWidgets, QtGui, QtCore
import ui_preferences
import ui_sundpood import ui_sundpood
import ui_overlay import ui_overlay
import keys import keys
###! UI !###
class OverlayUi(QtWidgets.QMainWindow, ui_overlay.Ui_MainWindow): class OverlayUi(QtWidgets.QMainWindow, ui_overlay.Ui_MainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
@ -21,6 +22,11 @@ class OverlayUi(QtWidgets.QMainWindow, ui_overlay.Ui_MainWindow):
self.hide() self.hide()
win.show() win.show()
class PreferencesUi(QtWidgets.QMainWindow, ui_preferences.Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
class MainUi(QtWidgets.QMainWindow, ui_sundpood.Ui_MainWindow): class MainUi(QtWidgets.QMainWindow, ui_sundpood.Ui_MainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
@ -28,9 +34,13 @@ class MainUi(QtWidgets.QMainWindow, ui_sundpood.Ui_MainWindow):
def keyPressEvent(self, e): def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_F1: if e.key() == QtCore.Qt.Key_F1:
pref.close()
self.hide() self.hide()
over.show() over.show()
def closeEvent(self, event):
pref.close()
###! JSON !### ###! JSON !###
def jsonread(file): ## Чтение JSON def jsonread(file): ## Чтение JSON
@ -44,15 +54,29 @@ def jsonwrite(file, data): ## Запись JSON
###! FUNCTIONS !### ###! FUNCTIONS !###
def found_device(list_): # Поиск микшера VoiceMeeter def find_device(list_): # Поиск микшера VoiceMeeter
msg = QtWidgets.QMessageBox()
msg.setIcon(QtWidgets.QMessageBox.Critical)
msg.setText("You don't install VoiceMeeter")
msg.setInformativeText('install VoiceMetter from "redist" folder or download it from \nvb-audio.com/Voicemeeter')
msg.setWindowTitle('Error')
index = 0 index = 0
device = 'VoiceMeeter Input'
found = False
for i in list_: for i in list_:
if 'VoiceMeeter Input' in i['name']: if device not in i['name']:
break
index += 1 index += 1
elif device in i['name']:
found = True
break
if found == False:
msg.exec_()
exit()
return index return index
def sound_get(mode): # Сбор файлов def sound_get(): # Сбор файлов
def check_format(name, format_): # Проверка слова до точки с конца строки def check_format(name, format_): # Проверка слова до точки с конца строки
suf = '' suf = ''
while name[-1] != '.': while name[-1] != '.':
@ -71,14 +95,14 @@ def sound_get(mode): # Сбор файлов
return False return False
def sound_convert(path, name, format_): # Конвертация из форматов 'mp3' 'm4a' в format_ def sound_convert(path, name, format_): # Конвертация из форматов 'mp3' 'm4a' в format_
if os.path.exists('ffmpeg.exe'):
old_name = name old_name = name
if check_format(name, ['mp3', 'm4a']): if check_format(name, ['mp3', 'm4a']):
while name[-1] != '.': while name[-1] != '.':
name = name[:-1] name = name[:-1]
name += format_ name += format_
os.system(f'''ffmpeg.exe -i "{os.path.join(path, old_name)}" os.system(f'ffmpeg.exe -i "{os.path.join(path, old_name)}" "{os.path.join(path, name)}"')
"{os.path.join(path, name)}"''')
os.remove(f'{os.path.join(path, old_name)}') os.remove(f'{os.path.join(path, old_name)}')
return name return name
@ -88,28 +112,43 @@ def sound_get(mode): # Сбор файлов
msg.setInformativeText('download sound in .wav / .mp3 / .m4a format') msg.setInformativeText('download sound in .wav / .mp3 / .m4a format')
msg.setWindowTitle('Error') msg.setWindowTitle('Error')
if os.path.exists('settings.json') and mode == False: ffmsg = QtWidgets.QMessageBox()
sounds_list = jsonread('settings.json') ffmsg.setIcon(QtWidgets.QMessageBox.Warning)
ffmsg.setText("You don't have ffmpeg.exe in the program root folder")
ffmsg.setInformativeText('download ffmpeg from ffmpeg.org for converting sound files')
ffmsg.setWindowTitle('Error')
elif not os.path.exists('settings.json') or mode == True:
if os.path.exists('sound'): if os.path.exists('sound'):
if len(os.listdir('sound')) == 0: if len(os.listdir('sound')) == 0:
msg.exec_() msg.exec_()
exit()
menu = [] menu = []
sounds_list = ['sound\\'] sounds_list = ['sound\\']
for i in os.listdir('sound'): for i in os.listdir('sound'):
if os.path.exists('ffmpeg.exe') or not ffmsg:
if os.path.isfile(os.path.join('sound', i)): if os.path.isfile(os.path.join('sound', i)):
i = sound_convert('sound', i, 'wav') name = sound_convert('sound', i, 'wav')
if name == None:
sounds_list.append(i) sounds_list.append(i)
else:
sounds_list.append(name)
else: else:
sounds_list_cat = [os.path.join('sound', i)] sounds_list_cat = [os.path.join('sound', i)]
for x in os.listdir(os.path.join('sound', i)): for x in os.listdir(os.path.join('sound', i)):
if os.path.isfile(os.path.join('sound', i, x)): if os.path.isfile(os.path.join('sound', i, x)):
x = sound_convert(os.path.join('sound', i), x, 'wav') name = sound_convert(os.path.join('sound', i), x, 'wav')
if name == None:
sounds_list_cat.append(x) sounds_list_cat.append(x)
else:
sounds_list_cat.append(name)
menu.append(sounds_list_cat) menu.append(sounds_list_cat)
else:
print('else')
try:
ffmsg.exec_()
ffmsg = False
except AttributeError:
pass
menu.append(sounds_list) menu.append(sounds_list)
sounds = [] sounds = []
@ -120,42 +159,65 @@ def sound_get(mode): # Сбор файлов
if os.path.exists('settings.json'): if os.path.exists('settings.json'):
hotkeys = jsonread('settings.json')['hotkeys'] hotkeys = jsonread('settings.json')['hotkeys']
sounds_list = {'sound':sounds, KEYS_CMD = jsonread('settings.json')['KEYS_CMD']
sounds_list = { 'sounds':sounds,
'hotkeys':hotkeys, 'hotkeys':hotkeys,
'menu':menu} 'menu':menu,
'KEYS_CMD':KEYS_CMD}
else: else:
sounds_list = { 'sounds':sounds, sounds_list = { 'sounds':sounds,
'hotkeys':{'Push button':''}, 'hotkeys':{'Push button':''},
'menu':menu} 'menu':menu,
'KEYS_CMD':{
'select_move_up' :' ',# вверх
'select_move_down' :' ',# вниз
'select_move_left' :' ',# влево
'select_move_right' :' ',# вправо
'play_sound' :' ',# Играть
'stop_sound' :' ',# Остановить
}}
for i in COMBOS: for i in COMBOS:
i.addItems(sounds) i.addItems(sounds)
jsonwrite('settings.json', sounds_list) jsonwrite('settings.json', sounds_list)
else: else:
sounds_list = { 'sounds':'',
'hotkeys':{'Push button':''},
'menu':'',
'KEYS_CMD':{
'select_move_up' :' ',# вверх
'select_move_down' :' ',# вниз
'select_move_left' :' ',# влево
'select_move_right' :' ',# вправо
'play_sound' :' ',# Играть
'stop_sound' :' ',# Остановить
}}
jsonwrite('settings.json', sounds_list)
os.mkdir('sound')
msg.exec_() msg.exec_()
exit()
return sounds_list
def save(): # Сохранение списка хоткеев def save(): # Сохранение списка хоткеев
hotkeys = {} hotkeys = {}
sounds = sound_get(False) sounds = jsonread('settings.json')['sounds']
for i in range(len(COMBOS)): for i in range(len(COMBOS)):
hotkeys.setdefault(HOTKEYS[i].text(), COMBOS[i].currentText()) hotkeys.setdefault(HOTKEYS[i].text(), COMBOS[i].currentText())
sounds_list = {'sounds':sounds, 'hotkeys':hotkeys, 'menu':menu} KEYS_JSON = {}
for i in KEYS_CMD.keys():
KEYS_JSON.setdefault(COMMAND_DICT[i], KEYS_CMD[i])
sounds_list = {'sounds':sounds, 'hotkeys':hotkeys, 'menu':menu, 'KEYS_CMD':KEYS_JSON}
jsonwrite('settings.json', sounds_list) jsonwrite('settings.json', sounds_list)
sounds = None KEYS_JSON = None
hotkeys = None hotkeys = None
sounds = None
def play_sound(index): # Проигрываение звука def play_sound(index): # Проигрываение звука
print(index)
try: try:
filename = COMBOS[index].currentText() filename = COMBOS[index].currentText()
try: try:
data, fs = sf.read(os.path.join('sound', filename), dtype='float32') data, fs = sf.read(os.path.join('sound', filename), dtype='float32')
sd.play(data, fs) sd.play(data, fs)
keyboard.wait(sd.play())
sd.wait()
except: except:
pass pass
except: except:
@ -163,19 +225,20 @@ def play_sound(index): # Проигрываение зву
try: try:
data, fs = sf.read(os.path.join(menu[select[0]][0], filename), dtype='float32') data, fs = sf.read(os.path.join(menu[select[0]][0], filename), dtype='float32')
sd.play(data, fs) sd.play(data, fs)
keyboard.wait(sd.play())
sd.wait()
except: except:
pass pass
def hotkey_remap(btn): # Переназначение хоткеев def hotkey_remap(btn): # Переназначение хоткеев
def check(key): def check(key):
button = HOTKEYS[btn] button = HOTKEYS[btn]
key = str(key) key = str(key).replace("'",'')
if key not in keys.forbidden: if key not in keys.forbidden:
print(key) HOTKEYS_CMD[HOTKEYS_CMD.index(button.text())] = keys.dict_[key]
COMMANDS[COMMANDS.index(button.text())] = key.replace("'",'') button.setText(keys.dict_[key])
button.setText(key.replace("'",'')) elif key == 'Key.backspace':
HOTKEYS_CMD[HOTKEYS_CMD.index(button.text())] = ' '
button.setText(' ')
for i in HOTKEYS: for i in HOTKEYS:
if i != HOTKEYS[btn]: if i != HOTKEYS[btn]:
i.setEnabled(True) i.setEnabled(True)
@ -189,9 +252,35 @@ def hotkey_remap(btn): # Переназначение хо
on_release=check) on_release=check)
hotkey_remap_Listener.start() hotkey_remap_Listener.start()
def pref_remap(btn, func_):
def check(key):
key = str(key).replace("'",'')
if key not in keys.forbidden:
func = find_key(COMMAND_DICT, func_)
KEYS_CMD.update({func : key})
btn.setText(keys.dict_[key])
elif key == 'Key.backspace':
func = find_key(COMMAND_DICT, func_)
KEYS_CMD.update({func : ' '})
btn.setText(' ')
for i in PREF_BTN:
i.setEnabled(True)
return False
for i in PREF_BTN:
i.setEnabled(False)
hotkey_remap_Listener = Listener(
on_release=check)
hotkey_remap_Listener.start()
save()
def find_key(dict, val):
return next(key for key, value in dict.items() if value == val)
###! CONTROL !### ###! CONTROL !###
def key_check(key): # Хоткеи
def select_move(mode): def select_move(mode):
select[1] += mode[1] select[1] += mode[1]
select[0] += mode[0] select[0] += mode[0]
@ -204,22 +293,29 @@ def key_check(key): # Хоткеи
over.label.setText(menu[select[0]][select[1]]) over.label.setText(menu[select[0]][select[1]])
win.select_label.setText(menu[select[0]][select[1]]) win.select_label.setText(menu[select[0]][select[1]])
key = str(key) def key_check(key): # Хоткеи
if key.replace("'",'') in COMMANDS: key_n = ''
play_sound(COMMANDS.index(key.replace("'",''))) key = str(key).replace("'",'')
try:
keyboard.add_hotkey(72, select_move, args=[[0, -1]]) key_n = keys.dict_[key]
keyboard.add_hotkey(80, select_move, args=[[0, 1]]) except KeyError:
keyboard.add_hotkey(77, select_move, args=[[1, 0]]) pass
keyboard.add_hotkey(75, select_move, args=[[-1, 0]]) print(f'{key_n} in {HOTKEYS_CMD} -- {key_n in HOTKEYS_CMD}')
keyboard.add_hotkey(76, play_sound, args=['']) if key_n in HOTKEYS_CMD:
keyboard.add_hotkey(73, sd.stop) play_sound(HOTKEYS_CMD.index(key_n))
elif key in KEYS_CMD.values():
find_key(KEYS_CMD, key)()
def main(): # Интерфейс def main(): # Интерфейс
win.show() win.show()
key_check_Listener = Listener(
on_release=key_check)
key_check_Listener.start() key_check_Listener.start()
win.save_button.clicked.connect(save) win.save_button.clicked.connect(save)
win.actionpreferences.triggered.connect(pref.show)
win.hotkey_1.clicked.connect(lambda: hotkey_remap(0)) win.hotkey_1.clicked.connect(lambda: hotkey_remap(0))
win.hotkey_2.clicked.connect(lambda: hotkey_remap(1)) win.hotkey_2.clicked.connect(lambda: hotkey_remap(1))
win.hotkey_3.clicked.connect(lambda: hotkey_remap(2)) win.hotkey_3.clicked.connect(lambda: hotkey_remap(2))
@ -233,16 +329,25 @@ def main(): # Интерфейс
win.hotkey_11.clicked.connect(lambda: hotkey_remap(10)) win.hotkey_11.clicked.connect(lambda: hotkey_remap(10))
win.hotkey_12.clicked.connect(lambda: hotkey_remap(11)) win.hotkey_12.clicked.connect(lambda: hotkey_remap(11))
pref.play_sound.clicked.connect(
lambda: pref_remap(pref.play_sound, 'play_sound'))
pref.stop_sound.clicked.connect(
lambda: pref_remap(pref.stop_sound, 'stop_sound'))
pref.select_move_up.clicked.connect(
lambda: pref_remap(pref.select_move_up, 'select_move_up'))
pref.select_move_down.clicked.connect(
lambda: pref_remap(pref.select_move_down, 'select_move_down'))
pref.select_move_left.clicked.connect(
lambda: pref_remap(pref.select_move_left, 'select_move_left'))
pref.select_move_right.clicked.connect(
lambda: pref_remap(pref.select_move_right, 'select_move_right'))
if __name__ == '__main__': if __name__ == '__main__':
### Поиск устроства ввода ###
list_ = list(sd.query_devices())
index = found_device(list_)
sd.default.device = list_[index]['name']
### Создание окна ### ### Создание окна ###
app = QtWidgets.QApplication([]) app = QtWidgets.QApplication([])
over = OverlayUi() over = OverlayUi()
pref = PreferencesUi()
win = MainUi() win = MainUi()
COMBOS = [ COMBOS = [
win.combo0, win.combo0,
@ -270,22 +375,53 @@ if __name__ == '__main__':
win.hotkey_10, win.hotkey_10,
win.hotkey_11, win.hotkey_11,
win.hotkey_12,] win.hotkey_12,]
PREF_BTN = [
pref.select_move_up,
pref.select_move_down,
pref.select_move_left,
pref.select_move_right,
pref.play_sound,
pref.stop_sound,]
sound_get_dict = sound_get(True) ### Поиск устроства ввода ###
list_ = list(sd.query_devices())
index = find_device(list_)
sd.default.device = list_[index]['name']
sound_get()
### Глобальные переменные ### ### Глобальные переменные ###
sounds = sound_get_dict['hotkeys'] sound_get_dict = jsonread('settings.json')
hotkeys = sound_get_dict['hotkeys']
menu = sound_get_dict['menu'] menu = sound_get_dict['menu']
select = [0, 0] select = [0, 0]
COMMAND_DICT = {
lambda: select_move([0, -1]):'select_move_up', # вверх
lambda: select_move([0, 1]) :'select_move_down', # вниз
lambda: select_move([-1, 0]):'select_move_left', # влево
lambda: select_move([1, 0]) :'select_move_right', # вправо
lambda: play_sound('') :'play_sound', # Играть
lambda: sd.stop() :'stop_sound', # Остановить
}
KEYS_CMD = COMMAND_DICT.copy()
KEYS_JSON = sound_get_dict['KEYS_CMD']
for i in KEYS_CMD.keys():
KEYS_CMD.update({i:KEYS_JSON[COMMAND_DICT[i]]})
KEYS_JSON = None
combo = 0 combo = 0
for i in sounds.items(): for i in KEYS_CMD.values():
PREF_BTN[combo].setText(keys.dict_[i])
combo += 1
combo = 0
for i in hotkeys.items():
index = COMBOS[combo].findText(i[1]) index = COMBOS[combo].findText(i[1])
COMBOS[combo].setCurrentIndex(index) COMBOS[combo].setCurrentIndex(index)
HOTKEYS[combo].setText(i[0]) HOTKEYS[combo].setText(i[0])
combo += 1 combo += 1
combo = None combo = None
COMMANDS = [ HOTKEYS_CMD = [
HOTKEYS[0].text(), HOTKEYS[0].text(),
HOTKEYS[1].text(), HOTKEYS[1].text(),
HOTKEYS[2].text(), HOTKEYS[2].text(),
@ -299,8 +435,5 @@ if __name__ == '__main__':
HOTKEYS[10].text(), HOTKEYS[10].text(),
HOTKEYS[11].text(),] HOTKEYS[11].text(),]
key_check_Listener = Listener(
on_release=key_check)
main() main()
sys.exit(app.exec()) sys.exit(app.exec())