Skip to content

Commit d116463

Browse files
committed
[synth] More fixes for the Roland-SE02 based on CodeRabbit feedback
1 parent 1580e32 commit d116463

1 file changed

Lines changed: 55 additions & 23 deletions

File tree

adaptations/Roland_SE02.py

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from __future__ import annotations
55

6-
from typing import Dict, List, Sequence, Union
6+
from typing import Dict, List, Optional, Sequence, Tuple, Union
77
import hashlib
88

99
# -----------------------------
@@ -15,6 +15,7 @@
1515

1616
# SE-02 edit buffer dump blocks (DT1 address starts with 0x05)
1717
EDITBUF_ADDR_PREFIX = (0x05,)
18+
EDITBUF_BLOCK_OFFSETS = ((0x00, 0x00), (0x00, 0x40), (0x01, 0x00), (0x01, 0x40))
1819

1920
# Optional tracing (disabled by default in public release)
2021
TRACE_ENABLED = False
@@ -160,14 +161,7 @@ def _retarget_dt1(blob: bytes, channel, target_bb: int):
160161
dev = _device_id_from_channel(channel)
161162

162163
for m in msgs:
163-
if not (
164-
len(m) >= 14
165-
and m[0] == 0xF0
166-
and m[1] == ROLAND_ID
167-
and m[6] == MODEL_ID
168-
and m[7] == CMD_DT1
169-
and m[-1] == 0xF7
170-
):
164+
if not _is_se02_dt1(m):
171165
continue
172166

173167
changed = False
@@ -197,6 +191,7 @@ def _is_se02_dt1(msg: bytes) -> bool:
197191
and msg[6] == MODEL_ID
198192
and msg[7] == CMD_DT1
199193
and msg[-1] == 0xF7
194+
and _roland_checksum_7bit(bytes(msg[8:-2])) == msg[-2]
200195
)
201196

202197

@@ -215,6 +210,41 @@ def _is_editbuf_dt1(msg: bytes) -> bool:
215210
return bool(a) and a[0] in EDITBUF_ADDR_PREFIX
216211

217212

213+
def _editbuf_block_info(msg: bytes) -> Optional[Tuple[int, Tuple[int, int]]]:
214+
if not _is_editbuf_dt1(msg):
215+
return None
216+
a = _addr4(msg)
217+
if not a:
218+
return None
219+
return a[1], (a[2], a[3])
220+
221+
222+
def _ordered_valid_editbuf_blocks(blocks: Sequence[bytes]) -> List[bytes]:
223+
if len(blocks) != len(EDITBUF_BLOCK_OFFSETS):
224+
return []
225+
226+
bb = None
227+
by_offset: Dict[Tuple[int, int], bytes] = {}
228+
for block in blocks:
229+
info = _editbuf_block_info(block)
230+
if info is None:
231+
return []
232+
233+
block_bb, offset = info
234+
if bb is None:
235+
bb = block_bb
236+
elif block_bb != bb:
237+
return []
238+
239+
if offset not in EDITBUF_BLOCK_OFFSETS or offset in by_offset:
240+
return []
241+
by_offset[offset] = block
242+
243+
if len(by_offset) != len(EDITBUF_BLOCK_OFFSETS):
244+
return []
245+
return [by_offset[offset] for offset in EDITBUF_BLOCK_OFFSETS]
246+
247+
218248
# -----------------------------
219249
# Device detect (KEEP STABLE)
220250
# -----------------------------
@@ -296,15 +326,16 @@ def isPartOfEditBufferDump(message) -> bool:
296326

297327
def isEditBufferDump(message) -> bool:
298328
"""
299-
True if the blob contains a full edit buffer dump (4 DT1 messages).
300-
We detect this by splitting the blob into SysEx messages and counting DT1 blocks.
329+
True if the blob contains a full edit buffer dump.
330+
A complete SE-02 edit buffer dump has the four expected DT1 block offsets
331+
for the same bank/slot identifier.
301332
"""
302333
blob = _to_blob(message)
303334
if len(blob) < 12:
304335
return False
305336
msgs = _split_sysex(blob) if blob.count(b"\xF0") >= 2 else ([blob] if blob else [])
306337
dt1 = [m for m in msgs if _is_editbuf_dt1(m)]
307-
ok = (len(dt1) == 4)
338+
ok = bool(_ordered_valid_editbuf_blocks(dt1))
308339
if ok:
309340
_trace(f"isEditBufferDump(len={len(blob)} msgs={len(msgs)} ok={ok})")
310341
return ok
@@ -426,7 +457,7 @@ def extractPatches(messages):
426457
File import hook:
427458
Orm gives a list of SysEx messages; we return a list of "patch blobs".
428459
SE-02 edit buffer dump = 4 DT1 messages.
429-
We concatenate 4 DT1 blocks into one blob.
460+
We concatenate each valid group of the four expected DT1 blocks into one blob.
430461
"""
431462
_trace(f"extractPatches(count={len(messages) if messages is not None else 'None'})")
432463
if not messages:
@@ -441,12 +472,14 @@ def extractPatches(messages):
441472
_trace(f"extractPatches: editbuf_dt1_blocks={len(dt1_blocks)}")
442473

443474
patches: List[bytes] = []
444-
for i in range(0, len(dt1_blocks) // 4):
445-
blocks = dt1_blocks[i * 4 : (i + 1) * 4]
446-
patches.append(b"".join(blocks))
447-
remainder = len(dt1_blocks) % 4
448-
if remainder:
449-
_trace(f"extractPatches: ignored incomplete trailing block group of {remainder} DT1 messages")
475+
group_size = len(EDITBUF_BLOCK_OFFSETS)
476+
for start in range(0, len(dt1_blocks), group_size):
477+
blocks = dt1_blocks[start : start + group_size]
478+
ordered_blocks = _ordered_valid_editbuf_blocks(blocks)
479+
if ordered_blocks:
480+
patches.append(b"".join(ordered_blocks))
481+
else:
482+
_trace(f"extractPatches: ignored invalid DT1 block group at index {start // group_size}")
450483

451484
_trace(f"extractPatches: returning patches={len(patches)}")
452485
return patches
@@ -667,11 +700,10 @@ def convertToProgramDump(channel, message, program_number):
667700
blob = _to_blob(message)
668701
try:
669702
target_bb = int(program_number)
670-
except Exception:
671-
target_bb = 0
703+
except (TypeError, ValueError) as exc:
704+
raise ValueError(f"program_number must be an int in the range 0..127, got {program_number!r}") from exc
672705
if not 0 <= target_bb <= 127:
673-
_trace(f"convertToProgramDump: invalid program_number={program_number}, defaulting to USER slot 0")
674-
target_bb = 0
706+
raise ValueError(f"program_number must be an int in the range 0..127, got {program_number!r}")
675707
out_blob, msg_count, addr_fixed, dev_fixed, touched_dt1 = _retarget_dt1(blob, channel, target_bb)
676708
_trace(
677709
f"convertToProgramDump: channel={channel} program_number={program_number} target_bb={target_bb} "

0 commit comments

Comments
 (0)