diff --git a/.gitignore b/.gitignore index bcc2d11..11f1f13 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,3 @@ /dep /dist /plugin.dll -/extra diff --git a/README.md b/README.md index fdd8026..842b961 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,38 @@ -# SickoCV v2.5.0 +# SickoCV v2.5.1 VCV Rack plugin modules -![SickoCV modules 2 5 0](https://user-images.githubusercontent.com/80784296/206871020-9b671118-03fa-45ca-9e4d-2a44b9ad53d2.JPG) +![SickoCV modules 2 5 1](https://user-images.githubusercontent.com/80784296/212480942-1812dcd5-8a6b-449a-8a5d-956da30b4cf5.JPG) ## Blender -### Stereo crossfade mixer with double modulation -#### - Description: +### Polyphonic stereo crossfade mixer with double modulation +#### - DESCRIPTION 'blender' is a crossfade mixer of mono or stereo signals. It can be used either with cv signals or audio sources. Mix can be modulated by uni/bipolar signals. Modulation can be further modulated by another signal. Audio rate modulations are allowed. -![blender](https://user-images.githubusercontent.com/80784296/201516763-00c7192d-f881-4b14-9c23-68c8be2a90d3.JPG) +![blender](https://user-images.githubusercontent.com/80784296/211660967-ce9aa25d-cc8f-45a9-beae-3381a13cf0af.JPG) -#### - Usage: -Connect CVs or audio sources to IN1 and IN2, mono or stereo signals can be independently used. +#### - INSTRUCTIONS +Connect CVs or audio sources to IN1 and IN2, mono or stereo signals can be independently used. Polyphonic inputs are allowed and are left/right independent, but accordingly to number of channels of IN1 input. PHASE switches invert the sign of input signals. -MIX knob sets the crossfade level of the inputs. +MIX knob sets the crossfade level of the inputs. +Inputs volume can be adjusted via two attenuators. +Master volume can be amplified up to 200%, a hard clip ±5v switch is present. +Output replicates input polyphony, but deticking in the context menu 'Polyphonic outs' option will mix channels into monophonic outs. -**MIX MOD section** +**MOD section** Connecting MIX MOD CV input enables mix modulation. ATNV knob attenuverts CV input. CV input range is usually unipolar 0-10v. RNG switch in 'bipolar' position adds +5v to CV input, so audio signals can be used for modulation. Modulation is added to the MIX knob. -**ATNV MD section** -ATNV MD can be used to add modulation to the ATNV knob in MIXMOD section, the rules are the same. +**MOD2 section** +MOD2 can be used to add modulation to the MOD attenuverter knob in MOD section, the rules are the same. ## Blender8 ### 8 single crossfade mixers with modulation -#### - Description: +#### - DESCRIPTION 'blender8' is a set of 8 crossfade mixers of two signals. As the previous one it can be used either with cv signals or audio sources. Mix can be modulated by uni/bipolar signals. @@ -37,21 +40,21 @@ Audio rate modulations are allowed. ![blender8](https://user-images.githubusercontent.com/80784296/201516772-12dac17b-f8a0-4f82-946a-da8b7d254b09.JPG) -#### - Usage: +#### - INSTRUCTIONS 'blender8' provides 8 mono crossfade mixers and differs from 'blender' module in the following things. Only the IN2 input signal can be phase inverted. If a CV input is connected for modulation, CV sets the mix percentage and the MIX knob becomes the CV attenuverter. ## bToggler / bToggler Compact ### Buffered stereo signal toggle switch router, with VCA and ASR envelope generator, in regular and compact form factor -#### - Description: +#### - DESCRIPTION - Buffered Toggled VCA with builtin ASR envelope generator - Buffered Toggled ASR envelope generator - Buffer mute/unmute CVs or mono/stereo AUDIO signals according to an ASR envelope activated by Toggle Triggers -![btoggler](https://user-images.githubusercontent.com/80784296/201516786-81b923a6-4d9d-4c6f-8c1c-74e43f9e7e9c.JPG) +![btoggler](https://user-images.githubusercontent.com/80784296/211221913-2ac04d94-b80b-4222-a02b-2719e0fb4d38.JPG) -#### - Usage: +#### - INSTRUCTIONS Connect a clock source. When ARM input is triggered (arm on), the L+(R) inputs will start to be routed to L+(R) outputs on next clock detection (according to ASR envelope values) and GATE output will provide a high state. @@ -62,7 +65,7 @@ If ARM is triggered again before clock detection it will abort arming (unarm). Attack, Sustain and Release knobs set the envelope of the routed signals. -A, S, R CVinputs are added to respective knob values. +A, S, R CVinputs are added to respective knob values, bToggler module has attenuverters. If L or (R) inputs are not connected, L and (R) outputs will provide just the envelope, so a mono signal can be connected to L input to route it to L output and nothing connected to (R) input to have the envelope on (R) output. @@ -73,7 +76,7 @@ NOTE: input trigger threshold is +1v. ## bToggler8 ### 8 buffered toggle switch signal router -#### - Description: +#### - DESCRIPTION 'bToggler8' can be used to mute/unmute up to 8 CVs or AUDIO signals, in sync to a tempo clock source. For example it can be used to play/stop drumkit parts independently (kick, snare, hats, etc): - connect an appropriate clock source to CLOCK @@ -89,7 +92,7 @@ Otherwise bToggler OUTs can be connected to envelope generators. In that case th ![btoggler8](https://user-images.githubusercontent.com/80784296/201516798-acfa6672-07d0-4f0e-bd38-6269a204eb64.JPG) -#### - Usage: +#### - INSTRUCTIONS Connect a clock source. When ARM input is triggered (arm on) the IN input will start to be routed to OUT on next clock detection and GATE output will provide a high state. @@ -113,7 +116,7 @@ Here below is one example of bToggler8 usage. When buttons are pressed on PULSES ## bToggler8+ ### 8 buffered toggle switch router, plus warnings to use with led midi controllers -#### - Description: +#### - DESCRIPTION 'bToggler8+' is almost the same of the previous one, but it has a further feature (WRN outs) to be used with programmable led midi controllers to have a visual feedback on the controller. Some midi controllers can light up or turn off their button leds by receiving the same commands they send. @@ -122,7 +125,7 @@ So when pressing buttons on controller, 'bToggler8+' will actually play/stop the ![btoggler8plus](https://user-images.githubusercontent.com/80784296/201516811-40c75bb5-84d2-411b-b9ed-fa876e178258.JPG) -#### - Usage: +#### - INSTRUCTIONS The same of the previous one, plus: When 'armed on' or 'armed off', the WRN (warning) output will provide a sequence of pulses until next clock is detected. @@ -150,74 +153,86 @@ Here below is one example of bToggler+ usage. The MIDI>GATE module is connected ![calcs](https://user-images.githubusercontent.com/80784296/201516821-8ea683bd-db11-4687-971d-67bef380b81c.JPG) -#### - Usage: +#### - INSTRUCTIONS A, B and C are the inputs. The output tables provide simple math calculations and averages between two inputs or the average of all of them. -U/B (Unipolar/Bipolar) switch clamps the outputs to 0/10V or -5/+5v. +U/B (Unipolar/Bipolar) switch clamps the outputs to 0/10V or ±5v. -## Drummer +## Drummer Drummer4 Drummer4+ ### Accent and choke utility for drum modules lacking these features -![drummer](https://user-images.githubusercontent.com/80784296/201516831-bff1df4b-b7e1-4065-b486-7501d6c4cde7.JPG) +![drummer](https://user-images.githubusercontent.com/80784296/212536993-c8ac8011-b324-4dae-99f6-8f8b548557eb.JPG) + +#### - INSTRUCTIONS +Drummer and Drummer4/Drummer4+ module can handle 2 or 4 drum sounds with separate standard and accent volume levels set by respective knobs. -#### - Usage: -Drummer module can handle two drum sounds with separate standard and accent volume levels set by respective knobs. Connect the IN input to a drum-like audio source or sample player, and OUT output to the mixer. Connect the TRIG input to the same module that feeds the drum module, it can be a sequencer or every other pulse generation module. Connect the ACC input to the module which generates the accents, it can be the sequencer or every other suitable module. When ACC is triggered at the same time as the TRIG input, Drummer module will output the Accent Level set by "Accent Level knob" instead of the one set by "Standard Level Knob". + Input triggers threshold is +1v. Each knob range is from 0 to 200% of the incoming IN level. -LIMIT switch hard clips the output in the range -5v/+5v. -CHOKE switch mutes one output when the other is triggered (for example when used with open/closed hihat sounds). +LIMIT switch hard clips the output in the range ±5v. +When CHOKE switch is on and a trigger occurs, the other slot (Drummer) or the next slot (Drummer4) is muted (for example when used with closed/open hihat sounds). + +- **Drummer note:** If 1 OUT is not connected, the audio signal will be mixed with the other one connected. -NOTE: In CHOKE mode, if both TRIG inputs are triggered at the same time, the upper section (#1) will have the priority and the lower one will be ignored. +In CHOKE mode, if both TRIG inputs are triggered at the same time, the upper section (#1) will have the priority and the lower one will be ignored. Example of Drummer module usage: -![drummer example](https://user-images.githubusercontent.com/80784296/204083554-dc651ff0-b94d-4b13-a699-e1dfb348b7e7.JPG) +![drummer example](https://user-images.githubusercontent.com/80784296/212531420-150a0d94-12c6-463e-b46b-0828f5d45895.JPG) [Download example](./examples/drummer%20example.vcvs?raw=true) (right-click -> save link as) -## Drummer4 -### 4 channel accent utility for drum modules lacking this feature - -![drummer4](https://user-images.githubusercontent.com/80784296/201516839-54364ebe-d3cc-4a4e-9c32-d85e2ec2653b.JPG) - -#### - Usage: -This module is almost the same of the previous one. It supports up to 4 channel and it manages only accent levels, there is no choking feature. -If OUT is not connected, the audio signal will be added to the next OUT. For example if you connect only out #2 and #4, out #1 and #3 will be respectively mixed with those ones, if you connect only out #4, this socket will output all the channels. +- **Drummer4 note:** +If one slot OUT is not connected, the audio signal will be added to the next one. For example if you connect only out #2 and #4, out #1 and #3 will be respectively mixed with those ones, if you connect only out #4, this socket will output all the channels. Example of Drummer4 module usage: -![drummer4 example](https://user-images.githubusercontent.com/80784296/204083563-c0913d0a-abde-44c7-8434-4036691c8720.JPG) +![drummer4 example](https://user-images.githubusercontent.com/80784296/212531441-575f9b49-dee2-47ca-a82d-0861a10145e5.JPG) [Download example](./examples/drummer4%20example.vcvs?raw=true) (right-click -> save link as) +- **Drummer4+ note:** +Drummer4+ it's the same of Drummer4. It only adds attenuverted CV inputs to parameter knobs. + ## DrumPlayer DrumPlayer+ ### 4 channel Drum Sample Player with accent and choke functionality -![drumplayer](https://user-images.githubusercontent.com/80784296/206871272-e62df892-03fa-49d2-9197-310b219198a3.JPG) +![drumplayer](https://user-images.githubusercontent.com/80784296/212537149-9a38032b-694f-488e-86b5-31bdfad43c7b.JPG) -#### Usage: -##### DrumPlayer+ +#### INSTRUCTIONS Load wav samples in the slots using context menu. + When TRIG input is triggered the sample will be played at the volume percentage set by to "Standard Level" knob + its relative attenuverted CVinput. If ACCENT input is HIGH when TRIG occurs, the sample will be played at "Accent Level" knob + its attenuverted CVinput. + Playing speed can be set by SPD knob from 1 to 200% and modulated with its attenuverted CVinput. Speed can be modified during sample playback. -If CHOKE switch is on when TRIG occurs, the playback of next slot will be stopped: it's commonly used to simulate a closed/open hihat. -LIM switch is a hard clipping limiter to -5v/+5v on the output. -If OUT is not connected, the audio signal will be added to the next OUT. In this way you can connect only the last OUT to have a master output, or you can skip some OUTs to mix only desired slots. -##### Context menu -In the context menu there is an option to disable "Normalled OUTs", then only the connected OUTs will output the relative slot sample. +External modulation is allowed only on drumPlayer+ + +If CHOKE switch is on when TRIG occurs, the playback of next slot is stopped with a 1ms fade out: it's commonly used to simulate a closed/open hihat. +LIM switch is a hard clipping limiter to ±5v on the output. -There are also 3 different interpolation algorithms, that are engaged during playback only when the sample samplerate differs from VCV working samplerate or playback speed differs from 100%. -- 'No interpolation' can be used when sample rates match and speed is 100% constant. -- 'Linear 1' and 'Linear 2' interpolates the samples with different weighted averages -- 'Hermite' uses a Cubic Hermite spline interpolation that offers a better result (default). +#### CONTEXT MENU +**Sample Slots** +Click on the slot number to open dialog. +When the sample is loaded the green led on the panel is turned on (drumPlayer), or the small 7segment display will show the first 5 chars of the filename (drumPlayer+). +Use Clear options to unload samples from slots. +Just right-click over the led areas or the displays to access the quick-load menus. -At the moment no anti-aliasing filter is present, so best audio quality results can be achieved matching samples/VCV samplerates and limiting speed variations. +**Interpolation** +There are 3 different interpolation algorithms, that are engaged during playback only when the sample samplerate differs from VCV working samplerate or playback speed differs from 100%. +- 'No interpolation' can be used when sample rates match and speed is 100% constant +- 'Linear 1' and 'Linear 2' interpolates the samples with different weighted averages +- 'Hermite' uses a Cubic Hermite spline interpolation that offers a better result (default) -##### DrumPlayer -This version it's almost the same of the Plus one, but it hasn't the sample names display and it can't be external modulated. +**Anti-aliasing filter** +Anti-aliasing filter is made up with 2x oversampling and a 20khz lowpass filter. + +**Outs mode** +Normalled (default): if one slot out is not connected, its output will be added to the next slot +Solo: every slot has its own out socket +Unconnected on Out 4: Every unconnected out is routed to out n.4 NOTE: input trigger threshold is +1v. @@ -226,43 +241,123 @@ NOTE: input trigger threshold is +1v. ![parking](https://user-images.githubusercontent.com/80784296/204013230-cda01462-92c9-4013-8599-c0ba9d798ae0.JPG) -#### - Usage: +#### - INSTRUCTIONS This module doesn't do anything. It's just a place to connect your temporarily unused cables when you don't want to forget to where they were wired. It can also be used to connect other modules sockets when they need to be wired to obtain some functionality. ## Shifter ### 64 selectable stages shift register -#### - Description: +#### - DESCRIPTION - 64 stages shift register that outputs only the selected stage controlled by knob/CV with attenuverter - Trigger delay to adjust the 1-sample latency of VCV cables -![shifter](https://user-images.githubusercontent.com/80784296/204009935-efd147d4-2d28-4b72-a607-af41e7c8e894.JPG) +![shifter](https://user-images.githubusercontent.com/80784296/212537155-aceff24b-4dc8-4c04-9063-fad4543c9cd6.JPG) -#### - Usage: +#### - INSTRUCTIONS Shifter module can be useful to shift back and fotrth a sequencer output on the fly, thanks to the 64 stages register. Stage can be controlled via the stage knob, or the 0-10v StageCV input with its attenuverter. If StageCV input is not connected, the attenuverter reduces the range of the Stage knob. Note that the Stage knob and StageCV are added together. The TRIG DELAY knob can be used to delay the TRIG INPUT up to 5 samples, because of the 1sample latency of VCV cables. This can be useful when you're triggering the sequencer with the same clock of Shifter module, and the input would be sampled before the sequencer advance. -![shifter example](https://user-images.githubusercontent.com/80784296/204090187-9ebec50d-65cf-4ae4-9310-0db271a24d32.JPG) +![shifter example](https://user-images.githubusercontent.com/80784296/212531455-776e3110-78ef-4bec-a3f8-64180fe4ca53.JPG) [Download example](./examples/shifter%20example.vcvs?raw=true) (right-click -> save link as) +## SickoPlayer +### wav sample player + +![sickoplayer](https://user-images.githubusercontent.com/80784296/212481297-755598b1-aa1e-4252-b750-42f86b337f25.JPG) + +#### - DESCRIPTION +- samples and 1-cycle waveforms player +- ±24 semitones tuning and v/oct input with polyphony +- envelope generator, loop, reverse, pingpong +- different interpolation modes, anti-aliasing filter, phase-scan feature + +#### - INSTRUCTIONS +Load sample using context menu or right-click in the waveform display area to access quick load menu. + +The display shows the waveform, filename, sample rate and number of channels (1-2 channels wav file are allowed). + +Mode switch allows to select if sample playback starts with a trigger or play it until a gate is high. + +When in Trig Mode the Trig-Mode switch has 3 options: +- **SS (Start/Stop)** A trigger starts attack stage from CueStart postition, another trigger sets playback to release stage and at the end sample position is reset to cue start +- **S (Start only)** A trigger starts attack stage from CueStart position, another trigger has no effects +- **PP (Play/Pause)** A trigger starts attack stage from curent sample position, another trigger goes to release stage + +In any Trig-Mode a trigger on STOP input sets the playback to release stage and reset sample position to Cue Start. + +Cue Start/End knobs are used to set the start of the Attack and the Release stage. + +When Loop button is switched on, playback restarts from Loop Start when Loop End is reached. + +REV button changes the playback direction. + +PNG button enables PingPong mode: +- in TRIG mode, when loop is enabled, it automatically switches the REV button when Loop Start/End is reached and inverts playback direction without stopping playback +- in GATE mode, it automatically switches the REV button when Loop Start/End is reached when loop is enabled, or when Cue Start/End is reached, and playback direction is inverted without stopping playback + +The envelope knobs can be external modulated with attenuverted CVinputs. + +Tune knob with its attenuverted CVinput, can tune up or down the sample with a ±2 octave range (semitone scale). +v/oct input accepts polyphonic cable usually combined with a polyphonic gate in when in Gate Mode. + +Master knob, with its attenuverted CVinput, sets the output volume from 0 to 200%. Limit switch is a hard clip limiter with a ±5v range. + +If sample file is mono, left out is duplicated to right out. +EOC outputs a 1ms pulse when sample reaches CueEnd or LoopEnd if Loop is enabled (or when Start positions are reached when in reverse playback). +EOR outputs a 1ms pulse when sample reaches the end of release stage. + +NOTE: input trigger threshold is +1v. + +#### CONTEXT MENU +**Sample Slot** +Click on "Load Sample" to open dialog. Use Clear options to unload sample from slot. +As described before, just right-click over the waveform display area to access the quick-load menu. + +**Interpolation** +There are 3 different interpolation algorithms, that are engaged during playback only when the sample samplerate differs from VCV working samplerate or playback speed differs from 100%. +- 'No interpolation' can be used when sample rates match and speed is 100% constant +- 'Linear 1' and 'Linear 2' interpolates the samples with different weighted averages +- 'Hermite' uses a Cubic Hermite spline interpolation that usually offers a better result (default) + +**Anti-aliasing filter** +Anti-aliasing filter is made up with 2x oversampling and a 20khz lowpass filter. + +**Crossfade length** +Crossfade can be set from 0 to 50ms and is engaged when the sample skips from LoopEnd to LoopStart or from CueEnd to CueStart when in Gate Mode. + +**Polyphonic Outs** +When this option is enabled the outs reflects v/oct input polyphony. Otherwise polyphonic outputs are mixed in one monophonic out. + +**Phase scan** +This feature automatically sets Cue and Loop Start/Stop positions at zero crossing points to avoid loop clicks and pops eventually in combination with proper crossfade length. +Be sure to disable it when using one-cycle waveforms. + +#### PRESETS +There are some factory presets stored in the context menu. +Loading a factory preset automatically clears the sample from memory, pay attention. + +#### USING ONE-CYCLE WAVEFORMS +One-cycle waveforms can be used in GATE mode with LOOP mode enabled. +Be sure to disable PhaseScan functionality, adjust Cue and Loop START to 0% and Cue/Loop END to 100%, or load relative factory preset before loading the sample. + ## Switcher / SwitcherSt ### 2>1 switch, 1>2 router, 2 signal swapper, mute, flip flop, toggle gate -#### - Description: -- Function type (switch, route, swap, mute, flipflop, toggle gate) autodetection +#### - DESCRIPTION - Signal switch (2 inputs, 1 output) - Signal router (1 input, 2 outputs) - Signal swapper (2 inputs, 2 outputs) - Mute (1 input, 1 output) - Flip flop - Toggle gate +- Function type autodetection (switch, route, swap, mute, flipflop, toggle gate) - Adjustable time crossfade between switched/routed/swapped signals ![switcher](https://user-images.githubusercontent.com/80784296/201516861-d3d2ab1b-7036-4355-b2ef-e4c5681fb432.JPG) -#### - Usage: +#### - INSTRUCTIONS Switcher or SwitcherSt (used for stereo signals) are multifunction modules that can be used as follows. The versatility of the module is offered thanks to the automatic detection of the function type. **TOGGLE/GATE modes** @@ -308,21 +403,21 @@ CV input is added to Fade knob value and the sum will be clamped in the range of ## Toggler / Toggler Compact ### Stereo signal toggle switch router, with VCA and ASR envelope generator, in regular and compact form factor -#### - Description: +#### - DESCRIPTION - Toggled VCA with builtin ASR envelope generator - Toggled ASR envelope generator - mute/unmute CVs or mono/stereo AUDIO signals according to an ASR envelope activated by a Gate or Toggle Triggers -![toggler](https://user-images.githubusercontent.com/80784296/201516866-3ca90766-503c-435d-a560-ba0f5c02deff.JPG) +![toggler](https://user-images.githubusercontent.com/80784296/211222030-1a5b4e86-eccd-4e4f-ae56-65efd100e336.JPG) -#### - Usage: +#### - INSTRUCTIONS **TOGGLE MODE** On receiving a trigger on TRIG input, it will send the L+(R) inputs to L+(R) outputs and set the GATE output to high. On next trigger it will interrupt L+(R) outputs and set the GATE output to low. Attack, Sustain and Release knobs set the envelope of the routed signal. -A, S, R CVinputs are added to respective knob values. +A, S, R CVinputs are added to respective knob values, Toggler module has attenuverters. If L or (R) inputs are not connected, L and (R) outputs will provide just the envelope, so a mono signal can be connected to L input to route it to L output and nothing connected to (R) input to have the envelope on (R) output. @@ -344,6 +439,8 @@ If Release is set to 0 (and attack is set greater than 0) and a new GATE or Togg These behaviors are more understandable connecting a scope on the output. -## Credits -The Component Library graphics for these modules are copyright © VCV and licensed under [CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) +## CREDITS +The Component Library graphics for these modules are copyright © VCV and licensed under [CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) +Thanks to [Squinkylabs](https://github.com/squinkylabs) and [Firo Lightfog](https://github.com/firolightfog) for help and testing +Thanks to [Omri Cohen](https://omricohen-music.com/) for support diff --git a/changelog.md b/changelog.md index f3befaa..a4f77e8 100644 --- a/changelog.md +++ b/changelog.md @@ -1,15 +1,25 @@ +### 2.5.1 (2023-01-15) +added following modules: +- Drummer4+ +- SickoPlayer + +Added anti-aliasing filter to DrumPlayer and DrumPlayer+ +Added polyphony to Blender and changed front panel +Added attenuverters to Toggler and bToggler +Changed time scale in ms to time knobs of all modules + ### 2.5.0 (2022-12-10) -added following modules: -DrumPlayer -DrumPlayer+ +added following modules: +DrumPlayer +DrumPlayer+ ### 2.4.1 (2022-11-25) -added Shifter module -added "Warn Inversion" context menu feature on bToggler8+ module -layout change on Parking module +added Shifter module +added "Warn Inversion" context menu feature on bToggler8+ module +layout change on Parking module ### 2.4.0 (2022-11-13) -added following modules: +added following modules: - Drummer - Drummer4 - Parking diff --git a/examples/drummer4 example.vcvs b/examples/drummer4 example.vcvs index 21f784e..33a9c7d 100644 --- a/examples/drummer4 example.vcvs +++ b/examples/drummer4 example.vcvs @@ -1,10 +1,86 @@ { "modules": [ { - "id": 3497961449537548, + "id": 223850238714815, + "plugin": "Valley", + "model": "uGraph", + "version": "2.0.4", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.40599998831748962, + "id": 2 + }, + { + "value": 0.3939756453037262, + "id": 3 + }, + { + "value": 0.75783085823059082, + "id": 4 + }, + { + "value": 0.62891554832458496, + "id": 5 + }, + { + "value": 0.57469886541366577, + "id": 6 + }, + { + "value": 0.39156582951545715, + "id": 7 + }, + { + "value": 0.64096337556838989, + "id": 8 + }, + { + "value": 0.16156628727912903, + "id": 9 + } + ], + "data": { + "sequencerMode": 0, + "triggerOutputMode": 0, + "accOutputMode": 0, + "extClockResolution": 0, + "chaosKnobMode": 0, + "runMode": 0, + "panelStyle": 0, + "running": 1 + }, + "pos": [ + -63, + 0 + ] + }, + { + "id": 2901042281631902, + "plugin": "Core", + "model": "Notes", + "version": "2.1.2", + "params": [], + "data": { + "text": "DRUMMER4 IS USED TO ACCENT DRUM ELEMENTS TRIGGERED BY uGRAPH.\n\nTRY TO DISCONNECT 'ACC' CABLES TO GET THE DIFFERENCE" + }, + "pos": [ + -80, + 0 + ] + }, + { + "id": 2409955625037567, "plugin": "SickoCV", "model": "Drummer4", - "version": "2.4.0", + "version": "2.5.1-beta13", "params": [ { "value": 0.0, @@ -23,7 +99,7 @@ "id": 3 }, { - "value": 1.0, + "value": 0.0, "id": 4 }, { @@ -35,15 +111,15 @@ "id": 6 }, { - "value": 1.0, + "value": 0.80000001192092896, "id": 7 }, { - "value": 1.3999999761581421, + "value": 0.5, "id": 8 }, { - "value": 1.0, + "value": 0.5, "id": 9 }, { @@ -51,8 +127,20 @@ "id": 10 }, { - "value": 1.0, + "value": 1.5, "id": 11 + }, + { + "value": 1.0, + "id": 12 + }, + { + "value": 1.0, + "id": 13 + }, + { + "value": 1.0, + "id": 14 } ], "pos": [ @@ -61,23 +149,9 @@ ] }, { - "id": 3070995261695945, - "plugin": "Core", - "model": "Notes", - "version": "2.1.2", - "params": [], - "data": { - "text": "DRUMMER4 IS USED TO ACCENT DRUM ELEMENTS TRIGGERED BY uGRAPH.\n\nTRY TO DISCONNECT 'ACC' CABLES TO GET THE DIFFERENCE" - }, - "pos": [ - -80, - 0 - ] - }, - { - "id": 7797171171641972, + "id": 6490468293922188, "plugin": "Autodafe-DrumKit", - "model": "DrumsKick", + "model": "DrumsHiHatClosed", "version": "2.0.0", "params": [ { @@ -85,19 +159,19 @@ "id": 0 } ], - "rightModuleId": 4346439725187691, + "leftModuleId": 3927591237463672, "data": { "sampletype": 1 }, "pos": [ - -38, + -30, 0 ] }, { - "id": 4346439725187691, + "id": 6342306170980849, "plugin": "Autodafe-DrumKit", - "model": "DrumsSnare", + "model": "DrumsKick", "version": "2.0.0", "params": [ { @@ -105,20 +179,19 @@ "id": 0 } ], - "leftModuleId": 7797171171641972, - "rightModuleId": 777101487573142, + "rightModuleId": 3927591237463672, "data": { "sampletype": 1 }, "pos": [ - -34, + -38, 0 ] }, { - "id": 777101487573142, + "id": 3927591237463672, "plugin": "Autodafe-DrumKit", - "model": "DrumsHiHatClosed", + "model": "DrumsSnare", "version": "2.0.0", "params": [ { @@ -126,17 +199,18 @@ "id": 0 } ], - "leftModuleId": 4346439725187691, + "leftModuleId": 6342306170980849, + "rightModuleId": 6490468293922188, "data": { "sampletype": 1 }, "pos": [ - -30, + -34, 0 ] }, { - "id": 1184885113607329, + "id": 5702467638535008, "plugin": "Fundamental", "model": "Mixer", "version": "2.3.1", @@ -154,188 +228,126 @@ -25, 0 ] - }, - { - "id": 5231550025391975, - "plugin": "Valley", - "model": "uGraph", - "version": "2.0.4", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.40599998831748962, - "id": 2 - }, - { - "value": 0.57228881120681763, - "id": 3 - }, - { - "value": 0.67469853162765503, - "id": 4 - }, - { - "value": 0.53373509645462036, - "id": 5 - }, - { - "value": 0.47228938341140747, - "id": 6 - }, - { - "value": 0.59518057107925415, - "id": 7 - }, - { - "value": 0.8301205039024353, - "id": 8 - }, - { - "value": 0.16156628727912903, - "id": 9 - } - ], - "data": { - "sequencerMode": 0, - "triggerOutputMode": 0, - "accOutputMode": 0, - "extClockResolution": 0, - "chaosKnobMode": 0, - "runMode": 0, - "panelStyle": 0, - "running": 1 - }, - "pos": [ - -63, - 0 - ] } ], "cables": [ { - "id": 4774703347885065, - "outputModuleId": 5231550025391975, + "id": 5823684175079074, + "outputModuleId": 223850238714815, "outputId": 0, - "inputModuleId": 3497961449537548, + "inputModuleId": 2409955625037567, "inputId": 0, "color": "#f3374b" }, { - "id": 2790194009028746, - "outputModuleId": 5231550025391975, + "id": 3974565371374600, + "outputModuleId": 223850238714815, "outputId": 1, - "inputModuleId": 3497961449537548, + "inputModuleId": 2409955625037567, "inputId": 1, "color": "#3695ef" }, { - "id": 4586379066983711, - "outputModuleId": 5231550025391975, + "id": 6497874647626622, + "outputModuleId": 223850238714815, "outputId": 2, - "inputModuleId": 3497961449537548, + "inputModuleId": 2409955625037567, "inputId": 2, "color": "#ffb437" }, { - "id": 1791452362943270, - "outputModuleId": 5231550025391975, + "id": 4335309241939342, + "outputModuleId": 223850238714815, "outputId": 0, - "inputModuleId": 7797171171641972, + "inputModuleId": 6342306170980849, "inputId": 0, "color": "#f3374b" }, { - "id": 8333556453732491, - "outputModuleId": 5231550025391975, + "id": 4222266341004006, + "outputModuleId": 223850238714815, "outputId": 1, - "inputModuleId": 4346439725187691, + "inputModuleId": 3927591237463672, "inputId": 0, "color": "#3695ef" }, { - "id": 110901914169552, - "outputModuleId": 5231550025391975, + "id": 8536420122931654, + "outputModuleId": 223850238714815, "outputId": 2, - "inputModuleId": 777101487573142, + "inputModuleId": 6490468293922188, "inputId": 0, "color": "#ffb437" }, { - "id": 6043275697190761, - "outputModuleId": 7797171171641972, + "id": 6194698884742427, + "outputModuleId": 6342306170980849, "outputId": 0, - "inputModuleId": 3497961449537548, + "inputModuleId": 2409955625037567, "inputId": 8, "color": "#f3374b" }, { - "id": 3235711675445026, - "outputModuleId": 4346439725187691, + "id": 5068268336921712, + "outputModuleId": 3927591237463672, "outputId": 0, - "inputModuleId": 3497961449537548, + "inputModuleId": 2409955625037567, "inputId": 9, "color": "#3695ef" }, { - "id": 276257367877262, - "outputModuleId": 777101487573142, + "id": 2214586665397933, + "outputModuleId": 6490468293922188, "outputId": 0, - "inputModuleId": 3497961449537548, + "inputModuleId": 2409955625037567, "inputId": 10, "color": "#ffb437" }, { - "id": 7977816361358507, - "outputModuleId": 3497961449537548, + "id": 4815836318978239, + "outputModuleId": 2409955625037567, "outputId": 0, - "inputModuleId": 1184885113607329, + "inputModuleId": 5702467638535008, "inputId": 0, "color": "#f3374b" }, { - "id": 7201972880467894, - "outputModuleId": 3497961449537548, + "id": 3369976190819465, + "outputModuleId": 2409955625037567, "outputId": 1, - "inputModuleId": 1184885113607329, + "inputModuleId": 5702467638535008, "inputId": 1, "color": "#3695ef" }, { - "id": 1850465808429826, - "outputModuleId": 3497961449537548, + "id": 8649739344974933, + "outputModuleId": 2409955625037567, "outputId": 2, - "inputModuleId": 1184885113607329, + "inputModuleId": 5702467638535008, "inputId": 2, "color": "#ffb437" }, { - "id": 1592120579850387, - "outputModuleId": 5231550025391975, + "id": 7511800003092808, + "outputModuleId": 223850238714815, "outputId": 3, - "inputModuleId": 3497961449537548, + "inputModuleId": 2409955625037567, "inputId": 4, "color": "#00b56e" }, { - "id": 5904744497133076, - "outputModuleId": 5231550025391975, + "id": 2445988826538185, + "outputModuleId": 223850238714815, "outputId": 5, - "inputModuleId": 3497961449537548, + "inputModuleId": 2409955625037567, "inputId": 6, "color": "#00b56e" }, { - "id": 2165477586161459, - "outputModuleId": 5231550025391975, + "id": 7149353699988909, + "outputModuleId": 223850238714815, "outputId": 4, - "inputModuleId": 3497961449537548, + "inputModuleId": 2409955625037567, "inputId": 5, "color": "#00b56e" } diff --git a/examples/shifter example.vcvs b/examples/shifter example.vcvs index deaf97c..6830a58 100644 --- a/examples/shifter example.vcvs +++ b/examples/shifter example.vcvs @@ -1,10 +1,81 @@ { "modules": [ { - "id": 7527797235935920, + "id": 7121582215935894, + "plugin": "ImpromptuModular", + "model": "Clocked-Clkd", + "version": "2.1.1", + "params": [ + { + "value": 5.0, + "id": 0 + }, + { + "value": -5.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 120.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + } + ], + "data": { + "panelTheme": 0, + "panelContrast": 220.0, + "running": true, + "bpmDetectionMode": false, + "resetOnStartStop": 0, + "ppqn": 4, + "resetClockOutputsHigh": true, + "momentaryRunInput": true, + "forceCvOnBpmOut": false, + "displayIndex": 0, + "trigOuts": [ + false, + false, + false, + false + ], + "clockMaster": -1 + }, + "pos": [ + -84, + 0 + ] + }, + { + "id": 6400718740888415, "plugin": "SickoCV", "model": "Shifter", - "version": "2.4.1", + "version": "2.5.1-beta13", "params": [ { "value": 1.0, @@ -21,12 +92,9 @@ ], "data": { "InitStart": false, - "CurrentStep": 3, + "CurrentStep": 31, "Register": [ 0.0, - -0.25, - -0.83333331346511841, - -0.83333331346511841, -0.58333331346511841, -0.58333331346511841, -0.25, @@ -87,87 +155,19 @@ -0.83333331346511841, -0.83333331346511841, -0.83333331346511841, + -0.83333331346511841, + -0.25, + -0.83333331346511841, -0.83333331346511841 ] }, "pos": [ - 47, - -1 - ] - }, - { - "id": 8394574231844270, - "plugin": "ImpromptuModular", - "model": "Clocked-Clkd", - "version": "2.1.1", - "params": [ - { - "value": 5.0, - "id": 0 - }, - { - "value": -5.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 120.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - }, - { - "value": 0.0, - "id": 9 - } - ], - "data": { - "panelTheme": 0, - "panelContrast": 220.0, - "running": false, - "bpmDetectionMode": false, - "resetOnStartStop": 0, - "ppqn": 4, - "resetClockOutputsHigh": true, - "momentaryRunInput": true, - "forceCvOnBpmOut": false, - "displayIndex": 0, - "trigOuts": [ - false, - false, - false, - false - ], - "clockMaster": -1 - }, - "pos": [ - 14, - -1 + -51, + 0 ] }, { - "id": 3655340153338995, + "id": 3532456181893443, "plugin": "Fundamental", "model": "VCO2", "version": "2.3.1", @@ -201,18 +201,18 @@ "id": 6 } ], - "rightModuleId": 6366808545810631, + "rightModuleId": 7257286608103019, "data": { "waveLen": 1024, "filename": "Basic.wav" }, "pos": [ - 51, - -1 + -47, + 0 ] }, { - "id": 7929617686135553, + "id": 4074760218460966, "plugin": "Fundamental", "model": "VCO2", "version": "2.3.1", @@ -246,18 +246,18 @@ "id": 6 } ], - "rightModuleId": 7068689151377942, + "rightModuleId": 8882760841408555, "data": { "waveLen": 1024, "filename": "Basic.wav" }, "pos": [ - 51, - -2 + -47, + -1 ] }, { - "id": 2730850758737770, + "id": 7752661722201504, "plugin": "ImpromptuModular", "model": "Phrase-Seq-32", "version": "2.1.1", @@ -559,7 +559,7 @@ "id": 74 } ], - "leftModuleId": 7759169675744668, + "leftModuleId": 8222246836378389, "data": { "panelTheme": 0, "panelContrast": 220.0, @@ -2699,12 +2699,12 @@ ] }, "pos": [ - 14, - -2 + -84, + -1 ] }, { - "id": 7068689151377942, + "id": 8882760841408555, "plugin": "Fundamental", "model": "ADSR", "version": "2.3.1", @@ -2746,15 +2746,15 @@ "id": 8 } ], - "leftModuleId": 7929617686135553, - "rightModuleId": 2213245730192373, + "leftModuleId": 4074760218460966, + "rightModuleId": 2374273209093873, "pos": [ - 58, - -2 + -40, + -1 ] }, { - "id": 2213245730192373, + "id": 2374273209093873, "plugin": "Fundamental", "model": "VCA-1", "version": "2.3.1", @@ -2768,61 +2768,40 @@ "id": 1 } ], - "leftModuleId": 7068689151377942, + "leftModuleId": 8882760841408555, "pos": [ - 67, - -2 - ] - }, - { - "id": 4321579215826562, - "plugin": "Fundamental", - "model": "VCA-1", - "version": "2.3.1", - "params": [ - { - "value": 0.61599969863891602, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - } - ], - "leftModuleId": 6366808545810631, - "pos": [ - 67, + -31, -1 ] }, { - "id": 6366808545810631, + "id": 36150136011700, "plugin": "Fundamental", - "model": "ADSR", + "model": "Random", "version": "2.3.1", "params": [ { - "value": 0.1640000194311142, + "value": 1.0, "id": 0 }, { - "value": 0.1499999463558197, + "value": 0.0, "id": 1 }, { - "value": 0.69799959659576416, + "value": 0.0, "id": 2 }, { - "value": 0.33399993181228638, + "value": 0.0, "id": 3 }, { - "value": 0.0, + "value": 1.0, "id": 4 }, { - "value": 0.0, + "value": 1.0, "id": 5 }, { @@ -2836,37 +2815,56 @@ { "value": 0.0, "id": 8 + }, + { + "value": 0.0, + "id": 9 } ], - "leftModuleId": 3655340153338995, - "rightModuleId": 4321579215826562, + "leftModuleId": 7301520820788079, + "pos": [ + -62, + 0 + ] + }, + { + "id": 8222246836378389, + "plugin": "Core", + "model": "Notes", + "version": "2.1.2", + "params": [], + "rightModuleId": 7752661722201504, + "data": { + "text": "PHRASE-SEQ HAS TWO SEQUENCES.\n\nSHIFTER MODULE SHIFTS THE STEPS OF THE SECOND SEQUENCE.\n\nRANDOM STEP SHIFT IS OBTAINED BY THE LFO PASSING THROUGH A SAMPLE & HOLD (RANDOM MODULE) AND THEN TO THE SHIFTER.\n\nTHE SAMPLE & HOLD OUT IS ATTENUVERTED TO HAVE THE SEQUENCE SHIFTED IN THE 1-4 RANGE ONLY.\n\nTHE 'TRIG DELAY' IS SET TO 1 BECAUSE CLOCK IS FEEDING SEQUENCER AND SHIFTER AT THE SAME TIME, BUT THE LATENCY OF THE CABLE FROM SEQUENCER TO SHIFTER MAKES IT NECESSARY TO PROCES THE 'TRIG' INPUT ONE SAMPLE LATER. " + }, "pos": [ - 58, + -100, -1 ] }, { - "id": 1893795678472272, + "id": 5405614949179472, "plugin": "Fundamental", - "model": "Mixer", + "model": "VCA-1", "version": "2.3.1", "params": [ { - "value": 1.0, + "value": 0.61599969863891602, "id": 0 + }, + { + "value": 1.0, + "id": 1 } ], - "data": { - "average": false, - "invert": false - }, + "leftModuleId": 7257286608103019, "pos": [ - 72, - -2 + -31, + 0 ] }, { - "id": 3215338966210003, + "id": 7301520820788079, "plugin": "Fundamental", "model": "LFO", "version": "2.3.1", @@ -2900,40 +2898,60 @@ "id": 6 } ], - "rightModuleId": 408711009305426, + "rightModuleId": 36150136011700, "pos": [ - 27, - -1 + -71, + 0 ] }, { - "id": 408711009305426, + "id": 7613014171209323, "plugin": "Fundamental", - "model": "Random", + "model": "Mixer", "version": "2.3.1", "params": [ { "value": 1.0, "id": 0 + } + ], + "data": { + "average": false, + "invert": false + }, + "pos": [ + -26, + -1 + ] + }, + { + "id": 7257286608103019, + "plugin": "Fundamental", + "model": "ADSR", + "version": "2.3.1", + "params": [ + { + "value": 0.1640000194311142, + "id": 0 }, { - "value": 0.0, + "value": 0.1499999463558197, "id": 1 }, { - "value": 0.0, + "value": 0.69799959659576416, "id": 2 }, { - "value": 0.0, + "value": 0.33399993181228638, "id": 3 }, { - "value": 1.0, + "value": 0.0, "id": 4 }, { - "value": 1.0, + "value": 0.0, "id": 5 }, { @@ -2947,170 +2965,152 @@ { "value": 0.0, "id": 8 - }, - { - "value": 0.0, - "id": 9 } ], - "leftModuleId": 3215338966210003, - "pos": [ - 36, - -1 - ] - }, - { - "id": 7759169675744668, - "plugin": "Core", - "model": "Notes", - "version": "2.1.2", - "params": [], - "rightModuleId": 2730850758737770, - "data": { - "text": "SHIFTER MODULE SHIFTS THE STEPS OF SECOND SEQUENCE OF PHRASE-SEQ, THANKS TO THE MODULATION OF LFO.\nMODULATION IS ATTENUVERTED TO HAVE THE SEQUENCE SHIFTED IN THE 1-4 RANGE ONLY.\n" - }, + "leftModuleId": 3532456181893443, + "rightModuleId": 5405614949179472, "pos": [ - -2, - -2 + -40, + 0 ] } ], "cables": [ { - "id": 5340704383635741, - "outputModuleId": 2730850758737770, + "id": 1966559299986496, + "outputModuleId": 7752661722201504, "outputId": 3, - "inputModuleId": 7527797235935920, + "inputModuleId": 6400718740888415, "inputId": 1, "color": "#8b4ade" }, { - "id": 3591117702391270, - "outputModuleId": 8394574231844270, + "id": 528484621586226, + "outputModuleId": 7121582215935894, "outputId": 1, - "inputModuleId": 2730850758737770, + "inputModuleId": 7752661722201504, "inputId": 3, "color": "#3695ef" }, { - "id": 2364282797832495, - "outputModuleId": 7068689151377942, + "id": 2653550287477040, + "outputModuleId": 8882760841408555, "outputId": 0, - "inputModuleId": 2213245730192373, + "inputModuleId": 2374273209093873, "inputId": 0, "color": "#00b56e" }, { - "id": 629065518684947, - "outputModuleId": 2730850758737770, + "id": 7144682055608276, + "outputModuleId": 7752661722201504, "outputId": 1, - "inputModuleId": 7068689151377942, + "inputModuleId": 8882760841408555, "inputId": 4, "color": "#3695ef" }, { - "id": 7228983751001551, - "outputModuleId": 7929617686135553, + "id": 8070547816788548, + "outputModuleId": 4074760218460966, "outputId": 0, - "inputModuleId": 2213245730192373, + "inputModuleId": 2374273209093873, "inputId": 1, "color": "#f3374b" }, { - "id": 7917208002481420, - "outputModuleId": 2730850758737770, + "id": 8808499654616084, + "outputModuleId": 7752661722201504, "outputId": 4, - "inputModuleId": 6366808545810631, + "inputModuleId": 7257286608103019, "inputId": 4, "color": "#3695ef" }, { - "id": 7107608145342271, - "outputModuleId": 6366808545810631, + "id": 5079393957140924, + "outputModuleId": 7257286608103019, "outputId": 0, - "inputModuleId": 4321579215826562, + "inputModuleId": 5405614949179472, "inputId": 0, "color": "#00b56e" }, { - "id": 4604845150664844, - "outputModuleId": 3655340153338995, + "id": 2462945602672498, + "outputModuleId": 3532456181893443, "outputId": 0, - "inputModuleId": 4321579215826562, + "inputModuleId": 5405614949179472, "inputId": 1, "color": "#f3374b" }, { - "id": 3532468485062862, - "outputModuleId": 8394574231844270, + "id": 8667167972472172, + "outputModuleId": 7121582215935894, "outputId": 1, - "inputModuleId": 7527797235935920, + "inputModuleId": 6400718740888415, "inputId": 0, "color": "#3695ef" }, { - "id": 2006386135031916, - "outputModuleId": 7527797235935920, + "id": 8828235454568441, + "outputModuleId": 6400718740888415, "outputId": 0, - "inputModuleId": 3655340153338995, + "inputModuleId": 3532456181893443, "inputId": 3, "color": "#8b4ade" }, { - "id": 2541385355614945, - "outputModuleId": 2730850758737770, + "id": 2626814834541086, + "outputModuleId": 7752661722201504, "outputId": 0, - "inputModuleId": 7929617686135553, + "inputModuleId": 4074760218460966, "inputId": 3, "color": "#ffb437" }, { - "id": 7481701231147602, - "outputModuleId": 2213245730192373, + "id": 7454456707519889, + "outputModuleId": 2374273209093873, "outputId": 0, - "inputModuleId": 1893795678472272, + "inputModuleId": 7613014171209323, "inputId": 0, "color": "#f3374b" }, { - "id": 3730985494185740, - "outputModuleId": 4321579215826562, + "id": 8614790484067421, + "outputModuleId": 5405614949179472, "outputId": 0, - "inputModuleId": 1893795678472272, + "inputModuleId": 7613014171209323, "inputId": 1, "color": "#f3374b" }, { - "id": 4924328284102293, - "outputModuleId": 3215338966210003, + "id": 633294413841649, + "outputModuleId": 7301520820788079, "outputId": 1, - "inputModuleId": 408711009305426, + "inputModuleId": 36150136011700, "inputId": 3, "color": "#00b56e" }, { - "id": 8440262038779674, - "outputModuleId": 408711009305426, - "outputId": 0, - "inputModuleId": 7527797235935920, - "inputId": 2, - "color": "#00b56e" - }, - { - "id": 5379850927279244, - "outputModuleId": 8394574231844270, + "id": 1575431316854743, + "outputModuleId": 7121582215935894, "outputId": 2, - "inputModuleId": 408711009305426, + "inputModuleId": 36150136011700, "inputId": 2, "color": "#3695ef" }, { - "id": 4108929091004825, - "outputModuleId": 8394574231844270, + "id": 3934933893275933, + "outputModuleId": 7121582215935894, "outputId": 4, - "inputModuleId": 2730850758737770, + "inputModuleId": 7752661722201504, "inputId": 2, "color": "#3695ef" + }, + { + "id": 8346352162984526, + "outputModuleId": 36150136011700, + "outputId": 0, + "inputModuleId": 6400718740888415, + "inputId": 2, + "color": "#00b56e" } ] } \ No newline at end of file diff --git a/extra/crossCompiler.md b/extra/crossCompiler.md new file mode 100644 index 0000000..63cb1f7 --- /dev/null +++ b/extra/crossCompiler.md @@ -0,0 +1,14 @@ +git tag v2.5.1 -m "create v2.5.1" +git push origin --tags + + +### How to build a VCVRack plugin with Github Action + +1. In your plugin repository create a folder `.github/workflows` +2. Put the workflow definition [build-plugin.yml](https://github.com/qno/vcv-plugin-github-actions-example/blob/main/.github/workflows/build-plugin.yml) into this folder +3. Make changes to your sources and push them to Github +4. In your Github repository navigate into the Action tab to see the progress and status of the Workflow run +5. To create a Github Release that contains the built plugin for all platforms you need to create and push a tag, e.g. like this: + * `git tag v2.0.9 -m "create v2.0.9"` + * `git push origin --tags` + * **Note:** Make sure that your tag version number is the same as the version in the [plugin.json](https://github.com/qno/vcv-plugin-github-actions-example/blob/main/plugin.json#L4) and the tag starts with `v` (it is a convention), otherwise the the publish step will be canceled. \ No newline at end of file diff --git a/plugin.json b/plugin.json index b30e974..de99261 100644 --- a/plugin.json +++ b/plugin.json @@ -1,24 +1,25 @@ { "slug": "SickoCV", "name": "SickoCV", - "version": "2.5.0", + "version": "2.5.1", "license": "GPL-3.0-or-later", "brand": "Sickozell", "author": "Sickozell", "authorEmail": "sickozell@sickozell.org", "authorUrl": "http://www.sickozell.org", "pluginUrl": "https://github.com/sickozell/SickoCV", - "manualUrl": "https://github.com/sickozell/SickoCV", + "manualUrl": "https://github.com/sickozell/SickoCV/blob/main/README.md", "sourceUrl": "https://github.com/sickozell/SickoCV", - "donateUrl": "", - "changelogUrl": "", + "donateUrl": "https://paypal.me/sickozell", + "changelogUrl": "https://github.com/sickozell/SickoCV/blob/main/changelog.md", "modules": [ { "slug": "Blender", "name": "Blender", "description": "Stereo crossfade mixer with double modulation", "tags": [ - "Mixer" + "Mixer", + "Polyphonic" ] }, { @@ -36,7 +37,7 @@ "tags": [ "Logic", "Envelope generator", - "Voltage-controlled amplifier" + "Voltage-controlled amplifier" ] }, { @@ -46,7 +47,7 @@ "tags": [ "Logic", "Envelope generator", - "Voltage-controlled amplifier" + "Voltage-controlled amplifier" ] }, { @@ -59,7 +60,7 @@ }, { "slug": "BtogglerPlus", - "name": "bToggler8Plus", + "name": "bToggler8+", "description": "8 buffered toggle switch router, plus warnings to use with led midi controllers", "tags": [ "Logic", @@ -81,13 +82,23 @@ "tags": [ "Utility", "Drum", - "Dual" + "Dual" ] }, { "slug": "Drummer4", "name": "Drummer4", - "description": "4 channel accent utility for drum modules lacking this feature", + "description": "4 channel accent and choke utility for drum modules lacking this feature", + "tags": [ + "Utility", + "Drum", + "Quad" + ] + }, + { + "slug": "Drummer4Plus", + "name": "Drummer4+", + "description": "4 channel accent and choke utility for drum modules lacking this feature", "tags": [ "Utility", "Drum", @@ -100,16 +111,18 @@ "description": "Drum Sample Player", "tags": [ "Sampler", - "Drum" + "Drum", + "Quad" ] }, { "slug": "DrumPlayerPlus", - "name": "Drum Player Plus", + "name": "Drum Player+", "description": "Drum Sample Player", "tags": [ "Sampler", - "Drum" + "Drum", + "Quad" ] }, { @@ -129,6 +142,15 @@ "Utility" ] }, + { + "slug": "SickoPlayer", + "name": "SickoPlayer", + "description": "Sample Player", + "tags": [ + "Sampler", + "Polyphonic" + ] + }, { "slug": "Switcher", "name": "Switcher", @@ -154,7 +176,7 @@ "tags": [ "Logic", "Envelope generator", - "Voltage-controlled amplifier" + "Voltage-controlled amplifier" ] }, { @@ -164,8 +186,8 @@ "tags": [ "Logic", "Envelope generator", - "Voltage-controlled amplifier" + "Voltage-controlled amplifier" ] } ] -} \ No newline at end of file +} diff --git a/presets/SickoPlayer/One Cycle Waveform.vcvm b/presets/SickoPlayer/One Cycle Waveform.vcvm new file mode 100644 index 0000000..4e0e4e0 --- /dev/null +++ b/presets/SickoPlayer/One Cycle Waveform.vcvm @@ -0,0 +1,95 @@ +{ + "plugin": "SickoCV", + "model": "SickoPlayer", + "version": "2.5.1", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 1.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 1.0, + "id": 7 + }, + { + "value": 0.05000000074505806, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 9.9999997473787516e-5, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 1.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.20000000298023224, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 1.0, + "id": 19 + } + ], + "data": { + "Interpolation": 3, + "AntiAlias": 1, + "xfade": 0, + "PolyOuts": 0, + "PhaseScan": false, + "Slot": "" + } +} \ No newline at end of file diff --git a/presets/SickoPlayer/Triggered Sample w envelope.vcvm b/presets/SickoPlayer/Triggered Sample w envelope.vcvm new file mode 100644 index 0000000..49fa57f --- /dev/null +++ b/presets/SickoPlayer/Triggered Sample w envelope.vcvm @@ -0,0 +1,95 @@ +{ + "plugin": "SickoCV", + "model": "SickoPlayer", + "version": "2.5.1", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 1.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 1.0, + "id": 7 + }, + { + "value": 0.20000000298023224, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 9.9999997473787516e-5, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 1.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.20000000298023224, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 1.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + } + ], + "data": { + "Interpolation": 3, + "AntiAlias": 1, + "xfade": 2, + "PolyOuts": 0, + "PhaseScan": true, + "Slot": "" + } +} \ No newline at end of file diff --git a/res/Blender.svg b/res/Blender.svg index c3c9bed..33b900e 100644 --- a/res/Blender.svg +++ b/res/Blender.svg @@ -24,18 +24,270 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showgrid="false" - inkscape:zoom="4.0000001" - inkscape:cx="56.499999" - inkscape:cy="464.24999" + inkscape:zoom="4" + inkscape:cx="130.875" + inkscape:cy="298" inkscape:window-width="1920" inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="g7864" + inkscape:current-layer="layer4" showguides="true" /> + + + + + + + + + + + + + + + + + + + + + + + - - + + style="display:inline;fill:#f2f2f2;stroke:none;stroke-width:0.300964;stroke-dasharray:none" + id="rect11622" + width="0.59676164" + height="0.91414613" + x="31.151863" + y="72.508003" + ry="0.083104193" + inkscape:label="line circle 1" /> + + style="display:inline;fill:#f2f2f2;stroke:none;stroke-width:0.300964;stroke-dasharray:none" + id="rect30860" + width="0.59676164" + height="0.91414613" + x="11.440405" + y="88.82" + ry="0.083104193" + inkscape:label="line circle 1" /> + + + + + + + + + + + + + + + ^ - ^ - (R) + style="font-size:2.82222px;text-align:center;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.265" + x="38.464611" + y="109.94516">(R) L + style="font-size:2.82222px;text-align:center;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.265" + x="28.034721" + y="109.94516">L OUT + style="font-size:3.175px;text-align:center;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.265" + x="33.289936" + y="105.89913">OUT + L + O + V B + x="15.450001" + y="108.05319">B U + x="15.450001" + y="104.04034">U ATNV MD + style="font-size:2.46944px;text-align:center;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.25294" + x="5.0216999" + y="96.298256">MOD2 B + x="22.19068" + y="80.594467">B U - RNG - CV - ATNV + x="22.19068" + y="76.92363">U MIX MOD + x="20.308319" + y="71.524124">MOD 1/2 - MIX + style="font-size:3.52778px;text-align:center;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.265" + x="32.473114" + y="62.153587">2 PHASE + id="tspan39347" + style="font-size:3.52778px;text-align:center;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.265" + x="13.423113" + y="62.153587">1 IN2 - PHASE IN1 + /\ + /\ + /\ + /\ + /\ + /\ + /\ + /\ - - - - - - + transform="translate(0.30037173,0.300062)"> + id="path30005" /> + id="path30007" /> + id="path30009" /> + id="path30012" /> + + id="path30017" /> + + + + id="path30022" /> + + + id="path30025" /> + + + + id="path30031" /> + id="path30034" /> - - + id="text29671" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.252939;stroke-dasharray:0.252939, 0.252939" + inkscape:label="MOD2"> + id="path30037" /> + id="path30039" /> + id="path30041" /> + id="path30043" /> + id="path30046" /> - - - - - - - - - - - - - - - - - - - - - - - + id="path30049" /> + inkscape:label="MOD"> + id="path30052" /> + id="path30054" /> + id="path30056" /> - - + aria-label="2" + id="text29687" + style="font-size:3.52778px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="2"> + id="path30059" /> - + aria-label="1" + id="text29691" + style="font-size:3.52778px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="1"> - - - + id="path30062" /> + id="path30065" /> + id="path30067" /> + id="path30069" /> + id="path30072" /> + id="path30075" /> + id="path30077" /> - - - - - - - + id="path30079" /> + id="path30082" /> + id="path30084" /> + id="path30086" /> + id="path30089" /> + id="path30092" /> + id="path30094" /> + id="path30096" /> + + + + + + + + + + + + + + + + + + + + - - - + aria-label="/\" + transform="scale(0.71753162,-1.3936668)" + id="text29739" + style="font-size:1.26565px;font-family:'C64 User';-inkscape-font-specification:'C64 User';display:inline;fill:#000000;stroke-width:0.190145;stroke-dasharray:0.190145, 0.190145" + inkscape:label="ph1"> + + - + aria-label="/\" + transform="scale(0.71753162,-1.3936668)" + id="text29743" + style="font-size:1.26565px;font-family:'C64 User';-inkscape-font-specification:'C64 User';display:inline;fill:#000000;stroke-width:0.190145;stroke-dasharray:0.190145, 0.190145" + inkscape:label="invph1"> + + + + + + + + + d="m 36.171557,109.94516 v -0.35278 H 35.81878 v -0.35278 h -0.352778 v -1.05833 h 0.352778 v -0.35278 h 0.352777 v -0.35277 h 0.705555 v 0.35277 h -0.352777 v 0.35278 h -0.352778 v 1.05833 h 0.352778 v 0.35278 h 0.352777 v 0.35278 z" + style="stroke-width:0.265" + id="path29871" /> + d="m 37.22989,109.94516 v -2.46944 h 1.763887 v 0.35277 h 0.352778 v 0.70556 h -0.352778 v 0.35278 H 38.641 v 0.35277 h 0.352777 v 0.35278 h 0.352778 v 0.35278 H 38.641 v -0.35278 h -0.352778 v -0.35278 h -0.352777 v 0.70556 z m 0.705555,-1.41111 H 38.641 v -0.70556 h -0.705555 z" + style="stroke-width:0.265" + id="path29873" /> + d="m 39.699332,109.94516 v -0.35278 h 0.352778 v -0.35278 h 0.352777 v -1.05833 H 40.05211 v -0.35278 h -0.352778 v -0.35277 h 0.705555 v 0.35277 h 0.352778 v 0.35278 h 0.352778 v 1.05833 h -0.352778 v 0.35278 h -0.352778 v 0.35278 z" + style="stroke-width:0.265" + id="path29875" /> + d="m 27.505555,107.47572 v 2.11666 h 1.41111 v 0.35278 H 26.8 v -2.46944 z" + style="stroke-width:0.265" + id="path29878" /> + d="m 29.519624,105.89913 v -0.39687 h -0.396875 v -1.98438 h 0.396875 v -0.39687 h 1.5875 v 0.39687 h 0.396875 v 1.98438 h -0.396875 v 0.39687 z m 0.396875,-0.39687 h 0.79375 v -1.98438 h -0.79375 z" + style="stroke-width:0.265" + id="path29881" /> + + d="m 35.472749,105.89913 v -2.38125 h -0.79375 v -0.39687 h 2.38125 v 0.39687 h -0.79375 v 2.38125 z" + style="stroke-width:0.265" + id="path29885" /> + + + + + + + + + d="M 24.35536,91.31633 V 91.00765 H 24.04668 V 90.69897 H 23.738 v -1.5434 h 0.61736 v 1.5434 h 0.61736 v -1.5434 h 0.61736 v 1.5434 H 25.2814 v 0.30868 h -0.30868 v 0.30868 z" + style="stroke-width:0.265" + id="path29894" /> + id="path29897" /> + id="path29900" /> - + id="text29791" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.252939;stroke-dasharray:0.252939, 0.252939" + inkscape:label="MOD2"> + id="path29903" /> + id="path29905" /> + id="path29907" /> - + id="path29909" /> + id="path29912" /> - - - - - - - - - + id="path29915" /> - - - - - - - - + inkscape:label="MOD"> + id="path29918" /> + id="path29920" /> - + id="path29922" /> + aria-label="2" + id="text29807" + style="font-size:3.52778px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="2"> - - + id="path29925" /> + aria-label="1" + id="text29811" + style="font-size:3.52778px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="1"> - - - - - - - - - + id="path29928" /> + id="path29931" /> + id="path29933" /> + id="path29935" /> + id="path29938" /> + id="path29941" /> + id="path29943" /> - - - - - - - + id="path29945" /> + id="path29948" /> + id="path29950" /> + id="path29952" /> + id="path29955" /> + id="path29958" /> + id="path29960" /> + id="path29962" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/res/Blender8.svg b/res/Blender8.svg index 84df3c1..ebe56d2 100644 --- a/res/Blender8.svg +++ b/res/Blender8.svg @@ -24,15 +24,15 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showgrid="false" - inkscape:zoom="2" - inkscape:cx="164" - inkscape:cy="53.5" + inkscape:zoom="1.4142136" + inkscape:cx="114.19775" + inkscape:cy="167.58431" inkscape:window-width="1920" inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="g7864" + inkscape:current-layer="layer1" showguides="true" /> @@ -1130,9 +1130,4 @@ style="fill:#e6e6e6;stroke:none" /> - - - R + y="51.778126">R S + y="51.778126">S A + y="51.778126">A RESET + y="31.804873">RESET ARM CLOCK + y="16.92845">CLOCK + inkscape:label="R rel" + transform="translate(0,-23.108671)"> + inkscape:label="S sus" + transform="translate(0,-23.108671)"> + inkscape:label="A att" + transform="translate(0,-23.108671)"> + inkscape:label="reset" + transform="translate(0,-7.4000155)"> @@ -604,7 +707,7 @@ @@ -749,7 +852,8 @@ aria-label="R" id="text2009" style="font-size:3.175px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" - inkscape:label="R rel"> + inkscape:label="R rel" + transform="translate(0,-23.108671)"> + inkscape:label="S sus" + transform="translate(0,-23.108671)"> + inkscape:label="A att" + transform="translate(0,-23.108671)"> + inkscape:label="reset" + transform="translate(0,-7.4000155)"> @@ -822,7 +929,7 @@ @@ -965,10 +1072,4 @@ style="fill:#e6e6e6" /> - diff --git a/res/BtogglerStCompact.svg b/res/BtogglerStCompact.svg index 7a799e8..622f21a 100644 --- a/res/BtogglerStCompact.svg +++ b/res/BtogglerStCompact.svg @@ -25,14 +25,14 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="2.8284271" - inkscape:cx="16.263456" - inkscape:cy="130.81476" + inkscape:cx="10.783379" + inkscape:cy="329.15821" inkscape:window-width="1920" inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="layer7" + inkscape:current-layer="g15193" showguides="true" /> @@ -325,7 +325,7 @@ - diff --git a/res/Calcs.svg b/res/Calcs.svg index 68bc285..29bd4a2 100644 --- a/res/Calcs.svg +++ b/res/Calcs.svg @@ -25,14 +25,14 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="4.0000001" - inkscape:cx="17.75" - inkscape:cy="-31.749999" + inkscape:cx="13.875" + inkscape:cy="-31.499999" inkscape:window-width="1920" inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="g7864-5" + inkscape:current-layer="g16210" showguides="true" /> @@ -653,7 +653,7 @@ - drumPlayer diff --git a/res/DrumPlayerPlus.svg b/res/DrumPlayerPlus.svg index 1cdfff6..0edb12d 100644 --- a/res/DrumPlayerPlus.svg +++ b/res/DrumPlayerPlus.svg @@ -24,15 +24,15 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showgrid="false" - inkscape:zoom="1.4142135" - inkscape:cx="259.15465" - inkscape:cy="158.39193" + inkscape:zoom="2.828427" + inkscape:cx="135.58773" + inkscape:cy="344.00746" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="layer1" + inkscape:current-layer="layer4" showguides="true" />LIM2x1x20ACCTRIGTRGOFF2x1x20LIM2x1x20ACCTRIGTRGOFF2x1x20LIM2x1x20ACCTRIGTRGOFF2x21x0LIM2x21x0ACCTRIGTRG-2x21x0drumPlayerdrumPlayer diff --git a/res/Drummer.svg b/res/Drummer.svg index a0b519f..289d31b 100644 --- a/res/Drummer.svg +++ b/res/Drummer.svg @@ -24,15 +24,15 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showgrid="false" - inkscape:zoom="1.0336252" - inkscape:cx="-152.37632" - inkscape:cy="238.96476" + inkscape:zoom="2.9235336" + inkscape:cx="79.184997" + inkscape:cy="99.537081" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="g5462" + inkscape:current-layer="layer1" showguides="true" /> @@ -230,6 +230,26 @@ y="63.697777" ry="0.23370494" inkscape:label="switchLimit" /> + + + + ACC + y="26.107725">ACC TRIG + y="12.749796">TRG ACC + y="91.939774">ACC TRIG + y="78.680771">TRG 2x + id="tspan1114">2 1x + y="12.749796" + id="tspan1174">SLV 2x + id="tspan1228">2 1x + y="26.107725" + id="tspan1236">ALV 2x + id="tspan1240">2 1x + y="78.680771" + id="tspan1248">SLV 2x + id="tspan1252">2 1x + y="91.939774" + id="tspan1260">ALV + transform="translate(0.30003772,0.30000031)"> + id="path12533" /> + id="path12535" /> + id="path12537" /> + id="path12540" /> + id="path12542" /> + id="path12545" /> + id="path12547" /> + id="path12549" /> - + id="path12552" /> + id="path12554" /> + id="path12556" /> + id="path12559" /> + id="path12561" /> + id="path12563" /> + id="path12566" /> + id="path12568" /> + id="path12571" /> + id="path12573" /> + id="path12575" /> + id="path12578" /> + id="path12580" /> - + id="path12582" /> + id="path12585" /> + id="path12587" /> + id="path12589" /> + id="path12591" /> + id="path12593" /> + id="path12596" /> + id="path12598" /> + id="path12601" /> + id="path12603" /> + id="path12605" /> + id="path12608" /> + id="path12610" /> + id="path12612" /> + id="path12614" /> + id="path12616" /> + id="path12619" /> + id="path12621" /> + id="path12623" /> + id="path12626" /> + id="path12628" /> + id="path12631" /> + id="path12634" /> - + id="path12637" /> + id="path12640" /> + + id="path12645" /> + id="path12647" /> - + id="path12650" /> + id="path12653" /> + + id="path12658" /> + id="path12660" /> - + id="path12663" /> + id="path12666" /> + id="path12669" /> + id="path12671" /> + - + id="path12676" /> + id="path12679" /> + + id="path12684" /> + id="path12686" /> + id="path12689" /> + id="path12691" /> + id="path12693" /> + id="path12697" /> + id="path12699" /> + id="path12703" /> + id="path12705" /> + id="path12707" /> - + id="path12711" /> + id="path12713" /> + id="path12715" /> + id="path12719" /> + id="path12721" /> + id="path12723" /> + id="path12727" /> + id="path12729" /> + id="path12733" /> + id="path12735" /> + id="path12737" /> + id="path12741" /> + id="path12743" /> - + id="path12745" /> + id="path12749" /> + id="path12751" /> + id="path12753" /> + id="path12755" /> + id="path12757" /> + id="path12761" /> + id="path12763" /> + id="path12767" /> + id="path12769" /> + id="path12771" /> + id="path12775" /> + id="path12777" /> + id="path12779" /> + id="path12781" /> + id="path12783" /> + id="path12787" /> + id="path12789" /> + id="path12791" /> + id="path12795" /> + id="path12797" /> + id="path12801" /> + id="path12805" /> - + id="path12809" /> + id="path12813" /> + + id="path12819" /> + id="path12821" /> - + id="path12825" /> + id="path12829" /> + id="path12833" /> + id="path12835" /> + - + id="path12841" /> + id="path12845" /> + id="path12849" /> + id="path12851" /> + - + id="path12857" /> + id="path12861" /> + + id="path12867" /> + id="path12869" /> - diff --git a/res/Drummer4.svg b/res/Drummer4.svg index cd4ea95..6be68f2 100644 --- a/res/Drummer4.svg +++ b/res/Drummer4.svg @@ -24,9 +24,9 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showgrid="false" - inkscape:zoom="1.4617668" - inkscape:cx="-39.33596" - inkscape:cy="231.22704" + inkscape:zoom="2.9235336" + inkscape:cx="160.25128" + inkscape:cy="258.59118" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="1272" @@ -176,15 +176,6 @@ y="111.29217" ry="2.0000165" inkscape:label="output rect" /> - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + transform="translate(0.3000519,0.29966676)"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + d="m 44.952004,110.19345 v -0.35278 h -0.352777 v -1.76388 h 0.352777 v -0.35278 h 1.41111 v 0.35278 h 0.352778 v 1.76388 h -0.352778 v 0.35278 z m 0.352778,-0.35278 h 0.705555 v -1.76388 h -0.705555 z" + style="fill:#000000;stroke-width:0.265" + id="path34469" /> + d="m 47.421447,110.19345 v -0.35278 h -0.352778 v -2.11666 h 0.705555 v 2.11666 h 0.705555 v -2.11666 h 0.705555 v 2.11666 h -0.352777 v 0.35278 z" + style="fill:#000000;stroke-width:0.265" + id="path34471" /> + d="m 50.243667,110.19345 v -2.11666 h -0.705555 v -0.35278 h 2.116665 v 0.35278 h -0.705555 v 2.11666 z" + style="fill:#000000;stroke-width:0.265" + id="path34473" /> + aria-label="OUT" + id="text34285" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="OUT1"> - - + d="m 31.492005,110.19345 v -0.35278 h -0.352777 v -1.76388 h 0.352777 v -0.35278 h 1.41111 v 0.35278 h 0.352778 v 1.76388 h -0.352778 v 0.35278 z m 0.352778,-0.35278 h 0.705555 v -1.76388 h -0.705555 z" + style="fill:#000000;stroke-width:0.265" + id="path34476" /> + d="m 33.961448,110.19345 v -0.35278 H 33.60867 v -2.11666 h 0.705555 v 2.11666 h 0.705555 v -2.11666 h 0.705555 v 2.11666 h -0.352777 v 0.35278 z" + style="fill:#000000;stroke-width:0.265" + id="path34478" /> + d="m 36.783668,110.19345 v -2.11666 h -0.705555 v -0.35278 h 2.116665 v 0.35278 h -0.705555 v 2.11666 z" + style="fill:#000000;stroke-width:0.265" + id="path34480" /> + id="path34483" /> + id="path34485" /> - - - - + id="path34487" /> + aria-label="OUT" + id="text34293" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="OUT1"> + d="m 4.5717256,110.19345 v -0.35278 H 4.2189481 v -1.76388 h 0.3527775 v -0.35278 h 1.41111 v 0.35278 h 0.3527775 v 1.76388 H 5.9828356 v 0.35278 z m 0.3527775,-0.35278 h 0.705555 v -1.76388 h -0.705555 z" + style="fill:#000000;stroke-width:0.265" + id="path34490" /> + d="m 7.0411682,110.19345 v -0.35278 H 6.6883907 v -2.11666 h 0.705555 v 2.11666 h 0.705555 v -2.11666 h 0.705555 v 2.11666 H 8.4522782 v 0.35278 z" + style="fill:#000000;stroke-width:0.265" + id="path34492" /> + d="m 9.8633883,110.19345 v -2.11666 h -0.705555 v -0.35278 h 2.1166647 v 0.35278 h -0.705555 v 2.11666 z" + style="fill:#000000;stroke-width:0.265" + id="path34494" /> - + id="text34297" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="LIMIT"> + id="path34497" /> + id="path34499" /> + id="path34501" /> + id="path34504" /> + id="path34506" /> - - + id="path34508" /> + id="text34305" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="LIMIT"> + id="path34511" /> + id="path34513" /> + id="path34515" /> + id="text34309" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="LIMIT"> + id="path34518" /> - - + id="path34520" /> + id="path34522" /> + aria-label="CHK" + transform="scale(0.94561118,1.0575171)" + id="text34313" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.250587;stroke-dasharray:0.250587, 0.250587" + inkscape:label="CHOKE"> - - + d="m 33.959792,81.261444 v -0.30868 h -0.30868 v -1.543403 h 0.30868 V 79.10068 h 1.234723 v 0.308681 h 0.30868 v 0.30868 h -0.617361 v -0.30868 h -0.617361 v 1.543403 h 0.617361 v -0.308681 h 0.617361 v 0.308681 h -0.30868 v 0.30868 z" + style="fill:#000000;stroke-width:0.250588" + id="path34525" /> + d="M 35.811876,81.261444 V 79.10068 h 0.617361 v 0.926042 h 0.617361 V 79.10068 h 0.617361 v 2.160764 h -0.617361 v -0.926042 h -0.617361 v 0.926042 z" + style="fill:#000000;stroke-width:0.250588" + id="path34527" /> + d="M 37.97264,81.261444 V 79.10068 h 0.617361 v 0.617361 h 0.30868 v -0.30868 h 0.308681 V 79.10068 h 0.617361 v 0.308681 h -0.30868 v 0.30868 h -0.308681 v 0.308681 h -0.308681 v 0.30868 h 0.308681 v 0.308681 h 0.308681 v 0.308681 h 0.30868 v 0.30868 h -0.617361 v -0.30868 h -0.308681 v -0.308681 h -0.30868 v 0.617361 z" + style="fill:#000000;stroke-width:0.250588" + id="path34529" /> + aria-label="CHK" + transform="scale(0.94561118,1.0575171)" + id="text34317" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.250587;stroke-dasharray:0.250587, 0.250587" + inkscape:label="CHOKE"> - - + d="m 19.683313,81.261444 v -0.30868 h -0.308681 v -1.543403 h 0.308681 V 79.10068 h 1.234722 v 0.308681 h 0.30868 v 0.30868 h -0.617361 v -0.30868 h -0.617361 v 1.543403 h 0.617361 v -0.308681 h 0.617361 v 0.308681 h -0.30868 v 0.30868 z" + style="fill:#000000;stroke-width:0.250588" + id="path34532" /> + d="M 21.535396,81.261444 V 79.10068 h 0.617361 v 0.926042 h 0.617361 V 79.10068 h 0.617361 v 2.160764 h -0.617361 v -0.926042 h -0.617361 v 0.926042 z" + style="fill:#000000;stroke-width:0.250588" + id="path34534" /> + d="M 23.69616,81.261444 V 79.10068 h 0.617361 v 0.617361 h 0.308681 v -0.30868 h 0.30868 V 79.10068 h 0.617361 v 0.308681 h -0.30868 v 0.30868 h -0.308681 v 0.308681 h -0.30868 v 0.30868 h 0.30868 v 0.308681 h 0.308681 v 0.308681 h 0.30868 v 0.30868 h -0.617361 v -0.30868 h -0.30868 v -0.308681 h -0.308681 v 0.617361 z" + style="fill:#000000;stroke-width:0.250588" + id="path34536" /> + aria-label="CHK" + transform="scale(0.94561118,1.0575171)" + id="text34321" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.250587;stroke-dasharray:0.250587, 0.250587" + inkscape:label="CHOKE"> + d="m 5.4073565,81.261444 v -0.30868 H 5.0986759 V 79.409361 H 5.4073565 V 79.10068 h 1.2347222 v 0.308681 h 0.3086806 v 0.30868 H 6.3333981 v -0.30868 H 5.716037 v 1.543403 h 0.6173611 v -0.308681 h 0.6173612 v 0.308681 H 6.6420787 v 0.30868 z" + style="fill:#000000;stroke-width:0.250588" + id="path34539" /> - - + d="M 7.2594399,81.261444 V 79.10068 H 7.876801 v 0.926042 H 8.4941621 V 79.10068 h 0.6173612 v 2.160764 H 8.4941621 V 80.335402 H 7.876801 v 0.926042 z" + style="fill:#000000;stroke-width:0.250588" + id="path34541" /> + d="M 9.4202038,81.261444 V 79.10068 h 0.6173612 v 0.617361 h 0.308681 v -0.30868 h 0.30868 V 79.10068 h 0.617361 v 0.308681 h -0.30868 v 0.30868 h -0.308681 v 0.308681 h -0.30868 v 0.30868 h 0.30868 v 0.308681 h 0.308681 v 0.308681 h 0.30868 v 0.30868 h -0.617361 v -0.30868 h -0.30868 v -0.308681 h -0.308681 v 0.617361 z" + style="fill:#000000;stroke-width:0.250588" + id="path34543" /> + id="text34325" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="IN1"> + id="path34546" /> - - - - - + id="path34548" /> + id="path34551" /> - - - - - - - - - - - - - - - - - - - - - - - + id="path34553" /> + inkscape:label="IN1"> + id="path34556" /> + id="path34558" /> + inkscape:label="IN1"> - - + id="path34561" /> + id="path34563" /> - + id="path34566" /> - - - - + id="path34569" /> - + id="path34572" /> - - - - - - - - - - - - - + id="text34353" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="0x"> + id="path34575" /> + id="text34357" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="2x"> + id="path34578" /> + + + id="path34581" /> + + + id="path34584" /> + id="text34369" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="0x"> + id="path34587" /> + + + id="path34590" /> + id="path34592" /> + id="path34594" /> - - + id="text34377" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="alv"> + id="path34597" /> + id="path34599" /> + id="path34601" /> + id="text34381" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="alv"> + id="path34604" /> + id="path34606" /> + id="path34608" /> + id="text34385" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="alv"> + + id="path34613" /> + id="path34615" /> + id="text34389" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="2x"> + id="path34618" /> + id="text34393" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="0x"> + id="path34621" /> - + id="path34624" /> + id="path34627" /> + inkscape:label="2x"> + id="path34630" /> + + + id="path34633" /> - + id="path34636" /> + id="path34639" /> + id="text34421" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="ACCENT1"> + + id="path34644" /> + id="path34646" /> - - + aria-label="ACC" + transform="scale(0.98925647,1.0108602)" + id="text34425" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="ACCENT1"> + d="M 31.515715,43.028957 V 41.26507 h 0.352778 v -0.352778 h 0.352777 v -0.352777 h 0.705555 v 0.352777 h 0.352778 v 0.352778 h 0.352777 v 1.763887 H 32.926825 V 41.970625 H 32.22127 v 1.058332 z m 0.705555,-1.41111 h 0.705555 V 41.26507 H 32.22127 Z" + style="fill:#000000;stroke-width:0.262154" + id="path34649" /> + d="M 34.337935,43.028957 V 42.67618 h -0.352777 v -1.763888 h 0.352777 v -0.352777 h 1.41111 v 0.352777 h 0.352778 v 0.352778 h -0.705555 v -0.352778 h -0.705555 v 1.763888 h 0.705555 v -0.352778 h 0.705555 v 0.352778 h -0.352778 v 0.352777 z" + style="fill:#000000;stroke-width:0.262154" + id="path34651" /> + d="M 36.807378,43.028957 V 42.67618 H 36.4546 v -1.763888 h 0.352778 v -0.352777 h 1.41111 v 0.352777 h 0.352778 v 0.352778 h -0.705555 v -0.352778 h -0.705555 v 1.763888 h 0.705555 v -0.352778 h 0.705555 v 0.352778 h -0.352778 v 0.352777 z" + style="fill:#000000;stroke-width:0.262154" + id="path34653" /> + id="text34429" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="ACCENT1"> + d="M 17.909539,43.028957 V 41.26507 h 0.352777 v -0.352778 h 0.352778 v -0.352777 h 0.705555 v 0.352777 h 0.352777 v 0.352778 h 0.352778 v 1.763887 h -0.705555 v -1.058332 h -0.705555 v 1.058332 z m 0.705555,-1.41111 h 0.705555 V 41.26507 h -0.705555 z" + style="fill:#000000;stroke-width:0.262154" + id="path34656" /> + d="M 20.731759,43.028957 V 42.67618 h -0.352777 v -1.763888 h 0.352777 v -0.352777 h 1.41111 v 0.352777 h 0.352778 v 0.352778 h -0.705555 v -0.352778 h -0.705555 v 1.763888 h 0.705555 v -0.352778 h 0.705555 v 0.352778 h -0.352778 v 0.352777 z" + style="fill:#000000;stroke-width:0.262154" + id="path34658" /> + + style="fill:#000000;stroke-width:0.262154" + id="path34663" /> + style="fill:#000000;stroke-width:0.262154" + id="path34665" /> + style="fill:#000000;stroke-width:0.262154" + id="path34667" /> - + id="text34437" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="SLV"> + d="M 46.256604,26.830812 V 26.566229 H 45.99202 v -0.264584 h 0.529167 v 0.264584 h 0.529168 V 26.037061 H 46.256604 V 25.772478 H 45.99202 V 25.24331 h 0.264584 v -0.264584 h 1.058335 v 0.264584 h 0.264583 v 0.264584 H 47.050355 V 25.24331 h -0.529168 v 0.529168 h 0.793752 v 0.264583 h 0.264583 v 0.529168 h -0.264583 v 0.264583 z" + style="fill:#000000;stroke-width:0.262154" + id="path34670" /> + d="m 48.373274,24.978726 v 1.587503 h 1.058335 v 0.264583 h -1.587503 v -1.852086 z" + style="fill:#000000;stroke-width:0.262154" + id="path34672" /> + d="m 50.22536,26.830812 v -0.264583 h -0.264584 v -0.264584 h -0.264584 v -1.322919 h 0.529168 v 1.322919 h 0.529167 v -1.322919 h 0.529168 v 1.322919 h -0.264584 v 0.264584 h -0.264584 v 0.264583 z" + style="fill:#000000;stroke-width:0.262154" + id="path34674" /> - - + id="text34441" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="SLV"> + d="m 32.650425,26.830812 v -0.264583 h -0.264583 v -0.264584 h 0.529167 v 0.264584 h 0.529168 V 26.037061 H 32.650425 V 25.772478 H 32.385842 V 25.24331 h 0.264583 v -0.264584 h 1.058335 v 0.264584 h 0.264584 v 0.264584 H 33.444177 V 25.24331 h -0.529168 v 0.529168 h 0.793751 v 0.264583 h 0.264584 v 0.529168 H 33.70876 v 0.264583 z" + style="fill:#000000;stroke-width:0.262154" + id="path34677" /> + d="m 34.767095,24.978726 v 1.587503 h 1.058335 v 0.264583 h -1.587502 v -1.852086 z" + style="fill:#000000;stroke-width:0.262154" + id="path34679" /> + d="m 36.619182,26.830812 v -0.264583 h -0.264584 v -0.264584 h -0.264584 v -1.322919 h 0.529168 v 1.322919 h 0.529167 v -1.322919 h 0.529168 v 1.322919 h -0.264584 v 0.264584 h -0.264584 v 0.264583 z" + style="fill:#000000;stroke-width:0.262154" + id="path34681" /> + id="text34445" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="SLV"> + d="m 19.044247,26.830812 v -0.264583 h -0.264584 v -0.264584 h 0.529168 v 0.264584 h 0.529167 V 26.037061 H 19.044247 V 25.772478 H 18.779663 V 25.24331 h 0.264584 v -0.264584 h 1.058335 v 0.264584 h 0.264584 v 0.264584 H 19.837998 V 25.24331 h -0.529167 v 0.529168 h 0.793751 v 0.264583 h 0.264584 v 0.529168 h -0.264584 v 0.264583 z" + style="fill:#000000;stroke-width:0.262154" + id="path34684" /> + d="m 21.160917,24.978726 v 1.587503 h 1.058335 v 0.264583 H 20.63175 v -1.852086 z" + style="fill:#000000;stroke-width:0.262154" + id="path34686" /> + d="M 23.013003,26.830812 V 26.566229 H 22.74842 v -0.264584 h -0.264584 v -1.322919 h 0.529167 v 1.322919 h 0.529168 v -1.322919 h 0.529167 v 1.322919 h -0.264584 v 0.264584 h -0.264583 v 0.264583 z" + style="fill:#000000;stroke-width:0.262154" + id="path34688" /> + id="text34449" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="SLV"> + d="M 5.437788,26.830812 V 26.566229 H 5.1732043 v -0.264584 h 0.5291675 v 0.264584 H 6.2315392 V 26.037061 H 5.437788 V 25.772478 H 5.1732043 V 25.24331 H 5.437788 v -0.264584 h 1.058335 v 0.264584 h 0.2645837 v 0.264584 H 6.2315392 V 25.24331 H 5.7023718 v 0.529168 H 6.496123 v 0.264583 h 0.2645837 v 0.529168 H 6.496123 v 0.264583 z" + style="fill:#000000;stroke-width:0.262154" + id="path34691" /> - - + d="m 7.5544579,24.978726 v 1.587503 h 1.058335 v 0.264583 H 7.0252905 v -1.852086 z" + style="fill:#000000;stroke-width:0.262154" + id="path34693" /> + d="M 9.4065441,26.830812 V 26.566229 H 9.1419604 V 26.301645 H 8.8773767 v -1.322919 h 0.5291674 v 1.322919 h 0.5291675 v -1.322919 h 0.5291674 v 1.322919 h -0.264584 v 0.264584 H 9.9357116 v 0.264583 z" + style="fill:#000000;stroke-width:0.262154" + id="path34695" /> + id="text34453" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="TRIG1"> + d="m 45.827449,14.435819 v -2.116665 h -0.705555 v -0.352778 h 2.116665 v 0.352778 h -0.705555 v 2.116665 z" + style="fill:#000000;stroke-width:0.262154" + id="path34698" /> + + + id="text34457" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="TRIG1"> + d="m 32.22127,14.435819 v -2.116665 h -0.705555 v -0.352778 h 2.116665 v 0.352778 h -0.705555 v 2.116665 z" + style="fill:#000000;stroke-width:0.262154" + id="path34705" /> + d="m 33.985158,14.435819 v -2.469443 h 1.763887 v 0.352778 h 0.352778 v 0.705555 h -0.352778 v 0.352777 h -0.352777 v 0.352778 h 0.352777 v 0.352777 h 0.352778 v 0.352778 H 35.396268 V 14.083041 H 35.04349 v -0.352777 h -0.352777 v 0.705555 z m 0.705555,-1.41111 h 0.705555 v -0.705555 h -0.705555 z" + style="fill:#000000;stroke-width:0.262154" + id="path34707" /> + + id="text34461" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="TRIG1"> + d="m 18.615094,14.435819 v -2.116665 h -0.705555 v -0.352778 h 2.116665 v 0.352778 h -0.705555 v 2.116665 z" + style="fill:#000000;stroke-width:0.262154" + id="path34712" /> + + + id="text34465" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="TRIG1"> + d="M 5.0086334,14.435819 V 12.319154 H 4.3030783 v -0.352778 h 2.1166651 v 0.352778 h -0.705555 v 2.116665 z" + style="fill:#000000;stroke-width:0.262154" + id="path34719" /> + d="m 6.7725209,14.435819 v -2.469443 h 1.7638876 v 0.352778 H 8.889186 v 0.705555 H 8.5364085 v 0.352777 H 8.183631 v 0.352778 h 0.3527775 v 0.352777 H 8.889186 v 0.352778 H 8.183631 V 14.083041 H 7.8308535 V 13.730264 H 7.478076 v 0.705555 z M 7.478076,13.024709 H 8.183631 V 12.319154 H 7.478076 Z" + style="fill:#000000;stroke-width:0.262154" + id="path34721" /> + + + + aria-label="OUT" + id="g34732" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="OUT1"> + d="m 44.952004,110.19345 v -0.35278 h -0.352777 v -1.76388 h 0.352777 v -0.35278 h 1.41111 v 0.35278 h 0.352778 v 1.76388 h -0.352778 v 0.35278 z m 0.352778,-0.35278 h 0.705555 v -1.76388 h -0.705555 z" + style="stroke-width:0.265" + id="path34726" /> + d="m 47.421447,110.19345 v -0.35278 h -0.352778 v -2.11666 h 0.705555 v 2.11666 h 0.705555 v -2.11666 h 0.705555 v 2.11666 h -0.352777 v 0.35278 z" + style="stroke-width:0.265" + id="path34728" /> + + aria-label="OUT" + id="g34740" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="OUT1"> + d="m 31.492005,110.19345 v -0.35278 h -0.352777 v -1.76388 h 0.352777 v -0.35278 h 1.41111 v 0.35278 h 0.352778 v 1.76388 h -0.352778 v 0.35278 z m 0.352778,-0.35278 h 0.705555 v -1.76388 h -0.705555 z" + style="stroke-width:0.265" + id="path34734" /> + + + aria-label="OUT" + id="g34748" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="OUT1"> + d="m 18.032004,110.19345 v -0.35278 h -0.352777 v -1.76388 h 0.352777 v -0.35278 h 1.41111 v 0.35278 h 0.352778 v 1.76388 h -0.352778 v 0.35278 z m 0.352778,-0.35278 h 0.705555 v -1.76388 h -0.705555 z" + style="stroke-width:0.265" + id="path34742" /> + d="m 20.501447,110.19345 v -0.35278 h -0.352778 v -2.11666 h 0.705555 v 2.11666 h 0.705555 v -2.11666 h 0.705555 v 2.11666 h -0.352777 v 0.35278 z" + style="stroke-width:0.265" + id="path34744" /> + + id="path34750" /> + id="path34752" /> + id="path34754" /> + id="g34764" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#cc3333;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="LIMIT"> + id="path34758" /> + + id="path34762" /> + id="g34772" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#cc3333;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="LIMIT"> + id="path34766" /> + id="path34768" /> + id="path34770" /> - + id="g34780" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#cc3333;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="LIMIT"> + id="path34774" /> + id="path34776" /> + id="path34778" /> + id="path34782" /> + id="path34784" /> + id="path34786" /> + + + d="m 33.959792,81.261444 v -0.30868 h -0.30868 v -1.543403 h 0.30868 V 79.10068 h 1.234723 v 0.308681 h 0.30868 v 0.30868 h -0.617361 v -0.30868 h -0.617361 v 1.543403 h 0.617361 v -0.308681 h 0.617361 v 0.308681 h -0.30868 v 0.30868 z" + style="stroke-width:0.250588" + id="path34790" /> + d="M 35.811876,81.261444 V 79.10068 h 0.617361 v 0.926042 h 0.617361 V 79.10068 h 0.617361 v 2.160764 h -0.617361 v -0.926042 h -0.617361 v 0.926042 z" + style="stroke-width:0.250588" + id="path34792" /> + + aria-label="CHK" + transform="scale(0.94561118,1.0575171)" + id="g34804" + style="font-size:2.46944px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#8d8dd8;stroke-width:0.250587;stroke-dasharray:0.250587, 0.250587" + inkscape:label="CHOKE"> + d="m 19.683313,81.261444 v -0.30868 h -0.308681 v -1.543403 h 0.308681 V 79.10068 h 1.234722 v 0.308681 h 0.30868 v 0.30868 h -0.617361 v -0.30868 h -0.617361 v 1.543403 h 0.617361 v -0.308681 h 0.617361 v 0.308681 h -0.30868 v 0.30868 z" + style="stroke-width:0.250588" + id="path34798" /> + + + + + + + + + + id="path34814" /> + id="path34816" /> + id="g34824" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="IN1"> + id="path34820" /> + id="path34822" /> + id="g34830" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="IN1"> + + id="path34828" /> + id="g34836" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="IN1"> + + id="path34834" /> - + id="path34838" /> + id="path34842" /> + inkscape:label="2x"> + id="path34846" /> + + + id="path34850" /> - + id="path34854" /> + id="path34858" /> - + inkscape:label="2x"> - - - - - + id="path34862" /> - + id="g34868" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="0x"> + id="path34866" /> + id="g34876" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="alv"> + id="path34870" /> + id="path34872" /> + id="path34874" /> - + id="g34884" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="alv"> + id="path34878" /> + id="path34880" /> + id="path34882" /> - - + id="g34892" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="alv"> + id="path34886" /> + id="path34888" /> + id="path34890" /> - - + id="g34900" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="alv"> - - + id="path34894" /> + id="path34896" /> + id="path34898" /> + id="g34904" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="2x"> + id="path34902" /> + id="g34908" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="0x"> + id="path34906" /> - + id="path34910" /> + id="path34914" /> + inkscape:label="2x"> + id="path34918" /> + + + id="path34922" /> - + id="path34926" /> + id="path34930" /> + id="g34940" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="ACCENT1"> + id="path34934" /> - - - - + id="path34936" /> + d="M 50.413556,43.028957 V 42.67618 h -0.352777 v -1.763888 h 0.352777 v -0.352777 h 1.41111 v 0.352777 h 0.352778 v 0.352778 h -0.705555 v -0.352778 h -0.705555 v 1.763888 h 0.705555 v -0.352778 h 0.705555 v 0.352778 h -0.352778 v 0.352777 z" + style="stroke-width:0.262154" + id="path34938" /> + inkscape:label="ACCENT1"> + id="path34942" /> + + id="path34946" /> + id="path34950" /> + id="path34952" /> + id="path34954" /> - + inkscape:label="ACCENT1"> + id="path34958" /> + id="path34960" /> + id="path34962" /> + id="g34972" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="SLV"> + + id="path34968" /> + id="path34970" /> + + + id="path34974" /> + id="path34976" /> + id="path34978" /> + id="g34988" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="SLV"> + id="path34982" /> + id="path34984" /> + id="path34986" /> + id="g34996" + style="font-size:2.11667px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="SLV"> + id="path34990" /> - - + id="path34992" /> + id="path34994" /> + id="g35004" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="TRIG1"> - - + id="path34998" /> + id="path35000" /> + id="path35002" /> + id="g35012" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="TRIG1"> - - + id="path35006" /> + id="path35008" /> + id="path35010" /> + id="g35020" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="TRIG1"> + id="path35014" /> - - + id="path35016" /> + id="path35018" /> + id="g35028" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#ffffff;stroke-width:0.262153;stroke-dasharray:0.262153, 0.262153" + inkscape:label="TRIG1"> + id="path35022" /> + id="path35024" /> + - diff --git a/res/Drummer4Plus.svg b/res/Drummer4Plus.svg new file mode 100644 index 0000000..cc99717 --- /dev/null +++ b/res/Drummer4Plus.svg @@ -0,0 +1,2950 @@ + + + + diff --git a/res/Parking.svg b/res/Parking.svg index 5bf7a67..8ffe6a2 100644 --- a/res/Parking.svg +++ b/res/Parking.svg @@ -25,14 +25,14 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="2.9235334" - inkscape:cx="63.450618" + inkscape:cx="58.31984" inkscape:cy="88.93348" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="layer4" + inkscape:current-layer="layer1" showguides="true" /> @@ -342,10 +342,4 @@ id="path1266" /> - diff --git a/res/Shifter.svg b/res/Shifter.svg index 1589e2c..6cf1a43 100644 --- a/res/Shifter.svg +++ b/res/Shifter.svg @@ -24,9 +24,9 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showgrid="false" - inkscape:zoom="2.8284273" - inkscape:cx="-40.835415" - inkscape:cy="125.15789" + inkscape:zoom="8.0000005" + inkscape:cx="60.687496" + inkscape:cy="282.74998" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="1272" @@ -182,13 +182,13 @@ inkscape:label="circle MIX 1" sodipodi:type="arc" sodipodi:cx="7.6199999" - sodipodi:cy="85.354004" + sodipodi:cy="76.053894" sodipodi:rx="3.5" sodipodi:ry="3.5" sodipodi:start="2.268928" sodipodi:end="0.87266463" sodipodi:arc-type="arc" - d="M 5.3702433,88.03516 A 3.5,3.5 0 0 1 4.3310757,84.156933 3.5,3.5 0 0 1 7.6199999,81.854004 3.5,3.5 0 0 1 10.908924,84.156933 3.5,3.5 0 0 1 9.8697565,88.035159" + d="m 5.3702433,78.73505 a 3.5,3.5 0 0 1 -1.0391676,-3.878226 3.5,3.5 0 0 1 3.2889242,-2.30293 3.5,3.5 0 0 1 3.2889241,2.30293 3.5,3.5 0 0 1 -1.0391675,3.878226" sodipodi:open="true" /> + - diff --git a/res/SickoPlayer.svg b/res/SickoPlayer.svg new file mode 100644 index 0000000..fdc98cc --- /dev/null +++ b/res/SickoPlayer.svg @@ -0,0 +1,1761 @@ + + + + diff --git a/res/Switcher.svg b/res/Switcher.svg index 4ca347e..67ede80 100644 --- a/res/Switcher.svg +++ b/res/Switcher.svg @@ -25,14 +25,14 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="5.6568542" - inkscape:cx="28.461048" + inkscape:cx="25.721009" inkscape:cy="-17.500893" inkscape:window-width="1920" inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="layer7" + inkscape:current-layer="layer1" showguides="true" /> @@ -633,10 +633,4 @@ id="path24117" /> - diff --git a/res/SwitcherSt.svg b/res/SwitcherSt.svg index 7c0de9b..7a53078 100644 --- a/res/SwitcherSt.svg +++ b/res/SwitcherSt.svg @@ -25,14 +25,14 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="5.6568544" - inkscape:cx="46.669046" + inkscape:cx="43.929008" inkscape:cy="36.946328" inkscape:window-width="1920" inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="layer7" + inkscape:current-layer="g23274" showguides="true" /> @@ -269,7 +269,7 @@ - diff --git a/res/Toggler.svg b/res/Toggler.svg index cd1f792..c4e14ce 100644 --- a/res/Toggler.svg +++ b/res/Toggler.svg @@ -24,15 +24,15 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showgrid="false" - inkscape:zoom="2.9235336" - inkscape:cx="237.72602" - inkscape:cy="62.937537" + inkscape:zoom="2.0672504" + inkscape:cx="-17.656303" + inkscape:cy="165.43714" inkscape:window-width="1920" inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="layer7" + inkscape:current-layer="layer1" showguides="true" /> @@ -178,81 +178,180 @@ ry="2.5" inkscape:label="input rect" /> + + + + + + + + + + + + @@ -263,26 +362,26 @@ style="display:none"> GATE (R) L OUT R + x="37.504646" + y="51.778126">R S + x="22.953611" + y="51.778126">S A + x="8.6650639" + y="51.778126">A RESET + y="31.70542">RESET TRIGTRIGGATE GATE + x="32.561905" + y="19.391666">GATE TOGGLE + x="34.701553" + y="14.156847">TOGGLE MODE + x="10.566772" + y="16.8256">MODE + id="g2041" + inkscape:label="etichette testo nere" + style="display:inline;fill:#000000" + transform="translate(0.3003315,0.29996945)"> + style="fill:#000000;stroke-width:0.265" + id="path2043" /> + style="fill:#000000;stroke-width:0.265" + id="path2045" /> + style="fill:#000000;stroke-width:0.265" + id="path2047" /> + style="fill:#000000;stroke-width:0.265" + id="path2049" /> + style="fill:#000000;stroke-width:0.265" + id="path2052" /> + style="fill:#000000;stroke-width:0.265" + id="path2054" /> + style="fill:#000000;stroke-width:0.265" + id="path2056" /> + style="fill:#000000;stroke-width:0.265" + id="path2059" /> + style="fill:#000000;stroke-width:0.265" + id="path2062" /> + style="fill:#000000;stroke-width:0.265" + id="path2064" /> + style="fill:#000000;stroke-width:0.265" + id="path2066" /> + style="fill:#000000;stroke-width:0.265" + id="path2069" /> + style="fill:#000000;stroke-width:0.265" + id="path2071" /> + style="fill:#000000;stroke-width:0.265" + id="path2073" /> + style="fill:#000000;stroke-width:0.265" + id="path2076" /> + style="fill:#000000;stroke-width:0.265" + id="path2079" /> + style="fill:#000000;stroke-width:0.265" + id="path2081" /> - + id="text2009" + style="font-size:3.175px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="R rel" + transform="translate(0,0.291)"> + - + id="text2013" + style="font-size:3.175px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="S sus" + transform="translate(0,0.291)"> + - + id="text2017" + style="font-size:3.175px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="A att" + transform="translate(0,0.291)"> + + id="text2021" + style="font-size:2.82222px;font-family:'C64 User';-inkscape-font-specification:'C64 User';text-align:center;text-anchor:middle;display:inline;fill:#000000;stroke-width:0.264999;stroke-dasharray:0.264999, 0.264999" + inkscape:label="rst" + transform="translate(0,-8.4996321)"> + style="fill:#000000;stroke-width:0.265" + id="path2093" /> + style="fill:#000000;stroke-width:0.265" + id="path2095" /> + style="fill:#000000;stroke-width:0.265" + id="path2097" /> + style="fill:#000000;stroke-width:0.265" + id="path2099" /> + style="fill:#000000;stroke-width:0.265" + id="path2101" /> + style="fill:#000000;stroke-width:0.262154" + id="path2104" /> + style="fill:#000000;stroke-width:0.262154" + id="path2106" /> + style="fill:#000000;stroke-width:0.262154" + id="path2108" /> + style="fill:#000000;stroke-width:0.262154" + id="path2110" /> + style="fill:#000000;stroke-width:0.262154" + id="path2112" /> + style="fill:#000000;stroke-width:0.262154" + id="path2114" /> + style="fill:#000000;stroke-width:0.262154" + id="path2116" /> + style="fill:#000000;stroke-width:0.262154" + id="path2118" /> + style="fill:#000000;stroke-width:0.262154" + id="path2121" /> + style="fill:#000000;stroke-width:0.262154" + id="path2123" /> + style="fill:#000000;stroke-width:0.262154" + id="path2125" /> + style="fill:#000000;stroke-width:0.262154" + id="path2127" /> + style="fill:#000000;stroke-width:0.262154" + id="path2130" /> + style="fill:#000000;stroke-width:0.262154" + id="path2132" /> + style="fill:#000000;stroke-width:0.262154" + id="path2134" /> + style="fill:#000000;stroke-width:0.262154" + id="path2136" /> + style="fill:#000000;stroke-width:0.262154" + id="path2138" /> + style="fill:#000000;stroke-width:0.262154" + id="path2140" /> + style="fill:#000000;stroke-width:0.262154" + id="path2143" /> + style="fill:#000000;stroke-width:0.262154" + id="path2145" /> + style="fill:#000000;stroke-width:0.262154" + id="path2147" /> + style="fill:#000000;stroke-width:0.262154" + id="path2149" /> + style="stroke-width:0.265" + id="path2152" /> + style="stroke-width:0.265" + id="path2154" /> + style="stroke-width:0.265" + id="path2156" /> + style="stroke-width:0.265" + id="path2158" /> + style="stroke-width:0.265" + id="path2162" /> + style="stroke-width:0.265" + id="path2164" /> + style="stroke-width:0.265" + id="path2166" /> + style="stroke-width:0.265" + id="path2170" /> + style="stroke-width:0.265" + id="path2174" /> + style="stroke-width:0.265" + id="path2176" /> + style="stroke-width:0.265" + id="path2178" /> + id="path2182" /> + id="path2184" /> + id="path2186" /> + id="path2190" /> + id="path2194" /> + id="path2196" /> + inkscape:label="R rel" + transform="translate(0,0.291)"> + id="path2200" /> + inkscape:label="S sus" + transform="translate(0,0.291)"> + id="path2204" /> + inkscape:label="A att" + transform="translate(0,0.291)"> + id="path2208" /> + inkscape:label="rst" + transform="translate(0,-8.4996321)"> + id="path2212" /> + id="path2214" /> + id="path2216" /> + id="path2218" /> + id="path2220" /> + id="path2224" /> + id="path2226" /> + id="path2228" /> + id="path2230" /> + id="path2232" /> + id="path2234" /> + id="path2236" /> + id="path2238" /> + id="path2242" /> + id="path2244" /> + id="path2246" /> + id="path2248" /> + id="path2252" /> + id="path2254" /> + id="path2256" /> + id="path2258" /> + id="path2260" /> + id="path2262" /> + id="path2266" /> + id="path2268" /> + id="path2270" /> + id="path2272" /> - diff --git a/res/TogglerCompact.svg b/res/TogglerCompact.svg index 5d003e9..34bc973 100644 --- a/res/TogglerCompact.svg +++ b/res/TogglerCompact.svg @@ -25,14 +25,14 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="4.0000001" - inkscape:cx="12.75" - inkscape:cy="83.499998" + inkscape:cx="8.8749998" + inkscape:cy="403.74999" inkscape:window-width="1920" inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-x="1272" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="layer7" + inkscape:current-layer="layer4" showguides="true" /> @@ -149,7 +149,7 @@ ry="2" inkscape:label="trg gate" /> - diff --git a/src/Blender.cpp b/src/Blender.cpp index 0d85a7d..c0f05a5 100644 --- a/src/Blender.cpp +++ b/src/Blender.cpp @@ -1,26 +1,43 @@ +#define MONOPHONIC 0 +#define POLYPHONIC 1 #include "plugin.hpp" struct Blender : Module { - float mixedOut[2] = {0,0}; float mix = 0; - float modAtten = 0; - float input1[2] = {0,0}; - float input2[2] = {0,0}; + float mod2 = 0; + float input1[2][16]; + float input2[2][16]; + float mixedOut[2][16]; + float summedOut[2]; + int limit; + float vol; + float vol1; + float vol2; + int phase1; + int phase2; + + int chanL; + int chanR; + int polyOuts = POLYPHONIC; enum ParamId { ENUMS(PHASE_SWITCH,2), MIX_PARAMS, - MODMIX_PARAMS, - MODATTEN_PARAMS, - RANGEMODMIX_SWITCH, - RANGEMODATTEN_SWITCH, + VOL_PARAMS, + LIMIT_PARAMS, + VOL1_PARAMS, + VOL2_PARAMS, + MOD1_ATNV_PARAMS, + MOD2_ATNV_PARAMS, + MOD1_RANGE_SWITCH, + MOD2_RANGE_SWITCH, PARAMS_LEN }; enum InputId { ENUMS(IN1_INPUT,2), ENUMS(IN2_INPUT,2), - MODMIXCV_INPUT, - MODATTENCV_INPUT, + MOD1_INPUT, + MOD2_INPUT, INPUTS_LEN }; enum OutputId { @@ -28,6 +45,7 @@ struct Blender : Module { OUTPUTS_LEN }; enum LightId { + LIMIT_LIGHT, LIGHTS_LEN }; @@ -38,79 +56,194 @@ struct Blender : Module { configInput(IN2_INPUT, "In2 L"); configInput(IN2_INPUT+1, "In2 R"); - configSwitch(PHASE_SWITCH, 0.f, 1.f, 0.f, "In1 Phase", {"Normal", "Inverted"}); - configSwitch(PHASE_SWITCH+1, 0.f, 1.f, 0.f, "In2 Phase", {"Normal", "Inverted"}); + configSwitch(PHASE_SWITCH, 0.f, 1.f, 1.f, "In1 Phase", {"Inverted", "Normal"}); + configSwitch(PHASE_SWITCH+1, 0.f, 1.f, 1.f, "In2 Phase", {"Inverted", "Normal"}); configParam(MIX_PARAMS, 0.f,1.f, 0.5f, "Mix", "%", 0, 100); + configParam(VOL1_PARAMS, 0.f,1.f, 1.f, "Volume 1", "%", 0, 100); + configParam(VOL2_PARAMS, 0.f,1.f, 1.f, "Volume 2", "%", 0, 100); + + configParam(MOD1_ATNV_PARAMS, -1.f,1.f, 0.f, "Mod Attenuv.", "%", 0, 100); + configInput(MOD1_INPUT, "Mod"); + configSwitch(MOD1_RANGE_SWITCH, 0.f, 1.f, 1.f, "Mod Input Range", {"Bipolar", "Unipolar"}); - configParam(MODMIX_PARAMS, -1.f,1.f, 0.f, "Mix Mod", "%", 0, 100); - configInput(MODMIXCV_INPUT, "Mix Mod Cv"); - configSwitch(RANGEMODMIX_SWITCH, 0.f, 1.f, 1.f, "Mix Mod Cv Input Range", {"Bipolar", "Unipolar"}); + configParam(MOD2_ATNV_PARAMS, -1.f,1.f, 0.f, "Mod2 Attenuv.", "%", 0, 100); + configInput(MOD2_INPUT, "Mod2"); + configSwitch(MOD2_RANGE_SWITCH, 0.f, 1.f, 1.f, "Mod2 Input Range", {"Bipolar", "Unipolar"}); - configParam(MODATTEN_PARAMS, -1.f,1.f, 0.f, "MixMod Attenuv. Mod", "%", 0, 100); - configInput(MODATTENCV_INPUT, "MixMod Attenuv. Mod Cv"); - configSwitch(RANGEMODATTEN_SWITCH, 0.f, 1.f, 1.f, "MixMod Attenuv. Mod Cv Input Range", {"Bipolar", "Unipolar"}); + configParam(VOL_PARAMS, 0.f,2.f, 1.f, "Master Volume", "%", 0, 100); + configSwitch(LIMIT_PARAMS, 0.f, 1.f, 0.f, "Limit", {"Off", "±5v"}); configOutput(OUT_OUTPUT, "L"); configOutput(OUT_OUTPUT+1, "R"); } + void onReset() override { + polyOuts = POLYPHONIC; + } + + json_t *dataToJson() override { + json_t *rootJ = json_object(); + json_object_set_new(rootJ, "PolyOuts", json_integer(polyOuts)); + return rootJ; + } + + void dataFromJson(json_t *rootJ) override { + json_t* polyOutsJ = json_object_get(rootJ, "PolyOuts"); + if (polyOutsJ) + polyOuts = json_integer_value(polyOutsJ); + } + void process(const ProcessArgs& args) override { - if (outputs[OUT_OUTPUT].isConnected() || outputs[OUT_OUTPUT+1].isConnected()){ - if (inputs[MODMIXCV_INPUT].isConnected()){ - if (inputs[MODATTENCV_INPUT].isConnected()){ - if (params[RANGEMODATTEN_SWITCH].getValue() == 1) { - modAtten = params[MODATTEN_PARAMS].getValue() * inputs[MODATTENCV_INPUT].getVoltage() / 10; - } else { - modAtten = params[MODATTEN_PARAMS].getValue() * (inputs[MODATTENCV_INPUT].getVoltage() + 5) / 10; - } - } else { - modAtten = 0; - } - if (modAtten > 1) { - modAtten = 1; - } else if (modAtten < -1) { - modAtten = -1; - } - if (params[RANGEMODMIX_SWITCH].getValue() == 1) { - mix = params[MIX_PARAMS].getValue() + ( (params[MODMIX_PARAMS].getValue() * inputs[MODMIXCV_INPUT].getVoltage() / 10) + modAtten); + + limit = params[LIMIT_PARAMS].getValue(); + lights[LIMIT_LIGHT].setBrightness(limit); + + if (outputs[OUT_OUTPUT].isConnected() || outputs[OUT_OUTPUT+1].isConnected()) { + vol1 = params[VOL1_PARAMS].getValue(); + vol2 = params[VOL2_PARAMS].getValue(); + phase1 = params[PHASE_SWITCH].getValue(); + phase2 = params[PHASE_SWITCH+1].getValue(); + vol = params[VOL_PARAMS].getValue(); + + if (inputs[MOD1_INPUT].isConnected()) { + if (inputs[MOD2_INPUT].isConnected()) { + if (params[MOD2_RANGE_SWITCH].getValue() == 1) + mod2 = params[MOD2_ATNV_PARAMS].getValue() * inputs[MOD2_INPUT].getVoltage() * 0.1; + else + mod2 = params[MOD2_ATNV_PARAMS].getValue() * (inputs[MOD2_INPUT].getVoltage() + 5) * 0.1; } else { - mix = params[MIX_PARAMS].getValue() + ( (params[MODMIX_PARAMS].getValue() * (inputs[MODMIXCV_INPUT].getVoltage() + 5) / 10) + modAtten); + mod2 = 0; } - if (mix > 1) { + + if (mod2 > 1) + mod2 = 1; + else if (mod2 < -1) + mod2 = -1; + + if (params[MOD1_RANGE_SWITCH].getValue() == 1) + mix = params[MIX_PARAMS].getValue() + ( (params[MOD1_ATNV_PARAMS].getValue() * inputs[MOD1_INPUT].getVoltage() * 0.1) + mod2); + else + mix = params[MIX_PARAMS].getValue() + ( (params[MOD1_ATNV_PARAMS].getValue() * (inputs[MOD1_INPUT].getVoltage() + 5) * 0.1) + mod2); + + if (mix > 1) mix = 1; - } else if (mix < 0) { + else if (mix < 0) { mix = -mix; - if (mix < -1) { + if (mix < -1) mix = -1; - } } } else { mix = params[MIX_PARAMS].getValue(); } - - for (int i=0; i<2; i++){ - if (outputs[OUT_OUTPUT+i].isConnected()){ - input1[i] = inputs[IN1_INPUT+i].getVoltage(); - if (params[PHASE_SWITCH].getValue() == 1){ - input1[i] = -input1[i]; - } - input2[i] = inputs[IN2_INPUT+i].getVoltage(); - if (params[PHASE_SWITCH+1].getValue() == 1){ - input2[i] = -input2[i]; - } - mixedOut[i] = (input1[i] * (1 - mix)) + (input2[i] * mix); - } else { - mixedOut[i] = 0; + } + + // LEFT CHANNEL + + if (outputs[OUT_OUTPUT].isConnected()) { + chanL = std::max(1, inputs[IN1_INPUT].getChannels()); + summedOut[0] = 0; + + for (int c = 0; c < chanL; c++) { + + input1[0][c] = inputs[IN1_INPUT].getVoltage(c) * vol1; + if (!phase1) // inverted if because of inverted switch widget + input1[0][c] = -input1[0][c]; + + input2[0][c] = inputs[IN2_INPUT].getVoltage(c) * vol2; + if (!phase2) // inverted if because of inverted switch widget + input2[0][c] = -input2[0][c]; + + mixedOut[0][c] = (input1[0][c] * (1 - mix)) + (input2[0][c] * mix) * vol; + + switch (polyOuts) { + case MONOPHONIC: + summedOut[0] += mixedOut[0][c]; + break; + + case POLYPHONIC: + if (limit) { + if (mixedOut[0][c] > 5) + mixedOut[0][c] = 5; + else if (mixedOut[0][c] < -5) + mixedOut[0][c] = -5; + } + outputs[OUT_OUTPUT].setVoltage(mixedOut[0][c], c); + break; } - } + + } + + } else { + for (int c = 0; c < 16; c++) + outputs[OUT_OUTPUT].setVoltage(0, c); + } + + // RIGHT CHANNEL + + if (outputs[OUT_OUTPUT+1].isConnected()) { + chanR = std::max(1, inputs[IN1_INPUT+1].getChannels()); + summedOut[1] = 0; + + for (int c = 0; c < chanR; c++) { + + input1[1][c] = inputs[IN1_INPUT+1].getVoltage(c) * vol1; + if (!phase1) // inverted if because of inverted switch widget + input1[1][c] = -input1[1][c]; + + input2[1][c] = inputs[IN2_INPUT+1].getVoltage(c) * vol2; + if (!phase2) // inverted if because of inverted switch widget + input2[1][c] = -input2[1][c]; + + mixedOut[1][c] = (input1[1][c] * (1 - mix)) + (input2[1][c] * mix) * vol; + + switch (polyOuts) { + case MONOPHONIC: + summedOut[1] += mixedOut[1][c]; + break; + + case POLYPHONIC: + if (limit) { + if (mixedOut[1][c] > 5) + mixedOut[1][c] = 5; + else if (mixedOut[1][c] < -5) + mixedOut[1][c] = -5; + } + outputs[OUT_OUTPUT+1].setVoltage(mixedOut[1][c], c); + break; + } + + } + } else { - mixedOut[0] = 0; - mixedOut[1] = 0; + for (int c = 0; c < 16; c++) + outputs[OUT_OUTPUT+1].setVoltage(0, c); + } + + switch (polyOuts) { + case MONOPHONIC: + if (limit) { + if (summedOut[0] > 5) + summedOut[0] = 5; + else if (summedOut[0] < -5) + summedOut[0] = -5; + + if (summedOut[1] > 5) + summedOut[1] = 5; + else if (summedOut[1] < -5) + summedOut[1] = -5; + } + outputs[OUT_OUTPUT].setVoltage(summedOut[0]); + outputs[OUT_OUTPUT+1].setVoltage(summedOut[1]); + break; + + case POLYPHONIC: + outputs[OUT_OUTPUT].setChannels(chanL); + outputs[OUT_OUTPUT+1].setChannels(chanR); + break; } - outputs[OUT_OUTPUT].setVoltage(mixedOut[0]); - outputs[OUT_OUTPUT+1].setVoltage(mixedOut[1]); - } + + } }; struct BlenderWidget : ModuleWidget { @@ -130,18 +263,31 @@ struct BlenderWidget : ModuleWidget { addParam(createParamCentered(mm2px(Vec(11.75, 34.6)), module, Blender::PHASE_SWITCH)); addParam(createParamCentered(mm2px(Vec(34.1, 34.6)), module, Blender::PHASE_SWITCH+1)); - addParam(createParamCentered(mm2px(Vec(22.86, 57)), module, Blender::MIX_PARAMS)); + addParam(createParamCentered(mm2px(Vec(11, 47.9)), module, Blender::VOL1_PARAMS)); + addParam(createParamCentered(mm2px(Vec(34.92, 47.9)), module, Blender::VOL2_PARAMS)); + + addParam(createParamCentered(mm2px(Vec(22.86, 54)), module, Blender::MIX_PARAMS)); - addParam(createParamCentered(mm2px(Vec(11.9, 83.7)), module, Blender::MODMIX_PARAMS)); - addInput(createInputCentered(mm2px(Vec(26, 83.7)), module, Blender::MODMIXCV_INPUT)); - addParam(createParamCentered(mm2px(Vec(35, 83.7)), module, Blender::RANGEMODMIX_SWITCH)); + addInput(createInputCentered(mm2px(Vec(8, 77.7)), module, Blender::MOD1_INPUT)); + addParam(createParamCentered(mm2px(Vec(18.4, 77.7)), module, Blender::MOD1_RANGE_SWITCH)); + addParam(createParamCentered(mm2px(Vec(31.4, 77.7)), module, Blender::MOD1_ATNV_PARAMS)); - addParam(createParamCentered(mm2px(Vec(11.75, 108.5)), module, Blender::MODATTEN_PARAMS)); - addInput(createInputCentered(mm2px(Vec(7, 116.2)), module, Blender::MODATTENCV_INPUT)); - addParam(createParamCentered(mm2px(Vec(15., 116.2)), module, Blender::RANGEMODATTEN_SWITCH)); + addInput(createInputCentered(mm2px(Vec(11.75, 115.7)), module, Blender::MOD2_INPUT)); + addParam(createParamCentered(mm2px(Vec(11.75, 94)), module, Blender::MOD2_ATNV_PARAMS)); + addParam(createParamCentered(mm2px(Vec(11.75, 105)), module, Blender::MOD2_RANGE_SWITCH)); + + addParam(createParamCentered(mm2px(Vec(31.1, 93.4)), module, Blender::VOL_PARAMS)); + addParam(createLightParamCentered>>(mm2px(Vec(39.75, 93.4)), module, Blender::LIMIT_PARAMS, Blender::LIMIT_LIGHT)); + + addOutput(createOutputCentered(mm2px(Vec(27.8, 115.2)), module, Blender::OUT_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(38.4, 115.2)), module, Blender::OUT_OUTPUT+1)); + } - addOutput(createOutputCentered(mm2px(Vec(29, 115.2)), module, Blender::OUT_OUTPUT)); - addOutput(createOutputCentered(mm2px(Vec(39.2, 115.2)), module, Blender::OUT_OUTPUT+1)); + void appendContextMenu(Menu *menu) override { + Blender *module = dynamic_cast(this->module); + assert(module); + menu->addChild(new MenuSeparator()); + menu->addChild(createBoolPtrMenuItem("Polyphonic outs", "", &module->polyOuts)); } }; diff --git a/src/Blender8.cpp b/src/Blender8.cpp index dd497a9..37621c0 100644 --- a/src/Blender8.cpp +++ b/src/Blender8.cpp @@ -90,29 +90,26 @@ struct Blender8 : Module { } void process(const ProcessArgs& args) override { - for (int i=0; i<8;i++){ - if (outputs[OUT_OUTPUT+i].isConnected()){ - if (inputs[MODMIXCV_INPUT+i].isConnected()){ - if (params[RANGEMODMIX_SWITCH+i].getValue() == 1) { + for (int i=0; i<8; i++) { + if (outputs[OUT_OUTPUT+i].isConnected()) { + if (inputs[MODMIXCV_INPUT+i].isConnected()) { + if (params[RANGEMODMIX_SWITCH+i].getValue() == 1) mix = params[MIX_PARAMS+i].getValue() * inputs[MODMIXCV_INPUT+i].getVoltage() / 10; - } else { + else mix = params[MIX_PARAMS+i].getValue() * (inputs[MODMIXCV_INPUT+i].getVoltage() + 5) / 10; - } - if (mix > 1) { - mix = 1; - } else if (mix < 0) { + if (mix > 1) + mix = 1; + else if (mix < 0) { mix = -mix; - if (mix < -1) { + if (mix < -1) mix = -1; - } } } else { mix = (params[MIX_PARAMS+i].getValue() + 1)/2; } input2 = inputs[IN2_INPUT+i].getVoltage(); - if (params[PHASE_SWITCH+i].getValue() == 1){ + if (params[PHASE_SWITCH+i].getValue() == 1) input2 = -input2; - } mixedOut = (inputs[IN1_INPUT+i].getVoltage() * (1 - mix)) + (input2 * mix); } else { mixedOut = 0; @@ -134,7 +131,7 @@ struct Blender8Widget : ModuleWidget { float y = 13; float ys = 22; - for (int i=0;i<8;i++) { + for (int i=0; i<8; i++) { addInput(createInputCentered(mm2px(Vec(6.7, ys+(i*y))), module, Blender8::IN1_INPUT+i)); addInput(createInputCentered(mm2px(Vec(16.1, ys+(i*y))), module, Blender8::IN2_INPUT+i)); diff --git a/src/Btoggler.cpp b/src/Btoggler.cpp index d9a4158..1b69c67 100644 --- a/src/Btoggler.cpp +++ b/src/Btoggler.cpp @@ -204,17 +204,17 @@ struct Btoggler : Module { if (clockConnection) { clock = inputs[CLOCK_INPUT].getVoltage(); - if (clock >= 1 && prevClock < 1) { + if (clock >= 1 && prevClock < 1) clockState = true; - } else { + else clockState = false; - } + prevClock = clock; if (inputs[RSTALL_INPUT].isConnected()){ rstAll = inputs[RSTALL_INPUT].getVoltage(); if (rstAll >= 1 && prevRstAll < 1) { - for (int i=0; i<8;i++){ + for (int i=0; i<8; i++) { // next lines are duplicated from case 3 outputs[GATE_OUTPUT+i].setVoltage(0); lights[OUT_LIGHT+i].setBrightness(0.f); @@ -233,8 +233,8 @@ struct Btoggler : Module { prevRstAll = rstAll; } - for (int i=0; i<8; i++){ - if (inputs[RST_INPUT+i].isConnected()){ + for (int i=0; i<8; i++) { + if (inputs[RST_INPUT+i].isConnected()) { rst[i] = inputs[RST_INPUT+i].getVoltage(); if (rst[i] >= 1 && prevRst[i] < 1) { // next lines are duplicated from case 3 @@ -243,7 +243,7 @@ struct Btoggler : Module { lights[WRN_LIGHT+i].setBrightness(0.f); // below is different from original: if internalState is 0 or 1 // it will not do the fade - if (params[FADE_PARAMS].getValue() != 0 && internalState[i] > 1){ + if (params[FADE_PARAMS].getValue() != 0 && internalState[i] > 1) { fading[i] = true; currentFadeSample[i] = 0; maxFadeSample = args.sampleRate / 1000 * params[FADE_PARAMS].getValue(); @@ -254,13 +254,13 @@ struct Btoggler : Module { prevRst[i] = rst[i]; } - if (inputs[ARM_INPUT+i].isConnected()){ + if (inputs[ARM_INPUT+i].isConnected()) { trigValue[i] = inputs[ARM_INPUT+i].getVoltage(); - if (trigValue[i] >= 1 && prevTrigValue[i] < 1){ + if (trigValue[i] >= 1 && prevTrigValue[i] < 1) trigState[i] = true; - } else { + else trigState[i] = false; - } + prevTrigValue[i] = trigValue[i]; switch (internalState[i]) { @@ -268,7 +268,7 @@ struct Btoggler : Module { if (trigState[i]){ // if occurs internalState[i] = 1; lights[WRN_LIGHT+i].setBrightness(1.f); - } else if (params[FADE_PARAMS].getValue() != 0){ + } else if (params[FADE_PARAMS].getValue() != 0) { if (fading[i] == true) { if (currentFadeSample[i] > maxFadeSample) { fading[i] = false; @@ -288,7 +288,7 @@ struct Btoggler : Module { break; case 1: // triggered waiting for next clock - if (trigState[i]){ // if another trigger occurs, then abort + if (trigState[i]) { // if another trigger occurs, then abort lights[WRN_LIGHT+i].setBrightness(0.f); internalState[i] = 0; } else if (clockState) { // if clock occurs @@ -296,7 +296,7 @@ struct Btoggler : Module { lights[OUT_LIGHT+i].setBrightness(1.f); lights[WRN_LIGHT+i].setBrightness(0.f); internalState[i] = 2; - if (params[FADE_PARAMS].getValue() != 0){ + if (params[FADE_PARAMS].getValue() != 0) { fading[i] = true; currentFadeSample[i] = 0; maxFadeSample = args.sampleRate / 1000 * params[FADE_PARAMS].getValue(); @@ -308,7 +308,7 @@ struct Btoggler : Module { if (trigState[i]) { // if ARM occurs internalState[i] = 3; lights[WRN_LIGHT+i].setBrightness(1.f); - } else if (params[FADE_PARAMS].getValue() != 0){ + } else if (params[FADE_PARAMS].getValue() != 0) { if (fading[i] == true) { outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * currentFadeSample[i] / maxFadeSample); currentFadeSample[i]++; @@ -327,7 +327,7 @@ struct Btoggler : Module { break; case 3: // gating and triggered, waiting for next clock - if (trigState[i]){ // if another trigger occurs, then abort + if (trigState[i]) { // if another trigger occurs, then abort internalState[i] = 2; lights[WRN_LIGHT+i].setBrightness(0.f); } else if (clockState) { @@ -335,7 +335,7 @@ struct Btoggler : Module { internalState[i] = 0; lights[OUT_LIGHT+i].setBrightness(0.f); lights[WRN_LIGHT+i].setBrightness(0.f); - if (params[FADE_PARAMS].getValue() != 0){ + if (params[FADE_PARAMS].getValue() != 0) { fading[i] = true; currentFadeSample[i] = 0; maxFadeSample = args.sampleRate / 1000 * params[FADE_PARAMS].getValue(); @@ -370,7 +370,6 @@ struct Btoggler : Module { } }; - struct BtogglerWidget : ModuleWidget { BtogglerWidget(Btoggler* module) { setModule(module); @@ -387,7 +386,7 @@ struct BtogglerWidget : ModuleWidget { float x = 8.9; float y = 10.8; - for (int i=0;i<8;i++) { + for (int i=0; i<8; i++) { addInput(createInputCentered(mm2px(Vec(5.1, 41+(i*y))), module, Btoggler::ARM_INPUT+i)); addInput(createInputCentered(mm2px(Vec(5.1+x, 41+(i*y))), module, Btoggler::IN_INPUT+i)); addOutput(createOutputCentered(mm2px(Vec(5.1+(2*x), 41+(i*y))), module, Btoggler::OUT_OUTPUT+i)); diff --git a/src/BtogglerPlus.cpp b/src/BtogglerPlus.cpp index 922dc7c..389c8ae 100644 --- a/src/BtogglerPlus.cpp +++ b/src/BtogglerPlus.cpp @@ -241,17 +241,17 @@ struct BtogglerPlus : Module { if (clockConnection) { clock = inputs[CLOCK_INPUT].getVoltage(); - if (clock >= 1 && prevClock < 1) { + if (clock >= 1 && prevClock < 1) clockState = true; - } else { + else clockState = false; - } + prevClock = clock; - if (inputs[RSTALL_INPUT].isConnected()){ + if (inputs[RSTALL_INPUT].isConnected()) { rstAll = inputs[RSTALL_INPUT].getVoltage(); if (rstAll >= 1 && prevRstAll < 1) { - for (int i=0; i<8;i++){ + for (int i=0; i<8; i++) { // next lines are duplicated from case 3 warnCounter[i] = 0; outputs[WARN_OUTPUT+i].setVoltage(0); @@ -260,7 +260,7 @@ struct BtogglerPlus : Module { lights[WRN_LIGHT+i].setBrightness(0.f); // below is different from original: if internalState is 0 or 1 // it will not do the fade - if (params[FADE_PARAMS].getValue() != 0 && internalState[i] > 1){ + if (params[FADE_PARAMS].getValue() != 0 && internalState[i] > 1) { fading[i] = true; currentFadeSample[i] = 0; maxFadeSample = args.sampleRate / 1000 * params[FADE_PARAMS].getValue(); @@ -272,8 +272,8 @@ struct BtogglerPlus : Module { prevRstAll = rstAll; } - for (int i=0; i<8;i++){ - if (inputs[RST_INPUT+i].isConnected()){ + for (int i=0; i<8; i++) { + if (inputs[RST_INPUT+i].isConnected()) { rst[i] = inputs[RST_INPUT+i].getVoltage(); if (rst[i] >= 1 && prevRst[i] < 1) { // next lines are duplicated from case 3 @@ -284,7 +284,7 @@ struct BtogglerPlus : Module { lights[WRN_LIGHT+i].setBrightness(0.f); // below is different from original: if internalState is 0 or 1 // it will not do the fade - if (params[FADE_PARAMS].getValue() != 0 && internalState[i] > 1){ + if (params[FADE_PARAMS].getValue() != 0 && internalState[i] > 1) { fading[i] = true; currentFadeSample[i] = 0; maxFadeSample = args.sampleRate / 1000 * params[FADE_PARAMS].getValue(); @@ -295,24 +295,24 @@ struct BtogglerPlus : Module { prevRst[i] = rst[i]; } - if (inputs[ARM_INPUT+i].isConnected()){ + if (inputs[ARM_INPUT+i].isConnected()) { trigValue[i] = inputs[ARM_INPUT+i].getVoltage(); - if (trigValue[i] >= 1 && prevTrigValue[i] < 1){ + if (trigValue[i] >= 1 && prevTrigValue[i] < 1) trigState[i] = true; - } else { + else trigState[i] = false; - } + prevTrigValue[i] = trigValue[i]; switch (internalState[i]) { case 0: // waiting for ARM - if (trigState[i]){ // if ARM occurs + if (trigState[i]) { // if ARM occurs internalState[i] = 1; lights[WRN_LIGHT+i].setBrightness(1.f); warnInOn = args.sampleRate / 2000 * params[WARNIN_PARAMS].getValue(); warnInOff = warnInOn + warnInOn; - } else if (params[FADE_PARAMS].getValue() != 0){ // if a FADE value is set - if (fading[i] == true) { // if it's currently fading + } else if (params[FADE_PARAMS].getValue() != 0) { // if a FADE value is set + if (fading[i] == true) { // if it's currently fading if (currentFadeSample[i] > maxFadeSample) { // if FADING has reached end fading[i] = false; currentFadeSample[i] = 0; @@ -330,7 +330,7 @@ struct BtogglerPlus : Module { break; case 1: // ARMed ON, waiting for next clock - if (trigState[i]){ // if another ARM occurs, then abort + if (trigState[i]) { // if another ARM occurs, then abort outputs[WARN_OUTPUT+i].setVoltage(0); lights[WRN_LIGHT+i].setBrightness(0.f); internalState[i] = 0; @@ -341,24 +341,23 @@ struct BtogglerPlus : Module { lights[WRN_LIGHT+i].setBrightness(0.f); warnCounter[i] = 0; internalState[i] = 2; - if (params[FADE_PARAMS].getValue() != 0){ + if (params[FADE_PARAMS].getValue() != 0) { fading[i] = true; currentFadeSample[i] = 0; maxFadeSample = args.sampleRate / 1000 * params[FADE_PARAMS].getValue(); } } else if (params[WARNIN_PARAMS].getValue() == 0) {// if clock has not reached and it's still warning outputs[WARN_OUTPUT+i].setVoltage(10); - } else if (params[WARNIN_PARAMS].getValue() == 200){ + } else if (params[WARNIN_PARAMS].getValue() == 200) { outputs[WARN_OUTPUT+i].setVoltage(0); } else { warnCounter[i]++; - if (warnCounter[i] > warnInOff) { + if (warnCounter[i] > warnInOff) warnCounter[i] = 0; - } else if (warnCounter[i] > warnInOn) { + else if (warnCounter[i] > warnInOn) outputs[WARN_OUTPUT+i].setVoltage(0); - } else { + else outputs[WARN_OUTPUT+i].setVoltage(10); - } } break; @@ -368,8 +367,8 @@ struct BtogglerPlus : Module { lights[WRN_LIGHT+i].setBrightness(1.f); warnOutOn = args.sampleRate / 2000 * params[WARNOUT_PARAMS].getValue(); warnOutOff = warnOutOn + warnOutOn; - } else if (params[FADE_PARAMS].getValue() != 0){ // if it's currently GATING, if FADE is set - if (fading[i] == true) { // if is currently FADING + } else if (params[FADE_PARAMS].getValue() != 0) { // if it's currently GATING, if FADE is set + if (fading[i] == true) { // if is currently FADING outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * currentFadeSample[i] / maxFadeSample); outputs[GATE_OUTPUT+i].setVoltage(10); outputs[WARN_OUTPUT+i].setVoltage(10); @@ -406,7 +405,7 @@ struct BtogglerPlus : Module { break; case 3: // gating and ARMed off, waiting for next clock - if (trigState[i]){ // if another ARM occurs, then abort + if (trigState[i]) { // if another ARM occurs, then abort internalState[i] = 2; lights[WRN_LIGHT+i].setBrightness(0.f); } else if (clockState) { // if clock occurs @@ -416,7 +415,7 @@ struct BtogglerPlus : Module { lights[OUT_LIGHT+i].setBrightness(0.f); lights[WRN_LIGHT+i].setBrightness(0.f); internalState[i] = 0; - if (params[FADE_PARAMS].getValue() != 0){ + if (params[FADE_PARAMS].getValue() != 0) { fading[i] = true; currentFadeSample[i] = 0; maxFadeSample = args.sampleRate / 1000 * params[FADE_PARAMS].getValue(); @@ -427,13 +426,12 @@ struct BtogglerPlus : Module { outputs[WARN_OUTPUT+i].setVoltage(0); } else { warnCounter[i]++; - if (warnCounter[i] > warnOutOff) { + if (warnCounter[i] > warnOutOff) warnCounter[i] = 0; - } else if (warnCounter[i] > warnOutOn) { + else if (warnCounter[i] > warnOutOn) outputs[WARN_OUTPUT+i].setVoltage(0); - } else { + else outputs[WARN_OUTPUT+i].setVoltage(10); - } } outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage()); break; @@ -464,7 +462,6 @@ struct BtogglerPlus : Module { } }; - struct BtogglerPlusWidget : ModuleWidget { BtogglerPlusWidget(BtogglerPlus* module) { setModule(module); diff --git a/src/BtogglerSt.cpp b/src/BtogglerSt.cpp index 1d93018..ac7cc40 100644 --- a/src/BtogglerSt.cpp +++ b/src/BtogglerSt.cpp @@ -3,8 +3,11 @@ struct BtogglerSt : Module { enum ParamId { ATTACK_PARAMS, + ATTACKATNV_PARAMS, SUSTAIN_PARAMS, + SUSTAINATNV_PARAMS, RELEASE_PARAMS, + RELEASEATNV_PARAMS, PARAMS_LEN }; enum InputId { @@ -43,19 +46,24 @@ struct BtogglerSt : Module { float rst = 0; float prevRst = 0; - float arSum = 0; float maxFadeSample = 0; float currentFadeSample = 0; bool fading = false; - float sustain = 1; float startFade = 0; float lastFade = 0; + float attack; + float sustain; + float release; + BtogglerSt() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); - configParam(ATTACK_PARAMS, 0.f, 10.f, 0.f, "Attack (s)"); - configParam(SUSTAIN_PARAMS, 0.f, 1.f, 1.f, "Level", "%", 0, 100); - configParam(RELEASE_PARAMS, 0.f, 10.f, 0.f, "Release (s)"); + configParam(ATTACK_PARAMS, 0.f, 10.f, 0.f, "Attack", "ms", 0, 1000); + configParam(ATTACKATNV_PARAMS, -1.f, 1.f, 0.f, "Attack Attenuv.", "%", 0, 100); + configParam(SUSTAIN_PARAMS, 0.f, 1.f, 1.f, "Sustain Level", "%", 0, 100); + configParam(SUSTAINATNV_PARAMS, -1.f, 1.f, 0.f, "Sustain Attenuv.", "%", 0, 100); + configParam(RELEASE_PARAMS, 0.f, 10.f, 0.f, "Release", "ms", 0, 1000); + configParam(RELEASEATNV_PARAMS, -1.f, 1.f, 0.f, "Release Attenuv.", "%", 0, 100); configInput(CLOCK_INPUT, "Clock"); configInput(ARM_INPUT, "Arm"); configInput(RST_INPUT, "Reset"); @@ -82,11 +90,9 @@ struct BtogglerSt : Module { prevTrigValue = 0; rst = 0; prevRst = 0; - arSum = 0; maxFadeSample = 0; currentFadeSample = 0; fading = false; - sustain = 1; startFade = 0; lastFade = 0; outputs[GATE_OUTPUT].setVoltage(0); @@ -117,7 +123,26 @@ struct BtogglerSt : Module { } void process(const ProcessArgs& args) override { + attack = params[ATTACK_PARAMS].getValue() + (inputs[ATTACK_INPUT].getVoltage() * params[ATTACKATNV_PARAMS].getValue()); + if (attack > 10) + attack = 10; + else if (attack < 0) + attack = 0; + + sustain = params[SUSTAIN_PARAMS].getValue() + (inputs[SUSTAIN_INPUT].getVoltage() * params[SUSTAINATNV_PARAMS].getValue() * 0.1); + if (sustain > 1) + sustain = 1; + else if (sustain < 0) + sustain = 0; + + release = params[RELEASE_PARAMS].getValue() + (inputs[RELEASE_INPUT].getVoltage() * params[RELEASEATNV_PARAMS].getValue()); + if (release > 10) + release = 10; + else if (release < 0) + release = 0; + clockConnection = inputs[CLOCK_INPUT].isConnected(); + if (clockConnection) { clock = inputs[CLOCK_INPUT].getVoltage(); if (clock >= 1 && prevClock < 1) { @@ -136,7 +161,7 @@ struct BtogglerSt : Module { lights[WRN_LIGHT].setBrightness(0.f); // below is different from original: if internalState is 0 or 1 // it will not do the fade - if ((params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0) && internalState == 1){ + if (release != 0 && internalState == 1){ if (fading) { startFade = lastFade; } else { @@ -166,25 +191,10 @@ struct BtogglerSt : Module { if (trigState){ // if occurs go to state waiting for next clock internalState = 1; lights[WRN_LIGHT].setBrightness(1.f); - } else if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + } else if (release != 0){ if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; if (lastFade < 0) { @@ -204,21 +214,8 @@ struct BtogglerSt : Module { } } } else { // if fading and BOTH inputs are not connected - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; + + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; @@ -256,7 +253,7 @@ struct BtogglerSt : Module { lights[WRN_LIGHT].setBrightness(0.f); internalState = 2; - if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0) { + if (attack != 0) { if (fading) { startFade = lastFade; } else { @@ -265,24 +262,11 @@ struct BtogglerSt : Module { } currentFadeSample = 0; } - } else if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + } else if (release != 0){ if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; @@ -303,21 +287,8 @@ struct BtogglerSt : Module { } } } else { // if fading and inputs are BOTH not connected - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; + + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; @@ -350,24 +321,11 @@ struct BtogglerSt : Module { if (trigState) { // if TRIG occurs lights[WRN_LIGHT].setBrightness(1.f); internalState = 3; // go to state waiting for next clock - } else if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0){ + } else if (attack != 0){ if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading attack and input connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -386,21 +344,8 @@ struct BtogglerSt : Module { } } } else { // if fading attack and inputs are BOTH not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - // get sustain value - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -416,12 +361,7 @@ struct BtogglerSt : Module { } currentFadeSample++; } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if not fading attack and one input connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + for (int i=0; i<2; i++){ if (inputs[IN_INPUT+i].isConnected()) { outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); @@ -430,22 +370,12 @@ struct BtogglerSt : Module { } } } else { // if not fading attack and input are BOTH not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); // send envelope on right channel } + } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if attack parameters are not set and ONE input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + for (int i=0; i<2; i++){ if (inputs[IN_INPUT+i].isConnected()) { outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); @@ -454,14 +384,10 @@ struct BtogglerSt : Module { } } } else { // if attack parameters are not set and BOTH inputs are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); + } break; @@ -474,7 +400,7 @@ struct BtogglerSt : Module { lights[WRN_LIGHT].setBrightness(0.f); lights[OUT_LIGHT].setBrightness(0.f); internalState = 0; - if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + if (release != 0){ if (fading) { startFade = lastFade; } else { @@ -483,24 +409,11 @@ struct BtogglerSt : Module { } currentFadeSample = 0; } - } else if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0){ + } else if (attack != 0){ if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading attack and ONE input connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -519,21 +432,8 @@ struct BtogglerSt : Module { } } } else { // if fading attack and BOTH input are not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - // get sustain value - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -549,12 +449,7 @@ struct BtogglerSt : Module { } currentFadeSample++; } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if not fading attack and ONE input connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + for (int i=0; i<2; i++){ if (inputs[IN_INPUT+i].isConnected()) { outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); @@ -563,22 +458,12 @@ struct BtogglerSt : Module { } } } else { // if not fading attack and BOTH inputs are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); // send envelope on right channel } } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if attack parameters are not set and ONE input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + for (int i=0; i<2; i++){ if (inputs[IN_INPUT+i].isConnected()) { outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); @@ -587,12 +472,7 @@ struct BtogglerSt : Module { } } } else { // if attack parameters are not set and BOTH inputs are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); } @@ -630,18 +510,21 @@ struct BtogglerStWidget : ModuleWidget { addChild(createWidget(Vec(0, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget(Vec(box.size.x - RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addInput(createInputCentered(mm2px(Vec(32, 18.68)), module, BtogglerSt::CLOCK_INPUT)); + addInput(createInputCentered(mm2px(Vec(30, 15.68)), module, BtogglerSt::CLOCK_INPUT)); - addInput(createInputCentered(mm2px(Vec(12.5, 47)), module, BtogglerSt::ARM_INPUT)); - addInput(createInputCentered(mm2px(Vec(33, 47)), module, BtogglerSt::RST_INPUT)); + addInput(createInputCentered(mm2px(Vec(12.5, 37.5)), module, BtogglerSt::ARM_INPUT)); + addInput(createInputCentered(mm2px(Vec(33, 37.5)), module, BtogglerSt::RST_INPUT)); - addParam(createParamCentered(mm2px(Vec(8.48, 65)), module, BtogglerSt::ATTACK_PARAMS)); + addParam(createParamCentered(mm2px(Vec(8.48, 60)), module, BtogglerSt::ATTACK_PARAMS)); + addParam(createParamCentered(mm2px(Vec(8.48, 71.5)), module, BtogglerSt::ATTACKATNV_PARAMS)); addInput(createInputCentered(mm2px(Vec(8.48, 80.5)), module, BtogglerSt::ATTACK_INPUT)); - addParam(createParamCentered(mm2px(Vec(22.8, 65)), module, BtogglerSt::SUSTAIN_PARAMS)); + addParam(createParamCentered(mm2px(Vec(22.8, 60)), module, BtogglerSt::SUSTAIN_PARAMS)); + addParam(createParamCentered(mm2px(Vec(22.8, 71.5)), module, BtogglerSt::SUSTAINATNV_PARAMS)); addInput(createInputCentered(mm2px(Vec(22.8, 80.5)), module, BtogglerSt::SUSTAIN_INPUT)); - addParam(createParamCentered(mm2px(Vec(37.32, 65)), module, BtogglerSt::RELEASE_PARAMS)); + addParam(createParamCentered(mm2px(Vec(37.32, 60)), module, BtogglerSt::RELEASE_PARAMS)); + addParam(createParamCentered(mm2px(Vec(37.32, 71.5)), module, BtogglerSt::RELEASEATNV_PARAMS)); addInput(createInputCentered(mm2px(Vec(37.32, 80.5)), module, BtogglerSt::RELEASE_INPUT)); addInput(createInputCentered(mm2px(Vec(7, 108.8)), module, BtogglerSt::IN_INPUT)); diff --git a/src/BtogglerStCompact.cpp b/src/BtogglerStCompact.cpp index 9df85e0..3f33d02 100644 --- a/src/BtogglerStCompact.cpp +++ b/src/BtogglerStCompact.cpp @@ -43,19 +43,21 @@ struct BtogglerStCompact : Module { float rst = 0; float prevRst = 0; - float arSum = 0; float maxFadeSample = 0; float currentFadeSample = 0; bool fading = false; - float sustain = 1; float startFade = 0; float lastFade = 0; + float attack; + float sustain; + float release; + BtogglerStCompact() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); - configParam(ATTACK_PARAMS, 0.f, 10.f, 0.f, "Attack (s)"); - configParam(SUSTAIN_PARAMS, 0.f, 1.f, 1.f, "Level", "%", 0, 100); - configParam(RELEASE_PARAMS, 0.f, 10.f, 0.f, "Release (s)"); + configParam(ATTACK_PARAMS, 0.f, 10.f, 0.f, "Attack", "ms", 0, 1000); + configParam(SUSTAIN_PARAMS, 0.f, 1.f, 1.f, "Sustain Level", "%", 0, 100); + configParam(RELEASE_PARAMS, 0.f, 10.f, 0.f, "Release", "ms", 0, 1000); configInput(CLOCK_INPUT, "Clock"); configInput(ARM_INPUT, "Arm"); configInput(RST_INPUT, "Reset"); @@ -82,11 +84,9 @@ struct BtogglerStCompact : Module { prevTrigValue = 0; rst = 0; prevRst = 0; - arSum = 0; maxFadeSample = 0; currentFadeSample = 0; fading = false; - sustain = 1; startFade = 0; lastFade = 0; outputs[GATE_OUTPUT].setVoltage(0); @@ -117,7 +117,26 @@ struct BtogglerStCompact : Module { } void process(const ProcessArgs& args) override { + attack = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); + if (attack > 10) + attack = 10; + else if (attack < 0) + attack = 0; + + sustain = params[SUSTAIN_PARAMS].getValue() + (inputs[SUSTAIN_INPUT].getVoltage() * 0.1); + if (sustain > 1) + sustain = 1; + else if (sustain < 0) + sustain = 0; + + release = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); + if (release > 10) + release = 10; + else if (release < 0) + release = 0; + clockConnection = inputs[CLOCK_INPUT].isConnected(); + if (clockConnection) { clock = inputs[CLOCK_INPUT].getVoltage(); if (clock >= 1 && prevClock < 1) { @@ -136,7 +155,7 @@ struct BtogglerStCompact : Module { lights[WRN_LIGHT].setBrightness(0.f); // below is different from original: if internalState is 0 or 1 // it will not do the fade - if ((params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0) && internalState == 1){ + if (release != 0 && internalState == 1){ if (fading) { startFade = lastFade; } else { @@ -166,25 +185,10 @@ struct BtogglerStCompact : Module { if (trigState){ // if occurs go to state waiting for next clock internalState = 1; lights[WRN_LIGHT].setBrightness(1.f); - } else if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + } else if (release != 0){ if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; if (lastFade < 0) { @@ -204,21 +208,8 @@ struct BtogglerStCompact : Module { } } } else { // if fading and BOTH inputs are not connected - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; + + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; @@ -256,7 +247,7 @@ struct BtogglerStCompact : Module { lights[WRN_LIGHT].setBrightness(0.f); internalState = 2; - if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0) { + if (attack != 0) { if (fading) { startFade = lastFade; } else { @@ -265,24 +256,11 @@ struct BtogglerStCompact : Module { } currentFadeSample = 0; } - } else if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + } else if (release != 0){ if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; @@ -303,21 +281,8 @@ struct BtogglerStCompact : Module { } } } else { // if fading and inputs are BOTH not connected - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; + + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; @@ -350,24 +315,11 @@ struct BtogglerStCompact : Module { if (trigState) { // if TRIG occurs lights[WRN_LIGHT].setBrightness(1.f); internalState = 3; // go to state waiting for next clock - } else if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0){ + } else if (attack != 0){ if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading attack and input connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -386,21 +338,8 @@ struct BtogglerStCompact : Module { } } } else { // if fading attack and inputs are BOTH not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - // get sustain value - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -416,12 +355,7 @@ struct BtogglerStCompact : Module { } currentFadeSample++; } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if not fading attack and one input connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + for (int i=0; i<2; i++){ if (inputs[IN_INPUT+i].isConnected()) { outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); @@ -430,22 +364,12 @@ struct BtogglerStCompact : Module { } } } else { // if not fading attack and input are BOTH not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); // send envelope on right channel } + } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if attack parameters are not set and ONE input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + for (int i=0; i<2; i++){ if (inputs[IN_INPUT+i].isConnected()) { outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); @@ -454,14 +378,10 @@ struct BtogglerStCompact : Module { } } } else { // if attack parameters are not set and BOTH inputs are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); + } break; @@ -474,7 +394,7 @@ struct BtogglerStCompact : Module { lights[WRN_LIGHT].setBrightness(0.f); lights[OUT_LIGHT].setBrightness(0.f); internalState = 0; - if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + if (release != 0){ if (fading) { startFade = lastFade; } else { @@ -483,24 +403,11 @@ struct BtogglerStCompact : Module { } currentFadeSample = 0; } - } else if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0){ + } else if (attack != 0){ if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading attack and ONE input connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -519,21 +426,8 @@ struct BtogglerStCompact : Module { } } } else { // if fading attack and BOTH input are not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - // get sustain value - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -549,12 +443,7 @@ struct BtogglerStCompact : Module { } currentFadeSample++; } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if not fading attack and ONE input connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + for (int i=0; i<2; i++){ if (inputs[IN_INPUT+i].isConnected()) { outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); @@ -563,22 +452,12 @@ struct BtogglerStCompact : Module { } } } else { // if not fading attack and BOTH inputs are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); // send envelope on right channel } } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if attack parameters are not set and ONE input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + for (int i=0; i<2; i++){ if (inputs[IN_INPUT+i].isConnected()) { outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); @@ -587,12 +466,7 @@ struct BtogglerStCompact : Module { } } } else { // if attack parameters are not set and BOTH inputs are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } + outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); } diff --git a/src/Calcs.cpp b/src/Calcs.cpp index e0a9f11..9319c1b 100644 --- a/src/Calcs.cpp +++ b/src/Calcs.cpp @@ -43,7 +43,6 @@ struct Calcs : Module { }; Calcs() { - config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); configInput(A_INPUT, "a"); configInput(B_INPUT, "b"); @@ -81,38 +80,33 @@ struct Calcs : Module { float checkRange(float checkedValue) { - if (params[RANGE_SWITCH].getValue() == 0){ - if (checkedValue > 5) { + if (params[RANGE_SWITCH].getValue() == 0) { + if (checkedValue > 5) checkedValue = 5; - } else { - if (checkedValue < -5) { - checkedValue = -5; - } - } + else if (checkedValue < -5) + checkedValue = -5; } else { - if (checkedValue > 10) { + if (checkedValue > 10) checkedValue = 10; - } else { - if (checkedValue < 0) { - checkedValue = 0; - } - } + else if (checkedValue < 0) + checkedValue = 0; } return checkedValue; } void process(const ProcessArgs& args) override { - if (inputs[A_INPUT].isConnected() && inputs[B_INPUT].isConnected()){ + if (inputs[A_INPUT].isConnected() && inputs[B_INPUT].isConnected()) { outputs[BPLUSA_OUTPUT].setVoltage(checkRange(inputs[A_INPUT].getVoltage() + inputs[B_INPUT].getVoltage())); outputs[ATIMESB_OUTPUT].setVoltage(checkRange(inputs[A_INPUT].getVoltage() * inputs[B_INPUT].getVoltage())); outputs[BMINUSA_OUTPUT].setVoltage(checkRange(inputs[B_INPUT].getVoltage() - inputs[A_INPUT].getVoltage())); outputs[AMINUSB_OUTPUT].setVoltage(checkRange(inputs[A_INPUT].getVoltage() - inputs[B_INPUT].getVoltage())); - if (inputs[B_INPUT].getVoltage() != 0) { + + if (inputs[B_INPUT].getVoltage() != 0) outputs[ADIVB_OUTPUT].setVoltage(checkRange(inputs[A_INPUT].getVoltage() / inputs[B_INPUT].getVoltage())); - } - if (inputs[C_INPUT].getVoltage() != 0) { + + if (inputs[C_INPUT].getVoltage() != 0) outputs[BDIVA_OUTPUT].setVoltage(checkRange(inputs[B_INPUT].getVoltage() / inputs[A_INPUT].getVoltage())); - } + outputs[AAVGB_OUTPUT].setVoltage(checkRange((inputs[A_INPUT].getVoltage() + inputs[B_INPUT].getVoltage())/2)); } else { outputs[BPLUSA_OUTPUT].setVoltage(0); @@ -123,17 +117,18 @@ struct Calcs : Module { outputs[BDIVA_OUTPUT].setVoltage(0); outputs[AAVGB_OUTPUT].setVoltage(0); } - if (inputs[B_INPUT].isConnected() && inputs[C_INPUT].isConnected()){ + if (inputs[B_INPUT].isConnected() && inputs[C_INPUT].isConnected()) { outputs[CPLUSB_OUTPUT].setVoltage(checkRange(inputs[B_INPUT].getVoltage() + inputs[C_INPUT].getVoltage())); outputs[BTIMESC_OUTPUT].setVoltage(checkRange(inputs[B_INPUT].getVoltage() * inputs[C_INPUT].getVoltage())); outputs[BMINUSC_OUTPUT].setVoltage(checkRange(inputs[B_INPUT].getVoltage() - inputs[C_INPUT].getVoltage())); outputs[CMINUSB_OUTPUT].setVoltage(checkRange(inputs[C_INPUT].getVoltage() - inputs[B_INPUT].getVoltage())); - if (inputs[C_INPUT].getVoltage() != 0) { + + if (inputs[C_INPUT].getVoltage() != 0) outputs[BDIVC_OUTPUT].setVoltage(checkRange(inputs[B_INPUT].getVoltage() / inputs[C_INPUT].getVoltage())); - } - if (inputs[B_INPUT].getVoltage() != 0) { + + if (inputs[B_INPUT].getVoltage() != 0) outputs[CDIVB_OUTPUT].setVoltage(checkRange(inputs[C_INPUT].getVoltage() / inputs[B_INPUT].getVoltage())); - } + outputs[BAVGC_OUTPUT].setVoltage(checkRange((inputs[B_INPUT].getVoltage() + inputs[C_INPUT].getVoltage())/2)); } else { outputs[CPLUSB_OUTPUT].setVoltage(0); @@ -145,17 +140,18 @@ struct Calcs : Module { outputs[BAVGC_OUTPUT].setVoltage(0); } - if (inputs[A_INPUT].isConnected() && inputs[C_INPUT].isConnected()){ + if (inputs[A_INPUT].isConnected() && inputs[C_INPUT].isConnected()) { outputs[CPLUSA_OUTPUT].setVoltage(checkRange(inputs[A_INPUT].getVoltage() + inputs[C_INPUT].getVoltage())); outputs[ATIMESC_OUTPUT].setVoltage(checkRange(inputs[A_INPUT].getVoltage() * inputs[C_INPUT].getVoltage())); outputs[AMINUSC_OUTPUT].setVoltage(checkRange(inputs[A_INPUT].getVoltage() - inputs[C_INPUT].getVoltage())); outputs[CMINUSA_OUTPUT].setVoltage(checkRange(inputs[C_INPUT].getVoltage() - inputs[A_INPUT].getVoltage())); - if (inputs[A_INPUT].getVoltage() != 0) { + + if (inputs[A_INPUT].getVoltage() != 0) outputs[CDIVA_OUTPUT].setVoltage(checkRange(inputs[C_INPUT].getVoltage() / inputs[A_INPUT].getVoltage())); - } - if (inputs[C_INPUT].getVoltage() != 0) { + + if (inputs[C_INPUT].getVoltage() != 0) outputs[ADIVC_OUTPUT].setVoltage(checkRange(inputs[A_INPUT].getVoltage() / inputs[C_INPUT].getVoltage())); - } + outputs[AAVGC_OUTPUT].setVoltage(checkRange((inputs[A_INPUT].getVoltage() + inputs[C_INPUT].getVoltage())/2)); } else { outputs[CPLUSA_OUTPUT].setVoltage(0); @@ -167,15 +163,13 @@ struct Calcs : Module { outputs[AAVGC_OUTPUT].setVoltage(0); } - if (inputs[A_INPUT].isConnected() && inputs[B_INPUT].isConnected() && inputs[C_INPUT].isConnected()){ + if (inputs[A_INPUT].isConnected() && inputs[B_INPUT].isConnected() && inputs[C_INPUT].isConnected()) outputs[AVGABC_OUTPUT].setVoltage(checkRange((inputs[A_INPUT].getVoltage() + inputs[B_INPUT].getVoltage() + inputs[C_INPUT].getVoltage())/3)); - } else { + else outputs[AVGABC_OUTPUT].setVoltage(0); - } } }; - struct CalcsWidget : ModuleWidget { CalcsWidget(Calcs* module) { setModule(module); @@ -243,5 +237,4 @@ struct CalcsWidget : ModuleWidget { } }; - Model* modelCalcs = createModel("Calcs"); \ No newline at end of file diff --git a/src/DrumPlayer.cpp b/src/DrumPlayer.cpp index 29f9beb..43911a3 100644 --- a/src/DrumPlayer.cpp +++ b/src/DrumPlayer.cpp @@ -1,3 +1,11 @@ +#define NO_INTERP 0 +#define LINEAR1_INTERP 1 +#define LINEAR2_INTERP 2 +#define HERMITE_INTERP 3 +#define NORMALLED_OUTS 0 +#define SOLO_OUTS 1 +#define UNCONNECTED_ON_4 2 + #include "plugin.hpp" #include "osdialog.h" #define DR_WAV_IMPLEMENTATION @@ -27,16 +35,17 @@ struct DrumPlayer : Module { NUM_OUTPUTS }; enum LightIds { + ENUMS(SLOT_LIGHT,4), NUM_LIGHTS }; unsigned int channels[4]; unsigned int sampleRate[4]; drwav_uint64 totalSampleC[4]; + drwav_uint64 totalSamples[4]; - vector playBuffer[4]; + vector playBuffer[4][2]; - bool loading[4] = {false, false, false, false}; bool fileLoaded[4] = {false, false, false, false}; bool play[4] = {false, false, false, false}; @@ -48,14 +57,9 @@ struct DrumPlayer : Module { double prevSampleWeight [4] = {0,0,0,0}; double currSampleWeight [4] = {0,0,0,0}; double prevSamplePos[4] = {0,0,0,0}; - double sampleInterpol = 0; - int sampleInterpCounter = 0; - double avePrevSample; - double avePostSample; - double resampled[4]; std::string storedPath[4] = {"","","",""}; - std::string fileDesc[4]; + std::string fileDescription[4] = {"--none--","--none--","--none--","--none--"}; float trigValue[4] = {0.f, 0.f, 0.f, 0.f}; float prevTrigValue[4] = {0.f, 0.f, 0.f, 0.f}; @@ -63,17 +67,18 @@ struct DrumPlayer : Module { float chokeValue[4] = {1.f, 1.f, 1.f, 1.f}; bool fading[4] = {false, false, false, false}; float fadingValue[4] = {0.f, 0.f, 0.f, 0.f}; + float fadeDecrement = 1000 / (APP->engine->getSampleRate()); // calcs volume decrement for 1ms fade double fadedPosition[4] = {0, 0, 0, 0}; float level[4]; float currentOutput; float summedOutput; - int resamplingMode = 3; - - //bool clearSlots = false; + int interpolationMode = HERMITE_INTERP; + int outsMode = 0; + int antiAlias = 1; - bool normalledOuts = true; + double a0, a1, a2, b1, b2, z1, z2; DrumPlayer() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); @@ -97,10 +102,10 @@ struct DrumPlayer : Module { configParam(ACCVOL_PARAM+2, 0.f, 2.0f, 1.0f, "Accent Level #3", "%", 0, 100); configParam(ACCVOL_PARAM+3, 0.f, 2.0f, 1.0f, "Accent Level #4", "%", 0, 100); - configParam(SPEED_PARAM, 0.01f, 2.0f, 1.0f, "Speed #1"); - configParam(SPEED_PARAM+1, 0.01f, 2.0f, 1.0f, "Speed #2"); - configParam(SPEED_PARAM+2, 0.01f, 2.0f, 1.0f, "Speed #3"); - configParam(SPEED_PARAM+3, 0.01f, 2.0f, 1.0f, "Speed #4"); + configParam(SPEED_PARAM, 0.01f, 2.0f, 1.0f, "Speed #1", "x", 0, 1); + configParam(SPEED_PARAM+1, 0.01f, 2.0f, 1.0f, "Speed #2", "x", 0, 1); + configParam(SPEED_PARAM+2, 0.01f, 2.0f, 1.0f, "Speed #3", "x", 0, 1); + configParam(SPEED_PARAM+3, 0.01f, 2.0f, 1.0f, "Speed #4", "x", 0, 1); configSwitch(CHOKE_SWITCH, 0.f, 1.f, 0.f, "Choke #1", {"Off", "On"}); configSwitch(CHOKE_SWITCH+1, 0.f, 1.f, 0.f, "Choke #2", {"Off", "On"}); @@ -111,26 +116,41 @@ struct DrumPlayer : Module { configOutput(OUT_OUTPUT+2,"out #3"); configOutput(OUT_OUTPUT+3,"out #4"); - playBuffer[0].resize(0); - playBuffer[1].resize(0); - playBuffer[2].resize(0); - playBuffer[3].resize(0); + playBuffer[0][0].resize(0); + playBuffer[1][0].resize(0); + playBuffer[2][0].resize(0); + playBuffer[3][0].resize(0); + playBuffer[0][1].resize(0); + playBuffer[1][1].resize(0); + playBuffer[2][1].resize(0); + playBuffer[3][1].resize(0); } void onReset() override { - resamplingMode = 3; - for (int i=0;i<4;i++) { - clearSlotFunct(i); + interpolationMode = HERMITE_INTERP; + antiAlias = 1; + outsMode = 0; + for (int i = 0; i < 4; i++) { + clearSlot(i); play[i] = false; choking[i] = false; fading[i] = false; } } + void onSampleRateChange() override { + for (int i = 0; i < 4; i++) { + if (fileLoaded[i]) + sampleCoeff[i] = sampleRate[i] / (APP->engine->getSampleRate()); + } + fadeDecrement = 1000 / (APP->engine->getSampleRate()); + } + json_t *dataToJson() override { json_t *rootJ = json_object(); - json_object_set_new(rootJ, "Resampling", json_integer(resamplingMode)); - json_object_set_new(rootJ, "NormalledOuts", json_boolean(normalledOuts)); + json_object_set_new(rootJ, "Interpolation", json_integer(interpolationMode)); + json_object_set_new(rootJ, "AntiAlias", json_integer(antiAlias)); + json_object_set_new(rootJ, "OutsMode", json_integer(outsMode)); json_object_set_new(rootJ, "Slot1", json_string(storedPath[0].c_str())); json_object_set_new(rootJ, "Slot2", json_string(storedPath[1].c_str())); json_object_set_new(rootJ, "Slot3", json_string(storedPath[2].c_str())); @@ -139,13 +159,17 @@ struct DrumPlayer : Module { } void dataFromJson(json_t *rootJ) override { - json_t* resamplingJ = json_object_get(rootJ, "Resampling"); - if (resamplingJ) - resamplingMode = json_integer_value(resamplingJ); + json_t* interpolationJ = json_object_get(rootJ, "Interpolation"); + if (interpolationJ) + interpolationMode = json_integer_value(interpolationJ); - json_t* normalledOutsJ = json_object_get(rootJ, "NormalledOuts"); - if (normalledOutsJ) - normalledOuts = json_boolean_value(normalledOutsJ); + json_t* antiAliasJ = json_object_get(rootJ, "AntiAlias"); + if (antiAliasJ) + antiAlias = json_integer_value(antiAliasJ); + + json_t* outsModeJ = json_object_get(rootJ, "OutsMode"); + if (outsModeJ) + outsMode = json_integer_value(outsModeJ); json_t *slot1J = json_object_get(rootJ, "Slot1"); if (slot1J) { @@ -169,9 +193,37 @@ struct DrumPlayer : Module { } } - void loadSample(std::string path, int slot) { + void calcBiquadLpf(double frequency, double samplerate, double Q) { + z1 = z2 = 0.0; + double Fc = frequency / samplerate; + double norm; + double K = tan(M_PI * Fc); + norm = 1 / (1 + K / Q + K * K); + a0 = K * K * norm; + a1 = 2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + } + + float biquadLpf(float in) { + double out = in * a0 + z1; + z1 = in * a1 + z2 - b1 * out; + z2 = in * a2 - b2 * out; + return out; + } + + /* + double hermiteInterpol(double x0, double x1, double x2, double x3, double t) { + double c0 = x1; + double c1 = .5F * (x2 - x0); + double c2 = x0 - (2.5F * x1) + (2 * x2) - (.5F * x3); + double c3 = (.5F * (x3 - x0)) + (1.5F * (x1 - x2)); + return (((((c3 * t) + c2) * t) + c1) * t) + c0; + } + */ - loading[slot] = true; + void loadSample(std::string path, int slot) { unsigned int c; unsigned int sr; drwav_uint64 tsc; @@ -179,56 +231,68 @@ struct DrumPlayer : Module { pSampleData = drwav_open_and_read_file_f32(path.c_str(), &c, &sr, &tsc); if (pSampleData != NULL) { - channels[slot] = c; - sampleRate[slot] = sr; - playBuffer[slot].clear(); - for (unsigned int i=0; i < tsc; i = i + c) { - if (channels[slot] == 1) - playBuffer[slot].push_back(pSampleData[i]); - else if (channels[slot] == 2) - playBuffer[slot].push_back((pSampleData[i]+(float)pSampleData[i+1])/2); + //channels[slot] = c; + sampleRate[slot] = sr * 2; + calcBiquadLpf(20000.0, sampleRate[slot], 1); + playBuffer[slot][0].clear(); + playBuffer[slot][1].clear(); + for (unsigned int i = 0; i < tsc; i = i + c) { + playBuffer[slot][0].push_back(pSampleData[i]); + playBuffer[slot][0].push_back(0); } - totalSampleC[slot] = playBuffer[slot].size(); + totalSampleC[slot] = playBuffer[slot][0].size(); + totalSamples[slot] = totalSampleC[slot]-1; drwav_free(pSampleData); - loading[slot] = false; - fileLoaded[slot] = true; + for (unsigned int i = 1; i < totalSamples[slot]; i = i + 2) + playBuffer[slot][0][i] = playBuffer[slot][0][i-1] * .5f + playBuffer[slot][0][i+1] * .5f; + + playBuffer[slot][0][totalSamples[slot]] = playBuffer[slot][0][totalSamples[slot]-1] * .5f; // halve the last sample + + for (unsigned int i = 0; i < totalSampleC[slot]; i++) + playBuffer[slot][1].push_back(biquadLpf(playBuffer[slot][0][i])); + + sampleCoeff[slot] = sampleRate[slot] / (APP->engine->getSampleRate()); // the % distance between samples at speed 1x char* pathDup = strdup(path.c_str()); - fileDesc[slot] = basename(pathDup); + fileDescription[slot] = basename(pathDup); free(pathDup); storedPath[slot] = path; + + fileLoaded[slot] = true; + } else { fileLoaded[slot] = false; + storedPath[slot] = ""; + fileDescription[slot] = "--none--"; } }; - void clearSlotFunct(int slot) { + void clearSlot(int slot) { storedPath[slot] = ""; - fileDesc[slot] = ""; - loading[slot] = false; + fileDescription[slot] = "--none--"; fileLoaded[slot] = false; - playBuffer[slot].clear(); + playBuffer[slot][0].clear(); + playBuffer[slot][1].clear(); totalSampleC[slot] = 0; } void process(const ProcessArgs &args) override { summedOutput = 0; - for (int i=0;i<4;i++){ - if (!fileLoaded[i]) - fileDesc[i] = "-----"; + for (int i = 0; i < 4; i++){ trigValue[i] = inputs[TRIG_INPUT+i].getVoltage(); + lights[SLOT_LIGHT+i].setBrightness(fileLoaded[i]); + if (trigValue[i] >= 1 && prevTrigValue[i] < 1){ if (play[i]) { fading[i] = true; - fadingValue[i] = 5.f; + fadingValue[i] = 1.f; fadedPosition[i] = samplePos[i]; } play[i] = true; - sampleCoeff[i] = sampleRate[i] / args.sampleRate; samplePos[i] = 0; currSampleWeight[i] = sampleCoeff[i]; prevSamplePos[i] = 0; @@ -240,101 +304,98 @@ struct DrumPlayer : Module { if (i < 3 && params[CHOKE_SWITCH+i].getValue()) { choking[i+1] = true; - chokeValue[i+1] = 0.9f; + chokeValue[i+1] = 1.f; } } prevTrigValue[i] = trigValue[i]; currentOutput = 0; - if (fileLoaded[i] && play[i] && floor(samplePos[i]) < totalSampleC[i] && floor(samplePos[i]) >= 0) { - switch (resamplingMode) { - case 0: - currentOutput = 5 * level[i] * playBuffer[i][floor(samplePos[i])]; + //if (fileLoaded[i] && play[i] && floor(samplePos[i]) < totalSampleC[i] && floor(samplePos[i]) >= 0) { + if (fileLoaded[i] && play[i] && floor(samplePos[i]) < totalSampleC[i]) { + switch (interpolationMode) { + case NO_INTERP: + currentOutput = 5 * level[i] * playBuffer[i][antiAlias][floor(samplePos[i])]; break; - case 1: - if (currSampleWeight[i] == 0.0) { - resampled[i] = playBuffer[i][floor(samplePos[i])]; + case LINEAR1_INTERP: + if (currSampleWeight[i] == 0) { + currentOutput = 5 * level[i] * float(playBuffer[i][antiAlias][floor(samplePos[i])]); } else { - sampleInterpol = 0; - sampleInterpCounter = 0; - avePostSample = 0; - for (int j=floor(prevSamplePos[i])+2;j 1 && floor(samplePos[i]) < totalSampleC[i] - 2) { - double a1 = .5F * (playBuffer[i][floor(samplePos[i])+1] - playBuffer[i][floor(samplePos[i])-1]); - double a2 = playBuffer[i][floor(samplePos[i])-1] - (2.5F * playBuffer[i][floor(samplePos[i])]) + (2 * playBuffer[i][floor(samplePos[i])+1]) - (.5F * playBuffer[i][floor(samplePos[i])+2]); - double a3 = (.5F * (playBuffer[i][floor(samplePos[i])+2] - playBuffer[i][floor(samplePos[i])-1])) + (1.5F * (playBuffer[i][floor(samplePos[i])] - playBuffer[i][floor(samplePos[i])+1])); - resampled[i] = (((((a3 * currSampleWeight[i]) + a2) * currSampleWeight[i]) + a1) * currSampleWeight[i]) + playBuffer[i][floor(samplePos[i])]; + if (floor(samplePos[i]) > 1 && floor(samplePos[i]) < totalSamples[i] - 1) { + /* + currentOutput = hermiteInterpol(playBuffer[i][antiAlias][floor(samplePos[i])-1], + playBuffer[i][antiAlias][floor(samplePos[i])], + playBuffer[i][antiAlias][floor(samplePos[i])+1], + playBuffer[i][antiAlias][floor(samplePos[i])+2], + currSampleWeight[i]); + */ + // below is translation of the above function + double a1 = .5F * (playBuffer[i][antiAlias][floor(samplePos[i])+1] - playBuffer[i][antiAlias][floor(samplePos[i])-1]); + double a2 = playBuffer[i][antiAlias][floor(samplePos[i])-1] - (2.5F * playBuffer[i][antiAlias][floor(samplePos[i])]) + (2 * playBuffer[i][antiAlias][floor(samplePos[i])+1]) - (.5F * playBuffer[i][antiAlias][floor(samplePos[i])+2]); + double a3 = (.5F * (playBuffer[i][antiAlias][floor(samplePos[i])+2] - playBuffer[i][antiAlias][floor(samplePos[i])-1])) + (1.5F * (playBuffer[i][antiAlias][floor(samplePos[i])] - playBuffer[i][antiAlias][floor(samplePos[i])+1])); + currentOutput = 5 * level[i] * float( + (((((a3 * currSampleWeight[i]) + a2) * currSampleWeight[i]) + a1) * currSampleWeight[i]) + playBuffer[i][antiAlias][floor(samplePos[i])] + ); } else { - resampled[i] = playBuffer[i][floor(samplePos[i])]; + currentOutput = 5 * level[i] * float(playBuffer[i][antiAlias][floor(samplePos[i])]); } } - //if (i == 0) - // debugDisplay = to_string(sampleInterpCounter); - - currentOutput = 5 * level[i] * float(resampled[i]); break; } if (i > 0 && choking[i]) { - if (chokeValue[i] < 0.1) { + if (chokeValue[i] < 0.0) { choking[i] = false; play[i] = false; currentOutput = 0; } else { currentOutput *= chokeValue[i]; - chokeValue[i] -= 0.1; + chokeValue[i] -= fadeDecrement; } } prevSamplePos[i] = samplePos[i]; - currentSpeed = sampleCoeff[i]*double(params[SPEED_PARAM+i].getValue()); - samplePos[i] += currentSpeed; - if (resamplingMode > 0) { + currentSpeed = double(params[SPEED_PARAM+i].getValue()); + samplePos[i] += sampleCoeff[i]*currentSpeed; + + if (interpolationMode > NO_INTERP) { prevSampleWeight[i] = currSampleWeight[i]; currSampleWeight[i] = samplePos[i] - floor(samplePos[i]); - //currSampleWeight[i] = modf(samplePos[i],&intSamplePos[i]); } if (fading[i]) { if (fadingValue[i] > 0) { - fadingValue[i] -= 0.1; - currentOutput += playBuffer[i][floor(fadedPosition[i])] * fadingValue[i] * level[i]; - fadedPosition[i] += currentSpeed; - if (fadedPosition[i] > totalSampleC[i]) + fadingValue[i] -= fadeDecrement; + currentOutput += (playBuffer[i][antiAlias][floor(fadedPosition[i])] * fadingValue[i] * level[i] * 5); + fadedPosition[i] += sampleCoeff[i]*currentSpeed; + if (fadedPosition[i] > totalSamples[i]) fading[i] = false; } else fading[i] = false; @@ -344,16 +405,32 @@ struct DrumPlayer : Module { play[i] = false; fading[i] = false; } - summedOutput += currentOutput; - if (outputs[OUT_OUTPUT+i].isConnected()) { - outputs[OUT_OUTPUT+i].setVoltage(summedOutput); - summedOutput = 0; + switch (outsMode) { + case NORMALLED_OUTS: + summedOutput += currentOutput; + if (outputs[OUT_OUTPUT+i].isConnected()) { + outputs[OUT_OUTPUT+i].setVoltage(summedOutput); + summedOutput = 0; + } + break; + + case SOLO_OUTS: + if (outputs[OUT_OUTPUT+i].isConnected()) + outputs[OUT_OUTPUT+i].setVoltage(currentOutput); + break; + + case UNCONNECTED_ON_4: + if (i == 3) { + summedOutput += currentOutput; + outputs[OUT_OUTPUT+i].setVoltage(summedOutput); + } else if (outputs[OUT_OUTPUT+i].isConnected()) + outputs[OUT_OUTPUT+i].setVoltage(currentOutput); + else + summedOutput += currentOutput; + break; } - if (!normalledOuts) - summedOutput = 0; - if (!inputs[TRIG_INPUT+i].isConnected()) play[i] = false; } @@ -363,16 +440,17 @@ struct DrumPlayer : Module { struct DrumPlayerItem1 : MenuItem { DrumPlayer *rm ; void onAction(const event::Action &e) override { - char *path = osdialog_file(OSDIALOG_OPEN, NULL, NULL, NULL); int i = 0; + rm->fileLoaded[i] = false; if (path) { - rm->play[i] = false; rm->loadSample(path, i); - rm->samplePos[i] = 0; rm->storedPath[i] = std::string(path); free(path); - } + } else if (rm->storedPath[i] == "") + rm->fileLoaded[i] = false; + else + rm->fileLoaded[i] = true; } }; @@ -381,13 +459,15 @@ struct DrumPlayerItem2 : MenuItem { void onAction(const event::Action &e) override { char *path = osdialog_file(OSDIALOG_OPEN, NULL, NULL, NULL); int i = 1; + rm->fileLoaded[i] = false; if (path) { - rm->play[i] = false; rm->loadSample(path, i); - rm->samplePos[i] = 0; rm->storedPath[i] = std::string(path); free(path); - } + } else if (rm->storedPath[i] == "") + rm->fileLoaded[i] = false; + else + rm->fileLoaded[i] = true; } }; @@ -396,13 +476,15 @@ struct DrumPlayerItem3 : MenuItem { void onAction(const event::Action &e) override { char *path = osdialog_file(OSDIALOG_OPEN, NULL, NULL, NULL); int i = 2; + rm->fileLoaded[i] = false; if (path) { - rm->play[i] = false; rm->loadSample(path, i); - rm->samplePos[i] = 0; rm->storedPath[i] = std::string(path); free(path); - } + } else if (rm->storedPath[i] == "") + rm->fileLoaded[i] = false; + else + rm->fileLoaded[i] = true; } }; @@ -411,12 +493,194 @@ struct DrumPlayerItem4 : MenuItem { void onAction(const event::Action &e) override { char *path = osdialog_file(OSDIALOG_OPEN, NULL, NULL, NULL); int i = 3; + rm->fileLoaded[i] = false; if (path) { - rm->play[i] = false; rm->loadSample(path, i); - rm->samplePos[i] = 0; rm->storedPath[i] = std::string(path); free(path); + } else if (rm->storedPath[i] == "") + rm->fileLoaded[i] = false; + else + rm->fileLoaded[i] = true; + } +}; + +struct dpSlot1Display : TransparentWidget { + DrumPlayer *module; + int frame = 0; + + dpSlot1Display() { + + } + + struct ClearSlot1Item : MenuItem { + DrumPlayer *module; + void onAction(const event::Action &e) override { + module->clearSlot(0); + } + }; + + void onButton(const event::Button &e) override { + if (e.button == GLFW_MOUSE_BUTTON_LEFT && e.action == GLFW_PRESS) + e.consume(this); + + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { + createContextMenu(); + e.consume(this); + } + } + + void createContextMenu() { + DrumPlayer *module = dynamic_cast(this->module); + assert(module); + + if (module) { + ui::Menu *menu = createMenu(); + + DrumPlayerItem1 *rootDirItem = new DrumPlayerItem1; + rootDirItem->text = "Load Sample Slot #1"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription[0])); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlot1Item::module, module)); + + } + } +}; + +struct dpSlot2Display : TransparentWidget { + DrumPlayer *module; + int frame = 0; + + dpSlot2Display() { + + } + + struct ClearSlot2Item : MenuItem { + DrumPlayer *module; + void onAction(const event::Action &e) override { + module->clearSlot(1); + } + }; + + void onButton(const event::Button &e) override { + if (e.button == GLFW_MOUSE_BUTTON_LEFT && e.action == GLFW_PRESS) + e.consume(this); + + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { + createContextMenu(); + e.consume(this); + } + } + + void createContextMenu() { + DrumPlayer *module = dynamic_cast(this->module); + assert(module); + + if (module) { + ui::Menu *menu = createMenu(); + + DrumPlayerItem2 *rootDirItem = new DrumPlayerItem2; + rootDirItem->text = "Load Sample Slot #2"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription[1])); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlot2Item::module, module)); + + } + } +}; + +struct dpSlot3Display : TransparentWidget { + DrumPlayer *module; + int frame = 0; + + dpSlot3Display() { + + } + + struct ClearSlot3Item : MenuItem { + DrumPlayer *module; + void onAction(const event::Action &e) override { + module->clearSlot(2); + } + }; + + void onButton(const event::Button &e) override { + if (e.button == GLFW_MOUSE_BUTTON_LEFT && e.action == GLFW_PRESS) + e.consume(this); + + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { + createContextMenu(); + e.consume(this); + } + } + + void createContextMenu() { + DrumPlayer *module = dynamic_cast(this->module); + assert(module); + + if (module) { + ui::Menu *menu = createMenu(); + + DrumPlayerItem3 *rootDirItem = new DrumPlayerItem3; + rootDirItem->text = "Load Sample Slot #3"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription[2])); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlot3Item::module, module)); + + } + } +}; + +struct dpSlot4Display : TransparentWidget { + DrumPlayer *module; + int frame = 0; + + dpSlot4Display() { + + } + + struct ClearSlot4Item : MenuItem { + DrumPlayer *module; + void onAction(const event::Action &e) override { + module->clearSlot(3); + } + }; + + void onButton(const event::Button &e) override { + if (e.button == GLFW_MOUSE_BUTTON_LEFT && e.action == GLFW_PRESS) + e.consume(this); + + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { + createContextMenu(); + e.consume(this); + } + } + + void createContextMenu() { + DrumPlayer *module = dynamic_cast(this->module); + assert(module); + + if (module) { + ui::Menu *menu = createMenu(); + + DrumPlayerItem4 *rootDirItem = new DrumPlayerItem4; + rootDirItem->text = "Load Sample Slot #4"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription[3])); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlot4Item::module, module)); + } } }; @@ -431,59 +695,92 @@ struct DrumPlayerWidget : ModuleWidget { addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); -; + float xDelta = 16; - for (int i=0;i<4;i++) { - addInput(createInputCentered(mm2px(Vec(8.9+(xDelta*i), 19.5)), module, DrumPlayer::TRIG_INPUT+i)); - addParam(createParamCentered(mm2px(Vec(8.9+(xDelta*i), 31.5)), module, DrumPlayer::TRIGVOL_PARAM+i)); + { + dpSlot1Display *display = new dpSlot1Display(); + display->box.pos = Vec(6, 21); + display->box.size = Vec(41, 24); + display->module = module; + addChild(display); + } - addInput(createInputCentered(mm2px(Vec(8.9+(xDelta*i), 49)), module, DrumPlayer::ACC_INPUT+i)); - addParam(createParamCentered(mm2px(Vec(8.9+(xDelta*i), 61)), module, DrumPlayer::ACCVOL_PARAM+i)); + { + dpSlot2Display *display = new dpSlot2Display(); + display->box.pos = Vec(54, 21); + display->box.size = Vec(41, 24); + display->module = module; + addChild(display); + } - addParam(createParamCentered(mm2px(Vec(8.9+(xDelta*i), 80.5)), module, DrumPlayer::SPEED_PARAM+i)); + { + dpSlot3Display *display = new dpSlot3Display(); + display->box.pos = Vec(101, 21); + display->box.size = Vec(41, 24); + display->module = module; + addChild(display); + } - if (i<3) { - addParam(createParamCentered(mm2px(Vec(8.9+(xDelta*i), 98.4)), module, DrumPlayer::CHOKE_SWITCH+i)); - } + { + dpSlot4Display *display = new dpSlot4Display(); + display->box.pos = Vec(148, 21); + display->box.size = Vec(41, 24); + display->module = module; + addChild(display); + } - addOutput(createOutputCentered(mm2px(Vec(8.9+(xDelta*i), 117)), module, DrumPlayer::OUT_OUTPUT+i)); + for (int i = 0; i < 4; i++) { + addChild(createLightCentered>(mm2px(Vec(9+(xDelta*i), 9)), module, DrumPlayer::SLOT_LIGHT+i)); + + addInput(createInputCentered(mm2px(Vec(9+(xDelta*i), 20.2)), module, DrumPlayer::TRIG_INPUT+i)); + addParam(createParamCentered(mm2px(Vec(9+(xDelta*i), 31.5)), module, DrumPlayer::TRIGVOL_PARAM+i)); + + addInput(createInputCentered(mm2px(Vec(9+(xDelta*i), 49.7)), module, DrumPlayer::ACC_INPUT+i)); + addParam(createParamCentered(mm2px(Vec(9+(xDelta*i), 61)), module, DrumPlayer::ACCVOL_PARAM+i)); + + addParam(createParamCentered(mm2px(Vec(9+(xDelta*i), 80.5)), module, DrumPlayer::SPEED_PARAM+i)); + + if (i<3) + addParam(createParamCentered(mm2px(Vec(9+(xDelta*i), 98.4)), module, DrumPlayer::CHOKE_SWITCH+i)); + + addOutput(createOutputCentered(mm2px(Vec(9+(xDelta*i), 117)), module, DrumPlayer::OUT_OUTPUT+i)); } } struct ClearSlotsItem : MenuItem { DrumPlayer *module; void onAction(const event::Action &e) override { - for (int i=0;i<4;i++) - module->clearSlotFunct(i); + for (int i = 0; i < 4; i++) + module->clearSlot(i); } }; struct ClearSlot1Item : MenuItem { DrumPlayer *module; void onAction(const event::Action &e) override { - module->clearSlotFunct(0); + module->clearSlot(0); } }; struct ClearSlot2Item : MenuItem { DrumPlayer *module; void onAction(const event::Action &e) override { - module->clearSlotFunct(1); + module->clearSlot(1); } }; struct ClearSlot3Item : MenuItem { DrumPlayer *module; void onAction(const event::Action &e) override { - module->clearSlotFunct(2); + module->clearSlot(2); } }; struct ClearSlot4Item : MenuItem { DrumPlayer *module; void onAction(const event::Action &e) override { - module->clearSlotFunct(3); + module->clearSlot(3); } }; @@ -494,57 +791,74 @@ struct DrumPlayerWidget : ModuleWidget { DrumPlayerItem1 *rootDirItem1 = new DrumPlayerItem1; menu->addChild(createMenuLabel("Sample Slots")); - rootDirItem1->text = std::to_string(1) + ": " + module->fileDesc[0]; + rootDirItem1->text = std::to_string(1) + ": " + module->fileDescription[0]; rootDirItem1->rm = module; menu->addChild(rootDirItem1); menu->addChild(construct(&MenuItem::rightText, "Clear #1", &ClearSlot1Item::module, module)); DrumPlayerItem2 *rootDirItem2 = new DrumPlayerItem2; - rootDirItem2->text = std::to_string(2) + ": " + module->fileDesc[1]; + rootDirItem2->text = std::to_string(2) + ": " + module->fileDescription[1]; rootDirItem2->rm = module; menu->addChild(rootDirItem2); menu->addChild(construct(&MenuItem::rightText, "Clear #2", &ClearSlot2Item::module, module)); DrumPlayerItem3 *rootDirItem3 = new DrumPlayerItem3; - rootDirItem3->text = std::to_string(3) + ": " + module->fileDesc[2]; + rootDirItem3->text = std::to_string(3) + ": " + module->fileDescription[2]; rootDirItem3->rm = module; menu->addChild(rootDirItem3); menu->addChild(construct(&MenuItem::rightText, "Clear #3", &ClearSlot3Item::module, module)); DrumPlayerItem4 *rootDirItem4 = new DrumPlayerItem4; - rootDirItem4->text = std::to_string(4) + ": " + module->fileDesc[3]; + rootDirItem4->text = std::to_string(4) + ": " + module->fileDescription[3]; rootDirItem4->rm = module; menu->addChild(rootDirItem4); menu->addChild(construct(&MenuItem::rightText, "Clear #4", &ClearSlot4Item::module, module)); - menu->addChild(new MenuSeparator()); - menu->addChild(construct(&MenuItem::text, "Clear ALL slots", &ClearSlotsItem::module, module)); - menu->addChild(new MenuSeparator()); + menu->addChild(new MenuSeparator()); + menu->addChild(construct(&MenuItem::text, "Clear ALL slots", &ClearSlotsItem::module, module)); + menu->addChild(new MenuSeparator()); - menu->addChild(createMenuLabel("Resampling Mode")); + menu->addChild(createMenuLabel("Interpolation")); struct ModeItem : MenuItem { DrumPlayer* module; - int resamplingMode; + int interpolationMode; void onAction(const event::Action& e) override { - module->resamplingMode = resamplingMode; + module->interpolationMode = interpolationMode; } }; - - std::string modeNames[4] = {"No interpolation", "Linear 1", "Linear 2", "Hermite"}; + std::string modeNames[4] = {"None", "Linear 1", "Linear 2", "Hermite"}; for (int i = 0; i < 4; i++) { ModeItem* modeItem = createMenuItem(modeNames[i]); - modeItem->rightText = CHECKMARK(module->resamplingMode == i); + modeItem->rightText = CHECKMARK(module->interpolationMode == i); modeItem->module = module; - modeItem->resamplingMode = i; + modeItem->interpolationMode = i; menu->addChild(modeItem); } menu->addChild(new MenuSeparator()); - menu->addChild(createBoolPtrMenuItem("Normalled OUTs", "", &module->normalledOuts)); + menu->addChild(createBoolPtrMenuItem("Anti-aliasing filter", "", &module->antiAlias)); + + menu->addChild(new MenuSeparator()); + menu->addChild(createMenuLabel("Outs mode")); + struct OutsItem : MenuItem { + DrumPlayer* module; + int outsMode; + void onAction(const event::Action& e) override { + module->outsMode = outsMode; + } + }; + std::string outsNames[3] = {"Normalled", "Solo", "Unconnected on out #4"}; + for (int i = 0; i < 3; i++) { + OutsItem* outsItem = createMenuItem(outsNames[i]); + outsItem->rightText = CHECKMARK(module->outsMode == i); + outsItem->module = module; + outsItem->outsMode = i; + menu->addChild(outsItem); + } } }; diff --git a/src/DrumPlayerPlus.cpp b/src/DrumPlayerPlus.cpp index 9fad058..6f2303b 100644 --- a/src/DrumPlayerPlus.cpp +++ b/src/DrumPlayerPlus.cpp @@ -1,3 +1,11 @@ +#define NO_INTERP 0 +#define LINEAR1_INTERP 1 +#define LINEAR2_INTERP 2 +#define HERMITE_INTERP 3 +#define NORMALLED_OUTS 0 +#define SOLO_OUTS 1 +#define UNCONNECTED_ON_4 2 + #include "plugin.hpp" #include "osdialog.h" //#define DR_WAV_IMPLEMENTATION @@ -40,29 +48,24 @@ struct DrumPlayerPlus : Module { unsigned int channels[4]; unsigned int sampleRate[4]; drwav_uint64 totalSampleC[4]; + drwav_uint64 totalSamples[4]; - vector playBuffer[4]; + vector playBuffer[4][2]; - bool loading[4] = {false, false, false, false}; bool fileLoaded[4] = {false, false, false, false}; bool play[4] = {false, false, false, false}; double samplePos[4] = {0,0,0,0}; double sampleCoeff[4]; - double currentSpeed = 0.0; + double currentSpeed = 0; double prevSampleWeight [4] = {0,0,0,0}; double currSampleWeight [4] = {0,0,0,0}; double prevSamplePos[4] = {0,0,0,0}; - double sampleInterpol = 0; - int sampleInterpCounter = 0; - double avePrevSample; - double avePostSample; - double resampled[4]; std::string storedPath[4] = {"","","",""}; - std::string fileDesc[4]; + std::string fileDescription[4] = {"--none--","--none--","--none--","--none--"}; std::string fileDisplay[4] = {"-----","-----","-----","-----"}; float trigValue[4] = {0.f, 0.f, 0.f, 0.f}; @@ -71,20 +74,21 @@ struct DrumPlayerPlus : Module { float chokeValue[4] = {1.f, 1.f, 1.f, 1.f}; bool fading[4] = {false, false, false, false}; float fadingValue[4] = {0.f, 0.f, 0.f, 0.f}; + float fadeDecrement = 1000 / (APP->engine->getSampleRate()); // calcs volume decrement for 1ms fade double fadedPosition[4] = {0, 0, 0, 0}; float level[4]; float currentOutput; float summedOutput; - int resamplingMode = 3; - - //bool clearSlots = false; - - bool normalledOuts = true; + int interpolationMode = HERMITE_INTERP; + int outsMode = 0; + int antiAlias = 1; //std::string debugDisplay = "X"; + double a0, a1, a2, b1, b2, z1, z2; + DrumPlayerPlus() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configInput(TRIG_INPUT,"Trig #1"); @@ -123,18 +127,18 @@ struct DrumPlayerPlus : Module { configParam(SPEEDATNV_PARAM+1, -1.0f, 1.0f, 0.0f, "Speed CV Attenuv. #2"); configParam(SPEEDATNV_PARAM+2, -1.0f, 1.0f, 0.0f, "Speed CV Attenuv. #3"); configParam(SPEEDATNV_PARAM+3, -1.0f, 1.0f, 0.0f, "Speed CV Attenuv. #4"); - configParam(SPEED_PARAM, 0.01f, 2.0f, 1.0f, "Speed #1"); - configParam(SPEED_PARAM+1, 0.01f, 2.0f, 1.0f, "Speed #2"); - configParam(SPEED_PARAM+2, 0.01f, 2.0f, 1.0f, "Speed #3"); - configParam(SPEED_PARAM+3, 0.01f, 2.0f, 1.0f, "Speed #4"); + configParam(SPEED_PARAM, 0.01f, 2.0f, 1.0f, "Speed #1", "x", 0, 1); + configParam(SPEED_PARAM+1, 0.01f, 2.0f, 1.0f, "Speed #2", "x", 0, 1); + configParam(SPEED_PARAM+2, 0.01f, 2.0f, 1.0f, "Speed #3", "x", 0, 1); + configParam(SPEED_PARAM+3, 0.01f, 2.0f, 1.0f, "Speed #4", "x", 0, 1); configInput(SPEED_INPUT,"Speed CV #1"); configInput(SPEED_INPUT+1,"Speed CV #2"); configInput(SPEED_INPUT+2,"Speed CV #3"); configInput(SPEED_INPUT+3,"Speed CV #4"); - configSwitch(LIMIT_SWITCH, 0.f, 1.f, 0.f, "Limit #1", {"Off", "5v"}); - configSwitch(LIMIT_SWITCH+1, 0.f, 1.f, 0.f, "Limit #2", {"Off", "5v"}); - configSwitch(LIMIT_SWITCH+2, 0.f, 1.f, 0.f, "Limit #3", {"Off", "5v"}); - configSwitch(LIMIT_SWITCH+3, 0.f, 1.f, 0.f, "Limit #4", {"Off", "5v"}); + configSwitch(LIMIT_SWITCH, 0.f, 1.f, 0.f, "Limit #1", {"Off", "±5v"}); + configSwitch(LIMIT_SWITCH+1, 0.f, 1.f, 0.f, "Limit #2", {"Off", "±5v"}); + configSwitch(LIMIT_SWITCH+2, 0.f, 1.f, 0.f, "Limit #3", {"Off", "±5v"}); + configSwitch(LIMIT_SWITCH+3, 0.f, 1.f, 0.f, "Limit #4", {"Off", "±5v"}); configSwitch(CHOKE_SWITCH, 0.f, 1.f, 0.f, "Choke #1", {"Off", "On"}); configSwitch(CHOKE_SWITCH+1, 0.f, 1.f, 0.f, "Choke #2", {"Off", "On"}); configSwitch(CHOKE_SWITCH+2, 0.f, 1.f, 0.f, "Choke #3", {"Off", "On"}); @@ -144,26 +148,41 @@ struct DrumPlayerPlus : Module { configOutput(OUT_OUTPUT+2,"out #3"); configOutput(OUT_OUTPUT+3,"out #4"); - playBuffer[0].resize(0); - playBuffer[1].resize(0); - playBuffer[2].resize(0); - playBuffer[3].resize(0); + playBuffer[0][0].resize(0); + playBuffer[1][0].resize(0); + playBuffer[2][0].resize(0); + playBuffer[3][0].resize(0); + playBuffer[0][1].resize(0); + playBuffer[1][1].resize(0); + playBuffer[2][1].resize(0); + playBuffer[3][1].resize(0); } void onReset() override { - resamplingMode = 3; - for (int i=0;i<4;i++) { - clearSlotFunct(i); + interpolationMode = HERMITE_INTERP; + antiAlias = 1; + outsMode = 0; + for (int i = 0; i < 4; i++) { + clearSlot(i); play[i] = false; choking[i] = false; fading[i] = false; } } + void onSampleRateChange() override { + for (int i = 0; i < 4; i++) { + if (fileLoaded[i]) + sampleCoeff[i] = sampleRate[i] / (APP->engine->getSampleRate()); + } + fadeDecrement = 1000 / (APP->engine->getSampleRate()); + } + json_t *dataToJson() override { json_t *rootJ = json_object(); - json_object_set_new(rootJ, "Resampling", json_integer(resamplingMode)); - json_object_set_new(rootJ, "NormalledOuts", json_boolean(normalledOuts)); + json_object_set_new(rootJ, "Interpolation", json_integer(interpolationMode)); + json_object_set_new(rootJ, "AntiAlias", json_integer(antiAlias)); + json_object_set_new(rootJ, "OutsMode", json_integer(outsMode)); json_object_set_new(rootJ, "Slot1", json_string(storedPath[0].c_str())); json_object_set_new(rootJ, "Slot2", json_string(storedPath[1].c_str())); json_object_set_new(rootJ, "Slot3", json_string(storedPath[2].c_str())); @@ -172,13 +191,17 @@ struct DrumPlayerPlus : Module { } void dataFromJson(json_t *rootJ) override { - json_t* resamplingJ = json_object_get(rootJ, "Resampling"); - if (resamplingJ) - resamplingMode = json_integer_value(resamplingJ); + json_t* interpolationJ = json_object_get(rootJ, "Interpolation"); + if (interpolationJ) + interpolationMode = json_integer_value(interpolationJ); + + json_t* antiAliasJ = json_object_get(rootJ, "AntiAlias"); + if (antiAliasJ) + antiAlias = json_integer_value(antiAliasJ); - json_t* normalledOutsJ = json_object_get(rootJ, "NormalledOuts"); - if (normalledOutsJ) - normalledOuts = json_boolean_value(normalledOutsJ); + json_t* outsModeJ = json_object_get(rootJ, "OutsMode"); + if (outsModeJ) + outsMode = json_integer_value(outsModeJ); json_t *slot1J = json_object_get(rootJ, "Slot1"); if (slot1J) { @@ -201,10 +224,38 @@ struct DrumPlayerPlus : Module { loadSample(storedPath[3], 3); } } + + void calcBiquadLpf(double frequency, double samplerate, double Q) { + z1 = z2 = 0.0; + double Fc = frequency / samplerate; + double norm; + double K = tan(M_PI * Fc); + norm = 1 / (1 + K / Q + K * K); + a0 = K * K * norm; + a1 = 2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + } + + float biquadLpf(float in) { + double out = in * a0 + z1; + z1 = in * a1 + z2 - b1 * out; + z2 = in * a2 - b2 * out; + return out; + } - void loadSample(std::string path, int slot) { + /* + double hermiteInterpol(double x0, double x1, double x2, double x3, double t) { + double c0 = x1; + double c1 = .5F * (x2 - x0); + double c2 = x0 - (2.5F * x1) + (2 * x2) - (.5F * x3); + double c3 = (.5F * (x3 - x0)) + (1.5F * (x1 - x2)); + return (((((c3 * t) + c2) * t) + c1) * t) + c0; + } + */ - loading[slot] = true; + void loadSample(std::string path, int slot) { unsigned int c; unsigned int sr; drwav_uint64 tsc; @@ -212,152 +263,164 @@ struct DrumPlayerPlus : Module { pSampleData = drwav_open_and_read_file_f32(path.c_str(), &c, &sr, &tsc); if (pSampleData != NULL) { - channels[slot] = c; - sampleRate[slot] = sr; - playBuffer[slot].clear(); - for (unsigned int i=0; i < tsc; i = i + c) { - if (channels[slot] == 1) - playBuffer[slot].push_back(pSampleData[i]); - else if (channels[slot] == 2) - playBuffer[slot].push_back((pSampleData[i]+(float)pSampleData[i+1])/2); + //channels[slot] = c; + sampleRate[slot] = sr * 2; + calcBiquadLpf(20000.0, sampleRate[slot], 1); + playBuffer[slot][0].clear(); + playBuffer[slot][1].clear(); + for (unsigned int i = 0; i < tsc; i = i + c) { + playBuffer[slot][0].push_back(pSampleData[i]); + playBuffer[slot][0].push_back(0); } - totalSampleC[slot] = playBuffer[slot].size(); + totalSampleC[slot] = playBuffer[slot][0].size(); + totalSamples[slot] = totalSampleC[slot]-1; drwav_free(pSampleData); - loading[slot] = false; - fileLoaded[slot] = true; + for (unsigned int i = 1; i < totalSamples[slot]; i = i + 2) + playBuffer[slot][0][i] = playBuffer[slot][0][i-1] * .5f + playBuffer[slot][0][i+1] * .5f; + + playBuffer[slot][0][totalSamples[slot]] = playBuffer[slot][0][totalSamples[slot]-1] * .5f; // halve the last sample + + for (unsigned int i = 0; i < totalSampleC[slot]; i++) + playBuffer[slot][1].push_back(biquadLpf(playBuffer[slot][0][i])); + + sampleCoeff[slot] = sampleRate[slot] / (APP->engine->getSampleRate()); char* pathDup = strdup(path.c_str()); - fileDesc[slot] = basename(pathDup); - fileDisplay[slot] = fileDesc[slot].substr(0,5); + fileDescription[slot] = basename(pathDup); + fileDisplay[slot] = fileDescription[slot].substr(0,5); free(pathDup); storedPath[slot] = path; + + fileLoaded[slot] = true; + } else { fileLoaded[slot] = false; + storedPath[slot] = ""; + fileDescription[slot] = "--none--"; + fileDisplay[slot] = "-----"; } }; - void clearSlotFunct(int slot) { + void clearSlot(int slot) { storedPath[slot] = ""; - fileDesc[slot] = ""; - fileDisplay[slot] ="-----"; - loading[slot] = false; + fileDescription[slot] = "--none--"; + fileDisplay[slot] = "-----"; fileLoaded[slot] = false; - playBuffer[slot].clear(); + playBuffer[slot][0].clear(); + playBuffer[slot][1].clear(); totalSampleC[slot] = 0; } - + void process(const ProcessArgs &args) override { summedOutput = 0; - for (int i=0;i<4;i++){ - if (!fileLoaded[i]) - fileDesc[i] = "-----"; + for (int i = 0; i < 4; i++){ trigValue[i] = inputs[TRIG_INPUT+i].getVoltage(); if (trigValue[i] >= 1 && prevTrigValue[i] < 1){ if (play[i]) { fading[i] = true; - fadingValue[i] = 5.f; + fadingValue[i] = 1.f; fadedPosition[i] = samplePos[i]; } play[i] = true; - sampleCoeff[i] = sampleRate[i] / args.sampleRate; samplePos[i] = 0; currSampleWeight[i] = sampleCoeff[i]; prevSamplePos[i] = 0; prevSampleWeight[i] = 0; //debugDisplay = "X"; if (inputs[ACC_INPUT+i].getVoltage() > 1) - level[i] = params[ACCVOL_PARAM+i].getValue() + (inputs[ACCVOL_INPUT+i].getVoltage() * params[ACCVOLATNV_PARAM+i].getValue()); + level[i] = params[ACCVOL_PARAM+i].getValue() + (inputs[ACCVOL_INPUT+i].getVoltage() * params[ACCVOLATNV_PARAM+i].getValue() * 0.1); else - level[i] = params[TRIGVOL_PARAM+i].getValue() + (inputs[TRIGVOL_INPUT+i].getVoltage() * params[TRIGVOLATNV_PARAM+i].getValue()); + level[i] = params[TRIGVOL_PARAM+i].getValue() + (inputs[TRIGVOL_INPUT+i].getVoltage() * params[TRIGVOLATNV_PARAM+i].getValue() * 0.1); + + if (level[i] > 2) + level[i] = 2; + else if (level[i] < 0) + level[i] = 0; if (i < 3 && params[CHOKE_SWITCH+i].getValue()) { choking[i+1] = true; - chokeValue[i+1] = 0.9f; + chokeValue[i+1] = 1.f; } } prevTrigValue[i] = trigValue[i]; currentOutput = 0; - if (fileLoaded[i] && play[i] && floor(samplePos[i]) < totalSampleC[i] && floor(samplePos[i]) >= 0) { - switch (resamplingMode) { - case 0: - currentOutput = 5 * level[i] * playBuffer[i][floor(samplePos[i])]; + //if (fileLoaded[i] && play[i] && floor(samplePos[i]) < totalSampleC[i] && floor(samplePos[i]) >= 0) { + if (fileLoaded[i] && play[i] && floor(samplePos[i]) < totalSampleC[i]) { + switch (interpolationMode) { + case NO_INTERP: + currentOutput = 5 * level[i] * float(playBuffer[i][antiAlias][floor(samplePos[i])]); break; - case 1: - if (currSampleWeight[i] == 0.0) { - resampled[i] = playBuffer[i][floor(samplePos[i])]; + case LINEAR1_INTERP: + if (currSampleWeight[i] == 0) { + currentOutput = 5 * level[i] * float(playBuffer[i][antiAlias][floor(samplePos[i])]); } else { - sampleInterpol = 0; - sampleInterpCounter = 0; - avePostSample = 0; - for (int j=floor(prevSamplePos[i])+2;j 1 && floor(samplePos[i]) < totalSampleC[i] - 2) { - double a1 = .5F * (playBuffer[i][floor(samplePos[i])+1] - playBuffer[i][floor(samplePos[i])-1]); - double a2 = playBuffer[i][floor(samplePos[i])-1] - (2.5F * playBuffer[i][floor(samplePos[i])]) + (2 * playBuffer[i][floor(samplePos[i])+1]) - (.5F * playBuffer[i][floor(samplePos[i])+2]); - double a3 = (.5F * (playBuffer[i][floor(samplePos[i])+2] - playBuffer[i][floor(samplePos[i])-1])) + (1.5F * (playBuffer[i][floor(samplePos[i])] - playBuffer[i][floor(samplePos[i])+1])); - resampled[i] = (((((a3 * currSampleWeight[i]) + a2) * currSampleWeight[i]) + a1) * currSampleWeight[i]) + playBuffer[i][floor(samplePos[i])]; + if (floor(samplePos[i]) > 1 && floor(samplePos[i]) < totalSamples[i] - 1) { + /* + resampled[i] = hermiteInterpol(playBuffer[i][antiAlias][floor(samplePos[i])-1], + playBuffer[i][antiAlias][floor(samplePos[i])], + playBuffer[i][antiAlias][floor(samplePos[i])+1], + playBuffer[i][antiAlias][floor(samplePos[i])+2], + currSampleWeight[i]); + */ + // below is translation of the above function + double a1 = .5F * (playBuffer[i][antiAlias][floor(samplePos[i])+1] - playBuffer[i][antiAlias][floor(samplePos[i])-1]); + double a2 = playBuffer[i][antiAlias][floor(samplePos[i])-1] - (2.5F * playBuffer[i][antiAlias][floor(samplePos[i])]) + (2 * playBuffer[i][antiAlias][floor(samplePos[i])+1]) - (.5F * playBuffer[i][antiAlias][floor(samplePos[i])+2]); + double a3 = (.5F * (playBuffer[i][antiAlias][floor(samplePos[i])+2] - playBuffer[i][antiAlias][floor(samplePos[i])-1])) + (1.5F * (playBuffer[i][antiAlias][floor(samplePos[i])] - playBuffer[i][antiAlias][floor(samplePos[i])+1])); + currentOutput = 5 * level[i] * float( + (((((a3 * currSampleWeight[i]) + a2) * currSampleWeight[i]) + a1) * currSampleWeight[i]) + playBuffer[i][antiAlias][floor(samplePos[i])] + ); } else { - resampled[i] = playBuffer[i][floor(samplePos[i])]; + currentOutput = 5 * level[i] * float(playBuffer[i][antiAlias][floor(samplePos[i])]); } } - //if (i == 0) - // debugDisplay = to_string(sampleInterpCounter); - - currentOutput = 5 * level[i] * float(resampled[i]); break; } if (i > 0 && choking[i]) { - if (chokeValue[i] < 0.1) { + if (chokeValue[i] < 0.0) { choking[i] = false; play[i] = false; currentOutput = 0; } else { currentOutput *= chokeValue[i]; - chokeValue[i] -= 0.1; + chokeValue[i] -= fadeDecrement; } } prevSamplePos[i] = samplePos[i]; if (inputs[SPEED_INPUT+i].isConnected()) { - currentSpeed = double((params[SPEED_PARAM+i].getValue()+(inputs[SPEED_INPUT+i].getVoltage()*params[SPEEDATNV_PARAM+i].getValue()))); + currentSpeed = double(params[SPEED_PARAM+i].getValue() + (inputs[SPEED_INPUT+i].getVoltage() * params[SPEEDATNV_PARAM+i].getValue() * 0.1)); if (currentSpeed > 2) currentSpeed = 2; else { @@ -370,94 +433,117 @@ struct DrumPlayerPlus : Module { samplePos[i] += sampleCoeff[i]*currentSpeed; - if (resamplingMode > 0) { + if (interpolationMode > NO_INTERP) { prevSampleWeight[i] = currSampleWeight[i]; currSampleWeight[i] = samplePos[i] - floor(samplePos[i]); - //currSampleWeight[i] = modf(samplePos[i],&intSamplePos[i]); - //if (i ==0) - // debugDisplay = to_string(sampleInterpCounter); } - if (fading[i]) { + if (fading[i]) { // fades previous samples if retrigged when already playing if (fadingValue[i] > 0) { - fadingValue[i] -= 0.1; - currentOutput += playBuffer[i][floor(fadedPosition[i])] * fadingValue[i] * level[i]; + fadingValue[i] -= fadeDecrement; + currentOutput += (playBuffer[i][antiAlias][floor(fadedPosition[i])] * fadingValue[i] * level[i] * 5); fadedPosition[i] += sampleCoeff[i]*currentSpeed; - if (fadedPosition[i] > totalSampleC[i]) + if (fadedPosition[i] > totalSamples[i]) fading[i] = false; } else fading[i] = false; } - } else { choking[i] = false; play[i] = false; fading[i] = false; } - summedOutput += currentOutput; - + /* if (params[LIMIT_SWITCH+i].getValue()) { - if (summedOutput > 5) - summedOutput = 5; - else if (summedOutput < -5) - summedOutput = -5; - } - - if (outputs[OUT_OUTPUT+i].isConnected()) { - outputs[OUT_OUTPUT+i].setVoltage(summedOutput); - summedOutput = 0; + if (currentOutput > 5) + currentOutput = 5; + else if (currentOutput < -5) + currentOutput = -5; } + */ - if (!normalledOuts) - summedOutput = 0; + switch (outsMode) { + case NORMALLED_OUTS: + summedOutput += currentOutput; - if (!inputs[TRIG_INPUT+i].isConnected()) - play[i] = false; - } - } -}; - -struct DrumPlayerPlusDisplay : TransparentWidget { - DrumPlayerPlus *module; - int frame = 0; - - DrumPlayerPlusDisplay() { + if (params[LIMIT_SWITCH+i].getValue()) { + if (summedOutput > 5) + summedOutput = 5; + else if (summedOutput < -5) + summedOutput = -5; + } - } + if (outputs[OUT_OUTPUT+i].isConnected()) { + outputs[OUT_OUTPUT+i].setVoltage(summedOutput); + summedOutput = 0; + } + break; + + case SOLO_OUTS: + if (outputs[OUT_OUTPUT+i].isConnected()) { + + if (params[LIMIT_SWITCH+i].getValue()) { + if (currentOutput > 5) + currentOutput = 5; + else if (currentOutput < -5) + currentOutput = -5; + } + outputs[OUT_OUTPUT+i].setVoltage(currentOutput); - void drawLayer(const DrawArgs &args, int layer) override { - if (module) { - if (layer ==1) { - shared_ptr font = APP->window->loadFont(asset::system("res/fonts/DSEG7ClassicMini-BoldItalic.ttf")); - nvgFontSize(args.vg, 10); - nvgFontFaceId(args.vg, font->handle); - nvgTextLetterSpacing(args.vg, 0); - nvgFillColor(args.vg, nvgRGBA(0xdd, 0x33, 0x33, 0xff)); - nvgTextBox(args.vg, 6, 0,120, module->fileDisplay[0].c_str(), NULL); - nvgTextBox(args.vg, 75, 0,120, module->fileDisplay[1].c_str(), NULL); - nvgTextBox(args.vg, 144, 0,120, module->fileDisplay[2].c_str(), NULL); - nvgTextBox(args.vg, 214, 0,120, module->fileDisplay[3].c_str(), NULL); - //nvgTextBox(args.vg, 2, -20,120, module->debugDisplay.c_str(), NULL); + } + break; + + case UNCONNECTED_ON_4: + if (i == 3) { + summedOutput += currentOutput; + if (params[LIMIT_SWITCH+i].getValue()) { + if (summedOutput > 5) + summedOutput = 5; + else if (summedOutput < -5) + summedOutput = -5; + } + outputs[OUT_OUTPUT+i].setVoltage(summedOutput); + } else if (outputs[OUT_OUTPUT+i].isConnected()) { + if (params[LIMIT_SWITCH+i].getValue()) { + if (currentOutput > 5) + currentOutput = 5; + else if (currentOutput < -5) + currentOutput = -5; + } + outputs[OUT_OUTPUT+i].setVoltage(currentOutput); + } else { + summedOutput += currentOutput; + if (params[LIMIT_SWITCH+i].getValue()) { + if (summedOutput > 5) + summedOutput = 5; + else if (summedOutput < -5) + summedOutput = -5; + } + } + break; } + + if (!inputs[TRIG_INPUT+i].isConnected()) + play[i] = false; } - Widget::drawLayer(args, layer); } }; struct DrumPlayerPlusItem1 : MenuItem { DrumPlayerPlus *rm ; void onAction(const event::Action &e) override { - char *path = osdialog_file(OSDIALOG_OPEN, NULL, NULL, NULL); int i = 0; + rm->fileLoaded[i] = false; if (path) { - rm->play[i] = false; rm->loadSample(path, i); - rm->samplePos[i] = 0; rm->storedPath[i] = std::string(path); free(path); - } + } else if (rm->storedPath[i] == "") + rm->fileLoaded[i] = false; + else + rm->fileLoaded[i] = true; } }; @@ -466,13 +552,15 @@ struct DrumPlayerPlusItem2 : MenuItem { void onAction(const event::Action &e) override { char *path = osdialog_file(OSDIALOG_OPEN, NULL, NULL, NULL); int i = 1; + rm->fileLoaded[i] = false; if (path) { - rm->play[i] = false; rm->loadSample(path, i); - rm->samplePos[i] = 0; rm->storedPath[i] = std::string(path); free(path); - } + } else if (rm->storedPath[i] == "") + rm->fileLoaded[i] = false; + else + rm->fileLoaded[i] = true; } }; @@ -481,13 +569,15 @@ struct DrumPlayerPlusItem3 : MenuItem { void onAction(const event::Action &e) override { char *path = osdialog_file(OSDIALOG_OPEN, NULL, NULL, NULL); int i = 2; + rm->fileLoaded[i] = false; if (path) { - rm->play[i] = false; rm->loadSample(path, i); - rm->samplePos[i] = 0; rm->storedPath[i] = std::string(path); free(path); - } + } else if (rm->storedPath[i] == "") + rm->fileLoaded[i] = false; + else + rm->fileLoaded[i] = true; } }; @@ -496,14 +586,227 @@ struct DrumPlayerPlusItem4 : MenuItem { void onAction(const event::Action &e) override { char *path = osdialog_file(OSDIALOG_OPEN, NULL, NULL, NULL); int i = 3; + rm->fileLoaded[i] = false; if (path) { - rm->play[i] = false; rm->loadSample(path, i); - rm->samplePos[i] = 0; rm->storedPath[i] = std::string(path); free(path); + } else if (rm->storedPath[i] == "") + rm->fileLoaded[i] = false; + else + rm->fileLoaded[i] = true; + } +}; + + +struct dppSlot1Display : TransparentWidget { + DrumPlayerPlus *module; + int frame = 0; + + dppSlot1Display() { + + } + + struct ClearSlot1Item : MenuItem { + DrumPlayerPlus *module; + void onAction(const event::Action &e) override { + module->clearSlot(0); + //module->fileDescription[0] = "abcde"; + } + }; + + void onButton(const event::Button &e) override { + if (e.button == GLFW_MOUSE_BUTTON_LEFT && e.action == GLFW_PRESS) + e.consume(this); + + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { + createContextMenu(); + e.consume(this); + } + } + + void createContextMenu() { + DrumPlayerPlus *module = dynamic_cast(this->module); + assert(module); + + if (module) { + ui::Menu *menu = createMenu(); + + DrumPlayerPlusItem1 *rootDirItem = new DrumPlayerPlusItem1; + rootDirItem->text = "Load Sample Slot #1"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription[0])); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlot1Item::module, module)); + + } + } +}; + +struct dppSlot2Display : TransparentWidget { + DrumPlayerPlus *module; + int frame = 0; + + dppSlot2Display() { + + } + + struct ClearSlot2Item : MenuItem { + DrumPlayerPlus *module; + void onAction(const event::Action &e) override { + module->clearSlot(1); + } + }; + + void onButton(const event::Button &e) override { + if (e.button == GLFW_MOUSE_BUTTON_LEFT && e.action == GLFW_PRESS) + e.consume(this); + + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { + createContextMenu(); + e.consume(this); } } + + void createContextMenu() { + DrumPlayerPlus *module = dynamic_cast(this->module); + assert(module); + + if (module) { + ui::Menu *menu = createMenu(); + + DrumPlayerPlusItem2 *rootDirItem = new DrumPlayerPlusItem2; + rootDirItem->text = "Load Sample Slot #2"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription[1])); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlot2Item::module, module)); + + } + } +}; + +struct dppSlot3Display : TransparentWidget { + DrumPlayerPlus *module; + int frame = 0; + + dppSlot3Display() { + + } + + struct ClearSlot3Item : MenuItem { + DrumPlayerPlus *module; + void onAction(const event::Action &e) override { + module->clearSlot(2); + } + }; + + void onButton(const event::Button &e) override { + if (e.button == GLFW_MOUSE_BUTTON_LEFT && e.action == GLFW_PRESS) + e.consume(this); + + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { + createContextMenu(); + e.consume(this); + } + } + + void createContextMenu() { + DrumPlayerPlus *module = dynamic_cast(this->module); + assert(module); + + if (module) { + ui::Menu *menu = createMenu(); + + DrumPlayerPlusItem3 *rootDirItem = new DrumPlayerPlusItem3; + rootDirItem->text = "Load Sample Slot #3"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription[2])); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlot3Item::module, module)); + + } + } +}; + +struct dppSlot4Display : TransparentWidget { + DrumPlayerPlus *module; + int frame = 0; + + dppSlot4Display() { + + } + + struct ClearSlot4Item : MenuItem { + DrumPlayerPlus *module; + void onAction(const event::Action &e) override { + module->clearSlot(3); + } + }; + + void onButton(const event::Button &e) override { + if (e.button == GLFW_MOUSE_BUTTON_LEFT && e.action == GLFW_PRESS) + e.consume(this); + + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { + createContextMenu(); + e.consume(this); + } + } + + void createContextMenu() { + DrumPlayerPlus *module = dynamic_cast(this->module); + assert(module); + + if (module) { + ui::Menu *menu = createMenu(); + + DrumPlayerPlusItem4 *rootDirItem = new DrumPlayerPlusItem4; + rootDirItem->text = "Load Sample Slot #4"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription[3])); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlot4Item::module, module)); + + } + } + + +}; + +struct DrumPlayerPlusDisplay : TransparentWidget { + DrumPlayerPlus *module; + int frame = 0; + + DrumPlayerPlusDisplay() { + + } + + void drawLayer(const DrawArgs &args, int layer) override { + if (module) { + if (layer ==1) { + shared_ptr font = APP->window->loadFont(asset::system("res/fonts/DSEG7ClassicMini-BoldItalic.ttf")); + nvgFontSize(args.vg, 10); + nvgFontFaceId(args.vg, font->handle); + nvgTextLetterSpacing(args.vg, 0); + nvgFillColor(args.vg, nvgRGBA(0xdd, 0x33, 0x33, 0xff)); + nvgTextBox(args.vg, 6, 0,120, module->fileDisplay[0].c_str(), NULL); + nvgTextBox(args.vg, 75, 0,120, module->fileDisplay[1].c_str(), NULL); + nvgTextBox(args.vg, 144, 0,120, module->fileDisplay[2].c_str(), NULL); + nvgTextBox(args.vg, 214, 0,120, module->fileDisplay[3].c_str(), NULL); + //nvgTextBox(args.vg, 2, -20,120, module->debugDisplay.c_str(), NULL); + } + } + Widget::drawLayer(args, layer); + } }; @@ -517,26 +820,59 @@ struct DrumPlayerPlusWidget : ModuleWidget { addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + { + dppSlot1Display *display1 = new dppSlot1Display(); + display1->box.pos = Vec(12, 33); + display1->box.size = Vec(52, 14); + display1->module = module; + addChild(display1); + } + + { + dppSlot2Display *display2 = new dppSlot2Display(); + display2->box.pos = Vec(82, 33); + display2->box.size = Vec(52, 14); + display2->module = module; + addChild(display2); + } + + { + dppSlot3Display *display3 = new dppSlot3Display(); + display3->box.pos = Vec(151, 33); + display3->box.size = Vec(52, 14); + display3->module = module; + addChild(display3); + } + + { + dppSlot4Display *display4 = new dppSlot4Display(); + display4->box.pos = Vec(221, 33); + display4->box.size = Vec(52, 14); + display4->module = module; + addChild(display4); + } + { DrumPlayerPlusDisplay *display = new DrumPlayerPlusDisplay(); display->box.pos = Vec(13, 45); - display->box.size = Vec(5, 5); + display->box.size = Vec(270, 100); display->module = module; addChild(display); } - + + float xDelta = 23.5; - for (int i=0;i<4;i++) { + for (int i = 0; i < 4; i++) { addInput(createInputCentered(mm2px(Vec(7.9+(xDelta*i), 21)), module, DrumPlayerPlus::TRIG_INPUT+i)); addParam(createParamCentered(mm2px(Vec(17.9+(xDelta*i), 28.5)), module, DrumPlayerPlus::TRIGVOLATNV_PARAM+i)); - addParam(createParamCentered(mm2px(Vec(7.9+(xDelta*i), 33)), module, DrumPlayerPlus::TRIGVOL_PARAM+i)); - addInput(createInputCentered(mm2px(Vec(17.9+(xDelta*i), 36.5)), module, DrumPlayerPlus::TRIGVOL_INPUT+i)); + addParam(createParamCentered(mm2px(Vec(7.9+(xDelta*i), 32)), module, DrumPlayerPlus::TRIGVOL_PARAM+i)); + addInput(createInputCentered(mm2px(Vec(17.9+(xDelta*i), 37)), module, DrumPlayerPlus::TRIGVOL_INPUT+i)); addInput(createInputCentered(mm2px(Vec(7.9+(xDelta*i), 47)), module, DrumPlayerPlus::ACC_INPUT+i)); addParam(createParamCentered(mm2px(Vec(17.9+(xDelta*i), 54.5)), module, DrumPlayerPlus::ACCVOLATNV_PARAM+i)); - addParam(createParamCentered(mm2px(Vec(7.9+(xDelta*i), 59)), module, DrumPlayerPlus::ACCVOL_PARAM+i)); - addInput(createInputCentered(mm2px(Vec(17.9+(xDelta*i), 62.5)), module, DrumPlayerPlus::ACCVOL_INPUT+i)); + addParam(createParamCentered(mm2px(Vec(7.9+(xDelta*i), 58)), module, DrumPlayerPlus::ACCVOL_PARAM+i)); + addInput(createInputCentered(mm2px(Vec(17.9+(xDelta*i), 63)), module, DrumPlayerPlus::ACCVOL_INPUT+i)); addParam(createParamCentered(mm2px(Vec(12.9+(xDelta*i), 78.5)), module, DrumPlayerPlus::SPEED_PARAM+i)); addInput(createInputCentered(mm2px(Vec(7.9+(xDelta*i), 88)), module, DrumPlayerPlus::SPEED_INPUT+i)); @@ -549,7 +885,6 @@ struct DrumPlayerPlusWidget : ModuleWidget { addParam(createParamCentered(mm2px(Vec(5+7.9+(xDelta*i), 103.9)), module, DrumPlayerPlus::LIMIT_SWITCH+i)); } - addOutput(createOutputCentered(mm2px(Vec(17.9+(xDelta*i), 117)), module, DrumPlayerPlus::OUT_OUTPUT+i)); } } @@ -557,36 +892,36 @@ struct DrumPlayerPlusWidget : ModuleWidget { struct ClearSlotsItem : MenuItem { DrumPlayerPlus *module; void onAction(const event::Action &e) override { - for (int i=0;i<4;i++) - module->clearSlotFunct(i); + for (int i = 0; i < 4; i++) + module->clearSlot(i); } }; struct ClearSlot1Item : MenuItem { DrumPlayerPlus *module; void onAction(const event::Action &e) override { - module->clearSlotFunct(0); + module->clearSlot(0); } }; struct ClearSlot2Item : MenuItem { DrumPlayerPlus *module; void onAction(const event::Action &e) override { - module->clearSlotFunct(1); + module->clearSlot(1); } }; struct ClearSlot3Item : MenuItem { DrumPlayerPlus *module; void onAction(const event::Action &e) override { - module->clearSlotFunct(2); + module->clearSlot(2); } }; struct ClearSlot4Item : MenuItem { DrumPlayerPlus *module; void onAction(const event::Action &e) override { - module->clearSlotFunct(3); + module->clearSlot(3); } }; @@ -597,57 +932,74 @@ struct DrumPlayerPlusWidget : ModuleWidget { DrumPlayerPlusItem1 *rootDirItem1 = new DrumPlayerPlusItem1; menu->addChild(createMenuLabel("Sample Slots")); - rootDirItem1->text = std::to_string(1) + ": " + module->fileDesc[0]; + rootDirItem1->text = "1: " + module->fileDescription[0]; rootDirItem1->rm = module; menu->addChild(rootDirItem1); menu->addChild(construct(&MenuItem::rightText, "Clear #1", &ClearSlot1Item::module, module)); DrumPlayerPlusItem2 *rootDirItem2 = new DrumPlayerPlusItem2; - rootDirItem2->text = std::to_string(2) + ": " + module->fileDesc[1]; + rootDirItem2->text = "2: " + module->fileDescription[1]; rootDirItem2->rm = module; menu->addChild(rootDirItem2); menu->addChild(construct(&MenuItem::rightText, "Clear #2", &ClearSlot2Item::module, module)); DrumPlayerPlusItem3 *rootDirItem3 = new DrumPlayerPlusItem3; - rootDirItem3->text = std::to_string(3) + ": " + module->fileDesc[2]; + rootDirItem3->text = "3: " + module->fileDescription[2]; rootDirItem3->rm = module; menu->addChild(rootDirItem3); menu->addChild(construct(&MenuItem::rightText, "Clear #3", &ClearSlot3Item::module, module)); DrumPlayerPlusItem4 *rootDirItem4 = new DrumPlayerPlusItem4; - rootDirItem4->text = std::to_string(4) + ": " + module->fileDesc[3]; + rootDirItem4->text = "4: " + module->fileDescription[3]; rootDirItem4->rm = module; menu->addChild(rootDirItem4); menu->addChild(construct(&MenuItem::rightText, "Clear #4", &ClearSlot4Item::module, module)); - menu->addChild(new MenuSeparator()); - menu->addChild(construct(&MenuItem::text, "Clear ALL slots", &ClearSlotsItem::module, module)); - menu->addChild(new MenuSeparator()); + menu->addChild(new MenuSeparator()); + menu->addChild(construct(&MenuItem::text, "Clear ALL slots", &ClearSlotsItem::module, module)); + menu->addChild(new MenuSeparator()); - menu->addChild(createMenuLabel("Resampling Mode")); + menu->addChild(createMenuLabel("Interpolation")); struct ModeItem : MenuItem { DrumPlayerPlus* module; - int resamplingMode; + int interpolationMode; void onAction(const event::Action& e) override { - module->resamplingMode = resamplingMode; + module->interpolationMode = interpolationMode; } }; - - std::string modeNames[4] = {"No interpolation", "Linear 1", "Linear 2", "Hermite"}; + std::string modeNames[4] = {"None", "Linear 1", "Linear 2", "Hermite"}; for (int i = 0; i < 4; i++) { ModeItem* modeItem = createMenuItem(modeNames[i]); - modeItem->rightText = CHECKMARK(module->resamplingMode == i); + modeItem->rightText = CHECKMARK(module->interpolationMode == i); modeItem->module = module; - modeItem->resamplingMode = i; + modeItem->interpolationMode = i; menu->addChild(modeItem); } menu->addChild(new MenuSeparator()); - menu->addChild(createBoolPtrMenuItem("Normalled OUTs", "", &module->normalledOuts)); + menu->addChild(createBoolPtrMenuItem("Anti-aliasing filter", "", &module->antiAlias)); + + menu->addChild(new MenuSeparator()); + menu->addChild(createMenuLabel("Outs mode")); + struct OutsItem : MenuItem { + DrumPlayerPlus* module; + int outsMode; + void onAction(const event::Action& e) override { + module->outsMode = outsMode; + } + }; + std::string outsNames[3] = {"Normalled", "Solo", "Unconnected on out #4"}; + for (int i = 0; i < 3; i++) { + OutsItem* outsItem = createMenuItem(outsNames[i]); + outsItem->rightText = CHECKMARK(module->outsMode == i); + outsItem->module = module; + outsItem->outsMode = i; + menu->addChild(outsItem); + } } }; diff --git a/src/Drummer.cpp b/src/Drummer.cpp index 28e97a0..acfc4d5 100644 --- a/src/Drummer.cpp +++ b/src/Drummer.cpp @@ -34,15 +34,13 @@ struct Drummer : Module { float out[2] = {0.f,0.f}; float outFinal = 0.f; - float maxFadeSample[2] = {0.f,0.f}; - float currentFadeSample[2] = {0.f,0.f}; - float startFade[2] = {0.f,0.f}; - float lastFade[2] = {0.f,0.f}; + float fadeCoeff = 1000 / APP->engine->getSampleRate(); // 1ms choke + float currentFade[2] = {0.f,0.f}; Drummer() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); configSwitch(CHOKE_SWITCH, 0.f, 1.f, 0.f, "Mode", {"Off", "On"}); - configSwitch(LIMIT_SWITCH, 0.f, 1.f, 0.f, "Limit", {"Off", "5v"}); + configSwitch(LIMIT_SWITCH, 0.f, 1.f, 0.f, "Limit", {"Off", "±5v"}); configParam(ACCENT_PARAMS, 0.f, 2.f, 1.f, "Accent Level #1", "%", 0, 100); configParam(ACCENT_PARAMS+1, 0.f, 2.f, 1.f, "Accent Level #2", "%", 0, 100); configParam(NOACCENT_PARAMS, 0.f, 2.f, 1.f, "Standard Level #1", "%", 0, 100); @@ -62,6 +60,10 @@ struct Drummer : Module { outputs[OUT_OUTPUT+1].setVoltage(inputs[IN_INPUT+1].getVoltage()); } + void onSampleRateChange() override { + fadeCoeff = 1000 / APP->engine->getSampleRate(); // 1ms choke + } + void process(const ProcessArgs& args) override { chokeMode = params[CHOKE_SWITCH].getValue(); limitMode = params[LIMIT_SWITCH].getValue(); @@ -69,7 +71,7 @@ struct Drummer : Module { switch (chokeMode) { case 0: trigValue[0] = inputs[TRIG_INPUT].getVoltage(); - if (trigValue[0] >= 1 && prevTrigValue[0] < 1){ + if (trigValue[0] >= 1 && prevTrigValue[0] < 1) { if (inputs[ACCENT_INPUT].getVoltage() >= 1) sustain[0] = params[ACCENT_PARAMS].getValue(); else @@ -79,7 +81,7 @@ struct Drummer : Module { out[0] = inputs[IN_INPUT].getVoltage() * sustain[0]; trigValue[1] = inputs[TRIG_INPUT+1].getVoltage(); - if (trigValue[1] >= 1 && prevTrigValue[1] < 1){ + if (trigValue[1] >= 1 && prevTrigValue[1] < 1) { if (inputs[ACCENT_INPUT+1].getVoltage() >= 1) sustain[1] = params[ACCENT_PARAMS+1].getValue(); else @@ -91,12 +93,10 @@ struct Drummer : Module { case 1: trigValue[0] = inputs[TRIG_INPUT].getVoltage(); - if (trigValue[0] >= 1 && prevTrigValue[0] < 1){ + if (trigValue[0] >= 1 && prevTrigValue[0] < 1) { choking[0] = true; trigState[0] = true; - startFade[0] = 1; - maxFadeSample[0] = args.sampleRate * 0.05f; - currentFadeSample[0] = 0; + currentFade[0] = 1; if (inputs[ACCENT_INPUT].getVoltage() >= 1) sustain[0] = params[ACCENT_PARAMS].getValue(); @@ -106,20 +106,17 @@ struct Drummer : Module { prevTrigValue[0] = trigValue[0]; if (choking[1]) { - lastFade[0] = -(currentFadeSample[0] / maxFadeSample[0]) + startFade[0]; - if (lastFade[0] < 0) { + currentFade[0] -= fadeCoeff; + if (currentFade[0] < 0) { choking[1] = false; trigState[0] = false; - currentFadeSample[0] = 0; - startFade[0] = 0; - lastFade[0] = 0; + currentFade[0] = 0; } else { if (trigState[0]) - out[0] = inputs[IN_INPUT].getVoltage() * lastFade[0] * sustain[0]; + out[0] = inputs[IN_INPUT].getVoltage() * currentFade[0] * sustain[0]; else out[0] = 0; } - currentFadeSample[0]++; } else { if (trigState[0]) out[0] = inputs[IN_INPUT].getVoltage() * sustain[0]; @@ -128,12 +125,10 @@ struct Drummer : Module { } trigValue[1] = inputs[TRIG_INPUT+1].getVoltage(); - if (trigValue[1] >= 1 && prevTrigValue[1] < 1 && !choking[0]){ + if (trigValue[1] >= 1 && prevTrigValue[1] < 1 && !choking[0]) { choking[1] = true; trigState[1] = true; - startFade[1] = 1; - maxFadeSample[1] = args.sampleRate * 0.05f; - currentFadeSample[1] = 0; + currentFade[1] = 1; if (inputs[ACCENT_INPUT+1].getVoltage() >= 1) sustain[1] = params[ACCENT_PARAMS+1].getValue(); @@ -143,20 +138,17 @@ struct Drummer : Module { prevTrigValue[1] = trigValue[1]; if (choking[0]) { - lastFade[1] = -(currentFadeSample[1] / maxFadeSample[1]) + startFade[1]; - if (lastFade[1] < 0) { + currentFade[1] -= fadeCoeff; + if (currentFade[1] < 0) { choking[0] = false; trigState[1] = false; - currentFadeSample[1] = 0; - startFade[1] = 0; - lastFade[1] = 0; + currentFade[1] = 0; } else { if (trigState[1]) - out[1] = inputs[IN_INPUT+1].getVoltage() * lastFade[1] * sustain[1]; + out[1] = inputs[IN_INPUT+1].getVoltage() * currentFade[1] * sustain[1]; else out[1] = 0; } - currentFadeSample[1]++; } else { if (trigState[1]) out[1] = inputs[IN_INPUT+1].getVoltage() * sustain[1]; @@ -194,7 +186,6 @@ struct Drummer : Module { } }; - struct DrummerWidget : ModuleWidget { DrummerWidget(Drummer* module) { setModule(module); @@ -205,8 +196,8 @@ struct DrummerWidget : ModuleWidget { addChild(createWidget(Vec(0, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget(Vec(box.size.x - RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addInput(createInputCentered(mm2px(Vec(11.5, 18.8)), module, Drummer::TRIG_INPUT)); - addInput(createInputCentered(mm2px(Vec(11.5, 31.9)), module, Drummer::ACCENT_INPUT)); + addInput(createInputCentered(mm2px(Vec(11.5, 17.8)), module, Drummer::TRIG_INPUT)); + addInput(createInputCentered(mm2px(Vec(11.5, 31.3)), module, Drummer::ACCENT_INPUT)); addParam(createParamCentered(mm2px(Vec(25, 17.8)), module, Drummer::NOACCENT_PARAMS)); addParam(createParamCentered(mm2px(Vec(25, 31.3)), module, Drummer::ACCENT_PARAMS)); @@ -217,8 +208,8 @@ struct DrummerWidget : ModuleWidget { addParam(createParamCentered(mm2px(Vec(5.35, 67.45)), module, Drummer::CHOKE_SWITCH)); addParam(createParamCentered(mm2px(Vec(22.25, 67.45)), module, Drummer::LIMIT_SWITCH)); - addInput(createInputCentered(mm2px(Vec(11.5, 85.4)), module, Drummer::TRIG_INPUT+1)); - addInput(createInputCentered(mm2px(Vec(11.5, 98.5)), module, Drummer::ACCENT_INPUT+1)); + addInput(createInputCentered(mm2px(Vec(11.5, 84.4)), module, Drummer::TRIG_INPUT+1)); + addInput(createInputCentered(mm2px(Vec(11.5, 97.8)), module, Drummer::ACCENT_INPUT+1)); addParam(createParamCentered(mm2px(Vec(25, 84.4)), module, Drummer::NOACCENT_PARAMS+1)); addParam(createParamCentered(mm2px(Vec(25, 97.8)), module, Drummer::ACCENT_PARAMS+1)); @@ -226,7 +217,6 @@ struct DrummerWidget : ModuleWidget { addInput(createInputCentered(mm2px(Vec(9.5, 117)), module, Drummer::IN_INPUT+1)); addOutput(createOutputCentered(mm2px(Vec(26.5, 117)), module, Drummer::OUT_OUTPUT+1)); } - }; Model* modelDrummer = createModel("Drummer"); \ No newline at end of file diff --git a/src/Drummer4.cpp b/src/Drummer4.cpp index 0cfde43..c4cd17a 100644 --- a/src/Drummer4.cpp +++ b/src/Drummer4.cpp @@ -2,7 +2,8 @@ struct Drummer4 : Module { enum ParamId { - ENUMS(LIMIT_SWITCH,4), + ENUMS(CHOKE_PARAMS,3), + ENUMS(LIMIT_PARAMS,4), ENUMS(NOACCENT_PARAMS,4), ENUMS(ACCENT_PARAMS,4), PARAMS_LEN @@ -18,6 +19,8 @@ struct Drummer4 : Module { OUTPUTS_LEN }; enum LightId { + ENUMS(CHOKE_LIGHT,3), + ENUMS(LIMIT_LIGHT,4), LIGHTS_LEN }; @@ -25,16 +28,27 @@ struct Drummer4 : Module { float prevTrigValue[4] = {0.f, 0.f, 0.f, 0.f}; bool trigState[4] = {false, false, false, false}; + bool choke[3] = {false, false, false}; + bool choking[3] = {false, false, false}; + int limit[4]; + + float fadeCoeff = 1000 / APP->engine->getSampleRate(); // 1ms choke + float currentFade[3] = {0.f,0.f,0.f}; + float sustain[4] = {1.f, 1.f, 1.f, 1.f}; float out[4] = {0.f, 0.f, 0.f, 0.f}; + float outSum; Drummer4() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); - configSwitch(LIMIT_SWITCH, 0.f, 1.f, 0.f, "Limit #1", {"Off", "5v"}); - configSwitch(LIMIT_SWITCH+1, 0.f, 1.f, 0.f, "Limit #2", {"Off", "5v"}); - configSwitch(LIMIT_SWITCH+2, 0.f, 1.f, 0.f, "Limit #3", {"Off", "5v"}); - configSwitch(LIMIT_SWITCH+3, 0.f, 1.f, 0.f, "Limit #4", {"Off", "5v"}); + configSwitch(LIMIT_PARAMS, 0.f, 1.f, 0.f, "Limit #1", {"Off", "±5v"}); + configSwitch(LIMIT_PARAMS+1, 0.f, 1.f, 0.f, "Limit #2", {"Off", "±5v"}); + configSwitch(LIMIT_PARAMS+2, 0.f, 1.f, 0.f, "Limit #3", {"Off", "±5v"}); + configSwitch(LIMIT_PARAMS+3, 0.f, 1.f, 0.f, "Limit #4", {"Off", "±5v"}); + configSwitch(CHOKE_PARAMS, 0.f, 1.f, 0.f, "Choke #1", {"Off", "On"}); + configSwitch(CHOKE_PARAMS+1, 0.f, 1.f, 0.f, "Choke #2", {"Off", "On"}); + configSwitch(CHOKE_PARAMS+2, 0.f, 1.f, 0.f, "Choke #3", {"Off", "On"}); configParam(ACCENT_PARAMS, 0.f, 2.f, 1.f, "Accent Level #1", "%", 0, 100); configParam(ACCENT_PARAMS+1, 0.f, 2.f, 1.f, "Accent Level #2", "%", 0, 100); configParam(ACCENT_PARAMS+2, 0.f, 2.f, 1.f, "Accent Level #3", "%", 0, 100); @@ -68,94 +82,231 @@ struct Drummer4 : Module { outputs[OUT_OUTPUT+3].setVoltage(inputs[IN_INPUT+3].getVoltage()); } + void onSampleRateChange() override { + fadeCoeff = 1000 / APP->engine->getSampleRate(); // 1ms choke + } + void process(const ProcessArgs& args) override { - trigValue[0] = inputs[TRIG_INPUT].getVoltage(); - if (trigValue[0] >= 1 && prevTrigValue[0] < 1){ - if (inputs[ACCENT_INPUT].getVoltage() >= 1) - sustain[0] = params[ACCENT_PARAMS].getValue(); - else - sustain[0] = params[NOACCENT_PARAMS].getValue(); - } - prevTrigValue[0] = trigValue[0]; - out[0] = inputs[IN_INPUT].getVoltage() * sustain[0]; - - trigValue[1] = inputs[TRIG_INPUT+1].getVoltage(); - if (trigValue[1] >= 1 && prevTrigValue[1] < 1){ - if (inputs[ACCENT_INPUT+1].getVoltage() >= 1) - sustain[1] = params[ACCENT_PARAMS+1].getValue(); - else - sustain[1] = params[NOACCENT_PARAMS+1].getValue(); - } - prevTrigValue[1] = trigValue[1]; - out[1] = inputs[IN_INPUT+1].getVoltage() * sustain[1]; + choke[0] = params[CHOKE_PARAMS].getValue(); + choke[1] = params[CHOKE_PARAMS+1].getValue(); + choke[2] = params[CHOKE_PARAMS+2].getValue(); + lights[CHOKE_LIGHT].setBrightness(choke[0]); + lights[CHOKE_LIGHT+1].setBrightness(choke[1]); + lights[CHOKE_LIGHT+2].setBrightness(choke[2]); + limit[0] = params[LIMIT_PARAMS].getValue(); + limit[1] = params[LIMIT_PARAMS+1].getValue(); + limit[2] = params[LIMIT_PARAMS+2].getValue(); + limit[3] = params[LIMIT_PARAMS+3].getValue(); + lights[LIMIT_LIGHT].setBrightness(limit[0]); + lights[LIMIT_LIGHT+1].setBrightness(limit[1]); + lights[LIMIT_LIGHT+2].setBrightness(limit[2]); + lights[LIMIT_LIGHT+3].setBrightness(limit[3]); + + // -------- SLOT 1 -------- + + if (inputs[TRIG_INPUT].isConnected()) { + trigValue[0] = inputs[TRIG_INPUT].getVoltage(); + if (trigValue[0] >= 1 && prevTrigValue[0] < 1) { + trigState[0] = true; + if (inputs[ACCENT_INPUT].getVoltage() >= 1) + sustain[0] = params[ACCENT_PARAMS].getValue(); + else + sustain[0] = params[NOACCENT_PARAMS].getValue(); + + if (choke[0]) { + trigState[1] = false; + choking[0] = true; + currentFade[0] = 1; + } + } + prevTrigValue[0] = trigValue[0]; + out[0] = inputs[IN_INPUT].getVoltage() * sustain[0]; + } else + out[0] = 0; + + // -------- SLOT 2 -------- + if (inputs[TRIG_INPUT+1].isConnected()) { + trigValue[1] = inputs[TRIG_INPUT+1].getVoltage(); + if (trigValue[1] >= 1 && prevTrigValue[1] < 1) { + trigState[1] = true; + if (inputs[ACCENT_INPUT+1].getVoltage() >= 1) + sustain[1] = params[ACCENT_PARAMS+1].getValue(); + else + sustain[1] = params[NOACCENT_PARAMS+1].getValue(); + + if (choke[1]) { + choking[1] = true; + currentFade[1] = 1; + } + } + prevTrigValue[1] = trigValue[1]; + out[1] = inputs[IN_INPUT+1].getVoltage() * sustain[1]; + } else + out[1] = 0; + + // -------- SLOT 3 -------- + + if (inputs[TRIG_INPUT+2].isConnected()) { trigValue[2] = inputs[TRIG_INPUT+2].getVoltage(); - if (trigValue[2] >= 1 && prevTrigValue[2] < 1){ - if (inputs[ACCENT_INPUT+2].getVoltage() >= 1) - sustain[2] = params[ACCENT_PARAMS+2].getValue(); - else - sustain[2] = params[NOACCENT_PARAMS+2].getValue(); - } - prevTrigValue[2] = trigValue[2]; - out[2] = inputs[IN_INPUT+2].getVoltage() * sustain[2]; - - trigValue[3] = inputs[TRIG_INPUT+3].getVoltage(); - if (trigValue[3] >= 1 && prevTrigValue[3] < 1){ - if (inputs[ACCENT_INPUT+3].getVoltage() >= 1) - sustain[3] = params[ACCENT_PARAMS+3].getValue(); - else - sustain[3] = params[NOACCENT_PARAMS+3].getValue(); - } - prevTrigValue[3] = trigValue[3]; - out[3] = inputs[IN_INPUT+3].getVoltage() * sustain[3]; + if (trigValue[2] >= 1 && prevTrigValue[2] < 1) { + trigState[2] = true; + if (inputs[ACCENT_INPUT+2].getVoltage() >= 1) + sustain[2] = params[ACCENT_PARAMS+2].getValue(); + else + sustain[2] = params[NOACCENT_PARAMS+2].getValue(); + + if (choke[2]) { + choking[2] = true; + currentFade[2] = 1; + } + } + prevTrigValue[2] = trigValue[2]; + out[2] = inputs[IN_INPUT+2].getVoltage() * sustain[2]; + } else + out[2] = 0; - // -------------------------------------------------------- + // -------- SLOT 4 -------- - if (outputs[OUT_OUTPUT].isConnected()) { - if (params[LIMIT_SWITCH].getValue()) { - if (out[0] > 5) - out[0] = 5; - else if (out[0] < -5) - out[0] = -5; + if (inputs[TRIG_INPUT+3].isConnected()) { + trigValue[3] = inputs[TRIG_INPUT+3].getVoltage(); + if (trigValue[3] >= 1 && prevTrigValue[3] < 1) { + trigState[3] = true; + if (inputs[ACCENT_INPUT+3].getVoltage() >= 1) + sustain[3] = params[ACCENT_PARAMS+3].getValue(); + else + sustain[3] = params[NOACCENT_PARAMS+3].getValue(); } - outputs[OUT_OUTPUT].setVoltage(out[0]); + prevTrigValue[3] = trigValue[3]; + out[3] = inputs[IN_INPUT+3].getVoltage() * sustain[3]; + } else + out[3] = 0; + + // ------------------------------------------------------------ + + // -------- OUT 1 -------- + + outSum = out[0]; + + if (limit[0]) { + if (outSum > 5) + outSum = 5; + else if (outSum < -5) + outSum = -5; + } + + if (outputs[OUT_OUTPUT].isConnected()) { + outputs[OUT_OUTPUT].setVoltage(outSum); + outSum = 0; } else { - out[1] += out[0]; + outSum = out[0]; + } + + // -------- OUT 2 -------- + + if (choke[0]) { + if (choking[0]) { + currentFade[0] -= fadeCoeff; + if (currentFade[0] < 0) { + choking[0] = false; + if (inputs[TRIG_INPUT+1].isConnected()) + trigState[0] = false; + trigState[1] = false; + currentFade[0] = 0; + } else { + if (trigState[0] && trigState[1]) + out[1] *= currentFade[0]; + else + out[1] = 0; + } + } else { + if (!trigState[1]) + out[1] = 0; + } + } + + outSum += out[1]; + if (limit[1]) { + if (outSum > 5) + outSum = 5; + else if (outSum < -5) + outSum = -5; } if (outputs[OUT_OUTPUT+1].isConnected()) { - if (params[LIMIT_SWITCH+1].getValue()) { - if (out[1] > 5) - out[1] = 5; - else if (out[1] < -5) - out[1] = -5; + outputs[OUT_OUTPUT+1].setVoltage(outSum); + outSum = 0; + } + + // -------- OUT 3 -------- + + if (choke[1]) { + if (choking[1]) { + currentFade[1] -= fadeCoeff; + if (currentFade[1] < 0) { + choking[1] = false; + if (inputs[TRIG_INPUT+2].isConnected()) + trigState[1] = false; + trigState[2] = false; + currentFade[1] = 0; + } else { + if (trigState[1] && trigState[2]) + out[2] *= currentFade[1]; + else + out[2] = 0; + } + } else { + if (!trigState[2]) + out[2] = 0; } - outputs[OUT_OUTPUT+1].setVoltage(out[1]); - } else { - out[2] += out[1]; + } + + outSum += out[2]; + if (limit[2]) { + if (outSum > 5) + outSum = 5; + else if (outSum < -5) + outSum = -5; } if (outputs[OUT_OUTPUT+2].isConnected()) { - if (params[LIMIT_SWITCH+2].getValue()) { - if (out[2] > 5) - out[2] = 5; - else if (out[2] < -5) - out[2] = -5; + outputs[OUT_OUTPUT+2].setVoltage(outSum); + outSum = 0; + } + + // -------- OUT 4 -------- + + if (choke[2]) { + if (choking[2]) { + currentFade[2] -= fadeCoeff; + if (currentFade[2] < 0) { + choking[2] = false; + if (inputs[TRIG_INPUT+3].isConnected()) + trigState[2] = false; + trigState[3] = false; + currentFade[2] = 0; + } else { + if (trigState[2] && trigState[3]) + out[3] *= currentFade[2]; + else + out[3] = 0; + } + } else { + if (!trigState[3]) + out[3] = 0; } - outputs[OUT_OUTPUT+2].setVoltage(out[2]); - } else { - out[3] += out[2]; } if (outputs[OUT_OUTPUT+3].isConnected()) { - if (params[LIMIT_SWITCH+3].getValue()) { - if (out[3] > 5) - out[3] = 5; - else if (out[3] < -5) - out[3] = -5; + outSum += out[3]; + if (limit[3]) { + if (outSum > 5) + outSum = 5; + else if (outSum < -5) + outSum = -5; } - outputs[OUT_OUTPUT+3].setVoltage(out[3]); + outputs[OUT_OUTPUT+3].setVoltage(outSum); } else { outputs[OUT_OUTPUT+3].setVoltage(0); } @@ -175,17 +326,18 @@ struct Drummer4Widget : ModuleWidget { float x = 13.46; float xs = 7.75; - for (int i=0;i<4;i++) { + for (int i=0; i<4; i++) { addInput(createInputCentered(mm2px(Vec(xs+(x*i), 20)), module, Drummer4::TRIG_INPUT+i)); addParam(createParamCentered(mm2px(Vec(xs+(x*i), 32)), module, Drummer4::NOACCENT_PARAMS+i)); addInput(createInputCentered(mm2px(Vec(xs+(x*i), 49)), module, Drummer4::ACCENT_INPUT+i)); addParam(createParamCentered(mm2px(Vec(xs+(x*i), 61)), module, Drummer4::ACCENT_PARAMS+i)); addInput(createInputCentered(mm2px(Vec(xs+(x*i), 77)), module, Drummer4::IN_INPUT+i)); - addParam(createParamCentered(mm2px(Vec(xs+(x*i), 95)), module, Drummer4::LIMIT_SWITCH+i)); + if (i < 3) + addParam(createLightParamCentered>>(mm2px(Vec(xs+(x*i), 90.5)), module, Drummer4::CHOKE_PARAMS+i, Drummer4::CHOKE_LIGHT+i)); + addParam(createLightParamCentered>>(mm2px(Vec(xs+(x*i), 101.5)), module, Drummer4::LIMIT_PARAMS+i, Drummer4::LIMIT_LIGHT+i)); addOutput(createOutputCentered(mm2px(Vec(xs+(x*i), 115.5)), module, Drummer4::OUT_OUTPUT+i)); } } - }; Model* modelDrummer4 = createModel("Drummer4"); \ No newline at end of file diff --git a/src/Drummer4Plus.cpp b/src/Drummer4Plus.cpp new file mode 100644 index 0000000..315b723 --- /dev/null +++ b/src/Drummer4Plus.cpp @@ -0,0 +1,389 @@ +#include "plugin.hpp" + +struct Drummer4Plus : Module { + enum ParamId { + ENUMS(CHOKE_SWITCH,3), + ENUMS(LIMIT_SWITCH,4), + ENUMS(NOACCENTVOL_PARAMS,4), + ENUMS(NOACCENTVOLATNV_PARAMS,4), + ENUMS(ACCENTVOL_PARAMS,4), + ENUMS(ACCENTVOLATNV_PARAMS,4), + PARAMS_LEN + }; + enum InputId { + ENUMS(TRIG_INPUT,4), + ENUMS(NOACCENTVOL_INPUT,4), + ENUMS(ACCENT_INPUT,4), + ENUMS(ACCENTVOL_INPUT,4), + ENUMS(IN_INPUT,4), + INPUTS_LEN + }; + enum OutputId { + ENUMS(OUT_OUTPUT,4), + OUTPUTS_LEN + }; + enum LightId { + LIGHTS_LEN + }; + + float trigValue[4] = {0.f, 0.f, 0.f, 0.f}; + float prevTrigValue[4] = {0.f, 0.f, 0.f, 0.f}; + bool trigState[4] = {false, false, false, false}; + + bool choke[3] = {false, false, false}; + bool choking[3] = {false, false, false}; + int limit[4]; + + float fadeCoeff = 1000 / APP->engine->getSampleRate(); // 1ms choke + float currentFade[3] = {0.f,0.f,0.f}; + + float sustain[4] = {1.f, 1.f, 1.f, 1.f}; + + float out[4] = {0.f, 0.f, 0.f, 0.f}; + float outSum; + + Drummer4Plus() { + config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); + configSwitch(LIMIT_SWITCH, 0.f, 1.f, 0.f, "Limit #1", {"Off", "±5v"}); + configSwitch(LIMIT_SWITCH+1, 0.f, 1.f, 0.f, "Limit #2", {"Off", "±5v"}); + configSwitch(LIMIT_SWITCH+2, 0.f, 1.f, 0.f, "Limit #3", {"Off", "±5v"}); + configSwitch(LIMIT_SWITCH+3, 0.f, 1.f, 0.f, "Limit #4", {"Off", "±5v"}); + configSwitch(CHOKE_SWITCH, 0.f, 1.f, 0.f, "Choke #1", {"Off", "On"}); + configSwitch(CHOKE_SWITCH+1, 0.f, 1.f, 0.f, "Choke #2", {"Off", "On"}); + configSwitch(CHOKE_SWITCH+2, 0.f, 1.f, 0.f, "Choke #3", {"Off", "On"}); + + configInput(TRIG_INPUT, "Trigger #1"); + configInput(TRIG_INPUT+1, "Trigger #2"); + configInput(TRIG_INPUT+2, "Trigger #3"); + configInput(TRIG_INPUT+3, "Trigger #4"); + configParam(NOACCENTVOL_PARAMS, 0.f, 2.f, 1.f, "Standard Level #1", "%", 0, 100); + configParam(NOACCENTVOL_PARAMS+1, 0.f, 2.f, 1.f, "Standard Level #2", "%", 0, 100); + configParam(NOACCENTVOL_PARAMS+2, 0.f, 2.f, 1.f, "Standard Level #3", "%", 0, 100); + configParam(NOACCENTVOL_PARAMS+3, 0.f, 2.f, 1.f, "Standard Level #4", "%", 0, 100); + configParam(NOACCENTVOLATNV_PARAMS, -1.f, 1.0f, 0.f, "Stand.Lev.CV Attenuv. #1", "%", 0, 100); + configParam(NOACCENTVOLATNV_PARAMS+1, -1.f, 1.0f, 0.f, "Stand.Lev.CV Attenuv. #2", "%", 0, 100); + configParam(NOACCENTVOLATNV_PARAMS+2, -1.f, 1.0f, 0.f, "Stand.Lev.CV Attenuv. #3", "%", 0, 100); + configParam(NOACCENTVOLATNV_PARAMS+3, -1.f, 1.0f, 0.f, "Stand.Lev.CV Attenuv. #4", "%", 0, 100); + configInput(NOACCENTVOL_INPUT,"Stand.Lev.CV #1"); + configInput(NOACCENTVOL_INPUT+1,"Stand.Lev.CV #2"); + configInput(NOACCENTVOL_INPUT+2,"Stand.Lev.CV #3"); + configInput(NOACCENTVOL_INPUT+3,"Stand.Lev.CV #4"); + + configInput(ACCENT_INPUT, "Accent #1"); + configInput(ACCENT_INPUT+1, "Accent #2"); + configInput(ACCENT_INPUT+2, "Accent #3"); + configInput(ACCENT_INPUT+3, "Accent #4"); + configParam(ACCENTVOL_PARAMS, 0.f, 2.f, 1.f, "Accent Level #1", "%", 0, 100); + configParam(ACCENTVOL_PARAMS+1, 0.f, 2.f, 1.f, "Accent Level #2", "%", 0, 100); + configParam(ACCENTVOL_PARAMS+2, 0.f, 2.f, 1.f, "Accent Level #3", "%", 0, 100); + configParam(ACCENTVOL_PARAMS+3, 0.f, 2.f, 1.f, "Accent Level #4", "%", 0, 100); + configParam(ACCENTVOLATNV_PARAMS, -1.f, 1.0f, 0.f, "Accent.Lev.CV Attenuv. #1", "%", 0, 100); + configParam(ACCENTVOLATNV_PARAMS+1, -1.f, 1.0f, 0.f, "Accent.Lev.CV Attenuv. #2", "%", 0, 100); + configParam(ACCENTVOLATNV_PARAMS+2, -1.f, 1.0f, 0.f, "Accent.Lev.CV Attenuv. #3", "%", 0, 100); + configParam(ACCENTVOLATNV_PARAMS+3, -1.f, 1.0f, 0.f, "Accent.Lev.CV Attenuv. #4", "%", 0, 100); + configInput(ACCENTVOL_INPUT,"Accent.Lev.CV #1"); + configInput(ACCENTVOL_INPUT+1,"Accent.Lev.CV #2"); + configInput(ACCENTVOL_INPUT+2,"Accent.Lev.CV #3"); + configInput(ACCENTVOL_INPUT+3,"Accent.Lev.CV #4"); + + configInput(IN_INPUT, "AUDIO #1"); + configInput(IN_INPUT+1, "AUDIO #2"); + configInput(IN_INPUT+2, "AUDIO #3"); + configInput(IN_INPUT+3, "AUDIO #4"); + configOutput(OUT_OUTPUT, "AUDIO #1"); + configOutput(OUT_OUTPUT+1, "AUDIO #2"); + configOutput(OUT_OUTPUT+2, "AUDIO #3"); + configOutput(OUT_OUTPUT+3, "AUDIO #4"); + } + + void processBypass(const ProcessArgs& args) override { + outputs[OUT_OUTPUT].setVoltage(inputs[IN_INPUT].getVoltage()); + outputs[OUT_OUTPUT+1].setVoltage(inputs[IN_INPUT+1].getVoltage()); + outputs[OUT_OUTPUT+2].setVoltage(inputs[IN_INPUT+2].getVoltage()); + outputs[OUT_OUTPUT+3].setVoltage(inputs[IN_INPUT+3].getVoltage()); + } + + void onSampleRateChange() override { + fadeCoeff = 1000 / APP->engine->getSampleRate(); // 1ms choke + } + + void process(const ProcessArgs& args) override { + + choke[0] = params[CHOKE_SWITCH].getValue(); + choke[1] = params[CHOKE_SWITCH+1].getValue(); + choke[2] = params[CHOKE_SWITCH+2].getValue(); + limit[0] = params[LIMIT_SWITCH].getValue(); + limit[1] = params[LIMIT_SWITCH+1].getValue(); + limit[2] = params[LIMIT_SWITCH+2].getValue(); + limit[3] = params[LIMIT_SWITCH+3].getValue(); + + // -------- SLOT 1 -------- + if (inputs[TRIG_INPUT].isConnected()) { + trigValue[0] = inputs[TRIG_INPUT].getVoltage(); + if (trigValue[0] >= 1 && prevTrigValue[0] < 1) { + trigState[0] = true; + if (inputs[ACCENT_INPUT].getVoltage() >= 1) + sustain[0] = params[ACCENTVOL_PARAMS].getValue() + (inputs[ACCENTVOL_INPUT].getVoltage() * params[ACCENTVOLATNV_PARAMS].getValue() * 0.1); + else + sustain[0] = params[NOACCENTVOL_PARAMS].getValue() + (inputs[NOACCENTVOL_INPUT].getVoltage() * params[NOACCENTVOLATNV_PARAMS].getValue() * 0.1); + + if (sustain[0] > 2) + sustain[0] = 2; + else if (sustain[0] < 0) + sustain[0] = 0; + + if (choke[0]) { + trigState[1] = false; + choking[0] = true; + currentFade[0] = 1; + } + } + prevTrigValue[0] = trigValue[0]; + out[0] = inputs[IN_INPUT].getVoltage() * sustain[0]; + } else + out[0] = 0; + + // -------- SLOT 2 -------- + + if (inputs[TRIG_INPUT+1].isConnected()) { + trigValue[1] = inputs[TRIG_INPUT+1].getVoltage(); + if (trigValue[1] >= 1 && prevTrigValue[1] < 1) { + trigState[1] = true; + if (inputs[ACCENT_INPUT+1].getVoltage() >= 1) + sustain[1] = params[ACCENTVOL_PARAMS+1].getValue() + (inputs[ACCENTVOL_INPUT+1].getVoltage() * params[ACCENTVOLATNV_PARAMS+1].getValue() * 0.1); + else + sustain[1] = params[NOACCENTVOL_PARAMS+1].getValue() + (inputs[NOACCENTVOL_INPUT+1].getVoltage() * params[NOACCENTVOLATNV_PARAMS+1].getValue() * 0.1); + + if (sustain[1] > 2) + sustain[1] = 2; + else if (sustain[1] < 0) + sustain[1] = 0; + + if (choke[1]) { + choking[1] = true; + currentFade[1] = 1; + } + } + prevTrigValue[1] = trigValue[1]; + out[1] = inputs[IN_INPUT+1].getVoltage() * sustain[1]; + } else + out[1] = 0; + + // -------- SLOT 3 -------- + + if (inputs[TRIG_INPUT+2].isConnected()) { + trigValue[2] = inputs[TRIG_INPUT+2].getVoltage(); + if (trigValue[2] >= 1 && prevTrigValue[2] < 1) { + trigState[2] = true; + if (inputs[ACCENT_INPUT+2].getVoltage() >= 1) + sustain[2] = params[ACCENTVOL_PARAMS+2].getValue() + (inputs[ACCENTVOL_INPUT+2].getVoltage() * params[ACCENTVOLATNV_PARAMS+2].getValue() * 0.1); + else + sustain[2] = params[NOACCENTVOL_PARAMS+2].getValue() + (inputs[NOACCENTVOL_INPUT+2].getVoltage() * params[NOACCENTVOLATNV_PARAMS+2].getValue() * 0.1); + + if (sustain[2] > 2) + sustain[2] = 2; + else if (sustain[2] < 0) + sustain[2] = 0; + + if (choke[2]) { + choking[2] = true; + currentFade[2] = 1; + } + } + prevTrigValue[2] = trigValue[2]; + out[2] = inputs[IN_INPUT+2].getVoltage() * sustain[2]; + } else + out[2] = 0; + + // -------- SLOT 4 -------- + + if (inputs[TRIG_INPUT+3].isConnected()) { + trigValue[3] = inputs[TRIG_INPUT+3].getVoltage(); + if (trigValue[3] >= 1 && prevTrigValue[3] < 1) { + trigState[3] = true; + if (inputs[ACCENT_INPUT+3].getVoltage() >= 1) + sustain[3] = params[ACCENTVOL_PARAMS+3].getValue() + (inputs[ACCENTVOL_INPUT+3].getVoltage() * params[ACCENTVOLATNV_PARAMS+3].getValue() * 0.1); + else + sustain[3] = params[NOACCENTVOL_PARAMS+3].getValue() + (inputs[NOACCENTVOL_INPUT+3].getVoltage() * params[NOACCENTVOLATNV_PARAMS+3].getValue() * 0.1); + + if (sustain[3] > 2) + sustain[3] = 2; + else if (sustain[3] < 0) + sustain[3] = 0; + + } + prevTrigValue[3] = trigValue[3]; + out[3] = inputs[IN_INPUT+3].getVoltage() * sustain[3]; + } else + out[3] = 0; + + // -------------------------------------------------------- + + // -------- OUT 1 -------- + + outSum = out[0]; + + if (limit[0]) { + if (outSum > 5) + outSum = 5; + else if (outSum < -5) + outSum = -5; + } + + if (outputs[OUT_OUTPUT].isConnected()) { + outputs[OUT_OUTPUT].setVoltage(outSum); + outSum = 0; + } else { + outSum = out[0]; + } + + // -------- OUT 2 -------- + + if (choke[0]) { + if (choking[0]) { + currentFade[0] -= fadeCoeff; + if (currentFade[0] < 0) { + choking[0] = false; + if (inputs[TRIG_INPUT+1].isConnected()) + trigState[0] = false; + trigState[1] = false; + currentFade[0] = 0; + } else { + if (trigState[0] && trigState[1]) + out[1] *= currentFade[0]; + else + out[1] = 0; + } + } else { + if (!trigState[1]) + out[1] = 0; + } + } + + outSum += out[1]; + if (limit[1]) { + if (outSum > 5) + outSum = 5; + else if (outSum < -5) + outSum = -5; + } + + if (outputs[OUT_OUTPUT+1].isConnected()) { + outputs[OUT_OUTPUT+1].setVoltage(outSum); + outSum = 0; + } + + // -------- OUT 3 -------- + + if (choke[1]) { + if (choking[1]) { + currentFade[1] -= fadeCoeff; + if (currentFade[1] < 0) { + choking[1] = false; + if (inputs[TRIG_INPUT+2].isConnected()) + trigState[1] = false; + trigState[2] = false; + currentFade[1] = 0; + } else { + if (trigState[1] && trigState[2]) + out[2] *= currentFade[1]; + else + out[2] = 0; + } + } else { + if (!trigState[2]) + out[2] = 0; + } + } + + outSum += out[2]; + if (limit[2]) { + if (outSum > 5) + outSum = 5; + else if (outSum < -5) + outSum = -5; + } + + if (outputs[OUT_OUTPUT+2].isConnected()) { + outputs[OUT_OUTPUT+2].setVoltage(outSum); + outSum = 0; + } + + // -------- OUT 4 -------- + + if (choke[2]) { + if (choking[2]) { + currentFade[2] -= fadeCoeff; + if (currentFade[2] < 0) { + choking[2] = false; + if (inputs[TRIG_INPUT+3].isConnected()) + trigState[2] = false; + trigState[3] = false; + currentFade[2] = 0; + } else { + if (trigState[2] && trigState[3]) + out[3] *= currentFade[2]; + else + out[3] = 0; + } + } else { + if (!trigState[3]) + out[3] = 0; + } + } + + if (outputs[OUT_OUTPUT+3].isConnected()) { + outSum += out[3]; + if (limit[3]) { + if (outSum > 5) + outSum = 5; + else if (outSum < -5) + outSum = -5; + } + outputs[OUT_OUTPUT+3].setVoltage(outSum); + } else { + outputs[OUT_OUTPUT+3].setVoltage(0); + } + } +}; + +struct Drummer4PlusWidget : ModuleWidget { + Drummer4PlusWidget(Drummer4Plus* module) { + setModule(module); + setPanel(createPanel(asset::plugin(pluginInstance, "res/Drummer4Plus.svg"))); + + addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + float xDelta = 23.5; + + for (int i = 0; i < 4; i++) { + addInput(createInputCentered(mm2px(Vec(17.9+(xDelta*i), 15)), module, Drummer4Plus::TRIG_INPUT+i)); + + addParam(createParamCentered(mm2px(Vec(9.9+(xDelta*i), 25.5)), module, Drummer4Plus::NOACCENTVOL_PARAMS+i)); + addParam(createParamCentered(mm2px(Vec(18.4+(xDelta*i), 35.5)), module, Drummer4Plus::NOACCENTVOLATNV_PARAMS+i)); + addInput(createInputCentered(mm2px(Vec(9.9+(xDelta*i), 40)), module, Drummer4Plus::NOACCENTVOL_INPUT+i)); + + addInput(createInputCentered(mm2px(Vec(17.9+(xDelta*i), 51.5)), module, Drummer4Plus::ACCENT_INPUT+i)); + + addParam(createParamCentered(mm2px(Vec(9.9+(xDelta*i), 62)), module, Drummer4Plus::ACCENTVOL_PARAMS+i)); + addParam(createParamCentered(mm2px(Vec(18.4+(xDelta*i), 72)), module, Drummer4Plus::ACCENTVOLATNV_PARAMS+i)); + addInput(createInputCentered(mm2px(Vec(9.9+(xDelta*i), 76.5)), module, Drummer4Plus::ACCENTVOL_INPUT+i)); + + addInput(createInputCentered(mm2px(Vec(17.9+(xDelta*i), 87)), module, Drummer4Plus::IN_INPUT+i)); + + if (i<3) { + addParam(createParamCentered(mm2px(Vec(7.9+(xDelta*i), 103.9)), module, Drummer4Plus::LIMIT_SWITCH+i)); + addParam(createParamCentered(mm2px(Vec(17.9+(xDelta*i), 103.9)), module, Drummer4Plus::CHOKE_SWITCH+i)); + } else { + addParam(createParamCentered(mm2px(Vec(5+7.9+(xDelta*i), 103.9)), module, Drummer4Plus::LIMIT_SWITCH+i)); + } + + addOutput(createOutputCentered(mm2px(Vec(17.9+(xDelta*i), 117)), module, Drummer4Plus::OUT_OUTPUT+i)); + } + } +}; + +Model* modelDrummer4Plus = createModel("Drummer4Plus"); \ No newline at end of file diff --git a/src/Parking.cpp b/src/Parking.cpp index 373b32e..299f2a5 100644 --- a/src/Parking.cpp +++ b/src/Parking.cpp @@ -54,7 +54,6 @@ struct Parking : Module { } void process(const ProcessArgs& args) override { - } }; diff --git a/src/Shifter.cpp b/src/Shifter.cpp index 0051320..509230c 100644 --- a/src/Shifter.cpp +++ b/src/Shifter.cpp @@ -63,7 +63,7 @@ struct Shifter : Module { void onReset(const ResetEvent &e) override { initStart = false; currentStep = 1; - for (int i=0;i<65;i++) + for (int i=0; i<65; i++) registerValue[i] = 0.f; Module::onReset(e); } @@ -79,7 +79,7 @@ struct Shifter : Module { json_object_set_new(rootJ, "CurrentStep", json_integer(currentStep)); json_t *registerJ = json_array(); - for (int i=0;i<65;i++) + for (int i=0; i<65; i++) json_array_insert_new(registerJ, i, json_real(registerValue[i])); json_object_set_new(rootJ, "Register", registerJ); return rootJ; @@ -97,7 +97,7 @@ struct Shifter : Module { json_t *registerJ = json_object_get(rootJ, "Register"); if (registerJ) - for (int i=0;i<65;i++) { + for (int i=0; i<65; i++) { json_t *registerArrayJ = json_array_get(registerJ, i); if (registerArrayJ) registerValue[i] = json_number_value(registerArrayJ); @@ -153,7 +153,7 @@ struct Shifter : Module { currentStep++; - if (currentStep > regLength ) + if (currentStep > regLength) currentStep = 1; } else { @@ -209,8 +209,9 @@ struct ShifterWidget : ModuleWidget { addParam(createParamCentered(mm2px(Vec(7.62, 36.1)), module, Shifter::DELAY_PARAMS)); addParam(createParamCentered(mm2px(Vec(7.62, 63.3)), module, Shifter::STAGE_PARAMS)); - addInput(createInputCentered(mm2px(Vec(7.62, 76)), module, Shifter::STAGE_INPUT)); - addParam(createParamCentered(mm2px(Vec(7.62, 85.3)), module, Shifter::ATNV_PARAMS)); + addParam(createParamCentered(mm2px(Vec(7.62, 76)), module, Shifter::ATNV_PARAMS)); + addInput(createInputCentered(mm2px(Vec(7.62, 84.5)), module, Shifter::STAGE_INPUT)); + addInput(createInputCentered(mm2px(Vec(7.62, 100.8)), module, Shifter::IN_INPUT)); diff --git a/src/SickoPlayer.cpp b/src/SickoPlayer.cpp new file mode 100644 index 0000000..f3350e1 --- /dev/null +++ b/src/SickoPlayer.cpp @@ -0,0 +1,1611 @@ +#define LEFT 0 +#define RIGHT 1 +#define STOP_STAGE 0 +#define ATTACK_STAGE 1 +#define DECAY_STAGE 2 +#define SUSTAIN_STAGE 3 +#define RELEASE_STAGE 4 +#define GATE_MODE 0 +#define TRIG_MODE 1 +#define START_STOP 0 +#define START_ONLY 1 +#define PLAY_PAUSE 2 +#define NO_INTERP 0 +#define LINEAR1_INTERP 1 +#define LINEAR2_INTERP 2 +#define HERMITE_INTERP 3 +#define MONOPHONIC 0 +#define POLYPHONIC 1 + +#include "plugin.hpp" +#include "osdialog.h" +//#define DR_WAV_IMPLEMENTATION +#include "dr_wav.h" +#include +#include "cmath" +#include +#include + +using namespace std; + +struct SickoPlayer : Module { + enum ParamIds { + VOL_PARAM, + VOLATNV_PARAM, + TUNE_PARAM, + TUNEATNV_PARAM, + CUESTART_PARAM, + CUEEND_PARAM, + LOOPSTART_PARAM, + LOOPEND_PARAM, + ATTACK_PARAM, + ATTACKATNV_PARAM, + DECAY_PARAM, + DECAYATNV_PARAM, + SUSTAIN_PARAM, + SUSTAINATNV_PARAM, + RELEASE_PARAM, + RELEASEATNV_PARAM, + TRIGGATEMODE_SWITCH, + TRIGMODE_SWITCH, + LIMIT_SWITCH, + LOOP_PARAM, + REV_PARAM, + PINGPONG_PARAM, + NUM_PARAMS + }; + enum InputIds { + TRIG_INPUT, + STOP_INPUT, + VOL_INPUT, + TUNE_INPUT, + VO_INPUT, + LOOPSTART_INPUT, + LOOPEND_INPUT, + ATTACK_INPUT, + DECAY_INPUT, + SUSTAIN_INPUT, + RELEASE_INPUT, + NUM_INPUTS + }; + enum OutputIds { + ENUMS(OUT_OUTPUT,2), + EOC_OUTPUT, + EOR_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + LOOP_LIGHT, + REV_LIGHT, + PINGPONG_LIGHT, + NUM_LIGHTS + }; + + unsigned int channels; + unsigned int sampleRate; + drwav_uint64 totalSampleC; + drwav_uint64 totalSamples; + + vector playBuffer[2][2]; + vector displayBuff; + int currentDisplay = 0; + float voctDisplay = 100.f; + + bool fileLoaded = false; + + bool play[16] = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}; + bool inPause[16] = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}; + + double samplePos[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + double sampleCoeff; + double currentSpeed = 0.0; + double distancePos[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + double cueStartPos; + double cueEndPos; + double loopStartPos; + double loopEndPos; + + float knobCueStartPos; + float knobCueEndPos; + float prevKnobCueStartPos = -1.f; + float prevKnobCueEndPos = 2.f; + + float knobLoopStartPos; + float knobLoopEndPos; + float prevKnobLoopStartPos = -1.f; + float prevKnobLoopEndPos = 2.f; + + float knobTune = 0.f; + float prevKnobTune = 9.f; + float tune; + + float voct[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + float prevVoct[16] = {11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f, 11.f}; + float speedVoct[16]; + + bool searchingCueStartPhase = false; + bool searchingCueEndPhase = false; + double scanCueStartSample; + double scanCueEndSample; + + bool searchingLoopStartPhase = false; + bool searchingLoopEndPhase = false; + double scanLoopStartSample; + double scanLoopEndSample; + + //bool searchingRestartPhase = false; // used only for trig start/restart mode + + double prevSampleWeight[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + double currSampleWeight[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + double prevSamplePos[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + std::string storedPath = ""; + std::string fileDescription = "--none--"; + std::string fileDisplay = ""; + std::string fileInfoDisplay = ""; + + float trigValue[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + float prevTrigValue[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + float stopValue[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + float prevStopValue[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + bool loop = false; + + int interpolationMode = HERMITE_INTERP; + int antiAlias = 1; + int polyOuts = POLYPHONIC; + bool phaseScan = true; + + int xFade = 2; + float fadeCoeff[7] = {APP->engine->getSampleRate(), 2000.f, 1000.f, 200.f, 100.f, 50.f, 20.f}; // None, 0.5ms, 1ms, 5ms, 10ms, 20ms, 50ms fading + + bool fading[16] = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}; + float fadingValue[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + float fadeDecrement = fadeCoeff[xFade]/(APP->engine->getSampleRate()); + double fadedPosition[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + float currentOutput; + float currentOutputR; + float sumOutput; + float sumOutputR; + + //std::string debugDisplay = "X"; + //std::string debugDisplay2 = "X"; + //int debugInt = 0; + + double a0, a1, a2, b1, b2, z1, z2; + + int trigMode; + int trigType; + int stage[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + float stageLevel[16]; + float fadeStageLevel[16]; + float lastStageLevel[16]; + float currentStageSample[16]; + float maxStageSample[16]; + + bool eoc = false; + bool eor = false; + float eocTime; + float eorTime; + float eocEorTime = (APP->engine->getSampleRate())/fadeCoeff[1]; + + int chan; + + float attackValue; + float decayValue; + float sustainValue; + float releaseValue; + float level; + int limiter; + + int rev; + int pingpong; + + SickoPlayer() { + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + + configSwitch(TRIGGATEMODE_SWITCH, 0.f, 1.f, 1.f, "Mode", {"Gate", "Trig"}); + configSwitch(TRIGMODE_SWITCH, 0.f, 2.f, 0.f, "Trig mode", {"Start/Stop", "Start Only", "Play/Pause"}); + + configInput(TRIG_INPUT,"Trig/Gate"); + configInput(STOP_INPUT,"Stop"); + + //****************************************************************************** + + configParam(CUESTART_PARAM, 0.f, 1.0f, 0.f, "Cue Start", "%", 0, 100); + configParam(CUEEND_PARAM, 0.f, 1.0f, 1.f, "Cue End", "%", 0, 100); + + configParam(LOOPSTART_PARAM, 0.f, 1.0f, 0.f, "Loop Start", "%", 0, 100); + configParam(LOOPEND_PARAM, 0.f, 1.0f, 1.0f, "Loop End", "%", 0, 100); + + configSwitch(LOOP_PARAM, 0.f, 1.f, 0.f, "Loop", {"Off", "On"}); + + //****************************************************************************** + + configParam(ATTACK_PARAM, 0.0001f, 10.f, 0.0001f, "Attack", "ms", 0, 1000); + configInput(ATTACK_INPUT,"Attack CV"); + configParam(ATTACKATNV_PARAM, -1.0f, 1.0f, 0.0f, "Attack CV Attenuv."); + + configParam(DECAY_PARAM, 0.0001f, 10.f, 0.0001f, "Decay", "ms", 0, 1000); + configInput(DECAY_INPUT,"Decay CV"); + configParam(DECAYATNV_PARAM, -1.0f, 1.0f, 0.0f, "Decay CV Attenuv."); + + configParam(SUSTAIN_PARAM, 0.f, 1.0f, 1.0f, "Sustain","%", 0, 100); + configInput(SUSTAIN_INPUT,"Sustain CV"); + configParam(SUSTAINATNV_PARAM, -1.0f, 1.0f, 0.0f, "Sustain CV Attenuv."); + + configParam(RELEASE_PARAM, 0.0001f, 10.f, 0.0001f, "Release", "ms", 0, 1000); + configInput(RELEASE_INPUT,"Release CV"); + configParam(RELEASEATNV_PARAM, -1.0f, 1.0f, 0.0f, "Release CV Attenuv."); + + //****************************************************************************** + + configInput(VO_INPUT,"V/Oct"); + + configSwitch(REV_PARAM, 0.f, 1.f, 0.f, "Playback", {"Forward", "Reverse"}); + configSwitch(PINGPONG_PARAM, 0.f, 1.f, 0.f, "PingPong", {"Off", "On"}); + + configParam(TUNE_PARAM, -2.f, 2.f, 0.f, "Tune", " semitones", 0, 12); + configInput(TUNE_INPUT,"Tune CV"); + configParam(TUNEATNV_PARAM, -1.0f, 1.0f, 0.0f, "Tune CV Attenuv."); + + configParam(VOL_PARAM, 0.f, 2.0f, 1.0f, "Master Volume", "%", 0, 100); + configInput(VOL_INPUT,"Master Volume CV"); + configParam(VOLATNV_PARAM, -1.f, 1.0f, 0.f, "Master Volume CV Attenuv.", "%", 0, 100); + + configSwitch(LIMIT_SWITCH, 0.f, 1.f, 0.f, "Limit", {"Off", "±5v"}); + + //****************************************************************************** + + configOutput(OUT_OUTPUT,"Left"); + configOutput(OUT_OUTPUT+1,"Right"); + configOutput(EOC_OUTPUT,"End of Cycle"); + configOutput(EOR_OUTPUT,"End of Release"); + + playBuffer[0][0].resize(0); + playBuffer[0][1].resize(0); + playBuffer[1][0].resize(0); + playBuffer[1][1].resize(0); + } + + void onReset() override { + interpolationMode = HERMITE_INTERP; + antiAlias = 1; + polyOuts = POLYPHONIC; + xFade = 2; + phaseScan = true; + clearSlot(); + for (int i = 0; i < 16; i++) { + play[i] = false; + inPause[i] = false; + fading[i] = false; + stage[i] = STOP_STAGE; + stageLevel[i] = 0; + voct[i] = 0.f; + prevVoct[i] = 11.f; + } + prevKnobCueStartPos = -1.f; + prevKnobCueEndPos = 2.f; + prevKnobLoopStartPos = -1.f; + prevKnobLoopEndPos = 2.f; + prevKnobTune = -1.f; + } + + void onSampleRateChange() override { + if (fileLoaded) { + sampleCoeff = sampleRate / (APP->engine->getSampleRate()); // the % distance between samples at speed 1x + fadeDecrement = fadeCoeff[xFade]/(APP->engine->getSampleRate()); // volume decrement used to mix loop edges or when retriggered in 'play/restart' mode + eocEorTime = (APP->engine->getSampleRate())/fadeCoeff[1]; // number of samples for 1 ms used for output triggers + } + fadeCoeff[0] = APP->engine->getSampleRate(); + } + + json_t *dataToJson() override { + json_t *rootJ = json_object(); + json_object_set_new(rootJ, "Interpolation", json_integer(interpolationMode)); + json_object_set_new(rootJ, "AntiAlias", json_integer(antiAlias)); + json_object_set_new(rootJ, "xfade", json_integer(xFade)); + json_object_set_new(rootJ, "PolyOuts", json_integer(polyOuts)); + json_object_set_new(rootJ, "PhaseScan", json_boolean(phaseScan)); + json_object_set_new(rootJ, "Slot", json_string(storedPath.c_str())); + return rootJ; + } + + void dataFromJson(json_t *rootJ) override { + json_t* interpolationJ = json_object_get(rootJ, "Interpolation"); + if (interpolationJ) + interpolationMode = json_integer_value(interpolationJ); + + json_t* antiAliasJ = json_object_get(rootJ, "AntiAlias"); + if (antiAliasJ) + antiAlias = json_integer_value(antiAliasJ); + + json_t* xFadeJ = json_object_get(rootJ, "xfade"); + if (xFadeJ) + xFade = json_integer_value(xFadeJ); + + json_t* polyOutsJ = json_object_get(rootJ, "PolyOuts"); + if (polyOutsJ) + polyOuts = json_integer_value(polyOutsJ); + + json_t* phaseScanJ = json_object_get(rootJ, "PhaseScan"); + if (phaseScanJ) + phaseScan = json_boolean_value(phaseScanJ); + + json_t *slotJ = json_object_get(rootJ, "Slot"); + if (slotJ) { + storedPath = json_string_value(slotJ); + loadSample(storedPath); + } + } + + void calcBiquadLpf(double frequency, double samplerate, double Q) { + z1 = z2 = 0.0; + double Fc = frequency / samplerate; + double norm; + double K = tan(M_PI * Fc); + norm = 1 / (1 + K / Q + K * K); + a0 = K * K * norm; + a1 = 2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + } + + float biquadLpf(float in) { + double out = in * a0 + z1; + z1 = in * a1 + z2 - b1 * out; + z2 = in * a2 - b2 * out; + return out; + } + + /* + double hermiteInterpol(double x0, double x1, double x2, double x3, double t) { + double c0 = x1; + double c1 = .5F * (x2 - x0); + double c2 = x0 - (2.5F * x1) + (2 * x2) - (.5F * x3); + double c3 = (.5F * (x3 - x0)) + (1.5F * (x1 - x2)); + return (((((c3 * t) + c2) * t) + c1) * t) + c0; + } + */ + + void loadSample(std::string path) { + unsigned int c; + unsigned int sr; + drwav_uint64 tsc; + float* pSampleData; + pSampleData = drwav_open_and_read_file_f32(path.c_str(), &c, &sr, &tsc); + + if (pSampleData != NULL) { + channels = c; + sampleRate = sr * 2; + calcBiquadLpf(20000.0, sampleRate, 1); + playBuffer[LEFT][0].clear(); + playBuffer[LEFT][1].clear(); + playBuffer[RIGHT][0].clear(); + playBuffer[RIGHT][1].clear(); + displayBuff.clear(); + for (unsigned int i=0; i < tsc; i = i + c) { + playBuffer[LEFT][0].push_back(pSampleData[i]); + playBuffer[LEFT][0].push_back(0); + if (channels == 2) { + playBuffer[RIGHT][0].push_back(pSampleData[i+1]); + playBuffer[RIGHT][0].push_back(0); + } + } + totalSampleC = playBuffer[LEFT][0].size(); + totalSamples = totalSampleC-1; + drwav_free(pSampleData); + + for (unsigned int i = 1; i < totalSamples; i = i+2) { + playBuffer[LEFT][0][i] = playBuffer[LEFT][0][i-1] * .5f + playBuffer[LEFT][0][i+1] * .5f; + if (channels == 2) + playBuffer[RIGHT][0][i] = playBuffer[RIGHT][0][i-1] * .5f + playBuffer[RIGHT][0][i+1] * .5f; + } + + playBuffer[LEFT][0][totalSamples] = playBuffer[LEFT][0][totalSamples-1] * .5f; // halve the last sample + if (channels == 2) + playBuffer[RIGHT][0][totalSamples] = playBuffer[RIGHT][0][totalSamples-1] * .5f; + + for (unsigned int i = 0; i < totalSampleC; i++) { + playBuffer[LEFT][1].push_back(biquadLpf(playBuffer[LEFT][0][i])); + if (channels == 2) + playBuffer[RIGHT][1].push_back(biquadLpf(playBuffer[RIGHT][0][i])); + } + + sampleCoeff = sampleRate / (APP->engine->getSampleRate()); // the % distance between samples at speed 1x + + prevKnobCueStartPos = -1.f; + prevKnobCueEndPos = 2.f; + prevKnobLoopStartPos = -1.f; + prevKnobLoopEndPos = 2.f; + + vector().swap(displayBuff); + for (int i = 0; i < floor(totalSampleC); i = i + floor(totalSampleC/240)) + displayBuff.push_back(playBuffer[0][0][i]); + + char* pathDup = strdup(path.c_str()); + fileDescription = basename(pathDup); + fileDisplay = fileDescription.substr(0, fileDescription.size()-4); + fileDisplay = fileDisplay.substr(0, 20); + fileInfoDisplay = std::to_string(sampleRate/2) + "-" + std::to_string(channels) + "Ch"; + free(pathDup); + storedPath = path; + + fileLoaded = true; + } else { + fileLoaded = false; + storedPath = ""; + fileDescription = "--none--"; + fileDisplay = ""; + fileInfoDisplay = ""; + } + }; + + void clearSlot() { + storedPath = ""; + fileDescription = "--none--"; + fileDisplay = ""; + fileInfoDisplay = ""; + fileLoaded = false; + playBuffer[LEFT][0].clear(); + playBuffer[RIGHT][0].clear(); + playBuffer[LEFT][1].clear(); + playBuffer[RIGHT][1].clear(); + totalSampleC = 0; + totalSamples = 0; + + } + + void process(const ProcessArgs &args) override { + + rev = params[REV_PARAM].getValue(); + lights[REV_LIGHT].setBrightness(rev); + + pingpong = params[PINGPONG_PARAM].getValue(); + lights[PINGPONG_LIGHT].setBrightness(pingpong); + + loop = params[LOOP_PARAM].getValue(); + lights[LOOP_LIGHT].setBrightness(loop); + chan = std::max(1, inputs[VO_INPUT].getChannels()); + + if (!fileLoaded) { + + for (int c = 0; c < chan; c++) { + play[c] = false; + inPause[c] = false; + fading[c] = false; + stage[c] = STOP_STAGE; + stageLevel[c] = 0; + voct[c] = 0.f; + prevVoct[c] = 11.f; + outputs[OUT_OUTPUT].setVoltage(0, c); + outputs[OUT_OUTPUT+1].setVoltage(0, c); + } + + } else { + + knobCueStartPos = params[CUESTART_PARAM].getValue(); + if (knobCueStartPos != prevKnobCueStartPos) { + prevKnobCueStartPos = knobCueStartPos; + cueStartPos = floor(totalSampleC * knobCueStartPos); + searchingCueStartPhase = true; + scanCueStartSample = cueStartPos; + if (cueStartPos > cueEndPos) + cueStartPos = cueEndPos; + } + + knobCueEndPos = params[CUEEND_PARAM].getValue(); + if (knobCueEndPos != prevKnobCueEndPos) { + prevKnobCueEndPos = knobCueEndPos; + cueEndPos = floor(totalSampleC * knobCueEndPos); + searchingCueEndPhase = true; + scanCueEndSample = cueEndPos; + if (cueEndPos < cueStartPos) + cueEndPos = cueStartPos; + } + + knobLoopStartPos = params[LOOPSTART_PARAM].getValue(); + if (knobLoopStartPos != prevKnobLoopStartPos) { + prevKnobLoopStartPos = knobLoopStartPos; + loopStartPos = floor(totalSampleC * knobLoopStartPos); + searchingLoopStartPhase = true; + scanLoopStartSample = loopStartPos; + if (loopStartPos > loopEndPos) + loopStartPos = loopEndPos; + } + + knobLoopEndPos = params[LOOPEND_PARAM].getValue(); + if (knobLoopEndPos != prevKnobLoopEndPos) { + prevKnobLoopEndPos = knobLoopEndPos; + loopEndPos = floor(totalSampleC * knobLoopEndPos); + searchingLoopEndPhase = true; + scanLoopEndSample = loopEndPos; + if (loopEndPos < loopStartPos) + loopEndPos = loopStartPos; + } + + if (phaseScan) { + if (searchingLoopStartPhase) { + if (playBuffer[LEFT][antiAlias][scanLoopStartSample+1] >= 0 && playBuffer[LEFT][antiAlias][scanLoopStartSample] <= 0) { + loopStartPos = scanLoopStartSample+1; + searchingLoopStartPhase = false; + } else { + scanLoopStartSample++; + if (scanLoopStartSample > loopEndPos) + searchingLoopStartPhase = false; + } + } + + if (searchingLoopEndPhase) { + if (playBuffer[LEFT][antiAlias][scanLoopEndSample-1] <= 0 && playBuffer[LEFT][antiAlias][scanLoopEndSample] >= 0) { + loopEndPos = scanLoopEndSample-1; + searchingLoopEndPhase = false; + } else { + scanLoopEndSample--; + if (scanLoopEndSample < loopStartPos) + searchingLoopEndPhase = false; + } + } + + if (searchingCueStartPhase) { // ********* START/STOP EDGES PHASE SCAN ********* + if (playBuffer[LEFT][antiAlias][scanCueStartSample+1] >= 0 && playBuffer[LEFT][antiAlias][scanCueStartSample] < 0) { + cueStartPos = scanCueStartSample+1; + searchingCueStartPhase = false; + } else { + scanCueStartSample++; + if (scanCueStartSample > cueEndPos) { + cueStartPos = cueEndPos; + searchingCueStartPhase = false; + } + } + } + + if (searchingCueEndPhase) { + if (playBuffer[LEFT][antiAlias][scanCueEndSample-1] <= 0 && playBuffer[LEFT][antiAlias][scanCueEndSample] > 0) { + cueEndPos = scanCueEndSample-1; + searchingCueEndPhase = false; + } else { + scanCueEndSample--; + if (scanCueEndSample < cueStartPos) { + cueEndPos = cueStartPos; + searchingCueEndPhase = false; + } + } + } + } + + /* + if (searchingRestartPhase) { // *** *** on PLAY/RESTART trig mode this continues playing until phase is reached (attack value must be set to 0) + if (playBuffer[LEFT][antiAlias][floor(samplePos)-1] <= 0 && playBuffer[LEFT][antiAlias][floor(samplePos)] > 0) { + searchingRestartPhase = false; + fading = true; + fadingValue = 1.f; + fadedPosition = samplePos; + + samplePos = floor(cueStartPos+1); + currSampleWeight = sampleCoeff; + prevSamplePos = floor(cueStartPos); + prevSampleWeight = 0; + stage = ATTACK_STAGE; + currentStageSample = 0; + lastStageLevel = 0; + fadeStageLevel = stageLevel; + } + } + */ + + trigMode = params[TRIGGATEMODE_SWITCH].getValue(); + trigType = params[TRIGMODE_SWITCH].getValue(); + + attackValue = params[ATTACK_PARAM].getValue() + (inputs[ATTACK_INPUT].getVoltage() * params[ATTACKATNV_PARAM].getValue()); + + decayValue = params[DECAY_PARAM].getValue() + (inputs[DECAY_INPUT].getVoltage() * params[DECAYATNV_PARAM].getValue()); + + sustainValue = params[SUSTAIN_PARAM].getValue() + (inputs[SUSTAIN_INPUT].getVoltage() * params[SUSTAINATNV_PARAM].getValue() * 0.1); + if (sustainValue > 1) + sustainValue = 1; + else if (sustainValue < 0) + sustainValue = 0; + + releaseValue = params[RELEASE_PARAM].getValue() + (inputs[RELEASE_INPUT].getVoltage() * params[RELEASEATNV_PARAM].getValue()); + + level = params[VOL_PARAM].getValue() + (inputs[VOL_INPUT].getVoltage() * params[VOLATNV_PARAM].getValue() * 0.1); + if (level > 2) + level = 2; + else if (level < 0) + level = 0; + + limiter = params[LIMIT_SWITCH].getValue(); + + knobTune = params[TUNE_PARAM].getValue(); + if (knobTune != prevKnobTune) { + tune = powf(2,knobTune); + knobTune = prevKnobTune; + } + + if (inputs[TUNE_INPUT].isConnected()) { + currentSpeed = double(tune + (inputs[TUNE_INPUT].getVoltage() * params[TUNEATNV_PARAM].getValue() * 0.1)); + if (currentSpeed > 4) + currentSpeed = 4; + else if (currentSpeed < 0.25) + currentSpeed = 0.25; + } else { + currentSpeed = double(tune); + } + + sumOutput = 0; + sumOutputR = 0; + + // START CHANNEL MANAGEMENT + + voctDisplay = 100.f; + + for (int c = 0; c < chan; c++) { + + trigValue[c] = inputs[TRIG_INPUT].getVoltage(c); + + switch (trigMode) { + case GATE_MODE: // ***** GATE MODE ***** + if (trigValue[c] >= 1) { + if (!play[c]) { + play[c] = true; + if (rev) { + samplePos[c] = floor(cueEndPos-1); + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueEndPos); + prevSampleWeight[c] = 0; + } else { + samplePos[c] = floor(cueStartPos+1); + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueStartPos); + prevSampleWeight[c] = 0; + } + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 0; + } else { + if (stage[c] == RELEASE_STAGE) { + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = stageLevel[c]; + } + } + } else { + if (play[c]) { + if (stage[c] != RELEASE_STAGE) { + stage[c]=RELEASE_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 1-stageLevel[c]; + } + } + } + break; + + case TRIG_MODE: // ***** TRIG MODE ***** + if (trigValue[c] >= 1 && prevTrigValue[c] < 1){ + switch (trigType) { + case START_STOP: // trig type: Start/Stop + if (play[c]) { + if (stage[c] != RELEASE_STAGE) { + stage[c]=RELEASE_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 1-stageLevel[c]; + } else { + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = stageLevel[c]; + } + } else { + play[c] = true; + if (rev) { + samplePos[c] = floor(cueEndPos-1); + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueEndPos); + prevSampleWeight[c] = 0; + } else { + samplePos[c] = floor(cueStartPos+1); + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueStartPos); + prevSampleWeight[c] = 0; + } + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 0; + fadeStageLevel[c] = stageLevel[c]; + } + break; + + case START_ONLY: // trig type: START ONLY + if (!play[c]) { + play[c] = true; + if (rev) { + samplePos[c] = floor(cueEndPos-1); + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueEndPos); + prevSampleWeight[c] = 0; + } else { + samplePos[c] = floor(cueStartPos+1); + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueStartPos); + prevSampleWeight[c] = 0; + } + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 0; + fadeStageLevel[c] = stageLevel[c]; + } else if (stage[c] == RELEASE_STAGE) { + play[c] = true; + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = stageLevel[c]; + } + break; + + /* + case START_RESTART: // trig type: Start/Restart + if (play[c]) { + if (!searchingRestartPhase) + searchingRestartPhase = true; + //restartSample = samplePos; + //fading[c] = true; + //fadingValue[c] = 1.f; + //fadedPosition[c] = samplePos; + } else { + play[c] = true; + samplePos[c] = floor(cueStartPos+1); + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueStartPos); + prevSampleWeight[c] = 0; + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 0; + fadeStageLevel[c] = stageLevel[c]; + } + break; + */ + case PLAY_PAUSE: // trig type: Play/Pause + if (play[c]) { + if (stage[c] != RELEASE_STAGE) { + inPause[c] = true; + stage[c] = RELEASE_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 1-stageLevel[c]; + } else { + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = stageLevel[c]; + } + } else { + if (inPause[c]) { + play[c] = true; + inPause[c] = false; + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 0; + fadeStageLevel[c] = stageLevel[c]; + } else { + play[c] = true; + if (rev) { + samplePos[c] = floor(cueEndPos-1); + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueEndPos); + prevSampleWeight[c] = 0; + } else { + samplePos[c] = floor(cueStartPos+1); + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueStartPos); + prevSampleWeight[c] = 0; + } + stage[c] = ATTACK_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 0; + fadeStageLevel[c] = stageLevel[c]; + } + } + break; + } + } + prevTrigValue[c] = trigValue[c]; + break; + } + + currentOutput = 0; + currentOutputR = 0; + + if (fileLoaded && play[c]) { + if (inputs[VO_INPUT].isConnected()) { + voct[c] = inputs[VO_INPUT].getVoltage(c); + if (voct[c] != prevVoct[c]) { + speedVoct[c] = pow(2,voct[c]); + prevVoct[c] = voct[c]; + } + distancePos[c] = currentSpeed * sampleCoeff * speedVoct[c]; + } else + distancePos[c] = currentSpeed * sampleCoeff; + + if (play[c] && voct[c] < voctDisplay) { + currentDisplay = c; + voctDisplay = voct[c]; + } + + switch (rev) { + case 0: // FORWARD PLAYBACK + if (loop && samplePos[c] > floor(loopEndPos)) { // *** REACHED END OF LOOP *** + if (pingpong) { + rev = 1; + params[REV_PARAM].setValue(1); + samplePos[c] = floor(loopEndPos)-1; + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(loopEndPos); + prevSampleWeight[c] = 0; + } else { + fading[c] = true; + fadingValue[c] = 1.f; + fadedPosition[c] = samplePos[c]; + fadeStageLevel[c] = stageLevel[c]; + samplePos[c] = floor(loopStartPos)+1; + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(loopStartPos); + prevSampleWeight[c] = 0; + if (fadedPosition[c] > totalSamples) + fading[c] = false; + } + if (c == currentDisplay) { + eoc = true; + eocTime = eocEorTime; + } + } else if (floor(samplePos[c]) > totalSamples) { // *** REACHED END OF SAMPLE *** + play[c] = false; + inPause[c] = false; + if (c == currentDisplay) { + eoc = true; + eocTime = eocEorTime; + } + } else if (samplePos[c] > cueEndPos) { // *** REACHED CUE END *** + if (stage[c] != RELEASE_STAGE) { + stage[c] = RELEASE_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 1-stageLevel[c]; + } + if (trigMode == GATE_MODE) { + if (pingpong) { + rev = 1; + params[REV_PARAM].setValue(1); + samplePos[c] = floor(cueEndPos)-1; + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueEndPos); + prevSampleWeight[c] = 0; + } else { + fading[c] = true; + fadingValue[c] = 1.f; + fadedPosition[c] = samplePos[c]; + + samplePos[c] = floor(cueStartPos)+1; + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueStartPos); + prevSampleWeight[c] = 0; + } + } + if (c == currentDisplay) { + eoc = true; + eocTime = eocEorTime; + } + } + break; + + case 1: // REVERSE PLAYBACK + if (loop && samplePos[c] < floor(loopStartPos)) { // *** REACHED BEGIN OF LOOP *** + if (pingpong) { + rev = 0; + params[REV_PARAM].setValue(0); + samplePos[c] = floor(loopStartPos)+1; + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(loopStartPos); + prevSampleWeight[c] = 0; + } else { + fading[c] = true; + fadingValue[c] = 1.f; + fadedPosition[c] = samplePos[c]; + fadeStageLevel[c] = stageLevel[c]; + samplePos[c] = floor(loopEndPos)-1; + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(loopEndPos); + prevSampleWeight[c] = 0; + if (fadedPosition[c] < 0) + fading[c] = false; + } + if (c == currentDisplay) { + eoc = true; + eocTime = eocEorTime; + } + } else if (floor(samplePos[c]) < 0) { // *** REACHED START OF SAMPLE *** + play[c] = false; + inPause[c] = false; + if (c == currentDisplay) { + eoc = true; + eocTime = eocEorTime; + } + } else if (samplePos[c] < cueStartPos) { // *** REACHED CUE START *** + if (stage[c] != RELEASE_STAGE) { + stage[c] = RELEASE_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 1-stageLevel[c]; + } + if (trigMode == GATE_MODE) { + if (pingpong) { + rev = 0; + params[REV_PARAM].setValue(0); + samplePos[c] = floor(cueStartPos)+1; + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueStartPos); + prevSampleWeight[c] = 0; + } else { + fading[c] = true; + fadingValue[c] = 1.f; + fadedPosition[c] = samplePos[c]; + samplePos[c] = floor(cueEndPos)-1; + currSampleWeight[c] = sampleCoeff; + prevSamplePos[c] = floor(cueEndPos); + prevSampleWeight[c] = 0; + } + } + if (c == currentDisplay) { + eoc = true; + eocTime = eocEorTime; + } + } + break; + } + + if (play[c]) { // it's false only if end of sample has reached, see above + stopValue[c] = inputs[STOP_INPUT].getVoltage(c); + if (stopValue[c] >= 1 && prevStopValue[c] < 1 && trigMode) { + if (stage[c] != RELEASE_STAGE) { + stage[c] = RELEASE_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 1-stageLevel[c]; + } + if (c == currentDisplay) { + eoc = true; + eocTime = eocEorTime; + } + } + prevStopValue[c] = stopValue[c]; + + switch (interpolationMode) { + case NO_INTERP: + currentOutput = playBuffer[LEFT][antiAlias][floor(samplePos[c])]; + if (channels == 2) + currentOutputR = playBuffer[RIGHT][antiAlias][floor(samplePos[c])]; + break; + + case LINEAR1_INTERP: + if (currSampleWeight[c] == 0) { // if no distance between samples, it means that speed is 1 and samplerates match -> no interpolation + currentOutput = playBuffer[LEFT][antiAlias][floor(samplePos[c])]; + if (channels == 2) + currentOutputR = playBuffer[RIGHT][antiAlias][floor(samplePos[c])]; + } else { // weighted average of the actual previous and next sample to get the value of theoretical one + currentOutput = (playBuffer[LEFT][antiAlias][floor(samplePos[c])] * (1-currSampleWeight[c])) + + (playBuffer[LEFT][antiAlias][floor(samplePos[c])+1] * currSampleWeight[c]); + if (channels == 2) + currentOutputR = (playBuffer[RIGHT][antiAlias][floor(samplePos[c])] * (1-currSampleWeight[c])) + + (playBuffer[RIGHT][antiAlias][floor(samplePos[c])+1] * currSampleWeight[c]); + } + + break; + + case LINEAR2_INTERP: + if (currSampleWeight[c] == 0) { // if no distance between samples, it means that speed is 1 and samplerates match -> no interpolation + currentOutput = playBuffer[LEFT][antiAlias][floor(samplePos[c])]; + if (channels == 2) + currentOutputR = playBuffer[RIGHT][antiAlias][floor(samplePos[c])]; + } else { // average of the weighted average of previous played sample and the weighted average of the current sample + currentOutput = ( + (playBuffer[LEFT][antiAlias][floor(prevSamplePos[c])] * (1-prevSampleWeight[c])) + + (playBuffer[LEFT][antiAlias][floor(prevSamplePos[c])+1] * prevSampleWeight[c]) + + (playBuffer[LEFT][antiAlias][floor(samplePos[c])] * (1-currSampleWeight[c])) + + (playBuffer[LEFT][antiAlias][floor(samplePos[c])+1] * currSampleWeight[c]) + ) / 2; + if (channels == 2) + currentOutputR = ( + (playBuffer[RIGHT][antiAlias][floor(prevSamplePos[c])] * (1-prevSampleWeight[c])) + + (playBuffer[RIGHT][antiAlias][floor(prevSamplePos[c])+1] * prevSampleWeight[c]) + + (playBuffer[RIGHT][antiAlias][floor(samplePos[c])] * (1-currSampleWeight[c])) + + (playBuffer[RIGHT][antiAlias][floor(samplePos[c])+1] * currSampleWeight[c]) + ) / 2; + } + + break; + + case HERMITE_INTERP: + if (currSampleWeight[c] == 0) { // if no distance between samples, it means that speed is 1 and samplerates match -> no interpolation + currentOutput = playBuffer[LEFT][antiAlias][floor(samplePos[c])]; + if (channels == 2) + currentOutputR = playBuffer[RIGHT][antiAlias][floor(samplePos[c])]; + } else { + if (floor(samplePos[c]) > 0 && floor(samplePos[c]) < totalSamples - 1) { + /* + currentOutput = hermiteInterpol(playBuffer[i][antiAlias][floor(samplePos[i])-1], + playBuffer[i][antiAlias][floor(samplePos[i])], + playBuffer[i][antiAlias][floor(samplePos[i])+1], + playBuffer[i][antiAlias][floor(samplePos[i])+2], + currSampleWeight[i]); + */ + // below is translation of the above function + double a1 = .5F * (playBuffer[LEFT][antiAlias][floor(samplePos[c])+1] - playBuffer[LEFT][antiAlias][floor(samplePos[c])-1]); + double a2 = playBuffer[LEFT][antiAlias][floor(samplePos[c])-1] - (2.5F * playBuffer[LEFT][antiAlias][floor(samplePos[c])]) + (2 * playBuffer[LEFT][antiAlias][floor(samplePos[c])+1]) - (.5F * playBuffer[LEFT][antiAlias][floor(samplePos[c])+2]); + double a3 = (.5F * (playBuffer[LEFT][antiAlias][floor(samplePos[c])+2] - playBuffer[LEFT][antiAlias][floor(samplePos[c])-1])) + (1.5F * (playBuffer[LEFT][antiAlias][floor(samplePos[c])] - playBuffer[LEFT][antiAlias][floor(samplePos[c])+1])); + currentOutput = (((((a3 * currSampleWeight[c]) + a2) * currSampleWeight[c]) + a1) * currSampleWeight[c]) + playBuffer[LEFT][antiAlias][floor(samplePos[c])]; + if (channels == 2) { + a1 = .5F * (playBuffer[RIGHT][antiAlias][floor(samplePos[c])+1] - playBuffer[RIGHT][antiAlias][floor(samplePos[c])-1]); + a2 = playBuffer[RIGHT][antiAlias][floor(samplePos[c])-1] - (2.5F * playBuffer[RIGHT][antiAlias][floor(samplePos[c])]) + (2 * playBuffer[RIGHT][antiAlias][floor(samplePos[c])+1]) - (.5F * playBuffer[RIGHT][antiAlias][floor(samplePos[c])+2]); + a3 = (.5F * (playBuffer[RIGHT][antiAlias][floor(samplePos[c])+2] - playBuffer[RIGHT][antiAlias][floor(samplePos[c])-1])) + (1.5F * (playBuffer[RIGHT][antiAlias][floor(samplePos[c])] - playBuffer[RIGHT][antiAlias][floor(samplePos[c])+1])); + currentOutputR = (((((a3 * currSampleWeight[c]) + a2) * currSampleWeight[c]) + a1) * currSampleWeight[c]) + playBuffer[RIGHT][antiAlias][floor(samplePos[c])]; + } + + } else { // if playing sample is the first or one of the last 3 -> no interpolation + currentOutput = playBuffer[LEFT][antiAlias][floor(samplePos[c])]; + if (channels == 2) + currentOutputR = playBuffer[RIGHT][antiAlias][floor(samplePos[c])]; + } + } + break; + } + + prevSamplePos[c] = samplePos[c]; + + if (rev) + samplePos[c] -= distancePos[c]; + else + samplePos[c] += distancePos[c]; + + if (interpolationMode > NO_INTERP) { + prevSampleWeight[c] = currSampleWeight[c]; + currSampleWeight[c] = samplePos[c] - floor(samplePos[c]); + } + + switch (stage[c]) { + case ATTACK_STAGE: + if (attackValue > 10) { + attackValue = 10; + } else if (attackValue < 0.0001f) { + attackValue = 0.0001f; + } + maxStageSample[c] = args.sampleRate * attackValue; + stageLevel[c] = (currentStageSample[c] / maxStageSample[c]) + lastStageLevel[c]; + if (stageLevel[c] > 1) { + stageLevel[c] = 1; + stage[c] = DECAY_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 0; + } + currentStageSample[c]++; + break; + + case DECAY_STAGE: + if (decayValue > 10) { + decayValue = 10; + } else if (decayValue < 0.0001f) { + decayValue = 0.0001f; + } + maxStageSample[c] = args.sampleRate * decayValue / (1-sustainValue); + stageLevel[c] = 1-(currentStageSample[c] / maxStageSample[c]) + lastStageLevel[c]; + if (stageLevel[c] < sustainValue) { + stageLevel[c] = sustainValue; + stage[c] = SUSTAIN_STAGE; + currentStageSample[c] = 0; + lastStageLevel[c] = 0; + } + currentStageSample[c]++; + break; + + case SUSTAIN_STAGE: + if (sustainValue > 1) { + sustainValue = 1; + } else if (sustainValue < 0) { + sustainValue = 0; + } + stageLevel[c] = sustainValue; + break; + + case RELEASE_STAGE: + if (releaseValue > 10) { + releaseValue = 10; + } else if (releaseValue < 0.0001f) { + releaseValue = 0.0001f; + } + maxStageSample[c] = args.sampleRate * releaseValue; + stageLevel[c] = 1-(currentStageSample[c] / maxStageSample[c]) - lastStageLevel[c]; + if (stageLevel[c] < 0) { + stageLevel[c] = 0; + stage[c] = STOP_STAGE; + play[c] = false; + lastStageLevel[c] = 0; + if (c == currentDisplay) { + eor = true; + eorTime = eocEorTime; + } + if (trigType == PLAY_PAUSE) { + if (samplePos[c] > cueEndPos) { + inPause[c] = false; + } + } + } + currentStageSample[c]++; + break; + } + + currentOutput *= 5 * level * stageLevel[c]; + if (channels == 2) + currentOutputR *= 5 * level * stageLevel[c]; + + + if (fading[c]) { // *** fades previous samples on LOOPS *** + if (fadingValue[c] > 0) { + fadingValue[c] -= fadeDecrement; + currentOutput *= 1 - fadingValue[c]; // fade in incomping sample + currentOutput += (playBuffer[LEFT][antiAlias][floor(fadedPosition[c])] * fadingValue[c] * 5 * level * fadeStageLevel[c]); + //currentOutputR = (playBuffer[LEFT][antiAlias][floor(fadedPosition[c])] * fadingValue[c] * 5 * level * fadeStageLevel[c]); // **** FOR FADE DEBUG + + if (channels == 2) { + currentOutputR *= 1 - fadingValue[c]; + currentOutputR += (playBuffer[RIGHT][antiAlias][floor(fadedPosition[c])] * fadingValue[c] * 5 * level * fadeStageLevel[c]); + } + + if (rev) { + fadedPosition[c] -= distancePos[c]; + if (fadedPosition[c] < 0) + fading[c] = false; + } else { + fadedPosition[c] += distancePos[c]; + if (fadedPosition[c] > totalSamples) + fading[c] = false; + } + } else + fading[c] = false; + } + + } + + } else { + play[c] = false; + fading[c] = false; + } + + switch (polyOuts) { + case MONOPHONIC: // monophonic CABLES + sumOutput += currentOutput; + if (channels == 2) + sumOutputR += currentOutputR; + break; + + case POLYPHONIC: // polyphonic CABLES + if (limiter) { // *** hard clip functionality *** + if (currentOutput > 5) + currentOutput = 5; + else if (currentOutput < -5) + currentOutput = -5; + if (channels == 2) { + if (currentOutputR > 5) + currentOutputR = 5; + else if (currentOutputR < -5) + currentOutputR = -5; + } + } + + if (outputs[OUT_OUTPUT].isConnected()) { + outputs[OUT_OUTPUT].setVoltage(currentOutput, c); + //outputs[OUT_OUTPUT+1].setVoltage(currentOutputR); // ********** FOR FADE DEBUG + } + + if (outputs[OUT_OUTPUT+1].isConnected()) { + if (channels == 2) + outputs[OUT_OUTPUT+1].setVoltage(currentOutputR, c); + else + outputs[OUT_OUTPUT+1].setVoltage(currentOutput, c); + } + break; + } + + if (!inputs[TRIG_INPUT].isConnected()) { + play[c] = false; + inPause[c] = false; + fading[c] = false; + } + + } // END OF CHANNEL MANAGEMENT + + switch (polyOuts) { + case MONOPHONIC: // monophonic CABLES + if (limiter) { // *** hard clip functionality *** + if (sumOutput > 5) + sumOutput = 5; + else if (sumOutput < -5) + sumOutput = -5; + if (channels == 2) { + if (sumOutputR > 5) + sumOutputR = 5; + else if (sumOutputR < -5) + sumOutputR = -5; + } + } + if (outputs[OUT_OUTPUT].isConnected()) { + outputs[OUT_OUTPUT].setVoltage(sumOutput); + } + if (outputs[OUT_OUTPUT+1].isConnected()) { + if (channels == 2) + outputs[OUT_OUTPUT+1].setVoltage(sumOutputR); + else + outputs[OUT_OUTPUT+1].setVoltage(sumOutput); + } + + break; + + case POLYPHONIC: // polyphonic CABLES + outputs[OUT_OUTPUT].setChannels(chan); + outputs[OUT_OUTPUT+1].setChannels(chan); + break; + } + + if (eoc) { + eocTime--; + if (eocTime < 0) { + eoc = false; + outputs[EOC_OUTPUT].setVoltage(0.f); + } else + outputs[EOC_OUTPUT].setVoltage(10.f); + } + + if (eor) { + eorTime--; + if (eorTime < 0) { + eor = false; + outputs[EOR_OUTPUT].setVoltage(0.f); + } else + outputs[EOR_OUTPUT].setVoltage(10.f); + } + } + + } +}; + +struct SickoPlayerItem : MenuItem { + SickoPlayer *rm ; + void onAction(const event::Action &e) override { + rm->fileLoaded = false; + char *path = osdialog_file(OSDIALOG_OPEN, NULL, NULL, NULL); + if (path) { + rm->loadSample(path); + rm->storedPath = std::string(path); + } else { + rm->fileLoaded = true; + } + if (rm->storedPath == "") { + rm->fileLoaded = false; + } + free(path); + } +}; + +struct SickoPlayerDisplay : TransparentWidget { + SickoPlayer *module; + int frame = 0; + SickoPlayerDisplay() { + } + + struct ClearSlotItem : MenuItem { + SickoPlayer *module; + void onAction(const event::Action &e) override { + module->clearSlot(); + } + }; + + void onButton(const event::Button &e) override { + if (e.button == GLFW_MOUSE_BUTTON_LEFT && e.action == GLFW_PRESS) + e.consume(this); + + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { + createContextMenu(); + e.consume(this); + } + } + + void drawLayer(const DrawArgs &args, int layer) override { + if (module) { + if (layer ==1) { + shared_ptr font = APP->window->loadFont(asset::system("res/fonts/DSEG7ClassicMini-BoldItalic.ttf")); + nvgFontSize(args.vg, 10); + nvgFontFaceId(args.vg, font->handle); + nvgTextLetterSpacing(args.vg, 0); + nvgFillColor(args.vg, nvgRGBA(0xdd, 0x33, 0x33, 0xff)); + nvgTextBox(args.vg, 7, 16,247, module->fileDisplay.c_str(), NULL); + nvgTextBox(args.vg, 167, 16,97, module->fileInfoDisplay.c_str(), NULL); + //nvgTextBox(args.vg, 9, 26,120, module->debugDisplay.c_str(), NULL); + //nvgTextBox(args.vg, 109, 26,120, module->debugDisplay2.c_str(), NULL); + + // Zero line + nvgStrokeColor(args.vg, nvgRGBA(0xff, 0xff, 0xff, 0x40)); + { + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 7, 59.5); + nvgLineTo(args.vg, 242, 59.5); + nvgClosePath(args.vg); + } + nvgStroke(args.vg); + + if (module->fileLoaded) { + int xLine; + // Playback line + nvgStrokeColor(args.vg, nvgRGBA(0xf5, 0xf5, 0xf5, 0xff)); + nvgStrokeWidth(args.vg, 0.8); + { + nvgBeginPath(args.vg); + xLine = 7 + floor(module->samplePos[module->currentDisplay] * 235 / module->totalSampleC); + nvgMoveTo(args.vg, xLine, 21); + nvgLineTo(args.vg, xLine, 96); + nvgClosePath(args.vg); + } + nvgStroke(args.vg); + + + // Cue Start line + nvgStrokeColor(args.vg, nvgRGBA(0x00, 0xf0, 0x00, 0xf0)); + nvgStrokeWidth(args.vg, 1); + { + nvgBeginPath(args.vg); + xLine = 7 + floor(module->cueStartPos * 235 / module->totalSampleC); + nvgMoveTo(args.vg, xLine , 21); + nvgLineTo(args.vg, xLine , 96); + nvgClosePath(args.vg); + } + nvgStroke(args.vg); + + // Cue End line + nvgStrokeColor(args.vg, nvgRGBA(0xf0, 0x00, 0x00, 0xf0)); + nvgStrokeWidth(args.vg, 1); + { + nvgBeginPath(args.vg); + xLine = 7 + floor(module->cueEndPos * 235 / module->totalSampleC); + nvgMoveTo(args.vg, xLine , 21); + nvgLineTo(args.vg, xLine , 96); + nvgClosePath(args.vg); + } + nvgStroke(args.vg); + + // Loop Start line + nvgStrokeColor(args.vg, nvgRGBA(0xf8, 0xec, 0x2e, 0xf0)); + nvgStrokeWidth(args.vg, 1); + { + nvgBeginPath(args.vg); + xLine = 7 + floor(module->loopStartPos * 235 / module->totalSampleC); + nvgMoveTo(args.vg, xLine , 21); + nvgLineTo(args.vg, xLine , 96); + nvgClosePath(args.vg); + } + nvgStroke(args.vg); + + // Loop End line + nvgStrokeColor(args.vg, nvgRGBA(0xea, 0x79, 0x26, 0xf0)); + nvgStrokeWidth(args.vg, 1); + { + nvgBeginPath(args.vg); + xLine = 7 + floor(module->loopEndPos * 235 / module->totalSampleC); + nvgMoveTo(args.vg, xLine , 21); + nvgLineTo(args.vg, xLine , 96); + nvgClosePath(args.vg); + } + nvgStroke(args.vg); + + // Waveform + nvgStrokeColor(args.vg, nvgRGBA(0x22, 0x44, 0xc9, 0xc0)); + nvgSave(args.vg); + Rect b = Rect(Vec(7, 22), Vec(235, 73)); + nvgScissor(args.vg, b.pos.x, b.pos.y, b.size.x, b.size.y); + nvgBeginPath(args.vg); + for (unsigned int i = 0; i < module->displayBuff.size(); i++) { + float x, y; + x = (float)i / (module->displayBuff.size() - 1); + y = module->displayBuff[i] / 2.0 + 0.5; + Vec p; + p.x = b.pos.x + b.size.x * x; + p.y = b.pos.y + b.size.y * (1.0 - y); + if (i == 0) + nvgMoveTo(args.vg, p.x, p.y); + else + nvgLineTo(args.vg, p.x, p.y); + } + nvgLineCap(args.vg, NVG_ROUND); + nvgMiterLimit(args.vg, 2.0); + nvgStrokeWidth(args.vg, 1.5); + nvgGlobalCompositeOperation(args.vg, NVG_LIGHTER); + nvgStroke(args.vg); + nvgResetScissor(args.vg); + nvgRestore(args.vg); + } + } + } + Widget::drawLayer(args, layer); + } + + void createContextMenu() { + SickoPlayer *module = dynamic_cast(this->module); + assert(module); + + if (module) { + ui::Menu *menu = createMenu(); + + + SickoPlayerItem *rootDirItem = new SickoPlayerItem; + rootDirItem->text = "Load Sample"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription)); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlotItem::module, module)); + + } + } +}; + +struct SickoPlayerWidget : ModuleWidget { + SickoPlayerWidget(SickoPlayer *module) { + setModule(module); + setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/SickoPlayer.svg"))); + + addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + { + SickoPlayerDisplay *display = new SickoPlayerDisplay(); + display->box.pos = Vec(3, 24); + display->box.size = Vec(247, 100); + display->module = module; + addChild(display); + } + + float xTrig1 = 12; + float xTrig2 = 31; + float yTrig1 = 50; + float yTrig2 = 64; + float xStart1 = 58; + float xStart2 = 70; + float yStart1 = 54; + float yStart2 = 64; + + float xEnv1 = 11.5f; + float xEnv1Add = 21.f; + float xEnv2 = 6.5f; + float xEnv2Add = 10.f; + float xEnv2Skip = 21.f; + float yEnv1 = 81.f; + float yEnv2 = 90.f; + + float yTunVol = 108; + float yTunVol2 = 117.5; + + addParam(createParamCentered(mm2px(Vec(xTrig1, yTrig1)), module, SickoPlayer::TRIGGATEMODE_SWITCH)); + addParam(createParamCentered(mm2px(Vec(xTrig2, yTrig1+1)), module, SickoPlayer::TRIGMODE_SWITCH)); + + addInput(createInputCentered(mm2px(Vec(xTrig1, yTrig2)), module, SickoPlayer::TRIG_INPUT)); + addInput(createInputCentered(mm2px(Vec(xTrig2, yTrig2)), module, SickoPlayer::STOP_INPUT)); + //---------------------------------------------------------------------------------------------------------------------------- + + addParam(createParamCentered(mm2px(Vec(xStart1, yStart1)), module, SickoPlayer::CUESTART_PARAM)); + addParam(createParamCentered(mm2px(Vec(xStart2, yStart1)), module, SickoPlayer::CUEEND_PARAM)); + + addParam(createParamCentered(mm2px(Vec(xStart1, yStart2)), module, SickoPlayer::LOOPSTART_PARAM)); + addParam(createParamCentered(mm2px(Vec(xStart2, yStart2)), module, SickoPlayer::LOOPEND_PARAM)); + + addParam(createLightParamCentered>>(mm2px(Vec(xStart2+9.5, yStart1+0.5)), module, SickoPlayer::PINGPONG_PARAM, SickoPlayer::PINGPONG_LIGHT)); + addParam(createLightParamCentered>>(mm2px(Vec(xStart2+9.5, yStart2-2)), module, SickoPlayer::LOOP_PARAM, SickoPlayer::LOOP_LIGHT)); + //---------------------------------------------------------------------------------------------------------------------------- + + addParam(createParamCentered(mm2px(Vec(xEnv1, yEnv1)), module, SickoPlayer::ATTACK_PARAM)); + addInput(createInputCentered(mm2px(Vec(xEnv2, yEnv2)), module, SickoPlayer::ATTACK_INPUT)); + addParam(createParamCentered(mm2px(Vec(xEnv2+xEnv2Add, yEnv2)), module, SickoPlayer::ATTACKATNV_PARAM)); + + addParam(createParamCentered(mm2px(Vec(xEnv1+xEnv1Add, yEnv1)), module, SickoPlayer::DECAY_PARAM)); + addInput(createInputCentered(mm2px(Vec(xEnv2+xEnv2Skip, yEnv2)), module, SickoPlayer::DECAY_INPUT)); + addParam(createParamCentered(mm2px(Vec(xEnv2+xEnv2Add+xEnv2Skip, yEnv2)), module, SickoPlayer::DECAYATNV_PARAM)); + + addParam(createParamCentered(mm2px(Vec(xEnv1+xEnv1Add*2, yEnv1)), module, SickoPlayer::SUSTAIN_PARAM)); + addInput(createInputCentered(mm2px(Vec(xEnv2+xEnv2Skip*2, yEnv2)), module, SickoPlayer::SUSTAIN_INPUT)); + addParam(createParamCentered(mm2px(Vec(xEnv2+xEnv2Add+xEnv2Skip*2, yEnv2)), module, SickoPlayer::SUSTAINATNV_PARAM)); + + addParam(createParamCentered(mm2px(Vec(xEnv1+xEnv1Add*3, yEnv1)), module, SickoPlayer::RELEASE_PARAM)); + addInput(createInputCentered(mm2px(Vec(xEnv2+xEnv2Skip*3, yEnv2)), module, SickoPlayer::RELEASE_INPUT)); + addParam(createParamCentered(mm2px(Vec(xEnv2+xEnv2Add+xEnv2Skip*3, yEnv2)), module, SickoPlayer::RELEASEATNV_PARAM)); + //---------------------------------------------------------------------------------------------------------------------------- + + addInput(createInputCentered(mm2px(Vec(9, 105.3)), module, SickoPlayer::VO_INPUT)); + + addParam(createLightParamCentered>>(mm2px(Vec(9, yTunVol2)), module, SickoPlayer::REV_PARAM, SickoPlayer::REV_LIGHT)); + + addParam(createParamCentered(mm2px(Vec(23.5, yTunVol)), module, SickoPlayer::TUNE_PARAM)); + addInput(createInputCentered(mm2px(Vec(18.5, yTunVol2)), module, SickoPlayer::TUNE_INPUT)); + addParam(createParamCentered(mm2px(Vec(28.5, yTunVol2)), module, SickoPlayer::TUNEATNV_PARAM)); + + addParam(createParamCentered(mm2px(Vec(45.5, yTunVol)), module, SickoPlayer::VOL_PARAM)); + addInput(createInputCentered(mm2px(Vec(40.5, yTunVol2)), module, SickoPlayer::VOL_INPUT)); + addParam(createParamCentered(mm2px(Vec(50.5, yTunVol2)), module, SickoPlayer::VOLATNV_PARAM)); + + addParam(createParamCentered(mm2px(Vec(59.3, 113)), module, SickoPlayer::LIMIT_SWITCH)); + //---------------------------------------------------------------------------------------------------------------------------- + + addOutput(createOutputCentered(mm2px(Vec(70.2, 105.3)), module, SickoPlayer::OUT_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(80.2, 105.3)), module, SickoPlayer::OUT_OUTPUT+1)); + addOutput(createOutputCentered(mm2px(Vec(70.2, 117.5)), module, SickoPlayer::EOC_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(80.2, 117.5)), module, SickoPlayer::EOR_OUTPUT)); + } + + struct ClearSlotItem : MenuItem { + SickoPlayer *module; + void onAction(const event::Action &e) override { + module->clearSlot(); + } + }; + + void appendContextMenu(Menu *menu) override { + SickoPlayer *module = dynamic_cast(this->module); + assert(module); + menu->addChild(new MenuSeparator()); + + SickoPlayerItem *rootDirItem = new SickoPlayerItem; + rootDirItem->text = "Load Sample"; + rootDirItem->rm = module; + menu->addChild(rootDirItem); + menu->addChild(createMenuLabel("Current Sample:")); + menu->addChild(createMenuLabel(module->fileDescription)); + + menu->addChild(construct(&MenuItem::rightText, "Clear", &ClearSlotItem::module, module)); + + menu->addChild(new MenuSeparator()); + + menu->addChild(createMenuLabel("Interpolation")); + struct ModeItem : MenuItem { + SickoPlayer* module; + int interpolationMode; + void onAction(const event::Action& e) override { + module->interpolationMode = interpolationMode; + } + }; + + std::string modeNames[4] = {"None", "Linear 1", "Linear 2", "Hermite"}; + for (int i = 0; i < 4; i++) { + ModeItem* modeItem = createMenuItem(modeNames[i]); + modeItem->rightText = CHECKMARK(module->interpolationMode == i); + modeItem->module = module; + modeItem->interpolationMode = i; + menu->addChild(modeItem); + } + + menu->addChild(new MenuSeparator()); + menu->addChild(createBoolPtrMenuItem("Anti-aliasing filter", "", &module->antiAlias)); + + menu->addChild(new MenuSeparator()); + + menu->addChild(createIndexSubmenuItem("Crossfade length", {"None", "0.5ms", "1ms", "5ms", "10ms", "20ms", "50ms"}, + [ = ]() { + return module->xFade; + }, + [ = ](int xFadeItem) { + module->xFade = xFadeItem; + module->fadeDecrement = module->fadeCoeff[module->xFade]/(APP->engine->getSampleRate()); + } + )); + + menu->addChild(new MenuSeparator()); + menu->addChild(createBoolPtrMenuItem("Polyphonic outs", "", &module->polyOuts)); + + menu->addChild(new MenuSeparator()); + menu->addChild(createBoolPtrMenuItem("Phase scan", "", &module->phaseScan)); + } +}; + +Model *modelSickoPlayer = createModel("SickoPlayer"); diff --git a/src/Switcher.cpp b/src/Switcher.cpp index 331b107..75142de 100644 --- a/src/Switcher.cpp +++ b/src/Switcher.cpp @@ -56,7 +56,7 @@ struct Switcher : Module { Switcher() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); configSwitch(MODE_SWITCH, 0.f, 1.f, 1.f, "Mode", {"Gate", "Toggle"}); - configParam(FADE_PARAMS, 0.f, 10.f, 0.f, "Fade Time (s)"); + configParam(FADE_PARAMS, 0.f, 10.f, 0.f, "Fade Time", "ms", 0, 1000); configInput(TRIG_INPUT, "Trig/Gate"); configInput(RST_INPUT, "Reset"); configInput(IN1_INPUT, "IN 1"); @@ -107,7 +107,7 @@ struct Switcher : Module { void process(const ProcessArgs& args) override { trigConnection = inputs[TRIG_INPUT].isConnected(); - if (!trigConnection){ + if (!trigConnection) { if (prevTrigConnection) { outputs[OUT1_OUTPUT].setVoltage(0); outputs[OUT2_OUTPUT].setVoltage(0); @@ -123,18 +123,14 @@ struct Switcher : Module { fadeValue = params[FADE_PARAMS].getValue() + inputs[FADECV_INPUT].getVoltage(); connection = 0; - if (inputs[IN1_INPUT].isConnected()){ + if (inputs[IN1_INPUT].isConnected()) connection = 1; - } - if (inputs[IN2_INPUT].isConnected()){ + if (inputs[IN2_INPUT].isConnected()) connection += 2; - } - if (outputs[OUT1_OUTPUT].isConnected()){ + if (outputs[OUT1_OUTPUT].isConnected()) connection += 4; - } - if (outputs[OUT2_OUTPUT].isConnected()){ + if (outputs[OUT2_OUTPUT].isConnected()) connection += 8; - } if (connection != prevConnection) { connectionChange = true; prevConnection = connection; @@ -168,11 +164,11 @@ struct Switcher : Module { switch (mode) { // ************************************** GATE MODE ********** case 0: - if (trigValue >= 1 && prevTrigValue < 1){ + if (trigValue >= 1 && prevTrigValue < 1) { currentSwitch = true; connectionChange = true; trigState = true; - } else if (trigValue < 1 && prevTrigValue >= 1){ + } else if (trigValue < 1 && prevTrigValue >= 1) { currentSwitch = false; connectionChange = true; trigState = true; @@ -180,7 +176,7 @@ struct Switcher : Module { prevTrigValue = trigValue; if (trigState) { - if (fadeValue != 0){ + if (fadeValue != 0) { if (fading) { startFade = 1-lastFade; } else { @@ -194,17 +190,17 @@ struct Switcher : Module { break; // ************************************** TRIG MODE ********** case 1: - if (trigValue >= 1 && prevTrigValue < 1){ + if (trigValue >= 1 && prevTrigValue < 1) trigState = true; - } else { + else trigState = false; - } + prevTrigValue = trigValue; if (trigState) { currentSwitch = !currentSwitch; connectionChange = true; - if (fadeValue != 0){ + if (fadeValue != 0) { if (fading) { startFade = 1-lastFade; } else { @@ -219,7 +215,7 @@ struct Switcher : Module { switch (connection) { case 4: // OUT1 = 4 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -240,11 +236,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -293,7 +289,7 @@ struct Switcher : Module { break; case 8: // OUT2 = 8 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -314,11 +310,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -367,7 +363,7 @@ struct Switcher : Module { break; case 12: // OUT1 + OUT2 = 12 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -388,11 +384,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -445,7 +441,7 @@ struct Switcher : Module { break; case 5: // IN1 + OUT1 = 5 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -466,11 +462,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -519,7 +515,7 @@ struct Switcher : Module { break; case 10: // IN2 + OUT2 = 10 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -540,11 +536,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -593,7 +589,7 @@ struct Switcher : Module { break; case 9: // IN1 + OUT2 = 9 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -614,11 +610,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -667,7 +663,7 @@ struct Switcher : Module { break; case 6: // IN2 + OUT1 = 6 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -688,11 +684,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -741,7 +737,7 @@ struct Switcher : Module { break; case 7: // IN1 + IN2 + OUT1 = 7 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -762,11 +758,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -815,7 +811,7 @@ struct Switcher : Module { break; case 11: // IN1 + IN2 + OUT2 = 11 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -836,11 +832,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -889,7 +885,7 @@ struct Switcher : Module { break; case 13: // IN1 + OUT1 + OUT2 = 13 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -910,11 +906,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -967,7 +963,7 @@ struct Switcher : Module { break; case 14: // IN2 + OUT1 + OUT2 = 14 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -988,11 +984,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -1045,7 +1041,7 @@ struct Switcher : Module { break; case 15: // IN1 + IN2 + OUT1 + OUT2 = 15 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -1066,11 +1062,11 @@ struct Switcher : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; diff --git a/src/SwitcherSt.cpp b/src/SwitcherSt.cpp index 720c8f3..9010934 100644 --- a/src/SwitcherSt.cpp +++ b/src/SwitcherSt.cpp @@ -57,7 +57,7 @@ struct SwitcherSt : Module { SwitcherSt() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); configSwitch(MODE_SWITCH, 0.f, 1.f, 1.f, "Mode", {"Gate", "Toggle"}); - configParam(FADE_PARAMS, 0.f, 10.f, 0.f, "Fade Time (s)"); + configParam(FADE_PARAMS, 0.f, 10.f, 0.f, "Fade Time", "ms", 0, 1000); configInput(TRIG_INPUT, "Trig/Gate"); configInput(RST_INPUT, "Reset"); configInput(IN1_INPUT, "IN 1 Left"); @@ -114,7 +114,7 @@ struct SwitcherSt : Module { void process(const ProcessArgs& args) override { trigConnection = inputs[TRIG_INPUT].isConnected(); - if (!trigConnection){ + if (!trigConnection) { if (prevTrigConnection) { outputs[OUT1_OUTPUT].setVoltage(0); outputs[OUT2_OUTPUT].setVoltage(0); @@ -130,18 +130,14 @@ struct SwitcherSt : Module { fadeValue = params[FADE_PARAMS].getValue() + inputs[FADECV_INPUT].getVoltage(); connection = 0; - if (inputs[IN1_INPUT].isConnected()){ + if (inputs[IN1_INPUT].isConnected()) connection = 1; - } - if (inputs[IN2_INPUT].isConnected()){ + if (inputs[IN2_INPUT].isConnected()) connection += 2; - } - if (outputs[OUT1_OUTPUT].isConnected()){ + if (outputs[OUT1_OUTPUT].isConnected()) connection += 4; - } - if (outputs[OUT2_OUTPUT].isConnected()){ + if (outputs[OUT2_OUTPUT].isConnected()) connection += 8; - } if (connection != prevConnection) { connectionChange = true; prevConnection = connection; @@ -175,11 +171,11 @@ struct SwitcherSt : Module { switch (mode) { // ************************************** GATE MODE ********** case 0: - if (trigValue >= 1 && prevTrigValue < 1){ + if (trigValue >= 1 && prevTrigValue < 1) { currentSwitch = true; connectionChange = true; trigState = true; - } else if (trigValue < 1 && prevTrigValue >= 1){ + } else if (trigValue < 1 && prevTrigValue >= 1) { currentSwitch = false; connectionChange = true; trigState = true; @@ -187,7 +183,7 @@ struct SwitcherSt : Module { prevTrigValue = trigValue; if (trigState) { - if (fadeValue != 0){ + if (fadeValue != 0) { if (fading) { startFade = 1-lastFade; } else { @@ -201,11 +197,11 @@ struct SwitcherSt : Module { break; // ************************************** TRIG MODE ********** case 1: - if (trigValue >= 1 && prevTrigValue < 1){ + if (trigValue >= 1 && prevTrigValue < 1) trigState = true; - } else { + else trigState = false; - } + prevTrigValue = trigValue; if (trigState) { @@ -226,7 +222,7 @@ struct SwitcherSt : Module { switch (connection) { case 4: // OUT1 = 4 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -247,11 +243,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -304,7 +300,7 @@ struct SwitcherSt : Module { break; case 8: // OUT2 = 8 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -325,11 +321,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -382,7 +378,7 @@ struct SwitcherSt : Module { break; case 12: // OUT1 + OUT2 = 12 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -403,11 +399,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -468,7 +464,7 @@ struct SwitcherSt : Module { break; case 5: // IN1 + OUT1 = 5 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -489,11 +485,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -546,7 +542,7 @@ struct SwitcherSt : Module { break; case 10: // IN2 + OUT2 = 10 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -567,11 +563,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -624,7 +620,7 @@ struct SwitcherSt : Module { break; case 9: // IN1 + OUT2 = 9 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -645,11 +641,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -702,7 +698,7 @@ struct SwitcherSt : Module { break; case 6: // IN2 + OUT1 = 6 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -723,11 +719,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -780,7 +776,7 @@ struct SwitcherSt : Module { break; case 7: // IN1 + IN2 + OUT1 = 7 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -801,11 +797,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -858,7 +854,7 @@ struct SwitcherSt : Module { break; case 11: // IN1 + IN2 + OUT2 = 11 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -879,11 +875,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -936,7 +932,7 @@ struct SwitcherSt : Module { break; case 13: // IN1 + OUT1 + OUT2 = 13 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -957,11 +953,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -1022,7 +1018,7 @@ struct SwitcherSt : Module { break; case 14: // IN2 + OUT1 + OUT2 = 14 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -1043,11 +1039,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; @@ -1108,7 +1104,7 @@ struct SwitcherSt : Module { break; case 15: // IN1 + IN2 + OUT1 + OUT2 = 15 - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { if (currentSwitch) { @@ -1129,11 +1125,11 @@ struct SwitcherSt : Module { } if (fading) { - if (fadeValue > 10) { + if (fadeValue > 10) fadeValue = 10; - } else if (fadeValue < 0) { + else if (fadeValue < 0) fadeValue = 0; - } + maxFadeSample = args.sampleRate * fadeValue; lastFade = (currentFadeSample / maxFadeSample) + startFade; diff --git a/src/Toggler.cpp b/src/Toggler.cpp index bdcc8f7..784ba5e 100644 --- a/src/Toggler.cpp +++ b/src/Toggler.cpp @@ -4,8 +4,11 @@ struct Toggler : Module { enum ParamId { MODE_SWITCH, ATTACK_PARAMS, + ATTACKATNV_PARAMS, SUSTAIN_PARAMS, + SUSTAINATNV_PARAMS, RELEASE_PARAMS, + RELEASEATNV_PARAMS, PARAMS_LEN }; enum InputId { @@ -39,20 +42,26 @@ struct Toggler : Module { float rst = 0; float prevRst = 0; - float arSum = 0; + //float arSum = 0; float maxFadeSample = 0; float currentFadeSample = 0; bool fading = false; - float sustain = 1; float startFade = 0; float lastFade = 0; + + float attack; + float sustain; + float release; Toggler() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); configSwitch(MODE_SWITCH, 0.f, 1.f, 1.f, "Mode", {"Gate", "Toggle"}); - configParam(ATTACK_PARAMS, 0.f, 10.f, 0.f, "Attack (s)"); - configParam(SUSTAIN_PARAMS, 0.f, 1.f, 1.f, "Level", "%", 0, 100); - configParam(RELEASE_PARAMS, 0.f, 10.f, 0.f, "Release (s)"); + configParam(ATTACK_PARAMS, 0.f, 10.f, 0.f, "Attack", "ms", 0, 1000); + configParam(ATTACKATNV_PARAMS, -1.f, 1.f, 0.f, "Attack Attenuv.", "%", 0, 100); + configParam(SUSTAIN_PARAMS, 0.f, 1.f, 1.f, "Sustain Level", "%", 0, 100); + configParam(SUSTAINATNV_PARAMS, -1.f, 1.f, 0.f, "Sustain Attenuv.", "%", 0, 100); + configParam(RELEASE_PARAMS, 0.f, 10.f, 0.f, "Release", "ms", 0, 1000); + configParam(RELEASEATNV_PARAMS, -1.f, 1.f, 0.f, "Release Attenuv.", "%", 0, 100); configInput(TRIG_INPUT, "Trig/Gate"); configInput(RST_INPUT, "Reset"); configInput(IN_INPUT, "L"); @@ -74,15 +83,11 @@ struct Toggler : Module { trigState = false; trigValue = 0; prevTrigValue = 0; - rst = 0; prevRst = 0; - - arSum = 0; maxFadeSample = 0; currentFadeSample = 0; fading = false; - sustain = 1; startFade = 0; lastFade = 0; @@ -113,27 +118,44 @@ struct Toggler : Module { } void process(const ProcessArgs& args) override { + attack = params[ATTACK_PARAMS].getValue() + (inputs[ATTACK_INPUT].getVoltage() * params[ATTACKATNV_PARAMS].getValue()); + if (attack > 10) + attack = 10; + else if (attack < 0) + attack = 0; + + sustain = params[SUSTAIN_PARAMS].getValue() + (inputs[SUSTAIN_INPUT].getVoltage() * params[SUSTAINATNV_PARAMS].getValue() * 0.1); + if (sustain > 1) + sustain = 1; + else if (sustain < 0) + sustain = 0; + + release = params[RELEASE_PARAMS].getValue() + (inputs[RELEASE_INPUT].getVoltage() * params[RELEASEATNV_PARAMS].getValue()); + if (release > 10) + release = 10; + else if (release < 0) + release = 0; + mode = params[MODE_SWITCH].getValue(); switch (mode) { // ************************************** GATE MODE ********** case 0: trigConnection = inputs[TRIG_INPUT].isConnected(); - if (trigConnection){ + if (trigConnection) { trigValue = inputs[TRIG_INPUT].getVoltage(); - if (trigValue >= 1 && prevTrigValue < 1){ + if (trigValue >= 1 && prevTrigValue < 1) trigState = true; - } else if (trigValue < 1 && prevTrigValue >= 1){ + else if (trigValue < 1 && prevTrigValue >= 1) trigState = false; - } prevTrigValue = trigValue; switch (internalState) { case 0: // waiting for TRIG - if (trigState){ // if GATE goes HIGH + if (trigState) { // if GATE goes HIGH outputs[GATE_OUTPUT].setVoltage(10); lights[OUT_LIGHT].setBrightness(1.f); internalState = 1; - if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0) { + if (attack != 0) { if (fading) { startFade = lastFade; } else { @@ -142,27 +164,11 @@ struct Toggler : Module { } currentFadeSample = 0; } - } else if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + } else if (release != 0) { if (fading == true) { // if it's fading if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading and ONE input connected - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; - if (lastFade < 0) { fading = false; currentFadeSample = 0; @@ -171,33 +177,16 @@ struct Toggler : Module { startFade = 0; lastFade = 0; } else { - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()){ + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * lastFade * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * lastFade * sustain); // send envelope - } } } } else { // if fading and BOTH inputs are not connected - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; - + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; - if (lastFade < 0) { fading = false; currentFadeSample = 0; @@ -228,7 +217,7 @@ struct Toggler : Module { outputs[GATE_OUTPUT].setVoltage(0); lights[OUT_LIGHT].setBrightness(0.f); internalState = 0; - if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + if (release != 0) { if (fading) { startFade = lastFade; } else { @@ -237,60 +226,27 @@ struct Toggler : Module { } currentFadeSample = 0; } - } else if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0){ + } else if (attack != 0) { if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading attack and ONE input is connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; - if (lastFade > 1) { fading = false; currentFadeSample = 0; startFade = 0; lastFade = 0; } else { - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * lastFade * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * lastFade * sustain); // send envelope - } } } } else { // if fading attack and input is not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; - + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; - if (lastFade > 1) { fading = false; currentFadeSample = 0; @@ -304,51 +260,25 @@ struct Toggler : Module { currentFadeSample++; } else { // if fading ATTACK has ended (fade=false) if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if GATING and ONE input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * sustain); // send envelope - } } } else { // if GATING and input is not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); // send envelope on right channel } } } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fade Attack parameters are not set and ONE input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * sustain); - } } } else { // if fade Attack parameters are not set and BOTH input are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); } @@ -367,7 +297,7 @@ struct Toggler : Module { break; // ********************************** TOGGLER MODE *************************************************** case 1: - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { // next lines are duplicated from case 1 @@ -375,7 +305,7 @@ struct Toggler : Module { lights[OUT_LIGHT].setBrightness(0.f); // below is different from original: if internalState is 0 or 1 // it will not do the fade - if ((params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0) && internalState == 1){ + if (release != 0 && internalState == 1) { if (fading) { startFade = lastFade; } else { @@ -391,25 +321,24 @@ struct Toggler : Module { } trigConnection = inputs[TRIG_INPUT].isConnected(); - if (trigConnection){ + if (trigConnection) { if (!prevTrigConnection && internalState == 1) lights[OUT_LIGHT].setBrightness(1.f); trigValue = inputs[TRIG_INPUT].getVoltage(); - if (trigValue >= 1 && prevTrigValue < 1){ + if (trigValue >= 1 && prevTrigValue < 1) trigState = true; - } else { + else trigState = false; - } prevTrigValue = trigValue; switch (internalState) { case 0: // waiting for TRIG - if (trigState){ // if TRIG occurs + if (trigState) { // if TRIG occurs outputs[GATE_OUTPUT].setVoltage(10); lights[OUT_LIGHT].setBrightness(1.f); internalState = 1; - if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0) { + if (attack != 0) { if (fading) { startFade = lastFade; } else { @@ -418,28 +347,11 @@ struct Toggler : Module { } currentFadeSample = 0; } - } else if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + } else if (release != 0) { if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; - - //if (currentFadeSample > maxFadeSample) { if (lastFade < 0) { fading = false; currentFadeSample = 0; @@ -448,33 +360,16 @@ struct Toggler : Module { startFade = 0; lastFade = 0; } else { - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * lastFade * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * lastFade * sustain); // send envelope - } } } } else { // if fading and BOTH input are not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; - + maxFadeSample = args.sampleRate * attack; lastFade = -(currentFadeSample / maxFadeSample) + startFade; - if (lastFade < 0) { fading = false; currentFadeSample = 0; @@ -504,7 +399,7 @@ struct Toggler : Module { outputs[GATE_OUTPUT].setVoltage(0); lights[OUT_LIGHT].setBrightness(0.f); internalState = 0; - if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + if (release != 0) { if (fading) { startFade = lastFade; } else { @@ -513,60 +408,27 @@ struct Toggler : Module { } currentFadeSample = 0; } - } else if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0){ + } else if (attack != 0) { if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading attack and ONE input connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; - if (lastFade > 1) { fading = false; currentFadeSample = 0; startFade = 0; lastFade = 0; } else { - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * lastFade * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * lastFade * sustain); // send envelope - } } } } else { // if fading attack and BOTH input are not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - // get sustain value - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; - + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; - if (lastFade > 1) { fading = false; currentFadeSample = 0; @@ -579,50 +441,24 @@ struct Toggler : Module { } currentFadeSample++; } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if not fading attack and ONE input connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10.f * sustain); // send envelope - } } } else { // if not fading attack and BOTH input are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); // send envelope on right channel } } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if attack parameters are not set and input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * sustain); - } } } else { // if attack parameters are not set and BOTH input are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); } @@ -654,18 +490,21 @@ struct TogglerWidget : ModuleWidget { addChild(createWidget(Vec(0, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget(Vec(box.size.x - RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addParam(createParamCentered(mm2px(Vec(30.458, 18.75)), module, Toggler::MODE_SWITCH)); + addParam(createParamCentered(mm2px(Vec(21.458, 15.75)), module, Toggler::MODE_SWITCH)); - addInput(createInputCentered(mm2px(Vec(12.5, 47.5)), module, Toggler::TRIG_INPUT)); - addInput(createInputCentered(mm2px(Vec(33, 47.5)), module, Toggler::RST_INPUT)); + addInput(createInputCentered(mm2px(Vec(12.5, 38.5)), module, Toggler::TRIG_INPUT)); + addInput(createInputCentered(mm2px(Vec(33, 38.5)), module, Toggler::RST_INPUT)); - addParam(createParamCentered(mm2px(Vec(8.48, 65)), module, Toggler::ATTACK_PARAMS)); + addParam(createParamCentered(mm2px(Vec(8.48, 60)), module, Toggler::ATTACK_PARAMS)); + addParam(createParamCentered(mm2px(Vec(8.48, 71.5)), module, Toggler::ATTACKATNV_PARAMS)); addInput(createInputCentered(mm2px(Vec(8.48, 80.5)), module, Toggler::ATTACK_INPUT)); - addParam(createParamCentered(mm2px(Vec(22.8, 65)), module, Toggler::SUSTAIN_PARAMS)); + addParam(createParamCentered(mm2px(Vec(22.8, 60)), module, Toggler::SUSTAIN_PARAMS)); + addParam(createParamCentered(mm2px(Vec(22.8, 71.5)), module, Toggler::SUSTAINATNV_PARAMS)); addInput(createInputCentered(mm2px(Vec(22.8, 80.5)), module, Toggler::SUSTAIN_INPUT)); - addParam(createParamCentered(mm2px(Vec(37.32, 65)), module, Toggler::RELEASE_PARAMS)); + addParam(createParamCentered(mm2px(Vec(37.32, 60)), module, Toggler::RELEASE_PARAMS)); + addParam(createParamCentered(mm2px(Vec(37.32, 71.5)), module, Toggler::RELEASEATNV_PARAMS)); addInput(createInputCentered(mm2px(Vec(37.32, 80.5)), module, Toggler::RELEASE_INPUT)); addInput(createInputCentered(mm2px(Vec(7, 108.8)), module, Toggler::IN_INPUT)); diff --git a/src/TogglerCompact.cpp b/src/TogglerCompact.cpp index c2b8cb2..3a83273 100644 --- a/src/TogglerCompact.cpp +++ b/src/TogglerCompact.cpp @@ -39,20 +39,22 @@ struct TogglerCompact : Module { float rst = 0; float prevRst = 0; - float arSum = 0; float maxFadeSample = 0; float currentFadeSample = 0; bool fading = false; - float sustain = 1; float startFade = 0; float lastFade = 0; + float attack; + float sustain; + float release; + TogglerCompact() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); configSwitch(MODE_SWITCH, 0.f, 1.f, 1.f, "Mode", {"Gate", "Toggle"}); - configParam(ATTACK_PARAMS, 0.f, 10.f, 0.f, "Attack (s)"); + configParam(ATTACK_PARAMS, 0.f, 10.f, 0.f, "Attack", "ms", 0, 1000); configParam(SUSTAIN_PARAMS, 0.f, 1.f, 1.f, "Level", "%", 0, 100); - configParam(RELEASE_PARAMS, 0.f, 10.f, 0.f, "Release (s)"); + configParam(RELEASE_PARAMS, 0.f, 10.f, 0.f, "Release", "ms", 0, 1000); configInput(TRIG_INPUT, "Trig/Gate"); configInput(RST_INPUT, "Reset"); configInput(IN_INPUT, "L"); @@ -74,15 +76,11 @@ struct TogglerCompact : Module { trigState = false; trigValue = 0; prevTrigValue = 0; - rst = 0; prevRst = 0; - - arSum = 0; maxFadeSample = 0; currentFadeSample = 0; fading = false; - sustain = 1; startFade = 0; lastFade = 0; @@ -113,27 +111,44 @@ struct TogglerCompact : Module { } void process(const ProcessArgs& args) override { + attack = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); + if (attack > 10) + attack = 10; + else if (attack < 0) + attack = 0; + + sustain = params[SUSTAIN_PARAMS].getValue() + (inputs[SUSTAIN_INPUT].getVoltage() * 0.1); + if (sustain > 1) + sustain = 1; + else if (sustain < 0) + sustain = 0; + + release = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); + if (release > 10) + release = 10; + else if (release < 0) + release = 0; + mode = params[MODE_SWITCH].getValue(); switch (mode) { // ************************************** GATE MODE ********** case 0: trigConnection = inputs[TRIG_INPUT].isConnected(); - if (trigConnection){ + if (trigConnection) { trigValue = inputs[TRIG_INPUT].getVoltage(); - if (trigValue >= 1 && prevTrigValue < 1){ + if (trigValue >= 1 && prevTrigValue < 1) trigState = true; - } else if (trigValue < 1 && prevTrigValue >= 1){ + else if (trigValue < 1 && prevTrigValue >= 1) trigState = false; - } prevTrigValue = trigValue; switch (internalState) { case 0: // waiting for TRIG - if (trigState){ // if GATE goes HIGH + if (trigState) { // if GATE goes HIGH outputs[GATE_OUTPUT].setVoltage(10); lights[OUT_LIGHT].setBrightness(1.f); internalState = 1; - if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0) { + if (attack != 0) { if (fading) { startFade = lastFade; } else { @@ -142,27 +157,11 @@ struct TogglerCompact : Module { } currentFadeSample = 0; } - } else if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + } else if (release != 0) { if (fading == true) { // if it's fading if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading and ONE input connected - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; - if (lastFade < 0) { fading = false; currentFadeSample = 0; @@ -171,33 +170,16 @@ struct TogglerCompact : Module { startFade = 0; lastFade = 0; } else { - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()){ + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * lastFade * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * lastFade * sustain); // send envelope - } } } } else { // if fading and BOTH inputs are not connected - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; - + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; - if (lastFade < 0) { fading = false; currentFadeSample = 0; @@ -228,7 +210,7 @@ struct TogglerCompact : Module { outputs[GATE_OUTPUT].setVoltage(0); lights[OUT_LIGHT].setBrightness(0.f); internalState = 0; - if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + if (release != 0) { if (fading) { startFade = lastFade; } else { @@ -237,60 +219,27 @@ struct TogglerCompact : Module { } currentFadeSample = 0; } - } else if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0){ + } else if (attack != 0) { if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading attack and ONE input is connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; - if (lastFade > 1) { fading = false; currentFadeSample = 0; startFade = 0; lastFade = 0; } else { - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * lastFade * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * lastFade * sustain); // send envelope - } } } } else { // if fading attack and input is not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; - + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; - if (lastFade > 1) { fading = false; currentFadeSample = 0; @@ -304,51 +253,25 @@ struct TogglerCompact : Module { currentFadeSample++; } else { // if fading ATTACK has ended (fade=false) if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if GATING and ONE input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * sustain); // send envelope - } } } else { // if GATING and input is not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); // send envelope on right channel } } } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fade Attack parameters are not set and ONE input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * sustain); - } } } else { // if fade Attack parameters are not set and BOTH input are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); } @@ -367,7 +290,7 @@ struct TogglerCompact : Module { break; // ********************************** TOGGLER MODE *************************************************** case 1: - if (inputs[RST_INPUT].isConnected()){ + if (inputs[RST_INPUT].isConnected()) { rst = inputs[RST_INPUT].getVoltage(); if (rst >= 1 && prevRst < 1) { // next lines are duplicated from case 1 @@ -375,7 +298,7 @@ struct TogglerCompact : Module { lights[OUT_LIGHT].setBrightness(0.f); // below is different from original: if internalState is 0 or 1 // it will not do the fade - if ((params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0) && internalState == 1){ + if (release != 0 && internalState == 1) { if (fading) { startFade = lastFade; } else { @@ -391,25 +314,24 @@ struct TogglerCompact : Module { } trigConnection = inputs[TRIG_INPUT].isConnected(); - if (trigConnection){ + if (trigConnection) { if (!prevTrigConnection && internalState == 1) lights[OUT_LIGHT].setBrightness(1.f); trigValue = inputs[TRIG_INPUT].getVoltage(); - if (trigValue >= 1 && prevTrigValue < 1){ + if (trigValue >= 1 && prevTrigValue < 1) trigState = true; - } else { + else trigState = false; - } prevTrigValue = trigValue; switch (internalState) { case 0: // waiting for TRIG - if (trigState){ // if TRIG occurs + if (trigState) { // if TRIG occurs outputs[GATE_OUTPUT].setVoltage(10); lights[OUT_LIGHT].setBrightness(1.f); internalState = 1; - if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0) { + if (attack != 0) { if (fading) { startFade = lastFade; } else { @@ -418,28 +340,11 @@ struct TogglerCompact : Module { } currentFadeSample = 0; } - } else if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + } else if (release != 0) { if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { - // update release value - arSum = params[RELEASE_PARAMS].getValue() + inputs[RELEASE_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + maxFadeSample = args.sampleRate * release; lastFade = -(currentFadeSample / maxFadeSample) + startFade; - - //if (currentFadeSample > maxFadeSample) { if (lastFade < 0) { fading = false; currentFadeSample = 0; @@ -448,31 +353,16 @@ struct TogglerCompact : Module { startFade = 0; lastFade = 0; } else { - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * lastFade * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * lastFade * sustain); // send envelope - } } } } else { // if fading and BOTH input are not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; + maxFadeSample = args.sampleRate * attack; lastFade = -(currentFadeSample / maxFadeSample) + startFade; if (lastFade < 0) { @@ -504,7 +394,7 @@ struct TogglerCompact : Module { outputs[GATE_OUTPUT].setVoltage(0); lights[OUT_LIGHT].setBrightness(0.f); internalState = 0; - if (params[RELEASE_PARAMS].getValue() != 0 || inputs[RELEASE_INPUT].getVoltage() != 0){ + if (release != 0) { if (fading) { startFade = lastFade; } else { @@ -513,25 +403,11 @@ struct TogglerCompact : Module { } currentFadeSample = 0; } - } else if (params[ATTACK_PARAMS].getValue() != 0 || inputs[ATTACK_INPUT].getVoltage() != 0){ + } else if (attack != 0){ if (fading == true) { if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if fading attack and ONE input connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - maxFadeSample = args.sampleRate * arSum; - // get sustain value - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; if (lastFade > 1) { @@ -541,30 +417,15 @@ struct TogglerCompact : Module { lastFade = 0; } else { for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * lastFade * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * lastFade * sustain); // send envelope - } } } } else { // if fading attack and BOTH input are not connected - // update attack value - arSum = params[ATTACK_PARAMS].getValue() + inputs[ATTACK_INPUT].getVoltage(); - if (arSum > 10) { - arSum = 10; - } else if (arSum < 0) { - arSum = 0; - } - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - // get sustain value - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - maxFadeSample = args.sampleRate * arSum; - + + maxFadeSample = args.sampleRate * attack; lastFade = (currentFadeSample / maxFadeSample) + startFade; if (lastFade > 1) { @@ -579,50 +440,24 @@ struct TogglerCompact : Module { } currentFadeSample++; } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if not fading attack and ONE input connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10.f * sustain); // send envelope - } } } else { // if not fading attack and BOTH input are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); // send envelope on right channel } } else if (inputs[IN_INPUT].isConnected() || inputs[IN_INPUT+1].isConnected()) { // if attack parameters are not set and input is connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } - for (int i=0; i<2; i++){ - if (inputs[IN_INPUT+i].isConnected()) { + for (int i=0; i<2; i++) { + if (inputs[IN_INPUT+i].isConnected()) outputs[OUT_OUTPUT+i].setVoltage(inputs[IN_INPUT+i].getVoltage() * sustain); - } else { + else outputs[OUT_OUTPUT+i].setVoltage(10 * sustain); - } } } else { // if attack parameters are not set and BOTH input are not connected - sustain = params[SUSTAIN_PARAMS].getValue() + inputs[SUSTAIN_INPUT].getVoltage() / 10; - if (sustain > 1) { - sustain = 1; - } else if (sustain < 0) { - sustain = 0; - } outputs[OUT_OUTPUT].setVoltage(10 * sustain); // send envelope on left and right channel outputs[OUT_OUTPUT+1].setVoltage(10 * sustain); } @@ -643,7 +478,6 @@ struct TogglerCompact : Module { } }; - struct TogglerCompactWidget : ModuleWidget { TogglerCompactWidget(TogglerCompact* module) { setModule(module); diff --git a/src/plugin.cpp b/src/plugin.cpp index f4757e1..97c3c69 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -29,4 +29,6 @@ void init(Plugin* p) { p->addModel(modelShifter); p->addModel(modelDrumPlayer); p->addModel(modelDrumPlayerPlus); + p->addModel(modelSickoPlayer); + p->addModel(modelDrummer4Plus); } diff --git a/src/plugin.hpp b/src/plugin.hpp index 8fabb7c..3d70c4f 100644 --- a/src/plugin.hpp +++ b/src/plugin.hpp @@ -26,3 +26,5 @@ extern Model* modelParking; extern Model* modelShifter; extern Model *modelDrumPlayer; extern Model *modelDrumPlayerPlus; +extern Model *modelSickoPlayer; +extern Model* modelDrummer4Plus;