Browse Source

removed Alikins

pull/320/head
U-ACTIVED\danielez 7 years ago
parent
commit
f2e4b3b02d
14 changed files with 1 additions and 3596 deletions
  1. +1
    -0
      repos/AS
  2. +0
    -4
      repos/Alikins/.gitignore
  3. +0
    -27
      repos/Alikins/LICENSE.txt
  4. +0
    -32
      repos/Alikins/Makefile
  5. +0
    -100
      repos/Alikins/README.md
  6. +0
    -115
      repos/Alikins/TODO.txt
  7. +0
    -2679
      repos/Alikins/res/IdleSwitch.svg
  8. +0
    -151
      repos/Alikins/res/MomentaryOnButtons.svg
  9. BIN
      repos/Alikins/res/Segment7Standard.ttf
  10. BIN
      repos/Alikins/screenshots/modules.png
  11. +0
    -311
      repos/Alikins/src/IdleSwitch.cpp
  12. +0
    -143
      repos/Alikins/src/MomentaryOnButtons.cpp
  13. +0
    -19
      repos/Alikins/src/alikins.cpp
  14. +0
    -15
      repos/Alikins/src/alikins.hpp

+ 1
- 0
repos/AS

@@ -0,0 +1 @@
Subproject commit 4a61ab9ce4b3690a7491a817cbadb79e3e14cb7f

+ 0
- 4
repos/Alikins/.gitignore View File

@@ -1,4 +0,0 @@
build/
dist/
.DS_Store
plugin.dylib

+ 0
- 27
repos/Alikins/LICENSE.txt View File

@@ -1,27 +0,0 @@
BSD 3-Clause License

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


+ 0
- 32
repos/Alikins/Makefile View File

@@ -1,32 +0,0 @@
SLUG = Alikins
VERSION = 0.6.0dev

RACK_DIR ?= ../..

# FLAGS will be passed to both the C and C++ compiler
FLAGS +=
CFLAGS +=
CXXFLAGS +=

# Careful about linking to libraries, since you can't assume much about the user's environment and library search path.
# Static libraries are fine.
LDFLAGS +=

# Add .cpp and .c files to the build
SOURCES = $(wildcard src/*.cpp)

# Must include the VCV plugin Makefile framework
include $(RACK_DIR)/plugin.mk

# http://cppcheck.sourceforge.net/
cppcheck:
cppcheck -i../../dep/include -i../../include --enable=style -DVERSION=0.5.1 --quiet src/

# https://github.com/google/styleguide
cpplint:
cpplint --headers=hpp --filter=-whitespace/line_length,-legal/copyright,whitespace/blank_line src/*.cpp src/*.hpp


DISTRIBUTABLES += $(wildcard LICENSE*) res

.PHONY: cppcheck cpplint

+ 0
- 100
repos/Alikins/README.md View File

@@ -1,100 +0,0 @@

# VCV Rack plugin

Plugins for use with VCV Rack virtual module synthesizer (https://github.com/VCVRack/Rack)

![screenshot](./screenshots/modules.png)

## Modules

### IdleSwitch

#### What

An 'idle loop' inspired module for detecting when an input
is idle and turns on a gate until it sees activity again.

If no input events are seen at "Input Source" within the timeout period
emit a gate on "Idle Gate Output" that lasts until there are input events
again. Then reset the timeout period.

Sort of metaphoricaly like an idle handler or timeout in event based
programming like GUI main loops.

The timeout period is set by the value
of the 'Time before idle' param.

##### Input event

An "Input event" is a gate or trigger (or a CV or audio signal
that looks sufficently like a gate or trigger).

After a input event, the Idle Gate Output will remain on until
an input event is seen at Input Source. When there is an input event, the Idle
Gate Output is turned off until the expiration of the 'Time before idle' or
the next 'Reset idle'.

##### Reset timer

If there is a 'Reset timer' source, when it gets an event, the timeout period
is reset. But unlike an "Input event", a 'Reset timer' event does does not
reset the idle status.

After "Reset time" event, the "Idle Gate Output" will remain on until
an input event is seen at Input Source. When there is an input event, the Idle
Gate Output is turned off until the expiration of the 'Time before idle' or
the next 'Reset idle'.

To use the eventloop/gui main loop analogy, a 'Reset idle' event is equilivent to
running an idle handler directly (or running a mainloop iteration with no non-idle
events pending).

##### Clock input

If a cable is hooked to the "Clock Input" then the pulse from the clock
will determine with the idle time expires. When there is a clock pulse,
if there were no input events since the previous clock pulse that is
considered idle.

The "Time before idle" display will reflect the time since the last
clock pulse. The "Time remaining" display will always show 0 for now,
at least until it can predict the future.

##### Time input and output

The "Time input" expects a CV output between 0 and 10V. The voltage
maps directly do the number of seconds for the idle timeout.
Eg. a 5.0V CV to "Time input" sets "Time before idle" to 5000ms (5.0 seconds)

The "Time output" sends a CV output between 0 and 10V indicating
the "Time before idle" value.

The "Time output" can be used to connect one or more IdleSwitch modules
together so they share the same "Time before idle".

In "Clock input" mode, the "Time Output" will correspond with the
"Time before idle" display until the time is over 10s, then the
"Time output" will max out at 10V.

#### Why

Original intentional was to use in combo with a human player and midi/cv keyboard.
As long as the human is playing, the IdleSwitch output is 'off', but if they go
idle for some time period the output is turned on. For example, a patch may plain
loud drone when idle, but would turn the drone off or down when the human played
and then turn it back on when it stopped. Or maybe it could be used to start an
drum fill...

The 'Reset idle' input allows this be kind of synced to a clock, beat, or sequence.
In the dronevexample above, the drone would then only come back in on a beat.

And perhaps most importantly, it can be used to do almost random output and
make weird noises.

### MomentaryOnButtons

A set of GUI buttons that send a +10V output while pressed.

## License

BSD 3-clause. See LICENSE.txt

+ 0
- 115
repos/Alikins/TODO.txt View File

@@ -1,115 +0,0 @@
plugin ideas:
- Mult with labels
- so I can route a distance output to mult and label
it as 'main seq gate output' to avoid tracing cables
- seq with start/stop/reset triggers (ie, one shot sequencer)
(or 'play', 'pause', 'go to begin')
- solve 'how do I run a sequence once?' FAQ
- event log
- visualization of past triggers/gates
- time series or sparkline-ish
- more or less a scope but without y values and
a very long time
- could do diff colors for gates/triggers
- or gates up and triggers down
- wide module
- multiple time view zooms
- 1x, 2x, 5x, 10, 20x, 50x, etc
- mostly for appearance or troubleshooting/debugging event stuff
- could evolve to supporting playing the the history back
- 1x speed or faster/slower
- scrubbing?
- multiple channels of events
- table module
- "an oscillator is a phasor and a table"
- phasor input (0.0 -> 1.0) or other scaled
- value output
- on step, read phasor value, look for a match
in the table, output the value
- ui
- just a scrollable list?
- columns
- phasor
- start range
- end range
- output value
- buttons to add delete entry
- load table from json in context menu
- uses:
- feed a sawtooth osc output into it to
create rudimentary wave table
- arbitrary quantizer
- building block
- fancy options
- entries that map a range of phasor input
values to a range of output values
- map ranges could be linear/log etc
- linear
- slope
- offset
- sub ranges could be cos/sine/exp/some distribution etc
- (similar to the old GIMP color gradient editor)
- likely could use gimp gradient (ggr) files as a type of table
- modulating the table offset or value amplitudes
- credits module
- widget that shows author, create/mod date, urls, license, other metainfo
- would save into vcv file as module json data
- use a rack_credits.json in ~/ or rack doc root to set the default
- list of author/credit metadata
- would get appended to if modified by new author
- how to only update on 'save' or 'save as' ?
- don't want to append on every autosave.vcv write
- track a single 'last_edit' to persist on every toJson
- then on load/fromJSON, add last_edit to author list
- if there is a way for plugin to distinquish a 'real save' vs
an 'autosave', then could use that.
- how to tell when a patch has been 'modified'?
- needed to avoid adding info on every save or autosave
- slightly klugey way:
- if plugin knows the patch it is in, could load patch .vcv/json
data and compare to 'previous'.
- chksum would be simplest
- but could do a smarter/deeper compare diving into the data
- uses:
- a patch with the module includes the author info
- if patch is shared (via patchstorage for ex), and modified
by a different author, the module json would include info
for the original author and modification author
- just as a display widget when sharing a screen capture
- concerns:
- could probably be better implemented as a feature of the core vcv serialization
- 'Equal and opposite'
- two eqs with 'opposite' settings and an effects loop in between
- before eq, after eq
- same bands and q's, but opposite gain
- ie, if 'before eq' boosts bass and treble by 10db and cuts mids by 12db
then the 'after eq' would cut bass and treble by 10db and boost mids by 12db
- an effects send and return in between
- munge audio signal, send it to effect (a distortion for ex) and unmunge on the way out
- the before/after transforms would automatically mirror each other
- otherwise pointless since it could be done with other modules
- other variations could exist for other reversible-ish transforms
- dont have to be perfect or lossless
- compress/expand
- bitcrush / 'bit extropalate' (is that a thing?)
- forward/reverse delay?
- pitch shift (probably most interesting, but
- transport gui module
- play/stop/pause/fast forward/reverse/record buttons
- gate and trig outputs for them
- just buttons, but with a explicit purpose
- uses
- generative patches that need a 'press play to start'
- specific values
- module with just text entrie fields for entering a float value
and an output for that value
- possibly with text widget in combo with a dial or inc/dec
buttons (spinbox widget)
- or 'click and drag to change value'
- up/down for small value
- left/right for multiplier (middle = 1x, left = 0..1.0x, right >1.0x multi)
- 'up and to the left' for fine grained adjustments
- fancy
- maybe automatically also show CV v/oct freq or note equiv
- maybe gate out and button to click to send value and gate output together


+ 0
- 2679
repos/Alikins/res/IdleSwitch.svg
File diff suppressed because it is too large
View File


+ 0
- 151
repos/Alikins/res/MomentaryOnButtons.svg View File

@@ -1,151 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="75"
height="380"
viewBox="0 0 19.843751 100.54167"
version="1.1"
id="svg8"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="MomentaryOnButtons.svg"
style="enable-background:new">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.6921053"
inkscape:cx="37.5"
inkscape:cy="190"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="false"
inkscape:snap-page="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:window-width="1440"
inkscape:window-height="856"
inkscape:window-x="11"
inkscape:window-y="2"
inkscape:window-maximized="0"
inkscape:measure-start="0,0"
inkscape:measure-end="0,0"
inkscape:snap-text-baseline="true"
inkscape:snap-nodes="false"
inkscape:snap-others="false"
inkscape:snap-grids="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-196.45832)"
style="opacity:0.81999966">
<path
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="M 0,196.45831 H 15.875 V 296.99999 H 0 Z"
id="rect817"
inkscape:connector-curvature="0" />
<rect
style="fill:#99ff55;fill-opacity:0.36097562;stroke:#000000;stroke-width:0.22707526;stroke-miterlimit:4;stroke-dasharray:0, 2.49782804;stroke-dashoffset:0;stroke-opacity:0.00485439"
id="rect4596"
width="6.5781407"
height="96.39846"
x="6.7771721"
y="196.41748" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="2.0959258"
y="199.32983"
id="text4602"><tspan
sodipodi:role="line"
id="tspan4600"
x="2.0959258"
y="208.6936"
style="stroke-width:0.26458332" /></text>
<rect
style="opacity:1;fill:#e08976;fill-opacity:0.37931034;stroke:#000000;stroke-width:0.24057104;stroke-miterlimit:4;stroke-dasharray:0, 2.64628129;stroke-dashoffset:0;stroke-opacity:0"
id="rect4598"
width="5.266654"
height="96.089233"
x="1.639776"
y="196.67091" />
<g
aria-label="Momentary"
transform="matrix(0.76786881,0,0,1.3023058,0.9381804,0)"
style="font-style:normal;font-weight:normal;font-size:3.08836555px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#e08934;fill-opacity:0.97647059;stroke:none;stroke-width:0.07720914"
id="text4606">
<path
d="m 1.7166386,151.74845 h 0.4539053 l 0.5745445,1.53212 0.5775606,-1.53212 h 0.4539053 v 2.25143 H 3.47948 v -1.97698 l -0.5805765,1.54418 H 2.5927813 L 2.0122048,152.0229 v 1.97698 H 1.7166386 Z"
style="fill:#e08934;fill-opacity:0.97647059;stroke-width:0.07720914"
id="path4608"
inkscape:connector-curvature="0" />
<path
d="m 5.0251709,152.50546 q -0.2231827,0 -0.3528699,0.17493 -0.1296872,0.17341 -0.1296872,0.47652 0,0.30311 0.1281792,0.47803 0.1296872,0.17342 0.3543779,0.17342 0.2216747,0 0.3513619,-0.17492 0.1296872,-0.17493 0.1296872,-0.47653 0,-0.30009 -0.1296872,-0.47502 -0.1296872,-0.17643 -0.3513619,-0.17643 z m 0,-0.23525 q 0.3619178,0 0.5685126,0.23525 0.2065948,0.23525 0.2065948,0.65145 0,0.4147 -0.2065948,0.65145 -0.2065948,0.23525 -0.5685126,0.23525 -0.3634258,0 -0.5700206,-0.23525 -0.2050868,-0.23675 -0.2050868,-0.65145 0,-0.4162 0.2050868,-0.65145 0.2065948,-0.23525 0.5700206,-0.23525 z"
style="fill:#e08934;fill-opacity:0.97647059;stroke-width:0.07720914"
id="path4610"
inkscape:connector-curvature="0" />
<path
d="m 7.5736757,152.63515 q 0.1040514,-0.18699 0.2488185,-0.27597 0.1447672,-0.089 0.340806,-0.089 0.2638984,0 0.4071576,0.18549 0.1432591,0.18397 0.1432591,0.52478 v 1.0194 H 8.4347386 v -1.01036 q 0,-0.24278 -0.085955,-0.36041 -0.085956,-0.11762 -0.2623904,-0.11762 -0.2156428,0 -0.340806,0.14326 -0.1251633,0.14326 -0.1251633,0.39057 v 0.95456 H 7.3414451 v -1.01036 q 0,-0.24429 -0.085955,-0.36041 -0.085955,-0.11762 -0.2654064,-0.11762 -0.2126267,0 -0.33779,0.14477 -0.1251632,0.14326 -0.1251632,0.38906 v 0.95456 H 6.2481516 V 152.3109 H 6.52713 v 0.26239 q 0.095003,-0.15532 0.2277066,-0.22922 0.1327032,-0.0739 0.3151701,-0.0739 0.1839749,0 0.3121542,0.0935 0.1296872,0.0935 0.1915148,0.27144 z"
style="fill:#e08934;fill-opacity:0.97647059;stroke-width:0.07720914"
id="path4612"
inkscape:connector-curvature="0" />
<path
d="m 10.713313,153.08604 v 0.13571 H 9.4375527 q 0.018096,0.28652 0.171911,0.43732 0.1553231,0.14929 0.4312853,0.14929 0.159847,0 0.309138,-0.0392 0.150799,-0.0392 0.298582,-0.11763 v 0.26239 q -0.149291,0.0633 -0.306122,0.0965 -0.156831,0.0332 -0.318186,0.0332 -0.4041414,0 -0.6408959,-0.23525 -0.2352466,-0.23524 -0.2352466,-0.63637 0,-0.4147 0.2231826,-0.65748 0.2246907,-0.2443 0.6047044,-0.2443 0.3408055,0 0.5383525,0.22017 0.199055,0.21866 0.199055,0.59566 z m -0.27747,-0.0814 q -0.003,-0.2277 -0.128179,-0.36342 -0.123656,-0.13572 -0.3287425,-0.13572 -0.2322306,0 -0.3724738,0.13119 -0.1387352,0.1312 -0.159847,0.36946 z"
style="fill:#e08934;fill-opacity:0.97647059;stroke-width:0.07720914"
id="path4614"
inkscape:connector-curvature="0" />
<path
d="m 12.572666,152.98048 v 1.0194 h -0.277471 v -1.01036 q 0,-0.23977 -0.09349,-0.3589 -0.0935,-0.11913 -0.280486,-0.11913 -0.224691,0 -0.354378,0.14326 -0.129688,0.14326 -0.129688,0.39057 v 0.95456 H 11.15817 v -1.68895 h 0.278978 v 0.26239 q 0.09953,-0.15231 0.233739,-0.22771 0.135719,-0.0754 0.312154,-0.0754 0.291042,0 0.440334,0.18096 0.149291,0.17945 0.149291,0.52931 z"
style="fill:#e08934;fill-opacity:0.97647059;stroke-width:0.07720914"
id="path4616"
inkscape:connector-curvature="0" />
<path
d="m 13.403569,151.83139 v 0.47954 h 0.571528 v 0.21564 h -0.571528 v 0.91686 q 0,0.20659 0.0558,0.26541 0.0573,0.0588 0.230723,0.0588 h 0.28501 v 0.23223 h -0.28501 q -0.321202,0 -0.443349,-0.11913 -0.122148,-0.12064 -0.122148,-0.43732 v -0.91686 h -0.203579 v -0.21564 h 0.203579 v -0.47954 z"
style="fill:#e08934;fill-opacity:0.97647059;stroke-width:0.07720914"
id="path4618"
inkscape:connector-curvature="0" />
<path
d="m 15.109107,153.15088 q -0.336282,0 -0.465969,0.0769 -0.129688,0.0769 -0.129688,0.26239 0,0.14778 0.09651,0.23524 0.09802,0.086 0.265406,0.086 0.230723,0 0.369458,-0.16286 0.140243,-0.16437 0.140243,-0.43581 v -0.0618 z m 0.553433,-0.11461 v 0.96361 h -0.277471 v -0.25636 q -0.095,0.15381 -0.236754,0.22771 -0.141752,0.0724 -0.346838,0.0724 -0.259375,0 -0.41319,-0.14477 -0.152307,-0.14627 -0.152307,-0.39057 0,-0.28501 0.190007,-0.42977 0.191515,-0.14477 0.570021,-0.14477 h 0.389061 v -0.0272 q 0,-0.19151 -0.126671,-0.29556 -0.125163,-0.10556 -0.35287,-0.10556 -0.144767,0 -0.281994,0.0347 -0.137227,0.0347 -0.263899,0.10405 v -0.25635 q 0.152307,-0.0588 0.295567,-0.0875 0.143259,-0.0302 0.278978,-0.0302 0.366442,0 0.547401,0.19001 0.180959,0.19001 0.180959,0.57605 z"
style="fill:#e08934;fill-opacity:0.97647059;stroke-width:0.07720914"
id="path4620"
inkscape:connector-curvature="0" />
<path
d="m 17.214262,152.5703 q -0.04675,-0.0271 -0.102544,-0.0392 -0.05429,-0.0136 -0.120639,-0.0136 -0.235246,0 -0.361918,0.15382 -0.125163,0.1523 -0.125163,0.43882 v 0.88972 H 16.22502 v -1.68895 h 0.278978 v 0.26239 q 0.08746,-0.15382 0.227707,-0.22771 0.140243,-0.0754 0.340806,-0.0754 0.02865,0 0.06334,0.005 0.03468,0.003 0.07691,0.0105 z"
style="fill:#e08934;fill-opacity:0.97647059;stroke-width:0.07720914"
id="path4622"
inkscape:connector-curvature="0" />
<path
d="m 18.211044,154.15671 q -0.117624,0.3016 -0.229215,0.39358 -0.111591,0.092 -0.298582,0.092 h -0.221675 v -0.23223 h 0.162863 q 0.114608,0 0.177943,-0.0543 0.06334,-0.0543 0.140243,-0.25635 l 0.04976,-0.12668 -0.68312,-1.6618 h 0.294058 l 0.527797,1.321 0.527797,-1.321 h 0.294058 z"
style="fill:#e08934;fill-opacity:0.97647059;stroke-width:0.07720914"
id="path4624"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

BIN
repos/Alikins/res/Segment7Standard.ttf View File


BIN
repos/Alikins/screenshots/modules.png View File

Before After
Width: 416  |  Height: 810  |  Size: 133KB

+ 0
- 311
repos/Alikins/src/IdleSwitch.cpp View File

@@ -1,311 +0,0 @@
#include <stdio.h>
#include <sstream>
#include <iomanip>

#include "alikins.hpp"
#include "dsp/digital.hpp"
// #include "util.hpp"


/* IdleSwitch
*
* What:
*
* If no input events are seen at Input Source within the timeout period
* emit a gate on Idle Gate Output that lasts until there are input events
* again. Then reset the timeout period.
*
* Sort of metaphoricaly like an idle handler or timeout in event based
* programming like GUI main loops.
*
* The timeout period is set by the value
* of the 'Time before idle' param.
*
* If there is a 'Reset idle' source, when it gets an event, the timeout period
* is reset. After a reset event, the Idle Gate Output will remain on until
* an input event is seen at Input Source. When there is an input event, the Idle
* Gate Output is turned off until the expiration of the 'Time before idle' or
* the next 'Reset idle'.
*
* To use the eventloop/gui main loop analogy, a 'Reset idle' event is equilivent to
* running an idle handler directly (or running a mainloop iteration with no non-idle
* events pending).
*
* Why:
*
* Original intentional was to use in combo with a human player and midi/cv keyboard.
* As long as the human is playing, the IdleSwitch output is 'off', but if they go
* idle for some time period the output is turned on. For example, a patch may plain
* loud drone when idle, but would turn the drone off or down when the human played
* and then turn it back on when it stopped. Or maybe it could be used to start an
* drum fill...
*
* The 'Reset idle' input allows this be kind of synced to a clock, beat, or sequence.
* In the dronevexample above, the drone would then only come back in on a beat.
*
* And perhaps most importantly, it can be used to do almost random output and
* make weird noises.
*/


/* TODO
* - is there a 'standard' for communicating lengths of time (like delay time)?
* - idle start trigger
* - idle end trigger
* - switch for output to be high for idle or low for idle
* - time display widget for timeout length
* - Fine/Course params fors for timeout
* - idle timeout countdown display for remaining time before timeout
* - gui 'progress' widget?
*/

struct IdleSwitch : Module {
enum ParamIds {
TIME_PARAM,
NUM_PARAMS
};
enum InputIds {
INPUT_SOURCE_INPUT,
HEARTBEAT_INPUT,
TIME_INPUT,
PULSE_INPUT,
NUM_INPUTS
};
enum OutputIds {
IDLE_GATE_OUTPUT,
TIME_OUTPUT,
IDLE_START_OUTPUT,
IDLE_END_OUTPUT,
FRAME_COUNT_OUTPUT,

NUM_OUTPUTS
};
enum LightIds {
NUM_LIGHTS
};

int idleTimeoutMS = 140;
int idleTimeLeftMS = 0;

SchmittTrigger inputTrigger;

// FIXME: these names are confusing
SchmittTrigger heartbeatTrigger;

// clock mode stuff
SchmittTrigger pulseTrigger;
int pulseFrame = 0;
bool waiting_for_pulse = false;
bool pulse_mode = false;

PulseGenerator idleStartPulse;
PulseGenerator idleEndPulse;

// FIXME: not really counts
int frameCount = 0;
int maxFrameCount = 0;

float idleGateOutput = 0.0;

float deltaTime = 0;

bool is_idle = false;

IdleSwitch() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
void step() override;
};


void IdleSwitch::step() {
bool pulse_seen = false;
bool time_exceeded = false;
pulse_mode = inputs[PULSE_INPUT].active;

float sampleRate = engineGetSampleRate();

// Compute the length of our idle time based on the knob + time cv
// -or-
// base it one the time since the last clock pulse
if (pulse_mode) {
if (inputTrigger.process(inputs[PULSE_INPUT].value)) {
// keep track of which frame we got a pulse
// FIXME: without a max time, frameCount can wrap?
// update pulseFrame to point to current frame count
pulseFrame = frameCount;

waiting_for_pulse = true;
pulse_seen = true;

}

deltaTime = fmax(frameCount - pulseFrame, 0) / sampleRate;
// if we are waiting, maxframeCount is the time since last pulse and increasing
maxFrameCount = frameCount;

} else {
deltaTime = params[TIME_PARAM].value;
if (inputs[TIME_INPUT].active) {
deltaTime += clamp(inputs[TIME_INPUT].value, 0.0f, 10.0f);
}

// TODO: refactor into submethods if not subclass
maxFrameCount = (int)ceilf(deltaTime * sampleRate);
}

idleTimeoutMS = std::round(deltaTime*1000);

// debug("is_idle: %d pulse_mode: %d pulse_frame: %d frameCount: %d maxFrameCount: %d ", is_idle, pulse_mode, pulseFrame, frameCount, maxFrameCount);
// debug("is_idle: %d pulse_mode: %d w_f_pulse: %d pulse_seen: %d pulseFrame: %d frameCount: %d deltaTime: %f",
// is_idle, pulse_mode, waiting_for_pulse, pulse_seen, pulseFrame, frameCount, deltaTime);

if (inputs[HEARTBEAT_INPUT].active &&
heartbeatTrigger.process(inputs[HEARTBEAT_INPUT].value)) {
frameCount = 0;
}

// time_left_s is always 0 for pulse mode until we predict the future
float frames_left = fmax(maxFrameCount - frameCount, 0);
float time_left_s = frames_left / sampleRate;

// TODO: simplify the start/end/gate on logic... really only a few states to check

// the start of idle (not idle -> idle trans)
if ((frameCount > maxFrameCount) || (waiting_for_pulse && pulse_seen)) {
time_exceeded = true;
if (!is_idle) {
idleStartPulse.trigger(0.01);
}

}

// stay idle once we start until there is an input event
is_idle = (is_idle || time_exceeded);

if (is_idle) {
idleGateOutput = 10.0;

} else {
idleGateOutput = 0.0;

is_idle = false;

// if we arent idle yet, the idleTimeLeft is changing and we need to update time remaining display
// update idletimeLeftMS which drives the digit display widget
idleTimeLeftMS = time_left_s*1000;
}

frameCount++;

if (inputs[INPUT_SOURCE_INPUT].active &&
inputTrigger.process(inputs[INPUT_SOURCE_INPUT].value)) {

// only end idle if we are already idle (idle->not idle transition)
if (is_idle) {
idleEndPulse.trigger(0.01);
}

is_idle = false;

waiting_for_pulse = false;
frameCount = 0;
pulseFrame = 0;
}

// once clock input works, could add an output to indicate how long between clock
// If in pulse mode, deltaTime can be larger than 10s internal, but the max output
// to "Time output" is 10V. ie, after 10s the "Time Output" stops increasing.
outputs[TIME_OUTPUT].value = clamp(deltaTime, 0.0f, 10.0f);
outputs[IDLE_GATE_OUTPUT].value = idleGateOutput;

outputs[IDLE_START_OUTPUT].value = idleStartPulse.process(1.0/engineGetSampleRate()) ? 10.0 : 0.0;
outputs[IDLE_END_OUTPUT].value = idleEndPulse.process(1.0/engineGetSampleRate()) ? 10.0 : 0.0;

}


// From AS DelayPlus.cpp https://github.com/AScustomWorks/AS
struct MsDisplayWidget : TransparentWidget {

int *value;
std::shared_ptr<Font> font;

MsDisplayWidget() {
font = Font::load(assetPlugin(plugin, "res/Segment7Standard.ttf"));
}

void draw(NVGcontext *vg) override {
// Background
// these go to...
NVGcolor backgroundColor = nvgRGB(0x11, 0x11, 0x11);

NVGcolor borderColor = nvgRGB(0xff, 0xff, 0xff);

nvgBeginPath(vg);

nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 5.0);
nvgFillColor(vg, backgroundColor);
nvgFill(vg);

nvgStrokeWidth(vg, 3.0);
nvgStrokeColor(vg, borderColor);

nvgStroke(vg);

// text
nvgFontSize(vg, 18);
nvgFontFaceId(vg, font->handle);
nvgTextLetterSpacing(vg, 2.5);

std::stringstream to_display;
to_display << std::right << std::setw(5) << *value;

Vec textPos = Vec(0.5f, 19.0f);

NVGcolor textColor = nvgRGB(0x65, 0xf6, 0x78);
nvgFillColor(vg, textColor);
nvgText(vg, textPos.x, textPos.y, to_display.str().c_str(), NULL);
}
};


struct IdleSwitchWidget : ModuleWidget {
IdleSwitchWidget(IdleSwitch *module);
};


IdleSwitchWidget::IdleSwitchWidget(IdleSwitch *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(plugin, "res/IdleSwitch.svg")));

addChild(Widget::create<ScrewSilver>(Vec(5, 0)));
addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 20, 365)));

addInput(Port::create<PJ301MPort>(Vec(37, 30.0), Port::INPUT, module, IdleSwitch::INPUT_SOURCE_INPUT));
addInput(Port::create<PJ301MPort>(Vec(37, 70.0), Port::INPUT, module, IdleSwitch::HEARTBEAT_INPUT));
addInput(Port::create<PJ301MPort>(Vec(70, 70.0), Port::INPUT, module, IdleSwitch::PULSE_INPUT));

// idle time display
// FIXME: handle large IdleTimeoutMs (> 99999ms) better
MsDisplayWidget *idle_time_display = new MsDisplayWidget();
idle_time_display->box.pos = Vec(20, 130);
idle_time_display->box.size = Vec(70, 24);
idle_time_display->value = &module->idleTimeoutMS;
addChild(idle_time_display);

addInput(Port::create<PJ301MPort>(Vec(10, 165.0), Port::INPUT, module, IdleSwitch::TIME_INPUT));
addParam(ParamWidget::create<Davies1900hBlackKnob>(Vec(38.86, 160.0), module, IdleSwitch::TIME_PARAM, 0.0, 10.0, 0.25));
addOutput(Port::create<PJ301MPort>(Vec(80, 165.0), Port::OUTPUT, module, IdleSwitch::TIME_OUTPUT));

MsDisplayWidget *time_remaining_display = new MsDisplayWidget();
time_remaining_display->box.pos = Vec(20, 235);
time_remaining_display->box.size = Vec(70, 24);
time_remaining_display->value = &module->idleTimeLeftMS;
addChild(time_remaining_display);

addOutput(Port::create<PJ301MPort>(Vec(10, 295.0), Port::OUTPUT, module, IdleSwitch::IDLE_START_OUTPUT));
addOutput(Port::create<PJ301MPort>(Vec(47.5, 295.0), Port::OUTPUT, module, IdleSwitch::IDLE_GATE_OUTPUT));
addOutput(Port::create<PJ301MPort>(Vec(85, 295.0), Port::OUTPUT, module, IdleSwitch::IDLE_END_OUTPUT));

}

Model *modelIdleSwitch = Model::create<IdleSwitch, IdleSwitchWidget>(
"Alikins", "IdleSwitch", "Idle Switch", SWITCH_TAG , UTILITY_TAG);

+ 0
- 143
repos/Alikins/src/MomentaryOnButtons.cpp View File

@@ -1,143 +0,0 @@
#include <stdio.h>
#include "alikins.hpp"


struct MomentaryOnButtons : Module {
enum ParamIds {
BUTTON1_PARAM,
BUTTON2_PARAM,
BUTTON3_PARAM,
BUTTON4_PARAM,
BUTTON5_PARAM,
BUTTON6_PARAM,
BUTTON7_PARAM,
BUTTON8_PARAM,
BUTTON9_PARAM,
BUTTON10_PARAM,
BUTTON11_PARAM,
BUTTON12_PARAM,
BUTTON13_PARAM,
NUM_PARAMS
};
enum InputIds {
BUTTON1_INPUT,
BUTTON2_INPUT,
BUTTON3_INPUT,
BUTTON4_INPUT,
BUTTON5_INPUT,
BUTTON6_INPUT,
BUTTON7_INPUT,
BUTTON8_INPUT,
BUTTON9_INPUT,
BUTTON10_INPUT,
BUTTON11_INPUT,
BUTTON12_INPUT,
BUTTON13_INPUT,
NUM_INPUTS
};
enum OutputIds {
BUTTON1_OUTPUT,
BUTTON2_OUTPUT,
BUTTON3_OUTPUT,
BUTTON4_OUTPUT,
BUTTON5_OUTPUT,
BUTTON6_OUTPUT,
BUTTON7_OUTPUT,
BUTTON8_OUTPUT,
BUTTON9_OUTPUT,
BUTTON10_OUTPUT,
BUTTON11_OUTPUT,
BUTTON12_OUTPUT,
BUTTON13_OUTPUT,
NUM_OUTPUTS
};
enum LightIds {
BLINK1_LIGHT,
BLINK2_LIGHT,
BLINK3_LIGHT,
BLINK4_LIGHT,
BLINK5_LIGHT,
BLINK6_LIGHT,
BLINK7_LIGHT,
BLINK8_LIGHT,
BLINK9_LIGHT,
BLINK10_LIGHT,
BLINK11_LIGHT,
BLINK12_LIGHT,
BLINK13_LIGHT,
NUM_LIGHTS
};


MomentaryOnButtons() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
void step() override;

// For more advanced Module features, read Rack's engine.hpp header file
// - toJson, fromJson: serialization of internal data
// - onSampleRateChange: event triggered by a change of sample rate
// - reset, randomize: implements special behavior when user clicks these from the context menu
};


void MomentaryOnButtons::step() {

for (int i = 0; i < MOMENTARY_BUTTONS; i++) {

lights[BLINK1_LIGHT + i].setBrightness(0.0);
outputs[BUTTON1_OUTPUT + i].value = 0.0;

if (params[BUTTON1_PARAM + i].value) {
outputs[BUTTON1_OUTPUT + i].value = 5.0;
lights[BLINK1_LIGHT + i].setBrightness(1.0);
}
}
}


struct MomentaryOnButtonsWidget : ModuleWidget {
MomentaryOnButtonsWidget(MomentaryOnButtons *module);
};


MomentaryOnButtonsWidget::MomentaryOnButtonsWidget(MomentaryOnButtons *module) : ModuleWidget(module) {
box.size = Vec(4 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);

int x_offset = 0;
int y_offset = 26;

int x_start = 0;
int y_start = 24;

int x_pos = 0;
int y_pos = 0;

int light_radius = 7;

{
SVGPanel *panel = new SVGPanel();
panel->box.size = box.size;
panel->setBackground(SVG::load(assetPlugin(plugin, "res/MomentaryOnButtons.svg")));
addChild(panel);
}

/*
addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
*/

for (int i = 0; i < MOMENTARY_BUTTONS; i++) {

x_pos = x_start + x_offset;
y_pos = y_start + (i * y_offset);

addParam(ParamWidget::create<LEDButton>(Vec(x_pos + light_radius, y_pos + 3), module, MomentaryOnButtons::BUTTON1_PARAM + i, 0.0, 1.0, 0.0));
addChild(ModuleLightWidget::create<MediumLight<RedLight>>(Vec(x_pos + 5 + light_radius, y_pos + light_radius), module, MomentaryOnButtons::BLINK1_LIGHT + i));

addOutput(Port::create<PJ301MPort>(Vec(x_pos + 20 + light_radius, y_pos), Port::OUTPUT, module, MomentaryOnButtons::BUTTON1_OUTPUT + i));
}
}

Model *modelMomentaryOnButtons = Model::create<MomentaryOnButtons, MomentaryOnButtonsWidget>(
"Alikins", "MomentaryOnButtons", "Momentary On Buttons", UTILITY_TAG);

+ 0
- 19
repos/Alikins/src/alikins.cpp View File

@@ -1,19 +0,0 @@
#include "alikins.hpp"

// The plugin-wide instance of the Plugin class
Plugin *plugin;

void init(rack::Plugin *p) {
plugin = p;
// This is the unique identifier for your plugin
p->slug = TOSTRING(SLUG);
p->version = TOSTRING(VERSION);

p->website = "https://github.com/alikins/Alikins-rack-plugins";
p->manual = "https://github.com/alikins/Alikins-rack-plugins/blob/master/README.md";

p->addModel(modelIdleSwitch);
p->addModel(modelMomentaryOnButtons);
// Any other plugin initialization may go here.
// As an alternative, consider lazy-loading assets and lookup tables when your module is created to reduce startup times of Rack.
}

+ 0
- 15
repos/Alikins/src/alikins.hpp View File

@@ -1,15 +0,0 @@
#include "rack.hpp"

const int MOMENTARY_BUTTONS = 13;
const int INPUT_SOURCES = 1;
using namespace rack;


extern Plugin *plugin;

////////////////////
// module widgets
////////////////////

extern Model *modelIdleSwitch;
extern Model *modelMomentaryOnButtons;

Loading…
Cancel
Save