diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c43514b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+plugin.dylib
+build
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ddeaa34
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+
+SOURCES = $(wildcard src/*.cpp)
+
+include ../../plugin.mk
+
+
+dist: all
+ mkdir -p dist/JW-Modules
+ cp LICENSE* dist/JW-Modules/
+ cp plugin.* dist/JW-Modules/
+ cp -R res dist/JW-Modules/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0adf953
--- /dev/null
+++ b/README.md
@@ -0,0 +1,20 @@
+# JW-Modules
+
+Modules for VCV Rack from https://vcvrack.com/
+
+## Building
+
+Compile Rack from source, following the instructions at https://github.com/VCVRack/Rack.
+
+Check out JW-Modules into the `plugins/` directory
+
+Then run:
+
+ make
+
+## Modules
+
+SimpleClock
+
+
+
diff --git a/res/DejaVuSansMono.ttf b/res/DejaVuSansMono.ttf
new file mode 100644
index 0000000..f578602
Binary files /dev/null and b/res/DejaVuSansMono.ttf differ
diff --git a/res/LICENSE-DejaVu.txt b/res/LICENSE-DejaVu.txt
new file mode 100644
index 0000000..254e2cc
--- /dev/null
+++ b/res/LICENSE-DejaVu.txt
@@ -0,0 +1,99 @@
+Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
+Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
+
+Bitstream Vera Fonts Copyright
+------------------------------
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
+a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute the
+Font Software, including without limitation the rights to use, copy, merge,
+publish, distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright and trademark notices and this permission notice shall
+be included in all copies of one or more of the Font Software typefaces.
+
+The Font Software may be modified, altered, or added to, and in particular
+the designs of glyphs or characters in the Fonts may be modified and
+additional glyphs or characters may be added to the Fonts, only if the fonts
+are renamed to names not containing either the words "Bitstream" or the word
+"Vera".
+
+This License becomes null and void to the extent applicable to Fonts or Font
+Software that has been modified and is distributed under the "Bitstream
+Vera" names.
+
+The Font Software may be sold as part of a larger software package but no
+copy of one or more of the Font Software typefaces may be sold by itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
+TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
+FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
+ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
+FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font Software
+without prior written authorization from the Gnome Foundation or Bitstream
+Inc., respectively. For further information, contact: fonts at gnome dot
+org.
+
+Arev Fonts Copyright
+------------------------------
+
+Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and
+associated documentation files (the "Font Software"), to reproduce
+and distribute the modifications to the Bitstream Vera Font Software,
+including without limitation the rights to use, copy, merge, publish,
+distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Tavmjong Bah" or the word "Arev".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the
+"Tavmjong Bah Arev" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the name of Tavmjong Bah shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealings in this Font Software without prior written authorization
+from Tavmjong Bah. For further information, contact: tavmjong @ free
+. fr.
+
+$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $
diff --git a/res/SimpleClock.png b/res/SimpleClock.png
new file mode 100644
index 0000000..f379a1e
Binary files /dev/null and b/res/SimpleClock.png differ
diff --git a/res/SimpleClock.svg b/res/SimpleClock.svg
new file mode 100644
index 0000000..19cd2d4
--- /dev/null
+++ b/res/SimpleClock.svg
@@ -0,0 +1,164 @@
+
+
+
+
diff --git a/src/JWModules.cpp b/src/JWModules.cpp
new file mode 100644
index 0000000..08f6385
--- /dev/null
+++ b/src/JWModules.cpp
@@ -0,0 +1,12 @@
+#include "JWModules.hpp"
+
+
+Plugin *plugin;
+
+void init(rack::Plugin *p) {
+ plugin = p;
+ plugin->slug = "JW-Modules";
+ plugin->name = "JW-Modules";
+ plugin->homepageUrl = "https://github.com/jeremywen/JW-Modules";
+ createModel(plugin, "SimpleClock", "SimpleClock");
+}
diff --git a/src/JWModules.hpp b/src/JWModules.hpp
new file mode 100644
index 0000000..6a9782d
--- /dev/null
+++ b/src/JWModules.hpp
@@ -0,0 +1,15 @@
+#include "rack.hpp"
+
+
+using namespace rack;
+
+
+extern Plugin *plugin;
+
+////////////////////
+// module widgets
+////////////////////
+
+struct SimpleClockWidget : ModuleWidget {
+ SimpleClockWidget();
+};
diff --git a/src/SimpleClock.cpp b/src/SimpleClock.cpp
new file mode 100644
index 0000000..01961c8
--- /dev/null
+++ b/src/SimpleClock.cpp
@@ -0,0 +1,138 @@
+#include "JWModules.hpp"
+#include "dsp/digital.hpp"
+
+
+struct SimpleClock : Module {
+ enum ParamIds {
+ CLOCK_PARAM,
+ RUN_PARAM,
+ GATE_PARAM,
+ NUM_PARAMS
+ };
+ enum InputIds {
+ CLOCK_INPUT,
+ NUM_INPUTS
+ };
+ enum OutputIds {
+ GATES_OUTPUT,
+ RESET_OUTPUT,
+ NUM_OUTPUTS
+ };
+
+ bool running = true;
+ SchmittTrigger clockTrigger; // for external clock
+ // For buttons
+ SchmittTrigger runningTrigger;
+ SchmittTrigger gateTriggers[8];
+ float phase = 0.0;
+ int index = 0;
+
+ enum GateMode {
+ TRIGGER,
+ RETRIGGER,
+ CONTINUOUS,
+ };
+ GateMode gateMode = TRIGGER;
+ PulseGenerator gatePulse;
+
+ // Lights
+ float runningLight = 0.0;
+
+ SimpleClock() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
+ void step();
+
+ json_t *toJson() {
+ json_t *rootJ = json_object();
+
+ // running
+ json_object_set_new(rootJ, "running", json_boolean(running));
+
+ return rootJ;
+ }
+
+ void fromJson(json_t *rootJ) {
+ // running
+ json_t *runningJ = json_object_get(rootJ, "running");
+ if (runningJ)
+ running = json_is_true(runningJ);
+
+ }
+
+ void initialize() {
+ }
+
+ void randomize() {
+ }
+};
+
+
+void SimpleClock::step() {
+ const float lightLambda = 0.075;
+ // Run
+ if (runningTrigger.process(params[RUN_PARAM].value)) {
+ running = !running;
+ }
+ runningLight = running ? 1.0 : 0.0;
+
+ bool nextStep = false;
+
+ if (running) {
+ // Internal clock
+ float clockTime = powf(2.0, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value);
+ phase += clockTime / gSampleRate;
+ if (phase >= 1.0) {
+ phase -= 1.0;
+ nextStep = true;
+ }
+ }
+
+ if (nextStep) {
+ // Advance step
+ int numSteps = 8;
+ index += 1;
+ if (index >= numSteps) {
+ index = 0;
+ }
+ gatePulse.trigger(1e-3);
+ }
+
+ bool pulse = gatePulse.process(1.0 / gSampleRate);
+
+ // Rows
+ bool gatesOn = running;
+ if (gateMode == TRIGGER)
+ gatesOn = gatesOn && pulse;
+ else if (gateMode == RETRIGGER)
+ gatesOn = gatesOn && !pulse;
+
+ // Outputs
+ outputs[RESET_OUTPUT].value = index == 0 ? 10.0 : 0.0;
+ outputs[GATES_OUTPUT].value = gatesOn ? 10.0 : 0.0;
+}
+
+
+SimpleClockWidget::SimpleClockWidget() {
+ SimpleClock *module = new SimpleClock();
+ setModule(module);
+ box.size = Vec(15*4, 380);
+
+ {
+ SVGPanel *panel = new SVGPanel();
+ panel->box.size = box.size;
+ panel->setBackground(SVG::load(assetPlugin(plugin, "res/SimpleClock.svg")));
+ addChild(panel);
+ }
+
+ addChild(createScrew(Vec(15, 0)));
+ addChild(createScrew(Vec(box.size.x-30, 0)));
+ addChild(createScrew(Vec(15, 365)));
+ addChild(createScrew(Vec(box.size.x-30, 365)));
+
+ addParam(createParam(Vec(16, 50), module, SimpleClock::CLOCK_PARAM, -2.0, 6.0, 2.0));
+
+ addParam(createParam(Vec(21, 130), module, SimpleClock::RUN_PARAM, 0.0, 1.0, 0.0));
+ addChild(createValueLight>(Vec(26, 135), &module->runningLight));
+
+ addOutput(createOutput(Vec(18, 218), module, SimpleClock::RESET_OUTPUT));
+ addOutput(createOutput(Vec(18, 318), module, SimpleClock::GATES_OUTPUT));
+}