-
Notifications
You must be signed in to change notification settings - Fork 24
feat: Fruity Slicer #158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat: Fruity Slicer #158
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,7 @@ | |
| "FruityFastDist", | ||
| "FruityNotebook2", | ||
| "FruitySend", | ||
| "FruitySlicer", | ||
| "FruitySoftClipper", | ||
| "FruityStereoEnhancer", | ||
| "Plucked", | ||
|
|
@@ -155,6 +156,49 @@ class FruitySendEvent(StructEventBase): | |
| ).compile() | ||
|
|
||
|
|
||
| class FruitySlicerEvent(StructEventBase): | ||
| STRUCT = c.Struct( | ||
| "_u1" / c.Bytes(8), | ||
| "bpm" / c.Float32l, | ||
| "pitch_shift" / c.Int32sl, | ||
| "time_stretch" / c.Int32sl, | ||
| "stretching_method" | ||
| / c.Enum( | ||
| c.Int32ul, | ||
| fill_gaps=0, | ||
| alt_fill_gaps=1, | ||
| pro_default=2, | ||
| pro_transient=3, | ||
| transient=4, | ||
| tonal=5, | ||
| monophonic=6, | ||
| speech=7, | ||
| ), | ||
| "fade_in" / c.Int32ul, | ||
| "fade_out" / c.Int32ul, | ||
| "file_path" / c.PascalString(c.Int8ul, "utf-8"), | ||
| "slices" | ||
| / c.PrefixedArray( | ||
| c.Int32ul, | ||
| c.Struct( | ||
| "name" / c.PascalString(c.Int8ul, "utf-8"), | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just checked these, the file path does seem to be a u8, but interestingly, the slice name field seems to be a bit unusual. The name is capped at 257 bytes, but it uses a different size format that seems to adapt to the actual length of the string. From what I can tell, the first byte is either the length of the string or 0xFF to indicate that the length is actually defined by the next four bytes (a u32). For example, hex
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is legit weird. Whatever could have stopped IL from using a VarInt instead? An adapter isn't enough here. We need a Construct subclass here.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The file path does seem to be limited to 255 characters, but it gets weirder -- attempting to load a sample with a longer path results in FL Studio itself crashing with the memory error
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get no such error in FL Studio 20.8.3.2304 - either while loading, or saving the project, or even re-opening the project. The full path is: There is a setting on Windows to remove the 260 limitation. Have you enabled it?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do have enabled, but I believe the reason it was crashing may have been due to Wine (I run Linux). With a unique file path of 259 characters, it seemed to use the same format as the slice names (the data field was FF 03 01 00 00). I assume maybe it shortens paths that are 260 characters or longer, but keeps paths that are longer than 260 characters the same, where this obscure format is only used for paths between 255 and 259 characters.
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright the length doesn't matter here, our construct will just need to check if the FF marker exists (and parse the next 4 bytes if it does). |
||
| "sample_offset" / c.Int32ul, | ||
| "key" / c.Int32sl, | ||
| "_u1" / c.Float32l, | ||
| "reversed" / c.Flag, | ||
| ), | ||
| ), | ||
| "animate" / c.Flag, | ||
| "starting_note" / c.Int32ul, | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shorter name |
||
| "play_to_end" / c.Flag, | ||
| "bitrate" / c.Int32ul, | ||
| "auto_dump" / c.Flag, | ||
| "declick" / c.Flag, | ||
| "auto_fit" / c.Flag, | ||
| "view_spectrum" / FourByteBool, | ||
| ).compile() | ||
|
|
||
|
|
||
| class FruitySoftClipperEvent(StructEventBase): | ||
| STRUCT = c.Struct("threshold" / c.Int32ul, "post" / c.Int32ul).compile() | ||
|
|
||
|
|
@@ -1007,6 +1051,84 @@ class FruitySend(_PluginBase[FruitySendEvent], _IPlugin, ModelReprMixin): | |
| """ | ||
|
|
||
|
|
||
| class FruitySlicer(_PluginBase[FruitySlicerEvent], _IPlugin, ModelReprMixin): | ||
| """""" | ||
|
|
||
| INTERNAL_NAME = "Fruity Slicer" | ||
| bpm = _NativePluginProp[float]() | ||
| """The BPM (beats per minute) of the sample.""" | ||
|
|
||
| pitch_shift = _NativePluginProp[int]() | ||
| """Pitch shift, in cents. Linear, 1:1. | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Linear and 1:1 is the same thing. Remove 1:1. I plan on creating a glossary section in my docs which explains all these terms. |
||
|
|
||
| | Type | Value | Representation | | ||
| |---------|-------|----------------| | ||
| | Min | -1200 | -1200 cents | | ||
| | Max | 1200 | +1200 cents | | ||
| | Default | 0 | +0 cent | | ||
| """ | ||
|
|
||
| time_stretch = _NativePluginProp[int]() | ||
| """Logarithmic. | ||
|
|
||
| | Type | Value | Representation | | ||
| |---------|--------|--------------------------| | ||
| | Min | -20000 | 25% / 60 bpm to 240 bpm | | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a shorter |
||
| | Max | 20000 | 400% / 60 bpm to 15 bpm | | ||
| | Default | 0 | 100% / 0 bpm to 0 bpm | | ||
| """ | ||
|
|
||
| stretching_method = _NativePluginProp[ | ||
| Literal[ | ||
| "fill_gaps", | ||
| "alt_fill_gaps", | ||
| "pro_default", | ||
| "pro_transient", | ||
| "transient", | ||
| "tonal", | ||
| "monophonic", | ||
| "speech", | ||
| ] | ||
| ]() | ||
| """The stretching method to use on the sample when `time_stretch` is not 0.""" | ||
|
|
||
| fade_in = _NativePluginProp[int]() | ||
| """Slice fade in, in milliseconds.""" | ||
|
|
||
| fade_out = _NativePluginProp[int]() | ||
| """Slice fade out, in milliseconds.""" | ||
|
|
||
| file_path = _NativePluginProp[str]() | ||
| """The file path of the sample.""" | ||
|
|
||
| slices = _NativePluginProp[list[dict]]() | ||
| """A list of slices.""" | ||
|
|
||
| animate = _NativePluginProp[bool]() | ||
| """Whether to highlight the slices as they are played.""" | ||
|
|
||
| starting_note = _NativePluginProp[int]() | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shorter name |
||
| """The MIDI note for slicing to start on. Default 60.""" | ||
|
|
||
| play_to_end = _NativePluginProp[bool]() | ||
| """Whether to play slices to the end of the sample.""" | ||
|
|
||
| bitrate = _NativePluginProp[int]() | ||
| """The bitrate of the sample.""" | ||
|
|
||
| auto_dump = _NativePluginProp[bool]() | ||
| """Whether to automatically dump slices to the piano roll.""" | ||
|
|
||
| declick = _NativePluginProp[bool]() | ||
| """Whether to prevent clicking on slices.""" | ||
|
|
||
| auto_fit = _NativePluginProp[bool]() | ||
| """Whether to automatically fit the beat to the project tempo on load.""" | ||
|
|
||
| view_spectrum = _NativePluginProp[bool]() | ||
| """Whether to view the slices as a spectrum instead of a waveform.""" | ||
|
|
||
|
|
||
| class FruitySoftClipper(_PluginBase[FruitySoftClipperEvent], _IPlugin, ModelReprMixin): | ||
| """""" | ||
|
|
||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be a
VarIntprefixed string. If 2 bytes are used to encode a path having >127 characters then its definitely VarInt prefixed.