From a0aaa13faa345221938ab9d163c001634430b9dd Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Fri, 6 Nov 2026 23:04:33 -0600 Subject: [PATCH 01/11] Analog Rytm MKII: Improved Envelopes 0.1.0-experimental The AMP envelope reworked, with times on every envelope knob: AMP HLD from no hold to AUTO without cutting the attack, fine ATK, DEC, REL and HLD steps at short times (0.2 ms to 5 ms), FUNC jumps on HLD, and ENV RESET AMP (Iced-Cream's Env Reset Amp, from MrScruff's rytm-mods) with a pre-fade. Unit-tested on an MKII over USB (TESTING.md). Co-Authored-By: Claude Opus 5.5 --- sdk/analog-rytm-mkii/modules/README.md | 2 +- .../modules/envelopes/LICENSE | 339 +++++++++++++ .../modules/envelopes/README.md | 70 +++ .../modules/envelopes/TESTING.md | 235 +++++++++ .../modules/envelopes/build.json | 129 +++++ .../modules/envelopes/media/LICENSE.md | 7 + .../modules/envelopes/media/thumbnail.svg | 8 + .../modules/envelopes/modwerk.module.json | 148 ++++++ .../modules/envelopes/src/amp-write.s | 137 +++++ .../modules/envelopes/src/envelopes.c | 478 ++++++++++++++++++ .../modules/envelopes/src/pre-fade.c | 104 ++++ .../modules/envelopes/tools/atk_table.py | 95 ++++ .../modules/envelopes/tools/dec_table.py | 128 +++++ .../modules/envelopes/upstream/README.md | 54 ++ .../analog-rytm-mkii-envelopes.json | 13 + 15 files changed, 1946 insertions(+), 1 deletion(-) create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/LICENSE create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/README.md create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/TESTING.md create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/build.json create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/media/LICENSE.md create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/media/thumbnail.svg create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/src/amp-write.s create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/src/pre-fade.c create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/tools/atk_table.py create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/tools/dec_table.py create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/upstream/README.md create mode 100644 src/community/module-changelogs/analog-rytm-mkii-envelopes.json diff --git a/sdk/analog-rytm-mkii/modules/README.md b/sdk/analog-rytm-mkii/modules/README.md index 2a7769110..f857d1acf 100644 --- a/sdk/analog-rytm-mkii/modules/README.md +++ b/sdk/analog-rytm-mkii/modules/README.md @@ -1,6 +1,6 @@ # Analog Rytm MKII modules -Each folder here is a library module for the Analog Rytm MKII on OS 1.74 and core-ar2 0.7 (modules built for 0.3 link with it, but for mods that patch a page's entry or a page key's list themselves: see the [SDK guide](../../machines/analog-rytm-mkii/README.md#parameter-pages-core-04-and-later)): [CHORUS](chorus/), [Pad Pressure Fix](chromatic-aftertouch-fix/), [Control In Actions](control-in-actions/), [Filter Hz](filter-hz/), [FLANGER](flanger/), [Live Rec Retrig Fix](live-rec-retrig-fix/), [Loop Sync](loop-sync/), [PHASER](phaser/), [Pipo Loop](pipo-loop/), [QPERF](qperf/), [Quick Trig Conditions](quick-fill-trig-condition/), [Quick Velocity+Aftertouch Assign](quick-velocity-aftertouch-assign/), [Sample RATE](sample-rate/), [Silent Pad+Trig Settings](silent-pad-trig/) and [Temp Save](temp-save/). CHORUS, FLANGER and PHASER are send effects: a set holding one builds on the Modwerk base's send-bus variant ([Send effects](../../machines/analog-rytm-mkii/README.md#send-effects)). A new module comes here with its pinned package and is live once merged ([Create a mod](../../machines/analog-rytm-mkii/README.md#create-a-mod)); `_submissions/` holds older submissions and takes no new modules or changes. Loop Sync 0.2.0-experimental entered on the owner's approval with emulator evidence for its source; its [TESTING.md](loop-sync/TESTING.md) records what is still open. Pipo Loop, Sample RATE and Silent Pad+Trig Settings entered on 2 November 2026, on the owner's approval with the author's unit reports; each TESTING.md records what is still open. Quick Trig Conditions (was Quick Fill Trig Condition, merged into `_submissions/` in #1149) entered with 0.2.0-experimental on 4 November 2026, with the author's unit report on its build FC09. +Each folder here is a library module for the Analog Rytm MKII on OS 1.74 and core-ar2 0.7 (modules built for 0.3 link with it, but for mods that patch a page's entry or a page key's list themselves: see the [SDK guide](../../machines/analog-rytm-mkii/README.md#parameter-pages-core-04-and-later)): [CHORUS](chorus/), [Pad Pressure Fix](chromatic-aftertouch-fix/), [Control In Actions](control-in-actions/), [Improved Envelopes](envelopes/), [Filter Hz](filter-hz/), [FLANGER](flanger/), [Live Rec Retrig Fix](live-rec-retrig-fix/), [Loop Sync](loop-sync/), [PHASER](phaser/), [Pipo Loop](pipo-loop/), [QPERF](qperf/), [Quick Trig Conditions](quick-fill-trig-condition/), [Quick Velocity+Aftertouch Assign](quick-velocity-aftertouch-assign/), [Sample RATE](sample-rate/), [Silent Pad+Trig Settings](silent-pad-trig/) and [Temp Save](temp-save/). CHORUS, FLANGER and PHASER are send effects: a set holding one builds on the Modwerk base's send-bus variant ([Send effects](../../machines/analog-rytm-mkii/README.md#send-effects)). A new module comes here with its pinned package and is live once merged ([Create a mod](../../machines/analog-rytm-mkii/README.md#create-a-mod)); `_submissions/` holds older submissions and takes no new modules or changes. Loop Sync 0.2.0-experimental entered on the owner's approval with emulator evidence for its source; its [TESTING.md](loop-sync/TESTING.md) records what is still open. Pipo Loop, Sample RATE and Silent Pad+Trig Settings entered on 2 November 2026, on the owner's approval with the author's unit reports; each TESTING.md records what is still open. Quick Trig Conditions (was Quick Fill Trig Condition, merged into `_submissions/` in #1149) entered with 0.2.0-experimental on 4 November 2026, with the author's unit report on its build FC09. Temp Save (merged into `_submissions/` in #1116) entered with 0.1.0-experimental on 5 November 2026, with the author's unit report on its build TS09. diff --git a/sdk/analog-rytm-mkii/modules/envelopes/LICENSE b/sdk/analog-rytm-mkii/modules/envelopes/LICENSE new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sdk/analog-rytm-mkii/modules/envelopes/README.md b/sdk/analog-rytm-mkii/modules/envelopes/README.md new file mode 100644 index 000000000..1e6fcd46c --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/README.md @@ -0,0 +1,70 @@ +# Improved Envelopes + +Module for the Analog Rytm MKII, OS 1.74. It reworks the AMP envelope and shows times on the +envelope knobs. It carries Env Reset Amp (ENV RESET AMP, with a pre-fade added) on, so a set takes this module instead. + +Credits: Nathaniel Pavel (@npp1993) for Envelopes and the pre-fade; MrScruff for ENV RESET AMP (rytm-mods +0015-env-reset-amp); Iced-Cream for its elemod port and Modwerk module; irpina for Elekloader and core-ar2. + +## What changes + +| Control | Stock | With Envelopes | +|---|---|---| +| AMP HLD | 0 = AUTO, 1..127 = 15.6 ms .. 16 s from the trig, 7.8 ms steps to 250 ms | 0 = no hold, 1..126 = 0.67 ms steps to 10 ms (15), 1.3 ms to 18 ms (21), 3.3 ms to 51 ms (31), 6.7 ms to 151 ms (46), 13 ms to 298 ms (57), then about 6 % a step to 15.5 s, 127 = AUTO. The decay never starts before the attack reaches the top. 0.67 ms is a block, the OS's smallest hold step | +| AMP DEC, FILTER DEC, FILTER REL | stock's curve: 7.9 ms at 1, about 8 ms steps at the low end, 300 ms at 23, 45 s at 127 | 0 instant, 0.2 ms steps to 5 ms (25), 0.5 ms to 15 ms (45), 1 ms to 25 ms (55), 2.5 ms to 50 ms (65), 5 ms to 100 ms (75), 10 ms to 200 ms (85), 25 ms to 300 ms (89), then about 14 % a step to 39.4 s (AMP 126) or 45 s (FILTER 127). AMP DEC 127 stays INF | +| AMP ATK | 0 instant, 1 = 5.3 ms, about 5 ms steps at the low end, 127 = 30 s | 0 instant, 0.2 ms steps to 5 ms (25), 0.5 ms steps to 15 ms (45), then about 10 % a step to 30 s (measured on the unit) | +| FILTER ATK | stock's curve (as AMP's) | the same new curve as AMP ATK, built for the filter's speed measured on the unit (1.00x the OS model); played on the unit in EV14, 7.5..384 ms within 0.3 % of target | +| FUNC + turn on HLD | jumps to AUTO | steps 0, 124.7 ms (a 16th at 120 BPM, HLD 42), AUTO | +| AMP ATK, HLD, DEC, FILTER ATK, DEC, REL | 0..127 | times: an attack's full ramp, a hold's length, a decay's or release's time to -60 dB; AMP DEC 127 = INF | +| SOUND SETTINGS > ENV RESET | OFF, FILTER | OFF, AMP, FILTER, AMP+FILT (Env Reset Amp). AMP fades the amp envelope to silence just before sequenced trigs and retrig rolls (a held pad's RTRG roll too), so they restart from silence; a pad or MIDI hit itself, and the first trig after PLAY, continue from the current level, as stock | + +Saved values keep their bytes and are read the new way: a project made on stock plays HLD 0 as no hold +(was AUTO) and HLD 127 as AUTO (was 16 s), HLD 1..126, DEC and REL on the new curves (the same byte is a different time, mostly shorter at the low end), and AMP and FILTER ATK on the new curve. MIDI CC 79 (HLD) and the ATK CC +follow the knob. There is no migration. + +The ramps stay as stock makes them: the attack is a straight line in amplitude, decay and release are +exponential (straight lines in dB). A choke or stop still fades over stock's fixed ~43 ms. + +## How it works + +- `src/amp-write.s` takes the amp record write in `amp_env_commands` (0x40109c24, every voice every + block). It runs ENV RESET AMP's pre-fade (`src/pre-fade.c`) while a track has AMP in its ENV + RESET, then `envelopes_voice`, except for a voice whose record repeats the last one it took when + that one changed nothing (an idle voice, a decay at its end): an idle unit makes no C call there. +- `envelopes_voice` (`src/envelopes.c`) follows each voice's amp level from the records sent (the level + lives in the voice hardware) and sets the state stock moves to: after a trig 1 (gate, AUTO) or 2 + (timed); in the timed state it ends the hold when the hold time has passed and the level is at the + top. A one-pole decay is followed slightly fast, so the attack is never thought done early. +- ATK's rates come from `atk_rate` (`tools/atk_table.py`, 16-bit packed): `envelopes_voice` writes + them into the attack's records (the trig's and each held block's) as they are sent. +- FILTER ATK's rates come from `envelopes_flt_atk` (same script, 32-bit words): a `ptr` site in + `build.json` points stock's lea at 0x4010d2a8 (the filter attack table, read for the attack record + and the state counter alike) at it. +- ENV RESET AMP: the pre-fade watches each track's queued sequencer trig and retrig series and ramps + a sounding voice toward silence (up to ~4 ms, starting up to 7.3 ms ahead), so stock's attack, which + starts from the current level, starts from silence. A pad or MIDI hit, and a trig queued less than + the fade ahead (the first after PLAY), are not known in time and play as stock. A roll faster than + about 15 ms gets half its spacing to fade, so below about 8 ms it may not reach silence. +- DEC, REL and HLD: `tools/dec_table.py` builds three tables (`envelopes_amp_dec`, `envelopes_flt_dec`, + `envelopes_hold`, 128 words each) and `ptr` sites in `build.json` point stock's leas at them: the amp + decay record (0x40109bee), the filter decay and release records (0x4010d342, 0x4010d3b2, 0x4010d3da) + and the hold compare (0x40109bc2). Stock's tables stay where they are, unread by the OS. The AMP table is built + for the VCA's 0.918x decay speed, the filter's for 1.00x. The hold counter moves a block (16 ticks, + 0.67 ms) at a time, so every hold is a whole number of blocks. +- Times on the knobs come from core-ar2's `core_params` text for ids 50..58; HLD's FUNC jump is its + parameter record's jump function (id 57, +0x4c/+0x50). + +## Limits + +- AMP ATK and DEC times are calibrated to one Rytm MKII (EV06, 6 Nov 2026): its VCA ran attacks at + 0.957x and decays at 0.918x the OS's timing model, so the ATK table is built for 0.957 and the + AMP DEC text is scaled by 0.918. The filter envelope, measured through the self-oscillating + filter's pitch, runs at the OS model's speed (attack 3 ms..390 ms, decay and release 47 ms..1.2 s + time constants), so FILTER times need no factor; attacks under 3 ms were not resolved. + Another unit may differ slightly. HLD is counted by the OS and matched within 2 ms. +- AMP DEC under about 5 ms is blurred by the VCA's own slew (~0.8 ms): DEC 1..8 all measure 1-2 ms. + FILTER DEC and REL under 15 ms were not resolved on the unit (TESTING.md). +- A module that times a note by AMP DEC's table must read the table address the OS code holds at + 0x40109bf0, not stock's 0x401ee61c: with this module that address points at the new table. +- On stock firmware a sound saved here plays the stock way (HLD 0 = AUTO, the old ATK curve). +- Unit results: TESTING.md. diff --git a/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md b/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md new file mode 100644 index 000000000..a131c1c22 --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md @@ -0,0 +1,235 @@ +# Improved Envelopes: testing + +## Unit, EV15 / ED02 (DEC, REL and HLD curves), 6 Nov 2026 + +Build ED02 (unit pass): RC31's set and no-send base b530a147 with Improved Envelopes (head de6be7d02: +idle skip fcdf99a0, the tables from `tools/dec_table.py`, HLD texts in whole ms below 2 s). sha256 6060d48f640ae90ed2306a0cbbfff7dca8b9a275e6636e3fa70fb830fba55f81, +lock RC31's NS01 (unchanged), ramSpare 15,708. Independent review of ED01: no bugs; its HLD text finding +(79/80 and 81/82 read alike) is fixed in ED02. rytm-emu 2ac0f1f boots it ("cpu exceptions: 32:..." +only) and the five `ptr` sites hold the tables' addresses. + +On the unit (track 1 as it is, the looped sine; MIDI CC 78-80 from the rig, takes recorded from MAIN OUT +over USB; envelope read at 0.083 ms steps, -3 dB to -23 dB slope, t60 = 60 dB x ms per dB): + +| AMP DEC | design t60 | measured | +|---|---|---| +| 1 / 2 / 3 / 5 / 8 | 0.2 / 0.4 / 0.6 / 1.0 / 1.6 ms | 1.0 / 1.0 / 1.25 / 1.5 / 1.75 ms (the VCA's slew floors the shortest) | +| 12 / 15 / 20 | 2.4 / 3.0 / 4.0 ms | 2.5 / 3.25 / 4.25 ms | +| 25 / 30 / 35 / 45 / 55 | 5 / 7.5 / 10 / 15 / 25 ms | 5.0 / 7.5 / 10.0 / 15.0 / 25.0 ms | +| 65 / 75 / 85 / 89 | 50 / 100 / 200 / 300 ms | 50.3 / 100.8 / 201.3 / 301.5 ms | +| 95 / 100 / 105 / 110 | 0.66 / 1.28 / 2.47 / 4.78 s | 0.665 / 1.284 / 2.476 / 4.763 s | +| 113 / 115 / 117 / 120 | 7.10 / 9.25 / 12.04 / 17.88 s | 7.04 / 9.19 / 12.00 / 17.69 s | + +From 5 ms up the AMP decay is within 0.7 % of the text; below 5 ms the VCA slew (~0.8 ms) sets the floor, +so DEC 1..8 differ by less than a millisecond. + +| AMP HLD (ATK 0, DEC 25) | design | measured decay start, minus HLD 0 (3.3 ms) | +|---|---|---| +| 1 / 2 / 3 / 5 / 8 / 10 / 15 | 0.67 / 1.33 / 2.0 / 3.33 / 5.33 / 6.67 / 10.0 ms | 0.58 / 1.33 / 1.92 / 3.25 / 5.25 / 6.58 / 9.92 ms | +| 21 / 31 / 42 / 46 / 57 | 18.0 / 51.3 / 124.7 / 151.3 / 298 ms | 17.9 / 51.25 / 124.6 / 151.2 / 297.9 ms | +| 70 / 85 / 90 / 100 | 627 / 1481 / 1972 / 3497 ms | 627.3 / 1481.2 / 1972.0 / 3496.7 ms | +| 110 / 126 | 6.20 / 15.5 s | 6.20 / 15.50 s | + +FILTER DEC and REL (self-oscillating tone, FRQ 86, ENV +6, level through the map of a linear ATK 64, +log-linear fit from 80 % to 10 %, two takes each): time constant against the text's t60 / ln 1000. + +| k | DEC | REL | +|---|---|---| +| 45 / 55 / 65 (15 / 25 / 50 ms) | 1.017 / 1.016 / 1.015 | not measurable (too short to track) | +| 75 / 89 / 100 (100 ms / 300 ms / 1.28 s) | 1.014 / 1.015 / 1.012 | 1.015 / 1.015 / 1.015 | + +DEC 30 (7.5 ms) was too short to track. The 1.5 % is the method's, as on EV14. + +Some takes of the HLD sweep came back with a one-off USB capture gap (a stretch of digital silence); +those were repeated and the clean take is the one above. + +On the unit's screen (ED02, the user): AMP HLD 90 reads 1972ms and fits the field. + +Not tested: FILTER DEC/REL below 15 ms and AMP DEC below 5 ms to better than the VCA's slew, the other knob texts on the unit's screen (host-checked: all 128 values of each knob distinct, at most 6 characters), FUNC jump to HLD 42, saving and reloading. + +## Idle CPU, LR03 / LP01 (6 November 2026) + +The amp writer called `envelopes_voice` for every voice every block, and voice 0 ran the pre-fade scan +every block. Now (8028baf2) voice 0 skips the scan while no track has AMP in its ENV RESET (it clears the +fade mask, as the scan finds), and a voice skips the C call when its rate and level words equal the last +ones it took and that call left the level follower as it was. The follower is a pure function of its +state and the record outside the attack words, so the skipped call would have changed nothing. Stock +(read in amp_env_commands) sends rate 0 / level 0 to an idle voice every block, and the same one-pole +record in the decay state, which a voice stays in until its next trig. + +- Measured on the owner's MKII with the private lag-telemetry base, RC31's set, scratch project, + sequencer stopped, no USB audio, 50 one-second readings: LR01 (RC31) 70.84 % of the audio block, + LR03 (RC31 with this source) 70.37 %. Pad mash (LR02, with two other idle changes): 81.7 % against + 82.7 %, ~10 % fewer presses. +- Independent code review: no findings (registers, ColdFire encodings, skip equivalence). +- rytm-emu: LP01 boots, TRAP #0 only. Rig re-run on the unit: pending. + +## Unit, EV14 (current), 6 Nov 2026 + +Build EV14: EV13's set with Improved Envelopes at 4efb6fbe (FILTER ATK table for the filter's 1.00x +speed, FILTER text unscaled; 18a15a2e adds only docs); sha256 +61163e6089ca427505e2c25fcd3401e13dd828a23094cd3d5be856bf5d83cc9f, lock NS01, ramSpare 17,788. +Flashed by the owner. FILTER ATK by the ~1.3 kHz method of the EV13 section (FRQ 86, ENV +6, ends +extrapolated, four takes each; mean / spread): + +| FILTER ATK | Target | Measured | Ratio | +|---|---|---|---| +| 10 / 15 / 20 / 25 | 2 / 3 / 4 / 5 ms | 1.88 / 3.01 / 3.83 / 4.87 ms (spread 0.04-0.21) | 0.94 / 1.00 / 0.96 / 0.97 | +| 30 / 35 / 40 / 45 | 7.5 / 10 / 12.5 / 15 ms | 7.50 / 9.99 / 12.50 / 15.01 ms (spread <= 0.008) | 1.000 | +| 50 / 55 / 64 / 72 / 80 | 23.8 / 37.9 / 87.2 / 183 / 384 ms | 23.86 / 37.96 / 87.40 / 183.46 / 385.03 ms | 1.001-1.003 | + +Below 3 ms one tone cycle (~0.5 ms) is a large part of the ramp, so 2 ms and shorter are within the +method's error. Everything else of EV13 carries over (AMP code unchanged). + +## Unit, EV13, 6 Nov 2026 + +Build EV13: EV09's set and base (no-send b530a147, lock NS01) with Improved Envelopes at a6df46ff +(FILTER ATK table, rounded knob times); sha256 +6c7598110742557956310a49906aa44d20978273f31d66a394eb8fa4de9c3cbb, ramSpare 17,708. Flashed by the +owner; scratch project, track 1 a looped sine. MAIN OUT over USB audio, settings by USB MIDI CC. + +**ENV RESET AMP, sequenced.** The owner programmed track 1 (trigs on steps 1, 5, 9; step 13 a trig +with RTRG 1/16, about 4 steps; other tracks muted); the rig set AMP ATK 64 (87 ms), HLD 0, DEC 100 +and ran the pattern with MIDI START, 120 BPM clock and STOP. + +| ENV RESET | Each later trig and retrig (steps 5, 9, 13 and the 1/16 roll) | +|---|---| +| AMP | the voice, at -1.9 dB (steps) or -0.1 dB (roll) 15 ms before, drops to -48..-54 dB at the trig, then rises to the top in ~91 ms (the 87 ms attack) | +| OFF | no dip: the attack continues from -2 dB and reaches the top within ~15-20 ms (stock) | + +Aborted fades (EV14, same day): the rig drove the pattern with its own MIDI clock and made the step-5 +trig fail on purpose, ENV RESET AMP, a steady ~1.3 kHz tone at -2 dB. STOP sent 3 ms before step 5: +the voice fades to -50 dB within ~5 ms and stays silent to the end of the take (1.2 s). Clock stopped +before step 5: the voice holds through the missed step, fades ~90 ms later (when the Rytm's own tempo +expected the trig) and stays silent. No jump back in either. Unexplained, seen once: on the first run +(MIDI START with no clock at all while CLOCK RECEIVE is on, same pattern), a fade ~85 ms before an +expected step was followed ~90 ms later by the level returning to -1 dB within 10 ms. Three more +START-without-clock runs did not show it (the sequencer either held silent or ignored START); a +transport with no clock at all is not a normal way to play, so it is left as a note. + +**FILTER ATK on the new table** (method as EV09 below: LP2, RES 127, FRQ 40, LEV 0, ENV +24, AMP ATK 0 +/ HLD AUTO / DEC INF, FILTER SUS 127 / DEC 0, single MIDI notes; rise start to top, by zero crossings). +Target = the curve; this build's table carried the 0.984 speed (superseded below). + +| ATK | Target | Measured | Resolution (two periods) | +|---|---|---|---| +| 64 / 72 / 80 / 96 | 87.2 / 183 / 384 / 1691 ms | 88.7 / 183.7 / 381.9 / 1710 ms | 4-7 ms | +| 45 / 55 | 15 / 37.9 ms | 16.1 / 42.3 ms | 4-5 ms | +| 1 / 5 / 10 / 25 / 35 | 0.2 / 1 / 2 / 5 / 10 ms | 1.6 / 1.9 / 1.5 / 11.3 / 11.5 ms | 1.5-5 ms | + +The long end matches within 2 %. Below 15 ms the filter tone is too low for this method to time the +ramp (a few cycles across it), so short FILTER ATK times were not measured this way (see the ~1.3 kHz runs below). A run at FRQ 70 put the top +of the sweep past the tracker's 12 kHz range and was discarded. + +**Filter envelope re-measured at ~1.3 kHz** (same EV13 unit, same day). The low tone above (139 Hz, +7 ms a cycle) blurs short segments, and timing the rise between thresholds cut its ends off. Here: +FRQ 86, ENV +6 (a 12-semitone sweep from ~1.3 kHz), each segment's ends extrapolated from line fits +over 10-30 % and 70-90 % of the sweep, four takes per attack value, two per decay/release value +(medians; three single takes where a fit failed are left out). + +| FILTER ATK | Target (curve) | Median measured | Ratio | +|---|---|---|---| +| 15 / 20 / 25 | 3 / 4 / 5 ms | 2.96 / 3.90 / 4.94 ms | 0.99 / 0.97 / 0.99 | +| 30 / 35 / 40 / 45 | 7.5 / 10 / 12.5 / 15 ms | 7.61 / 10.15 / 12.71 / 15.25 ms | 1.015-1.017 | +| 50 / 55 / 64 / 72 / 80 | 23.8 / 37.9 / 87.2 / 183 / 384 ms | 24.26 / 38.57 / 88.82 / 186.42 / 391.19 ms | 1.017-1.019 (spread <= 0.06 ms) | +| 5 / 10 | 1 / 2 ms | 0.82 / 1.66 ms | below the method's ~0.5 ms cycle | + +The table then carried 0.984, so the filter ran at 0.984 x 1.018 = 1.00x the OS model. + +| FILTER (time constant) | 24 | 40 | 56 | 72 | 88 | +|---|---|---|---|---|---| +| DEC, model ms | 47.2 | 120.7 | 268.5 | 566.0 | 1164.4 | +| DEC, measured / model | 1.013 | 1.011 | 1.008* | 1.002 | 0.987 | +| REL, measured / model | 1.014 | 1.016* | 1.015* | 1.013 | 1.014 | + +(* one of two takes; the other's fit failed.) Level read back through a linear attack's pitch map, +log-linear fit between 80 % and 10 %. So the filter envelope runs at the model's speed: 4efb6fbe +builds the FILTER ATK table for 1.0 and shows FILTER times unscaled (EV14). EV14's table is not yet +played on the unit. + +Not tested on the unit in EV13: knob texts (rytm-emu: FILTER ATK reads 1.0ms, 4.2ms, 11.0ms, 16.5ms, +2.2s on the curve), FUNC jumps, choke, saving and reloading, CPU cost. + +## Unit, EV09, 6 Nov 2026 + +Build EV09: RC30's set with envelopes in place of env-reset-amp, on the private no-send base b530a147, +lock NS01; sha256 6cccc5e5c91bd24e89c1220ecddef3c569386aed9b44e9f3d79c590999c3f908 (source b6727c48; +the display-name commit 0764febb is in it). Flashed by the owner; track 1 as the owner set it (a +looped ~1 kHz sine), only AMP ATK/HLD/DEC sent over USB MIDI (CC 78/79/80), MAIN OUT over USB audio. + +| Check | Target | Measured | +|---|---|---| +| ATK peak 10 / 25 / 35 / 45 / 55 / 64 / 72 / 80 | 2 / 5 / 10 / 15 / 37.9 / 87.2 / 183 / 384 ms | 2.5 / 5.0 / 10.25 / 15.5 / 38.25 / 87.5 / 183.5 / 383.75 ms | +| ATK 0 / 1 / 5 (0 / 0.2 / 1 ms) | | 0.75 / 1.5 / 1.25 ms (the VCA's own slew) | +| Decay start HLD 0 / 1 / 7 / 15 / 31 / 47 | 0 / 15.6 / 62.5 / 125 / 250 / 500 ms | 2.5 / 17.5 / 64.2 / 126.8 / 251.5 / 501.5 ms | +| AUTO, note 100 / 300 ms | 100 / 300 ms | 102.5 / 301.5 ms | +| Never cut, ATK 87 ms: HLD 0 / 2 / 7 (62.5 ms) | peak at 87 ms | 87.5 / 87.5 / 87.5-87.8 ms (HLD 7 re-run 3x: one sweep take had a late USB note) | +| Second MIDI note on a decaying voice (ATK 64/72, DEC 100/110; ENV RESET set to AMP or AMP+FILT, as the owner recalls; MIDI hits bypass it by design) | attack continues from the current level to the first peak | -14.27 vs -14.28 dB, all three; the second peak came 23 / 24.5 / 52 ms after the note, from 0.9 / 1.2 / 2.0 dB below the peak (no restart, as designed). Not a test of ENV RESET AMP | +| AMP DEC slope, DEC 6..126 | 0.918 x model (text) | 0.90-0.925 x model (DEC 108/114 captures failed) | + +Decay start = the 3 dB point minus 3 x the measured dB slope. The VCA ran attacks at 0.957x and decays +at 0.918x the OS timing model on EV06; EV07 on builds the ATK table and the AMP ATK/DEC text for it. + +### Filter envelope timing (EV09, same day) + +Track 1's filter self-oscillating (LP2, RES 127, FRQ 40, sample LEV 0, ENV depth +24, AMP ATK 0 / HLD +AUTO / DEC INF), its pitch tracked by zero crossings: the envelope's level was read back through the +pitch-to-level map of a linear attack (FILTER ATK 48), so the cutoff curve does not bias the fit. + +| Segment | Values | Measured / model | +|---|---|---| +| Attack (rise start to top) | ATK 16 / 32 / 48 / 56 / 64 / 72 / 80 | 0.956 / 0.979 / 0.983 / 0.984 / 0.984 / 0.985 / 0.986 | +| Decay (time constant, SUS 0) | DEC 24 / 40 / 56 / 72 / 88 | 0.905 / 0.902 / 0.895 / 0.887 / 0.873 | +| Release (time constant, SUS 127) | REL 24 / 40 / 56 / 72 / 88 | 0.906 / 0.904 / 0.902 / 0.902 / 0.901 | + +FILTER ATK text scaled by 0.984, DEC and REL by 0.90 (EV10..EV13). Superseded: the ~1.3 kHz runs in +the EV13 section show both were this method's bias; from 4efb6fbe the filter has no factor. + +These runs used stock's FILTER ATK table (118 ms..3.7 s attacks). The new FILTER ATK table +(`envelopes_flt_atk`, site 0x4010d2aa, EV11 on) is checked in rytm-emu only (knob text); its times on +the unit, and the filter's speed below 118 ms, were not tested then (now measured: EV13 section). + +## Unit, EV04 + +## Unit (Analog Rytm MKII, OS 1.74), 6 Nov 2026 + +Build EV04: RC30's set with Envelopes in place of Env Reset Amp, base 8b0cafbc, sha256 +374157b56041b15bff1d9795371cc60c6a7f0388c7075378e1365287a549d393 (source 818f7b08). Flashed by the +owner; scratch project. + +Automated: track 1 (BD) on BD ANALOG with its DEC 127, filter open, no FX, AMP DEC 40, played over USB +MIDI (channel 1, note 0, velocity 100), MAIN OUT recorded over USB audio; script envtest.py (private +rig, not in the repo). BD ANALOG's own body falls about 3 dB over the first 150 ms and it has an onset +click, so hold and AUTO are judged against the HLD 47 take (held to 500 ms), not by an absolute peak. + +| Check | Result | +|---|---| +| HLD 0, ATK 0 | falls from the hit (below the held take by 20 ms) | +| HLD 1 / 7 / 15 / 31 (15.6 / 62.5 / 125 / 250 ms) | leaves the held take after about 20 / 80 / 150 / 300 ms (sample points 10-50 ms apart) | +| AUTO, note 100 ms / 300 ms | leaves the held take right after note-off (125 / 400 ms points) | +| AUTO, ATK 64, note 50 ms | decays from the note-off, mid-attack (AUTO is outside the never-cut rule) | +| Never cut: ATK 64 (87 ms) with HLD 0, 2 (24 ms), 7 (62.5 ms) | identical takes; peak 87 ms, decay from 85 ms | +| ATK peak: 55 / 64 / 72 / 80 (37.9 / 87.2 / 183 / 384 ms) | 36.8 / 87.3 / 171.5 / 348 ms (long ones peak early on BD ANALOG's falling body) | +| ATK rise 10-90 %: 0 / 1 / 5 / 10 / 25 (0 / 0.2 / 1 / 2 / 5 ms) | 1.0 / 1.0 / 1.25 / 1.75 / 3.75 ms (hardware slew ~0.8 ms floors the shortest) | +| ATK 64 rise 10-90 % | 64.8 ms = 0.74 of the 87.2 ms ramp, as earlier probe measurements | + +Not tested on the unit: knob texts and the AMP picture (rytm-emu only), FUNC jumps, ENV RESET AMP and +its pre-fade in this build (unchanged code from Env Reset Amp 1.1.0, which passed ER05), filter +DEC/REL times, retrigs, choke, saving and reloading, CPU cost. + +## rytm-emu (2ac0f1f), EV02-EV04 + +- Boots to the main screen; CPU exceptions only TRAP #0, as RC30. +- HLD text: 24ms (2), 31ms (3), 125ms (15), 500ms (47), 10.5s (116), 13s (120), AUTO (127). +- AMP DEC text: 63ms (7), 3.3s (68), 39.5s (124). (EV02 showed 0 / 1667s: fixed in EV03.) +- ATK text: 6.5ms (28), 38ms (55). +- FUNC + turn on HLD: 0 -> 15 -> 127 and back (stock's debounce paces it). +- AMP picture: HLD 0 attack straight into decay, AUTO with the note at 127. +- State traces (voice 0): HLD 0 + ATK 0 -> decay one block after the trig; HLD 0/2 + ATK 38 ms -> + decay at 57 blocks (38 ms); HLD 15 -> 3024 ticks (125 ms); AUTO -> state 1 (gate); HLD turned to + AUTO during a timed hold -> state 1. + +## Review + +Independent code review (two rounds): findings fixed in 5437e197 (MAC-mode -60 dB times, follower +start at silence, AUTO turned mid-hold, slow-rate floor); second round found no new bugs. diff --git a/sdk/analog-rytm-mkii/modules/envelopes/build.json b/sdk/analog-rytm-mkii/modules/envelopes/build.json new file mode 100644 index 000000000..abdb842da --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/build.json @@ -0,0 +1,129 @@ +{ + "schemaVersion": 1, + "sources": [ + "src/amp-write.s", + "src/pre-fade.c", + "src/envelopes.c" + ], + "defsym": {}, + "cflags": [], + "weak": [], + "subscribe": [ + { + "event": "ev_tick", + "fn": "envelopes_tick", + "order": 50 + } + ], + "contribute": [ + { + "to": "core_params", + "order": 50, + "data": "00000000", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_params", + 0 + ] + ] + } + ], + "collections": {}, + "copied": [], + "regions": [], + "claims": [ + "ui:SOUND SETTINGS ENV RESET values", + "ui:FUNC + turn of AMP HLD", + "ui:value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL", + "ui:AMP page envelope picture HLD", + "audio:amp envelope record write", + "audio:filter attack rate table", + "audio:amp hold table", + "audio:amp decay table", + "audio:filter decay and release table" + ], + "requires": [], + "derive": null, + "releases": { + "1.74": { + "defsym": {}, + "cflags": [], + "sites": [ + { + "addr": "0x400bcf8a", + "len": 2, + "stockSha256": "0b358362552792220751c58c4cca9c4e54407d2339649a0b96182880f0504c1a", + "op": "bytes", + "new": "7403", + "kind": "code" + }, + { + "addr": "0x400ef8d6", + "len": 2, + "stockSha256": "4e4b41344512feecd49483d4a3f357ebd5b45f53276f21411a66cb3b4d597c16", + "op": "bytes", + "new": "4e71", + "kind": "code" + }, + { + "addr": "0x40109c24", + "len": 8, + "stockSha256": "3df81daa6f0b5b044b3c5bbf7c45a8d96b97caa686b60bf262eeda8b7dc87dc5", + "op": "jmp", + "target": "envelopes_write" + }, + { + "addr": "0x400d3302", + "len": 6, + "stockSha256": "704bb7e62b7dc84ac22bb9ec1242ae79e917ce47a7b6a4aa06ec60b72654b2c0", + "op": "jsr", + "target": "envelopes_amp_graph" + }, + { + "addr": "0x4010d2aa", + "len": 4, + "stockSha256": "bb101f17b7e23130f5e92c2f8e616cf858c9db923af32f0756f4cd9af27591d0", + "op": "ptr", + "target": "envelopes_flt_atk" + }, + { + "addr": "0x40109bc4", + "len": 4, + "stockSha256": "a93a6f0c7e9387b5bf90a027d5678b11c90d555082736705d44faca3b73d46b6", + "op": "ptr", + "target": "envelopes_hold" + }, + { + "addr": "0x40109bf0", + "len": 4, + "stockSha256": "8879f37f45bb49679a30176c392dc823a5215ba1fdbecc9406684fec9adbc2aa", + "op": "ptr", + "target": "envelopes_amp_dec" + }, + { + "addr": "0x4010d344", + "len": 4, + "stockSha256": "e752dd02ad509e30bf4eab19cb5a7ef8760906dfdfa6d410e8a42e3635a2ef39", + "op": "ptr", + "target": "envelopes_flt_dec" + }, + { + "addr": "0x4010d3b4", + "len": 4, + "stockSha256": "e752dd02ad509e30bf4eab19cb5a7ef8760906dfdfa6d410e8a42e3635a2ef39", + "op": "ptr", + "target": "envelopes_flt_dec" + }, + { + "addr": "0x4010d3dc", + "len": 4, + "stockSha256": "e752dd02ad509e30bf4eab19cb5a7ef8760906dfdfa6d410e8a42e3635a2ef39", + "op": "ptr", + "target": "envelopes_flt_dec" + } + ] + } + } +} diff --git a/sdk/analog-rytm-mkii/modules/envelopes/media/LICENSE.md b/sdk/analog-rytm-mkii/modules/envelopes/media/LICENSE.md new file mode 100644 index 000000000..aaca18e4b --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/media/LICENSE.md @@ -0,0 +1,7 @@ +# Rytm UI documentation captures + +The Modwerk contributor dedicates their original capture contribution to the public domain under CC0-1.0. This declaration covers the act of capture and accompanying original captions, not the depicted firmware interface. + +Elektron retains rights in its underlying interface and firmware. Module interface additions retain their author's terms in [../LICENSE](../LICENSE). No firmware, extracted stock code, raw memory/framebuffer data, card images or audio samples are included. The images are unmodified firmware-rendered pixels at integer scale. + +Manifest identifier: `LicenseRef-Rytm-UI-Documentation`. Capture identity and inputs: [capture.json](capture.json). diff --git a/sdk/analog-rytm-mkii/modules/envelopes/media/thumbnail.svg b/sdk/analog-rytm-mkii/modules/envelopes/media/thumbnail.svg new file mode 100644 index 000000000..0137eaeb5 --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/media/thumbnail.svg @@ -0,0 +1,8 @@ + +ENV RESET AMP +SOUND SETTINGS ENV RESET gains AMP and AMP+FILT: the amp envelope restarts from silence on every trig, so AMP ATK is heard on every hit. Original conceptual illustration, not an instrument screen or a measured result. + + + +ENV RESET: AMP + diff --git a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json new file mode 100644 index 000000000..c6082b389 --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json @@ -0,0 +1,148 @@ +{ + "schemaVersion": 3, + "id": "envelopes", + "name": "Improved Envelopes", + "version": "0.1.0-experimental", + "machine": "analog-rytm-mkii", + "category": "machines", + "exclusive": false, + "author": { + "github": "npp1993", + "name": "Nathaniel Pavel", + "credits": [ + "Nathaniel Pavel — Envelopes: HOLD order and attack-aware hold, the ATK curve, envelope times on the knobs, and ENV RESET AMP's pre-fade.", + "MrScruff — ENV RESET AMP, the original mod 0015-env-reset-amp in rytm-mods, its design and code; published in rytm-mods-src with permission.", + "Iced-Cream — Env Reset Amp, the elemod port (rytm2_mods) and its Modwerk module, which Envelopes carries on.", + "irpina — Elekloader and core-ar2, the core it links with." + ] + }, + "maintainers": [ + "npp1993" + ], + "presentation": { + "label": "IMPROVED ENVELOPES", + "family": "Sound", + "summary": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", + "overview": "Envelopes reworks the AMP envelope. HOLD runs from 0 (no hold: the decay starts the moment the attack reaches the top) up to AUTO at the top of the knob (hold while the note lasts); a hold never cuts the attack short. AMP ATK and FILTER ATK step 0.2 ms at a time up to 5 ms, 0.5 ms up to 15 ms, then about 10 % a step up to 30 s. SOUND SETTINGS > ENV RESET gains AMP and AMP+FILT (from Env Reset Amp): sequenced trigs and retrig rolls restart the amp envelope from silence after a short pre-fade; a pad or MIDI hit itself, and the first trig after PLAY, continue from the current level, as stock. AMP ATK, HLD and DEC and FILTER ATK, DEC and REL show times instead of 0..127.", + "highlights": [ + "HOLD: 0 = no hold, top = AUTO; never cuts the attack.", + "AMP and FILTER ATK: 0.2 ms steps at the low end.", + "ENV RESET AMP with a click-free pre-fade.", + "Envelope knobs show ms and s." + ], + "usage": [ + "Load a sound, open the AMP page and turn HLD fully left: the sound decays straight from its peak.", + "Turn HLD fully right to AUTO: the sound holds while the trig or note lasts.", + "Turn ATK from 0 up: it reads 0.2ms, 0.4ms, ... with fine steps for clicks and transients." + ] + }, + "access": { + "location": "AMP page (HLD, ATK); SOUND menu (FUNC + MUTE) > SOUND SETTINGS > ENV RESET.", + "steps": [ + "Open the AMP page.", + "Turn HLD or ATK; FUNC + turn on HLD jumps between 0, 125 ms and AUTO." + ], + "screenshots": [] + }, + "controls": [ + { + "name": "AMP > HLD", + "default": null, + "doc": "0 no hold, then 0.67 ms steps to 10 ms, 1.3 ms to 18 ms, 3.3 ms to 51 ms, 6.7 ms to 151 ms, 13 ms to 298 ms, about 6 % a step to 15.5 s, AUTO at the top. The decay never starts before the attack peaks.", + "labels": null + }, + { + "name": "AMP > ATK", + "default": null, + "doc": "0 instant, 0.2 ms steps to 5 ms, 0.5 ms steps to 15 ms, then about 10 % a step to 30 s.", + "labels": null + }, + { + "name": "FILTER > ATK", + "default": null, + "doc": "The same curve as AMP ATK: 0 instant, 0.2 ms steps to 5 ms, 0.5 ms steps to 15 ms, then about 10 % a step to 30 s.", + "labels": null + }, + { + "name": "AMP > DEC, FILTER > DEC and REL", + "default": null, + "doc": "0 instant, 0.2 ms steps to 5 ms, 0.5 ms to 15 ms, 1 ms to 25 ms, 2.5 ms to 50 ms, 5 ms to 100 ms, 10 ms to 200 ms, 25 ms to 300 ms, then about 14 % a step to 40-45 s. Times are to -60 dB. AMP DEC at the top stays INF.", + "labels": null + }, + { + "name": "SOUND SETTINGS > ENV RESET", + "default": null, + "doc": "Steps OFF, AMP, FILTER, AMP+FILT. With AMP, sequenced trigs and retrig rolls (a held pad's RTRG too) restart the amp envelope from silence after a short pre-fade; a pad or MIDI hit itself, and the first trig after PLAY, continue from the current level, as stock.", + "labels": null + } + ], + "compatibility": { + "releases": [ + "1.74" + ], + "requires": [], + "conflicts": [], + "limitations": [ + "Built for OS 1.74 only.", + "Saved HLD, ATK, DEC and REL values read differently from stock: HLD 0 is no hold instead of AUTO, 127 is AUTO instead of 16 s, and HLD, AMP and FILTER ATK, DEC and REL follow the new curves.", + "Times shown are calibrated to one Rytm MKII (AMP attack 0.957x, decay 0.918x; the filter envelope runs at the OS model's speed); another unit may differ slightly.", + "ENV RESET AMP acts only on trigs the Rytm schedules in time (sequencer trigs, retrig rolls): a pad or MIDI hit itself and the first trig after PLAY play as stock, and a roll faster than about 8 ms may not fade fully to silence." + ] + }, + "platform": { + "kind": "elemod", + "core": "0.3", + "build": "build.json", + "events": [ + "ev_tick" + ], + "claims": [ + "ui:SOUND SETTINGS ENV RESET values", + "ui:FUNC + turn of AMP HLD", + "ui:value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL", + "ui:AMP page envelope picture HLD", + "audio:amp envelope record write", + "audio:filter attack rate table", + "audio:amp hold table", + "audio:amp decay table", + "audio:filter decay and release table" + ] + }, + "resources": { + "memoryBytes": null, + "fastBytes": null, + "load": { + "display": "Not measured yet", + "method": "unmeasured", + "conditions": "Measure with every voice playing, retrigs and modulated envelopes." + } + }, + "evidence": { + "tier": "none", + "moduleVersion": "0.1.0-experimental", + "reports": [], + "hardware": null, + "verifiedBy": null, + "sourceSha256": null + }, + "tests": { + "report": "TESTING.md", + "summary": "Not tested yet." + }, + "license": { + "spdx": "GPL-2.0-only", + "file": "LICENSE", + "declaration": "Nathaniel Pavel's code, and MrScruff's rytm-mods code with Iced-Cream's elemod port, under GPL-2.0-only. The source names firmware addresses only; the patch preconditions are addresses, lengths and SHA-256s." + }, + "media": [ + { + "path": "media/thumbnail.svg", + "kind": "thumbnail", + "caption": "Env Reset Amp", + "alt": "Original illustration of four envelopes, each rising from zero", + "credit": "Iced-Cream", + "license": "GPL-2.0-only", + "source": "Original vector illustration; not a device screenshot." + } + ] +} diff --git a/sdk/analog-rytm-mkii/modules/envelopes/src/amp-write.s b/sdk/analog-rytm-mkii/modules/envelopes/src/amp-write.s new file mode 100644 index 000000000..68078f2e7 --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/src/amp-write.s @@ -0,0 +1,137 @@ + | SPDX-License-Identifier: GPL-2.0-only + | Envelopes - the amp envelope record write (OS 1.74). + | + | ENV RESET AMP comes from Env Reset Amp: MrScruff's rytm-mods 0015, ported + | to elemod by Iced-Cream, with Nathaniel Pavel's pre-fade (1.1): the voice + | fades out over up to ~4 ms, starting up to 7.3 ms before a trig the + | Rytm schedules itself - a sequencer trig or a retrig - so stock's + | attack, which ramps from the + | current level, starts from silence on time. A pad or MIDI hit is not + | known in advance and plays as stock. + | + | Envelopes adds (Nathaniel Pavel): every voice's record then goes to + | envelopes_voice (envelopes.c), which puts this module's ATK rate into + | the attack's records, follows the voice's amp level and decides when + | the hold ends (HOLD 0 = no hold, 127 = AUTO, never before the attack's + | top). + | + | Rate word bit 30, which stock sets for ENV RESET FILTER, resets the + | level to 0 - the filter envelope's neutral point, but half gain on the + | amp - so it is not used here. + + .equ VOICE_TRACK, 0x40291138 | voice -> track, bytes + .equ WRITE_RESUME, 0x40109c2c | moveq #8,%d0, then the level word + .equ TRIG, 0x8000e508 | per track, long: 1 on a trig + .equ FADE_START, 0xb006a7ec | linear ramp from the current level + .equ FADE_GO_ON, 0x3006a7ec | the same ramp, continued + .equ FADE_LEVEL, 0x00000080 | to -128 + .equ ENV_RESET, 0x8000ea30 | per track, byte: bit 0 AMP (12 tracks) + + .text + + | ------------------------------------------------------------------ + | envelopes_write: over the two `move.l %d0` stores of the voice's rate + | word at 0x40109c24 (amp_env_commands 0x40109940), every block for each + | voice, in every state, after stock's state machine. + | + | For voice 0 it first runs envelopes_scan (pre-fade.c), which marks the + | voices a scheduled trig with AMP in its ENV RESET will restart within + | the fade; while no track has AMP in its ENV RESET it clears the mask + | instead, as the scan would. For a marked voice that is sounding and was + | not trigged this block, it sends a linear ramp to -128 instead of the + | state's command: the ramp (mode B) in its first block, then mode 3 with + | the same target and rate every block until the trig, as stock's own + | attack does. + | + | Then envelopes_voice, unless the voice's record is the one it last + | took and that one left the voice as it was (envelopes_gate, pre-fade.c): + | an idle voice (rate and level words 0) and a decay that has reached its + | end get the same record every block, so an idle unit makes no C call. + | + | d0 the rate word, d2 the level word, d3 the voice, a2 its state (-1 + | idle; +4 the hold counter), a3 the frame at the voice's record, a4 the + | track's sound slice (+0 ATK, +2 HLD, +4 DEC). d1, d4 and a0 are written + | before they are read on the next pass, so they are free. + | ------------------------------------------------------------------ + .globl envelopes_write + .align 2 +envelopes_write: + tst.l %d3 + bne.s 1f + move.l ENV_RESET,%d1 | once a block: any track's AMP bit + or.l ENV_RESET+4,%d1 + or.l ENV_RESET+8,%d1 + andi.l #0x01010101,%d1 + bne.s 3f + clr.l envelopes_gate | no voice to fade + bra.s 1f +3: lea -16(%sp),%sp + movem.l %d0-%d1/%a0-%a1,(%sp) + jsr envelopes_scan + movem.l (%sp),%d0-%d1/%a0-%a1 + lea 16(%sp),%sp +1: move.l envelopes_gate,%d1 | the voices to fade + btst %d3,%d1 + beq.s 9f + tst.l (%a2) + bmi.s 9f | idle + lea VOICE_TRACK,%a0 + mvz.b (%a0,%d3.l),%d1 + lea TRIG,%a0 + moveq #1,%d4 + cmp.l (%a0,%d1.l*4),%d4 + beq.s 9f | trigged this block + move.l #FADE_GO_ON,%d0 + move.l envelopes_gate+4,%d1 | the fades that start now + btst %d3,%d1 + beq.s 2f + move.l #FADE_START,%d0 +2: move.l #FADE_LEVEL,%d2 +9: move.l envelopes_gate+8,%d1 | the voices left as they were + btst %d3,%d1 + beq.s 5f + lea envelopes_gate+16,%a0 + cmp.l (%a0,%d3.l*4),%d0 | the same rate word + bne.s 5f + cmp.l 32(%a0,%d3.l*4),%d2 | and level word: nothing changes + beq.s 8f +5: lea -16(%sp),%sp + movem.l %d0-%d1/%a0-%a1,(%sp) + move.l %d2,-(%sp) | level word + move.l %d0,-(%sp) | rate word + move.l %a4,-(%sp) | sound slice + move.l %a2,-(%sp) | state, counter + move.l %d3,-(%sp) | voice + jsr envelopes_voice + move.l %d0,20(%sp) | the rate word it returns + lea 20(%sp),%sp + movem.l (%sp),%d0-%d1/%a0-%a1 + lea 16(%sp),%sp +8: move.l %d0,172(%a3) | displaced + move.l %d0,236(%a3) + jmp WRITE_RESUME + + | ------------------------------------------------------------------ + | envelopes_amp_graph: over the AMP page's call of stock's envelope + | picture at 0x400d3302, `jsr 0x40038bce` (SoundPageView's draw). The + | picture takes (view, bmp, 6, 0, 0, ATK, HLD, DEC) in 8.8 and draws HLD + | 0 as AUTO (the note and a full-width hold). Here HLD 127 is AUTO and 0 + | is no hold, so 127 goes in as 0 and 0 as 1/256 (no width, no note). + | At entry the arguments sit above the return address: HLD at 28(%sp). + | d0 is free: the caller drops it. + | ------------------------------------------------------------------ + .equ AMP_PICTURE, 0x40038bce + + .globl envelopes_amp_graph + .align 2 +envelopes_amp_graph: + move.l 28(%sp),%d0 + cmp.l #0x7f00,%d0 + blt.s 1f + clr.l 28(%sp) | AUTO + bra.s 2f +1: tst.l %d0 + bgt.s 2f + moveq #1,%d0 | no hold + move.l %d0,28(%sp) +2: jmp AMP_PICTURE diff --git a/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c b/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c new file mode 100644 index 000000000..0efcacada --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Envelopes (Nathaniel Pavel): the AMP envelope's HOLD order and ATK curve, and times on the +// envelope knobs, for the Analog Rytm MKII OS 1.74. ENV RESET AMP and its pre-fade are +// Env Reset Amp's (amp-write.s, pre-fade.c). +// +// HOLD (AMP page, id 57) keeps its stored byte, read as: 0 no hold, 1..126 the new hold +// times (counted from the trig), 127 AUTO (hold while the note is on, stock's 0). The decay +// never starts before the attack reaches the top, so every value but AUTO is at least a +// plain attack-decay. Stock's state machine (amp_env_commands 0x40109940) still runs; at +// its record write, envelopes_voice sets the state it moves to: 1 (gate) or 2 (timed) +// after a trig, and in the timed state 2 or 3 (decay) by its own rule. To know when the +// attack is at the top, it follows each voice's level from the records sent (the level +// itself lives in the voice hardware and is not read back). +// +// ATK (id 56): envelopes_voice puts the rate from atk_rate (tools/atk_table.py) into the +// attack's records: 0 instant, 0.2 ms steps to 5 ms, 0.5 ms steps to 15 ms, then about 10 % a +// step to stock's 30 s. +// +// DEC and REL (AMP DEC id 58, FILTER DEC id 51, FILTER REL id 53) and HLD (id 57) have fine steps +// at the short end too (tools/dec_table.py): their stock tables are replaced by our own, through +// ptr sites in build.json, so stock's state machine and record writers read them unchanged. +// +// FILTER ATK (id 50) has the same curve, in its own table envelopes_flt_atk: build.json's ptr +// site points stock's lea at 0x4010d2a8 (the filter envelope's attack table, read for the +// attack record and the state counter alike) at it. +// +// The AMP ATK, HLD and DEC and FILTER ATK, DEC and REL knobs show times: an attack's full +// ramp, a decay's or release's time to -60 dB, a hold's length. + +#include +#include "analog-rytm-mk2/pages.h" + +typedef uint32_t word_t; + +// ---- stock OS 1.74 ---- +// (The stock tables of AMP HLD 0x401ee81c, AMP DEC 0x401ee61c and FILTER DEC/REL 0x401ef030 are +// replaced by envelopes_hold, envelopes_amp_dec and envelopes_flt_dec below, through ptr sites.) +#define HOLD_TICKS envelopes_hold +#define AMP_DECAY envelopes_amp_dec +#define FLT_DECAY envelopes_flt_dec +#define REC(id) (0x419a4888 + 84 * (id)) // a parameter's RAM record +#define JUMP_MANAGER(id) (*(volatile word_t *)(REC(id) + 0x4c)) +#define JUMP_INVOKER(id) (*(volatile word_t *)(REC(id) + 0x50)) +#define STOCK_MANAGER 0x400fe584 // a stateless lambda's manager + +#define ID_F_ATK 50 +#define ID_F_DEC 51 +#define ID_F_REL 53 +#define ID_A_ATK 56 +#define ID_A_HLD 57 +#define ID_A_DEC 58 + +// The unit's VCA ramps run faster than the OS's timing model: attack 0.957x, decay 0.918x +// (Rytm MKII, EV06, 6 Nov 2026: a 1 kHz tone, ATK 10..80 and DEC 6..126). The ATK table is +// built for it; the times shown are scaled to it, in 1/1024. +#define HW_ATTACK 980 +#define HW_DECAY 940 +// The filter envelope runs at the model's speed (same unit, 6 Nov 2026, through the +// self-oscillating filter's pitch at ~1.3 kHz: attack 1.00x over 3..390 ms, decay and release +// 0.99-1.01x over 47 ms..1.2 s time constants), so FILTER text needs no factor. (An earlier +// low-pitch method, which cut the ends off each segment, had read 0.98x (0.984 used) and 0.90x.) + +#define HLD_AUTO 127 +#define LEVEL_ATTACK 0x4000007fu // the trig's attack record (state 0): ramp to 127 +#define LEVEL_HOLD 0x0000007fu // states 1 and 2: the attack continued +#define TOP ((127 << 16) - (1 << 15)) // within half a level of the top + +// Generated by tools/atk_table.py: AMP ATK knob -> linear rate coefficient, packed. +static const uint16_t atk_rate[128] = { + 0x0000, 0x203f, 0x33c3, 0x3dd8, 0x453d, 0x4ad0, 0x4e76, 0x5215, + 0x55ea, 0x58e0, 0x5b3c, 0x5d28, 0x5ec0, 0x6032, 0x627f, 0x647d, + 0x663a, 0x67c3, 0x691f, 0x6a56, 0x6b6d, 0x6c6a, 0x6d50, 0x6e21, + 0x6ee1, 0x6f92, 0x7224, 0x74a4, 0x76c1, 0x7890, 0x7a21, 0x7b80, + 0x7cb5, 0x7dc8, 0x7ebd, 0x7f9a, 0x80c5, 0x8230, 0x837c, 0x84ab, + 0x85c3, 0x86c5, 0x87b4, 0x8891, 0x8960, 0x8a20, 0x8c0e, 0x8dd0, + 0x8f6a, 0x91bf, 0x9468, 0x96d4, 0x9909, 0x9b0d, 0x9ce2, 0x9e8e, + 0xa028, 0xa2ee, 0xa576, 0xa7c4, 0xa9de, 0xabc9, 0xad87, 0xaf1f, + 0xb124, 0xb3c9, 0xb631, 0xb863, 0xba64, 0xbc37, 0xbde0, 0xbf64, + 0xc18c, 0xc411, 0xc65c, 0xc874, 0xca5c, 0xcc19, 0xcdaf, 0xcf20, + 0xd0e3, 0xd349, 0xd579, 0xd777, 0xd948, 0xdaf0, 0xdc73, 0xddd3, + 0xdf14, 0xe072, 0xe288, 0xe46e, 0xe629, 0xe7bd, 0xe92e, 0xea7d, + 0xebaf, 0xecc6, 0xedc5, 0xeeac, 0xef80, 0xf081, 0xf1e0, 0xf320, + 0xf443, 0xf54d, 0xf640, 0xf71c, 0xf7e6, 0xf89d, 0xf945, 0xf9dd, + 0xfa68, 0xfae7, 0xfb5a, 0xfbc4, 0xfc24, 0xfc7b, 0xfccb, 0xfd13, + 0xfd56, 0xfd92, 0xfdc9, 0xfdfb, 0xfe29, 0xfe53, 0xfe79, 0xfe9b, +}; + +// The same curve for FILTER ATK (0 -> 127 levels), read by stock through the lea at +// 0x4010d2a8 (attack record and the state counter alike), so full 32-bit words. +const uint32_t envelopes_flt_atk[128] __attribute__((aligned(4))) = { + 0x00000, 0x2f499, 0x42751, 0x4d097, 0x54128, 0x59e5b, 0x5db60, 0x60cd9, + 0x64cd8, 0x67e49, 0x6a5a0, 0x6c5ad, 0x6e04a, 0x6f6be, 0x713e1, 0x73515, + 0x75214, 0x76ba0, 0x7824c, 0x7968e, 0x7a8c4, 0x7b93a, 0x7c82d, 0x7d5d0, + 0x7e24e, 0x7edca, 0x80da2, 0x83749, 0x85a7d, 0x878a2, 0x892bc, 0x8a98f, + 0x8bdaf, 0x8cf90, 0x8df8c, 0x8edee, 0x8faf0, 0x90d85, 0x92319, 0x936de, + 0x9490e, 0x959d6, 0x9695f, 0x977cc, 0x98538, 0x991bf, 0x9b1e2, 0x9cf29, + 0x9e9d6, 0xa044a, 0xa3095, 0xa58f2, 0xa7dba, 0xa9f3e, 0xabdc9, 0xad99f, + 0xaf2fc, 0xb1435, 0xb3e58, 0xb64bf, 0xb87be, 0xba7a4, 0xbc4b6, 0xbdf36, + 0xbf75c, 0xc1abe, 0xc42dd, 0xc676f, 0xc88c4, 0xca725, 0xcc2d6, 0xcdc13, + 0xcf315, 0xd101a, 0xd3653, 0xd592a, 0xd78ec, 0xd95de, 0xdb040, 0xdc84d, + 0xdde38, 0xdf233, 0xe08d4, 0xe2a07, 0xe484a, 0xe63df, 0xe7d04, 0xe93ef, + 0xea8d2, 0xebbdd, 0xecd38, 0xedd0a, 0xeeb75, 0xef89a, 0xf092b, 0xf1f03, + 0xf32eb, 0xf4511, 0xf559b, 0xf64af, 0xf726d, 0xf7ef5, 0xf8a5f, 0xf94c9, + 0xf9e45, 0xfa6eb, 0xfaecd, 0xfb5fb, 0xfbc89, 0xfc281, 0xfc7f1, 0xfcce7, + 0xfd16d, 0xfd58b, 0xfd94d, 0xfdcb9, 0xfdfd9, 0xfe2b1, 0xfe549, 0xfe7a7, + 0xfe9cd, 0xfebc5, 0xfed8f, 0xfef31, 0xff0ad, 0xff209, 0xff345, 0xff465, +}; + +// AMP DEC knob -> one-pole coefficient (time to -60 dB, for the VCA at 0.918x), read by stock +// through the lea at 0x40109bee. +const uint32_t envelopes_amp_dec[128] __attribute__((aligned(4))) = { + 0x00000, 0x0889d, 0x110f2, 0x1933b, 0x1dff5, 0x2246e, 0x26b39, 0x29fbb, + 0x2c836, 0x2e85d, 0x30508, 0x33065, 0x354ef, 0x37423, 0x38f18, 0x3a69d, + 0x3bb51, 0x3cdae, 0x3de14, 0x3eccf, 0x3fa1d, 0x40c64, 0x4226b, 0x43696, + 0x4491f, 0x45a36, 0x47fa1, 0x49ef3, 0x4b98d, 0x4d06c, 0x4e44c, 0x4f5bb, + 0x50a4a, 0x525bd, 0x53e57, 0x55484, 0x5689b, 0x57ae4, 0x58b9b, 0x59af1, + 0x5a910, 0x5b61c, 0x5c233, 0x5cd6f, 0x5d7e6, 0x5e1ad, 0x5f368, 0x60624, + 0x62203, 0x63af8, 0x65172, 0x665cb, 0x6784e, 0x68937, 0x698ba, 0x6a700, + 0x6c62b, 0x6e02a, 0x6f62d, 0x7121e, 0x732dc, 0x74f86, 0x768d3, 0x77f53, + 0x79376, 0x7a597, 0x7c4eb, 0x7df08, 0x7f523, 0x81030, 0x8310d, 0x84dd0, + 0x86732, 0x87dc3, 0x891f5, 0x8a422, 0x8c38a, 0x8ddb7, 0x8f3de, 0x90db9, + 0x92ea5, 0x94b74, 0x964e1, 0x97b7b, 0x98fb4, 0x9a1e8, 0x9c857, 0x9e716, + 0xa0080, 0xa2a71, 0xa6370, 0xa9566, 0xac131, 0xae793, 0xb1272, 0xb4d6e, + 0xb8121, 0xbae71, 0xbd629, 0xbf8f9, 0xc2ef9, 0xc6477, 0xc9358, 0xcbc70, + 0xce074, 0xd000b, 0xd3761, 0xd67e1, 0xd9263, 0xdb7a5, 0xdd84d, 0xdf4ec, + 0xe1c05, 0xe47ff, 0xe6e8a, 0xe9052, 0xeaded, 0xec7e1, 0xede9f, 0xef28f, + 0xf0811, 0xf26b1, 0xf4189, 0xf5911, 0xf6daf, 0xf7fc3, 0xf8f9b, 0xf9d7d, +}; + +// FILTER DEC and REL knob -> coefficient (the filter runs at the OS model's speed), read by +// stock through the leas at 0x4010d342, 0x4010d3b2 and 0x4010d3da. +const uint32_t envelopes_flt_dec[128] __attribute__((aligned(4))) = { + 0x00000, 0x07968, 0x0f951, 0x179ce, 0x1ca90, 0x1ffe0, 0x24b38, 0x28362, + 0x2aeca, 0x2d154, 0x2ed76, 0x309a3, 0x33108, 0x352b3, 0x36fcf, 0x38939, + 0x39f9b, 0x3b377, 0x3c535, 0x3d527, 0x3e38f, 0x3f0a4, 0x3fc93, 0x40f01, + 0x42318, 0x4359f, 0x45e33, 0x4802d, 0x49d0b, 0x4b5de, 0x4cb73, 0x4de62, + 0x4ef20, 0x4fe09, 0x516ce, 0x52ee7, 0x544bc, 0x5589c, 0x56ac7, 0x57b73, + 0x58acd, 0x598fd, 0x5a622, 0x5b25a, 0x5bdbc, 0x5c85e, 0x5dba7, 0x5ecb0, + 0x5fbd9, 0x612da, 0x62b4e, 0x64173, 0x65597, 0x667fe, 0x678df, 0x68868, + 0x6aa54, 0x6c69f, 0x6de95, 0x6f322, 0x709eb, 0x7291f, 0x744ab, 0x75d2a, + 0x77316, 0x786d4, 0x7a8ef, 0x7c55f, 0x7dd71, 0x7f215, 0x807f4, 0x82747, + 0x842eb, 0x85b7f, 0x8717d, 0x88549, 0x8a77d, 0x8c3ff, 0x8dc1f, 0x8f0ce, + 0x90579, 0x924da, 0x9408b, 0x95929, 0x96f30, 0x98304, 0x9ace0, 0x9ce5e, + 0x9e9c6, 0xa013b, 0xa3f51, 0xa75bc, 0xaa570, 0xacf40, 0xaf3e6, 0xb280c, + 0xb605d, 0xb91b9, 0xbbcfd, 0xbe2e9, 0xc084d, 0xc4291, 0xc75a2, 0xca265, + 0xcc9a1, 0xcec04, 0xd144f, 0xd4924, 0xd7772, 0xda008, 0xdc39b, 0xde2c9, + 0xdfe1c, 0xe2c20, 0xe561d, 0xe7ae9, 0xe9b2a, 0xeb76f, 0xed035, 0xee5ed, + 0xef8f5, 0xf1349, 0xf3087, 0xf4a27, 0xf609f, 0xf744f, 0xf8591, 0xf94b1, +}; + +// AMP HLD knob -> hold in ticks of 2 samples, whole blocks of 16, read by stock through the lea +// at 0x40109bc2 and by envelopes_voice. 0 is no hold and 127 AUTO (not read). +const int32_t envelopes_hold[128] __attribute__((aligned(4))) = { + 0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240, + 272, 304, 336, 368, 400, 432, 512, 592, + 672, 752, 832, 912, 992, 1072, 1152, 1232, + 1392, 1552, 1712, 1872, 2032, 2192, 2352, 2512, + 2672, 2832, 2992, 3152, 3312, 3472, 3632, 3952, + 4272, 4592, 4912, 5232, 5552, 5872, 6192, 6512, + 6832, 7152, 7568, 8016, 8496, 8992, 9520, 10080, + 10672, 11312, 11968, 12688, 13424, 14224, 15056, 15952, + 16880, 17872, 18928, 20048, 21232, 22480, 23808, 25216, + 26704, 28272, 29936, 31696, 33568, 35552, 37648, 39856, + 42208, 44704, 47328, 50128, 53072, 56208, 59520, 63024, + 66736, 70672, 74848, 79248, 83920, 88864, 94112, 99664, + 105536, 111744, 118336, 125312, 132704, 140512, 148800, 157568, + 166864, 176688, 187104, 198128, 209808, 222176, 235280, 249136, + 263824, 279376, 295840, 313280, 331744, 351296, 372000, 372000, +}; + +// ---- the voice's amp level, followed from the records ---- +// +// A record is a level word (W, start S, target T as signed bytes) and a rate word: mode +// [31:28], sub-block nibble, flags [23:20] (0 linear, 1 one-pole) and a 20-bit +// coefficient. Modes as measured on the unit: B and 3 head for T from the current level, +// F (and 7) load S first, 9 changes the rate only, A and 2 freeze, 0 and 8 send nothing +// (the running segment goes on). Per tick (2 samples) a linear segment moves step / 2^23 +// levels; a one-pole one keeps (2^31 - step) / 2^31 of its distance to T. +// +// Levels are kept in 1/65536, from silence (-128) at boot: an idle voice gets no records. +// The follower errs low: a one-pole block takes 16 x step / 2^31 of the distance at the unit's +// measured decay speed (HW_DECAY), slightly more than the hardware's 1 - (1 - x)^16, so a +// falling level is followed at or below the real one; the attack is followed at the model's +// speed, slower than the unit's (HW_ATTACK). So the attack is never thought done early. +// (Stock's amp sends no rising one-pole segment.) +struct amp { + int32_t level, target; + uint32_t step; + uint8_t one_pole, frozen; +}; +#define SILENT (-128 * 65536) +static struct amp amps[8] = { + { SILENT, SILENT, 0, 0, 0 }, { SILENT, SILENT, 0, 0, 0 }, { SILENT, SILENT, 0, 0, 0 }, + { SILENT, SILENT, 0, 0, 0 }, { SILENT, SILENT, 0, 0, 0 }, { SILENT, SILENT, 0, 0, 0 }, + { SILENT, SILENT, 0, 0, 0 }, { SILENT, SILENT, 0, 0, 0 }, +}; + +static uint32_t atk_coeff(int k) +{ + uint32_t u = atk_rate[k < 0 ? 0 : k > 127 ? 127 : k]; + return (u >> 12) << 16 | (u & 0xfff) << 4; +} + +static uint32_t rate_step(uint32_t c) +{ + uint32_t e = c >> 16 & 15, m = c & 0xffff; + return ((0x7fffffffu - (m << 14)) >> e) - 32768u; +} + +__attribute__((noinline)) static void follow(struct amp *a, uint32_t rate, uint32_t lw) +{ + unsigned mode = rate >> 28; + int32_t d; + uint32_t ad, move; + + if (mode == 0xa || mode == 0x2) { + a->frozen = 1; + } else if (mode && mode != 8) { + if (mode & 4) + a->level = (int32_t)(int8_t)(lw >> 8) * 65536; + if (mode != 9) + a->target = (int32_t)(int8_t)lw * 65536; + a->step = rate_step(rate & 0xfffff); + a->one_pole = rate >> 20 & 1; + a->frozen = 0; + } + if (a->frozen) + return; + d = a->target - a->level; + ad = d < 0 ? (uint32_t)-d : (uint32_t)d; + if (!ad) + return; + if (!a->one_pole) { + move = a->step >> 3; // 16 ticks: step x 16 x 65536 / 2^23 + if (!move) + move = 1; // a rate this slow still ends + if (move >= ad) { + a->level = a->target; + return; + } + ad -= move; + } else { + // 16 ticks: 16 x step / 2^31, in 1/65536, at the unit's decay speed (1 / 0.918), + // rounded up (step >> 6 keeps the fraction for slow decays); 2^27 and up is instant. + move = a->step >= (1u << 27) ? 65536 : (((a->step >> 6) * 1116) >> 15) + 1; + if (move >= 65536) { + a->level = a->target; + return; + } + ad -= (ad >> 8) * move >> 8; + } + a->level = d < 0 ? a->target + (int32_t)ad : a->target - (int32_t)ad; +} + +// Called by envelopes_write (amp-write.s) for every voice every block, after stock's state +// machine and before the record is stored; returns the rate word to store. st[0] is the +// voice's state, st[1] its hold counter (cleared at the trig, +16 a block in state 2, already +// added this block); snd[0] is the track's ATK, snd[2] its HLD. +extern volatile uint32_t envelopes_gate[20]; // pre-fade.c +#define GATE_STILL envelopes_gate[2] +#define GATE_RATE(v) envelopes_gate[4 + (v)] +#define GATE_LW(v) envelopes_gate[12 + (v)] + +uint32_t envelopes_voice(int32_t v, volatile int32_t *st, const volatile int8_t *snd, uint32_t rate, + uint32_t lw) +{ + struct amp *a = &s[v & 7], was = *a; + int h = snd[2]; + uint32_t bit = 1u << (v & 7); + + // The attack's records (the trig's, then each held block's): this module's ATK curve. + if (lw == LEVEL_ATTACK || lw == LEVEL_HOLD) + rate = (rate & 0xfff00000u) | atk_coeff(snd[0]); + + if (lw == LEVEL_ATTACK) { + st[0] = h == HLD_AUTO ? 1 : 2; + } else if (lw == LEVEL_HOLD && h == HLD_AUTO && st[0] == 2) { + st[0] = 1; // turned to AUTO while held: the gate (set at the trig) ends it + } else if (lw == LEVEL_HOLD && h != HLD_AUTO && (uint32_t)(st[0] - 1) < 3u) { + // States 1 and 2 send the continued attack; 3 here is 2 that stock just ended. + int32_t hold = h > 0 ? HOLD_TICKS[h] : 0; + st[0] = st[1] - 16 >= hold && a->level >= TOP ? 3 : 2; + } + follow(a, rate, lw); + // A record that is neither attack word and left the follower as it was does the same next + // time: until the record changes, the writer skips this call (amp-write.s). Idle voices and + // a decay that has reached its end get the same record every block. + if (lw != LEVEL_ATTACK && lw != LEVEL_HOLD && a->level == was.level && a->target == was.target && + a->step == was.step && a->one_pole == was.one_pole && a->frozen == was.frozen) { + GATE_RATE(v & 7) = rate; + GATE_LW(v & 7) = lw; + GATE_STILL |= bit; + } else { + GATE_STILL &= ~bit; + } + return rate; +} + +// ---- FUNC + turn on HOLD: 0, 125 ms (a 16th at 120 BPM), AUTO ---- +static int32_t hold_jump(const void *fn, int32_t value, int32_t delta, int32_t min, int32_t max, + int32_t def) +{ + static const int8_t pos[] = { 0, 42, HLD_AUTO }; + int v = value >> 8, i; + + (void)fn, (void)min, (void)max, (void)def; + if (delta > 0) { + for (i = 0; i < 3; i++) + if (pos[i] > v) + return pos[i] << 8; + } else { + for (i = 2; i >= 0; i--) + if (pos[i] < v) + return pos[i] << 8; + } + return v << 8; +} + +// The records are built at boot; the jump goes in once and is checked at the UI's rate. +void envelopes_tick(void *ctrl) +{ + (void)ctrl; + if (JUMP_INVOKER(ID_A_HLD) != (word_t)hold_jump) { + JUMP_MANAGER(ID_A_HLD) = STOCK_MANAGER; + JUMP_INVOKER(ID_A_HLD) = (word_t)hold_jump; + } +} + +// ---- times on the knobs ---- +__attribute__((noinline)) static char *put_uint(char *p, uint32_t v) +{ + char t[10]; + int n = 0; + do + t[n++] = (char)('0' + v % 10); + while ((v /= 10) && n < 10); + while (n) + *p++ = t[--n]; + return p; +} + +__attribute__((noinline)) static void put_text(char *p, const char *s) +{ + while ((*p++ = *s++)) + ; +} + +// ticks of 2 samples: "0", "0.2ms", "9.8ms", "87ms", "1234ms", "2.1s", "15.5s", "100s". +__attribute__((noinline)) static void put_time(char *p, uint32_t ticks) +{ + uint32_t ms10, ms, s10; + + if (ticks > 40000000u) + ticks = 40000000u; + ms10 = (ticks * 10 + 12) / 24; + if (!ms10) { + put_text(p, "0"); + return; + } + if (ms10 < 200) { // tenths up to 20 ms: ATK's 0.5 ms steps stay visible + p = put_uint(p, ms10 / 10); + *p++ = '.'; + p = put_uint(p, ms10 % 10); + put_text(p, "ms"); + return; + } + // Each unit rounds from the ticks, not from the unit below it (31.46 ms shows 31ms). + ms = (ticks + 12) / 24; + if (ms < 2000) { // whole ms up to 2 s: HLD's 6 % steps stay apart + put_text(put_uint(p, ms), "ms"); + return; + } + s10 = (ticks + 1200) / 2400; + if (s10 < 1000) { + p = put_uint(p, s10 / 10); + *p++ = '.'; + p = put_uint(p, s10 % 10); + put_text(p, "s"); + return; + } + put_text(put_uint(p, (ticks + 12000) / 24000), "s"); +} + +// log2(y) x 65536, y > 0 (as SY RUMB's). +__attribute__((noinline)) static int32_t log2_q16(uint32_t y) +{ + int32_t n = 31, bit, f = 0; + uint32_t m; + + while (!(y & 0x80000000u)) { + y <<= 1; + n--; + } + m = y >> 16; + for (bit = 15; bit >= 0; bit--) { + m = (m * m) >> 15; + if (m >= 65536) { + m >>= 1; + f |= 1 << bit; + } + } + return (n << 16) + f; +} + +// A one-pole segment's ticks to fall 60 dB: ln 1000 / -ln p, p = 1 - step / 2^31 a tick. +// The OS's own (0x4011e85c) runs on the MAC in fractional mode, which only the audio +// interrupt sets, so it reads wrong from the UI. Small steps: -ln p = x (1 + x / 2), x = +// step / 2^31 (the next term is under 0.01 %); larger: log2, 1/65536 resolution. +__attribute__((noinline)) static uint32_t t60_ticks(uint32_t c) +{ + uint32_t s = rate_step(c), d; + int32_t q; + + if (s < 16) + return 0x7fffffffu; + if (s < (1u << 25)) { + d = (s >> 4) + (s >> 18) * (s >> 18); // x (1 + x / 2), in 2^-27 + return 927143219u / d; // ln 1000 x 2^27 + } + if (s >= 0x7fff0000u) + return 0; + q = (31 << 16) - log2_q16(0x7fffffffu - s); + return q > 0 ? 653118u / (uint32_t)q : 0x7fffffffu; // log2 1000 x 65536 +} + +// A linear segment's ticks over levels, as the OS counts them (0x4011e7d6). +__attribute__((noinline)) static uint32_t linear_ticks(uint32_t levels, uint32_t c) +{ + uint32_t s = rate_step(c); + return s ? (levels << 23) / s + 1 : 0x7fffffffu; +} + +// ticks x f / 1024, rounded, without overflow (ticks up to 0x7fffffff). Rounded, not +// floored, so short attacks (a few dozen ticks) read their nearest tenth. +static uint32_t scaled(uint32_t ticks, uint32_t f) +{ + return (ticks >> 10) * f + (((ticks & 1023) * f + 512) >> 10); +} + +static int envelopes_text(struct core_text *t) +{ + int v = t->value >> 8; + + if (v < 0) + v = 0; + if (v > 127) + v = 127; + switch (t->id) { + case ID_A_ATK: + put_time(t->buf, scaled(linear_ticks(255, atk_coeff(v)), HW_ATTACK)); + break; + case ID_A_HLD: + if (v == HLD_AUTO) + put_text(t->buf, "AUTO"); + else + put_time(t->buf, v ? (uint32_t)HOLD_TICKS[v] : 0); + break; + case ID_A_DEC: + if (v == 127) + put_text(t->buf, "INF"); + else + put_time(t->buf, scaled(t60_ticks(AMP_DECAY[v] & 0xfffff), HW_DECAY)); + break; + case ID_F_ATK: + put_time(t->buf, linear_ticks(127, envelopes_flt_atk[v])); + break; + case ID_F_DEC: + case ID_F_REL: + put_time(t->buf, t60_ticks(FLT_DECAY[v] & 0xfffff)); + break; + default: + return CORE_TEXT_PASS; + } + return CORE_TEXT_DONE; +} + +const struct core_param envelopes_params = { ID_F_ATK, ID_A_DEC, 0, 0, envelopes_text }; diff --git a/sdk/analog-rytm-mkii/modules/envelopes/src/pre-fade.c b/sdk/analog-rytm-mkii/modules/envelopes/src/pre-fade.c new file mode 100644 index 000000000..b286dd46a --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/src/pre-fade.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Envelopes: ENV RESET pre-fade (Nathaniel Pavel, from Env Reset Amp 1.1): fade a sounding voice out before a +// trig the Rytm schedules itself, so stock's attack, which ramps from the +// current level, restarts from silence without a click. +// +// The sequencer queues each track's next trig a step ahead, its probability +// already rolled, in the track's first event slot (state 1), and keeps the time +// it will fire at in the track's event times. Mutes are applied only when the +// trig fires, so they are read here the same way. Read in OS 1.74 and checked +// in rytm-emu: a queued trig always fired and an unqueued one never did, at 50 % +// and without a condition; a muted track's trig stays queued but does not fire. +// A retrig series (a trig's RTRG, or a pad held with RTRG) fires on its own +// tick counter, which stock steps once a tick (0x4012089a); the next hits are +// worked out the same way. Pads, MIDI and a trig queued less than the fade ahead +// (the first after PLAY) are not seen in time: those play as stock. + +#include + +#define TRACKS 12 +#define FADE_BLOCKS 10 // the fade starts up to 11 blocks (7.3 ms) before the trig + +#define CLOCK (*(volatile int32_t *)0x8000fe54) // musical clock, + 2 x TEMPO a block +#define TEMPO (*(volatile int32_t *)0x40287ffc) // BPM x 120 +#define EVENT(t) (*(volatile int32_t *)(0x8000fd50 + 12 * (t))) // next event's time +#define SLOT(t) (*(volatile int32_t *)(0x42ac5fb0 + 224 * (t))) // 1: a trig queued +#define TRACK_HELD(t) (*(volatile int32_t *)(0x42ad4c30 + 6668 * (t) + 6664)) +#define MUTES (*(volatile uint32_t *)0x8000ed98) +#define SOLOS (*(volatile uint32_t *)0x8000ed9c) +#define LIVE_MUTES (*(volatile uint16_t *)0x8000fc90) +#define ENV_RESET ((volatile uint8_t *)0x8000ea30) // [track] bit 0 amp +#define TRACK_VOICE ((const uint8_t *)0x4025a3a0) // [track] physical voice +#define TICK 90000 // clock units in a 240 PPQN tick +#define RT_TRIG(t) (*(volatile int32_t *)(0x42ac6b48 + 56 * (t))) // nonzero: a series runs +#define RT_RATE(t) (*(volatile int32_t *)(0x42ac6b48 + 56 * (t) + 36)) // RETRIG 0..16 +#define RT_COUNT ((volatile int32_t *)0x42adf5d0) // [track] 960..1, -1 a tick +#define RT_DEADLINE ((volatile int32_t *)0x8000fdec) // [track] its next tick's time +#define RT_FIRES ((const volatile uint16_t *)0x402909b8) // [count] bit RATE-1: fires + +// The amp writer's state (amp-write.s reads it for every voice every block), kept together so +// a voice with nothing to do touches three 16-byte lines: [0] the voices to fade this block, [1] of +// those, the voices whose fade starts now, [2] the voices whose last record left the level +// follower unchanged (envelopes.c), [4 + v] and [12 + v] that record's rate and level words. +volatile uint32_t envelopes_gate[20] __attribute__((aligned(16))); +#define envelopes_mask envelopes_gate[0] +#define envelopes_first envelopes_gate[1] + +// Clock units from now to track t's next retrig, as stock counts it, or -1 when +// none falls within window. A series that fires again sooner than twice the +// window gets half its spacing to fade in instead, so a fast roll still sounds. +static int32_t retrig_ahead(int t, int32_t clock, int32_t window) +{ + int32_t count = RT_COUNT[t], at = RT_DEADLINE[t] - clock, first = -1; + int rate = RT_RATE(t); + + // A deadline already past is a series stock no longer ticks. + if (rate < 0 || rate > 16 || at < -TICK) + return -1; + for (; at < 2 * window; at += TICK) { + if (--count <= 0) { + count = 960; + } else if (!(RT_FIRES[count] * 2 >> rate & 1)) { + continue; + } + if (first < 0) { + if (at >= window) + return -1; + first = at; + } else { + return first < (at - first) / 2 ? first : -1; + } + } + return first; +} + +// Called by the amp writer for voice 0, once a block, while a track's sound has AMP in its +// ENV RESET: the voices whose sound restarts its amp envelope on a scheduled trig or retrig +// within FADE_BLOCKS. With none, the writer clears the mask itself (as this finds). +void envelopes_scan(void) +{ + uint32_t mask = 0, muted; + int32_t window, clock = CLOCK; + int t; + + // As stock decides at the trig (0x4011ffde): solo mutes every other track. + muted = SOLOS ? ~SOLOS & ~0x1000u : MUTES; + muted |= LIVE_MUTES; + // The trig fires in the block its time falls in; the clock is this block's start. + window = (FADE_BLOCKS + 1) * 2 * TEMPO; + for (t = 0; t < TRACKS; t++) { + int32_t ahead; + + if ((muted >> t & 1) || !(ENV_RESET[t] & 1)) + continue; + ahead = -1; + if (SLOT(t) == 1 && !TRACK_HELD(t)) + ahead = EVENT(t) - clock; + if ((ahead < 0 || ahead >= window) && RT_TRIG(t)) + ahead = retrig_ahead(t, clock, window); + if (ahead >= 0 && ahead < window) + mask |= 1u << TRACK_VOICE[t]; + } + envelopes_first = mask & ~envelopes_mask; + envelopes_mask = mask; +} diff --git a/sdk/analog-rytm-mkii/modules/envelopes/tools/atk_table.py b/sdk/analog-rytm-mkii/modules/envelopes/tools/atk_table.py new file mode 100644 index 000000000..f44887130 --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/tools/atk_table.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only +"""Envelopes' AMP ATK curve: knob value -> amp envelope rate word (20-bit coefficient). + +The amp attack is a linear ramp from silence (-128) to the top (127), 255 levels. A +coefficient c (e = c[19:16], m = c[15:0]) moves the level step / 2^23 levels per tick +(2 samples at 48 kHz), step = ((0x7FFFFFFF - (m << 14)) >> e) - 32768, as the OS times its +linear segments. The curve: + + 0 instant (c = 0) + 1..25 0.2 ms steps, 0.2 .. 5 ms + 26..45 0.5 ms steps, 5.5 .. 15 ms + 46..127 x r a step, 15 ms .. 29.89 s (stock's ATK 127) + +Stored packed in 16 bits, e << 12 | m >> 4 (m rounded to a multiple of 16: at most 2.3e-4 off in +step); unpacked as (u >> 12) << 16 | (u & 0xfff) << 4. Prints the C table for src/envelopes.c; +--check prints each value's time back from the packed table. +""" +import sys + +TICKS_PER_MS = 24.0 # 48 kHz, 2 samples a tick +HW_SPEED = 0.957 # the unit's amp attack runs 0.957x the OS timing model (EV06, 6 Nov 2026) +F_LEVELS, F_HW_SPEED = 127, 1.0 # the filter attack: 0 -> 127 levels, at the model's speed (EV13: 1.00x, 3 ms..390 ms) +TOP_MS = 29889.0 # stock ATK 127's full ramp +LEVELS = 255 + + +def curve_ms(): + t = [0.0] + for k in range(1, 26): + t.append(0.2 * k) + for k in range(26, 46): + t.append(5.0 + 0.5 * (k - 25)) + r = (TOP_MS / t[45]) ** (1.0 / (127 - 45)) + for k in range(46, 128): + t.append(t[45] * r ** (k - 45)) + return t + + +def step_of(c): + e, m = (c >> 16) & 15, c & 0xFFFF + return ((0x7FFFFFFF - (m << 14)) >> e) - 32768 + + +def encode(ms, levels=LEVELS, hw=HW_SPEED, packed=True): + if ms <= 0: + return 0 + ticks = ms / hw * TICKS_PER_MS - 1 # model ticks the unit plays in ms; +1 as the OS counts + s = int(round(levels * 2 ** 23 / ticks)) + 32768 + n = 32 - s.bit_length() - 1 # clz(s) - 1: s << n has bit 30 as its top bit + m = (0x7FFFFFFF - (s << n)) >> 14 + if packed: + m = min((m + 8) >> 4, 0xFFF) << 4 # packed: the low 4 bits of m are dropped + assert 0 <= n <= 15 and 0 <= m <= 0xFFFF, (ms, s, n, m) + return (n << 16) | m + + +def pack(c): + return (c >> 16) << 12 | (c & 0xFFFF) >> 4 + + +def ramp_ms(c, levels=LEVELS, hw=HW_SPEED): + return ((levels << 23) / step_of(c) + 1) / TICKS_PER_MS * hw + + +def main(): + t = curve_ms() + table = [encode(x) for x in t] + ftable = [encode(x, F_LEVELS, F_HW_SPEED, False) for x in t] + if '--check' in sys.argv: + for k, (want, c) in enumerate(zip(t, table)): + got = ramp_ms(c) + err = 0 if want == 0 else (got - want) / want * 100 + print(f'{k:3d} want {want:10.3f} ms c {c:05x} got {got:10.3f} ms {err:+.2f} %') + for k, (want, c) in enumerate(zip(t, ftable)): + got = ramp_ms(c, F_LEVELS, F_HW_SPEED) + err = 0 if want == 0 else (got - want) / want * 100 + print(f'{k:3d} want {want:10.3f} ms c {c:05x} got {got:10.3f} ms {err:+.2f} %') + return + print('// Generated by tools/atk_table.py: AMP ATK knob -> linear rate coefficient, packed.') + print('static const uint16_t atk_rate[128] = {') + for i in range(0, 128, 8): + print(' ' + ', '.join(f'0x{pack(c):04x}' for c in table[i:i + 8]) + ',') + print('};') + print() + print('// The same curve for FILTER ATK (0 -> 127 levels), read by stock through the lea at') + print('// 0x4010d2a8 (attack record and the state counter alike), so full 32-bit words.') + print('const uint32_t envelopes_flt_atk[128] __attribute__((aligned(4))) = {') + for i in range(0, 128, 8): + print(' ' + ', '.join(f'0x{c:05x}' for c in ftable[i:i + 8]) + ',') + print('};') + + +if __name__ == '__main__': + main() diff --git a/sdk/analog-rytm-mkii/modules/envelopes/tools/dec_table.py b/sdk/analog-rytm-mkii/modules/envelopes/tools/dec_table.py new file mode 100644 index 000000000..43edf8c3f --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/tools/dec_table.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only +"""Envelopes' DEC/REL and HLD curves: knob value -> table word for the stock readers. + +DEC/REL (AMP DEC, FILTER DEC and REL; the time to fall 60 dB, shown as the knob text): + 0 instant + 1..25 0.2 ms steps, 0.2 .. 5 ms + 26..45 0.5 ms steps, 5.5 .. 15 ms + 46..55 1 ms steps, 16 .. 25 ms + 56..65 2.5 ms steps, 27.5 .. 50 ms + 66..75 5 ms steps, 55 .. 100 ms + 76..85 10 ms steps, 110 .. 200 ms + 86..89 25 ms steps, 225 .. 300 ms + 90..127 x r a step, to 45 s (AMP 127 stays INF, which the OS never reads) +A word is a 20-bit coefficient (e = c[19:16], m = c[15:0]) of a one-pole segment: per tick +(2 samples) the level keeps p = 1 - step / 2^31 of its distance, step = ((0x7FFFFFFF - (m << 14)) +>> e) - 32768, as stock's tables (0x401ee61c, 0x401ef030). The AMP table is built for the unit's +VCA, which decays at 0.918x the OS model (EV06); the filter runs at the model's speed (EV13). + +HLD (AMP hold, 0 = no hold, 127 = AUTO): ticks of 2 samples, whole blocks of 16 ticks (0.667 ms), +as the OS counts the hold: + 1..15 1 block, 0.67 .. 10 ms + 16..21 2 blocks, 11.3 .. 18 ms + 22..31 5 blocks, 21.3 .. 51.3 ms + 32..42 10 blocks, 58 .. 124.7 ms (42 is the FUNC jump's 16th at 120 BPM) + 43..46 10 blocks, 131 .. 151 ms + 47..57 20 blocks, 164 .. 298 ms + 58..126 x r a step, to 15.5 s + +Prints the C tables for src/envelopes.c; --check prints each value back from the table. +""" +import math +import sys + +TICKS_PER_MS = 24.0 +HW_AMP, HW_FLT = 0.918, 1.0 # decay speed against the OS model (EV06, EV13) +DEC_TOP_MS = 45000.0 # stock DEC 127's time to -60 dB +HLD_TOP_MS = 15500.0 # stock HLD 126 +BLOCK = 16 # ticks the hold counter moves a block + + +def dec_ms(): + segs = [(0.2, 5.0), (0.5, 15.0), (1.0, 25.0), (2.5, 50.0), (5.0, 100.0), (10.0, 200.0), (25.0, 300.0)] + t = [0.0] + for step, end in segs: + n = round((end - t[-1]) / step) + base = t[-1] + for i in range(1, n + 1): + t.append(base + step * i) + k0 = len(t) - 1 + r = (DEC_TOP_MS / t[k0]) ** (1.0 / (127 - k0)) + for k in range(k0 + 1, 128): + t.append(t[k0] * r ** (k - k0)) + assert len(t) == 128 + return t + + +def hld_blocks(): + b = [0] + for step, count in [(1, 15), (2, 6), (5, 10), (10, 11), (10, 4), (20, 11)]: + for _ in range(count): + b.append(b[-1] + step) + k0 = len(b) - 1 + top = HLD_TOP_MS * TICKS_PER_MS / BLOCK + r = (top / b[k0]) ** (1.0 / (126 - k0)) + for k in range(k0 + 1, 127): + b.append(max(b[-1] + 1, round(b[k0] * r ** (k - k0)))) + b.append(b[-1]) # 127 is AUTO: never read + assert len(b) == 128 + return b + + +def encode(ms, hw): + """20-bit coefficient whose one-pole falls 60 dB in ms (the unit's time, at speed hw).""" + if ms <= 0: + return 0 + ticks = ms / hw * TICKS_PER_MS + p = math.exp(-math.log(1000.0) / ticks) + s = int(round((1.0 - p) * 2 ** 31)) + 32768 + n = 32 - s.bit_length() - 1 + m = (0x7FFFFFFF - (s << n)) >> 14 + assert 0 <= n <= 15 and 0 <= m <= 0xFFFF, (ms, s, n, m) + return (n << 16) | m + + +def t60_ms(c, hw): + e, m = (c >> 16) & 15, c & 0xFFFF + s = ((0x7FFFFFFF - (m << 14)) >> e) - 32768 + p = 1.0 - s / 2 ** 31 + return math.log(1000.0) / -math.log(p) / TICKS_PER_MS * hw if 0 < p < 1 else 0.0 + + +def emit(name, words, decl, comment, fmt): + print(comment) + print(f'{decl} {name}[128] __attribute__((aligned(4))) = {{') + for i in range(0, 128, 8): + print(' ' + ', '.join(fmt(w) for w in words[i:i + 8]) + ',') + print('};') + print() + + +def main(): + t = dec_ms() + amp = [encode(x, HW_AMP) for x in t] + flt = [encode(x, HW_FLT) for x in t] + hold = [b * BLOCK for b in hld_blocks()] + if '--check' in sys.argv: + for k in range(128): + ga, gf = t60_ms(amp[k], HW_AMP), t60_ms(flt[k], HW_FLT) + ea = 0 if t[k] == 0 else (ga - t[k]) / t[k] * 100 + ef = 0 if t[k] == 0 else (gf - t[k]) / t[k] * 100 + print(f'{k:3d} DEC want {t[k]:9.2f} ms amp {amp[k]:05x} {ga:9.2f} ({ea:+.2f} %) ' + f'flt {flt[k]:05x} {gf:9.2f} ({ef:+.2f} %) HLD {hold[k] / TICKS_PER_MS:8.2f} ms') + return + print('// Generated by tools/dec_table.py.') + emit('envelopes_amp_dec', amp, 'const uint32_t', + '// AMP DEC knob -> one-pole coefficient (time to -60 dB, for the VCA at 0.918x), read by stock\n' + '// through the lea at 0x40109bee.', lambda w: f'0x{w:05x}') + emit('envelopes_flt_dec', flt, 'const uint32_t', + '// FILTER DEC and REL knob -> coefficient (the filter runs at the OS model\'s speed), read by\n' + '// stock through the leas at 0x4010d342, 0x4010d3b2 and 0x4010d3da.', lambda w: f'0x{w:05x}') + emit('envelopes_hold', hold, 'const int32_t', + '// AMP HLD knob -> hold in ticks of 2 samples, whole blocks of 16, read by stock through the lea\n' + '// at 0x40109bc2 and by envelopes_voice. 0 is no hold and 127 AUTO (not read).', lambda w: f'{w}') + + +if __name__ == '__main__': + main() diff --git a/sdk/analog-rytm-mkii/modules/envelopes/upstream/README.md b/sdk/analog-rytm-mkii/modules/envelopes/upstream/README.md new file mode 100644 index 000000000..1a6f4088d --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/upstream/README.md @@ -0,0 +1,54 @@ +# env-reset-amp + +Port of rytm-mods-src `mods/0015-env-reset-amp` (MrScruff; hardware-verified there). + +SOUND menu (FUNC + MUTE) > SOUND SETTINGS > ENV RESET now steps OFF, AMP, FILTER, AMP+FILT. With AMP +or AMP+FILT the amp envelope restarts from silence on every trig instead of continuing from its +current level, so AMP ATK is heard on every hit. A trig on a voice that is still sounding drops it +to silence at once, which can click (most with ATK 0 and a long DEC). The setting is the sound's, +saved with it. + +## How it hooks + +Three sites, as rytm-mods' registry: + +| addr | stock | new | why | +|---|---|---|---| +| 0x400bcf1e | `7402` moveq #2,%d2 | `7403` moveq #3,%d2 | ENV RESET's setter masked the amp bit off | +| 0x400ef86a | `d683` add.l %d3,%d3 | `4e71` nop | the menu stepped by two (OFF <-> FILTER) | +| 0x40109b04 | `0080b0000000` ori.l #0xb0000000,%d0 | `jmp env_reset_amp_attack` | the trig's amp attack command | + +The stub re-emits the `ori.l`, looks up the voice's track and its ENV RESET byte (0x8000ea30 + track), +and with bit 0 set sends stock's decay form at DEC 0 (rate 0xB0100000, level 0x80) instead; the hold +states that follow ramp up from silence at the ATK rate. It resumes at 0x40109b0a. It runs in the +voice-command routine (0x401098d4). + +## Changes from rytm-mods + +- The shipping code is unchanged. The label `amp_attack` is renamed `env_reset_amp_attack` (global + labels carry the mod id) and is the only `.globl`. +- The `bit_probe` diagnostic is not ported: it needs a fourth patch (0x40109aae) only that build + carries. The source sets `P_BIT_PROBE` to 0, so the probe's code is not assembled. +- It runs from the elemod DDR area instead of cave13 (0x400298e4). + +## Test (on a unit) + +1. Pick an analog BD sound, AMP ATK about 40, DEC long (100+). +2. Stock ENV RESET (OFF or FILTER): hit the pad quickly several times; the attack is heard on the + first hit only. +3. Set ENV RESET to AMP: every hit now fades in at the ATK rate. +4. ENV RESET steps OFF / AMP / FILTER / AMP+FILT with the arrows. + +## Results so far + +- Hardware: on an Analog Rytm MKII, 2026-10-13, in a build of core-ar2 with filter-hz, ctrl-all, + env-reset-amp and slice-loop: works as described (ENV RESET values and the + amp restart). +- `.run` 52 B (50 B of code), 3 sites, no relocations; lint OK; links with core-ar2 0.1. +- The 50 B of code are byte-identical to the stub in rytm-mods-src's default build (cave13, + 0x400298e4); the two byte sites match that build byte for byte; the probe's patch site is stock in + both. +- rytm-emu, the four-mod build above: ENV RESET steps FILTER -> AMP -> OFF and OFF -> AMP -> FILTER -> AMP+FILT + (stock: FILTER <-> OFF only); with AMP chosen, BD's ENV RESET byte in the engine reads 01 (stock + 00). Three BD pad hits reach the attack site and resume at 0x40109b0a on both builds. The + emulator's voice model is not used to judge the sound: that needs the unit. diff --git a/src/community/module-changelogs/analog-rytm-mkii-envelopes.json b/src/community/module-changelogs/analog-rytm-mkii-envelopes.json new file mode 100644 index 000000000..995158dfd --- /dev/null +++ b/src/community/module-changelogs/analog-rytm-mkii-envelopes.json @@ -0,0 +1,13 @@ +[ + { + "version": "0.1.0-experimental", + "date": "2026-11-07", + "changes": [ + "First release, for Analog Rytm MKII OS 1.74: the AMP envelope reworked, and every envelope knob shows its time.", + "AMP HLD runs from no hold (0) to AUTO (127) and never cuts the attack; FUNC + turn jumps 0, 125 ms, AUTO.", + "ATK, AMP DEC and FILTER DEC/REL step 0.2 ms up to 5 ms, then finer than stock up to 300 ms; HLD steps 0.67 ms.", + "SOUND SETTINGS > ENV RESET gains AMP: sequenced trigs and retrig rolls restart from silence (Env Reset Amp).", + "Saved projects play their HLD, ATK, DEC and REL on the new curves." + ] + } +] From 26dd68102e014409ee7a4410c5854e8d564ef028 Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Fri, 6 Nov 2026 23:05:42 -0600 Subject: [PATCH 02/11] Improved Envelopes: source-only OS 1.74 package for 0.1.0-experimental Compiled from a0aaa13f in the pinned toolchain (build-elemod-isolated, image 39efd52a), exported with package-elemod-recipe.mjs; --check reproduces it. Co-Authored-By: Claude Opus 5.5 --- sdk/imports/envelopes-2026-11-07.json | 20 + ...envelopes-0.1.0-experimental-os1.74.elemod | 615 ++++++++++++++++++ 2 files changed, 635 insertions(+) create mode 100644 sdk/imports/envelopes-2026-11-07.json create mode 100644 sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod diff --git a/sdk/imports/envelopes-2026-11-07.json b/sdk/imports/envelopes-2026-11-07.json new file mode 100644 index 000000000..144675ed8 --- /dev/null +++ b/sdk/imports/envelopes-2026-11-07.json @@ -0,0 +1,20 @@ +{ + "schemaVersion": 1, + "module": "analog-rytm-mkii/envelopes", + "version": "0.1.0-experimental", + "date": "2026-11-07", + "changes": [ + "First release. The AMP envelope reworked: AMP HLD runs from no hold (0) to AUTO (127) without cutting the attack; ATK, AMP DEC, FILTER DEC and REL and AMP HLD get fine steps at short times (0.2 ms to 5 ms); every envelope knob shows its time; FUNC + turn on HLD steps 0, 124.7 ms, AUTO; SOUND SETTINGS > ENV RESET gains AMP (Env Reset Amp, with a pre-fade)." + ], + "runtimeSourceSha256": "ae0914c144b265c64fec3da6d9ff94832b84fd7de74c582c02b5765499415618", + "packages": [ + { + "os": "1.74", + "path": "sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod", + "sha256": "f9779b13edaf0d838b3539cc6bf7a4ae16a66b1e918ccac9f3cf82c6ab7f328c" + } + ], + "stockPolicy": "No firmware or stock-derived code/tables are present. Addresses, lengths and SHA-256 guards are metadata; exported instructions and sections are authored module code. Local materialized recipes and firmware are never committed.", + "evidence": "sdk/analog-rytm-mkii/modules/envelopes/TESTING.md", + "requires": [] +} diff --git a/sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod b/sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod new file mode 100644 index 000000000..1ae7ceaca --- /dev/null +++ b/sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod @@ -0,0 +1,615 @@ +{ + "elemod": 2, + "id": "envelopes", + "version": "0.1.0-experimental", + "title": "Improved Envelopes", + "description": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", + "category": "machines", + "author": "npp1993", + "license": "GPL-2.0-only", + "target": { + "device": "analog-rytm-mk2", + "product": "Analog Rytm MKII", + "os": "1.74", + "syx_sha256": "cb0f99d620edde994fb860c0e79cc2464e427d06882828cfdfb00fc53700e123", + "section3_sha256": "34cd0c4da8e4b810d1b25284475a99ea53821e2ab7d30a978bf15dc578251f3b", + "section3_len": 3005432 + }, + "sections": { + ".run": { + "align": 4, + "len": 5808, + "parts": [ + [ + "hex", + "4a83663822398000ea3082b98000ea3482b98000ea38028101010101660842b90000000060164feffff048d703034eb9000000004cd703034fef0010223900000000070167384a926b3441f94029113873b0380041f98000e5087801b8b01c00671c203c3006a7ec22390000000007016706203cb006a7ec243c000000802239000000000701671241f900000000b0b03c006606b4b03c2067284feffff048d703032f022f002f0c2f0a2f034eb9000000002f4000144fef00144cd703034fef0010274000ac274000ec4ef940109c2c202f001c0c8000007f006d0642af001c600a4a806e0670012f40001c4ef940038bce00004fefffd048d77cfc22798000fe544ab98000ed9c670001a220398000ed9c46800880000c7df98000fc90283940287ffc7a16267c42ad66384283287c8000fd509dce4c045800247c42adf5d0207c42ac6b488c80702c4c004800070666262a43dbfc8000ea30101508000000671620087201e5882a40dbfc37fab290b295673c4a906674528341e80038588a49ec000c740c47eb1a0cb48366c0203900000000220e4680c28023c10000000023ce000000004cd77cfc4fef00304e754a9366c0201490896bbab0856cb62a7c4025a3a0700173b5380041e800385283588a49ec000c740ce3a8220e47eb1a0c82802c41b4836600ff6660a22a7c3d53081c74102e12dbca201522280024b4816500ff7690890c80fffea0706d00ff6ab0846c00ff647401e3aa2a4372ff2f48002c260253872407d4824a876f560682402909b8204275d0d482c4834a82670c4a816c4ab0856c0000a42200068000015f90b0846dce206f002c260d4a816d00ff18b2856d00ff58528341e80038588a49ec000c740c47eb1a0cb4836600fed06000ff0c2e3c000003c04a816db6908120006a025280206f002c260de280b2806c00fed6b2856cc06000ff1420398000ed987a167df98000fc90283940287ffc267c42ad6638287c8000fd504283247c42adf5d09dce8c804c045800702c4c004800207c42ac6b486000fe64206f002c260d588a528341e80038740c49ec000c47eb1a0cb4836600fe466000fe820000598f2f03701c2f027602222f00142401e0aa70f7206f0010c082b680670000b84a806700009c44c266000106202f0018e088710048404240224020802401760ee7aa7614712f001b484042402f4200082401e6a942030282000fffff214000041143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff80002141000824009489b3c0672222424a826d7c222800084a28000c663ee6896778b3c1630893c14a826d7690892080241f261f588f4e754a28000d66f220280004240022509489b3c066c260e270011140000d241f261f588f4e750c8107ffffff62caec89263c0000045c4c031800760fe6a952810c810001000064b02609e08b4c031800e08993c14a826c9e60122202448122416000ff7c7201b3c16286608cd0892080608822507609b6826600ff042401760ee7aa7614202800042f4200082401e6a942030282000fffff1143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff8000214100086000ff082f02202f000c2200e0814aaf00106f1a4a816d267429b4816c30747eb4816c200280ffffff00241f4e75747fb4816d10742ab4816d144a816fe6241f42804e75241f203c00007f004e75241f203c00002a004e754fefffe448d7401c222f0024780a2401260f4c4420004c4420024def001206830000001c204e43e8000106800000003010807009b08164262202b68967202401780a4c4420004c442002204943e8000106800000003010807009b08165da7001908e226f0020d08841f6080012e0bdc866fa4cd7401cd0af00204fef001c4e75226f0008206f0004101910c066fa4e75518f2f02202f0014206f00100c8002625a006306203c02625a00720a74174c00180006810000000cb481645c0c81000012bf630000a8220006810000000c0c810000bb7f630000de22000681000004b00c8100249eff6346068000002ee0243c00005dc04c4200002f002f084ebaff02508f223c000000002f4100142f400010241f508f6000ff6a203c000000002f4000142f480010241f508f6000ff54243c000009604c42100143fafec6700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c00000000609c74184c42100143fafe8c700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c000000002f4100142f400010241f508f6000fece74184c4210012f012f084ebafe40508f223c000000002f4100142f400010241f508f6000fea84fefffec48d7007c242f00182202d2816afcd48242414841307c001e4284700f04c291c2340176017c0fe1ab5380c4c12202eca94a826c08220242414841888374ffb48066de200848404240d0844cd7007c4fef00144e752f02740e222f00082001e5a8740f4241484102803fffc0002040203c7fffffff9088e2a822000681ffff8000b48164560c8101ffffff632c0c817ffeffff6250203c7fffffff90812f004ebaff5c721f4841588f9280203c0009f73e4c410000241f4e757412e888e4a93401c4c122000681fffff800203c37431533d2824c410000241f4e75241f203c7fffffff4e75241f42804e752f02740e202f000c2200e5a94240484002813fffc0002041720fc081223c7fffffff9288e0a90681ffff80004a816712202f00087417e5a84c410000241f52804e75241f203c7fffffff4e75518f2f0a727f2f02206f001420280008e0802240b2806c30327c007f2228000474080681ffffffceb4816532323b1a0848c14efb180200f2003200280032002800280120006600904a806cd02228000493c90681ffffffce7408b48164ce241f4280245f508f4e7545f90000000020329c000280000fffff2f002f48000c4ebafe9e206f000c2e802f28000c4ebafcee508f7001241f245f508f4e752228000c747eb4806d00013c4a806f00011241f90000000020309c002f002f014ebafcbe508f700160ce2068000c727e2f48000cb2806d0000fa41f90000000024309c000282000fffff2f02740a4ebafe32588f2200e4a90280000003ff243c000003ac4c021800740ac0fc03ac068000000200e4a82040487018002f2f00104ebafc5e508f70016000ff6e45f9000000002f329c004878007f2f4800104ebafe78588f206f000c2e802f28000c4ebafc30508f70016000ff4045f900000000740c71f29a002200e4a8e989740a4840424073c180812f00487800ff2f4800104ebafe36508f2200e4a90280000003ff243c000003d44c021800740ac0fc03d4068000000200e4a8224048711800206f000c2f28000c4ebafbc8508f70016000fed842802f002f014ebafbb6508f6000fef64879000000002f084ebafb94508f70016000feb44879000000002f014ebafb80508f70016000fea04fefffc8700748d7041cc0af003c206f00447401262f004c73280002e1aa2f41001e3200c2fc000e0681000000000c834000007f67000158760e4c00380043f900000000283138002f440022787fb8af004c6700008a41f1380028280008246800042f4400261828000c2f4a001a45e800041f4400321828000d1f4400332f2f004c2f2f004c2f4a00262808508445e8000c41e8000d2f4a00362f48003c2f4400322f012f40001e2f4900224ebaf86c4fef000c226f0016222f0022202f0012b2b13800670001184682c5b900000000202f00484cd7041c4fef00384e75282f004871100284fff0000020444a806d00018a43f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6700018c226f0040760220515388b688650001864aaf001e6f00019a282f001e41f90000000022704c00246f0040206a000441e8fff1b3c86c0001a0262f00220c83007e7fff6f000192307c00034878007f2f00226f004822882f012f40001e4ebaf7a24fef000c202f00124682c5b9000000006000ff48262f004871100283fff0000020434a806d0000a243f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e670000a4307c00022f3c4000007f2f00226f004822886092222f001a246f001eb2926600fede226f0026206f002ab3d06600fed0246f002e73af00327792b6816600fec0206f003473af00337790b2836600feb0222f0048262f004c41f90000000021810c1021830c3085b90000000020014cd7041c4fef00384e75428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600ff60307c00012f3c4000007f6000ff5c428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600fe78206f00407602b69067224878007f2f002f012f40001e4ebaf65e4fef000c202f00126000feba93c96000fe724878007f76012f0020832f012f40001e4ebaf6384fef000c202f00126000fe94307c00024878007f6000fe6e203c00000000b0b9419a5b8c6718203c400fe58423c0419a5b88203c0000000023c0419a5b8c4e750000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000000000320000003a00000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000011000000130000001500000017000000190000001b00000020000000250000002a0000002f00000034000000390000003e00000043000000480000004d00000057000000610000006b000000750000007f00000089000000930000009d000000a7000000b1000000bb000000c5000000cf000000d9000000e3000000f70000010b0000011f00000133000001470000015b0000016f0000018300000197000001ab000001bf000001d9000001f5000002130000023200000253000002760000029b000002c3000002ec000003190000034700000379000003ad000003e50000041f0000045d0000049f000004e50000052f0000057d000005d00000062800000685000006e70000074f000007bd00000832000008ae00000931000009bb00000a4e00000aea00000b8e00000c3d00000cf500000db900000e8800000f630000104b0000114100001246000013590000147d000015b2000016fa00001855000019c400001b4800001ce400001e98000020660000224e0000245400002678000028bd00002b2300002dae0000305f000033390000363e0000397100003cd300004069000044350000483a00004c7c000050fe000055c400005ad200005ad2000000000000079680000f951000179ce0001ca900001ffe000024b38000283620002aeca0002d1540002ed76000309a300033108000352b300036fcf0003893900039f9b0003b3770003c5350003d5270003e38f0003f0a40003fc9300040f01000423180004359f00045e330004802d00049d0b0004b5de0004cb730004de620004ef200004fe09000516ce00052ee7000544bc0005589c00056ac700057b7300058acd000598fd0005a6220005b25a0005bdbc0005c85e0005dba70005ecb00005fbd9000612da00062b4e0006417300065597000667fe000678df000688680006aa540006c69f0006de950006f322000709eb0007291f000744ab00075d2a00077316000786d40007a8ef0007c55f0007dd710007f215000807f400082747000842eb00085b7f0008717d000885490008a77d0008c3ff0008dc1f0008f0ce00090579000924da0009408b0009592900096f30000983040009ace00009ce5e0009e9c6000a013b000a3f51000a75bc000aa570000acf40000af3e6000b280c000b605d000b91b9000bbcfd000be2e9000c084d000c4291000c75a2000ca265000cc9a1000cec04000d144f000d4924000d7772000da008000dc39b000de2c9000dfe1c000e2c20000e561d000e7ae9000e9b2a000eb76f000ed035000ee5ed000ef8f5000f1349000f3087000f4a27000f609f000f744f000f8591000f94b1000000000000889d000110f20001933b0001dff50002246e00026b3900029fbb0002c8360002e85d0003050800033065000354ef0003742300038f180003a69d0003bb510003cdae0003de140003eccf0003fa1d00040c640004226b000436960004491f00045a3600047fa100049ef30004b98d0004d06c0004e44c0004f5bb00050a4a000525bd00053e57000554840005689b00057ae400058b9b00059af10005a9100005b61c0005c2330005cd6f0005d7e60005e1ad0005f368000606240006220300063af800065172000665cb0006784e00068937000698ba0006a7000006c62b0006e02a0006f62d0007121e000732dc00074f86000768d300077f53000793760007a5970007c4eb0007df080007f523000810300008310d00084dd00008673200087dc3000891f50008a4220008c38a0008ddb70008f3de00090db900092ea500094b74000964e100097b7b00098fb40009a1e80009c8570009e716000a0080000a2a71000a6370000a9566000ac131000ae793000b1272000b4d6e000b8121000bae71000bd629000bf8f9000c2ef9000c6477000c9358000cbc70000ce074000d000b000d3761000d67e1000d9263000db7a5000dd84d000df4ec000e1c05000e47ff000e6e8a000e9052000eaded000ec7e1000ede9f000ef28f000f0811000f26b1000f4189000f5911000f6daf000f7fc3000f8f9b000f9d7d000000000002f499000427510004d0970005412800059e5b0005db6000060cd900064cd800067e490006a5a00006c5ad0006e04a0006f6be000713e1000735150007521400076ba00007824c0007968e0007a8c40007b93a0007c82d0007d5d00007e24e0007edca00080da20008374900085a7d000878a2000892bc0008a98f0008bdaf0008cf900008df8c0008edee0008faf000090d8500092319000936de0009490e000959d60009695f000977cc00098538000991bf0009b1e20009cf290009e9d6000a044a000a3095000a58f2000a7dba000a9f3e000abdc9000ad99f000af2fc000b1435000b3e58000b64bf000b87be000ba7a4000bc4b6000bdf36000bf75c000c1abe000c42dd000c676f000c88c4000ca725000cc2d6000cdc13000cf315000d101a000d3653000d592a000d78ec000d95de000db040000dc84d000dde38000df233000e08d4000e2a07000e484a000e63df000e7d04000e93ef000ea8d2000ebbdd000ecd38000edd0a000eeb75000ef89a000f092b000f1f03000f32eb000f4511000f559b000f64af000f726d000f7ef5000f8a5f000f94c9000f9e45000fa6eb000faecd000fb5fb000fbc89000fc281000fc7f1000fcce7000fd16d000fd58b000fd94d000fdcb9000fdfd9000fe2b1000fe549000fe7a7000fe9cd000febc5000fed8f000fef31000ff0ad000ff209000ff345000ff4650000203f33c33dd8453d4ad04e76521555ea58e05b3c5d285ec06032627f647d663a67c3691f6a566b6d6c6a6d506e216ee16f92722474a476c178907a217b807cb57dc87ebd7f9a80c58230837c84ab85c386c587b4889189608a208c0e8dd08f6a91bf946896d499099b0d9ce29e8ea028a2eea576a7c4a9deabc9ad87af1fb124b3c9b631b863ba64bc37bde0bf64c18cc411c65cc874ca5ccc19cdafcf20d0e3d349d579d777d948daf0dc73ddd3df14e072e288e46ee629e7bde92eea7debafecc6edc5eeacef80f081f1e0f320f443f54df640f71cf7e6f89df945f9ddfa68fae7fb5afbc4fc24fc7bfccbfd13fd56fd92fdc9fdfbfe29fe53fe79fe9b30006d730073004155544f00494e4600" + ] + ] + }, + ".bss": { + "align": 16, + "size": 80 + } + }, + "symbols": { + "VOICE_TRACK": [ + "abs", + 1076433208 + ], + "WRITE_RESUME": [ + "abs", + 1074830380 + ], + "TRIG": [ + "abs", + 2147542280 + ], + "FADE_START": [ + "abs", + 2953226220 + ], + "FADE_GO_ON": [ + "abs", + 805742572 + ], + "FADE_LEVEL": [ + "abs", + 128 + ], + "ENV_RESET": [ + "abs", + 2147543600 + ], + "AMP_PICTURE": [ + "abs", + 1073974222 + ], + "follow": [ + ".run", + 784 + ], + "hold_jump": [ + ".run", + 1176 + ], + "put_uint": [ + ".run", + 1260 + ], + "put_text": [ + ".run", + 1388 + ], + "put_time": [ + ".run", + 1404 + ], + "log2_q16": [ + ".run", + 1734 + ], + "t60_ticks": [ + ".run", + 1822 + ], + "linear_ticks": [ + ".run", + 1972 + ], + "envelopes_text": [ + ".run", + 2048 + ], + "atk_rate": [ + ".run", + 5536 + ], + "amps": [ + ".run", + 3356 + ], + "envelopes_amp_graph": [ + ".run", + 208 + ], + "envelopes_flt_dec": [ + ".run", + 4000 + ], + "envelopes_flt_atk": [ + ".run", + 5024 + ], + "envelopes_gate": [ + ".bss", + 0 + ], + "envelopes_voice": [ + ".run", + 2550 + ], + "envelopes_amp_dec": [ + ".run", + 4512 + ], + "envelopes_write": [ + ".run", + 0 + ], + "envelopes_hold": [ + ".run", + 3488 + ], + "envelopes_params": [ + ".run", + 3468 + ], + "envelopes_tick": [ + ".run", + 3314 + ], + "envelopes_scan": [ + ".run", + 244 + ] + }, + "exports": [ + "envelopes_amp_dec", + "envelopes_amp_graph", + "envelopes_flt_atk", + "envelopes_flt_dec", + "envelopes_gate", + "envelopes_hold", + "envelopes_params", + "envelopes_scan", + "envelopes_tick", + "envelopes_voice", + "envelopes_write" + ], + "imports": [], + "weak": [], + "relocs": [ + [ + ".run", + 32, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 48, + "abs32", + "sec:.run", + 244 + ], + [ + ".run", + 62, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 106, + "abs32", + "sec:.bss", + 4 + ], + [ + ".run", + 128, + "abs32", + "sec:.bss", + 8 + ], + [ + ".run", + 138, + "abs32", + "sec:.bss", + 16 + ], + [ + ".run", + 174, + "abs32", + "sec:.run", + 2550 + ], + [ + ".run", + 400, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 412, + "abs32", + "sec:.bss", + 4 + ], + [ + ".run", + 418, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 1520, + "abs32", + "sec:.run", + 5797 + ], + [ + ".run", + 1542, + "abs32", + "sec:.run", + 5792 + ], + [ + ".run", + 1618, + "abs32", + "sec:.run", + 5797 + ], + [ + ".run", + 1676, + "abs32", + "sec:.run", + 5794 + ], + [ + ".run", + 1714, + "abs32", + "sec:.run", + 5794 + ], + [ + ".run", + 2154, + "abs32", + "sec:.run", + 4000 + ], + [ + ".run", + 2224, + "abs32", + "sec:.run", + 3488 + ], + [ + ".run", + 2264, + "abs32", + "sec:.run", + 4512 + ], + [ + ".run", + 2346, + "abs32", + "sec:.run", + 5024 + ], + [ + ".run", + 2392, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 2512, + "abs32", + "sec:.run", + 5804 + ], + [ + ".run", + 2532, + "abs32", + "sec:.run", + 5799 + ], + [ + ".run", + 2592, + "abs32", + "sec:.run", + 3356 + ], + [ + ".run", + 2614, + "abs32", + "sec:.run", + 3356 + ], + [ + ".run", + 2754, + "abs32", + "sec:.bss", + 8 + ], + [ + ".run", + 2794, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 2862, + "abs32", + "sec:.run", + 3488 + ], + [ + ".run", + 2940, + "abs32", + "sec:.bss", + 8 + ], + [ + ".run", + 2970, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 3098, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 3112, + "abs32", + "sec:.bss", + 8 + ], + [ + ".run", + 3132, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 3188, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 3316, + "abs32", + "sec:.run", + 1176 + ], + [ + ".run", + 3342, + "abs32", + "sec:.run", + 1176 + ], + [ + ".run", + 3484, + "abs32", + "sec:.run", + 2048 + ] + ], + "sites": [ + { + "addr": "0x400bcf8a", + "len": 2, + "stock_sha256": "0b358362552792220751c58c4cca9c4e54407d2339649a0b96182880f0504c1a", + "new": "7403", + "kind": "code", + "relocs": [] + }, + { + "addr": "0x400ef8d6", + "len": 2, + "stock_sha256": "4e4b41344512feecd49483d4a3f357ebd5b45f53276f21411a66cb3b4d597c16", + "new": "4e71", + "kind": "code", + "relocs": [] + }, + { + "addr": "0x40109c24", + "len": 8, + "stock_sha256": "3df81daa6f0b5b044b3c5bbf7c45a8d96b97caa686b60bf262eeda8b7dc87dc5", + "new": "4ef9000000004e71", + "kind": "code", + "relocs": [ + [ + 2, + "abs32", + "sym:envelopes_write", + 0 + ] + ] + }, + { + "addr": "0x400d3302", + "len": 6, + "stock_sha256": "704bb7e62b7dc84ac22bb9ec1242ae79e917ce47a7b6a4aa06ec60b72654b2c0", + "new": "4eb900000000", + "kind": "code", + "relocs": [ + [ + 2, + "abs32", + "sym:envelopes_amp_graph", + 0 + ] + ] + }, + { + "addr": "0x4010d2aa", + "len": 4, + "stock_sha256": "bb101f17b7e23130f5e92c2f8e616cf858c9db923af32f0756f4cd9af27591d0", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_flt_atk", + 0 + ] + ] + }, + { + "addr": "0x40109bc4", + "len": 4, + "stock_sha256": "a93a6f0c7e9387b5bf90a027d5678b11c90d555082736705d44faca3b73d46b6", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_hold", + 0 + ] + ] + }, + { + "addr": "0x40109bf0", + "len": 4, + "stock_sha256": "8879f37f45bb49679a30176c392dc823a5215ba1fdbecc9406684fec9adbc2aa", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_amp_dec", + 0 + ] + ] + }, + { + "addr": "0x4010d344", + "len": 4, + "stock_sha256": "e752dd02ad509e30bf4eab19cb5a7ef8760906dfdfa6d410e8a42e3635a2ef39", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_flt_dec", + 0 + ] + ] + }, + { + "addr": "0x4010d3b4", + "len": 4, + "stock_sha256": "e752dd02ad509e30bf4eab19cb5a7ef8760906dfdfa6d410e8a42e3635a2ef39", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_flt_dec", + 0 + ] + ] + }, + { + "addr": "0x4010d3dc", + "len": 4, + "stock_sha256": "e752dd02ad509e30bf4eab19cb5a7ef8760906dfdfa6d410e8a42e3635a2ef39", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_flt_dec", + 0 + ] + ] + } + ], + "collections": {}, + "contribute": [ + { + "to": "ev_tick", + "order": 50, + "data": "00000000", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_tick", + 0 + ] + ], + "claims": [] + }, + { + "to": "core_params", + "order": 50, + "data": "00000000", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_params", + 0 + ] + ], + "claims": [] + } + ], + "copied": [], + "resources": { + "regions": [], + "names": [ + "ui:SOUND SETTINGS ENV RESET values", + "ui:FUNC + turn of AMP HLD", + "ui:value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL", + "ui:AMP page envelope picture HLD", + "audio:amp envelope record write", + "audio:filter attack rate table", + "audio:amp hold table", + "audio:amp decay table", + "audio:filter decay and release table" + ], + "core": "0.3" + }, + "requires": [ + "core" + ], + "conflicts": [], + "signature": null +} From e946d7e62706fabb6aac78bc72b494dc7f826fa9 Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Fri, 6 Nov 2026 23:13:26 -0600 Subject: [PATCH 03/11] Improved Envelopes: library README sections, tutorial and rytm-emu captures Co-Authored-By: Claude Opus 5.5 --- .../modules/envelopes/README.md | 71 +++++++++++++++--- .../modules/envelopes/media/capture.json | 31 ++++++++ .../modules/envelopes/media/decay-time.png | Bin 0 -> 11444 bytes .../modules/envelopes/media/hold-time.png | Bin 0 -> 11616 bytes .../modules/envelopes/modwerk.module.json | 61 +++++++++++++-- 5 files changed, 147 insertions(+), 16 deletions(-) create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/media/capture.json create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/media/decay-time.png create mode 100644 sdk/analog-rytm-mkii/modules/envelopes/media/hold-time.png diff --git a/sdk/analog-rytm-mkii/modules/envelopes/README.md b/sdk/analog-rytm-mkii/modules/envelopes/README.md index 1e6fcd46c..609859e4a 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/README.md +++ b/sdk/analog-rytm-mkii/modules/envelopes/README.md @@ -1,12 +1,13 @@ # Improved Envelopes -Module for the Analog Rytm MKII, OS 1.74. It reworks the AMP envelope and shows times on the -envelope knobs. It carries Env Reset Amp (ENV RESET AMP, with a pre-fade added) on, so a set takes this module instead. +## Overview -Credits: Nathaniel Pavel (@npp1993) for Envelopes and the pre-fade; MrScruff for ENV RESET AMP (rytm-mods -0015-env-reset-amp); Iced-Cream for its elemod port and Modwerk module; irpina for Elekloader and core-ar2. +Module for the Analog Rytm MKII, OS 1.74. It reworks the AMP envelope and shows times on every +envelope knob: AMP HLD runs from no hold to AUTO without cutting the attack, ATK, DEC, REL and HLD get +fine steps at short times (0.2 ms up to 5 ms), and SOUND SETTINGS > ENV RESET gains AMP. It carries +Iced-Cream's Env Reset Amp (ENV RESET AMP, from MrScruff's rytm-mods) on, with a pre-fade added. -## What changes +## Controls | Control | Stock | With Envelopes | |---|---|---| @@ -18,12 +19,18 @@ Credits: Nathaniel Pavel (@npp1993) for Envelopes and the pre-fade; MrScruff for | AMP ATK, HLD, DEC, FILTER ATK, DEC, REL | 0..127 | times: an attack's full ramp, a hold's length, a decay's or release's time to -60 dB; AMP DEC 127 = INF | | SOUND SETTINGS > ENV RESET | OFF, FILTER | OFF, AMP, FILTER, AMP+FILT (Env Reset Amp). AMP fades the amp envelope to silence just before sequenced trigs and retrig rolls (a held pad's RTRG roll too), so they restart from silence; a pad or MIDI hit itself, and the first trig after PLAY, continue from the current level, as stock | -Saved values keep their bytes and are read the new way: a project made on stock plays HLD 0 as no hold -(was AUTO) and HLD 127 as AUTO (was 16 s), HLD 1..126, DEC and REL on the new curves (the same byte is a different time, mostly shorter at the low end), and AMP and FILTER ATK on the new curve. MIDI CC 79 (HLD) and the ATK CC -follow the knob. There is no migration. +## Usage -The ramps stay as stock makes them: the attack is a straight line in amplitude, decay and release are -exponential (straight lines in dB). A choke or stop still fades over stock's fixed ~43 ms. +Shape short, clicky transients and tight holds by ear and by number: every envelope knob reads its +time, and the short end has the resolution drums need. + +### Quick tutorial + +1. Press AMP. Turn DEC down: the knob shows its time to -60 dB, in 0.2 ms steps below 5 ms. +2. Turn HLD to 0: the decay starts as soon as the attack peaks. Turn it up for a hold in ms, or to the top for AUTO (decay from note-off). +3. Hold FUNC and turn HLD: it jumps between 0, 125 ms and AUTO. +4. On the FILTER page, ATK, DEC and REL show their times on the same fine curves. +5. In SOUND SETTINGS, set ENV RESET to AMP: sequenced trigs and retrig rolls restart the amp envelope from silence. ## How it works @@ -54,7 +61,27 @@ exponential (straight lines in dB). A choke or stop still fades over stock's fix - Times on the knobs come from core-ar2's `core_params` text for ids 50..58; HLD's FUNC jump is its parameter record's jump function (id 57, +0x4c/+0x50). -## Limits +## Changes to stock flows + +| Change | For whom | Why | Neighbouring flows | +| --- | --- | --- | --- | +| AMP HLD 0 is no hold and 127 is AUTO (stock: 0 is AUTO, 127 is 16 s); HLD, ATK, DEC and REL follow new curves. | Anyone with the module installed, including projects made on stock. | A hold that starts at zero and grows with the knob, and resolution at the short end, need the knob's values to mean new times. | Saved sounds and projects play their stored bytes on the new curves (no migration); MIDI CC follows the knob. | +| FUNC + turn on HLD steps 0, 124.7 ms, AUTO (stock: jumps to AUTO). | Anyone who uses the FUNC jump on HLD. | Quick access to the three most used holds. | Other knobs' FUNC jumps are unchanged. | +| ENV RESET gains AMP and AMP+FILT. | Anyone who picks them; OFF and FILTER behave as stock. | Env Reset Amp's feature. | A pad or MIDI hit, and the first trig after PLAY, continue from the current level, as stock. | + +Saved values keep their bytes and are read the new way: a project made on stock plays HLD 0 as no hold +(was AUTO) and HLD 127 as AUTO (was 16 s), HLD 1..126, DEC and REL on the new curves (the same byte is a different time, mostly shorter at the low end), and AMP and FILTER ATK on the new curve. MIDI CC 79 (HLD) and the ATK CC +follow the knob. There is no migration. + +The ramps stay as stock makes them: the attack is a straight line in amplitude, decay and release are +exponential (straight lines in dB). A choke or stop still fades over stock's fixed ~43 ms. + +## Compatibility and limitations + +It patches the amp record write in `amp_env_commands` (0x40109c24) and points stock's envelope table +reads at its own tables (`ptr` sites, listed under How it works), and subscribes to `ev_tick`. Claims: +ENV RESET's values, FUNC + turn on AMP HLD, the value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL, +the AMP page picture and the amp and filter envelope tables. It needs no other module. - AMP ATK and DEC times are calibrated to one Rytm MKII (EV06, 6 Nov 2026): its VCA ran attacks at 0.957x and decays at 0.918x the OS's timing model, so the ATK table is built for 0.957 and the @@ -68,3 +95,25 @@ exponential (straight lines in dB). A choke or stop still fades over stock's fix 0x40109bf0, not stock's 0x401ee61c: with this module that address points at the new table. - On stock firmware a sound saved here plays the stock way (HLD 0 = AUTO, the old ATK curve). - Unit results: TESTING.md. + +## Tests and measurements + +Measured on the author's Analog Rytm MKII over USB (builds EV04 to ED02, in combined sets of up to 16 +modules), with rytm-emu for the screens ([TESTING.md](TESTING.md)): AMP DEC within 0.7 % of its text +from 5 ms, AMP HLD within 0.1 ms, FILTER ATK within 0.3 %, FILTER DEC and REL 1.5 % (the method's). +Memory: 5,900 bytes of the shared mod area (the base alone leaves 119,004, with this module 113,104). +Load: the amp record write runs every block for every voice; an idle voice makes no C call there. + +## Authorship and licences + +Nathaniel Pavel (@npp1993): Envelopes, the curves, the knob times and ENV RESET AMP's pre-fade. +MrScruff: ENV RESET AMP, rytm-mods 0015-env-reset-amp, its design and code. Iced-Cream: its elemod +port and Modwerk module, which this carries on. irpina: Elekloader and core-ar2. GPL-2.0-only +([LICENSE](LICENSE)). The source names firmware addresses only; no Elektron firmware is included. + +## Screens and audio + +Screenshots are rytm-emu captures of build EN01, this package linked alone on the Modwerk base +([media/capture.json](media/capture.json)). No audio preview. + +![AMP DEC reading 2.2ms](media/decay-time.png) ![AMP HLD reading 4.0ms](media/hold-time.png) diff --git a/sdk/analog-rytm-mkii/modules/envelopes/media/capture.json b/sdk/analog-rytm-mkii/modules/envelopes/media/capture.json new file mode 100644 index 000000000..fdd19fe3f --- /dev/null +++ b/sdk/analog-rytm-mkii/modules/envelopes/media/capture.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "machine": "analog-rytm-mkii", + "moduleId": "envelopes", + "moduleVersion": "0.1.0-experimental", + "firmware": "1.74", + "capturedAt": "2026-11-07T05:10:00Z", + "imageSha256": "b1bccf4d23c6b584ae36f39f2412dddff98c4a206bea83dff6613b313f2ba8bf", + "build": "Modwerk's linker: Modwerk base for core-ar2 0.7 (plain variant ba530f45) + this folder's Improved Envelopes 0.1.0-experimental, materialised against stock OS 1.74, --version EN01", + "emulator": { + "name": "rytm-emu", + "repository": "https://github.com/trigcondition/rytm-emu", + "binary": "dtboot", + "settings": "revision 2ac0f1f; no card (starts formatted); JIT on; --every 1000M; DTBOOT_TURN_PNG after each turn" + }, + "conditions": "Cold boot; eight NO presses from 7003M, 300M apart, close the calibration notices. AMP at 11003M (12M). 64 turns of DEC (encoder 2) by -6, 20M apart from 11303M; then 6 turns of HLD (encoder 1) by +6, 20M apart from 12803M. Frames are dtboot's firmware-rendered 128x64 screen at 3x, unmodified.", + "captures": [ + { + "path": "media/decay-time.png", + "frame": "turn64.png", + "plan": "DTBOOT_TURN_PNG=t3 dtboot Rytm-EN01-os1.74.syx --instr 13400M --every 1000M --press NO@7003M:12M --press NO@7303M:12M --press NO@7603M:12M --press NO@7903M:12M --press NO@8203M:12M --press NO@8503M:12M --press NO@8803M:12M --press NO@9103M:12M --press AMP@11003M:12M --turn 2:-6@11303Mx64/20M --turn 1:6@12803Mx6/20M", + "sha256": "5166a566f68a2dbd427c05469c589464d1691c67e39b671566615fc00d154dc9" + }, + { + "path": "media/hold-time.png", + "frame": "turn70.png", + "plan": "DTBOOT_TURN_PNG=t3 dtboot Rytm-EN01-os1.74.syx --instr 13400M --every 1000M --press NO@7003M:12M --press NO@7303M:12M --press NO@7603M:12M --press NO@7903M:12M --press NO@8203M:12M --press NO@8503M:12M --press NO@8803M:12M --press NO@9103M:12M --press AMP@11003M:12M --turn 2:-6@11303Mx64/20M --turn 1:6@12803Mx6/20M", + "sha256": "869cde2e56143f53fb755ee383d59f1bb0c575d371d0de9d285f372a77b12cd5" + } + ] +} diff --git a/sdk/analog-rytm-mkii/modules/envelopes/media/decay-time.png b/sdk/analog-rytm-mkii/modules/envelopes/media/decay-time.png new file mode 100644 index 0000000000000000000000000000000000000000..2bfc7053569f561d2492489351f517642ecbbe27 GIT binary patch literal 11444 zcmeHNZETh08GZ{g2LvHyOQSg3!a=rWp-V+fEitok_!0Lq zrB^nG?+_x(KY`y38c zs^}k0$T{Ub@AGlr*L8nBPwToht7px)VMY)Hvof_Se-;EKJMs6M-=2ccXI@zF;~@Ca zQ<;@N`T64||9f-lA5y<~<;1Yr@!{^1?;L!zZcEShfn)aHgD)L;df(zO(QpcvjNe-;@6dLK)^W^!LAjhRao)bM*IK$#8Ngi)=@h}NP~C# z>~g{3Spmt}pW$+=NS0Ux04^)3c;@yC-8lDeqmk~o%PH+Y|9S<2 z7t9i?xiTl4SgBYhWP@dHwTglspeXE7l?DrTgc<9vY%K#prXHoaI&wkpV!v1w;0`rx zCgxbB$|}#9zG95GMR2@e4q88{$9<3!l0qkx{u-JrGoY2TFcS3NU~c=&8sx%#T?cHP;TU zf+g&_oP!g?r?&sTFoR7eKUV4#@T zlMF9=kp(0$w^)mj@B)7mRFIKs(_&+ac}*tvMX*B5@uE0US+LMUC>^pn&H>ZVncQ%A zocsq#%Y0s*ap8tL%1^l-Qte?ImKL)z+Bfp&-fm#!l1dDM#&Ov_ll^#aURa zz8&5fyT?METqfFXwZ^0{fomG4!&U|Wr%ouGVZ96X6uWa(q}miDS8Ec`?AyJIVpCWw zU^~J2Lqo}M?R_IBS6F!^obC^~>@PpF#N1xORFya;4s#qwm_# z2Dg_?p)mm#gqI#Wot-k&@D`1oOPfs7$o%$Pcxx{Eyl{vMwTpi@4|(fFi;j@2=JXtM zGXps%G7=fYmNG->vZ28oV6T&v!DAY~a*Wg-i5SsaCULS2$Pj%QysP!O5z&5ux&bF{?;V<0`NQt{>Jg@S1fDKIRA97$Xx;5pW@%@ZlV2^;TTyhDhJVW@0$&uJ z?VDq65PwAiDr&0lbSaI8K7^cAy2L;`d&C%nEC5{hS?Ej?G&HTL=vrn#39ouLsg*)L zGdGi;EpEwQ(;94d^j+?ajw-QvRyownp>UeocsRT0JG_gg1_v6)NlC-=Rif+tHsM6d zSRxK64EQ2_Kb)kwg{Fmk2sYx9N&dR_x1;^rY%I`Zx7wz|W+80=Ueskg2t^1{lnXDy znR9q}!iG1X>uLi23R@nd{n-jnfI(~mC9=;F`sSl?ZihGt*^TZQsUU~?zhYmG$}& zn~g{U9IFU?13g)23+~QYc*SIX?PgLym@4_LPODW+I3pL{z`{`LMIb=7J+g%j0YqG( zb%LfJxE%2$i*n`NXqUvY8b%|j({x(QM7Dirmsuj-LB^^{jSil$1q}9xl+DHK)5VzPC9!yNht4`Gp!|C+8QYmYatoe)-&EO@2=?4;0>o|#M zLRG2>W>_8%Mff@_~(3Qikxj$VWLXH%MinV6_QjvM=M*a`RA;;AOT-R0?I4Q6-SGG>wnHdTt zO|YfcBI&rc2B?#iM3E9gu4_ApHIxlbz0&Vt^ajlzQ^Vn|?a>NkiRQMZk@CAs%^P#j zZIr)S&YVlXoa(t4B3R?au9=@Y1PzJkdyIh5>>~&*qdS;IGduwmb3HwMcr8DXv6|(Q zZeAy!En;A|%V&BENoigZvi**q;o@9a=?z{XE9g31l2u{_B(;Nom(;dw2tCeVui62^ zrC1|VTUkZDkT@3UR@hKzS>@c6E0o2O3LlzMZrQbT+zZUk%NS18^9TijA$Dcv#PLkQ z>XYq@y}3Hu1w8R9mwib42-tyx1u4@caK?%(+E4jrcnkGK;>sWqREfcZ#&+N#_!1 zK_R-zZ65y3mC?*3xOlM2D#aW?PJ>)BO^3>gU7C!nhbBoH&=a)6?v)DCY9Z~f@^+k- zDm`2I3<M{jhs5{OH)L5T<}<8>{VcG*nju9- z_zlD9)HQ%yeWREJ!zIADKp-$(N%;8OJ_Dv;QxWm$x=~4pw1q`S?>)RKHglCk{0vL6 zU`qD!Wu_AO7PzF!V`H-ywsuE@hfjsym+l%4QTbQ-=1#K?-4!!yfG=wHarq%^Ueu3Y zSazk~ECEpXAYGF@kI50r9aM8{lPr4XXM)?1hmdz9WZBR0Z4Y6pLt2$|tL_8w3%=qX5CPNX|o zGHT0PE6bt^i+hyn)P~IeB+JTiGrHb(_XX_$JcgCo*_Ot&geEy622v;VG$j`*?#D>i zr9+B1k8madb0MlgGcZry!-7rFTP;^NVBSp4U5Cj@o&{|1t zlNJ%WLd<(mUCXOjU+Qr-i#(_>1J-vo?b=2_UL!(LD@XXFxvc^xl`t04x(XBc=qY7% z4W={&GU@@b9tNywo1A#UbFwG9n}pEnzJL$~5IXwn!OrB+Lro;Dti+gfL7$V5P2NF% z?g}dq2gnswzFHe=mX3UGQsfK-P_zP3L@H7ijY|q`Ee+(iuiJ70R&tP5L^wEy*bse7 z5YJ!@aj8@dayqQM;^_peOSK-KOqti%$-o;@U(qebG=WW^%b8ec(lLO~M1@f2^-ZOO*;qmjl?{gEEL~}el50`>2*j7}MAAt2JzmhJBBn^cRvwP@q=nYcV zKTb_~3Ry8;4zPVg{)L2mz`jpcfQxP`O^QoOg8E#M@T@tPbHKQwpQ zE+`Mz)Jc9kIKA*PlJ-!bTt&g%1u$}1irbMVa7FCJYghe*n>)kB#w7mcTrD;2e9aw3@Y5ay)UvGZz-Fw21_U-@zgLr$OfN+Zrm!52f<@P{W z!>~5_w3i{bt$3l~bhxPanhsCyaKS57bnJ_5qIy9q9YJ8K2{n12G;idIzi z#DdbEW7RsI#k+FOMop^-M#b1|O~nC@+F$ioPSogl2i#nXQlp7TRScOXe9j(Xk`%4% zsm$@v5h+f<#G!pYcnYqMd23w(JW9?Yc%T69E}dW-E6`JpXi?kNQJ=f8hTAnzI--)( zi=<1=FZqq?BFLbW6H;E&#bVHPFKY{g_n7h*~rA>@CFI=T99*A z$~6GU<1Fc5Bdb@{nHGCjN>{}@>MbBm;*H|E#KwAc246xzIrNDi(Zn;tHz0FP!d&sg zk-^ojJ}K4uq_aD^9WnZ`G+mGFSDqkF)>zUP$4t9v{9a`mT`{^T*iJJ30r?nbMC>>>0>CnHX;v zZJRU|2adJ0p8u#P)qy3Ze%;Q2!E<{TcMoBSX+PT7`oLuS>heA;G0AP6yL)3x-#*sW zb4_sY`87Syt&z{*NMrrR*n`37;iIwitm7vd62U_^1hUtIL89%kokOv7{r+PuXL_-N zEGk()v5P-kCK4PDL`GANMLSQ%x+{(}4kyY@`Dk`^EWK;}ME||z^$nx9&s`^94#~=r zjUvVFUil369V@MtHT4aN!@*R+J1Dir> zD3e@?MJFK3oPAI%l}w2+x7Uqk>v~hKeb_i$^09mg8S1QvCq3e15@E*$V%^EHNvPt(+J%!t*88+OREb<9-%Yt3+_B zir-Q{%PXXA4a9Kjn!W@i@~Ti{cwE(ldmyMfn4Za=+%}D;hVo)`Sd0?7vd4DsPykgW z!s{vip;N2qn_YH!ux~yQsv0+lah)nK{L z_Uv#?cLhRW_5llZZUE`%d4NSDRzr;-fOLp&0EBYT5wK#1L~+;1gmsvPw8j{}h3G-E z$A-eZgz;Rz-6Ko4z1odLM8X6!v6RM4AERTkHjio-pi>x#e&ct_G~iKjg^TIWA9xOy zZA$>Ju94SBQ+ZO87yxhcffHRptelMHwL)(`Y^Gux|4&Ao5x_}-7ombu=7YTGQTA7A zK?JSJlTWUzd3+TF*(gauv51%e%OODViPs?!LCyBHQBI1yKkV)te7E1mir<}pRZc^2 zXp#Z5Yc}vC1p18cn1&qjGY|$obs_jaH|d2_V$m$r(Ua*reqzt3mY6(3qGSiUP%V%s zGzB}V1$pIq6IY4)g%!i#yQh+GicwokSc8N(65cFqGmtaOFTX??-!mZZnOpR4`+Fq0 zXGc)N3@tR3Oj`VL`>UCc_DMc%eE{E@hE(#^P9zwB0pWHEKRMS|lly@%Cz(IhBEL(1 zExq?)pAxVo>ZFb>;e4q^o|Zkz9@<&4BbFPGrAXhhYBJ7P&FqbCXf#@qmE&V6NtW{R zu!=x9%JQebH2u^gQW#LNt*lOvTG#YshF{6tD*olW$Nna(r2;|*Ik`N$)0P29ZX!kyIqXUQ9x^^lcBu=c+SYsKFXy~Ar$$!|XNYPtSJc0C(5yf*KNZ!o# zvY2b41rP_KUjKWdUUHXc6$bKF$zHN#8J7%k$=tidXct^kV37s1$TL*0MARz~r1-7O z+13>&CI4pX9~YLX3Zh0^Fq&=JmP+oPPR@y{yUWcB`3;>5@V4-pME2hi6ZU>yRuWWneBNbwAiU~Z1j?;8^uXKuu&wee64U`62~XNmpGbpZ zW@#de_=Kt!Z{_2lhe+uHWNb)`hb&q1Ag;7!JDmwyNUkn7vn9;38V6f936UUMiQ)Hz zbA(7N&|1%bw_1n*HJ@@$iKy|w*{-~P zkzJ!|mrAp!=tP!aR{};tri78j1$Y9>L|PP9r{HbrID?+d>HI#dfxTWXU`+EC^L;Tk z1az;7v`A@itb2^Ki@lv9ut(ctwm1?aDGRU8Yvj5WEJq^-_-`lMw0fU9b&>tB;N-IMEjQ zz!KM?2S-9LL?bJ6*74~1AUNh0Knuc53eA{hT=A}N{t<9txw0{kgEAhhIwf-dA>;yE zxHdAk5uxX#{L>5}oWi0oJprUl@% z(EhOMx@(oQWWgz=UF}MH#wj)Ia_2i^n752>pinG}pv>k|>4Q;C&j;wbM`> z9D&Xk@r zz>lHC^auvinHZxQEj}Wg>GCQwh7_YM=8lDz`!5Ed6IJ(=o6W~h#NUVwo(s`7{2p~e zX&Mtw`77MgnOl(<-(zmoA0AqG(Ip`KvA;;xFbgFz!nyKk9v6Ed#UcnY8)R%GwS2t< zU-~qY9CiUBlE0EqWKMDHu!L~-Hh!YMuQ-rj9B0nVjw|^vTQ7}}5*WKq{vZ`DO`(kos%4Pi zz`^-bu1xgSK?#w|8PIq*&m(i`+x`d9VN&5kvsjeVL{9v1l{aLOJf_B{7f=x_+9x)F z@Gy$wDwls4mD4^*0mv7!CW8lf7=%HwAjon;OFLuYvU|ZP|kV( zJ3~6~tcbW4RT@eK?BH=0uNcSl-8m>KB6lgm0Cs}oficycV-nG0rl1*SAsl~Hp`arv z2z8~!u>nv;zSdZ|lm=hUk|M)iIJm-?!0vMz3OLL)p{y?dypBV(UsNE+LJS`Z*h@J3 z%UM!PT>nS7Pat1FP|N_~Zrm{?Q#e|6>{OUOJ~L+^6qvglr&CbJ-qSq1A~ADiRJ=r_ z*lIwl4^Qz|zLYo?-jv8zJ+jl>hl!`b5OXtHC+2VY3z_q5+2Zbj+!$s}_#vy03oOA< z1M|x=nGapozhR}c=BQBh3{i@sPL`gij(JRm+CiHyv!3;_9zR4IkHrP$E}FhBmPV+k z&_73xx1_pCzAnQ8lPh{^D^S zwoTJR^B`Pue7S9Ju?Nd4$^t8((hz4?`esxuqqCIo2LD(~Dm?Z*;V>t^oZJ*nRNQ$l ziZpc~_K0+p4XlDu1x2PU6bUCQQt>u=Np(1a$5dR39k|LhS;|OMp93My2!{2mw#}~5 z!D_8->9~kU(sEJ$y!R9`7tj&M1Y|92EyIJEsHZp=^o(-MjAmcq!r>QW$`!iM!C%j& zX5>A^ctJ3sS&NRF4fJw1e1L;GlsfWa01 z2q8aaVF&&hV&Q*ryC@+^XI~gpdd~x<&_Iktf-(b{F#8m{2A=kbn`KJHS*BWD{VRXR zcSacm(>o0laIWBQu?;(5KTiaV_cm=^7b$ zU<~kQIacI7n|#ZM`oK*CFZ?j~shxbv*hRy2B&@>)s88y2mcn@&9Rk8a+)>2~Jq)Yt zD9+Cw2hW|}1POWjh*ZU@1qO3N(hEO4dwP*h7t?V^k}c-9ynp2{G5PyB>IIZx;4Ta) z^|%${=o91vJlA=bHjd0$ya^!MM!&>77V63*mY@MAf;bvRv%C*BG1jCf=Q88Ma~&~q zHlWuBgw-d<<`sUaSrgDzjJuJ!;q|lZ8KEdm!1C#@hVeQVo**H%p5L%segeS&)q;Ca zdf5i>!gqR5P746^ytN}IU^uOX!@>n(45R?3kt+ovOo*-Uepm?OGmx`0cO(V5#k!%+ z^E6IqCEl)((7?f?-b?6TAsZryoYpS=uw>S`ujYXwmvGpuso5>o4Pi-qr?(Pl6gQqW z&)5qZavch5+}!};RfmNT#zw282X_gt*lk5S7G61$c+Q*F;mk<|kVnSIIvamrmG zRYz~q@$5%EEfDl(^tb~O3kp2ds>o#;AwC{>BMUMY@0>T8!=VR~%ify1K9hSi+F3J6 z&Yp>TZ0xftj=F~@P_7XIPT^Z`z=(0^KiC}k1;^v|*4#2Fjgg6*U8YOgOglv`yR66~ z%`$XQ-bUbY8IgBUH$oaAI*t_Wi6%6y;$1sMuyTdF(iaIW_)bURnv2l{z;pw-+iL8E z9LqR7^%4HpM2m}$ah8Khaj5sfO71QkOyOb}iOnCFY8O$2a$Yy874F3%RQ1Zw;TG{5 z!0xFta*GKm!4-5O9=a2jvU)-C3rHyT#*;l8VSxZ{0E>|}R9&eW3Llym?TM{F<2!UJ zc^z^zFZsGOM^|X=#=?;FGtI-~R@V&1Y^_1gKXfYOl}DV(kIk3+$9D*VaR?vYiX5Fg i!`=he8UC4RiqB8o|BV}aPU7ZtkXW^5<>2y%Uj8rOPjQg| literal 0 HcmV?d00001 diff --git a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json index c6082b389..373f0def6 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json +++ b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json @@ -31,9 +31,11 @@ "Envelope knobs show ms and s." ], "usage": [ - "Load a sound, open the AMP page and turn HLD fully left: the sound decays straight from its peak.", - "Turn HLD fully right to AUTO: the sound holds while the trig or note lasts.", - "Turn ATK from 0 up: it reads 0.2ms, 0.4ms, ... with fine steps for clicks and transients." + "Press AMP. Turn DEC down: the knob shows its time to -60 dB, in 0.2 ms steps below 5 ms.", + "Turn HLD to 0: the decay starts as soon as the attack peaks. Turn it up for a hold in ms, or to the top for AUTO (decay from note-off).", + "Hold FUNC and turn HLD: it jumps between 0, 125 ms and AUTO.", + "On the FILTER page, ATK, DEC and REL show their times on the same fine curves.", + "In SOUND SETTINGS, set ENV RESET to AMP: sequenced trigs and retrig rolls restart the amp envelope from silence." ] }, "access": { @@ -127,7 +129,24 @@ }, "tests": { "report": "TESTING.md", - "summary": "Not tested yet." + "summary": "Emulator captures, and the author's measurements on an Analog Rytm MKII over USB (ED02 and earlier builds).", + "documentation": { + "tutorial": { + "title": "Quick tutorial", + "steps": [ + "Press AMP. Turn DEC down: the knob shows its time to -60 dB, in 0.2 ms steps below 5 ms.", + "Turn HLD to 0: the decay starts as soon as the attack peaks. Turn it up for a hold in ms, or to the top for AUTO (decay from note-off).", + "Hold FUNC and turn HLD: it jumps between 0, 125 ms and AUTO.", + "On the FILTER page, ATK, DEC and REL show their times on the same fine curves.", + "In SOUND SETTINGS, set ENV RESET to AMP: sequenced trigs and retrig rolls restart the amp envelope from silence." + ] + }, + "screenshots": [ + "media/decay-time.png", + "media/hold-time.png" + ], + "captureRecord": "media/capture.json" + } }, "license": { "spdx": "GPL-2.0-only", @@ -138,11 +157,43 @@ { "path": "media/thumbnail.svg", "kind": "thumbnail", - "caption": "Env Reset Amp", + "caption": "Improved Envelopes", "alt": "Original illustration of four envelopes, each rising from zero", "credit": "Iced-Cream", "license": "GPL-2.0-only", "source": "Original vector illustration; not a device screenshot." + }, + { + "path": "media/decay-time.png", + "kind": "screenshot", + "caption": "AMP page, DEC turned down: DECAY TIME, 2.2ms.", + "alt": "AMP page titled DECAY TIME with the DEC knob reading 2.2ms and a short decay drawn in the envelope picture.", + "credit": "Nathaniel Pavel documentation capture; Elektron interface", + "license": "LicenseRef-Rytm-UI-Documentation", + "source": "original", + "capture": { + "type": "emulator", + "release": "1.74", + "moduleVersion": "0.1.0-experimental", + "imageSha256": "b1bccf4d23c6b584ae36f39f2412dddff98c4a206bea83dff6613b313f2ba8bf", + "setup": "Headless rytm-emu (dtboot) running EN01: the Modwerk base for core-ar2 0.7 (plain variant ba530f45) and this folder's Improved Envelopes 0.1.0-experimental, linked by Modwerk's linker on stock OS 1.74, the default kit and pattern A01. Firmware-rendered 128x64 screen at 3x. UI documentation only." + } + }, + { + "path": "media/hold-time.png", + "kind": "screenshot", + "caption": "AMP page, HLD turned up: HOLD TIME, 4.0ms, beside DEC at 1.8ms.", + "alt": "AMP page titled HOLD TIME with the HLD knob reading 4.0ms and DEC reading 1.8ms.", + "credit": "Nathaniel Pavel documentation capture; Elektron interface", + "license": "LicenseRef-Rytm-UI-Documentation", + "source": "original", + "capture": { + "type": "emulator", + "release": "1.74", + "moduleVersion": "0.1.0-experimental", + "imageSha256": "b1bccf4d23c6b584ae36f39f2412dddff98c4a206bea83dff6613b313f2ba8bf", + "setup": "Headless rytm-emu (dtboot) running EN01: the Modwerk base for core-ar2 0.7 (plain variant ba530f45) and this folder's Improved Envelopes 0.1.0-experimental, linked by Modwerk's linker on stock OS 1.74, the default kit and pattern A01. Firmware-rendered 128x64 screen at 3x. UI documentation only." + } } ] } From e82901fc33391b2824adb024ef680417a12ce7aa Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Fri, 6 Nov 2026 23:27:56 -0600 Subject: [PATCH 04/11] Improved Envelopes: library parity test lists it Co-Authored-By: Claude Opus 5.5 --- src/devices/library-parity.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/library-parity.test.ts b/src/devices/library-parity.test.ts index a80b840ff..d97ed03ed 100644 --- a/src/devices/library-parity.test.ts +++ b/src/devices/library-parity.test.ts @@ -58,10 +58,10 @@ describe('Digitakt II research preview', () => { }) describe('Analog Rytm MKII library', () => { - it('lists Audio In FX, CHORUS, Pad Pressure Fix, Control In Actions, Filter Hz, FLANGER, Live Rec Retrig Fix, Loop Sync, PHASER, Pipo Loop, QPERF, Quick Trig Conditions, Quick Velocity+Aftertouch Assign, Sample RATE, Silent Pad+Trig and Temp Save and leaves the core build preview once a module is in the library', () => { + it('lists Audio In FX, CHORUS, Pad Pressure Fix, Control In Actions, Improved Envelopes, Filter Hz, FLANGER, Live Rec Retrig Fix, Loop Sync, PHASER, Pipo Loop, QPERF, Quick Trig Conditions, Quick Velocity+Aftertouch Assign, Sample RATE, Silent Pad+Trig and Temp Save and leaves the core build preview once a module is in the library', () => { expect(DEVICES_BY_ID['analog-rytm-mkii'].status).toBe('preview') expect(isCoreBuildPreview('analog-rytm-mkii')).toBe(false) - expect(DIGI_MODS.filter(mod => mod.device === 'analog-rytm-mkii').map(mod => [mod.id, mod.version, mod.releases])).toEqual([['audio-in-fx', '0.1.0', ['1.74']], ['chorus', '0.1.0', ['1.74']], ['chromatic-aftertouch-fix', '0.2.0', ['1.74']], ['control-in-actions', '0.1.2', ['1.74']], ['filter-hz', '1.2.0', ['1.74']], ['flanger', '0.1.0', ['1.74']], ['live-rec-retrig-fix', '0.2.1', ['1.74']], ['loop-sync', '0.3.2', ['1.74']], ['phaser', '0.1.0', ['1.74']], ['pipo-loop', '0.1.2', ['1.74']], ['qperf', '0.2.0', ['1.74']], ['quick-fill-trig-condition', '0.2.0', ['1.74']], ['quick-velocity-aftertouch-assign', '0.1.0', ['1.74']], ['sample-rate', '0.1.1', ['1.74']], ['silent-pad-trig', '0.7.0', ['1.74']], ['temp-save', '0.1.0', ['1.74']]]) + expect(DIGI_MODS.filter(mod => mod.device === 'analog-rytm-mkii').map(mod => [mod.id, mod.version, mod.releases])).toEqual([['audio-in-fx', '0.1.0', ['1.74']], ['chorus', '0.1.0', ['1.74']], ['chromatic-aftertouch-fix', '0.2.0', ['1.74']], ['control-in-actions', '0.1.2', ['1.74']], ['envelopes', '0.1.0', ['1.74']], ['filter-hz', '1.2.0', ['1.74']], ['flanger', '0.1.0', ['1.74']], ['live-rec-retrig-fix', '0.2.1', ['1.74']], ['loop-sync', '0.3.2', ['1.74']], ['phaser', '0.1.0', ['1.74']], ['pipo-loop', '0.1.2', ['1.74']], ['qperf', '0.2.0', ['1.74']], ['quick-fill-trig-condition', '0.2.0', ['1.74']], ['quick-velocity-aftertouch-assign', '0.1.0', ['1.74']], ['sample-rate', '0.1.1', ['1.74']], ['silent-pad-trig', '0.7.0', ['1.74']], ['temp-save', '0.1.0', ['1.74']]]) }) }) From 968d426bc6522778031075f654c3f30b15b94fa9 Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Fri, 6 Nov 2026 23:28:23 -0600 Subject: [PATCH 05/11] Improved Envelopes: comment and TESTING wording Co-Authored-By: Claude Opus 5.5 --- sdk/analog-rytm-mkii/modules/envelopes/TESTING.md | 2 +- sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md b/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md index a131c1c22..03620dfda 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md +++ b/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md @@ -57,7 +57,7 @@ state and the record outside the attack words, so the skipped call would have ch (read in amp_env_commands) sends rate 0 / level 0 to an idle voice every block, and the same one-pole record in the decay state, which a voice stays in until its next trig. -- Measured on the owner's MKII with the private lag-telemetry base, RC31's set, scratch project, +- Measured on the author's MKII with the private lag-telemetry base, RC31's set, scratch project, sequencer stopped, no USB audio, 50 one-second readings: LR01 (RC31) 70.84 % of the audio block, LR03 (RC31 with this source) 70.37 %. Pad mash (LR02, with two other idle changes): 81.7 % against 82.7 %, ~10 % fewer presses. diff --git a/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c b/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c index 0efcacada..5d42441bc 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c +++ b/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c @@ -382,7 +382,7 @@ __attribute__((noinline)) static void put_time(char *p, uint32_t ticks) put_text(put_uint(p, (ticks + 12000) / 24000), "s"); } -// log2(y) x 65536, y > 0 (as SY RUMB's). +// log2(y) x 65536, y > 0. __attribute__((noinline)) static int32_t log2_q16(uint32_t y) { int32_t n = 31, bit, f = 0; From 3c450590484c14a1e353a84a7351e453c3f2cd09 Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Fri, 6 Nov 2026 23:29:12 -0600 Subject: [PATCH 06/11] Improved Envelopes: pin the 0.1.0 package at 26dd6810, vendor it, verification record Co-Authored-By: Claude Opus 5.5 --- .../2026-11-07-rytm-improved-envelopes.md | 8 + .../elekloader-envelopes-2026-11-07.json | 34 + sdk/imports/envelopes-2026-11-07.json | 2 +- ...envelopes-0.1.0-experimental-os1.74.elemod | 615 ++++++++++++++++++ 4 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 docs/verification/2026-11-07-rytm-improved-envelopes.md create mode 100644 sdk/imports/elekloader-envelopes-2026-11-07.json create mode 100644 vendor/elekloader/catalog/envelopes-0.1.0-experimental-os1.74.elemod diff --git a/docs/verification/2026-11-07-rytm-improved-envelopes.md b/docs/verification/2026-11-07-rytm-improved-envelopes.md new file mode 100644 index 000000000..9b0528978 --- /dev/null +++ b/docs/verification/2026-11-07-rytm-improved-envelopes.md @@ -0,0 +1,8 @@ +# Analog Rytm MKII: Improved Envelopes 0.1.0-experimental — 7 November 2026 + +Nathaniel Pavel's (@npp1993) Improved Envelopes enters the library (id `envelopes`). It carries Iced-Cream's Env Reset Amp (ENV RESET AMP, from MrScruff's rytm-mods) on with a pre-fade, runs AMP HLD from no hold to AUTO, gives ATK, DEC, REL and HLD fine steps at short times, and shows every envelope knob's time. Its source-only OS 1.74 package is pinned in `sdk/imports/elekloader-envelopes-2026-11-07.json` (commit `26dd6810`). + +- **Build:** `scripts/build-elemod-isolated.sh` in `modwerk-source-tools` (image `39efd52a…`) from clean checkouts of `a0aaa13f` and later commits on the branch. Exported with `package-elemod-recipe.mjs`, which reproduces it with `--check` from each; `verify-elemod-release-exports.mjs` reproduces the 43 current exports. +- **Package:** `envelopes-0.1.0-experimental-os1.74.elemod` `f9779b13…328c`. +- **Emulator:** rytm-emu `2ac0f1f`, EN01 (the plain Modwerk base `ba530f45` + this package, `b1bccf4d…`): boots; the AMP page's DEC and HLD read their times (`media/capture.json`). +- **On a unit:** the author's Analog Rytm MKII over USB, in combined sets of up to 16 modules (EV04 to ED02): AMP DEC within 0.7 % of its text from 5 ms, AMP HLD within 0.1 ms, FILTER ATK within 0.3 %, FILTER DEC and REL 1.5 % (method), ENV RESET AMP with sequencer trigs and RTRG rolls. As reported; details in the module's TESTING.md. Not run alone on a unit. diff --git a/sdk/imports/elekloader-envelopes-2026-11-07.json b/sdk/imports/elekloader-envelopes-2026-11-07.json new file mode 100644 index 000000000..a0b86aa8a --- /dev/null +++ b/sdk/imports/elekloader-envelopes-2026-11-07.json @@ -0,0 +1,34 @@ +{ + "schema": 1, + "kind": "elekloader-catalog", + "revision": "envelopes-2026-11-07", + "about": "Modwerk source-only envelopes package for Analog Rytm MKII OS 1.74, compiled from sdk/analog-rytm-mkii/modules/envelopes.", + "cores": [], + "mods": [ + { + "file": "envelopes-0.1.0-experimental-os1.74.elemod", + "sha256": "f9779b13edaf0d838b3539cc6bf7a4ae16a66b1e918ccac9f3cf82c6ab7f328c", + "id": "envelopes", + "version": "0.1.0-experimental", + "device": "analog-rytm-mk2", + "os": "1.74", + "license": "GPL-2.0-only", + "source": { + "repo": "repeat98/modwerk", + "commit": "26dd68102e014409ee7a4410c5854e8d564ef028", + "path": "sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod" + }, + "title": "Improved Envelopes", + "requires": [ + "core" + ], + "conflicts": [], + "summary": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", + "description": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", + "category": "Synthesis", + "author": "npp1993", + "needs_core": "0.7", + "on_unit": "This source ran on the author's Analog Rytm MKII on OS 1.74 in a 16-module combined image (ED02, measured over USB: AMP DEC, AMP HLD, FILTER DEC and REL); this package has not run alone on a unit." + } + ] +} diff --git a/sdk/imports/envelopes-2026-11-07.json b/sdk/imports/envelopes-2026-11-07.json index 144675ed8..d1ca882d2 100644 --- a/sdk/imports/envelopes-2026-11-07.json +++ b/sdk/imports/envelopes-2026-11-07.json @@ -6,7 +6,7 @@ "changes": [ "First release. The AMP envelope reworked: AMP HLD runs from no hold (0) to AUTO (127) without cutting the attack; ATK, AMP DEC, FILTER DEC and REL and AMP HLD get fine steps at short times (0.2 ms to 5 ms); every envelope knob shows its time; FUNC + turn on HLD steps 0, 124.7 ms, AUTO; SOUND SETTINGS > ENV RESET gains AMP (Env Reset Amp, with a pre-fade)." ], - "runtimeSourceSha256": "ae0914c144b265c64fec3da6d9ff94832b84fd7de74c582c02b5765499415618", + "runtimeSourceSha256": "75e8f25452c379aaffba31095e59e1978a09f3acc227e659ebd20d2c088375ee", "packages": [ { "os": "1.74", diff --git a/vendor/elekloader/catalog/envelopes-0.1.0-experimental-os1.74.elemod b/vendor/elekloader/catalog/envelopes-0.1.0-experimental-os1.74.elemod new file mode 100644 index 000000000..1ae7ceaca --- /dev/null +++ b/vendor/elekloader/catalog/envelopes-0.1.0-experimental-os1.74.elemod @@ -0,0 +1,615 @@ +{ + "elemod": 2, + "id": "envelopes", + "version": "0.1.0-experimental", + "title": "Improved Envelopes", + "description": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", + "category": "machines", + "author": "npp1993", + "license": "GPL-2.0-only", + "target": { + "device": "analog-rytm-mk2", + "product": "Analog Rytm MKII", + "os": "1.74", + "syx_sha256": "cb0f99d620edde994fb860c0e79cc2464e427d06882828cfdfb00fc53700e123", + "section3_sha256": "34cd0c4da8e4b810d1b25284475a99ea53821e2ab7d30a978bf15dc578251f3b", + "section3_len": 3005432 + }, + "sections": { + ".run": { + "align": 4, + "len": 5808, + "parts": [ + [ + "hex", + "4a83663822398000ea3082b98000ea3482b98000ea38028101010101660842b90000000060164feffff048d703034eb9000000004cd703034fef0010223900000000070167384a926b3441f94029113873b0380041f98000e5087801b8b01c00671c203c3006a7ec22390000000007016706203cb006a7ec243c000000802239000000000701671241f900000000b0b03c006606b4b03c2067284feffff048d703032f022f002f0c2f0a2f034eb9000000002f4000144fef00144cd703034fef0010274000ac274000ec4ef940109c2c202f001c0c8000007f006d0642af001c600a4a806e0670012f40001c4ef940038bce00004fefffd048d77cfc22798000fe544ab98000ed9c670001a220398000ed9c46800880000c7df98000fc90283940287ffc7a16267c42ad66384283287c8000fd509dce4c045800247c42adf5d0207c42ac6b488c80702c4c004800070666262a43dbfc8000ea30101508000000671620087201e5882a40dbfc37fab290b295673c4a906674528341e80038588a49ec000c740c47eb1a0cb48366c0203900000000220e4680c28023c10000000023ce000000004cd77cfc4fef00304e754a9366c0201490896bbab0856cb62a7c4025a3a0700173b5380041e800385283588a49ec000c740ce3a8220e47eb1a0c82802c41b4836600ff6660a22a7c3d53081c74102e12dbca201522280024b4816500ff7690890c80fffea0706d00ff6ab0846c00ff647401e3aa2a4372ff2f48002c260253872407d4824a876f560682402909b8204275d0d482c4834a82670c4a816c4ab0856c0000a42200068000015f90b0846dce206f002c260d4a816d00ff18b2856d00ff58528341e80038588a49ec000c740c47eb1a0cb4836600fed06000ff0c2e3c000003c04a816db6908120006a025280206f002c260de280b2806c00fed6b2856cc06000ff1420398000ed987a167df98000fc90283940287ffc267c42ad6638287c8000fd504283247c42adf5d09dce8c804c045800702c4c004800207c42ac6b486000fe64206f002c260d588a528341e80038740c49ec000c47eb1a0cb4836600fe466000fe820000598f2f03701c2f027602222f00142401e0aa70f7206f0010c082b680670000b84a806700009c44c266000106202f0018e088710048404240224020802401760ee7aa7614712f001b484042402f4200082401e6a942030282000fffff214000041143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff80002141000824009489b3c0672222424a826d7c222800084a28000c663ee6896778b3c1630893c14a826d7690892080241f261f588f4e754a28000d66f220280004240022509489b3c066c260e270011140000d241f261f588f4e750c8107ffffff62caec89263c0000045c4c031800760fe6a952810c810001000064b02609e08b4c031800e08993c14a826c9e60122202448122416000ff7c7201b3c16286608cd0892080608822507609b6826600ff042401760ee7aa7614202800042f4200082401e6a942030282000fffff1143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff8000214100086000ff082f02202f000c2200e0814aaf00106f1a4a816d267429b4816c30747eb4816c200280ffffff00241f4e75747fb4816d10742ab4816d144a816fe6241f42804e75241f203c00007f004e75241f203c00002a004e754fefffe448d7401c222f0024780a2401260f4c4420004c4420024def001206830000001c204e43e8000106800000003010807009b08164262202b68967202401780a4c4420004c442002204943e8000106800000003010807009b08165da7001908e226f0020d08841f6080012e0bdc866fa4cd7401cd0af00204fef001c4e75226f0008206f0004101910c066fa4e75518f2f02202f0014206f00100c8002625a006306203c02625a00720a74174c00180006810000000cb481645c0c81000012bf630000a8220006810000000c0c810000bb7f630000de22000681000004b00c8100249eff6346068000002ee0243c00005dc04c4200002f002f084ebaff02508f223c000000002f4100142f400010241f508f6000ff6a203c000000002f4000142f480010241f508f6000ff54243c000009604c42100143fafec6700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c00000000609c74184c42100143fafe8c700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c000000002f4100142f400010241f508f6000fece74184c4210012f012f084ebafe40508f223c000000002f4100142f400010241f508f6000fea84fefffec48d7007c242f00182202d2816afcd48242414841307c001e4284700f04c291c2340176017c0fe1ab5380c4c12202eca94a826c08220242414841888374ffb48066de200848404240d0844cd7007c4fef00144e752f02740e222f00082001e5a8740f4241484102803fffc0002040203c7fffffff9088e2a822000681ffff8000b48164560c8101ffffff632c0c817ffeffff6250203c7fffffff90812f004ebaff5c721f4841588f9280203c0009f73e4c410000241f4e757412e888e4a93401c4c122000681fffff800203c37431533d2824c410000241f4e75241f203c7fffffff4e75241f42804e752f02740e202f000c2200e5a94240484002813fffc0002041720fc081223c7fffffff9288e0a90681ffff80004a816712202f00087417e5a84c410000241f52804e75241f203c7fffffff4e75518f2f0a727f2f02206f001420280008e0802240b2806c30327c007f2228000474080681ffffffceb4816532323b1a0848c14efb180200f2003200280032002800280120006600904a806cd02228000493c90681ffffffce7408b48164ce241f4280245f508f4e7545f90000000020329c000280000fffff2f002f48000c4ebafe9e206f000c2e802f28000c4ebafcee508f7001241f245f508f4e752228000c747eb4806d00013c4a806f00011241f90000000020309c002f002f014ebafcbe508f700160ce2068000c727e2f48000cb2806d0000fa41f90000000024309c000282000fffff2f02740a4ebafe32588f2200e4a90280000003ff243c000003ac4c021800740ac0fc03ac068000000200e4a82040487018002f2f00104ebafc5e508f70016000ff6e45f9000000002f329c004878007f2f4800104ebafe78588f206f000c2e802f28000c4ebafc30508f70016000ff4045f900000000740c71f29a002200e4a8e989740a4840424073c180812f00487800ff2f4800104ebafe36508f2200e4a90280000003ff243c000003d44c021800740ac0fc03d4068000000200e4a8224048711800206f000c2f28000c4ebafbc8508f70016000fed842802f002f014ebafbb6508f6000fef64879000000002f084ebafb94508f70016000feb44879000000002f014ebafb80508f70016000fea04fefffc8700748d7041cc0af003c206f00447401262f004c73280002e1aa2f41001e3200c2fc000e0681000000000c834000007f67000158760e4c00380043f900000000283138002f440022787fb8af004c6700008a41f1380028280008246800042f4400261828000c2f4a001a45e800041f4400321828000d1f4400332f2f004c2f2f004c2f4a00262808508445e8000c41e8000d2f4a00362f48003c2f4400322f012f40001e2f4900224ebaf86c4fef000c226f0016222f0022202f0012b2b13800670001184682c5b900000000202f00484cd7041c4fef00384e75282f004871100284fff0000020444a806d00018a43f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6700018c226f0040760220515388b688650001864aaf001e6f00019a282f001e41f90000000022704c00246f0040206a000441e8fff1b3c86c0001a0262f00220c83007e7fff6f000192307c00034878007f2f00226f004822882f012f40001e4ebaf7a24fef000c202f00124682c5b9000000006000ff48262f004871100283fff0000020434a806d0000a243f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e670000a4307c00022f3c4000007f2f00226f004822886092222f001a246f001eb2926600fede226f0026206f002ab3d06600fed0246f002e73af00327792b6816600fec0206f003473af00337790b2836600feb0222f0048262f004c41f90000000021810c1021830c3085b90000000020014cd7041c4fef00384e75428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600ff60307c00012f3c4000007f6000ff5c428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600fe78206f00407602b69067224878007f2f002f012f40001e4ebaf65e4fef000c202f00126000feba93c96000fe724878007f76012f0020832f012f40001e4ebaf6384fef000c202f00126000fe94307c00024878007f6000fe6e203c00000000b0b9419a5b8c6718203c400fe58423c0419a5b88203c0000000023c0419a5b8c4e750000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000000000320000003a00000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000011000000130000001500000017000000190000001b00000020000000250000002a0000002f00000034000000390000003e00000043000000480000004d00000057000000610000006b000000750000007f00000089000000930000009d000000a7000000b1000000bb000000c5000000cf000000d9000000e3000000f70000010b0000011f00000133000001470000015b0000016f0000018300000197000001ab000001bf000001d9000001f5000002130000023200000253000002760000029b000002c3000002ec000003190000034700000379000003ad000003e50000041f0000045d0000049f000004e50000052f0000057d000005d00000062800000685000006e70000074f000007bd00000832000008ae00000931000009bb00000a4e00000aea00000b8e00000c3d00000cf500000db900000e8800000f630000104b0000114100001246000013590000147d000015b2000016fa00001855000019c400001b4800001ce400001e98000020660000224e0000245400002678000028bd00002b2300002dae0000305f000033390000363e0000397100003cd300004069000044350000483a00004c7c000050fe000055c400005ad200005ad2000000000000079680000f951000179ce0001ca900001ffe000024b38000283620002aeca0002d1540002ed76000309a300033108000352b300036fcf0003893900039f9b0003b3770003c5350003d5270003e38f0003f0a40003fc9300040f01000423180004359f00045e330004802d00049d0b0004b5de0004cb730004de620004ef200004fe09000516ce00052ee7000544bc0005589c00056ac700057b7300058acd000598fd0005a6220005b25a0005bdbc0005c85e0005dba70005ecb00005fbd9000612da00062b4e0006417300065597000667fe000678df000688680006aa540006c69f0006de950006f322000709eb0007291f000744ab00075d2a00077316000786d40007a8ef0007c55f0007dd710007f215000807f400082747000842eb00085b7f0008717d000885490008a77d0008c3ff0008dc1f0008f0ce00090579000924da0009408b0009592900096f30000983040009ace00009ce5e0009e9c6000a013b000a3f51000a75bc000aa570000acf40000af3e6000b280c000b605d000b91b9000bbcfd000be2e9000c084d000c4291000c75a2000ca265000cc9a1000cec04000d144f000d4924000d7772000da008000dc39b000de2c9000dfe1c000e2c20000e561d000e7ae9000e9b2a000eb76f000ed035000ee5ed000ef8f5000f1349000f3087000f4a27000f609f000f744f000f8591000f94b1000000000000889d000110f20001933b0001dff50002246e00026b3900029fbb0002c8360002e85d0003050800033065000354ef0003742300038f180003a69d0003bb510003cdae0003de140003eccf0003fa1d00040c640004226b000436960004491f00045a3600047fa100049ef30004b98d0004d06c0004e44c0004f5bb00050a4a000525bd00053e57000554840005689b00057ae400058b9b00059af10005a9100005b61c0005c2330005cd6f0005d7e60005e1ad0005f368000606240006220300063af800065172000665cb0006784e00068937000698ba0006a7000006c62b0006e02a0006f62d0007121e000732dc00074f86000768d300077f53000793760007a5970007c4eb0007df080007f523000810300008310d00084dd00008673200087dc3000891f50008a4220008c38a0008ddb70008f3de00090db900092ea500094b74000964e100097b7b00098fb40009a1e80009c8570009e716000a0080000a2a71000a6370000a9566000ac131000ae793000b1272000b4d6e000b8121000bae71000bd629000bf8f9000c2ef9000c6477000c9358000cbc70000ce074000d000b000d3761000d67e1000d9263000db7a5000dd84d000df4ec000e1c05000e47ff000e6e8a000e9052000eaded000ec7e1000ede9f000ef28f000f0811000f26b1000f4189000f5911000f6daf000f7fc3000f8f9b000f9d7d000000000002f499000427510004d0970005412800059e5b0005db6000060cd900064cd800067e490006a5a00006c5ad0006e04a0006f6be000713e1000735150007521400076ba00007824c0007968e0007a8c40007b93a0007c82d0007d5d00007e24e0007edca00080da20008374900085a7d000878a2000892bc0008a98f0008bdaf0008cf900008df8c0008edee0008faf000090d8500092319000936de0009490e000959d60009695f000977cc00098538000991bf0009b1e20009cf290009e9d6000a044a000a3095000a58f2000a7dba000a9f3e000abdc9000ad99f000af2fc000b1435000b3e58000b64bf000b87be000ba7a4000bc4b6000bdf36000bf75c000c1abe000c42dd000c676f000c88c4000ca725000cc2d6000cdc13000cf315000d101a000d3653000d592a000d78ec000d95de000db040000dc84d000dde38000df233000e08d4000e2a07000e484a000e63df000e7d04000e93ef000ea8d2000ebbdd000ecd38000edd0a000eeb75000ef89a000f092b000f1f03000f32eb000f4511000f559b000f64af000f726d000f7ef5000f8a5f000f94c9000f9e45000fa6eb000faecd000fb5fb000fbc89000fc281000fc7f1000fcce7000fd16d000fd58b000fd94d000fdcb9000fdfd9000fe2b1000fe549000fe7a7000fe9cd000febc5000fed8f000fef31000ff0ad000ff209000ff345000ff4650000203f33c33dd8453d4ad04e76521555ea58e05b3c5d285ec06032627f647d663a67c3691f6a566b6d6c6a6d506e216ee16f92722474a476c178907a217b807cb57dc87ebd7f9a80c58230837c84ab85c386c587b4889189608a208c0e8dd08f6a91bf946896d499099b0d9ce29e8ea028a2eea576a7c4a9deabc9ad87af1fb124b3c9b631b863ba64bc37bde0bf64c18cc411c65cc874ca5ccc19cdafcf20d0e3d349d579d777d948daf0dc73ddd3df14e072e288e46ee629e7bde92eea7debafecc6edc5eeacef80f081f1e0f320f443f54df640f71cf7e6f89df945f9ddfa68fae7fb5afbc4fc24fc7bfccbfd13fd56fd92fdc9fdfbfe29fe53fe79fe9b30006d730073004155544f00494e4600" + ] + ] + }, + ".bss": { + "align": 16, + "size": 80 + } + }, + "symbols": { + "VOICE_TRACK": [ + "abs", + 1076433208 + ], + "WRITE_RESUME": [ + "abs", + 1074830380 + ], + "TRIG": [ + "abs", + 2147542280 + ], + "FADE_START": [ + "abs", + 2953226220 + ], + "FADE_GO_ON": [ + "abs", + 805742572 + ], + "FADE_LEVEL": [ + "abs", + 128 + ], + "ENV_RESET": [ + "abs", + 2147543600 + ], + "AMP_PICTURE": [ + "abs", + 1073974222 + ], + "follow": [ + ".run", + 784 + ], + "hold_jump": [ + ".run", + 1176 + ], + "put_uint": [ + ".run", + 1260 + ], + "put_text": [ + ".run", + 1388 + ], + "put_time": [ + ".run", + 1404 + ], + "log2_q16": [ + ".run", + 1734 + ], + "t60_ticks": [ + ".run", + 1822 + ], + "linear_ticks": [ + ".run", + 1972 + ], + "envelopes_text": [ + ".run", + 2048 + ], + "atk_rate": [ + ".run", + 5536 + ], + "amps": [ + ".run", + 3356 + ], + "envelopes_amp_graph": [ + ".run", + 208 + ], + "envelopes_flt_dec": [ + ".run", + 4000 + ], + "envelopes_flt_atk": [ + ".run", + 5024 + ], + "envelopes_gate": [ + ".bss", + 0 + ], + "envelopes_voice": [ + ".run", + 2550 + ], + "envelopes_amp_dec": [ + ".run", + 4512 + ], + "envelopes_write": [ + ".run", + 0 + ], + "envelopes_hold": [ + ".run", + 3488 + ], + "envelopes_params": [ + ".run", + 3468 + ], + "envelopes_tick": [ + ".run", + 3314 + ], + "envelopes_scan": [ + ".run", + 244 + ] + }, + "exports": [ + "envelopes_amp_dec", + "envelopes_amp_graph", + "envelopes_flt_atk", + "envelopes_flt_dec", + "envelopes_gate", + "envelopes_hold", + "envelopes_params", + "envelopes_scan", + "envelopes_tick", + "envelopes_voice", + "envelopes_write" + ], + "imports": [], + "weak": [], + "relocs": [ + [ + ".run", + 32, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 48, + "abs32", + "sec:.run", + 244 + ], + [ + ".run", + 62, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 106, + "abs32", + "sec:.bss", + 4 + ], + [ + ".run", + 128, + "abs32", + "sec:.bss", + 8 + ], + [ + ".run", + 138, + "abs32", + "sec:.bss", + 16 + ], + [ + ".run", + 174, + "abs32", + "sec:.run", + 2550 + ], + [ + ".run", + 400, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 412, + "abs32", + "sec:.bss", + 4 + ], + [ + ".run", + 418, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 1520, + "abs32", + "sec:.run", + 5797 + ], + [ + ".run", + 1542, + "abs32", + "sec:.run", + 5792 + ], + [ + ".run", + 1618, + "abs32", + "sec:.run", + 5797 + ], + [ + ".run", + 1676, + "abs32", + "sec:.run", + 5794 + ], + [ + ".run", + 1714, + "abs32", + "sec:.run", + 5794 + ], + [ + ".run", + 2154, + "abs32", + "sec:.run", + 4000 + ], + [ + ".run", + 2224, + "abs32", + "sec:.run", + 3488 + ], + [ + ".run", + 2264, + "abs32", + "sec:.run", + 4512 + ], + [ + ".run", + 2346, + "abs32", + "sec:.run", + 5024 + ], + [ + ".run", + 2392, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 2512, + "abs32", + "sec:.run", + 5804 + ], + [ + ".run", + 2532, + "abs32", + "sec:.run", + 5799 + ], + [ + ".run", + 2592, + "abs32", + "sec:.run", + 3356 + ], + [ + ".run", + 2614, + "abs32", + "sec:.run", + 3356 + ], + [ + ".run", + 2754, + "abs32", + "sec:.bss", + 8 + ], + [ + ".run", + 2794, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 2862, + "abs32", + "sec:.run", + 3488 + ], + [ + ".run", + 2940, + "abs32", + "sec:.bss", + 8 + ], + [ + ".run", + 2970, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 3098, + "abs32", + "sec:.bss", + 0 + ], + [ + ".run", + 3112, + "abs32", + "sec:.bss", + 8 + ], + [ + ".run", + 3132, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 3188, + "abs32", + "sec:.run", + 5536 + ], + [ + ".run", + 3316, + "abs32", + "sec:.run", + 1176 + ], + [ + ".run", + 3342, + "abs32", + "sec:.run", + 1176 + ], + [ + ".run", + 3484, + "abs32", + "sec:.run", + 2048 + ] + ], + "sites": [ + { + "addr": "0x400bcf8a", + "len": 2, + "stock_sha256": "0b358362552792220751c58c4cca9c4e54407d2339649a0b96182880f0504c1a", + "new": "7403", + "kind": "code", + "relocs": [] + }, + { + "addr": "0x400ef8d6", + "len": 2, + "stock_sha256": "4e4b41344512feecd49483d4a3f357ebd5b45f53276f21411a66cb3b4d597c16", + "new": "4e71", + "kind": "code", + "relocs": [] + }, + { + "addr": "0x40109c24", + "len": 8, + "stock_sha256": "3df81daa6f0b5b044b3c5bbf7c45a8d96b97caa686b60bf262eeda8b7dc87dc5", + "new": "4ef9000000004e71", + "kind": "code", + "relocs": [ + [ + 2, + "abs32", + "sym:envelopes_write", + 0 + ] + ] + }, + { + "addr": "0x400d3302", + "len": 6, + "stock_sha256": "704bb7e62b7dc84ac22bb9ec1242ae79e917ce47a7b6a4aa06ec60b72654b2c0", + "new": "4eb900000000", + "kind": "code", + "relocs": [ + [ + 2, + "abs32", + "sym:envelopes_amp_graph", + 0 + ] + ] + }, + { + "addr": "0x4010d2aa", + "len": 4, + "stock_sha256": "bb101f17b7e23130f5e92c2f8e616cf858c9db923af32f0756f4cd9af27591d0", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_flt_atk", + 0 + ] + ] + }, + { + "addr": "0x40109bc4", + "len": 4, + "stock_sha256": "a93a6f0c7e9387b5bf90a027d5678b11c90d555082736705d44faca3b73d46b6", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_hold", + 0 + ] + ] + }, + { + "addr": "0x40109bf0", + "len": 4, + "stock_sha256": "8879f37f45bb49679a30176c392dc823a5215ba1fdbecc9406684fec9adbc2aa", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_amp_dec", + 0 + ] + ] + }, + { + "addr": "0x4010d344", + "len": 4, + "stock_sha256": "e752dd02ad509e30bf4eab19cb5a7ef8760906dfdfa6d410e8a42e3635a2ef39", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_flt_dec", + 0 + ] + ] + }, + { + "addr": "0x4010d3b4", + "len": 4, + "stock_sha256": "e752dd02ad509e30bf4eab19cb5a7ef8760906dfdfa6d410e8a42e3635a2ef39", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_flt_dec", + 0 + ] + ] + }, + { + "addr": "0x4010d3dc", + "len": 4, + "stock_sha256": "e752dd02ad509e30bf4eab19cb5a7ef8760906dfdfa6d410e8a42e3635a2ef39", + "new": "00000000", + "kind": "data", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_flt_dec", + 0 + ] + ] + } + ], + "collections": {}, + "contribute": [ + { + "to": "ev_tick", + "order": 50, + "data": "00000000", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_tick", + 0 + ] + ], + "claims": [] + }, + { + "to": "core_params", + "order": 50, + "data": "00000000", + "relocs": [ + [ + 0, + "abs32", + "sym:envelopes_params", + 0 + ] + ], + "claims": [] + } + ], + "copied": [], + "resources": { + "regions": [], + "names": [ + "ui:SOUND SETTINGS ENV RESET values", + "ui:FUNC + turn of AMP HLD", + "ui:value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL", + "ui:AMP page envelope picture HLD", + "audio:amp envelope record write", + "audio:filter attack rate table", + "audio:amp hold table", + "audio:amp decay table", + "audio:filter decay and release table" + ], + "core": "0.3" + }, + "requires": [ + "core" + ], + "conflicts": [], + "signature": null +} From 0339df08f4027b2077854990d0c4a7f4c48ef30b Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Sat, 7 Nov 2026 09:45:13 -0600 Subject: [PATCH 07/11] Improved Envelopes: ENV RESET AMP leaves the module, its own origin note and thumbnail ENV RESET AMP and its pre-fade go back to Env Reset Amp, now in the library on its own: the two byte sites at 0x400bcf8a and 0x400ef8d6, pre-fade.c, the ENV RESET claim and its docs and release-note lines. The writer keeps only the idle skip (envelopes_gate moves to envelopes.c, still-mask at [0]). Beside Env Reset Amp the HOLD rule holds from the next block's attack record (stock's state 0 at 0x40109b5a, read in OS 1.74; upstream/README.md), so no conflict. upstream/README.md and media/thumbnail.svg are Envelopes' own; TESTING says the author where it said the owner, and drops the empty EV04 head. Co-Authored-By: Claude Opus 5.5 --- .../modules/envelopes/README.md | 27 ++--- .../modules/envelopes/TESTING.md | 41 ++----- .../modules/envelopes/build.json | 18 --- .../modules/envelopes/media/thumbnail.svg | 15 ++- .../modules/envelopes/modwerk.module.json | 35 ++---- .../modules/envelopes/src/amp-write.s | 82 ++------------ .../modules/envelopes/src/envelopes.c | 16 +-- .../modules/envelopes/src/pre-fade.c | 104 ------------------ .../modules/envelopes/upstream/README.md | 79 +++++-------- sdk/imports/envelopes-2026-11-07.json | 2 +- .../analog-rytm-mkii-envelopes.json | 2 +- 11 files changed, 97 insertions(+), 324 deletions(-) delete mode 100644 sdk/analog-rytm-mkii/modules/envelopes/src/pre-fade.c diff --git a/sdk/analog-rytm-mkii/modules/envelopes/README.md b/sdk/analog-rytm-mkii/modules/envelopes/README.md index 609859e4a..9646f5033 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/README.md +++ b/sdk/analog-rytm-mkii/modules/envelopes/README.md @@ -4,8 +4,8 @@ Module for the Analog Rytm MKII, OS 1.74. It reworks the AMP envelope and shows times on every envelope knob: AMP HLD runs from no hold to AUTO without cutting the attack, ATK, DEC, REL and HLD get -fine steps at short times (0.2 ms up to 5 ms), and SOUND SETTINGS > ENV RESET gains AMP. It carries -Iced-Cream's Env Reset Amp (ENV RESET AMP, from MrScruff's rytm-mods) on, with a pre-fade added. +fine steps at short times (0.2 ms up to 5 ms). It installs beside Env Reset Amp (ENV RESET AMP), which +it began from. ## Controls @@ -17,7 +17,6 @@ Iced-Cream's Env Reset Amp (ENV RESET AMP, from MrScruff's rytm-mods) on, with a | FILTER ATK | stock's curve (as AMP's) | the same new curve as AMP ATK, built for the filter's speed measured on the unit (1.00x the OS model); played on the unit in EV14, 7.5..384 ms within 0.3 % of target | | FUNC + turn on HLD | jumps to AUTO | steps 0, 124.7 ms (a 16th at 120 BPM, HLD 42), AUTO | | AMP ATK, HLD, DEC, FILTER ATK, DEC, REL | 0..127 | times: an attack's full ramp, a hold's length, a decay's or release's time to -60 dB; AMP DEC 127 = INF | -| SOUND SETTINGS > ENV RESET | OFF, FILTER | OFF, AMP, FILTER, AMP+FILT (Env Reset Amp). AMP fades the amp envelope to silence just before sequenced trigs and retrig rolls (a held pad's RTRG roll too), so they restart from silence; a pad or MIDI hit itself, and the first trig after PLAY, continue from the current level, as stock | ## Usage @@ -30,13 +29,11 @@ time, and the short end has the resolution drums need. 2. Turn HLD to 0: the decay starts as soon as the attack peaks. Turn it up for a hold in ms, or to the top for AUTO (decay from note-off). 3. Hold FUNC and turn HLD: it jumps between 0, 125 ms and AUTO. 4. On the FILTER page, ATK, DEC and REL show their times on the same fine curves. -5. In SOUND SETTINGS, set ENV RESET to AMP: sequenced trigs and retrig rolls restart the amp envelope from silence. ## How it works - `src/amp-write.s` takes the amp record write in `amp_env_commands` (0x40109c24, every voice every - block). It runs ENV RESET AMP's pre-fade (`src/pre-fade.c`) while a track has AMP in its ENV - RESET, then `envelopes_voice`, except for a voice whose record repeats the last one it took when + block) and calls `envelopes_voice`, except for a voice whose record repeats the last one it took when that one changed nothing (an idle voice, a decay at its end): an idle unit makes no C call there. - `envelopes_voice` (`src/envelopes.c`) follows each voice's amp level from the records sent (the level lives in the voice hardware) and sets the state stock moves to: after a trig 1 (gate, AUTO) or 2 @@ -47,11 +44,6 @@ time, and the short end has the resolution drums need. - FILTER ATK's rates come from `envelopes_flt_atk` (same script, 32-bit words): a `ptr` site in `build.json` points stock's lea at 0x4010d2a8 (the filter attack table, read for the attack record and the state counter alike) at it. -- ENV RESET AMP: the pre-fade watches each track's queued sequencer trig and retrig series and ramps - a sounding voice toward silence (up to ~4 ms, starting up to 7.3 ms ahead), so stock's attack, which - starts from the current level, starts from silence. A pad or MIDI hit, and a trig queued less than - the fade ahead (the first after PLAY), are not known in time and play as stock. A roll faster than - about 15 ms gets half its spacing to fade, so below about 8 ms it may not reach silence. - DEC, REL and HLD: `tools/dec_table.py` builds three tables (`envelopes_amp_dec`, `envelopes_flt_dec`, `envelopes_hold`, 128 words each) and `ptr` sites in `build.json` point stock's leas at them: the amp decay record (0x40109bee), the filter decay and release records (0x4010d342, 0x4010d3b2, 0x4010d3da) @@ -67,7 +59,6 @@ time, and the short end has the resolution drums need. | --- | --- | --- | --- | | AMP HLD 0 is no hold and 127 is AUTO (stock: 0 is AUTO, 127 is 16 s); HLD, ATK, DEC and REL follow new curves. | Anyone with the module installed, including projects made on stock. | A hold that starts at zero and grows with the knob, and resolution at the short end, need the knob's values to mean new times. | Saved sounds and projects play their stored bytes on the new curves (no migration); MIDI CC follows the knob. | | FUNC + turn on HLD steps 0, 124.7 ms, AUTO (stock: jumps to AUTO). | Anyone who uses the FUNC jump on HLD. | Quick access to the three most used holds. | Other knobs' FUNC jumps are unchanged. | -| ENV RESET gains AMP and AMP+FILT. | Anyone who picks them; OFF and FILTER behave as stock. | Env Reset Amp's feature. | A pad or MIDI hit, and the first trig after PLAY, continue from the current level, as stock. | Saved values keep their bytes and are read the new way: a project made on stock plays HLD 0 as no hold (was AUTO) and HLD 127 as AUTO (was 16 s), HLD 1..126, DEC and REL on the new curves (the same byte is a different time, mostly shorter at the low end), and AMP and FILTER ATK on the new curve. MIDI CC 79 (HLD) and the ATK CC @@ -80,7 +71,7 @@ exponential (straight lines in dB). A choke or stop still fades over stock's fix It patches the amp record write in `amp_env_commands` (0x40109c24) and points stock's envelope table reads at its own tables (`ptr` sites, listed under How it works), and subscribes to `ev_tick`. Claims: -ENV RESET's values, FUNC + turn on AMP HLD, the value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL, +FUNC + turn on AMP HLD, the value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL, the AMP page picture and the amp and filter envelope tables. It needs no other module. - AMP ATK and DEC times are calibrated to one Rytm MKII (EV06, 6 Nov 2026): its VCA ran attacks at @@ -94,6 +85,10 @@ the AMP page picture and the amp and filter envelope tables. It needs no other m - A module that times a note by AMP DEC's table must read the table address the OS code holds at 0x40109bf0, not stock's 0x401ee61c: with this module that address points at the new table. - On stock firmware a sound saved here plays the stock way (HLD 0 = AUTO, the old ATK curve). +- Beside Env Reset Amp: with AMP in a track's ENV RESET, that module replaces the trig's attack + record with a drop to silence. Envelopes then keeps its HOLD rule from the next block's attack + record (read in the OS code: [upstream/README.md](upstream/README.md#beside-env-reset-amp)); the + pair has not yet run together on a unit. - Unit results: TESTING.md. ## Tests and measurements @@ -106,9 +101,9 @@ Load: the amp record write runs every block for every voice; an idle voice makes ## Authorship and licences -Nathaniel Pavel (@npp1993): Envelopes, the curves, the knob times and ENV RESET AMP's pre-fade. -MrScruff: ENV RESET AMP, rytm-mods 0015-env-reset-amp, its design and code. Iced-Cream: its elemod -port and Modwerk module, which this carries on. irpina: Elekloader and core-ar2. GPL-2.0-only +Nathaniel Pavel (@npp1993): Envelopes, the curves and the knob times. MrScruff and Iced-Cream: Env +Reset Amp (rytm-mods 0015 and its elemod port), whose reading of the amp envelope's commands this +module started from; none of its code is carried. irpina: Elekloader and core-ar2. GPL-2.0-only ([LICENSE](LICENSE)). The source names firmware addresses only; no Elektron firmware is included. ## Screens and audio diff --git a/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md b/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md index 03620dfda..d5d9efe38 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md +++ b/sdk/analog-rytm-mkii/modules/envelopes/TESTING.md @@ -43,15 +43,13 @@ DEC 30 (7.5 ms) was too short to track. The 1.5 % is the method's, as on EV14. Some takes of the HLD sweep came back with a one-off USB capture gap (a stretch of digital silence); those were repeated and the clean take is the one above. -On the unit's screen (ED02, the user): AMP HLD 90 reads 1972ms and fits the field. +On the unit's screen (ED02, the author): AMP HLD 90 reads 1972ms and fits the field. Not tested: FILTER DEC/REL below 15 ms and AMP DEC below 5 ms to better than the VCA's slew, the other knob texts on the unit's screen (host-checked: all 128 values of each knob distinct, at most 6 characters), FUNC jump to HLD 42, saving and reloading. ## Idle CPU, LR03 / LP01 (6 November 2026) -The amp writer called `envelopes_voice` for every voice every block, and voice 0 ran the pre-fade scan -every block. Now (8028baf2) voice 0 skips the scan while no track has AMP in its ENV RESET (it clears the -fade mask, as the scan finds), and a voice skips the C call when its rate and level words equal the last +The amp writer called `envelopes_voice` for every voice every block. Now (8028baf2) a voice skips the C call when its rate and level words equal the last ones it took and that call left the level follower as it was. The follower is a pure function of its state and the record outside the attack words, so the skipped call would have changed nothing. Stock (read in amp_env_commands) sends rate 0 / level 0 to an idle voice every block, and the same one-pole @@ -69,7 +67,7 @@ record in the decay state, which a voice stays in until its next trig. Build EV14: EV13's set with Improved Envelopes at 4efb6fbe (FILTER ATK table for the filter's 1.00x speed, FILTER text unscaled; 18a15a2e adds only docs); sha256 61163e6089ca427505e2c25fcd3401e13dd828a23094cd3d5be856bf5d83cc9f, lock NS01, ramSpare 17,788. -Flashed by the owner. FILTER ATK by the ~1.3 kHz method of the EV13 section (FRQ 86, ENV +6, ends +Flashed by the author. FILTER ATK by the ~1.3 kHz method of the EV13 section (FRQ 86, ENV +6, ends extrapolated, four takes each; mean / spread): | FILTER ATK | Target | Measured | Ratio | @@ -86,26 +84,10 @@ method's error. Everything else of EV13 carries over (AMP code unchanged). Build EV13: EV09's set and base (no-send b530a147, lock NS01) with Improved Envelopes at a6df46ff (FILTER ATK table, rounded knob times); sha256 6c7598110742557956310a49906aa44d20978273f31d66a394eb8fa4de9c3cbb, ramSpare 17,708. Flashed by the -owner; scratch project, track 1 a looped sine. MAIN OUT over USB audio, settings by USB MIDI CC. +author; scratch project, track 1 a looped sine. MAIN OUT over USB audio, settings by USB MIDI CC. -**ENV RESET AMP, sequenced.** The owner programmed track 1 (trigs on steps 1, 5, 9; step 13 a trig -with RTRG 1/16, about 4 steps; other tracks muted); the rig set AMP ATK 64 (87 ms), HLD 0, DEC 100 -and ran the pattern with MIDI START, 120 BPM clock and STOP. - -| ENV RESET | Each later trig and retrig (steps 5, 9, 13 and the 1/16 roll) | -|---|---| -| AMP | the voice, at -1.9 dB (steps) or -0.1 dB (roll) 15 ms before, drops to -48..-54 dB at the trig, then rises to the top in ~91 ms (the 87 ms attack) | -| OFF | no dip: the attack continues from -2 dB and reaches the top within ~15-20 ms (stock) | - -Aborted fades (EV14, same day): the rig drove the pattern with its own MIDI clock and made the step-5 -trig fail on purpose, ENV RESET AMP, a steady ~1.3 kHz tone at -2 dB. STOP sent 3 ms before step 5: -the voice fades to -50 dB within ~5 ms and stays silent to the end of the take (1.2 s). Clock stopped -before step 5: the voice holds through the missed step, fades ~90 ms later (when the Rytm's own tempo -expected the trig) and stays silent. No jump back in either. Unexplained, seen once: on the first run -(MIDI START with no clock at all while CLOCK RECEIVE is on, same pattern), a fade ~85 ms before an -expected step was followed ~90 ms later by the level returning to -1 dB within 10 ms. Three more -START-without-clock runs did not show it (the sequencer either held silent or ignored START); a -transport with no clock at all is not a normal way to play, so it is left as a note. +EV13 and EV14 also carried ENV RESET AMP with a pre-fade; it left this module before 0.1.0 (Env Reset +Amp keeps ENV RESET AMP), so those runs are not recorded here. **FILTER ATK on the new table** (method as EV09 below: LP2, RES 127, FRQ 40, LEV 0, ENV +24, AMP ATK 0 / HLD AUTO / DEC INF, FILTER SUS 127 / DEC 0, single MIDI notes; rise start to top, by zero crossings). @@ -154,7 +136,7 @@ Not tested on the unit in EV13: knob texts (rytm-emu: FILTER ATK reads 1.0ms, 4. Build EV09: RC30's set with envelopes in place of env-reset-amp, on the private no-send base b530a147, lock NS01; sha256 6cccc5e5c91bd24e89c1220ecddef3c569386aed9b44e9f3d79c590999c3f908 (source b6727c48; -the display-name commit 0764febb is in it). Flashed by the owner; track 1 as the owner set it (a +the display-name commit 0764febb is in it). Flashed by the author; track 1 as the author set it (a looped ~1 kHz sine), only AMP ATK/HLD/DEC sent over USB MIDI (CC 78/79/80), MAIN OUT over USB audio. | Check | Target | Measured | @@ -164,7 +146,7 @@ looped ~1 kHz sine), only AMP ATK/HLD/DEC sent over USB MIDI (CC 78/79/80), MAIN | Decay start HLD 0 / 1 / 7 / 15 / 31 / 47 | 0 / 15.6 / 62.5 / 125 / 250 / 500 ms | 2.5 / 17.5 / 64.2 / 126.8 / 251.5 / 501.5 ms | | AUTO, note 100 / 300 ms | 100 / 300 ms | 102.5 / 301.5 ms | | Never cut, ATK 87 ms: HLD 0 / 2 / 7 (62.5 ms) | peak at 87 ms | 87.5 / 87.5 / 87.5-87.8 ms (HLD 7 re-run 3x: one sweep take had a late USB note) | -| Second MIDI note on a decaying voice (ATK 64/72, DEC 100/110; ENV RESET set to AMP or AMP+FILT, as the owner recalls; MIDI hits bypass it by design) | attack continues from the current level to the first peak | -14.27 vs -14.28 dB, all three; the second peak came 23 / 24.5 / 52 ms after the note, from 0.9 / 1.2 / 2.0 dB below the peak (no restart, as designed). Not a test of ENV RESET AMP | +| Second MIDI note on a decaying voice (ATK 64/72, DEC 100/110) | attack continues from the current level to the first peak | -14.27 vs -14.28 dB, all three; the second peak came 23 / 24.5 / 52 ms after the note, from 0.9 / 1.2 / 2.0 dB below the peak | | AMP DEC slope, DEC 6..126 | 0.918 x model (text) | 0.90-0.925 x model (DEC 108/114 captures failed) | Decay start = the 3 dB point minus 3 x the measured dB slope. The VCA ran attacks at 0.957x and decays @@ -189,13 +171,11 @@ These runs used stock's FILTER ATK table (118 ms..3.7 s attacks). The new FILTER (`envelopes_flt_atk`, site 0x4010d2aa, EV11 on) is checked in rytm-emu only (knob text); its times on the unit, and the filter's speed below 118 ms, were not tested then (now measured: EV13 section). -## Unit, EV04 - ## Unit (Analog Rytm MKII, OS 1.74), 6 Nov 2026 Build EV04: RC30's set with Envelopes in place of Env Reset Amp, base 8b0cafbc, sha256 374157b56041b15bff1d9795371cc60c6a7f0388c7075378e1365287a549d393 (source 818f7b08). Flashed by the -owner; scratch project. +author; scratch project. Automated: track 1 (BD) on BD ANALOG with its DEC 127, filter open, no FX, AMP DEC 40, played over USB MIDI (channel 1, note 0, velocity 100), MAIN OUT recorded over USB audio; script envtest.py (private @@ -213,8 +193,7 @@ click, so hold and AUTO are judged against the HLD 47 take (held to 500 ms), not | ATK rise 10-90 %: 0 / 1 / 5 / 10 / 25 (0 / 0.2 / 1 / 2 / 5 ms) | 1.0 / 1.0 / 1.25 / 1.75 / 3.75 ms (hardware slew ~0.8 ms floors the shortest) | | ATK 64 rise 10-90 % | 64.8 ms = 0.74 of the 87.2 ms ramp, as earlier probe measurements | -Not tested on the unit: knob texts and the AMP picture (rytm-emu only), FUNC jumps, ENV RESET AMP and -its pre-fade in this build (unchanged code from Env Reset Amp 1.1.0, which passed ER05), filter +Not tested on the unit: knob texts and the AMP picture (rytm-emu only), FUNC jumps, filter DEC/REL times, retrigs, choke, saving and reloading, CPU cost. ## rytm-emu (2ac0f1f), EV02-EV04 diff --git a/sdk/analog-rytm-mkii/modules/envelopes/build.json b/sdk/analog-rytm-mkii/modules/envelopes/build.json index abdb842da..deeeadc95 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/build.json +++ b/sdk/analog-rytm-mkii/modules/envelopes/build.json @@ -2,7 +2,6 @@ "schemaVersion": 1, "sources": [ "src/amp-write.s", - "src/pre-fade.c", "src/envelopes.c" ], "defsym": {}, @@ -34,7 +33,6 @@ "copied": [], "regions": [], "claims": [ - "ui:SOUND SETTINGS ENV RESET values", "ui:FUNC + turn of AMP HLD", "ui:value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL", "ui:AMP page envelope picture HLD", @@ -51,22 +49,6 @@ "defsym": {}, "cflags": [], "sites": [ - { - "addr": "0x400bcf8a", - "len": 2, - "stockSha256": "0b358362552792220751c58c4cca9c4e54407d2339649a0b96182880f0504c1a", - "op": "bytes", - "new": "7403", - "kind": "code" - }, - { - "addr": "0x400ef8d6", - "len": 2, - "stockSha256": "4e4b41344512feecd49483d4a3f357ebd5b45f53276f21411a66cb3b4d597c16", - "op": "bytes", - "new": "4e71", - "kind": "code" - }, { "addr": "0x40109c24", "len": 8, diff --git a/sdk/analog-rytm-mkii/modules/envelopes/media/thumbnail.svg b/sdk/analog-rytm-mkii/modules/envelopes/media/thumbnail.svg index 0137eaeb5..657a69227 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/media/thumbnail.svg +++ b/sdk/analog-rytm-mkii/modules/envelopes/media/thumbnail.svg @@ -1,8 +1,17 @@ -ENV RESET AMP -SOUND SETTINGS ENV RESET gains AMP and AMP+FILT: the amp envelope restarts from silence on every trig, so AMP ATK is heard on every hit. Original conceptual illustration, not an instrument screen or a measured result. +Improved Envelopes +An amp envelope: an attack, a hold that runs from none to AUTO, and an exponential decay, over a time ruler whose steps are finest at the short end. Original conceptual illustration, not an instrument screen or a measured result. -ENV RESET: AMP + + + + + + +ATK HLD DEC +0.2ms +0..AUTO + diff --git a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json index 373f0def6..e40c84cdc 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json +++ b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json @@ -10,9 +10,8 @@ "github": "npp1993", "name": "Nathaniel Pavel", "credits": [ - "Nathaniel Pavel — Envelopes: HOLD order and attack-aware hold, the ATK curve, envelope times on the knobs, and ENV RESET AMP's pre-fade.", - "MrScruff — ENV RESET AMP, the original mod 0015-env-reset-amp in rytm-mods, its design and code; published in rytm-mods-src with permission.", - "Iced-Cream — Env Reset Amp, the elemod port (rytm2_mods) and its Modwerk module, which Envelopes carries on.", + "Nathaniel Pavel — Envelopes: HOLD order and attack-aware hold, the ATK, DEC, REL and HLD curves, and envelope times on the knobs.", + "MrScruff and Iced-Cream — Env Reset Amp (rytm-mods 0015 and its elemod port), whose reading of the amp envelope's commands this module started from; none of its code is carried.", "irpina — Elekloader and core-ar2, the core it links with." ] }, @@ -22,24 +21,23 @@ "presentation": { "label": "IMPROVED ENVELOPES", "family": "Sound", - "summary": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", - "overview": "Envelopes reworks the AMP envelope. HOLD runs from 0 (no hold: the decay starts the moment the attack reaches the top) up to AUTO at the top of the knob (hold while the note lasts); a hold never cuts the attack short. AMP ATK and FILTER ATK step 0.2 ms at a time up to 5 ms, 0.5 ms up to 15 ms, then about 10 % a step up to 30 s. SOUND SETTINGS > ENV RESET gains AMP and AMP+FILT (from Env Reset Amp): sequenced trigs and retrig rolls restart the amp envelope from silence after a short pre-fade; a pad or MIDI hit itself, and the first trig after PLAY, continue from the current level, as stock. AMP ATK, HLD and DEC and FILTER ATK, DEC and REL show times instead of 0..127.", + "summary": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, and the envelope knobs show times.", + "overview": "Envelopes reworks the AMP envelope. HOLD runs from 0 (no hold: the decay starts the moment the attack reaches the top) up to AUTO at the top of the knob (hold while the note lasts); a hold never cuts the attack short. AMP ATK and FILTER ATK step 0.2 ms at a time up to 5 ms, 0.5 ms up to 15 ms, then about 10 % a step up to 30 s; AMP DEC and FILTER DEC and REL step 0.2 ms up to 5 ms and stay finer than stock up to 300 ms. AMP ATK, HLD and DEC and FILTER ATK, DEC and REL show times instead of 0..127.", "highlights": [ "HOLD: 0 = no hold, top = AUTO; never cuts the attack.", "AMP and FILTER ATK: 0.2 ms steps at the low end.", - "ENV RESET AMP with a click-free pre-fade.", + "AMP DEC, FILTER DEC and REL: 0.2 ms steps up to 5 ms.", "Envelope knobs show ms and s." ], "usage": [ "Press AMP. Turn DEC down: the knob shows its time to -60 dB, in 0.2 ms steps below 5 ms.", "Turn HLD to 0: the decay starts as soon as the attack peaks. Turn it up for a hold in ms, or to the top for AUTO (decay from note-off).", "Hold FUNC and turn HLD: it jumps between 0, 125 ms and AUTO.", - "On the FILTER page, ATK, DEC and REL show their times on the same fine curves.", - "In SOUND SETTINGS, set ENV RESET to AMP: sequenced trigs and retrig rolls restart the amp envelope from silence." + "On the FILTER page, ATK, DEC and REL show their times on the same fine curves." ] }, "access": { - "location": "AMP page (HLD, ATK); SOUND menu (FUNC + MUTE) > SOUND SETTINGS > ENV RESET.", + "location": "AMP page (ATK, HLD, DEC); FILTER page (ATK, DEC, REL).", "steps": [ "Open the AMP page.", "Turn HLD or ATK; FUNC + turn on HLD jumps between 0, 125 ms and AUTO." @@ -70,12 +68,6 @@ "default": null, "doc": "0 instant, 0.2 ms steps to 5 ms, 0.5 ms to 15 ms, 1 ms to 25 ms, 2.5 ms to 50 ms, 5 ms to 100 ms, 10 ms to 200 ms, 25 ms to 300 ms, then about 14 % a step to 40-45 s. Times are to -60 dB. AMP DEC at the top stays INF.", "labels": null - }, - { - "name": "SOUND SETTINGS > ENV RESET", - "default": null, - "doc": "Steps OFF, AMP, FILTER, AMP+FILT. With AMP, sequenced trigs and retrig rolls (a held pad's RTRG too) restart the amp envelope from silence after a short pre-fade; a pad or MIDI hit itself, and the first trig after PLAY, continue from the current level, as stock.", - "labels": null } ], "compatibility": { @@ -87,8 +79,7 @@ "limitations": [ "Built for OS 1.74 only.", "Saved HLD, ATK, DEC and REL values read differently from stock: HLD 0 is no hold instead of AUTO, 127 is AUTO instead of 16 s, and HLD, AMP and FILTER ATK, DEC and REL follow the new curves.", - "Times shown are calibrated to one Rytm MKII (AMP attack 0.957x, decay 0.918x; the filter envelope runs at the OS model's speed); another unit may differ slightly.", - "ENV RESET AMP acts only on trigs the Rytm schedules in time (sequencer trigs, retrig rolls): a pad or MIDI hit itself and the first trig after PLAY play as stock, and a roll faster than about 8 ms may not fade fully to silence." + "Times shown are calibrated to one Rytm MKII (AMP attack 0.957x, decay 0.918x; the filter envelope runs at the OS model's speed); another unit may differ slightly." ] }, "platform": { @@ -99,7 +90,6 @@ "ev_tick" ], "claims": [ - "ui:SOUND SETTINGS ENV RESET values", "ui:FUNC + turn of AMP HLD", "ui:value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL", "ui:AMP page envelope picture HLD", @@ -137,8 +127,7 @@ "Press AMP. Turn DEC down: the knob shows its time to -60 dB, in 0.2 ms steps below 5 ms.", "Turn HLD to 0: the decay starts as soon as the attack peaks. Turn it up for a hold in ms, or to the top for AUTO (decay from note-off).", "Hold FUNC and turn HLD: it jumps between 0, 125 ms and AUTO.", - "On the FILTER page, ATK, DEC and REL show their times on the same fine curves.", - "In SOUND SETTINGS, set ENV RESET to AMP: sequenced trigs and retrig rolls restart the amp envelope from silence." + "On the FILTER page, ATK, DEC and REL show their times on the same fine curves." ] }, "screenshots": [ @@ -151,15 +140,15 @@ "license": { "spdx": "GPL-2.0-only", "file": "LICENSE", - "declaration": "Nathaniel Pavel's code, and MrScruff's rytm-mods code with Iced-Cream's elemod port, under GPL-2.0-only. The source names firmware addresses only; the patch preconditions are addresses, lengths and SHA-256s." + "declaration": "Nathaniel Pavel's code, under GPL-2.0-only. The source names firmware addresses only; the patch preconditions are addresses, lengths and SHA-256s." }, "media": [ { "path": "media/thumbnail.svg", "kind": "thumbnail", "caption": "Improved Envelopes", - "alt": "Original illustration of four envelopes, each rising from zero", - "credit": "Iced-Cream", + "alt": "Original illustration of an amp envelope (attack, hold, decay) over a time ruler with fine steps at the short end", + "credit": "Nathaniel Pavel", "license": "GPL-2.0-only", "source": "Original vector illustration; not a device screenshot." }, diff --git a/sdk/analog-rytm-mkii/modules/envelopes/src/amp-write.s b/sdk/analog-rytm-mkii/modules/envelopes/src/amp-write.s index 68078f2e7..ced8fe172 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/src/amp-write.s +++ b/sdk/analog-rytm-mkii/modules/envelopes/src/amp-write.s @@ -1,31 +1,12 @@ | SPDX-License-Identifier: GPL-2.0-only - | Envelopes - the amp envelope record write (OS 1.74). + | Envelopes - the amp envelope record write (OS 1.74), Nathaniel Pavel. | - | ENV RESET AMP comes from Env Reset Amp: MrScruff's rytm-mods 0015, ported - | to elemod by Iced-Cream, with Nathaniel Pavel's pre-fade (1.1): the voice - | fades out over up to ~4 ms, starting up to 7.3 ms before a trig the - | Rytm schedules itself - a sequencer trig or a retrig - so stock's - | attack, which ramps from the - | current level, starts from silence on time. A pad or MIDI hit is not - | known in advance and plays as stock. - | - | Envelopes adds (Nathaniel Pavel): every voice's record then goes to - | envelopes_voice (envelopes.c), which puts this module's ATK rate into - | the attack's records, follows the voice's amp level and decides when - | the hold ends (HOLD 0 = no hold, 127 = AUTO, never before the attack's - | top). - | - | Rate word bit 30, which stock sets for ENV RESET FILTER, resets the - | level to 0 - the filter envelope's neutral point, but half gain on the - | amp - so it is not used here. + | Every voice's record goes to envelopes_voice (envelopes.c), which puts + | this module's ATK rate into the attack's records, follows the voice's + | amp level and decides when the hold ends (HOLD 0 = no hold, 127 = + | AUTO, never before the attack's top). - .equ VOICE_TRACK, 0x40291138 | voice -> track, bytes .equ WRITE_RESUME, 0x40109c2c | moveq #8,%d0, then the level word - .equ TRIG, 0x8000e508 | per track, long: 1 on a trig - .equ FADE_START, 0xb006a7ec | linear ramp from the current level - .equ FADE_GO_ON, 0x3006a7ec | the same ramp, continued - .equ FADE_LEVEL, 0x00000080 | to -128 - .equ ENV_RESET, 0x8000ea30 | per track, byte: bit 0 AMP (12 tracks) .text @@ -34,60 +15,21 @@ | word at 0x40109c24 (amp_env_commands 0x40109940), every block for each | voice, in every state, after stock's state machine. | - | For voice 0 it first runs envelopes_scan (pre-fade.c), which marks the - | voices a scheduled trig with AMP in its ENV RESET will restart within - | the fade; while no track has AMP in its ENV RESET it clears the mask - | instead, as the scan would. For a marked voice that is sounding and was - | not trigged this block, it sends a linear ramp to -128 instead of the - | state's command: the ramp (mode B) in its first block, then mode 3 with - | the same target and rate every block until the trig, as stock's own - | attack does. - | - | Then envelopes_voice, unless the voice's record is the one it last - | took and that one left the voice as it was (envelopes_gate, pre-fade.c): - | an idle voice (rate and level words 0) and a decay that has reached its - | end get the same record every block, so an idle unit makes no C call. + | It calls envelopes_voice unless the voice's record is the one it last + | took and that one left the voice as it was (envelopes_gate, + | envelopes.c): an idle voice (rate and level words 0) and a decay that + | has reached its end get the same record every block, so an idle unit + | makes no C call. | | d0 the rate word, d2 the level word, d3 the voice, a2 its state (-1 | idle; +4 the hold counter), a3 the frame at the voice's record, a4 the - | track's sound slice (+0 ATK, +2 HLD, +4 DEC). d1, d4 and a0 are written + | track's sound slice (+0 ATK, +2 HLD, +4 DEC). d1 and a0 are written | before they are read on the next pass, so they are free. | ------------------------------------------------------------------ .globl envelopes_write .align 2 envelopes_write: - tst.l %d3 - bne.s 1f - move.l ENV_RESET,%d1 | once a block: any track's AMP bit - or.l ENV_RESET+4,%d1 - or.l ENV_RESET+8,%d1 - andi.l #0x01010101,%d1 - bne.s 3f - clr.l envelopes_gate | no voice to fade - bra.s 1f -3: lea -16(%sp),%sp - movem.l %d0-%d1/%a0-%a1,(%sp) - jsr envelopes_scan - movem.l (%sp),%d0-%d1/%a0-%a1 - lea 16(%sp),%sp -1: move.l envelopes_gate,%d1 | the voices to fade - btst %d3,%d1 - beq.s 9f - tst.l (%a2) - bmi.s 9f | idle - lea VOICE_TRACK,%a0 - mvz.b (%a0,%d3.l),%d1 - lea TRIG,%a0 - moveq #1,%d4 - cmp.l (%a0,%d1.l*4),%d4 - beq.s 9f | trigged this block - move.l #FADE_GO_ON,%d0 - move.l envelopes_gate+4,%d1 | the fades that start now - btst %d3,%d1 - beq.s 2f - move.l #FADE_START,%d0 -2: move.l #FADE_LEVEL,%d2 -9: move.l envelopes_gate+8,%d1 | the voices left as they were + move.l envelopes_gate,%d1 | the voices left as they were btst %d3,%d1 beq.s 5f lea envelopes_gate+16,%a0 diff --git a/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c b/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c index 5d42441bc..d6b80edaf 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c +++ b/sdk/analog-rytm-mkii/modules/envelopes/src/envelopes.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // Envelopes (Nathaniel Pavel): the AMP envelope's HOLD order and ATK curve, and times on the -// envelope knobs, for the Analog Rytm MKII OS 1.74. ENV RESET AMP and its pre-fade are -// Env Reset Amp's (amp-write.s, pre-fade.c). +// envelope knobs, for the Analog Rytm MKII OS 1.74. // // HOLD (AMP page, id 57) keeps its stored byte, read as: 0 no hold, 1..126 the new hold // times (counted from the trig), 127 AUTO (hold while the note is on, stock's 0). The decay @@ -253,15 +252,18 @@ __attribute__((noinline)) static void follow(struct amp *a, uint32_t rate, uint3 a->level = d < 0 ? a->target + (int32_t)ad : a->target - (int32_t)ad; } +// The writer's skip state (amp-write.s reads it for every voice every block), kept together so a +// voice with nothing to do touches three 16-byte lines: [0] the voices whose last record left the +// level follower unchanged, [4 + v] and [12 + v] that record's rate and level words. +volatile uint32_t envelopes_gate[20] __attribute__((aligned(16))); +#define GATE_STILL envelopes_gate[0] +#define GATE_RATE(v) envelopes_gate[4 + (v)] +#define GATE_LW(v) envelopes_gate[12 + (v)] + // Called by envelopes_write (amp-write.s) for every voice every block, after stock's state // machine and before the record is stored; returns the rate word to store. st[0] is the // voice's state, st[1] its hold counter (cleared at the trig, +16 a block in state 2, already // added this block); snd[0] is the track's ATK, snd[2] its HLD. -extern volatile uint32_t envelopes_gate[20]; // pre-fade.c -#define GATE_STILL envelopes_gate[2] -#define GATE_RATE(v) envelopes_gate[4 + (v)] -#define GATE_LW(v) envelopes_gate[12 + (v)] - uint32_t envelopes_voice(int32_t v, volatile int32_t *st, const volatile int8_t *snd, uint32_t rate, uint32_t lw) { diff --git a/sdk/analog-rytm-mkii/modules/envelopes/src/pre-fade.c b/sdk/analog-rytm-mkii/modules/envelopes/src/pre-fade.c deleted file mode 100644 index b286dd46a..000000000 --- a/sdk/analog-rytm-mkii/modules/envelopes/src/pre-fade.c +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Envelopes: ENV RESET pre-fade (Nathaniel Pavel, from Env Reset Amp 1.1): fade a sounding voice out before a -// trig the Rytm schedules itself, so stock's attack, which ramps from the -// current level, restarts from silence without a click. -// -// The sequencer queues each track's next trig a step ahead, its probability -// already rolled, in the track's first event slot (state 1), and keeps the time -// it will fire at in the track's event times. Mutes are applied only when the -// trig fires, so they are read here the same way. Read in OS 1.74 and checked -// in rytm-emu: a queued trig always fired and an unqueued one never did, at 50 % -// and without a condition; a muted track's trig stays queued but does not fire. -// A retrig series (a trig's RTRG, or a pad held with RTRG) fires on its own -// tick counter, which stock steps once a tick (0x4012089a); the next hits are -// worked out the same way. Pads, MIDI and a trig queued less than the fade ahead -// (the first after PLAY) are not seen in time: those play as stock. - -#include - -#define TRACKS 12 -#define FADE_BLOCKS 10 // the fade starts up to 11 blocks (7.3 ms) before the trig - -#define CLOCK (*(volatile int32_t *)0x8000fe54) // musical clock, + 2 x TEMPO a block -#define TEMPO (*(volatile int32_t *)0x40287ffc) // BPM x 120 -#define EVENT(t) (*(volatile int32_t *)(0x8000fd50 + 12 * (t))) // next event's time -#define SLOT(t) (*(volatile int32_t *)(0x42ac5fb0 + 224 * (t))) // 1: a trig queued -#define TRACK_HELD(t) (*(volatile int32_t *)(0x42ad4c30 + 6668 * (t) + 6664)) -#define MUTES (*(volatile uint32_t *)0x8000ed98) -#define SOLOS (*(volatile uint32_t *)0x8000ed9c) -#define LIVE_MUTES (*(volatile uint16_t *)0x8000fc90) -#define ENV_RESET ((volatile uint8_t *)0x8000ea30) // [track] bit 0 amp -#define TRACK_VOICE ((const uint8_t *)0x4025a3a0) // [track] physical voice -#define TICK 90000 // clock units in a 240 PPQN tick -#define RT_TRIG(t) (*(volatile int32_t *)(0x42ac6b48 + 56 * (t))) // nonzero: a series runs -#define RT_RATE(t) (*(volatile int32_t *)(0x42ac6b48 + 56 * (t) + 36)) // RETRIG 0..16 -#define RT_COUNT ((volatile int32_t *)0x42adf5d0) // [track] 960..1, -1 a tick -#define RT_DEADLINE ((volatile int32_t *)0x8000fdec) // [track] its next tick's time -#define RT_FIRES ((const volatile uint16_t *)0x402909b8) // [count] bit RATE-1: fires - -// The amp writer's state (amp-write.s reads it for every voice every block), kept together so -// a voice with nothing to do touches three 16-byte lines: [0] the voices to fade this block, [1] of -// those, the voices whose fade starts now, [2] the voices whose last record left the level -// follower unchanged (envelopes.c), [4 + v] and [12 + v] that record's rate and level words. -volatile uint32_t envelopes_gate[20] __attribute__((aligned(16))); -#define envelopes_mask envelopes_gate[0] -#define envelopes_first envelopes_gate[1] - -// Clock units from now to track t's next retrig, as stock counts it, or -1 when -// none falls within window. A series that fires again sooner than twice the -// window gets half its spacing to fade in instead, so a fast roll still sounds. -static int32_t retrig_ahead(int t, int32_t clock, int32_t window) -{ - int32_t count = RT_COUNT[t], at = RT_DEADLINE[t] - clock, first = -1; - int rate = RT_RATE(t); - - // A deadline already past is a series stock no longer ticks. - if (rate < 0 || rate > 16 || at < -TICK) - return -1; - for (; at < 2 * window; at += TICK) { - if (--count <= 0) { - count = 960; - } else if (!(RT_FIRES[count] * 2 >> rate & 1)) { - continue; - } - if (first < 0) { - if (at >= window) - return -1; - first = at; - } else { - return first < (at - first) / 2 ? first : -1; - } - } - return first; -} - -// Called by the amp writer for voice 0, once a block, while a track's sound has AMP in its -// ENV RESET: the voices whose sound restarts its amp envelope on a scheduled trig or retrig -// within FADE_BLOCKS. With none, the writer clears the mask itself (as this finds). -void envelopes_scan(void) -{ - uint32_t mask = 0, muted; - int32_t window, clock = CLOCK; - int t; - - // As stock decides at the trig (0x4011ffde): solo mutes every other track. - muted = SOLOS ? ~SOLOS & ~0x1000u : MUTES; - muted |= LIVE_MUTES; - // The trig fires in the block its time falls in; the clock is this block's start. - window = (FADE_BLOCKS + 1) * 2 * TEMPO; - for (t = 0; t < TRACKS; t++) { - int32_t ahead; - - if ((muted >> t & 1) || !(ENV_RESET[t] & 1)) - continue; - ahead = -1; - if (SLOT(t) == 1 && !TRACK_HELD(t)) - ahead = EVENT(t) - clock; - if ((ahead < 0 || ahead >= window) && RT_TRIG(t)) - ahead = retrig_ahead(t, clock, window); - if (ahead >= 0 && ahead < window) - mask |= 1u << TRACK_VOICE[t]; - } - envelopes_first = mask & ~envelopes_mask; - envelopes_mask = mask; -} diff --git a/sdk/analog-rytm-mkii/modules/envelopes/upstream/README.md b/sdk/analog-rytm-mkii/modules/envelopes/upstream/README.md index 1a6f4088d..fd60fee80 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/upstream/README.md +++ b/sdk/analog-rytm-mkii/modules/envelopes/upstream/README.md @@ -1,54 +1,33 @@ -# env-reset-amp +# Improved Envelopes: origin -Port of rytm-mods-src `mods/0015-env-reset-amp` (MrScruff; hardware-verified there). +Improved Envelopes is Nathaniel Pavel's (@npp1993) own module, written for Modwerk; it is not a port +and has no upstream release. It began as an extension of Iced-Cream's Env Reset Amp (MrScruff's +rytm-mods 0015, ported to elemod), whose reading of the amp envelope's commands it builds on. From +0.1.0 it carries none of that module's code: ENV RESET AMP is Env Reset Amp's alone +(`../../env-reset-amp/`), and the two install side by side. -SOUND menu (FUNC + MUTE) > SOUND SETTINGS > ENV RESET now steps OFF, AMP, FILTER, AMP+FILT. With AMP -or AMP+FILT the amp envelope restarts from silence on every trig instead of continuing from its -current level, so AMP ATK is heard on every hit. A trig on a voice that is still sounding drops it -to silence at once, which can click (most with ATK 0 and a long DEC). The setting is the sound's, -saved with it. +## Sites (OS 1.74) -## How it hooks - -Three sites, as rytm-mods' registry: - -| addr | stock | new | why | +| addr | len | op | what | |---|---|---|---| -| 0x400bcf1e | `7402` moveq #2,%d2 | `7403` moveq #3,%d2 | ENV RESET's setter masked the amp bit off | -| 0x400ef86a | `d683` add.l %d3,%d3 | `4e71` nop | the menu stepped by two (OFF <-> FILTER) | -| 0x40109b04 | `0080b0000000` ori.l #0xb0000000,%d0 | `jmp env_reset_amp_attack` | the trig's amp attack command | - -The stub re-emits the `ori.l`, looks up the voice's track and its ENV RESET byte (0x8000ea30 + track), -and with bit 0 set sends stock's decay form at DEC 0 (rate 0xB0100000, level 0x80) instead; the hold -states that follow ramp up from silence at the ATK rate. It resumes at 0x40109b0a. It runs in the -voice-command routine (0x401098d4). - -## Changes from rytm-mods - -- The shipping code is unchanged. The label `amp_attack` is renamed `env_reset_amp_attack` (global - labels carry the mod id) and is the only `.globl`. -- The `bit_probe` diagnostic is not ported: it needs a fourth patch (0x40109aae) only that build - carries. The source sets `P_BIT_PROBE` to 0, so the probe's code is not assembled. -- It runs from the elemod DDR area instead of cave13 (0x400298e4). - -## Test (on a unit) - -1. Pick an analog BD sound, AMP ATK about 40, DEC long (100+). -2. Stock ENV RESET (OFF or FILTER): hit the pad quickly several times; the attack is heard on the - first hit only. -3. Set ENV RESET to AMP: every hit now fades in at the ATK rate. -4. ENV RESET steps OFF / AMP / FILTER / AMP+FILT with the arrows. - -## Results so far - -- Hardware: on an Analog Rytm MKII, 2026-10-13, in a build of core-ar2 with filter-hz, ctrl-all, - env-reset-amp and slice-loop: works as described (ENV RESET values and the - amp restart). -- `.run` 52 B (50 B of code), 3 sites, no relocations; lint OK; links with core-ar2 0.1. -- The 50 B of code are byte-identical to the stub in rytm-mods-src's default build (cave13, - 0x400298e4); the two byte sites match that build byte for byte; the probe's patch site is stock in - both. -- rytm-emu, the four-mod build above: ENV RESET steps FILTER -> AMP -> OFF and OFF -> AMP -> FILTER -> AMP+FILT - (stock: FILTER <-> OFF only); with AMP chosen, BD's ENV RESET byte in the engine reads 01 (stock - 00). Three BD pad hits reach the attack site and resume at 0x40109b0a on both builds. The - emulator's voice model is not used to judge the sound: that needs the unit. +| 0x40109c24 | 8 | jmp `envelopes_write` | the amp record write in `amp_env_commands`, every voice every block | +| 0x400d3302 | 6 | jsr `envelopes_amp_graph` | the AMP page's envelope picture (HLD 127 drawn as AUTO, 0 as no hold) | +| 0x4010d2aa | 4 | ptr `envelopes_flt_atk` | FILTER ATK rate table | +| 0x40109bc4 | 4 | ptr `envelopes_hold` | AMP HLD compare | +| 0x40109bf0 | 4 | ptr `envelopes_amp_dec` | AMP DEC record | +| 0x4010d344, 0x4010d3b4, 0x4010d3dc | 4 each | ptr `envelopes_flt_dec` | FILTER DEC and REL records | + +Addresses, lengths and SHA-256 guards are in `../build.json`; no stock bytes are included. + +## Beside Env Reset Amp + +Env Reset Amp takes state 0's `ori.l` at 0x40109b70 and, with AMP in a track's ENV RESET, sends a +drop to silence (rate 0xb0100000, level 0x80) in place of the trig's attack record (level +0x4000007f). Envelopes then never sees that record, so stock picks the state after the trig as it +always does (0x40109b5a: HLD byte 0 gives state 1, the gate; any other value state 2, timed), with +the hold counter cleared. From the next block the voice sends the continued attack (level 0x7f), +which Envelopes rewrites to its ATK curve and on which it applies its HOLD rule: HLD 127 turns +state 2 into the gate, any other value sets 2 or 3 by the hold time and the attack's top. Its level +follower takes the drop as an instant one-pole fall to -128. So the attack still runs from silence +on Envelopes' curve, the hold still counts from the trig, and the decay never starts before the +top. Read in OS 1.74's code, not yet run on the unit. diff --git a/sdk/imports/envelopes-2026-11-07.json b/sdk/imports/envelopes-2026-11-07.json index d1ca882d2..88d4eeb29 100644 --- a/sdk/imports/envelopes-2026-11-07.json +++ b/sdk/imports/envelopes-2026-11-07.json @@ -4,7 +4,7 @@ "version": "0.1.0-experimental", "date": "2026-11-07", "changes": [ - "First release. The AMP envelope reworked: AMP HLD runs from no hold (0) to AUTO (127) without cutting the attack; ATK, AMP DEC, FILTER DEC and REL and AMP HLD get fine steps at short times (0.2 ms to 5 ms); every envelope knob shows its time; FUNC + turn on HLD steps 0, 124.7 ms, AUTO; SOUND SETTINGS > ENV RESET gains AMP (Env Reset Amp, with a pre-fade)." + "First release. The AMP envelope reworked: AMP HLD runs from no hold (0) to AUTO (127) without cutting the attack; ATK, AMP DEC, FILTER DEC and REL and AMP HLD get fine steps at short times (0.2 ms to 5 ms); every envelope knob shows its time; FUNC + turn on HLD steps 0, 124.7 ms, AUTO. Installs beside Env Reset Amp, which keeps ENV RESET AMP." ], "runtimeSourceSha256": "75e8f25452c379aaffba31095e59e1978a09f3acc227e659ebd20d2c088375ee", "packages": [ diff --git a/src/community/module-changelogs/analog-rytm-mkii-envelopes.json b/src/community/module-changelogs/analog-rytm-mkii-envelopes.json index 995158dfd..24b19dbfe 100644 --- a/src/community/module-changelogs/analog-rytm-mkii-envelopes.json +++ b/src/community/module-changelogs/analog-rytm-mkii-envelopes.json @@ -6,7 +6,7 @@ "First release, for Analog Rytm MKII OS 1.74: the AMP envelope reworked, and every envelope knob shows its time.", "AMP HLD runs from no hold (0) to AUTO (127) and never cuts the attack; FUNC + turn jumps 0, 125 ms, AUTO.", "ATK, AMP DEC and FILTER DEC/REL step 0.2 ms up to 5 ms, then finer than stock up to 300 ms; HLD steps 0.67 ms.", - "SOUND SETTINGS > ENV RESET gains AMP: sequenced trigs and retrig rolls restart from silence (Env Reset Amp).", + "Installs beside Env Reset Amp, which keeps ENV RESET AMP.", "Saved projects play their HLD, ATK, DEC and REL on the new curves." ] } From 2c53a2207051e8258e4a37e4cc5dba10adb211fa Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Sat, 7 Nov 2026 09:49:40 -0600 Subject: [PATCH 08/11] Improved Envelopes: rebuilt 0.1.0 package without ENV RESET, 5,228 bytes Built by build-elemod-isolated.sh in modwerk-source-tools (39efd52a) from ed0cac207; package-elemod-recipe.mjs --check reproduces it and verify-elemod-release-exports.mjs reproduces all 49 exports. Linked on the plain base ba530f45: ramSpare 113,776 alone (EN02) and beside Env Reset Amp 1.0.0 (EN03). Co-Authored-By: Claude Opus 5.5 --- .../modules/envelopes/README.md | 2 +- .../modules/envelopes/modwerk.module.json | 2 +- sdk/imports/envelopes-2026-11-07.json | 4 +- ...envelopes-0.1.0-experimental-os1.74.elemod | 252 ++++++------------ 4 files changed, 79 insertions(+), 181 deletions(-) diff --git a/sdk/analog-rytm-mkii/modules/envelopes/README.md b/sdk/analog-rytm-mkii/modules/envelopes/README.md index 9646f5033..18b93fa27 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/README.md +++ b/sdk/analog-rytm-mkii/modules/envelopes/README.md @@ -96,7 +96,7 @@ the AMP page picture and the amp and filter envelope tables. It needs no other m Measured on the author's Analog Rytm MKII over USB (builds EV04 to ED02, in combined sets of up to 16 modules), with rytm-emu for the screens ([TESTING.md](TESTING.md)): AMP DEC within 0.7 % of its text from 5 ms, AMP HLD within 0.1 ms, FILTER ATK within 0.3 %, FILTER DEC and REL 1.5 % (the method's). -Memory: 5,900 bytes of the shared mod area (the base alone leaves 119,004, with this module 113,104). +Memory: 5,228 bytes of the shared mod area (the plain base alone leaves 119,004, with this module 113,776). Load: the amp record write runs every block for every voice; an idle voice makes no C call there. ## Authorship and licences diff --git a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json index e40c84cdc..3da364f7e 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json +++ b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json @@ -101,7 +101,7 @@ ] }, "resources": { - "memoryBytes": null, + "memoryBytes": 5228, "fastBytes": null, "load": { "display": "Not measured yet", diff --git a/sdk/imports/envelopes-2026-11-07.json b/sdk/imports/envelopes-2026-11-07.json index 88d4eeb29..6f6b9b0c9 100644 --- a/sdk/imports/envelopes-2026-11-07.json +++ b/sdk/imports/envelopes-2026-11-07.json @@ -6,12 +6,12 @@ "changes": [ "First release. The AMP envelope reworked: AMP HLD runs from no hold (0) to AUTO (127) without cutting the attack; ATK, AMP DEC, FILTER DEC and REL and AMP HLD get fine steps at short times (0.2 ms to 5 ms); every envelope knob shows its time; FUNC + turn on HLD steps 0, 124.7 ms, AUTO. Installs beside Env Reset Amp, which keeps ENV RESET AMP." ], - "runtimeSourceSha256": "75e8f25452c379aaffba31095e59e1978a09f3acc227e659ebd20d2c088375ee", + "runtimeSourceSha256": "8a7323f7932374f2f1759b0c37bca786970855265433bcf31c7ef9e05b5a9424", "packages": [ { "os": "1.74", "path": "sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod", - "sha256": "f9779b13edaf0d838b3539cc6bf7a4ae16a66b1e918ccac9f3cf82c6ab7f328c" + "sha256": "3c5016aebe69610e3406a0d6839fdb91a1a97caf6b3538907c2e16d76046dc30" } ], "stockPolicy": "No firmware or stock-derived code/tables are present. Addresses, lengths and SHA-256 guards are metadata; exported instructions and sections are authored module code. Local materialized recipes and firmware are never committed.", diff --git a/sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod b/sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod index 1ae7ceaca..77f987e78 100644 --- a/sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod +++ b/sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod @@ -3,7 +3,7 @@ "id": "envelopes", "version": "0.1.0-experimental", "title": "Improved Envelopes", - "description": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", + "description": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, and the envelope knobs show times.", "category": "machines", "author": "npp1993", "license": "GPL-2.0-only", @@ -18,11 +18,11 @@ "sections": { ".run": { "align": 4, - "len": 5808, + "len": 5136, "parts": [ [ "hex", - "4a83663822398000ea3082b98000ea3482b98000ea38028101010101660842b90000000060164feffff048d703034eb9000000004cd703034fef0010223900000000070167384a926b3441f94029113873b0380041f98000e5087801b8b01c00671c203c3006a7ec22390000000007016706203cb006a7ec243c000000802239000000000701671241f900000000b0b03c006606b4b03c2067284feffff048d703032f022f002f0c2f0a2f034eb9000000002f4000144fef00144cd703034fef0010274000ac274000ec4ef940109c2c202f001c0c8000007f006d0642af001c600a4a806e0670012f40001c4ef940038bce00004fefffd048d77cfc22798000fe544ab98000ed9c670001a220398000ed9c46800880000c7df98000fc90283940287ffc7a16267c42ad66384283287c8000fd509dce4c045800247c42adf5d0207c42ac6b488c80702c4c004800070666262a43dbfc8000ea30101508000000671620087201e5882a40dbfc37fab290b295673c4a906674528341e80038588a49ec000c740c47eb1a0cb48366c0203900000000220e4680c28023c10000000023ce000000004cd77cfc4fef00304e754a9366c0201490896bbab0856cb62a7c4025a3a0700173b5380041e800385283588a49ec000c740ce3a8220e47eb1a0c82802c41b4836600ff6660a22a7c3d53081c74102e12dbca201522280024b4816500ff7690890c80fffea0706d00ff6ab0846c00ff647401e3aa2a4372ff2f48002c260253872407d4824a876f560682402909b8204275d0d482c4834a82670c4a816c4ab0856c0000a42200068000015f90b0846dce206f002c260d4a816d00ff18b2856d00ff58528341e80038588a49ec000c740c47eb1a0cb4836600fed06000ff0c2e3c000003c04a816db6908120006a025280206f002c260de280b2806c00fed6b2856cc06000ff1420398000ed987a167df98000fc90283940287ffc267c42ad6638287c8000fd504283247c42adf5d09dce8c804c045800702c4c004800207c42ac6b486000fe64206f002c260d588a528341e80038740c49ec000c47eb1a0cb4836600fe466000fe820000598f2f03701c2f027602222f00142401e0aa70f7206f0010c082b680670000b84a806700009c44c266000106202f0018e088710048404240224020802401760ee7aa7614712f001b484042402f4200082401e6a942030282000fffff214000041143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff80002141000824009489b3c0672222424a826d7c222800084a28000c663ee6896778b3c1630893c14a826d7690892080241f261f588f4e754a28000d66f220280004240022509489b3c066c260e270011140000d241f261f588f4e750c8107ffffff62caec89263c0000045c4c031800760fe6a952810c810001000064b02609e08b4c031800e08993c14a826c9e60122202448122416000ff7c7201b3c16286608cd0892080608822507609b6826600ff042401760ee7aa7614202800042f4200082401e6a942030282000fffff1143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff8000214100086000ff082f02202f000c2200e0814aaf00106f1a4a816d267429b4816c30747eb4816c200280ffffff00241f4e75747fb4816d10742ab4816d144a816fe6241f42804e75241f203c00007f004e75241f203c00002a004e754fefffe448d7401c222f0024780a2401260f4c4420004c4420024def001206830000001c204e43e8000106800000003010807009b08164262202b68967202401780a4c4420004c442002204943e8000106800000003010807009b08165da7001908e226f0020d08841f6080012e0bdc866fa4cd7401cd0af00204fef001c4e75226f0008206f0004101910c066fa4e75518f2f02202f0014206f00100c8002625a006306203c02625a00720a74174c00180006810000000cb481645c0c81000012bf630000a8220006810000000c0c810000bb7f630000de22000681000004b00c8100249eff6346068000002ee0243c00005dc04c4200002f002f084ebaff02508f223c000000002f4100142f400010241f508f6000ff6a203c000000002f4000142f480010241f508f6000ff54243c000009604c42100143fafec6700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c00000000609c74184c42100143fafe8c700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c000000002f4100142f400010241f508f6000fece74184c4210012f012f084ebafe40508f223c000000002f4100142f400010241f508f6000fea84fefffec48d7007c242f00182202d2816afcd48242414841307c001e4284700f04c291c2340176017c0fe1ab5380c4c12202eca94a826c08220242414841888374ffb48066de200848404240d0844cd7007c4fef00144e752f02740e222f00082001e5a8740f4241484102803fffc0002040203c7fffffff9088e2a822000681ffff8000b48164560c8101ffffff632c0c817ffeffff6250203c7fffffff90812f004ebaff5c721f4841588f9280203c0009f73e4c410000241f4e757412e888e4a93401c4c122000681fffff800203c37431533d2824c410000241f4e75241f203c7fffffff4e75241f42804e752f02740e202f000c2200e5a94240484002813fffc0002041720fc081223c7fffffff9288e0a90681ffff80004a816712202f00087417e5a84c410000241f52804e75241f203c7fffffff4e75518f2f0a727f2f02206f001420280008e0802240b2806c30327c007f2228000474080681ffffffceb4816532323b1a0848c14efb180200f2003200280032002800280120006600904a806cd02228000493c90681ffffffce7408b48164ce241f4280245f508f4e7545f90000000020329c000280000fffff2f002f48000c4ebafe9e206f000c2e802f28000c4ebafcee508f7001241f245f508f4e752228000c747eb4806d00013c4a806f00011241f90000000020309c002f002f014ebafcbe508f700160ce2068000c727e2f48000cb2806d0000fa41f90000000024309c000282000fffff2f02740a4ebafe32588f2200e4a90280000003ff243c000003ac4c021800740ac0fc03ac068000000200e4a82040487018002f2f00104ebafc5e508f70016000ff6e45f9000000002f329c004878007f2f4800104ebafe78588f206f000c2e802f28000c4ebafc30508f70016000ff4045f900000000740c71f29a002200e4a8e989740a4840424073c180812f00487800ff2f4800104ebafe36508f2200e4a90280000003ff243c000003d44c021800740ac0fc03d4068000000200e4a8224048711800206f000c2f28000c4ebafbc8508f70016000fed842802f002f014ebafbb6508f6000fef64879000000002f084ebafb94508f70016000feb44879000000002f014ebafb80508f70016000fea04fefffc8700748d7041cc0af003c206f00447401262f004c73280002e1aa2f41001e3200c2fc000e0681000000000c834000007f67000158760e4c00380043f900000000283138002f440022787fb8af004c6700008a41f1380028280008246800042f4400261828000c2f4a001a45e800041f4400321828000d1f4400332f2f004c2f2f004c2f4a00262808508445e8000c41e8000d2f4a00362f48003c2f4400322f012f40001e2f4900224ebaf86c4fef000c226f0016222f0022202f0012b2b13800670001184682c5b900000000202f00484cd7041c4fef00384e75282f004871100284fff0000020444a806d00018a43f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6700018c226f0040760220515388b688650001864aaf001e6f00019a282f001e41f90000000022704c00246f0040206a000441e8fff1b3c86c0001a0262f00220c83007e7fff6f000192307c00034878007f2f00226f004822882f012f40001e4ebaf7a24fef000c202f00124682c5b9000000006000ff48262f004871100283fff0000020434a806d0000a243f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e670000a4307c00022f3c4000007f2f00226f004822886092222f001a246f001eb2926600fede226f0026206f002ab3d06600fed0246f002e73af00327792b6816600fec0206f003473af00337790b2836600feb0222f0048262f004c41f90000000021810c1021830c3085b90000000020014cd7041c4fef00384e75428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600ff60307c00012f3c4000007f6000ff5c428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600fe78206f00407602b69067224878007f2f002f012f40001e4ebaf65e4fef000c202f00126000feba93c96000fe724878007f76012f0020832f012f40001e4ebaf6384fef000c202f00126000fe94307c00024878007f6000fe6e203c00000000b0b9419a5b8c6718203c400fe58423c0419a5b88203c0000000023c0419a5b8c4e750000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000000000320000003a00000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000011000000130000001500000017000000190000001b00000020000000250000002a0000002f00000034000000390000003e00000043000000480000004d00000057000000610000006b000000750000007f00000089000000930000009d000000a7000000b1000000bb000000c5000000cf000000d9000000e3000000f70000010b0000011f00000133000001470000015b0000016f0000018300000197000001ab000001bf000001d9000001f5000002130000023200000253000002760000029b000002c3000002ec000003190000034700000379000003ad000003e50000041f0000045d0000049f000004e50000052f0000057d000005d00000062800000685000006e70000074f000007bd00000832000008ae00000931000009bb00000a4e00000aea00000b8e00000c3d00000cf500000db900000e8800000f630000104b0000114100001246000013590000147d000015b2000016fa00001855000019c400001b4800001ce400001e98000020660000224e0000245400002678000028bd00002b2300002dae0000305f000033390000363e0000397100003cd300004069000044350000483a00004c7c000050fe000055c400005ad200005ad2000000000000079680000f951000179ce0001ca900001ffe000024b38000283620002aeca0002d1540002ed76000309a300033108000352b300036fcf0003893900039f9b0003b3770003c5350003d5270003e38f0003f0a40003fc9300040f01000423180004359f00045e330004802d00049d0b0004b5de0004cb730004de620004ef200004fe09000516ce00052ee7000544bc0005589c00056ac700057b7300058acd000598fd0005a6220005b25a0005bdbc0005c85e0005dba70005ecb00005fbd9000612da00062b4e0006417300065597000667fe000678df000688680006aa540006c69f0006de950006f322000709eb0007291f000744ab00075d2a00077316000786d40007a8ef0007c55f0007dd710007f215000807f400082747000842eb00085b7f0008717d000885490008a77d0008c3ff0008dc1f0008f0ce00090579000924da0009408b0009592900096f30000983040009ace00009ce5e0009e9c6000a013b000a3f51000a75bc000aa570000acf40000af3e6000b280c000b605d000b91b9000bbcfd000be2e9000c084d000c4291000c75a2000ca265000cc9a1000cec04000d144f000d4924000d7772000da008000dc39b000de2c9000dfe1c000e2c20000e561d000e7ae9000e9b2a000eb76f000ed035000ee5ed000ef8f5000f1349000f3087000f4a27000f609f000f744f000f8591000f94b1000000000000889d000110f20001933b0001dff50002246e00026b3900029fbb0002c8360002e85d0003050800033065000354ef0003742300038f180003a69d0003bb510003cdae0003de140003eccf0003fa1d00040c640004226b000436960004491f00045a3600047fa100049ef30004b98d0004d06c0004e44c0004f5bb00050a4a000525bd00053e57000554840005689b00057ae400058b9b00059af10005a9100005b61c0005c2330005cd6f0005d7e60005e1ad0005f368000606240006220300063af800065172000665cb0006784e00068937000698ba0006a7000006c62b0006e02a0006f62d0007121e000732dc00074f86000768d300077f53000793760007a5970007c4eb0007df080007f523000810300008310d00084dd00008673200087dc3000891f50008a4220008c38a0008ddb70008f3de00090db900092ea500094b74000964e100097b7b00098fb40009a1e80009c8570009e716000a0080000a2a71000a6370000a9566000ac131000ae793000b1272000b4d6e000b8121000bae71000bd629000bf8f9000c2ef9000c6477000c9358000cbc70000ce074000d000b000d3761000d67e1000d9263000db7a5000dd84d000df4ec000e1c05000e47ff000e6e8a000e9052000eaded000ec7e1000ede9f000ef28f000f0811000f26b1000f4189000f5911000f6daf000f7fc3000f8f9b000f9d7d000000000002f499000427510004d0970005412800059e5b0005db6000060cd900064cd800067e490006a5a00006c5ad0006e04a0006f6be000713e1000735150007521400076ba00007824c0007968e0007a8c40007b93a0007c82d0007d5d00007e24e0007edca00080da20008374900085a7d000878a2000892bc0008a98f0008bdaf0008cf900008df8c0008edee0008faf000090d8500092319000936de0009490e000959d60009695f000977cc00098538000991bf0009b1e20009cf290009e9d6000a044a000a3095000a58f2000a7dba000a9f3e000abdc9000ad99f000af2fc000b1435000b3e58000b64bf000b87be000ba7a4000bc4b6000bdf36000bf75c000c1abe000c42dd000c676f000c88c4000ca725000cc2d6000cdc13000cf315000d101a000d3653000d592a000d78ec000d95de000db040000dc84d000dde38000df233000e08d4000e2a07000e484a000e63df000e7d04000e93ef000ea8d2000ebbdd000ecd38000edd0a000eeb75000ef89a000f092b000f1f03000f32eb000f4511000f559b000f64af000f726d000f7ef5000f8a5f000f94c9000f9e45000fa6eb000faecd000fb5fb000fbc89000fc281000fc7f1000fcce7000fd16d000fd58b000fd94d000fdcb9000fdfd9000fe2b1000fe549000fe7a7000fe9cd000febc5000fed8f000fef31000ff0ad000ff209000ff345000ff4650000203f33c33dd8453d4ad04e76521555ea58e05b3c5d285ec06032627f647d663a67c3691f6a566b6d6c6a6d506e216ee16f92722474a476c178907a217b807cb57dc87ebd7f9a80c58230837c84ab85c386c587b4889189608a208c0e8dd08f6a91bf946896d499099b0d9ce29e8ea028a2eea576a7c4a9deabc9ad87af1fb124b3c9b631b863ba64bc37bde0bf64c18cc411c65cc874ca5ccc19cdafcf20d0e3d349d579d777d948daf0dc73ddd3df14e072e288e46ee629e7bde92eea7debafecc6edc5eeacef80f081f1e0f320f443f54df640f71cf7e6f89df945f9ddfa68fae7fb5afbc4fc24fc7bfccbfd13fd56fd92fdc9fdfbfe29fe53fe79fe9b30006d730073004155544f00494e4600" + "2239000000000701671241f900000000b0b03c006606b4b03c2067284feffff048d703032f022f002f0c2f0a2f034eb9000000002f4000144fef00144cd703034fef0010274000ac274000ec4ef940109c2c202f001c0c8000007f006d0642af001c600a4a806e0670012f40001c4ef940038bce598f2f03701c2f027602222f00142401e0aa70f7206f0010c082b680670000b84a806700009c44c266000106202f0018e088710048404240224020802401760ee7aa7614712f001b484042402f4200082401e6a942030282000fffff214000041143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff80002141000824009489b3c0672222424a826d7c222800084a28000c663ee6896778b3c1630893c14a826d7690892080241f261f588f4e754a28000d66f220280004240022509489b3c066c260e270011140000d241f261f588f4e750c8107ffffff62caec89263c0000045c4c031800760fe6a952810c810001000064b02609e08b4c031800e08993c14a826c9e60122202448122416000ff7c7201b3c16286608cd0892080608822507609b6826600ff042401760ee7aa7614202800042f4200082401e6a942030282000fffff1143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff8000214100086000ff082f02202f000c2200e0814aaf00106f1a4a816d267429b4816c30747eb4816c200280ffffff00241f4e75747fb4816d10742ab4816d144a816fe6241f42804e75241f203c00007f004e75241f203c00002a004e754fefffe448d7401c222f0024780a2401260f4c4420004c4420024def001206830000001c204e43e8000106800000003010807009b08164262202b68967202401780a4c4420004c442002204943e8000106800000003010807009b08165da7001908e226f0020d08841f6080012e0bdc866fa4cd7401cd0af00204fef001c4e75226f0008206f0004101910c066fa4e75518f2f02202f0014206f00100c8002625a006306203c02625a00720a74174c00180006810000000cb481645c0c81000012bf630000a8220006810000000c0c810000bb7f630000de22000681000004b00c8100249eff6346068000002ee0243c00005dc04c4200002f002f084ebaff02508f223c000000002f4100142f400010241f508f6000ff6a203c000000002f4000142f480010241f508f6000ff54243c000009604c42100143fafec6700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c00000000609c74184c42100143fafe8c700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c000000002f4100142f400010241f508f6000fece74184c4210012f012f084ebafe40508f223c000000002f4100142f400010241f508f6000fea84fefffec48d7007c242f00182202d2816afcd48242414841307c001e4284700f04c291c2340176017c0fe1ab5380c4c12202eca94a826c08220242414841888374ffb48066de200848404240d0844cd7007c4fef00144e752f02740e222f00082001e5a8740f4241484102803fffc0002040203c7fffffff9088e2a822000681ffff8000b48164560c8101ffffff632c0c817ffeffff6250203c7fffffff90812f004ebaff5c721f4841588f9280203c0009f73e4c410000241f4e757412e888e4a93401c4c122000681fffff800203c37431533d2824c410000241f4e75241f203c7fffffff4e75241f42804e752f02740e202f000c2200e5a94240484002813fffc0002041720fc081223c7fffffff9288e0a90681ffff80004a816712202f00087417e5a84c410000241f52804e75241f203c7fffffff4e75518f2f0a727f2f02206f001420280008e0802240b2806c30327c007f2228000474080681ffffffceb4816532323b1a0848c14efb180200f2003200280032002800280120006600904a806cd02228000493c90681ffffffce7408b48164ce241f4280245f508f4e7545f90000000020329c000280000fffff2f002f48000c4ebafe9e206f000c2e802f28000c4ebafcee508f7001241f245f508f4e752228000c747eb4806d00013c4a806f00011241f90000000020309c002f002f014ebafcbe508f700160ce2068000c727e2f48000cb2806d0000fa41f90000000024309c000282000fffff2f02740a4ebafe32588f2200e4a90280000003ff243c000003ac4c021800740ac0fc03ac068000000200e4a82040487018002f2f00104ebafc5e508f70016000ff6e45f9000000002f329c004878007f2f4800104ebafe78588f206f000c2e802f28000c4ebafc30508f70016000ff4045f900000000740c71f29a002200e4a8e989740a4840424073c180812f00487800ff2f4800104ebafe36508f2200e4a90280000003ff243c000003d44c021800740ac0fc03d4068000000200e4a8224048711800206f000c2f28000c4ebafbc8508f70016000fed842802f002f014ebafbb6508f6000fef64879000000002f084ebafb94508f70016000feb44879000000002f014ebafb80508f70016000fea04fefffc8700748d7041cc0af003c206f00447401262f004c73280002e1aa2f41001e3200c2fc000e0681000000000c834000007f67000158760e4c00380043f900000000283138002f440022787fb8af004c6700008a41f1380028280008246800042f4400261828000c2f4a001a45e800041f4400321828000d1f4400332f2f004c2f2f004c2f4a00262808508445e8000c41e8000d2f4a00362f48003c2f4400322f012f40001e2f4900224ebaf86c4fef000c226f0016222f0022202f0012b2b13800670001184682c5b900000000202f00484cd7041c4fef00384e75282f004871100284fff0000020444a806d00018643f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e67000188226f0040760220515388b688650001824aaf001e6f000196282f001e41f90000000022704c00246f0040206a000441e8fff1b3c86c00019c262f00220c83007e7fff6f00018e307c00034878007f2f00226f004822882f012f40001e4ebaf7a24fef000c202f00124682c5b9000000006000ff48262f004871100283fff0000020434a806d00009e43f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e670000a0307c00022f3c4000007f2f00226f004822886092222f001a246f001eb2926600fede226f0026206f002ab3d06600fed0246f002e73af00327792b6816600fec0206f003473af00337790b2836600feb0222f004841f900000000262f004c21810c1021830c30859020014cd7041c4fef00384e75428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600ff64307c00012f3c4000007f6000ff60428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600fe7c206f00407602b69067224878007f2f002f012f40001e4ebaf6624fef000c202f00126000febe93c96000fe764878007f76012f0020832f012f40001e4ebaf63c4fef000c202f00126000fe98307c00024878007f6000fe72203c00000000b0b9419a5b8c6718203c400fe58423c0419a5b88203c0000000023c0419a5b8c4e750000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000000000320000003a00000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000011000000130000001500000017000000190000001b00000020000000250000002a0000002f00000034000000390000003e00000043000000480000004d00000057000000610000006b000000750000007f00000089000000930000009d000000a7000000b1000000bb000000c5000000cf000000d9000000e3000000f70000010b0000011f00000133000001470000015b0000016f0000018300000197000001ab000001bf000001d9000001f5000002130000023200000253000002760000029b000002c3000002ec000003190000034700000379000003ad000003e50000041f0000045d0000049f000004e50000052f0000057d000005d00000062800000685000006e70000074f000007bd00000832000008ae00000931000009bb00000a4e00000aea00000b8e00000c3d00000cf500000db900000e8800000f630000104b0000114100001246000013590000147d000015b2000016fa00001855000019c400001b4800001ce400001e98000020660000224e0000245400002678000028bd00002b2300002dae0000305f000033390000363e0000397100003cd300004069000044350000483a00004c7c000050fe000055c400005ad200005ad2000000000000079680000f951000179ce0001ca900001ffe000024b38000283620002aeca0002d1540002ed76000309a300033108000352b300036fcf0003893900039f9b0003b3770003c5350003d5270003e38f0003f0a40003fc9300040f01000423180004359f00045e330004802d00049d0b0004b5de0004cb730004de620004ef200004fe09000516ce00052ee7000544bc0005589c00056ac700057b7300058acd000598fd0005a6220005b25a0005bdbc0005c85e0005dba70005ecb00005fbd9000612da00062b4e0006417300065597000667fe000678df000688680006aa540006c69f0006de950006f322000709eb0007291f000744ab00075d2a00077316000786d40007a8ef0007c55f0007dd710007f215000807f400082747000842eb00085b7f0008717d000885490008a77d0008c3ff0008dc1f0008f0ce00090579000924da0009408b0009592900096f30000983040009ace00009ce5e0009e9c6000a013b000a3f51000a75bc000aa570000acf40000af3e6000b280c000b605d000b91b9000bbcfd000be2e9000c084d000c4291000c75a2000ca265000cc9a1000cec04000d144f000d4924000d7772000da008000dc39b000de2c9000dfe1c000e2c20000e561d000e7ae9000e9b2a000eb76f000ed035000ee5ed000ef8f5000f1349000f3087000f4a27000f609f000f744f000f8591000f94b1000000000000889d000110f20001933b0001dff50002246e00026b3900029fbb0002c8360002e85d0003050800033065000354ef0003742300038f180003a69d0003bb510003cdae0003de140003eccf0003fa1d00040c640004226b000436960004491f00045a3600047fa100049ef30004b98d0004d06c0004e44c0004f5bb00050a4a000525bd00053e57000554840005689b00057ae400058b9b00059af10005a9100005b61c0005c2330005cd6f0005d7e60005e1ad0005f368000606240006220300063af800065172000665cb0006784e00068937000698ba0006a7000006c62b0006e02a0006f62d0007121e000732dc00074f86000768d300077f53000793760007a5970007c4eb0007df080007f523000810300008310d00084dd00008673200087dc3000891f50008a4220008c38a0008ddb70008f3de00090db900092ea500094b74000964e100097b7b00098fb40009a1e80009c8570009e716000a0080000a2a71000a6370000a9566000ac131000ae793000b1272000b4d6e000b8121000bae71000bd629000bf8f9000c2ef9000c6477000c9358000cbc70000ce074000d000b000d3761000d67e1000d9263000db7a5000dd84d000df4ec000e1c05000e47ff000e6e8a000e9052000eaded000ec7e1000ede9f000ef28f000f0811000f26b1000f4189000f5911000f6daf000f7fc3000f8f9b000f9d7d000000000002f499000427510004d0970005412800059e5b0005db6000060cd900064cd800067e490006a5a00006c5ad0006e04a0006f6be000713e1000735150007521400076ba00007824c0007968e0007a8c40007b93a0007c82d0007d5d00007e24e0007edca00080da20008374900085a7d000878a2000892bc0008a98f0008bdaf0008cf900008df8c0008edee0008faf000090d8500092319000936de0009490e000959d60009695f000977cc00098538000991bf0009b1e20009cf290009e9d6000a044a000a3095000a58f2000a7dba000a9f3e000abdc9000ad99f000af2fc000b1435000b3e58000b64bf000b87be000ba7a4000bc4b6000bdf36000bf75c000c1abe000c42dd000c676f000c88c4000ca725000cc2d6000cdc13000cf315000d101a000d3653000d592a000d78ec000d95de000db040000dc84d000dde38000df233000e08d4000e2a07000e484a000e63df000e7d04000e93ef000ea8d2000ebbdd000ecd38000edd0a000eeb75000ef89a000f092b000f1f03000f32eb000f4511000f559b000f64af000f726d000f7ef5000f8a5f000f94c9000f9e45000fa6eb000faecd000fb5fb000fbc89000fc281000fc7f1000fcce7000fd16d000fd58b000fd94d000fdcb9000fdfd9000fe2b1000fe549000fe7a7000fe9cd000febc5000fed8f000fef31000ff0ad000ff209000ff345000ff4650000203f33c33dd8453d4ad04e76521555ea58e05b3c5d285ec06032627f647d663a67c3691f6a566b6d6c6a6d506e216ee16f92722474a476c178907a217b807cb57dc87ebd7f9a80c58230837c84ab85c386c587b4889189608a208c0e8dd08f6a91bf946896d499099b0d9ce29e8ea028a2eea576a7c4a9deabc9ad87af1fb124b3c9b631b863ba64bc37bde0bf64c18cc411c65cc874ca5ccc19cdafcf20d0e3d349d579d777d948daf0dc73ddd3df14e072e288e46ee629e7bde92eea7debafecc6edc5eeacef80f081f1e0f320f443f54df640f71cf7e6f89df945f9ddfa68fae7fb5afbc4fc24fc7bfccbfd13fd56fd92fdc9fdfbfe29fe53fe79fe9b30006d730073004155544f00494e4600" ] ] }, @@ -32,93 +32,69 @@ } }, "symbols": { - "VOICE_TRACK": [ - "abs", - 1076433208 - ], "WRITE_RESUME": [ "abs", 1074830380 ], - "TRIG": [ - "abs", - 2147542280 - ], - "FADE_START": [ - "abs", - 2953226220 - ], - "FADE_GO_ON": [ - "abs", - 805742572 - ], - "FADE_LEVEL": [ - "abs", - 128 - ], - "ENV_RESET": [ - "abs", - 2147543600 - ], "AMP_PICTURE": [ "abs", 1073974222 ], "follow": [ ".run", - 784 + 116 ], "hold_jump": [ ".run", - 1176 + 508 ], "put_uint": [ ".run", - 1260 + 592 ], "put_text": [ ".run", - 1388 + 720 ], "put_time": [ ".run", - 1404 + 736 ], "log2_q16": [ ".run", - 1734 + 1066 ], "t60_ticks": [ ".run", - 1822 + 1154 ], "linear_ticks": [ ".run", - 1972 + 1304 ], "envelopes_text": [ ".run", - 2048 + 1380 ], "atk_rate": [ ".run", - 5536 + 4864 ], "amps": [ ".run", - 3356 + 2684 ], "envelopes_amp_graph": [ ".run", - 208 + 82 ], "envelopes_flt_dec": [ ".run", - 4000 + 3328 ], "envelopes_flt_atk": [ ".run", - 5024 + 4352 ], "envelopes_gate": [ ".bss", @@ -126,11 +102,11 @@ ], "envelopes_voice": [ ".run", - 2550 + 1882 ], "envelopes_amp_dec": [ ".run", - 4512 + 3840 ], "envelopes_write": [ ".run", @@ -138,19 +114,15 @@ ], "envelopes_hold": [ ".run", - 3488 + 2816 ], "envelopes_params": [ ".run", - 3468 + 2796 ], "envelopes_tick": [ ".run", - 3314 - ], - "envelopes_scan": [ - ".run", - 244 + 2642 ] }, "exports": [ @@ -161,7 +133,6 @@ "envelopes_gate", "envelopes_hold", "envelopes_params", - "envelopes_scan", "envelopes_tick", "envelopes_voice", "envelopes_write" @@ -171,274 +142,202 @@ "relocs": [ [ ".run", - 32, - "abs32", - "sec:.bss", - 0 - ], - [ - ".run", - 48, - "abs32", - "sec:.run", - 244 - ], - [ - ".run", - 62, + 2, "abs32", "sec:.bss", 0 ], [ ".run", - 106, - "abs32", - "sec:.bss", - 4 - ], - [ - ".run", - 128, - "abs32", - "sec:.bss", - 8 - ], - [ - ".run", - 138, + 12, "abs32", "sec:.bss", 16 ], [ ".run", - 174, + 48, "abs32", "sec:.run", - 2550 - ], - [ - ".run", - 400, - "abs32", - "sec:.bss", - 0 + 1882 ], [ ".run", - 412, - "abs32", - "sec:.bss", - 4 - ], - [ - ".run", - 418, - "abs32", - "sec:.bss", - 0 - ], - [ - ".run", - 1520, + 852, "abs32", "sec:.run", - 5797 + 5125 ], [ ".run", - 1542, + 874, "abs32", "sec:.run", - 5792 + 5120 ], [ ".run", - 1618, + 950, "abs32", "sec:.run", - 5797 + 5125 ], [ ".run", - 1676, + 1008, "abs32", "sec:.run", - 5794 + 5122 ], [ ".run", - 1714, + 1046, "abs32", "sec:.run", - 5794 + 5122 ], [ ".run", - 2154, + 1486, "abs32", "sec:.run", - 4000 + 3328 ], [ ".run", - 2224, + 1556, "abs32", "sec:.run", - 3488 + 2816 ], [ ".run", - 2264, + 1596, "abs32", "sec:.run", - 4512 + 3840 ], [ ".run", - 2346, + 1678, "abs32", "sec:.run", - 5024 + 4352 ], [ ".run", - 2392, + 1724, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 2512, + 1844, "abs32", "sec:.run", - 5804 + 5132 ], [ ".run", - 2532, + 1864, "abs32", "sec:.run", - 5799 + 5127 ], [ ".run", - 2592, + 1924, "abs32", "sec:.run", - 3356 + 2684 ], [ ".run", - 2614, + 1946, "abs32", "sec:.run", - 3356 + 2684 ], [ ".run", - 2754, + 2086, "abs32", "sec:.bss", - 8 + 0 ], [ ".run", - 2794, + 2126, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 2862, + 2194, "abs32", "sec:.run", - 3488 + 2816 ], [ ".run", - 2940, + 2272, "abs32", "sec:.bss", - 8 + 0 ], [ ".run", - 2970, + 2302, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 3098, + 2426, "abs32", "sec:.bss", 0 ], [ ".run", - 3112, - "abs32", - "sec:.bss", - 8 - ], - [ - ".run", - 3132, + 2460, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 3188, + 2516, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 3316, + 2644, "abs32", "sec:.run", - 1176 + 508 ], [ ".run", - 3342, + 2670, "abs32", "sec:.run", - 1176 + 508 ], [ ".run", - 3484, + 2812, "abs32", "sec:.run", - 2048 + 1380 ] ], "sites": [ - { - "addr": "0x400bcf8a", - "len": 2, - "stock_sha256": "0b358362552792220751c58c4cca9c4e54407d2339649a0b96182880f0504c1a", - "new": "7403", - "kind": "code", - "relocs": [] - }, - { - "addr": "0x400ef8d6", - "len": 2, - "stock_sha256": "4e4b41344512feecd49483d4a3f357ebd5b45f53276f21411a66cb3b4d597c16", - "new": "4e71", - "kind": "code", - "relocs": [] - }, { "addr": "0x40109c24", "len": 8, @@ -595,7 +494,6 @@ "resources": { "regions": [], "names": [ - "ui:SOUND SETTINGS ENV RESET values", "ui:FUNC + turn of AMP HLD", "ui:value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL", "ui:AMP page envelope picture HLD", From da82639053ed2b27de8abb2279fd8180ece5a02b Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Sat, 7 Nov 2026 09:51:58 -0600 Subject: [PATCH 09/11] Improved Envelopes: pin the rebuilt package at 2c53a220, vendor it, captures on EN02 The rytm-emu captures retaken on EN02 (plain base + this package) are pixel-identical to EN01's. Verification record updated. Co-Authored-By: Claude Opus 5.5 --- .../2026-11-07-rytm-improved-envelopes.md | 11 +- .../modules/envelopes/README.md | 2 +- .../modules/envelopes/media/capture.json | 10 +- .../modules/envelopes/modwerk.module.json | 8 +- .../elekloader-envelopes-2026-11-07.json | 10 +- sdk/imports/envelopes-2026-11-07.json | 2 +- ...envelopes-0.1.0-experimental-os1.74.elemod | 252 ++++++------------ 7 files changed, 97 insertions(+), 198 deletions(-) diff --git a/docs/verification/2026-11-07-rytm-improved-envelopes.md b/docs/verification/2026-11-07-rytm-improved-envelopes.md index 9b0528978..a88b58801 100644 --- a/docs/verification/2026-11-07-rytm-improved-envelopes.md +++ b/docs/verification/2026-11-07-rytm-improved-envelopes.md @@ -1,8 +1,9 @@ # Analog Rytm MKII: Improved Envelopes 0.1.0-experimental — 7 November 2026 -Nathaniel Pavel's (@npp1993) Improved Envelopes enters the library (id `envelopes`). It carries Iced-Cream's Env Reset Amp (ENV RESET AMP, from MrScruff's rytm-mods) on with a pre-fade, runs AMP HLD from no hold to AUTO, gives ATK, DEC, REL and HLD fine steps at short times, and shows every envelope knob's time. Its source-only OS 1.74 package is pinned in `sdk/imports/elekloader-envelopes-2026-11-07.json` (commit `26dd6810`). +Nathaniel Pavel's (@npp1993) Improved Envelopes enters the library (id `envelopes`). It runs AMP HLD from no hold to AUTO, gives ATK, DEC, REL and HLD fine steps at short times, and shows every envelope knob's time. ENV RESET AMP stays with Env Reset Amp, which installs beside it. Its source-only OS 1.74 package is pinned in `sdk/imports/elekloader-envelopes-2026-11-07.json` (commit `2c53a220`). -- **Build:** `scripts/build-elemod-isolated.sh` in `modwerk-source-tools` (image `39efd52a…`) from clean checkouts of `a0aaa13f` and later commits on the branch. Exported with `package-elemod-recipe.mjs`, which reproduces it with `--check` from each; `verify-elemod-release-exports.mjs` reproduces the 43 current exports. -- **Package:** `envelopes-0.1.0-experimental-os1.74.elemod` `f9779b13…328c`. -- **Emulator:** rytm-emu `2ac0f1f`, EN01 (the plain Modwerk base `ba530f45` + this package, `b1bccf4d…`): boots; the AMP page's DEC and HLD read their times (`media/capture.json`). -- **On a unit:** the author's Analog Rytm MKII over USB, in combined sets of up to 16 modules (EV04 to ED02): AMP DEC within 0.7 % of its text from 5 ms, AMP HLD within 0.1 ms, FILTER ATK within 0.3 %, FILTER DEC and REL 1.5 % (method), ENV RESET AMP with sequencer trigs and RTRG rolls. As reported; details in the module's TESTING.md. Not run alone on a unit. +- **Build:** `scripts/build-elemod-isolated.sh` in `modwerk-source-tools` (image `39efd52a…`) from a clean checkout of `ed0cac20`. Exported with `package-elemod-recipe.mjs`, which reproduces it with `--check`; `verify-elemod-release-exports.mjs` reproduces the 49 current exports. +- **Package:** `envelopes-0.1.0-experimental-os1.74.elemod` `3c5016ae…dc30`. Linked on the plain base `ba530f45`: ramSpare 113,776 alone (EN02, 5,228 bytes for the module) and beside Env Reset Amp 1.0.0 (EN03). +- **Beside Env Reset Amp:** no shared bytes; the HOLD rule holds after its drop record, read in OS 1.74's state machine (module `upstream/README.md`). +- **Emulator:** rytm-emu `2ac0f1f`, EN02 (the plain base + this package, `c8835018…`): boots; the AMP page's DEC and HLD read their times (`media/capture.json`). +- **On a unit:** the author's Analog Rytm MKII over USB, in combined sets of up to 16 modules (EV04 to ED02): AMP DEC within 0.7 % of its text from 5 ms, AMP HLD within 0.1 ms, FILTER ATK within 0.3 %, FILTER DEC and REL 1.5 % (method). As reported; details in the module's TESTING.md. This package: not yet run on a unit. diff --git a/sdk/analog-rytm-mkii/modules/envelopes/README.md b/sdk/analog-rytm-mkii/modules/envelopes/README.md index 18b93fa27..6ec5820e6 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/README.md +++ b/sdk/analog-rytm-mkii/modules/envelopes/README.md @@ -108,7 +108,7 @@ module started from; none of its code is carried. irpina: Elekloader and core-ar ## Screens and audio -Screenshots are rytm-emu captures of build EN01, this package linked alone on the Modwerk base +Screenshots are rytm-emu captures of build EN02, this package linked alone on the Modwerk base ([media/capture.json](media/capture.json)). No audio preview. ![AMP DEC reading 2.2ms](media/decay-time.png) ![AMP HLD reading 4.0ms](media/hold-time.png) diff --git a/sdk/analog-rytm-mkii/modules/envelopes/media/capture.json b/sdk/analog-rytm-mkii/modules/envelopes/media/capture.json index fdd19fe3f..3b0aea089 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/media/capture.json +++ b/sdk/analog-rytm-mkii/modules/envelopes/media/capture.json @@ -4,9 +4,9 @@ "moduleId": "envelopes", "moduleVersion": "0.1.0-experimental", "firmware": "1.74", - "capturedAt": "2026-11-07T05:10:00Z", - "imageSha256": "b1bccf4d23c6b584ae36f39f2412dddff98c4a206bea83dff6613b313f2ba8bf", - "build": "Modwerk's linker: Modwerk base for core-ar2 0.7 (plain variant ba530f45) + this folder's Improved Envelopes 0.1.0-experimental, materialised against stock OS 1.74, --version EN01", + "capturedAt": "2026-11-07T15:51:00Z", + "imageSha256": "c8835018e591328648e6f5c08fe11e9c929098753234211537cba49c78da4c2e", + "build": "Modwerk's linker: Modwerk base for core-ar2 0.7 (plain variant ba530f45) + this folder's Improved Envelopes 0.1.0-experimental, materialised against stock OS 1.74, --version EN02", "emulator": { "name": "rytm-emu", "repository": "https://github.com/trigcondition/rytm-emu", @@ -18,13 +18,13 @@ { "path": "media/decay-time.png", "frame": "turn64.png", - "plan": "DTBOOT_TURN_PNG=t3 dtboot Rytm-EN01-os1.74.syx --instr 13400M --every 1000M --press NO@7003M:12M --press NO@7303M:12M --press NO@7603M:12M --press NO@7903M:12M --press NO@8203M:12M --press NO@8503M:12M --press NO@8803M:12M --press NO@9103M:12M --press AMP@11003M:12M --turn 2:-6@11303Mx64/20M --turn 1:6@12803Mx6/20M", + "plan": "DTBOOT_TURN_PNG=t3 dtboot Rytm-EN02-os1.74.syx --instr 13400M --every 1000M --press NO@7003M:12M --press NO@7303M:12M --press NO@7603M:12M --press NO@7903M:12M --press NO@8203M:12M --press NO@8503M:12M --press NO@8803M:12M --press NO@9103M:12M --press AMP@11003M:12M --turn 2:-6@11303Mx64/20M --turn 1:6@12803Mx6/20M", "sha256": "5166a566f68a2dbd427c05469c589464d1691c67e39b671566615fc00d154dc9" }, { "path": "media/hold-time.png", "frame": "turn70.png", - "plan": "DTBOOT_TURN_PNG=t3 dtboot Rytm-EN01-os1.74.syx --instr 13400M --every 1000M --press NO@7003M:12M --press NO@7303M:12M --press NO@7603M:12M --press NO@7903M:12M --press NO@8203M:12M --press NO@8503M:12M --press NO@8803M:12M --press NO@9103M:12M --press AMP@11003M:12M --turn 2:-6@11303Mx64/20M --turn 1:6@12803Mx6/20M", + "plan": "DTBOOT_TURN_PNG=t3 dtboot Rytm-EN02-os1.74.syx --instr 13400M --every 1000M --press NO@7003M:12M --press NO@7303M:12M --press NO@7603M:12M --press NO@7903M:12M --press NO@8203M:12M --press NO@8503M:12M --press NO@8803M:12M --press NO@9103M:12M --press AMP@11003M:12M --turn 2:-6@11303Mx64/20M --turn 1:6@12803Mx6/20M", "sha256": "869cde2e56143f53fb755ee383d59f1bb0c575d371d0de9d285f372a77b12cd5" } ] diff --git a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json index 3da364f7e..9e2ccbc50 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json +++ b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json @@ -164,8 +164,8 @@ "type": "emulator", "release": "1.74", "moduleVersion": "0.1.0-experimental", - "imageSha256": "b1bccf4d23c6b584ae36f39f2412dddff98c4a206bea83dff6613b313f2ba8bf", - "setup": "Headless rytm-emu (dtboot) running EN01: the Modwerk base for core-ar2 0.7 (plain variant ba530f45) and this folder's Improved Envelopes 0.1.0-experimental, linked by Modwerk's linker on stock OS 1.74, the default kit and pattern A01. Firmware-rendered 128x64 screen at 3x. UI documentation only." + "imageSha256": "c8835018e591328648e6f5c08fe11e9c929098753234211537cba49c78da4c2e", + "setup": "Headless rytm-emu (dtboot) running EN02: the Modwerk base for core-ar2 0.7 (plain variant ba530f45) and this folder's Improved Envelopes 0.1.0-experimental, linked by Modwerk's linker on stock OS 1.74, the default kit and pattern A01. Firmware-rendered 128x64 screen at 3x. UI documentation only." } }, { @@ -180,8 +180,8 @@ "type": "emulator", "release": "1.74", "moduleVersion": "0.1.0-experimental", - "imageSha256": "b1bccf4d23c6b584ae36f39f2412dddff98c4a206bea83dff6613b313f2ba8bf", - "setup": "Headless rytm-emu (dtboot) running EN01: the Modwerk base for core-ar2 0.7 (plain variant ba530f45) and this folder's Improved Envelopes 0.1.0-experimental, linked by Modwerk's linker on stock OS 1.74, the default kit and pattern A01. Firmware-rendered 128x64 screen at 3x. UI documentation only." + "imageSha256": "c8835018e591328648e6f5c08fe11e9c929098753234211537cba49c78da4c2e", + "setup": "Headless rytm-emu (dtboot) running EN02: the Modwerk base for core-ar2 0.7 (plain variant ba530f45) and this folder's Improved Envelopes 0.1.0-experimental, linked by Modwerk's linker on stock OS 1.74, the default kit and pattern A01. Firmware-rendered 128x64 screen at 3x. UI documentation only." } } ] diff --git a/sdk/imports/elekloader-envelopes-2026-11-07.json b/sdk/imports/elekloader-envelopes-2026-11-07.json index a0b86aa8a..5ebfb63ce 100644 --- a/sdk/imports/elekloader-envelopes-2026-11-07.json +++ b/sdk/imports/elekloader-envelopes-2026-11-07.json @@ -7,7 +7,7 @@ "mods": [ { "file": "envelopes-0.1.0-experimental-os1.74.elemod", - "sha256": "f9779b13edaf0d838b3539cc6bf7a4ae16a66b1e918ccac9f3cf82c6ab7f328c", + "sha256": "3c5016aebe69610e3406a0d6839fdb91a1a97caf6b3538907c2e16d76046dc30", "id": "envelopes", "version": "0.1.0-experimental", "device": "analog-rytm-mk2", @@ -15,7 +15,7 @@ "license": "GPL-2.0-only", "source": { "repo": "repeat98/modwerk", - "commit": "26dd68102e014409ee7a4410c5854e8d564ef028", + "commit": "2c53a2207051e8258e4a37e4cc5dba10adb211fa", "path": "sdk/imports/packages/envelopes/envelopes-0.1.0-experimental-os1.74.elemod" }, "title": "Improved Envelopes", @@ -23,12 +23,12 @@ "core" ], "conflicts": [], - "summary": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", - "description": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", + "summary": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, and the envelope knobs show times.", + "description": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, and the envelope knobs show times.", "category": "Synthesis", "author": "npp1993", "needs_core": "0.7", - "on_unit": "This source ran on the author's Analog Rytm MKII on OS 1.74 in a 16-module combined image (ED02, measured over USB: AMP DEC, AMP HLD, FILTER DEC and REL); this package has not run alone on a unit." + "on_unit": "This source's curves ran on the author's Analog Rytm MKII on OS 1.74 in a 16-module combined image (ED02, measured over USB: AMP DEC, AMP HLD, FILTER DEC and REL); this package has not yet run on a unit." } ] } diff --git a/sdk/imports/envelopes-2026-11-07.json b/sdk/imports/envelopes-2026-11-07.json index 6f6b9b0c9..1d4d817e9 100644 --- a/sdk/imports/envelopes-2026-11-07.json +++ b/sdk/imports/envelopes-2026-11-07.json @@ -6,7 +6,7 @@ "changes": [ "First release. The AMP envelope reworked: AMP HLD runs from no hold (0) to AUTO (127) without cutting the attack; ATK, AMP DEC, FILTER DEC and REL and AMP HLD get fine steps at short times (0.2 ms to 5 ms); every envelope knob shows its time; FUNC + turn on HLD steps 0, 124.7 ms, AUTO. Installs beside Env Reset Amp, which keeps ENV RESET AMP." ], - "runtimeSourceSha256": "8a7323f7932374f2f1759b0c37bca786970855265433bcf31c7ef9e05b5a9424", + "runtimeSourceSha256": "5b7a6ea089841cb86dbc9d8209da3e92d1b317aea504a047c862152b488d27c2", "packages": [ { "os": "1.74", diff --git a/vendor/elekloader/catalog/envelopes-0.1.0-experimental-os1.74.elemod b/vendor/elekloader/catalog/envelopes-0.1.0-experimental-os1.74.elemod index 1ae7ceaca..77f987e78 100644 --- a/vendor/elekloader/catalog/envelopes-0.1.0-experimental-os1.74.elemod +++ b/vendor/elekloader/catalog/envelopes-0.1.0-experimental-os1.74.elemod @@ -3,7 +3,7 @@ "id": "envelopes", "version": "0.1.0-experimental", "title": "Improved Envelopes", - "description": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, ENV RESET gains AMP, and the envelope knobs show times.", + "description": "The AMP envelope reworked: HOLD runs from no hold to AUTO, ATK, HOLD and DEC/REL have fine steps from 0.2 ms, and the envelope knobs show times.", "category": "machines", "author": "npp1993", "license": "GPL-2.0-only", @@ -18,11 +18,11 @@ "sections": { ".run": { "align": 4, - "len": 5808, + "len": 5136, "parts": [ [ "hex", - "4a83663822398000ea3082b98000ea3482b98000ea38028101010101660842b90000000060164feffff048d703034eb9000000004cd703034fef0010223900000000070167384a926b3441f94029113873b0380041f98000e5087801b8b01c00671c203c3006a7ec22390000000007016706203cb006a7ec243c000000802239000000000701671241f900000000b0b03c006606b4b03c2067284feffff048d703032f022f002f0c2f0a2f034eb9000000002f4000144fef00144cd703034fef0010274000ac274000ec4ef940109c2c202f001c0c8000007f006d0642af001c600a4a806e0670012f40001c4ef940038bce00004fefffd048d77cfc22798000fe544ab98000ed9c670001a220398000ed9c46800880000c7df98000fc90283940287ffc7a16267c42ad66384283287c8000fd509dce4c045800247c42adf5d0207c42ac6b488c80702c4c004800070666262a43dbfc8000ea30101508000000671620087201e5882a40dbfc37fab290b295673c4a906674528341e80038588a49ec000c740c47eb1a0cb48366c0203900000000220e4680c28023c10000000023ce000000004cd77cfc4fef00304e754a9366c0201490896bbab0856cb62a7c4025a3a0700173b5380041e800385283588a49ec000c740ce3a8220e47eb1a0c82802c41b4836600ff6660a22a7c3d53081c74102e12dbca201522280024b4816500ff7690890c80fffea0706d00ff6ab0846c00ff647401e3aa2a4372ff2f48002c260253872407d4824a876f560682402909b8204275d0d482c4834a82670c4a816c4ab0856c0000a42200068000015f90b0846dce206f002c260d4a816d00ff18b2856d00ff58528341e80038588a49ec000c740c47eb1a0cb4836600fed06000ff0c2e3c000003c04a816db6908120006a025280206f002c260de280b2806c00fed6b2856cc06000ff1420398000ed987a167df98000fc90283940287ffc267c42ad6638287c8000fd504283247c42adf5d09dce8c804c045800702c4c004800207c42ac6b486000fe64206f002c260d588a528341e80038740c49ec000c47eb1a0cb4836600fe466000fe820000598f2f03701c2f027602222f00142401e0aa70f7206f0010c082b680670000b84a806700009c44c266000106202f0018e088710048404240224020802401760ee7aa7614712f001b484042402f4200082401e6a942030282000fffff214000041143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff80002141000824009489b3c0672222424a826d7c222800084a28000c663ee6896778b3c1630893c14a826d7690892080241f261f588f4e754a28000d66f220280004240022509489b3c066c260e270011140000d241f261f588f4e750c8107ffffff62caec89263c0000045c4c031800760fe6a952810c810001000064b02609e08b4c031800e08993c14a826c9e60122202448122416000ff7c7201b3c16286608cd0892080608822507609b6826600ff042401760ee7aa7614202800042f4200082401e6a942030282000fffff1143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff8000214100086000ff082f02202f000c2200e0814aaf00106f1a4a816d267429b4816c30747eb4816c200280ffffff00241f4e75747fb4816d10742ab4816d144a816fe6241f42804e75241f203c00007f004e75241f203c00002a004e754fefffe448d7401c222f0024780a2401260f4c4420004c4420024def001206830000001c204e43e8000106800000003010807009b08164262202b68967202401780a4c4420004c442002204943e8000106800000003010807009b08165da7001908e226f0020d08841f6080012e0bdc866fa4cd7401cd0af00204fef001c4e75226f0008206f0004101910c066fa4e75518f2f02202f0014206f00100c8002625a006306203c02625a00720a74174c00180006810000000cb481645c0c81000012bf630000a8220006810000000c0c810000bb7f630000de22000681000004b00c8100249eff6346068000002ee0243c00005dc04c4200002f002f084ebaff02508f223c000000002f4100142f400010241f508f6000ff6a203c000000002f4000142f480010241f508f6000ff54243c000009604c42100143fafec6700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c00000000609c74184c42100143fafe8c700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c000000002f4100142f400010241f508f6000fece74184c4210012f012f084ebafe40508f223c000000002f4100142f400010241f508f6000fea84fefffec48d7007c242f00182202d2816afcd48242414841307c001e4284700f04c291c2340176017c0fe1ab5380c4c12202eca94a826c08220242414841888374ffb48066de200848404240d0844cd7007c4fef00144e752f02740e222f00082001e5a8740f4241484102803fffc0002040203c7fffffff9088e2a822000681ffff8000b48164560c8101ffffff632c0c817ffeffff6250203c7fffffff90812f004ebaff5c721f4841588f9280203c0009f73e4c410000241f4e757412e888e4a93401c4c122000681fffff800203c37431533d2824c410000241f4e75241f203c7fffffff4e75241f42804e752f02740e202f000c2200e5a94240484002813fffc0002041720fc081223c7fffffff9288e0a90681ffff80004a816712202f00087417e5a84c410000241f52804e75241f203c7fffffff4e75518f2f0a727f2f02206f001420280008e0802240b2806c30327c007f2228000474080681ffffffceb4816532323b1a0848c14efb180200f2003200280032002800280120006600904a806cd02228000493c90681ffffffce7408b48164ce241f4280245f508f4e7545f90000000020329c000280000fffff2f002f48000c4ebafe9e206f000c2e802f28000c4ebafcee508f7001241f245f508f4e752228000c747eb4806d00013c4a806f00011241f90000000020309c002f002f014ebafcbe508f700160ce2068000c727e2f48000cb2806d0000fa41f90000000024309c000282000fffff2f02740a4ebafe32588f2200e4a90280000003ff243c000003ac4c021800740ac0fc03ac068000000200e4a82040487018002f2f00104ebafc5e508f70016000ff6e45f9000000002f329c004878007f2f4800104ebafe78588f206f000c2e802f28000c4ebafc30508f70016000ff4045f900000000740c71f29a002200e4a8e989740a4840424073c180812f00487800ff2f4800104ebafe36508f2200e4a90280000003ff243c000003d44c021800740ac0fc03d4068000000200e4a8224048711800206f000c2f28000c4ebafbc8508f70016000fed842802f002f014ebafbb6508f6000fef64879000000002f084ebafb94508f70016000feb44879000000002f014ebafb80508f70016000fea04fefffc8700748d7041cc0af003c206f00447401262f004c73280002e1aa2f41001e3200c2fc000e0681000000000c834000007f67000158760e4c00380043f900000000283138002f440022787fb8af004c6700008a41f1380028280008246800042f4400261828000c2f4a001a45e800041f4400321828000d1f4400332f2f004c2f2f004c2f4a00262808508445e8000c41e8000d2f4a00362f48003c2f4400322f012f40001e2f4900224ebaf86c4fef000c226f0016222f0022202f0012b2b13800670001184682c5b900000000202f00484cd7041c4fef00384e75282f004871100284fff0000020444a806d00018a43f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6700018c226f0040760220515388b688650001864aaf001e6f00019a282f001e41f90000000022704c00246f0040206a000441e8fff1b3c86c0001a0262f00220c83007e7fff6f000192307c00034878007f2f00226f004822882f012f40001e4ebaf7a24fef000c202f00124682c5b9000000006000ff48262f004871100283fff0000020434a806d0000a243f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e670000a4307c00022f3c4000007f2f00226f004822886092222f001a246f001eb2926600fede226f0026206f002ab3d06600fed0246f002e73af00327792b6816600fec0206f003473af00337790b2836600feb0222f0048262f004c41f90000000021810c1021830c3085b90000000020014cd7041c4fef00384e75428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600ff60307c00012f3c4000007f6000ff5c428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600fe78206f00407602b69067224878007f2f002f012f40001e4ebaf65e4fef000c202f00126000feba93c96000fe724878007f76012f0020832f012f40001e4ebaf6384fef000c202f00126000fe94307c00024878007f6000fe6e203c00000000b0b9419a5b8c6718203c400fe58423c0419a5b88203c0000000023c0419a5b8c4e750000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000000000320000003a00000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000011000000130000001500000017000000190000001b00000020000000250000002a0000002f00000034000000390000003e00000043000000480000004d00000057000000610000006b000000750000007f00000089000000930000009d000000a7000000b1000000bb000000c5000000cf000000d9000000e3000000f70000010b0000011f00000133000001470000015b0000016f0000018300000197000001ab000001bf000001d9000001f5000002130000023200000253000002760000029b000002c3000002ec000003190000034700000379000003ad000003e50000041f0000045d0000049f000004e50000052f0000057d000005d00000062800000685000006e70000074f000007bd00000832000008ae00000931000009bb00000a4e00000aea00000b8e00000c3d00000cf500000db900000e8800000f630000104b0000114100001246000013590000147d000015b2000016fa00001855000019c400001b4800001ce400001e98000020660000224e0000245400002678000028bd00002b2300002dae0000305f000033390000363e0000397100003cd300004069000044350000483a00004c7c000050fe000055c400005ad200005ad2000000000000079680000f951000179ce0001ca900001ffe000024b38000283620002aeca0002d1540002ed76000309a300033108000352b300036fcf0003893900039f9b0003b3770003c5350003d5270003e38f0003f0a40003fc9300040f01000423180004359f00045e330004802d00049d0b0004b5de0004cb730004de620004ef200004fe09000516ce00052ee7000544bc0005589c00056ac700057b7300058acd000598fd0005a6220005b25a0005bdbc0005c85e0005dba70005ecb00005fbd9000612da00062b4e0006417300065597000667fe000678df000688680006aa540006c69f0006de950006f322000709eb0007291f000744ab00075d2a00077316000786d40007a8ef0007c55f0007dd710007f215000807f400082747000842eb00085b7f0008717d000885490008a77d0008c3ff0008dc1f0008f0ce00090579000924da0009408b0009592900096f30000983040009ace00009ce5e0009e9c6000a013b000a3f51000a75bc000aa570000acf40000af3e6000b280c000b605d000b91b9000bbcfd000be2e9000c084d000c4291000c75a2000ca265000cc9a1000cec04000d144f000d4924000d7772000da008000dc39b000de2c9000dfe1c000e2c20000e561d000e7ae9000e9b2a000eb76f000ed035000ee5ed000ef8f5000f1349000f3087000f4a27000f609f000f744f000f8591000f94b1000000000000889d000110f20001933b0001dff50002246e00026b3900029fbb0002c8360002e85d0003050800033065000354ef0003742300038f180003a69d0003bb510003cdae0003de140003eccf0003fa1d00040c640004226b000436960004491f00045a3600047fa100049ef30004b98d0004d06c0004e44c0004f5bb00050a4a000525bd00053e57000554840005689b00057ae400058b9b00059af10005a9100005b61c0005c2330005cd6f0005d7e60005e1ad0005f368000606240006220300063af800065172000665cb0006784e00068937000698ba0006a7000006c62b0006e02a0006f62d0007121e000732dc00074f86000768d300077f53000793760007a5970007c4eb0007df080007f523000810300008310d00084dd00008673200087dc3000891f50008a4220008c38a0008ddb70008f3de00090db900092ea500094b74000964e100097b7b00098fb40009a1e80009c8570009e716000a0080000a2a71000a6370000a9566000ac131000ae793000b1272000b4d6e000b8121000bae71000bd629000bf8f9000c2ef9000c6477000c9358000cbc70000ce074000d000b000d3761000d67e1000d9263000db7a5000dd84d000df4ec000e1c05000e47ff000e6e8a000e9052000eaded000ec7e1000ede9f000ef28f000f0811000f26b1000f4189000f5911000f6daf000f7fc3000f8f9b000f9d7d000000000002f499000427510004d0970005412800059e5b0005db6000060cd900064cd800067e490006a5a00006c5ad0006e04a0006f6be000713e1000735150007521400076ba00007824c0007968e0007a8c40007b93a0007c82d0007d5d00007e24e0007edca00080da20008374900085a7d000878a2000892bc0008a98f0008bdaf0008cf900008df8c0008edee0008faf000090d8500092319000936de0009490e000959d60009695f000977cc00098538000991bf0009b1e20009cf290009e9d6000a044a000a3095000a58f2000a7dba000a9f3e000abdc9000ad99f000af2fc000b1435000b3e58000b64bf000b87be000ba7a4000bc4b6000bdf36000bf75c000c1abe000c42dd000c676f000c88c4000ca725000cc2d6000cdc13000cf315000d101a000d3653000d592a000d78ec000d95de000db040000dc84d000dde38000df233000e08d4000e2a07000e484a000e63df000e7d04000e93ef000ea8d2000ebbdd000ecd38000edd0a000eeb75000ef89a000f092b000f1f03000f32eb000f4511000f559b000f64af000f726d000f7ef5000f8a5f000f94c9000f9e45000fa6eb000faecd000fb5fb000fbc89000fc281000fc7f1000fcce7000fd16d000fd58b000fd94d000fdcb9000fdfd9000fe2b1000fe549000fe7a7000fe9cd000febc5000fed8f000fef31000ff0ad000ff209000ff345000ff4650000203f33c33dd8453d4ad04e76521555ea58e05b3c5d285ec06032627f647d663a67c3691f6a566b6d6c6a6d506e216ee16f92722474a476c178907a217b807cb57dc87ebd7f9a80c58230837c84ab85c386c587b4889189608a208c0e8dd08f6a91bf946896d499099b0d9ce29e8ea028a2eea576a7c4a9deabc9ad87af1fb124b3c9b631b863ba64bc37bde0bf64c18cc411c65cc874ca5ccc19cdafcf20d0e3d349d579d777d948daf0dc73ddd3df14e072e288e46ee629e7bde92eea7debafecc6edc5eeacef80f081f1e0f320f443f54df640f71cf7e6f89df945f9ddfa68fae7fb5afbc4fc24fc7bfccbfd13fd56fd92fdc9fdfbfe29fe53fe79fe9b30006d730073004155544f00494e4600" + "2239000000000701671241f900000000b0b03c006606b4b03c2067284feffff048d703032f022f002f0c2f0a2f034eb9000000002f4000144fef00144cd703034fef0010274000ac274000ec4ef940109c2c202f001c0c8000007f006d0642af001c600a4a806e0670012f40001c4ef940038bce598f2f03701c2f027602222f00142401e0aa70f7206f0010c082b680670000b84a806700009c44c266000106202f0018e088710048404240224020802401760ee7aa7614712f001b484042402f4200082401e6a942030282000fffff214000041143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff80002141000824009489b3c0672222424a826d7c222800084a28000c663ee6896778b3c1630893c14a826d7690892080241f261f588f4e754a28000d66f220280004240022509489b3c066c260e270011140000d241f261f588f4e750c8107ffffff62caec89263c0000045c4c031800760fe6a952810c810001000064b02609e08b4c031800e08993c14a826c9e60122202448122416000ff7c7201b3c16286608cd0892080608822507609b6826600ff042401760ee7aa7614202800042f4200082401e6a942030282000fffff1143000d7601c283262f00084242484202833fffc0001141000c223c7fffffff9283e4a90681ffff8000214100086000ff082f02202f000c2200e0814aaf00106f1a4a816d267429b4816c30747eb4816c200280ffffff00241f4e75747fb4816d10742ab4816d144a816fe6241f42804e75241f203c00007f004e75241f203c00002a004e754fefffe448d7401c222f0024780a2401260f4c4420004c4420024def001206830000001c204e43e8000106800000003010807009b08164262202b68967202401780a4c4420004c442002204943e8000106800000003010807009b08165da7001908e226f0020d08841f6080012e0bdc866fa4cd7401cd0af00204fef001c4e75226f0008206f0004101910c066fa4e75518f2f02202f0014206f00100c8002625a006306203c02625a00720a74174c00180006810000000cb481645c0c81000012bf630000a8220006810000000c0c810000bb7f630000de22000681000004b00c8100249eff6346068000002ee0243c00005dc04c4200002f002f084ebaff02508f223c000000002f4100142f400010241f508f6000ff6a203c000000002f4000142f480010241f508f6000ff54243c000009604c42100143fafec6700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c00000000609c74184c42100143fafe8c700a4c4010024c4010012f012f082f49000c4e91204010fc002e2f022f08226f00144e914fef0010223c000000002f4100142f400010241f508f6000fece74184c4210012f012f084ebafe40508f223c000000002f4100142f400010241f508f6000fea84fefffec48d7007c242f00182202d2816afcd48242414841307c001e4284700f04c291c2340176017c0fe1ab5380c4c12202eca94a826c08220242414841888374ffb48066de200848404240d0844cd7007c4fef00144e752f02740e222f00082001e5a8740f4241484102803fffc0002040203c7fffffff9088e2a822000681ffff8000b48164560c8101ffffff632c0c817ffeffff6250203c7fffffff90812f004ebaff5c721f4841588f9280203c0009f73e4c410000241f4e757412e888e4a93401c4c122000681fffff800203c37431533d2824c410000241f4e75241f203c7fffffff4e75241f42804e752f02740e202f000c2200e5a94240484002813fffc0002041720fc081223c7fffffff9288e0a90681ffff80004a816712202f00087417e5a84c410000241f52804e75241f203c7fffffff4e75518f2f0a727f2f02206f001420280008e0802240b2806c30327c007f2228000474080681ffffffceb4816532323b1a0848c14efb180200f2003200280032002800280120006600904a806cd02228000493c90681ffffffce7408b48164ce241f4280245f508f4e7545f90000000020329c000280000fffff2f002f48000c4ebafe9e206f000c2e802f28000c4ebafcee508f7001241f245f508f4e752228000c747eb4806d00013c4a806f00011241f90000000020309c002f002f014ebafcbe508f700160ce2068000c727e2f48000cb2806d0000fa41f90000000024309c000282000fffff2f02740a4ebafe32588f2200e4a90280000003ff243c000003ac4c021800740ac0fc03ac068000000200e4a82040487018002f2f00104ebafc5e508f70016000ff6e45f9000000002f329c004878007f2f4800104ebafe78588f206f000c2e802f28000c4ebafc30508f70016000ff4045f900000000740c71f29a002200e4a8e989740a4840424073c180812f00487800ff2f4800104ebafe36508f2200e4a90280000003ff243c000003d44c021800740ac0fc03d4068000000200e4a8224048711800206f000c2f28000c4ebafbc8508f70016000fed842802f002f014ebafbb6508f6000fef64879000000002f084ebafb94508f70016000feb44879000000002f014ebafb80508f70016000fea04fefffc8700748d7041cc0af003c206f00447401262f004c73280002e1aa2f41001e3200c2fc000e0681000000000c834000007f67000158760e4c00380043f900000000283138002f440022787fb8af004c6700008a41f1380028280008246800042f4400261828000c2f4a001a45e800041f4400321828000d1f4400332f2f004c2f2f004c2f4a00262808508445e8000c41e8000d2f4a00362f48003c2f4400322f012f40001e2f4900224ebaf86c4fef000c226f0016222f0022202f0012b2b13800670001184682c5b900000000202f00484cd7041c4fef00384e75282f004871100284fff0000020444a806d00018643f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e67000188226f0040760220515388b688650001824aaf001e6f000196282f001e41f90000000022704c00246f0040206a000441e8fff1b3c86c00019c262f00220c83007e7fff6f00018e307c00034878007f2f00226f004822882f012f40001e4ebaf7a24fef000c202f00124682c5b9000000006000ff48262f004871100283fff0000020434a806d00009e43f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e670000a0307c00022f3c4000007f2f00226f004822886092222f001a246f001eb2926600fede226f0026206f002ab3d06600fed0246f002e73af00327792b6816600fec0206f003473af00337790b2836600feb0222f004841f900000000262f004c21810c1021830c30859020014cd7041c4fef00384e75428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600ff64307c00012f3c4000007f6000ff60428043f900000000780c71f10a002600e8a8e98b787f4840424077c3808326088083b8af001e6600fe7c206f00407602b69067224878007f2f002f012f40001e4ebaf6624fef000c202f00126000febe93c96000fe764878007f76012f0020832f012f40001e4ebaf63c4fef000c202f00126000fe98307c00024878007f6000fe72203c00000000b0b9419a5b8c6718203c400fe58423c0419a5b88203c0000000023c0419a5b8c4e750000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000ff800000ff800000000000000000000000320000003a00000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000011000000130000001500000017000000190000001b00000020000000250000002a0000002f00000034000000390000003e00000043000000480000004d00000057000000610000006b000000750000007f00000089000000930000009d000000a7000000b1000000bb000000c5000000cf000000d9000000e3000000f70000010b0000011f00000133000001470000015b0000016f0000018300000197000001ab000001bf000001d9000001f5000002130000023200000253000002760000029b000002c3000002ec000003190000034700000379000003ad000003e50000041f0000045d0000049f000004e50000052f0000057d000005d00000062800000685000006e70000074f000007bd00000832000008ae00000931000009bb00000a4e00000aea00000b8e00000c3d00000cf500000db900000e8800000f630000104b0000114100001246000013590000147d000015b2000016fa00001855000019c400001b4800001ce400001e98000020660000224e0000245400002678000028bd00002b2300002dae0000305f000033390000363e0000397100003cd300004069000044350000483a00004c7c000050fe000055c400005ad200005ad2000000000000079680000f951000179ce0001ca900001ffe000024b38000283620002aeca0002d1540002ed76000309a300033108000352b300036fcf0003893900039f9b0003b3770003c5350003d5270003e38f0003f0a40003fc9300040f01000423180004359f00045e330004802d00049d0b0004b5de0004cb730004de620004ef200004fe09000516ce00052ee7000544bc0005589c00056ac700057b7300058acd000598fd0005a6220005b25a0005bdbc0005c85e0005dba70005ecb00005fbd9000612da00062b4e0006417300065597000667fe000678df000688680006aa540006c69f0006de950006f322000709eb0007291f000744ab00075d2a00077316000786d40007a8ef0007c55f0007dd710007f215000807f400082747000842eb00085b7f0008717d000885490008a77d0008c3ff0008dc1f0008f0ce00090579000924da0009408b0009592900096f30000983040009ace00009ce5e0009e9c6000a013b000a3f51000a75bc000aa570000acf40000af3e6000b280c000b605d000b91b9000bbcfd000be2e9000c084d000c4291000c75a2000ca265000cc9a1000cec04000d144f000d4924000d7772000da008000dc39b000de2c9000dfe1c000e2c20000e561d000e7ae9000e9b2a000eb76f000ed035000ee5ed000ef8f5000f1349000f3087000f4a27000f609f000f744f000f8591000f94b1000000000000889d000110f20001933b0001dff50002246e00026b3900029fbb0002c8360002e85d0003050800033065000354ef0003742300038f180003a69d0003bb510003cdae0003de140003eccf0003fa1d00040c640004226b000436960004491f00045a3600047fa100049ef30004b98d0004d06c0004e44c0004f5bb00050a4a000525bd00053e57000554840005689b00057ae400058b9b00059af10005a9100005b61c0005c2330005cd6f0005d7e60005e1ad0005f368000606240006220300063af800065172000665cb0006784e00068937000698ba0006a7000006c62b0006e02a0006f62d0007121e000732dc00074f86000768d300077f53000793760007a5970007c4eb0007df080007f523000810300008310d00084dd00008673200087dc3000891f50008a4220008c38a0008ddb70008f3de00090db900092ea500094b74000964e100097b7b00098fb40009a1e80009c8570009e716000a0080000a2a71000a6370000a9566000ac131000ae793000b1272000b4d6e000b8121000bae71000bd629000bf8f9000c2ef9000c6477000c9358000cbc70000ce074000d000b000d3761000d67e1000d9263000db7a5000dd84d000df4ec000e1c05000e47ff000e6e8a000e9052000eaded000ec7e1000ede9f000ef28f000f0811000f26b1000f4189000f5911000f6daf000f7fc3000f8f9b000f9d7d000000000002f499000427510004d0970005412800059e5b0005db6000060cd900064cd800067e490006a5a00006c5ad0006e04a0006f6be000713e1000735150007521400076ba00007824c0007968e0007a8c40007b93a0007c82d0007d5d00007e24e0007edca00080da20008374900085a7d000878a2000892bc0008a98f0008bdaf0008cf900008df8c0008edee0008faf000090d8500092319000936de0009490e000959d60009695f000977cc00098538000991bf0009b1e20009cf290009e9d6000a044a000a3095000a58f2000a7dba000a9f3e000abdc9000ad99f000af2fc000b1435000b3e58000b64bf000b87be000ba7a4000bc4b6000bdf36000bf75c000c1abe000c42dd000c676f000c88c4000ca725000cc2d6000cdc13000cf315000d101a000d3653000d592a000d78ec000d95de000db040000dc84d000dde38000df233000e08d4000e2a07000e484a000e63df000e7d04000e93ef000ea8d2000ebbdd000ecd38000edd0a000eeb75000ef89a000f092b000f1f03000f32eb000f4511000f559b000f64af000f726d000f7ef5000f8a5f000f94c9000f9e45000fa6eb000faecd000fb5fb000fbc89000fc281000fc7f1000fcce7000fd16d000fd58b000fd94d000fdcb9000fdfd9000fe2b1000fe549000fe7a7000fe9cd000febc5000fed8f000fef31000ff0ad000ff209000ff345000ff4650000203f33c33dd8453d4ad04e76521555ea58e05b3c5d285ec06032627f647d663a67c3691f6a566b6d6c6a6d506e216ee16f92722474a476c178907a217b807cb57dc87ebd7f9a80c58230837c84ab85c386c587b4889189608a208c0e8dd08f6a91bf946896d499099b0d9ce29e8ea028a2eea576a7c4a9deabc9ad87af1fb124b3c9b631b863ba64bc37bde0bf64c18cc411c65cc874ca5ccc19cdafcf20d0e3d349d579d777d948daf0dc73ddd3df14e072e288e46ee629e7bde92eea7debafecc6edc5eeacef80f081f1e0f320f443f54df640f71cf7e6f89df945f9ddfa68fae7fb5afbc4fc24fc7bfccbfd13fd56fd92fdc9fdfbfe29fe53fe79fe9b30006d730073004155544f00494e4600" ] ] }, @@ -32,93 +32,69 @@ } }, "symbols": { - "VOICE_TRACK": [ - "abs", - 1076433208 - ], "WRITE_RESUME": [ "abs", 1074830380 ], - "TRIG": [ - "abs", - 2147542280 - ], - "FADE_START": [ - "abs", - 2953226220 - ], - "FADE_GO_ON": [ - "abs", - 805742572 - ], - "FADE_LEVEL": [ - "abs", - 128 - ], - "ENV_RESET": [ - "abs", - 2147543600 - ], "AMP_PICTURE": [ "abs", 1073974222 ], "follow": [ ".run", - 784 + 116 ], "hold_jump": [ ".run", - 1176 + 508 ], "put_uint": [ ".run", - 1260 + 592 ], "put_text": [ ".run", - 1388 + 720 ], "put_time": [ ".run", - 1404 + 736 ], "log2_q16": [ ".run", - 1734 + 1066 ], "t60_ticks": [ ".run", - 1822 + 1154 ], "linear_ticks": [ ".run", - 1972 + 1304 ], "envelopes_text": [ ".run", - 2048 + 1380 ], "atk_rate": [ ".run", - 5536 + 4864 ], "amps": [ ".run", - 3356 + 2684 ], "envelopes_amp_graph": [ ".run", - 208 + 82 ], "envelopes_flt_dec": [ ".run", - 4000 + 3328 ], "envelopes_flt_atk": [ ".run", - 5024 + 4352 ], "envelopes_gate": [ ".bss", @@ -126,11 +102,11 @@ ], "envelopes_voice": [ ".run", - 2550 + 1882 ], "envelopes_amp_dec": [ ".run", - 4512 + 3840 ], "envelopes_write": [ ".run", @@ -138,19 +114,15 @@ ], "envelopes_hold": [ ".run", - 3488 + 2816 ], "envelopes_params": [ ".run", - 3468 + 2796 ], "envelopes_tick": [ ".run", - 3314 - ], - "envelopes_scan": [ - ".run", - 244 + 2642 ] }, "exports": [ @@ -161,7 +133,6 @@ "envelopes_gate", "envelopes_hold", "envelopes_params", - "envelopes_scan", "envelopes_tick", "envelopes_voice", "envelopes_write" @@ -171,274 +142,202 @@ "relocs": [ [ ".run", - 32, - "abs32", - "sec:.bss", - 0 - ], - [ - ".run", - 48, - "abs32", - "sec:.run", - 244 - ], - [ - ".run", - 62, + 2, "abs32", "sec:.bss", 0 ], [ ".run", - 106, - "abs32", - "sec:.bss", - 4 - ], - [ - ".run", - 128, - "abs32", - "sec:.bss", - 8 - ], - [ - ".run", - 138, + 12, "abs32", "sec:.bss", 16 ], [ ".run", - 174, + 48, "abs32", "sec:.run", - 2550 - ], - [ - ".run", - 400, - "abs32", - "sec:.bss", - 0 + 1882 ], [ ".run", - 412, - "abs32", - "sec:.bss", - 4 - ], - [ - ".run", - 418, - "abs32", - "sec:.bss", - 0 - ], - [ - ".run", - 1520, + 852, "abs32", "sec:.run", - 5797 + 5125 ], [ ".run", - 1542, + 874, "abs32", "sec:.run", - 5792 + 5120 ], [ ".run", - 1618, + 950, "abs32", "sec:.run", - 5797 + 5125 ], [ ".run", - 1676, + 1008, "abs32", "sec:.run", - 5794 + 5122 ], [ ".run", - 1714, + 1046, "abs32", "sec:.run", - 5794 + 5122 ], [ ".run", - 2154, + 1486, "abs32", "sec:.run", - 4000 + 3328 ], [ ".run", - 2224, + 1556, "abs32", "sec:.run", - 3488 + 2816 ], [ ".run", - 2264, + 1596, "abs32", "sec:.run", - 4512 + 3840 ], [ ".run", - 2346, + 1678, "abs32", "sec:.run", - 5024 + 4352 ], [ ".run", - 2392, + 1724, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 2512, + 1844, "abs32", "sec:.run", - 5804 + 5132 ], [ ".run", - 2532, + 1864, "abs32", "sec:.run", - 5799 + 5127 ], [ ".run", - 2592, + 1924, "abs32", "sec:.run", - 3356 + 2684 ], [ ".run", - 2614, + 1946, "abs32", "sec:.run", - 3356 + 2684 ], [ ".run", - 2754, + 2086, "abs32", "sec:.bss", - 8 + 0 ], [ ".run", - 2794, + 2126, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 2862, + 2194, "abs32", "sec:.run", - 3488 + 2816 ], [ ".run", - 2940, + 2272, "abs32", "sec:.bss", - 8 + 0 ], [ ".run", - 2970, + 2302, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 3098, + 2426, "abs32", "sec:.bss", 0 ], [ ".run", - 3112, - "abs32", - "sec:.bss", - 8 - ], - [ - ".run", - 3132, + 2460, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 3188, + 2516, "abs32", "sec:.run", - 5536 + 4864 ], [ ".run", - 3316, + 2644, "abs32", "sec:.run", - 1176 + 508 ], [ ".run", - 3342, + 2670, "abs32", "sec:.run", - 1176 + 508 ], [ ".run", - 3484, + 2812, "abs32", "sec:.run", - 2048 + 1380 ] ], "sites": [ - { - "addr": "0x400bcf8a", - "len": 2, - "stock_sha256": "0b358362552792220751c58c4cca9c4e54407d2339649a0b96182880f0504c1a", - "new": "7403", - "kind": "code", - "relocs": [] - }, - { - "addr": "0x400ef8d6", - "len": 2, - "stock_sha256": "4e4b41344512feecd49483d4a3f357ebd5b45f53276f21411a66cb3b4d597c16", - "new": "4e71", - "kind": "code", - "relocs": [] - }, { "addr": "0x40109c24", "len": 8, @@ -595,7 +494,6 @@ "resources": { "regions": [], "names": [ - "ui:SOUND SETTINGS ENV RESET values", "ui:FUNC + turn of AMP HLD", "ui:value text of AMP ATK/HLD/DEC and FILTER ATK/DEC/REL", "ui:AMP page envelope picture HLD", From 7a46f803519ac34a0e882379c15bd2abdde21287 Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Sun, 8 Nov 2026 09:30:50 -0600 Subject: [PATCH 10/11] Improved Envelopes: load from the code and the emulator screenshots, for the publication gate Co-Authored-By: Claude Opus 5.5 --- .../modules/envelopes/modwerk.module.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json index 9e2ccbc50..5579c97e6 100644 --- a/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json +++ b/sdk/analog-rytm-mkii/modules/envelopes/modwerk.module.json @@ -42,7 +42,10 @@ "Open the AMP page.", "Turn HLD or ATK; FUNC + turn on HLD jumps between 0, 125 ms and AUTO." ], - "screenshots": [] + "screenshots": [ + "media/decay-time.png", + "media/hold-time.png" + ] }, "controls": [ { @@ -104,9 +107,9 @@ "memoryBytes": 5228, "fastBytes": null, "load": { - "display": "Not measured yet", - "method": "unmeasured", - "conditions": "Measure with every voice playing, retrigs and modulated envelopes." + "display": "Small: one compare per voice each block, and a short C call per voice only while its amp envelope moves", + "method": "static", + "conditions": "Read in the code: the amp record write skips a voice whose record repeats and changed nothing, so an idle voice makes no C call. On the author's MKII an earlier build in a 16-module set (LR03, private telemetry base, sequencer stopped) read 70.37 % of the audio block idle, against 70.84 % before that skip (LR01); the module's own share was not separated." } }, "evidence": { From f0ea11f583e0e5a10ad07f0e66d91a87b825257a Mon Sep 17 00:00:00 2001 From: Nathaniel Pawelczyk Date: Sun, 8 Nov 2026 09:31:42 -0600 Subject: [PATCH 11/11] Improved Envelopes: record the source tree hash after the manifest change (package bytes unchanged) Co-Authored-By: Claude Opus 5.5 --- sdk/imports/envelopes-2026-11-07.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/imports/envelopes-2026-11-07.json b/sdk/imports/envelopes-2026-11-07.json index 1d4d817e9..4992f1920 100644 --- a/sdk/imports/envelopes-2026-11-07.json +++ b/sdk/imports/envelopes-2026-11-07.json @@ -6,7 +6,7 @@ "changes": [ "First release. The AMP envelope reworked: AMP HLD runs from no hold (0) to AUTO (127) without cutting the attack; ATK, AMP DEC, FILTER DEC and REL and AMP HLD get fine steps at short times (0.2 ms to 5 ms); every envelope knob shows its time; FUNC + turn on HLD steps 0, 124.7 ms, AUTO. Installs beside Env Reset Amp, which keeps ENV RESET AMP." ], - "runtimeSourceSha256": "5b7a6ea089841cb86dbc9d8209da3e92d1b317aea504a047c862152b488d27c2", + "runtimeSourceSha256": "bc9eb9aa91bbe8c8db6e0c3ad171e6b1edeefda50d2c46561711a695e4bc2474", "packages": [ { "os": "1.74",