kitstarter 0.2.2__tar.gz → 0.3.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.
Files changed (25) hide show
  1. {kitstarter-0.2.2 → kitstarter-0.3.0}/PKG-INFO +2 -2
  2. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/__init__.py +3 -3
  3. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/gui/main_window.py +8 -2
  4. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/gui/samples_widget.py +27 -24
  5. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/pindb.py +10 -2
  6. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/starter_kits.py +7 -14
  7. {kitstarter-0.2.2 → kitstarter-0.3.0}/pyproject.toml +2 -2
  8. {kitstarter-0.2.2 → kitstarter-0.3.0}/.gitignore +0 -0
  9. {kitstarter-0.2.2 → kitstarter-0.3.0}/LICENSE +0 -0
  10. {kitstarter-0.2.2 → kitstarter-0.3.0}/README.md +0 -0
  11. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/gui/__init__.py +0 -0
  12. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/gui/main_window.ui +0 -0
  13. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/arrow-down-disabled.svg +0 -0
  14. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/arrow-down-enabled.svg +0 -0
  15. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/arrow-up-disabled.svg +0 -0
  16. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/arrow-up-enabled.svg +0 -0
  17. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/delete.svg +0 -0
  18. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/empty.sfz +0 -0
  19. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/inst-complete.svg +0 -0
  20. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/inst-incomplete.svg +0 -0
  21. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/pin.svg +0 -0
  22. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/sample-mismatch.svg +0 -0
  23. {kitstarter-0.2.2 → kitstarter-0.3.0}/kitstarter/res/sample-okay.svg +0 -0
  24. {kitstarter-0.2.2 → kitstarter-0.3.0}/tests/pindb.py +0 -0
  25. {kitstarter-0.2.2 → kitstarter-0.3.0}/tests/samples_widget.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kitstarter
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: kitstarter is a program you can use to "sketch in" a drumkit SFZ file.
5
5
  Author-email: Leon Dionne <ldionne@dridesign.sh.cn>
6
6
  Description-Content-Type: text/markdown
@@ -9,7 +9,7 @@ Requires-Dist: PyQt5
9
9
  Requires-Dist: soso_qt_extras >= 1.6.0
10
10
  Requires-Dist: conn_jack
11
11
  Requires-Dist: midi_notes
12
- Requires-Dist: sfzen >= 1.2.0
12
+ Requires-Dist: sfzen >= 1.2.0, <= 2.0.0
13
13
  Requires-Dist: liquiphy
14
14
  Requires-Dist: soundfile
15
15
  Requires-Dist: jack_audio_player
@@ -15,7 +15,7 @@ from PyQt5.QtWidgets import QApplication, QWidget, QSplitter
15
15
  from qt_extras import DevilBox
16
16
  from conn_jack import JackConnectError
17
17
 
18
- __version__ = "0.2.2"
18
+ __version__ = "0.3.0"
19
19
 
20
20
 
21
21
  APPLICATION_NAME = "KitStarter"
@@ -77,13 +77,13 @@ def _geometry_key(widget):
77
77
  """
78
78
  Automatic QSettings key generated from class name.
79
79
  """
80
- return f'{type(widget).__name__}/geometry'
80
+ return f'{widget.__class__.__name__}/geometry'
81
81
 
82
82
  def _splitter_geometry_key(widget, splitter):
83
83
  """
84
84
  Automatic QSettings key generated from class name.
85
85
  """
86
- return f'{type(widget).__name__}/{splitter.objectName()}/geometry'
86
+ return f'{widget.__class__.__name__}/{splitter.objectName()}/geometry'
87
87
 
88
88
  QWidget.restore_geometry = _restore_geometry
89
89
  QWidget.save_geometry = _save_geometry
@@ -2,7 +2,10 @@
2
2
  #
3
3
  # Copyright 2025 Leon Dionne <ldionne@dridesign.sh.cn>
4
4
  #
5
- import os, logging, platform, subprocess, tempfile
5
+ """
6
+ Provides MainWindow of the kitstarter application.
7
+ """
8
+ import os, logging, tempfile
6
9
  from os.path import join, dirname, basename, abspath, splitext
7
10
  from functools import lru_cache
8
11
  from collections import namedtuple
@@ -39,6 +42,9 @@ MESSAGE_TIMEOUT = 3000
39
42
 
40
43
 
41
44
  class MainWindow(QMainWindow):
45
+ """
46
+ User interface of the kitstarter application.
47
+ """
42
48
 
43
49
  sig_ports_complete = pyqtSignal() # \
44
50
  sig_sources_changed = pyqtSignal() # Used to decouple JackConnectionManager callbacks
@@ -369,7 +375,7 @@ class MainWindow(QMainWindow):
369
375
  # file tree / sample display management
370
376
 
371
377
  @pyqtSlot(int)
372
- def slot_instrument_changed(self, index):
378
+ def slot_instrument_changed(self, _):
373
379
  self.chk_filter_instrument.setText('Filter "{}"'.format(
374
380
  self.lst_instruments.currentItem().text()))
375
381
  if self.chk_filter_instrument.isChecked():
@@ -2,6 +2,9 @@
2
2
  #
3
3
  # Copyright 2025 Leon Dionne <ldionne@dridesign.sh.cn>
4
4
  #
5
+ """
6
+ Provides classes used inside a Qt dialog for editing a multi-sample instrument.
7
+ """
5
8
  import logging
6
9
  from os.path import join, basename
7
10
  from math import sqrt
@@ -161,23 +164,23 @@ class VelocityGraph(_Track):
161
164
  if self.hover_point_index is None:
162
165
  self.range_change_event(event)
163
166
  else:
164
- self.sample._velcurves[self.hover_point_index] = Velcurve(
165
- self.sample._velcurves[self.hover_point_index].velocity \
167
+ self.sample.velcurves[self.hover_point_index] = Velcurve(
168
+ self.sample.velcurves[self.hover_point_index].velocity \
166
169
  if event.modifiers() & Qt.ControlModifier \
167
170
  else self.x2v(event.x()),
168
- self.sample._velcurves[self.hover_point_index].amplitude \
171
+ self.sample.velcurves[self.hover_point_index].amplitude \
169
172
  if event.modifiers() & Qt.ShiftModifier \
170
173
  else self.y2a(event.y())
171
174
  )
172
175
  self.update()
173
- elif event.buttons() == Qt.NoButton and self.sample._velcurves:
176
+ elif event.buttons() == Qt.NoButton and self.sample.velcurves:
174
177
  near_points = [ (
175
178
  sqrt(
176
179
  pow(abs(self.v2x(velcurve.velocity) - event.x()), 2) +
177
180
  pow(abs(self.a2y(velcurve.amplitude) - event.y()), 2)
178
181
  ),
179
182
  index
180
- ) for index, velcurve in enumerate(self.sample._velcurves) ]
183
+ ) for index, velcurve in enumerate(self.sample.velcurves) ]
181
184
  near_points.sort()
182
185
  hover_point_index = near_points[0][1] if near_points[0][0] < POLAR_SNAP_RANGE else None
183
186
  if hover_point_index != self.hover_point_index:
@@ -192,7 +195,7 @@ class VelocityGraph(_Track):
192
195
  self.hover_point_grabbed = True
193
196
  self.update()
194
197
 
195
- def mouseReleaseEvent(self, event):
198
+ def mouseReleaseEvent(self, _):
196
199
  if self.hover_point_grabbed:
197
200
  self.hover_point_grabbed = False
198
201
  self.sig_value_changed.emit()
@@ -240,8 +243,8 @@ class VelocityGraph(_Track):
240
243
  # line across to lovel:
241
244
  points.append(QPointF(self.v2x(self.lovel), self.rect().bottom()))
242
245
 
243
- if self.sample._velcurves:
244
- for velcurve in self.sample._velcurves:
246
+ if self.sample.velcurves:
247
+ for velcurve in self.sample.velcurves:
245
248
  points.append(QPointF(self.v2x(velcurve.velocity), self.a2y(velcurve.amplitude)))
246
249
  else:
247
250
  points.append(QPointF(self.v2x(self.lovel), self.v2y(self.lovel)))
@@ -264,7 +267,7 @@ class VelocityGraph(_Track):
264
267
  painter.drawLine(start, end)
265
268
  start = end
266
269
 
267
- for index, velcurve in enumerate(self.sample._velcurves):
270
+ for index, velcurve in enumerate(self.sample.velcurves):
268
271
  if self.hover_point_index == index:
269
272
  painter.setPen(self.velcurve_pen_grabbed \
270
273
  if self.hover_point_grabbed else self.velcurve_pen_hover)
@@ -325,7 +328,7 @@ class VelocityGraph(_Track):
325
328
  if lovel < hivel else None
326
329
 
327
330
  def update_velcurves(self):
328
- velcurves = []
331
+ self.sample.velcurves = []
329
332
  if self.overlaps:
330
333
  self.overlaps.sort(key = lambda overlap: overlap.lovel)
331
334
  lo_overlap = self.overlaps.pop(0) if self.overlaps[0].lovel == self.lovel else None
@@ -338,21 +341,21 @@ class VelocityGraph(_Track):
338
341
  else:
339
342
  mid_overlaps = []
340
343
  if lo_overlap:
341
- velcurves.append(Velcurve(self.lovel, 0.0))
342
- velcurves.append(Velcurve(lo_overlap.hivel, self.v2a(lo_overlap.hivel)))
344
+ self.sample.velcurves.append(Velcurve(self.lovel, 0.0))
345
+ self.sample.velcurves.append(Velcurve(lo_overlap.hivel, self.v2a(lo_overlap.hivel)))
343
346
  else:
344
- velcurves.append(Velcurve(self.lovel, self.v2a(self.lovel)))
347
+ self.sample.velcurves.append(Velcurve(self.lovel, self.v2a(self.lovel)))
345
348
  for mid_overlap in mid_overlaps:
346
- velcurves.append(Velcurve(mid_overlap.lovel, self.v2a(mid_overlap.lovel)))
349
+ self.sample.velcurves.append(Velcurve(mid_overlap.lovel, self.v2a(mid_overlap.lovel)))
347
350
  mid_overlap_center = mid_overlap.lovel + round((mid_overlap.hivel - mid_overlap.lovel) / 2)
348
- velcurves.append(Velcurve(mid_overlap_center, 0.0))
349
- velcurves.append(Velcurve(mid_overlap.hivel, self.v2a(mid_overlap.hivel)))
351
+ self.sample.velcurves.append(Velcurve(mid_overlap_center, 0.0))
352
+ self.sample.velcurves.append(Velcurve(mid_overlap.hivel, self.v2a(mid_overlap.hivel)))
350
353
  if hi_overlap:
351
- velcurves.append(Velcurve(hi_overlap.lovel, self.v2a(hi_overlap.lovel)))
352
- velcurves.append(Velcurve(self.hivel, 0.0))
354
+ self.sample.velcurves.append(Velcurve(hi_overlap.lovel, self.v2a(hi_overlap.lovel)))
355
+ self.sample.velcurves.append(Velcurve(self.hivel, 0.0))
353
356
  else:
354
- velcurves.append(Velcurve(self.hivel, self.v2a(self.hivel)))
355
- self.sample.velcurves = velcurves
357
+ self.sample.velcurves.append(Velcurve(self.hivel, self.v2a(self.hivel)))
358
+ self.sample.dirty = True
356
359
  self.update()
357
360
 
358
361
 
@@ -686,7 +689,7 @@ class SamplesWidget(QWidget):
686
689
 
687
690
  def velo_graphs(self):
688
691
  """
689
- Returns a list of VelocityGraph
692
+ Returns a list of VelocityGraph objects.
690
693
  """
691
694
  # Exclude first row (scale) and last row (pad)
692
695
  return self.grid.column(COL_GRAPH)[1:-1]
@@ -729,9 +732,9 @@ class SamplesWidget(QWidget):
729
732
  def slot_spread(self):
730
733
  tracks = self.velo_graphs()
731
734
  spread = 127 / len(tracks)
732
- for i in range(len(tracks)):
733
- tracks[i].lovel = round(i * spread)
734
- tracks[i].hivel = round((i + 1) * spread)
735
+ for i, track in enumerate(tracks):
736
+ track.lovel = round(i * spread)
737
+ track.hivel = round((i + 1) * spread)
735
738
  self.find_overlaps()
736
739
  self.slot_value_changed()
737
740
 
@@ -2,13 +2,21 @@
2
2
  #
3
3
  # Copyright 2025 Leon Dionne <ldionne@dridesign.sh.cn>
4
4
  #
5
- import os, logging, re
6
- from operator import attrgetter
5
+ """
6
+ Provides PinDatabase class - an abstraction over an sqlite database which keeps
7
+ track of samples on your hard drive and which instrument(s) thay have been
8
+ "pinned" to.
9
+ """
10
+ import os, logging
7
11
  from sqlite3 import connect
8
12
  from appdirs import user_config_dir
9
13
 
10
14
 
11
15
  class PinDatabase():
16
+ """
17
+ An abstraction over an sqlite database which keeps track of samples on your
18
+ hard drive and which instrument(s) thay have been "pinned" to.
19
+ """
12
20
 
13
21
  instance = None # Enforce singleton
14
22
  conn = None
@@ -6,12 +6,11 @@
6
6
  """
7
7
  Provides Drumkit SFZ wrapper which allows import / copy operations.
8
8
  """
9
- import logging
10
9
  from os.path import abspath, basename
11
10
  from collections import namedtuple
12
11
  from midi_notes import Note, MIDI_DRUM_IDS, MIDI_DRUM_NAMES
13
12
  from sfzen import SFZ
14
- from sfzen.drumkits import Drumkit, PITCH_GROUPS, pitch_id_tuple, iter_pitch_by_group
13
+ from sfzen.drumkits import PITCH_GROUPS, pitch_id_tuple, iter_pitch_by_group
15
14
 
16
15
  Velcurve = namedtuple('Velcurve', ['velocity', 'amplitude'])
17
16
 
@@ -50,7 +49,7 @@ class StarterKit:
50
49
  starter_sample._tune = opcodes['tune'].value
51
50
  for code, opcode in region.opcodes.items():
52
51
  if code.startswith('amp_velcurve'):
53
- starter_sample._velcurves.append(Velcurve(int(code[13:]), float(opcode.value)))
52
+ starter_sample.velcurves.append(Velcurve(int(code[13:]), float(opcode.value)))
54
53
  instrument.samples[starter_sample.path] = starter_sample
55
54
 
56
55
  def samples(self):
@@ -147,6 +146,9 @@ class StarterInstrument:
147
146
 
148
147
 
149
148
  class StarterSample:
149
+ """
150
+ Contains basic sample info which is compiled into an .sfz opcode.
151
+ """
150
152
 
151
153
  def __init__(self, path, pitch):
152
154
  self.path = abspath(path)
@@ -156,7 +158,7 @@ class StarterSample:
156
158
  self._volume = 0.0
157
159
  self._transpose = 0
158
160
  self._tune = 0
159
- self._velcurves = []
161
+ self.velcurves = []
160
162
  self.dirty = False
161
163
 
162
164
  def __str__(self):
@@ -207,15 +209,6 @@ class StarterSample:
207
209
  self._tune = value
208
210
  self.dirty = True
209
211
 
210
- @property
211
- def velcurves(self):
212
- return self._velcurves
213
-
214
- @velcurves.setter
215
- def velcurves(self, value):
216
- self._velcurves = value
217
- self.dirty = True
218
-
219
212
  def write(self, stream):
220
213
  stream.write('<region>\n')
221
214
  stream.write(f'sample={self.path}\n')
@@ -225,7 +218,7 @@ class StarterSample:
225
218
  stream.write(f'lovel={self._lovel}\n')
226
219
  if self._hivel < 127:
227
220
  stream.write(f'hivel={self._hivel}\n')
228
- for point in self._velcurves:
221
+ for point in self.velcurves:
229
222
  stream.write(f'amp_velcurve_{point.velocity}={point.amplitude:.1f}\n')
230
223
  if self._transpose != 0:
231
224
  stream.write(f'transpose={self._transpose}\n')
@@ -10,7 +10,7 @@ dependencies = [
10
10
  "soso_qt_extras >= 1.6.0",
11
11
  "conn_jack",
12
12
  "midi_notes",
13
- "sfzen >= 1.2.0",
13
+ "sfzen >= 1.2.0, <= 2.0.0",
14
14
  "liquiphy",
15
15
  "soundfile",
16
16
  "jack_audio_player"
@@ -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 = "0.2.2"
30
+ current_version = "0.3.0"
31
31
  version_pattern = "MAJOR.MINOR.PATCH"
32
32
  commit_message = "Bump version {old_version} -> {new_version}"
33
33
  commit = true
File without changes
File without changes
File without changes
File without changes