kitbash 1.5.2__tar.gz → 1.8.0__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.
- kitbash-1.8.0/PKG-INFO +128 -0
- kitbash-1.8.0/README.md +111 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/__init__.py +10 -2
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/__main__.py +4 -8
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/gui/drumkit_widget.py +14 -5
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/gui/kit_save_dialog.py +0 -1
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/gui/main_window.py +54 -81
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/gui/main_window.ui +13 -13
- kitbash-1.8.0/kitbash/install.py +42 -0
- kitbash-1.8.0/kitbash/jack_audio.py +78 -0
- kitbash-1.8.0/kitbash/res/kitbash-icon.png +0 -0
- kitbash-1.8.0/kitbash/res/kitbash-icon.svg +168 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/worker_threads.py +3 -3
- {kitbash-1.5.2 → kitbash-1.8.0}/pyproject.toml +7 -8
- kitbash-1.5.2/PKG-INFO +0 -22
- kitbash-1.5.2/README.md +0 -4
- kitbash-1.5.2/kitbash/jack_audio.py +0 -243
- kitbash-1.5.2/kitbash/res/kitbash-icon.png +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/.gitignore +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/LICENSE +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/gui/__init__.py +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/res/empty.sfz +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/res/group_expanded.svg +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/res/group_hidden.svg +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/scripts/bash_project.py +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/styles/light.css +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/kitbash/styles/system.css +0 -0
- {kitbash-1.5.2 → kitbash-1.8.0}/tests/file_save_dialog.py +0 -0
kitbash-1.8.0/PKG-INFO
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: kitbash
|
|
3
|
+
Version: 1.8.0
|
|
4
|
+
Summary: Provides universal settings, styles, cached icons, and pixmaps, and the base
|
|
5
|
+
Author-email: Leon Dionne <ldionne@dridesign.sh.cn>
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
8
|
+
Requires-Dist: log_soso >= 1.0.3
|
|
9
|
+
Requires-Dist: PyQt5
|
|
10
|
+
Requires-Dist: qt_liquid_pool >= 1.2.0
|
|
11
|
+
Requires-Dist: recent_items_list >= 1.1.2
|
|
12
|
+
Requires-Dist: sfzen >= 2.3.2
|
|
13
|
+
Requires-Dist: soso_qt_extras >= 1.7.0
|
|
14
|
+
Requires-Dist: xdg_soso >= 0.2.0
|
|
15
|
+
Project-URL: Home, https://github.com/Zen-Master-SoSo/kitbash
|
|
16
|
+
|
|
17
|
+
# KitBash
|
|
18
|
+
|
|
19
|
+
A GUI application which you can use to create a new SFZ drumkit from pieces of other drumkits.
|
|
20
|
+
|
|
21
|
+
## Intro
|
|
22
|
+
|
|
23
|
+
Got a drumkit [SFZ](https://sfzformat.com/) that sounds pretty good, but
|
|
24
|
+
there's just one instrument that doesn't quite cut it? Want to replace that one
|
|
25
|
+
snare, or even that whole set of tom-toms?
|
|
26
|
+
|
|
27
|
+
That's what kitbash was written for!
|
|
28
|
+
|
|
29
|
+
Kitbash allows you to create projects in which you can import mutiple drumkits
|
|
30
|
+
from SFZ files, select the pieces of each kit you want, then export the
|
|
31
|
+
finished drumkit to a new SFZ.
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
Starting with an empty project, use the "Edit" -> "Load Drumkit" menu, or click
|
|
36
|
+
on the "plus" symbol in the toolbar. You'll see all the instruments defined in
|
|
37
|
+
the drumkit you just loaded, grouped into categories, such as "Snares", "Tom
|
|
38
|
+
toms", "Hi-hats", etc.
|
|
39
|
+
|
|
40
|
+
### Audio preview
|
|
41
|
+
|
|
42
|
+
To listen to audio playback, you need to select an "Audio sink" from the dropdown
|
|
43
|
+
list at the top-right of the window. You audio out devices should be listed
|
|
44
|
+
there. Note that this is a JACK application, and your JACK audio connection kit
|
|
45
|
+
server must be running to play audio.
|
|
46
|
+
|
|
47
|
+
To preview the sound of each instrument, click on the instrument name.
|
|
48
|
+
Releasing the mouse stops the playback.
|
|
49
|
+
|
|
50
|
+
To preview the drumkit you are assembling, you need to send it MIDI note
|
|
51
|
+
events. Choose the MIDI source from the dropdown list at the top-right area of
|
|
52
|
+
the window, and send MIDI events. A MIDI source can be an external device, like
|
|
53
|
+
a MIDI keyboard, or the MIDI output of another program, such as
|
|
54
|
+
[qtractor](https://qtractor.org/), [MuseScore](https://musescore.com/), or
|
|
55
|
+
[JackMIDILooper](https://github.com/Zen-Master-SoSo/jack_midi_looper).
|
|
56
|
+
|
|
57
|
+
### Instrument selection
|
|
58
|
+
|
|
59
|
+
The instruments selected to be included in your final drumkit are indicated by
|
|
60
|
+
the check boxes next to the instrument and category names.
|
|
61
|
+
|
|
62
|
+
Check the box next to a category to select all the instruments in that category
|
|
63
|
+
for inclusion in your new drumkit. Check the checkbox next to any individual
|
|
64
|
+
instrument (i.e. "Ride Bell"), to include only that instrument.
|
|
65
|
+
|
|
66
|
+
When you load the first drumkit, all categories and instruments are selected.
|
|
67
|
+
Load another drumkit in the same way as you did the first (using the menu or
|
|
68
|
+
the toolbar). Selecting an instrument from one drumkit de-selects that
|
|
69
|
+
instrument from all other loaded drumkits.
|
|
70
|
+
|
|
71
|
+
You can make changes while playing a loop from the incoming MIDI source, and
|
|
72
|
+
the changes are (almost) immediately made to the "bashed" drumkit you are
|
|
73
|
+
making.
|
|
74
|
+
|
|
75
|
+
### Exporting SFZ
|
|
76
|
+
|
|
77
|
+
When you're satisfied with what you've selected, you can save the "bashed"
|
|
78
|
+
drumkit as an .sfz file in a new location. From the menu, select "File" ->
|
|
79
|
+
"Save Bashed Kit As..." and choose the location. Or, click the corresponding
|
|
80
|
+
icon in the toolbar.
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
### Saving a project
|
|
84
|
+
|
|
85
|
+
A "project" is a list of the source SFZs and which groups and instruments from
|
|
86
|
+
each them are selected. You can save a project for later, make whatever changes
|
|
87
|
+
you desire, and then export the SFZ you created again. This way, you don't have
|
|
88
|
+
to start from scratch every time you wish to make that one small change.
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## Install
|
|
92
|
+
|
|
93
|
+
Install in the usual way:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
$ pip install kitbash
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Requirements
|
|
100
|
+
|
|
101
|
+
You'll need both [JACK audio connection kit](https://jackaudio.org/) and
|
|
102
|
+
[liquidsfz](https://github.com/swesterfeld/liquidsfz) in order to have live
|
|
103
|
+
previews. You can run the program without either, but you won't be able to
|
|
104
|
+
listen to your changes as you are making them.
|
|
105
|
+
|
|
106
|
+
To install JACK:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
$ sudo apt install jackd
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
...or...
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
$ sudo dnf install jackd
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
To install liquidsfz:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
$ git clone https://github.com/swesterfeld/liquidsfz.git
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
... and follow the instructions found in the liquidsfz README to install it.
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
kitbash-1.8.0/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# KitBash
|
|
2
|
+
|
|
3
|
+
A GUI application which you can use to create a new SFZ drumkit from pieces of other drumkits.
|
|
4
|
+
|
|
5
|
+
## Intro
|
|
6
|
+
|
|
7
|
+
Got a drumkit [SFZ](https://sfzformat.com/) that sounds pretty good, but
|
|
8
|
+
there's just one instrument that doesn't quite cut it? Want to replace that one
|
|
9
|
+
snare, or even that whole set of tom-toms?
|
|
10
|
+
|
|
11
|
+
That's what kitbash was written for!
|
|
12
|
+
|
|
13
|
+
Kitbash allows you to create projects in which you can import mutiple drumkits
|
|
14
|
+
from SFZ files, select the pieces of each kit you want, then export the
|
|
15
|
+
finished drumkit to a new SFZ.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Starting with an empty project, use the "Edit" -> "Load Drumkit" menu, or click
|
|
20
|
+
on the "plus" symbol in the toolbar. You'll see all the instruments defined in
|
|
21
|
+
the drumkit you just loaded, grouped into categories, such as "Snares", "Tom
|
|
22
|
+
toms", "Hi-hats", etc.
|
|
23
|
+
|
|
24
|
+
### Audio preview
|
|
25
|
+
|
|
26
|
+
To listen to audio playback, you need to select an "Audio sink" from the dropdown
|
|
27
|
+
list at the top-right of the window. You audio out devices should be listed
|
|
28
|
+
there. Note that this is a JACK application, and your JACK audio connection kit
|
|
29
|
+
server must be running to play audio.
|
|
30
|
+
|
|
31
|
+
To preview the sound of each instrument, click on the instrument name.
|
|
32
|
+
Releasing the mouse stops the playback.
|
|
33
|
+
|
|
34
|
+
To preview the drumkit you are assembling, you need to send it MIDI note
|
|
35
|
+
events. Choose the MIDI source from the dropdown list at the top-right area of
|
|
36
|
+
the window, and send MIDI events. A MIDI source can be an external device, like
|
|
37
|
+
a MIDI keyboard, or the MIDI output of another program, such as
|
|
38
|
+
[qtractor](https://qtractor.org/), [MuseScore](https://musescore.com/), or
|
|
39
|
+
[JackMIDILooper](https://github.com/Zen-Master-SoSo/jack_midi_looper).
|
|
40
|
+
|
|
41
|
+
### Instrument selection
|
|
42
|
+
|
|
43
|
+
The instruments selected to be included in your final drumkit are indicated by
|
|
44
|
+
the check boxes next to the instrument and category names.
|
|
45
|
+
|
|
46
|
+
Check the box next to a category to select all the instruments in that category
|
|
47
|
+
for inclusion in your new drumkit. Check the checkbox next to any individual
|
|
48
|
+
instrument (i.e. "Ride Bell"), to include only that instrument.
|
|
49
|
+
|
|
50
|
+
When you load the first drumkit, all categories and instruments are selected.
|
|
51
|
+
Load another drumkit in the same way as you did the first (using the menu or
|
|
52
|
+
the toolbar). Selecting an instrument from one drumkit de-selects that
|
|
53
|
+
instrument from all other loaded drumkits.
|
|
54
|
+
|
|
55
|
+
You can make changes while playing a loop from the incoming MIDI source, and
|
|
56
|
+
the changes are (almost) immediately made to the "bashed" drumkit you are
|
|
57
|
+
making.
|
|
58
|
+
|
|
59
|
+
### Exporting SFZ
|
|
60
|
+
|
|
61
|
+
When you're satisfied with what you've selected, you can save the "bashed"
|
|
62
|
+
drumkit as an .sfz file in a new location. From the menu, select "File" ->
|
|
63
|
+
"Save Bashed Kit As..." and choose the location. Or, click the corresponding
|
|
64
|
+
icon in the toolbar.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### Saving a project
|
|
68
|
+
|
|
69
|
+
A "project" is a list of the source SFZs and which groups and instruments from
|
|
70
|
+
each them are selected. You can save a project for later, make whatever changes
|
|
71
|
+
you desire, and then export the SFZ you created again. This way, you don't have
|
|
72
|
+
to start from scratch every time you wish to make that one small change.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
## Install
|
|
76
|
+
|
|
77
|
+
Install in the usual way:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
$ pip install kitbash
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Requirements
|
|
84
|
+
|
|
85
|
+
You'll need both [JACK audio connection kit](https://jackaudio.org/) and
|
|
86
|
+
[liquidsfz](https://github.com/swesterfeld/liquidsfz) in order to have live
|
|
87
|
+
previews. You can run the program without either, but you won't be able to
|
|
88
|
+
listen to your changes as you are making them.
|
|
89
|
+
|
|
90
|
+
To install JACK:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
$ sudo apt install jackd
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
...or...
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
$ sudo dnf install jackd
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
To install liquidsfz:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
$ git clone https://github.com/swesterfeld/liquidsfz.git
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
... and follow the instructions found in the liquidsfz README to install it.
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
@@ -28,14 +28,14 @@ from functools import lru_cache
|
|
|
28
28
|
from PyQt5.QtCore import QSettings
|
|
29
29
|
from PyQt5.QtWidgets import QApplication, QSplitter
|
|
30
30
|
from qt_extras import DevilBox
|
|
31
|
-
from conn_jack import JackConnectError
|
|
32
31
|
|
|
33
|
-
__version__ = "1.
|
|
32
|
+
__version__ = "1.8.0"
|
|
34
33
|
|
|
35
34
|
APPLICATION_NAME = "kitbash"
|
|
36
35
|
PACKAGE_DIR = dirname(__file__)
|
|
37
36
|
DEFAULT_STYLE = 'system'
|
|
38
37
|
AUDIO_ICON_SIZE = 16
|
|
38
|
+
KEY_PREVIEW_VELOCITY = 'PreviewVelocity'
|
|
39
39
|
KEY_STYLE = 'Style'
|
|
40
40
|
KEY_SAMPLES_MODE = 'KitSaveDialog/SamplesMode'
|
|
41
41
|
KEY_RECENT_DRUMKIT_FOLDER = 'RecentDrumkitFolder'
|
|
@@ -44,8 +44,16 @@ KEY_RECENT_PROJECT_FOLDER = 'RecentProjectFolder'
|
|
|
44
44
|
KEY_RECENT_PROJECTS = 'RecentProjects'
|
|
45
45
|
KEY_SAMPLE_XPLORE_ROOT = 'SampleExplorer/Root'
|
|
46
46
|
KEY_SAMPLE_XPLORE_CURR = 'SampleExplorer/Current'
|
|
47
|
+
KEY_MIDI_SOURCE = 'MIDISource'
|
|
48
|
+
KEY_AUDIO_SINK = 'AudioSink'
|
|
47
49
|
|
|
48
50
|
|
|
51
|
+
def audio():
|
|
52
|
+
if not hasattr(audio, 'instance'):
|
|
53
|
+
from kitbash.jack_audio import Audio
|
|
54
|
+
audio.instance = Audio()
|
|
55
|
+
return audio.instance
|
|
56
|
+
|
|
49
57
|
@lru_cache
|
|
50
58
|
def __settings():
|
|
51
59
|
return QSettings('ZenSoSo', APPLICATION_NAME)
|
|
@@ -22,9 +22,8 @@ kitbash is a program you can use to combine parts of various SFZ files into a
|
|
|
22
22
|
new SFZ with instruments "borrowed" from the originals.
|
|
23
23
|
"""
|
|
24
24
|
import sys, os, argparse, logging
|
|
25
|
-
from PyQt5.QtWidgets import QApplication
|
|
26
|
-
from qt_extras import
|
|
27
|
-
from conn_jack import JackConnectError
|
|
25
|
+
from PyQt5.QtWidgets import QApplication, QErrorMessage
|
|
26
|
+
from qt_extras import exceptions_hook
|
|
28
27
|
from kitbash.gui.main_window import MainWindow
|
|
29
28
|
|
|
30
29
|
|
|
@@ -61,11 +60,8 @@ def main():
|
|
|
61
60
|
#-----------------------------------------------------------------------
|
|
62
61
|
|
|
63
62
|
app = QApplication([])
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
except JackConnectError:
|
|
67
|
-
DevilBox('Could not connect to JACK server. Is it running?')
|
|
68
|
-
sys.exit(1)
|
|
63
|
+
sys.excepthook = exceptions_hook
|
|
64
|
+
main_window = MainWindow(options)
|
|
69
65
|
main_window.show()
|
|
70
66
|
sys.exit(app.exec())
|
|
71
67
|
|
|
@@ -29,7 +29,7 @@ from PyQt5.QtWidgets import (QApplication, QVBoxLayout, QHBoxLayout, QLabel,
|
|
|
29
29
|
QFrame, QSizePolicy, QPushButton, QCheckBox)
|
|
30
30
|
from qt_extras import SigBlock
|
|
31
31
|
from sfzen.drumkits import PercussionInstrument
|
|
32
|
-
from kitbash import PACKAGE_DIR
|
|
32
|
+
from kitbash import PACKAGE_DIR, KEY_PREVIEW_VELOCITY, get_setting, audio
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
@lru_cache
|
|
@@ -64,9 +64,9 @@ class DrumkitWidget(QFrame):
|
|
|
64
64
|
self.sfz_filename = filename
|
|
65
65
|
self.moniker = basename(self.sfz_filename)
|
|
66
66
|
self.drumkit = None
|
|
67
|
-
self.
|
|
68
|
-
self.initial_height = None
|
|
67
|
+
self.synth = None
|
|
69
68
|
|
|
69
|
+
self.initial_height = None
|
|
70
70
|
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
|
|
71
71
|
|
|
72
72
|
main_layout = QVBoxLayout()
|
|
@@ -130,6 +130,7 @@ class DrumkitWidget(QFrame):
|
|
|
130
130
|
Fills the groups and instruments of this the DrumkitWidget.
|
|
131
131
|
"""
|
|
132
132
|
self.drumkit = drumkit
|
|
133
|
+
self.synth = audio().create_synth(self.sfz_filename)
|
|
133
134
|
for group in self.drumkit.percussion_groups.values():
|
|
134
135
|
if group.is_empty():
|
|
135
136
|
continue
|
|
@@ -162,14 +163,21 @@ class DrumkitWidget(QFrame):
|
|
|
162
163
|
"""
|
|
163
164
|
Triggered by InstrumentButton mouse press.
|
|
164
165
|
"""
|
|
165
|
-
self.
|
|
166
|
+
self.synth.noteon(
|
|
167
|
+
self.drumkit.midi_channel,
|
|
168
|
+
inst.pitch,
|
|
169
|
+
get_setting(KEY_PREVIEW_VELOCITY, 80, int)
|
|
170
|
+
)
|
|
166
171
|
|
|
167
172
|
@pyqtSlot(PercussionInstrument)
|
|
168
173
|
def slot_instrument_released(self, inst):
|
|
169
174
|
"""
|
|
170
175
|
Triggered by InstrumentButton mouse relase.
|
|
171
176
|
"""
|
|
172
|
-
self.
|
|
177
|
+
self.synth.noteoff(
|
|
178
|
+
self.drumkit.midi_channel,
|
|
179
|
+
inst.pitch
|
|
180
|
+
)
|
|
173
181
|
|
|
174
182
|
@pyqtSlot(QPushButton)
|
|
175
183
|
def slot_instrument_toggled(self, button):
|
|
@@ -187,6 +195,7 @@ class DrumkitWidget(QFrame):
|
|
|
187
195
|
"""
|
|
188
196
|
Triggered by the "remove" button click event.
|
|
189
197
|
"""
|
|
198
|
+
audio().delete_synth(self.synth)
|
|
190
199
|
self.sig_remove_drumkit.emit(self)
|
|
191
200
|
|
|
192
201
|
@pyqtSlot(bool)
|
|
@@ -31,20 +31,21 @@ from PyQt5.QtCore import Qt, QObject, pyqtSlot, QTimer, QThreadPool, QPoint, QCo
|
|
|
31
31
|
from PyQt5.QtWidgets import (
|
|
32
32
|
QApplication, QMainWindow, QMessageBox, QFileDialog, QAction, QActionGroup, QMenu)
|
|
33
33
|
from PyQt5.QtGui import QIcon
|
|
34
|
-
from qt_extras import ShutUpQT,
|
|
34
|
+
from qt_extras import ShutUpQT, DevilBox
|
|
35
35
|
from qt_extras.list_layout import VListLayout
|
|
36
36
|
from recent_items_list import RecentItemsList
|
|
37
37
|
from sfzen import SAMPLES_ABSPATH
|
|
38
38
|
from sfzen.drumkits import Drumkit
|
|
39
39
|
from kitbash import (
|
|
40
40
|
APPLICATION_NAME, PACKAGE_DIR, DEFAULT_STYLE,
|
|
41
|
-
styles, set_application_style, get_setting, set_setting, GeometrySaver,
|
|
42
|
-
KEY_STYLE, KEY_SAMPLES_MODE,
|
|
41
|
+
styles, set_application_style, get_setting, set_setting, GeometrySaver, audio,
|
|
42
|
+
KEY_PREVIEW_VELOCITY, KEY_STYLE, KEY_SAMPLES_MODE,
|
|
43
|
+
KEY_RECENT_DRUMKIT_FOLDER, KEY_RECENT_DRUMKITS,
|
|
43
44
|
KEY_RECENT_PROJECT_FOLDER, KEY_RECENT_PROJECTS)
|
|
44
45
|
from kitbash.worker_threads import KitLoader, KitBasher
|
|
45
|
-
from kitbash.jack_audio import Audio
|
|
46
46
|
from kitbash.gui.drumkit_widget import DrumkitWidget
|
|
47
47
|
from kitbash.gui.kit_save_dialog import KitSaveDialog
|
|
48
|
+
from kitbash.install import install
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
UPDATES_DEBOUNCE = 680
|
|
@@ -94,7 +95,18 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
94
95
|
# Setup background threadpool for KitLoader and KitBasher workers
|
|
95
96
|
self.background_threadpool = QThreadPool()
|
|
96
97
|
# Setup jack audio
|
|
97
|
-
self.audio =
|
|
98
|
+
self.audio = audio()
|
|
99
|
+
# Setup source/sink combo boxes:
|
|
100
|
+
self.cmb_midi_sources = self.audio.midi_in_combo_box(self)
|
|
101
|
+
self.lo_source_combo.replaceWidget(self.cmb_midi_src_placeholder, self.cmb_midi_sources)
|
|
102
|
+
self.cmb_midi_src_placeholder.setVisible(False)
|
|
103
|
+
self.cmb_midi_src_placeholder.deleteLater()
|
|
104
|
+
del self.cmb_midi_src_placeholder
|
|
105
|
+
self.cmb_audio_sinks = self.audio.audio_out_combo_box(self)
|
|
106
|
+
self.lo_sink_combo.replaceWidget(self.cmb_audio_sink_placeholder, self.cmb_audio_sinks)
|
|
107
|
+
self.cmb_audio_sink_placeholder.setVisible(False)
|
|
108
|
+
self.cmb_audio_sink_placeholder.deleteLater()
|
|
109
|
+
del self.cmb_audio_sink_placeholder
|
|
98
110
|
# Setup GUI elements
|
|
99
111
|
self.fill_style_menu()
|
|
100
112
|
self.setup_kits_area()
|
|
@@ -108,6 +120,7 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
108
120
|
self.audio.connect()
|
|
109
121
|
if self.options.Filename:
|
|
110
122
|
self.load_project(self.options.Filename)
|
|
123
|
+
install()
|
|
111
124
|
|
|
112
125
|
def setup_kits_area(self):
|
|
113
126
|
self.drumkit_widgets = VListLayout(end_space = 10)
|
|
@@ -122,7 +135,7 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
122
135
|
self.action_save_project.triggered.connect(self.slot_save_project)
|
|
123
136
|
self.action_save_project_as.triggered.connect(self.slot_save_project_as)
|
|
124
137
|
self.action_save_bashed_kit.triggered.connect(self.slot_save_kit)
|
|
125
|
-
self.
|
|
138
|
+
self.action_save_bashed_kit_as.triggered.connect(self.slot_save_kit_as)
|
|
126
139
|
self.action_add_drumkit.triggered.connect(self.slot_add_drumkit)
|
|
127
140
|
self.action_remove_all_kits.triggered.connect(self.slot_remove_all_kits)
|
|
128
141
|
self.action_reload_style.triggered.connect(self.slot_reload_style)
|
|
@@ -137,14 +150,8 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
137
150
|
self.b_copy_path.clicked.connect(self.slot_copy_kit_path)
|
|
138
151
|
self.b_add_drumkit.clicked.connect(self.slot_add_drumkit)
|
|
139
152
|
self.b_xruns.clicked.connect(self.slot_xruns_clicked)
|
|
140
|
-
self.
|
|
141
|
-
|
|
142
|
-
self.cmb_audio_sinks.currentTextChanged.connect(
|
|
143
|
-
self.audio.slot_audio_sink_selected)
|
|
144
|
-
self.audio.sig_sources_changed.connect(
|
|
145
|
-
self.slot_sources_changed)
|
|
146
|
-
self.audio.sig_sinks_changed.connect(
|
|
147
|
-
self.slot_sinks_changed)
|
|
153
|
+
self.spn_velocity.valueChanged.connect(self.slot_velocity_value_changed)
|
|
154
|
+
self.audio.sig_jack_ready.connect(self.slot_jack_ready)
|
|
148
155
|
|
|
149
156
|
def update_ui(self):
|
|
150
157
|
title = APPLICATION_NAME \
|
|
@@ -158,7 +165,11 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
158
165
|
self.action_new_project.setEnabled(has_kits)
|
|
159
166
|
self.action_save_project.setEnabled(has_kits and self.dirty)
|
|
160
167
|
self.action_save_project_as.setEnabled(has_kits)
|
|
161
|
-
self.action_save_bashed_kit.setEnabled(has_kits)
|
|
168
|
+
self.action_save_bashed_kit.setEnabled(has_kits and self.saved_sfz_filename is not None)
|
|
169
|
+
self.action_save_bashed_kit.setText(
|
|
170
|
+
'Save bashed kit' if self.saved_sfz_filename is None
|
|
171
|
+
else f'Save "{self.saved_sfz_filename}"')
|
|
172
|
+
self.action_save_bashed_kit_as.setEnabled(has_kits)
|
|
162
173
|
self.b_save_project.setEnabled(has_kits)
|
|
163
174
|
self.b_save_kit.setEnabled(has_kits)
|
|
164
175
|
self.b_copy_path.setVisible(bool(self.saved_sfz_filename))
|
|
@@ -218,7 +229,6 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
218
229
|
Starts project load; saves recent file name.
|
|
219
230
|
Permission to clear must already have been given.
|
|
220
231
|
"""
|
|
221
|
-
logging.debug('load_project %s', filename)
|
|
222
232
|
if exists(filename):
|
|
223
233
|
try:
|
|
224
234
|
with open(filename, 'r', encoding = 'utf-8') as fh:
|
|
@@ -251,18 +261,6 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
251
261
|
self.set_dirty(False)
|
|
252
262
|
self.statusbar.showMessage(f'Saved project at {self.project_filename}', MESSAGE_TIMEOUT)
|
|
253
263
|
|
|
254
|
-
def save_kit(self):
|
|
255
|
-
kit = self.bashed_kit.simplified()
|
|
256
|
-
kit.default_path = dirname(self.saved_sfz_filename)
|
|
257
|
-
try:
|
|
258
|
-
kit.save_as(self.saved_sfz_filename, self.saved_sfz_samples_mode)
|
|
259
|
-
logging.debug('Saved bashed SFZ at %s', self.saved_sfz_filename)
|
|
260
|
-
self.statusbar.showMessage(f'Saved {self.saved_sfz_filename}', MESSAGE_TIMEOUT)
|
|
261
|
-
except OSError as e:
|
|
262
|
-
DevilBox('Hardlinks between devices are not allowed.\n' +\
|
|
263
|
-
'Choose a different path or sample mode.' if e.errno == 18 \
|
|
264
|
-
else str(e))
|
|
265
|
-
|
|
266
264
|
def register_recent_project(self):
|
|
267
265
|
self.recent_projects.bump(self.project_filename)
|
|
268
266
|
set_setting(KEY_RECENT_PROJECT_FOLDER, dirname(self.project_filename))
|
|
@@ -332,41 +330,10 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
332
330
|
# -----------------------------------------------------------------
|
|
333
331
|
# JACK audio / source / sink management
|
|
334
332
|
|
|
335
|
-
@pyqtSlot(int)
|
|
336
|
-
def slot_jack_ready(self,
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
@pyqtSlot()
|
|
340
|
-
def slot_jack_down(self):
|
|
341
|
-
self.lbl_jack_state.setText('JACK is down')
|
|
342
|
-
|
|
343
|
-
@pyqtSlot()
|
|
344
|
-
def slot_sources_changed(self):
|
|
345
|
-
with SigBlock(self.cmb_midi_srcs):
|
|
346
|
-
self.cmb_midi_srcs.clear()
|
|
347
|
-
self.cmb_midi_srcs.addItem('')
|
|
348
|
-
for port in self.audio.conn_man.output_ports():
|
|
349
|
-
if port.is_midi:
|
|
350
|
-
self.cmb_midi_srcs.addItem(port.name)
|
|
351
|
-
if self.audio.synth.connected_midi_src_port:
|
|
352
|
-
self.cmb_midi_srcs.setCurrentText(self.audio.midi_src)
|
|
353
|
-
|
|
354
|
-
@pyqtSlot()
|
|
355
|
-
def slot_sinks_changed(self):
|
|
356
|
-
with SigBlock(self.cmb_audio_sinks):
|
|
357
|
-
self.cmb_audio_sinks.clear()
|
|
358
|
-
self.cmb_audio_sinks.addItem('')
|
|
359
|
-
valid_clients = set(
|
|
360
|
-
port.client_name for port in self.audio.conn_man.input_ports()
|
|
361
|
-
if port.is_audio )
|
|
362
|
-
for client in valid_clients:
|
|
363
|
-
self.cmb_audio_sinks.addItem(client)
|
|
364
|
-
if self.audio.synth.connected_audio_sink_ports:
|
|
365
|
-
self.cmb_audio_sinks.setCurrentText(self.audio.audio_sink)
|
|
366
|
-
|
|
367
|
-
@pyqtSlot(str)
|
|
368
|
-
def slot_midi_connected(self, port_name):
|
|
369
|
-
self.statusbar.showMessage(f'Connected to "{port_name}"', MESSAGE_TIMEOUT)
|
|
333
|
+
@pyqtSlot(bool, int)
|
|
334
|
+
def slot_jack_ready(self, state, _):
|
|
335
|
+
if not state:
|
|
336
|
+
DevilBox('JACK is down')
|
|
370
337
|
|
|
371
338
|
# -----------------------------------------------------------------
|
|
372
339
|
# Drumkit load / delete / instrument selection
|
|
@@ -402,8 +369,6 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
402
369
|
"""
|
|
403
370
|
drumkit_widget.set_drumkit(drumkit)
|
|
404
371
|
drumkit_widget.sig_inst_toggle.connect(self.slot_inst_toggle)
|
|
405
|
-
drumkit_widget.sig_note_on.connect(self.slot_note_on)
|
|
406
|
-
drumkit_widget.sig_note_off.connect(self.slot_note_off)
|
|
407
372
|
drumkit_widget.sig_remove_drumkit.connect(self.slot_remove_drumkit)
|
|
408
373
|
if self.project_loading:
|
|
409
374
|
drumkit_widget.apply_selections(
|
|
@@ -468,26 +433,23 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
468
433
|
Triggered from KitBasher signal when bashing is finished.
|
|
469
434
|
"""
|
|
470
435
|
self.bashed_kit = bashed_kit
|
|
471
|
-
|
|
472
|
-
self.bashed_kit.write(fob)
|
|
473
|
-
self.audio.synth.load(self.tempfile) # pylint: disable = no-member
|
|
436
|
+
self.audio.load_kit(self.bashed_kit)
|
|
474
437
|
self.statusbar.showMessage('Drumkit updated', MESSAGE_TIMEOUT)
|
|
475
438
|
|
|
476
|
-
@pyqtSlot(int)
|
|
477
|
-
def slot_note_on(self, pitch):
|
|
478
|
-
self.audio.synth.noteon(0, pitch, self.spn_velocity.value())
|
|
479
|
-
|
|
480
|
-
@pyqtSlot(int)
|
|
481
|
-
def slot_note_off(self, pitch):
|
|
482
|
-
self.audio.synth.noteoff(0, pitch)
|
|
483
|
-
|
|
484
439
|
# -----------------------------------------------------------------
|
|
485
440
|
# UI handling slots:
|
|
486
441
|
|
|
442
|
+
@pyqtSlot(int)
|
|
443
|
+
def slot_velocity_value_changed(self, value):
|
|
444
|
+
"""
|
|
445
|
+
Triggered by spn_velocity.valueChanged
|
|
446
|
+
"""
|
|
447
|
+
set_setting(KEY_PREVIEW_VELOCITY, value)
|
|
448
|
+
|
|
487
449
|
@pyqtSlot()
|
|
488
450
|
def slot_xruns_clicked(self):
|
|
489
451
|
"""
|
|
490
|
-
Triggered by b_xruns.click
|
|
452
|
+
Triggered by b_xruns.click
|
|
491
453
|
"""
|
|
492
454
|
self.base_xruns = self.current_xruns
|
|
493
455
|
self.b_xruns.setText('0')
|
|
@@ -616,15 +578,26 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
616
578
|
@pyqtSlot()
|
|
617
579
|
def slot_save_kit(self):
|
|
618
580
|
if self.saved_sfz_filename is None:
|
|
619
|
-
self.slot_save_kit_as()
|
|
581
|
+
return self.slot_save_kit_as()
|
|
582
|
+
try:
|
|
583
|
+
self.bashed_kit.save_as(
|
|
584
|
+
self.saved_sfz_filename, samples_mode = self.saved_sfz_samples_mode)
|
|
585
|
+
except OSError as e:
|
|
586
|
+
if e.errno == 18:
|
|
587
|
+
DevilBox('Hardlinks between devices are not allowed.\n' +
|
|
588
|
+
'Choose a different path or sample mode.')
|
|
589
|
+
elif e.errno == 2:
|
|
590
|
+
return self.slot_save_kit_as()
|
|
591
|
+
else:
|
|
592
|
+
DevilBox(str(e))
|
|
620
593
|
else:
|
|
621
|
-
self.
|
|
594
|
+
self.statusbar.showMessage(f'Saved {self.saved_sfz_filename}', MESSAGE_TIMEOUT)
|
|
595
|
+
self.update_ui()
|
|
622
596
|
|
|
623
597
|
@pyqtSlot()
|
|
624
598
|
def slot_save_kit_as(self):
|
|
625
599
|
"""
|
|
626
600
|
Triggered by "File -> Save bashed kit" menu
|
|
627
|
-
See also: slot_drumkit_bashed
|
|
628
601
|
"""
|
|
629
602
|
dlg = KitSaveDialog(self,
|
|
630
603
|
int(get_setting(KEY_SAMPLES_MODE, SAMPLES_ABSPATH)) \
|
|
@@ -633,7 +606,7 @@ class MainWindow(QMainWindow, GeometrySaver):
|
|
|
633
606
|
if dlg.exec_() and dlg.selected_file:
|
|
634
607
|
self.saved_sfz_filename = dlg.selected_file
|
|
635
608
|
self.saved_sfz_samples_mode = dlg.samples_mode
|
|
636
|
-
self.
|
|
609
|
+
self.slot_save_kit()
|
|
637
610
|
|
|
638
611
|
@pyqtSlot()
|
|
639
612
|
def slot_add_drumkit(self):
|