kitbash 1.11.0__tar.gz → 1.12.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {kitbash-1.11.0 → kitbash-1.12.1}/PKG-INFO +3 -3
  2. kitbash-1.12.1/kitbash/__init__.py +83 -0
  3. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/__main__.py +3 -1
  4. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/gui/kit_save_dialog.py +17 -3
  5. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/gui/main_window.py +28 -15
  6. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/jack_audio.py +2 -1
  7. {kitbash-1.11.0 → kitbash-1.12.1}/pyproject.toml +2 -2
  8. kitbash-1.11.0/kitbash/__init__.py +0 -147
  9. {kitbash-1.11.0 → kitbash-1.12.1}/.gitignore +0 -0
  10. {kitbash-1.11.0 → kitbash-1.12.1}/LICENSE +0 -0
  11. {kitbash-1.11.0 → kitbash-1.12.1}/README.md +0 -0
  12. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/gui/__init__.py +0 -0
  13. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/gui/drumkit_widget.py +0 -0
  14. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/gui/main_window.ui +0 -0
  15. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/res/empty.sfz +0 -0
  16. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/res/group_expanded.svg +0 -0
  17. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/res/group_hidden.svg +0 -0
  18. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/res/kitbash-icon.png +0 -0
  19. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/res/kitbash-icon.svg +0 -0
  20. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/res/save-sfz-icon.svg +0 -0
  21. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/scripts/bash_project.py +0 -0
  22. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/styles/light.css +0 -0
  23. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/styles/system.css +0 -0
  24. {kitbash-1.11.0 → kitbash-1.12.1}/kitbash/worker_threads.py +0 -0
  25. {kitbash-1.11.0 → kitbash-1.12.1}/tests/file_save_dialog.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kitbash
3
- Version: 1.11.0
4
- Summary: Provides universal settings, styles, cached icons, and pixmaps, and the base
3
+ Version: 1.12.1
4
+ Summary: A GUI application which you can use to create a new SFZ drumkit from pieces of other drumkits.
5
5
  Author-email: Leon Dionne <ldionne@dridesign.sh.cn>
6
6
  Description-Content-Type: text/markdown
7
7
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
@@ -10,7 +10,7 @@ Requires-Dist: PyQt5
10
10
  Requires-Dist: qt_liquid_pool >= 1.2.0
11
11
  Requires-Dist: recent_items_list >= 1.1.2
12
12
  Requires-Dist: sfzen >= 2.3.2
13
- Requires-Dist: soso_qt_extras >= 1.7.0
13
+ Requires-Dist: soso_qt_extras >= 1.13.0
14
14
  Requires-Dist: xdg_soso >= 1.1.0
15
15
  Project-URL: Home, https://github.com/Zen-Master-SoSo/kitbash
16
16
 
@@ -0,0 +1,83 @@
1
+ # kitbash/kitbash/__init__.py
2
+ #
3
+ # Copyright 2025-2026 Leon Dionne <ldionne@dridesign.sh.cn>
4
+ #
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 2 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
+ # MA 02110-1301, USA.
19
+ #
20
+ """
21
+ A GUI application which you can use to create a new SFZ drumkit from pieces of other drumkits.
22
+ """
23
+ import logging
24
+ from os.path import dirname, basename, splitext, join
25
+ from glob import glob
26
+ from functools import lru_cache
27
+ from PyQt5.QtCore import QSettings
28
+ from PyQt5.QtWidgets import QApplication, QSplitter
29
+ from qt_extras import DevilBox
30
+ from qt_extras.settings import get_setting
31
+ from xdg_soso import XDGSetup
32
+
33
+ __version__ = "1.12.1"
34
+
35
+ VENDOR_NAME = 'ZenSoSo'
36
+ APPLICATION_NAME = 'KitBash'
37
+ PACKAGE_DIR = dirname(__file__)
38
+ DEFAULT_STYLE = 'system'
39
+ AUDIO_ICON_SIZE = 16
40
+ KEY_PREVIEW_VELOCITY = 'PreviewVelocity'
41
+ KEY_STYLE = 'Style'
42
+ KEY_SAMPLES_MODE = 'KitSaveDialog/SamplesMode'
43
+ KEY_RECENT_DRUMKIT_FOLDER = 'RecentDrumkitFolder'
44
+ KEY_RECENT_DRUMKITS = 'RecentDrumkits'
45
+ KEY_RECENT_PROJECT_FOLDER = 'RecentProjectFolder'
46
+ KEY_RECENT_PROJECTS = 'RecentProjects'
47
+ KEY_SAMPLE_XPLORE_ROOT = 'SampleExplorer/Root'
48
+ KEY_SAMPLE_XPLORE_CURR = 'SampleExplorer/Current'
49
+ KEY_MIDI_SOURCE = 'MIDISource'
50
+ KEY_AUDIO_SINK = 'AudioSink'
51
+
52
+
53
+ def audio():
54
+ if not hasattr(audio, 'instance'):
55
+ from kitbash.jack_audio import Audio
56
+ audio.instance = Audio()
57
+ return audio.instance
58
+
59
+ @lru_cache
60
+ def styles():
61
+ return {
62
+ splitext(basename(path))[0] : path \
63
+ for path in glob(join(PACKAGE_DIR, 'styles', '*.css'))
64
+ }
65
+
66
+ def set_application_style():
67
+ style = get_setting(KEY_STYLE, DEFAULT_STYLE)
68
+ with open(styles()[style], 'r', encoding = 'utf-8') as cssfile:
69
+ QApplication.instance().setStyleSheet(cssfile.read())
70
+
71
+
72
+ class KitbashSetup(XDGSetup):
73
+
74
+ def __init__(self):
75
+ super().__init__(__package__, APPLICATION_NAME)
76
+ self.vendor_name = VENDOR_NAME
77
+ self.comment = "Bash together new .SFZ drumkits from pieces of existing ones."
78
+ self.application_icon = join(dirname(__file__), 'res', 'kitbash-icon.svg')
79
+ self.categories = ['AudioVideo', 'Audio']
80
+ self.keywords = ['Audio', 'Sound', 'midi', 'SFZ', 'Drumkit']
81
+
82
+
83
+ # end kitbash/kitbash/__init__.py
@@ -26,8 +26,9 @@ from os import environ
26
26
  from argparse import ArgumentParser
27
27
  from PyQt5.QtWidgets import QApplication
28
28
  from qt_extras import exceptions_hook
29
+ from qt_extras.settings import init_settings
29
30
  from xdg_soso import is_xdg
30
- from kitbash import KitbashSetup
31
+ from kitbash import VENDOR_NAME, KitbashSetup
31
32
  from kitbash.gui.main_window import MainWindow
32
33
 
33
34
 
@@ -81,6 +82,7 @@ menu.""")
81
82
  pass
82
83
  #-----------------------------------------------------------------------
83
84
  app = QApplication([])
85
+ init_settings(VENDOR_NAME, __package__)
84
86
  sys.excepthook = exceptions_hook
85
87
  main_window = MainWindow(options)
86
88
  main_window.show()
@@ -24,9 +24,11 @@ from os.path import realpath, splitext
24
24
  from functools import partial
25
25
  from PyQt5.QtCore import Qt, pyqtSlot, QCoreApplication
26
26
  from PyQt5.QtWidgets import QVBoxLayout, QLabel, QFileDialog, QGroupBox, QRadioButton
27
- from sfzen import (
28
- SAMPLES_ABSPATH, SAMPLES_RELPATH, SAMPLES_COPY, SAMPLES_SYMLINK, SAMPLES_HARDLINK)
29
- from kitbash import set_setting, GeometrySaver, KEY_SAMPLES_MODE
27
+ from qt_extras.geometry_saver import GeometrySaver
28
+ from qt_extras.settings import get_setting, set_setting
29
+ from sfzen import (SAMPLES_ABSPATH, SAMPLES_RELPATH, SAMPLES_COPY,
30
+ SAMPLES_SYMLINK, SAMPLES_HARDLINK)
31
+ from kitbash import KEY_SAMPLES_MODE
30
32
 
31
33
 
32
34
  class KitSaveDialog(QFileDialog, GeometrySaver):
@@ -77,6 +79,18 @@ class KitSaveDialog(QFileDialog, GeometrySaver):
77
79
  self.layout().addWidget(gb)
78
80
  self.selected_file = None
79
81
 
82
+ # -------------------------
83
+ # GeometrySaver overrides
84
+
85
+ def get_setting(self, key, default = None, type_ = None):
86
+ return get_setting(key, default, type_)
87
+
88
+ def set_setting(self, key, value):
89
+ set_setting(key, value)
90
+
91
+ # -------------------------
92
+ # Slots
93
+
80
94
  @pyqtSlot(int, bool)
81
95
  def slot_set_mode(self, mode, _):
82
96
  """
@@ -34,12 +34,14 @@ from PyQt5.QtWidgets import (
34
34
  from PyQt5.QtGui import QIcon
35
35
  from qt_extras import ShutUpQT, DevilBox
36
36
  from qt_extras.list_layout import VListLayout
37
+ from qt_extras.settings import get_setting, set_setting
38
+ from qt_extras.geometry_saver import GeometrySaver
37
39
  from recent_items_list import RecentItemsList
38
40
  from sfzen import SAMPLES_ABSPATH
39
41
  from sfzen.drumkits import Drumkit
40
42
  from kitbash import (
41
43
  APPLICATION_NAME, PACKAGE_DIR, DEFAULT_STYLE,
42
- styles, set_application_style, get_setting, set_setting, GeometrySaver, audio,
44
+ styles, set_application_style, audio,
43
45
  KEY_PREVIEW_VELOCITY, KEY_STYLE, KEY_SAMPLES_MODE,
44
46
  KEY_RECENT_DRUMKIT_FOLDER, KEY_RECENT_DRUMKITS,
45
47
  KEY_RECENT_PROJECT_FOLDER, KEY_RECENT_PROJECTS)
@@ -72,6 +74,7 @@ class MainWindow(QMainWindow, GeometrySaver):
72
74
  with ShutUpQT():
73
75
  uic.loadUi(join(PACKAGE_DIR, 'gui', 'main_window.ui'), self)
74
76
  self.setWindowIcon(QIcon(join(PACKAGE_DIR, 'res', 'kitbash-icon.png')))
77
+ self.action_save_bashed_kit.setIcon(QIcon(join(PACKAGE_DIR, 'res', 'save-sfz-icon.svg')))
75
78
  self.b_save_kit.setIcon(QIcon(join(PACKAGE_DIR, 'res', 'save-sfz-icon.svg')))
76
79
  self.b_save_kit.setIconSize(QSize(20, 20))
77
80
  # Setup signals
@@ -175,6 +178,15 @@ class MainWindow(QMainWindow, GeometrySaver):
175
178
  self.b_save_kit.setEnabled(has_kits)
176
179
  self.b_copy_path.setVisible(bool(self.saved_sfz_filename))
177
180
 
181
+ # -----------------------------------------------------------------
182
+ # GeometrySaver overrides
183
+
184
+ def get_setting(self, key, default = None, type_ = None):
185
+ return get_setting(key, default, type_)
186
+
187
+ def set_setting(self, key, value):
188
+ set_setting(key, value)
189
+
178
190
  # -----------------------------------------------------------------
179
191
  # Style functions:
180
192
 
@@ -579,21 +591,22 @@ class MainWindow(QMainWindow, GeometrySaver):
579
591
  @pyqtSlot()
580
592
  def slot_save_kit(self):
581
593
  if self.saved_sfz_filename is None:
582
- return self.slot_save_kit_as()
583
- try:
584
- self.bashed_kit.save_as(
585
- self.saved_sfz_filename, samples_mode = self.saved_sfz_samples_mode)
586
- except OSError as e:
587
- if e.errno == 18:
588
- DevilBox('Hardlinks between devices are not allowed.\n' +
589
- 'Choose a different path or sample mode.')
590
- elif e.errno == 2:
591
- return self.slot_save_kit_as()
592
- else:
593
- DevilBox(str(e))
594
+ self.slot_save_kit_as()
594
595
  else:
595
- self.statusbar.showMessage(f'Saved {self.saved_sfz_filename}', MESSAGE_TIMEOUT)
596
- self.update_ui()
596
+ try:
597
+ self.bashed_kit.save_as(
598
+ self.saved_sfz_filename, samples_mode = self.saved_sfz_samples_mode)
599
+ except OSError as e:
600
+ if e.errno == 18:
601
+ DevilBox('Hardlinks between devices are not allowed.\n' +
602
+ 'Choose a different path or sample mode.')
603
+ elif e.errno == 2:
604
+ self.slot_save_kit_as()
605
+ else:
606
+ DevilBox(str(e))
607
+ else:
608
+ self.statusbar.showMessage(f'Saved {self.saved_sfz_filename}', MESSAGE_TIMEOUT)
609
+ self.update_ui()
597
610
 
598
611
  @pyqtSlot()
599
612
  def slot_save_kit_as(self):
@@ -23,8 +23,9 @@ Provides MainWindow of the kitbash application.
23
23
  import logging # pylint: disable = unused-import
24
24
  from tempfile import mkstemp
25
25
  from os import unlink
26
+ from qt_extras.settings import get_setting, set_setting
26
27
  from qt_liquid_pool import LiquidPool
27
- from kitbash import get_setting, set_setting, KEY_MIDI_SOURCE, KEY_AUDIO_SINK
28
+ from kitbash import KEY_MIDI_SOURCE, KEY_AUDIO_SINK
28
29
 
29
30
 
30
31
  class Audio(LiquidPool):
@@ -11,7 +11,7 @@ dependencies = [
11
11
  "qt_liquid_pool >= 1.2.0",
12
12
  "recent_items_list >= 1.1.2",
13
13
  "sfzen >= 2.3.2",
14
- "soso_qt_extras >= 1.7.0",
14
+ "soso_qt_extras >= 1.13.0",
15
15
  "xdg_soso >= 1.1.0"
16
16
  ]
17
17
 
@@ -27,7 +27,7 @@ requires = ["flit_core >=3.2,<4"]
27
27
  build-backend = "flit_core.buildapi"
28
28
 
29
29
  [bumpver]
30
- current_version = "1.11.0"
30
+ current_version = "1.12.1"
31
31
  version_pattern = "MAJOR.MINOR.PATCH"
32
32
  commit_message = "Bump version {old_version} -> {new_version}"
33
33
  commit = true
@@ -1,147 +0,0 @@
1
- # kitbash/kitbash/__init__.py
2
- #
3
- # Copyright 2025-2026 Leon Dionne <ldionne@dridesign.sh.cn>
4
- #
5
- # This program is free software; you can redistribute it and/or modify
6
- # it under the terms of the GNU General Public License as published by
7
- # the Free Software Foundation; either version 2 of the License, or
8
- # (at your option) any later version.
9
- #
10
- # This program is distributed in the hope that it will be useful,
11
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- # GNU General Public License for more details.
14
- #
15
- # You should have received a copy of the GNU General Public License
16
- # along with this program; if not, write to the Free Software
17
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
- # MA 02110-1301, USA.
19
- #
20
- """
21
- Provides universal settings, styles, cached icons, and pixmaps, and the base
22
- class of windows which save and restore their own geometry.
23
- """
24
- import logging
25
- from os.path import dirname, basename, splitext, join
26
- from glob import glob
27
- from functools import lru_cache
28
- from PyQt5.QtCore import QSettings
29
- from PyQt5.QtWidgets import QApplication, QSplitter
30
- from qt_extras import DevilBox
31
- from xdg_soso import XDGSetup
32
-
33
- __version__ = "1.11.0"
34
-
35
- APPLICATION_NAME = "kitbash"
36
- PACKAGE_DIR = dirname(__file__)
37
- DEFAULT_STYLE = 'system'
38
- AUDIO_ICON_SIZE = 16
39
- KEY_PREVIEW_VELOCITY = 'PreviewVelocity'
40
- KEY_STYLE = 'Style'
41
- KEY_SAMPLES_MODE = 'KitSaveDialog/SamplesMode'
42
- KEY_RECENT_DRUMKIT_FOLDER = 'RecentDrumkitFolder'
43
- KEY_RECENT_DRUMKITS = 'RecentDrumkits'
44
- KEY_RECENT_PROJECT_FOLDER = 'RecentProjectFolder'
45
- KEY_RECENT_PROJECTS = 'RecentProjects'
46
- KEY_SAMPLE_XPLORE_ROOT = 'SampleExplorer/Root'
47
- KEY_SAMPLE_XPLORE_CURR = 'SampleExplorer/Current'
48
- KEY_MIDI_SOURCE = 'MIDISource'
49
- KEY_AUDIO_SINK = 'AudioSink'
50
-
51
-
52
- def audio():
53
- if not hasattr(audio, 'instance'):
54
- from kitbash.jack_audio import Audio
55
- audio.instance = Audio()
56
- return audio.instance
57
-
58
- @lru_cache
59
- def __settings():
60
- return QSettings('ZenSoSo', APPLICATION_NAME)
61
-
62
- def get_setting(key, default = None, type_ = None):
63
- value = __settings().value(key, default)
64
- if type_:
65
- if value is None:
66
- return type_()
67
- if type_ is bool:
68
- return value == '1'
69
- return type_(value)
70
- return value
71
-
72
- def set_setting(key, value):
73
- if isinstance(value, bool):
74
- value = '1' if value else '0'
75
- __settings().setValue(key, value)
76
-
77
- def delete_setting(key):
78
- __settings().remove(key)
79
-
80
- @lru_cache
81
- def styles():
82
- return {
83
- splitext(basename(path))[0] : path \
84
- for path in glob(join(PACKAGE_DIR, 'styles', '*.css'))
85
- }
86
-
87
- def set_application_style():
88
- style = get_setting(KEY_STYLE, DEFAULT_STYLE)
89
- with open(styles()[style], 'r', encoding = 'utf-8') as cssfile:
90
- QApplication.instance().setStyleSheet(cssfile.read())
91
-
92
-
93
- class GeometrySaver:
94
- """
95
- Provides classes declared in this project which inherit from QDialog methods to
96
- easily save/restore window / splitter geometry.
97
-
98
- Geometry is saved in this project's QSettings accessed as "settings()"
99
- """
100
-
101
- def restore_geometry(self):
102
- if not hasattr(self, 'restoreGeometry'):
103
- logging.error('Object of type %s has no "restoreGeometry" function',
104
- self.__class__.__name__)
105
- return
106
- geometry = get_setting(self.__geometry_key())
107
- if geometry is not None:
108
- self.restoreGeometry(geometry) # pylint: disable = no-member
109
- # pylint: disable-next = no-member
110
- for splitter in self.findChildren(QSplitter):
111
- geometry = get_setting(self.__splitter_geometry_key(splitter))
112
- if geometry is not None:
113
- splitter.restoreState(geometry) # pylint: disable = no-member
114
-
115
- def save_geometry(self):
116
- if not hasattr(self, 'saveGeometry'):
117
- logging.error('Object of type %s has no "saveGeometry" function',
118
- self.__class__.__name__)
119
- return
120
- set_setting(
121
- self.__geometry_key(),
122
- self.saveGeometry()) # pylint: disable = no-member
123
- # pylint: disable-next = no-member
124
- for splitter in self.findChildren(QSplitter):
125
- set_setting(
126
- self.__splitter_geometry_key(splitter),
127
- splitter.saveState()) # pylint: disable = no-member
128
-
129
- def __geometry_key(self):
130
- return f'{self.__class__.__name__}/geometry'
131
-
132
- def __splitter_geometry_key(self, splitter):
133
- return f'{self.__class__.__name__}/{splitter.objectName()}/geometry'
134
-
135
-
136
- class KitbashSetup(XDGSetup):
137
-
138
- def __init__(self):
139
- super().__init__('kitbash', 'Kitbash')
140
- self._comment = "Bash together new .SFZ drumkits from pieces of existing ones."
141
- self._vendor_name = 'zen_soso'
142
- self._application_icon = join(dirname(__file__), 'res', 'kitbash-icon.svg')
143
- self._categories = ['AudioVideo', 'Audio']
144
- self._keywords = ['Audio', 'Sound', 'midi', 'SFZ', 'Drumkit']
145
-
146
-
147
- # end kitbash/kitbash/__init__.py
File without changes
File without changes
File without changes
File without changes