diff --git a/src/python/rv/modules/sampler.py b/src/python/rv/modules/sampler.py index 3637440..48748db 100644 --- a/src/python/rv/modules/sampler.py +++ b/src/python/rv/modules/sampler.py @@ -2,7 +2,7 @@ from io import BytesIO from itertools import chain from struct import pack, unpack -from typing import List, Optional +from typing import BinaryIO, List, Optional from logutils import BraceMessage as _F from rv.controller import Controller @@ -28,6 +28,9 @@ class Sampler(BaseSampler, Module): loaded into the latest version of SunVox and then saved. """ + INS_VERSION = 6 + XI_ENV_POINTS = 12 + chnk = 0x109 options_chnm = 0x0101 @@ -215,6 +218,7 @@ def __init__(self, chnm): class Sample: def __init__(self): self.data = b"" + self._length = 0 self.loop_start = 0 self.loop_len = 0 self.volume = 64 @@ -226,7 +230,9 @@ def __init__(self): self.loop_sustain = False self.panning = 0 self.relative_note = 16 - self.unknown6 = b"\0" * 23 + self.reserved2 = 0 + self.name = b"" + self.start_pos = 0 @property def frame_size(self): @@ -251,6 +257,24 @@ def frames(self): volume_fadeout = Controller((0, 8192), 0, attached=False) samples: List[Optional[Sample]] + version: int + max_version: int + + # Legacy + instrument_name: bytes + volume_old: int + finetune: int + relative_note: int + editor_cursor: int + editor_selected_size: int + + # Unused + unused1: int + unused2: int + unused3: int + unused4: int + unused5: int + unused6: int def __init__(self, **kwargs): super(Sampler, self).__init__(**kwargs) @@ -265,11 +289,18 @@ def __init__(self, **kwargs): ] self.note_samples = self.NoteSampleMap() self.samples = [None] * 128 - self.unknown1 = b"\0" * 28 - self.unknown2 = b"\0" * 4 - self.unknown3 = b"\x40\x00\x80\x00\x00\x00\x00\x00" - self.unknown4 = b"\x04\x00\x00\x00" - self.unknown5 = b"\0" * 9 + self.instrument_name = kwargs.get("instrument_name", b"") + self.version = self.INS_VERSION + self.max_version = self.INS_VERSION + self.unused1 = 0 + self.unused2 = 0 + self.unused3 = 0 + self.unused4 = 0 + self.volume_old = 64 + self.finetune = 0 + self.relative_note = 0 + self.editor_cursor = 0 + self.editor_selected_size = 0 self.effect = None def specialized_iff_chunks(self): @@ -297,42 +328,86 @@ def specialized_iff_chunks(self): yield from self.sample_chunks(i, sample) def global_config_chunks(self): - def b(v): - return pack(" None: + self._f.write(value.ljust(width, b"\0")[:width]) + + def int8(self, value: int) -> None: + self._f.write(pack(" None: + self._f.write(pack(" None: + self._f.write(pack(" None: + self._f.write(pack(" None: + self._f.write(pack(" None: + self._f.write(pack(" bytes: + start = self._index + new_index = start + length + buf = self._data[start:new_index] + self._index = new_index + return buf + + def char(self, length: int) -> bytes: + return self.bytes(length).rstrip(b"\0") + + def skip(self, length: int) -> None: + self._index += length + + def int8(self, default=None) -> int: + return self._read(" int: + return self._read(" int: + return self._read(" int: + return self._read(" int: + return self._read(" int: + return self._read(" int: + start = self._index + new_index = start + length + buf = self._data[start:new_index] + if len(buf) < length: + if default is None: + raise RuntimeError("default not provided") + return default + self._index = new_index + return unpack(spec, buf)[0] diff --git a/tests/files/sampler.sunsynth b/tests/files/sampler.sunsynth index 3d30d30..aca49d1 100644 Binary files a/tests/files/sampler.sunsynth and b/tests/files/sampler.sunsynth differ diff --git a/tests/python/readwrite/synth/test_sampler.py b/tests/python/readwrite/synth/test_sampler.py index 99c5382..e07f8ce 100644 --- a/tests/python/readwrite/synth/test_sampler.py +++ b/tests/python/readwrite/synth/test_sampler.py @@ -167,6 +167,7 @@ def test_sampler(read_write_read_synth): assert sample1.finetune == 72 assert sample1.panning == 58 assert sample1.relative_note == 28 + assert sample1.start_pos == 3 assert sample1.data == pack( "<" + ("b" * len(EXPECTED_SAMPLE1_SAMPLES)), *EXPECTED_SAMPLE1_SAMPLES, @@ -181,6 +182,7 @@ def test_sampler(read_write_read_synth): assert sample2.finetune == 78 assert sample2.panning == -27 assert sample2.relative_note == -16 + assert sample2.start_pos == 0 assert sample2.data == pack( "<" + ("h" * len(EXPECTED_SAMPLE2_SAMPLES)), *EXPECTED_SAMPLE2_SAMPLES, @@ -195,6 +197,7 @@ def test_sampler(read_write_read_synth): assert sample3.finetune == -49 assert sample3.panning == 37 assert sample3.relative_note == 8 + assert sample3.start_pos == 0 assert sample3.data == pack( "<" + ("f" * len(EXPECTED_SAMPLE3_SAMPLES)), *EXPECTED_SAMPLE3_SAMPLES,