circuitpython-synthtools 0.8.1__py3-none-any.whl → 0.9.0__py3-none-any.whl
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.
Potentially problematic release.
This version of circuitpython-synthtools might be problematic. Click here for more details.
- {circuitpython_synthtools-0.8.1.dist-info → circuitpython_synthtools-0.9.0.dist-info}/METADATA +4 -1
- {circuitpython_synthtools-0.8.1.dist-info → circuitpython_synthtools-0.9.0.dist-info}/RECORD +9 -9
- {circuitpython_synthtools-0.8.1.dist-info → circuitpython_synthtools-0.9.0.dist-info}/WHEEL +1 -1
- synthtools/__init__.py +1 -1
- synthtools/arpeggiator.py +12 -14
- synthtools/step_sequencer.py +44 -35
- synthtools/trig_sequencer.py +12 -14
- {circuitpython_synthtools-0.8.1.dist-info → circuitpython_synthtools-0.9.0.dist-info}/licenses/LICENSE +0 -0
- {circuitpython_synthtools-0.8.1.dist-info → circuitpython_synthtools-0.9.0.dist-info}/top_level.txt +0 -0
{circuitpython_synthtools-0.8.1.dist-info → circuitpython_synthtools-0.9.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: circuitpython-synthtools
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: CircuitPython helper library to do help doing synthio
|
|
5
5
|
Author-email: Tod Kurt <tod@todbot.com>
|
|
6
6
|
License: MIT
|
|
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
15
15
|
Description-Content-Type: text/x-rst
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: Adafruit-Blinka
|
|
18
|
+
Requires-Dist: adafruit-circuitpython-ticks
|
|
18
19
|
Provides-Extra: optional
|
|
19
20
|
Dynamic: license-file
|
|
20
21
|
|
|
@@ -60,6 +61,8 @@ Dependencies
|
|
|
60
61
|
This driver depends on:
|
|
61
62
|
|
|
62
63
|
* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
|
|
64
|
+
* `Adafruit CircuitPython Ticks <https://github.com/adafruit/Adafruit_CircuitPython_Ticks>`_
|
|
65
|
+
(``StepSequencer``)
|
|
63
66
|
|
|
64
67
|
Please ensure all dependencies are available on the CircuitPython filesystem.
|
|
65
68
|
This is easily achieved by downloading
|
{circuitpython_synthtools-0.8.1.dist-info → circuitpython_synthtools-0.9.0.dist-info}/RECORD
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
circuitpython_synthtools-0.
|
|
2
|
-
synthtools/__init__.py,sha256=
|
|
1
|
+
circuitpython_synthtools-0.9.0.dist-info/licenses/LICENSE,sha256=jhhRyxpqyQxyF_D6SzY2-jCA5v8Z8JXfezCtxBS85CM,1075
|
|
2
|
+
synthtools/__init__.py,sha256=gJ90pjs_sYcEZsznlkNIZkOc8CBf983wybRAl7iL-R0,2752
|
|
3
3
|
synthtools/ahr_envelope.py,sha256=fWhjp7LahNGjL8qtTgyiAnX5hnviAULuyc9dEJ6t74I,9233
|
|
4
|
-
synthtools/arpeggiator.py,sha256=
|
|
4
|
+
synthtools/arpeggiator.py,sha256=s9tV68pw_GhKlxuNKrN0f8l7V2azhp5SyO-4lOPijQA,4185
|
|
5
5
|
synthtools/audio_fx.py,sha256=PjnETf5kKIlG_tLKwM49PCvSkM2txfZf2o7MuEnU2W4,8778
|
|
6
6
|
synthtools/bassline_synth.py,sha256=1QM7r2l29Nscbgn_sxmD_f-XhZt80xaOFsevOM0dpbQ,51553
|
|
7
7
|
synthtools/blocks.py,sha256=EsGcDEzIJX_dvBN8CVlDrewtl16x5leU03tum9jrhr0,1995
|
|
@@ -12,16 +12,16 @@ synthtools/param_scaler.py,sha256=dmaFkzRhrfZn54DAgPwZs7P4B4BFd90ZUvMHpWIf2i4,62
|
|
|
12
12
|
synthtools/paramset.py,sha256=--V89zHR4pUhkSey1CX7iMLNsF5l1hKmKWrAr3j_cRA,9938
|
|
13
13
|
synthtools/patch.py,sha256=vMr-kdVD66uxY8BrrnB0J6uDLREjuu16I8HzfhAkqHs,6033
|
|
14
14
|
synthtools/pitch_glider.py,sha256=R5h0Lbyq_slo7SKORRM7a0oumVugE15L8hOZJCov0AY,1927
|
|
15
|
-
synthtools/step_sequencer.py,sha256=
|
|
15
|
+
synthtools/step_sequencer.py,sha256=lCFsFmysXOAo_aXFLiBHqK4pStW2Fr5QmnxQ-uA_Kzw,4831
|
|
16
16
|
synthtools/subtractive_synth.py,sha256=WIpmhbiiLtyQRFV9mHWWM-duST5RfY9HUN4SRf5wTOw,3382
|
|
17
17
|
synthtools/swarm_synth.py,sha256=kCYsdVuaafTKkD06_m22iFaPUMCzeBKX67mkrsEq3pk,10945
|
|
18
18
|
synthtools/synth.py,sha256=ZdmAKWBVzJqPyzU5W1hxnJ6j09D4rnCWm77s5jRW_Ww,36528
|
|
19
|
-
synthtools/trig_sequencer.py,sha256=
|
|
19
|
+
synthtools/trig_sequencer.py,sha256=kqMFgr7q_lNn0KV-tt-52SEP4oz2PpS7kSq18svvFlM,3300
|
|
20
20
|
synthtools/utils.py,sha256=deKQbkGXIBdGUOXBOpRCc-UHdPiL8YmybIJ3BBo9aA4,648
|
|
21
21
|
synthtools/waves.py,sha256=lwDka71TsoHGJcyVfmG4t-TEf6TjBwftJEXSS4Qxyx0,22407
|
|
22
22
|
synthtools/wavetable.py,sha256=7zQdAvHyiSp7wiVjl-lIfeifpbdsp7M5cCVbMT7eku0,3725
|
|
23
23
|
synthtools/wavetable_synth.py,sha256=nggGXEr3tlADvTI38gCDRSw8XEaB5kHkzvQGSFfw16E,7969
|
|
24
|
-
circuitpython_synthtools-0.
|
|
25
|
-
circuitpython_synthtools-0.
|
|
26
|
-
circuitpython_synthtools-0.
|
|
27
|
-
circuitpython_synthtools-0.
|
|
24
|
+
circuitpython_synthtools-0.9.0.dist-info/METADATA,sha256=mhnlzRg78n-2sNVNECEcjAdwgrIKAlMco4fNI-PnNcM,7298
|
|
25
|
+
circuitpython_synthtools-0.9.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
26
|
+
circuitpython_synthtools-0.9.0.dist-info/top_level.txt,sha256=1xt53cH064i7vvFVDFyuJugc1NogReXvzsXbYGlgnKE,11
|
|
27
|
+
circuitpython_synthtools-0.9.0.dist-info/RECORD,,
|
synthtools/__init__.py
CHANGED
|
@@ -36,7 +36,7 @@ Anything not listed below is still importable by its module path::
|
|
|
36
36
|
|
|
37
37
|
import sys
|
|
38
38
|
|
|
39
|
-
__version__ = "0.
|
|
39
|
+
__version__ = "0.9.0"
|
|
40
40
|
__repo__ = "https://github.com/todbot/CircuitPython_SynthTools.git"
|
|
41
41
|
|
|
42
42
|
#: Public name -> the submodule that defines it. Every entry is loaded on
|
synthtools/arpeggiator.py
CHANGED
|
@@ -11,16 +11,7 @@ Part of synthtools.
|
|
|
11
11
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
try:
|
|
17
|
-
from supervisor import ticks_ms
|
|
18
|
-
except ImportError:
|
|
19
|
-
|
|
20
|
-
def ticks_ms():
|
|
21
|
-
"""stand-in for supervisor.ticks_ms"""
|
|
22
|
-
return time.monotonic_ns() // 1_000_000
|
|
23
|
-
|
|
14
|
+
from adafruit_ticks import ticks_add, ticks_diff, ticks_ms
|
|
24
15
|
|
|
25
16
|
patterns = (
|
|
26
17
|
(0, 4, 7, 12),
|
|
@@ -68,6 +59,7 @@ class Arpeggiator:
|
|
|
68
59
|
self.held_note = None
|
|
69
60
|
self.next_millis = 0
|
|
70
61
|
self.held_millis = 0
|
|
62
|
+
self._frac_millis = 0.0 # step_millis's fraction, carried between steps
|
|
71
63
|
|
|
72
64
|
def set_bpm(self, bpm, rate=None):
|
|
73
65
|
"""Set BPM and optionally rate"""
|
|
@@ -90,6 +82,7 @@ class Arpeggiator:
|
|
|
90
82
|
def start(self):
|
|
91
83
|
"""Start the arpeggiator running"""
|
|
92
84
|
self.next_millis = ticks_ms()
|
|
85
|
+
self._frac_millis = 0.0
|
|
93
86
|
self.on = True
|
|
94
87
|
|
|
95
88
|
def stop(self):
|
|
@@ -105,12 +98,12 @@ class Arpeggiator:
|
|
|
105
98
|
now = ticks_ms()
|
|
106
99
|
|
|
107
100
|
# trigger note-off after gate time
|
|
108
|
-
if self.held_note and now
|
|
101
|
+
if self.held_note and ticks_diff(now, self.held_millis) > 0:
|
|
109
102
|
self.off_func(self.held_note)
|
|
110
103
|
self.held_note = None
|
|
111
104
|
|
|
112
105
|
# trigger note-on on if time to do so
|
|
113
|
-
delta_millis = now
|
|
106
|
+
delta_millis = ticks_diff(now, self.next_millis)
|
|
114
107
|
if delta_millis >= 0 and len(self.notes) > 0: # time for new note
|
|
115
108
|
note = self.notes[self.i] + self.oct_distance * self.octave
|
|
116
109
|
# print("\t\t\t\t\t", "delta:",delta_millis)
|
|
@@ -120,8 +113,13 @@ class Arpeggiator:
|
|
|
120
113
|
self.held_note = note # save for note-off
|
|
121
114
|
|
|
122
115
|
# set up when note off and next note happens
|
|
123
|
-
|
|
124
|
-
|
|
116
|
+
# int ticks: they wrap at 2**29, first ~65 s after power-on, and a
|
|
117
|
+
# 30-bit float can't hold one that big to the ms
|
|
118
|
+
self._frac_millis += self.step_millis
|
|
119
|
+
step = int(self._frac_millis)
|
|
120
|
+
self._frac_millis -= step
|
|
121
|
+
self.held_millis = ticks_add(now, int(self.step_millis * self.gate))
|
|
122
|
+
self.next_millis = ticks_add(now, step - delta_millis // 2)
|
|
125
123
|
|
|
126
124
|
# go to next note
|
|
127
125
|
self.i = (self.i + 1) % len(self.notes)
|
synthtools/step_sequencer.py
CHANGED
|
@@ -11,15 +11,7 @@ Part of synthtools.
|
|
|
11
11
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
try:
|
|
17
|
-
from supervisor import ticks_ms
|
|
18
|
-
except ImportError:
|
|
19
|
-
|
|
20
|
-
def ticks_ms():
|
|
21
|
-
"""stand-in for supervisor.ticks_ms"""
|
|
22
|
-
return time.monotonic_ns() // 1_000_000
|
|
14
|
+
from adafruit_ticks import ticks_add, ticks_diff, ticks_ms
|
|
23
15
|
|
|
24
16
|
|
|
25
17
|
class StepSequencer:
|
|
@@ -46,8 +38,10 @@ class StepSequencer:
|
|
|
46
38
|
self.held_note = None # the current note playing
|
|
47
39
|
self.transpose = 0
|
|
48
40
|
self.playing = False # is sequence running or not (but use .start()/.stop())
|
|
41
|
+
self.external_clock = False # owner calls trigger(), update() only releases gates
|
|
42
|
+
self.catch_up_steps = 0 # how far behind to still play every step, late, not resync
|
|
49
43
|
self.next_millis = 0
|
|
50
|
-
self.
|
|
44
|
+
self._frac_millis = 0.0 # step_millis's fraction, carried between steps
|
|
51
45
|
|
|
52
46
|
@property
|
|
53
47
|
def bpm(self):
|
|
@@ -68,46 +62,61 @@ class StepSequencer:
|
|
|
68
62
|
def start(self):
|
|
69
63
|
"""Start sequencer going"""
|
|
70
64
|
self.next_millis = ticks_ms()
|
|
65
|
+
self._frac_millis = 0.0
|
|
71
66
|
self.playing = True
|
|
72
|
-
self.error_millis = 0
|
|
73
67
|
|
|
74
|
-
def
|
|
75
|
-
"""
|
|
68
|
+
def pause(self):
|
|
69
|
+
"""Pause sequencer where it is, turning off any currently-sounding note"""
|
|
76
70
|
if self.held_note:
|
|
77
71
|
self.off_func(*self.held_note)
|
|
72
|
+
self.held_note = None
|
|
78
73
|
self.playing = False
|
|
74
|
+
|
|
75
|
+
def stop(self):
|
|
76
|
+
"""Stop sequencer and rewind, turning off any currently-sounding note"""
|
|
77
|
+
self.pause()
|
|
79
78
|
self.i = 0
|
|
80
79
|
|
|
80
|
+
def trigger(self, now=None):
|
|
81
|
+
"""Play the current step and advance, for an owner keeping its own clock"""
|
|
82
|
+
if now is None:
|
|
83
|
+
now = ticks_ms()
|
|
84
|
+
if self.i >= self.step_count: # step_count shrank under us
|
|
85
|
+
self.i = 0
|
|
86
|
+
(note, vel, gate, on) = self.steps[self.i] # get new note to play
|
|
87
|
+
note += self.transpose # adjust for transpose
|
|
88
|
+
self.held_note = (note, vel, gate, on) # save it for when we note_off it
|
|
89
|
+
|
|
90
|
+
# trigger new note
|
|
91
|
+
self.on_func(*self.held_note) # held_note = (note,vel,gate,on)
|
|
92
|
+
|
|
93
|
+
# prep for next step in sequence
|
|
94
|
+
self.i = (self.i + 1) % self.step_count
|
|
95
|
+
|
|
96
|
+
# int ticks: they wrap at 2**29, first ~65 s after power-on, and a
|
|
97
|
+
# 30-bit float can't hold one that big to the ms
|
|
98
|
+
self._frac_millis += self.step_millis
|
|
99
|
+
step = int(self._frac_millis)
|
|
100
|
+
self._frac_millis -= step
|
|
101
|
+
self.next_millis = ticks_add(self.next_millis, step)
|
|
102
|
+
# a stall put us too far behind
|
|
103
|
+
if ticks_diff(self.next_millis, now) < -self.catch_up_steps * step:
|
|
104
|
+
self.next_millis = ticks_add(now, step)
|
|
105
|
+
# next note off is some percentage smaller
|
|
106
|
+
gate = int(self.step_millis * self.held_note[2])
|
|
107
|
+
self.gate_off_millis = ticks_add(now, gate)
|
|
108
|
+
|
|
81
109
|
def update(self):
|
|
82
110
|
"""Update the sequencer. Call as frequently as possible"""
|
|
83
111
|
if not self.playing:
|
|
84
112
|
return
|
|
85
113
|
|
|
86
114
|
now = ticks_ms()
|
|
87
|
-
delta_millis = now - self.next_millis
|
|
88
115
|
|
|
89
116
|
# trigger note-off after gate time
|
|
90
|
-
if now
|
|
117
|
+
if self.held_note and ticks_diff(now, self.gate_off_millis) >= 0:
|
|
91
118
|
self.off_func(*self.held_note)
|
|
92
119
|
self.held_note = None
|
|
93
120
|
|
|
94
|
-
if
|
|
95
|
-
|
|
96
|
-
self.error_millis += delta_millis
|
|
97
|
-
(note, vel, gate, on) = self.steps[self.i] # get new note to play
|
|
98
|
-
note += self.transpose # adjust for transpose
|
|
99
|
-
self.held_note = (note, vel, gate, on) # save it for when we note_off it
|
|
100
|
-
|
|
101
|
-
# trigger new note
|
|
102
|
-
self.on_func(*self.held_note) # held_note = (note,vel,gate,on)
|
|
103
|
-
|
|
104
|
-
# prep for next step in sequence
|
|
105
|
-
self.i = (self.i + 1) % self.step_count
|
|
106
|
-
|
|
107
|
-
# set up when next note on is, with some error correction
|
|
108
|
-
self.next_millis = now + self.step_millis
|
|
109
|
-
if self.error_millis > 1:
|
|
110
|
-
self.next_millis -= self.error_millis
|
|
111
|
-
self.error_millis = 0
|
|
112
|
-
# next note off is some percentage smaller
|
|
113
|
-
self.gate_off_millis = now + self.step_millis * self.held_note[2]
|
|
121
|
+
if not self.external_clock and ticks_diff(now, self.next_millis) >= 0:
|
|
122
|
+
self.trigger(now)
|
synthtools/trig_sequencer.py
CHANGED
|
@@ -11,15 +11,7 @@ Part of synthtools.
|
|
|
11
11
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
try:
|
|
17
|
-
from supervisor import ticks_ms
|
|
18
|
-
except ImportError:
|
|
19
|
-
|
|
20
|
-
def ticks_ms():
|
|
21
|
-
"""stand-in for supervisor.ticks_ms"""
|
|
22
|
-
return time.monotonic_ns() // 1_000_000
|
|
14
|
+
from adafruit_ticks import ticks_add, ticks_diff, ticks_ms
|
|
23
15
|
|
|
24
16
|
|
|
25
17
|
class TrigSequencer:
|
|
@@ -45,6 +37,7 @@ class TrigSequencer:
|
|
|
45
37
|
self.drum_map = [0] * trig_count
|
|
46
38
|
self.step_millis = 0 # real value once bpm is set; update()/start() need it to exist
|
|
47
39
|
self.next_millis = 0
|
|
40
|
+
self._frac_millis = 0.0 # step_millis's fraction, carried between steps
|
|
48
41
|
|
|
49
42
|
@property
|
|
50
43
|
def bpm(self):
|
|
@@ -58,6 +51,7 @@ class TrigSequencer:
|
|
|
58
51
|
def start(self):
|
|
59
52
|
"""Start sequencer going"""
|
|
60
53
|
self.next_millis = ticks_ms()
|
|
54
|
+
self._frac_millis = 0.0
|
|
61
55
|
self.playing = True
|
|
62
56
|
|
|
63
57
|
def stop(self):
|
|
@@ -78,15 +72,19 @@ class TrigSequencer:
|
|
|
78
72
|
return
|
|
79
73
|
|
|
80
74
|
now = ticks_ms()
|
|
81
|
-
delta_millis = now - self.next_millis
|
|
82
75
|
|
|
83
|
-
if
|
|
76
|
+
if ticks_diff(now, self.next_millis) >= 0: # time to play
|
|
84
77
|
for t in range(self.trig_count):
|
|
85
78
|
if self.trigs[t][self.i] == 1:
|
|
86
79
|
self.on_func(t, self.drum_map[t])
|
|
87
80
|
|
|
88
81
|
# prep for next step in sequence
|
|
89
82
|
self.i = (self.i + 1) % self.step_count
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
83
|
+
# int ticks: they wrap at 2**29, first ~65 s after power-on, and a
|
|
84
|
+
# 30-bit float can't hold one that big to the ms
|
|
85
|
+
self._frac_millis += self.step_millis
|
|
86
|
+
step = int(self._frac_millis)
|
|
87
|
+
self._frac_millis -= step
|
|
88
|
+
self.next_millis = ticks_add(self.next_millis, step)
|
|
89
|
+
if ticks_diff(self.next_millis, now) < 0: # a stall put us a whole step behind
|
|
90
|
+
self.next_millis = ticks_add(now, step)
|
|
File without changes
|
{circuitpython_synthtools-0.8.1.dist-info → circuitpython_synthtools-0.9.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|