shapes, smoothing pwm, etc
This commit is contained in:
parent
b5c815671f
commit
b7c5c27328
8 changed files with 544 additions and 169 deletions
|
|
@ -35,6 +35,7 @@ pico_generate_pio_header(clock ${CMAKE_CURRENT_LIST_DIR}/quadrature_encoder.pio)
|
|||
# Pull in standard library and hardware abstraction
|
||||
target_link_libraries(clock
|
||||
pico_stdlib
|
||||
hardware_pwm
|
||||
hardware_gpio
|
||||
hardware_pio
|
||||
hardware_i2c
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class DisplayHandler {
|
|||
char buffer[32];
|
||||
uint8_t currentScreen;
|
||||
std::string screens[7];
|
||||
std::array<std::string, 5> out_pages = {"Exit", "Mod", "Width", "Prob", "Mute"};
|
||||
std::array<std::string, 9> out_pages = {"Exit", "Mod", "Shape", "Level", "Width", "Swing", "Prob", "Sticky", "Mute"};
|
||||
bool onOutScreen = 0;
|
||||
void renderMainPage();
|
||||
void renderOutPage();
|
||||
|
|
|
|||
|
|
@ -4,27 +4,43 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include "Output.h"
|
||||
#include "globals.h"
|
||||
|
||||
|
||||
|
||||
class Gate : public Output {
|
||||
private:
|
||||
uint32_t dur;
|
||||
uint32_t triggerCount;
|
||||
uint32_t scheduledTick;
|
||||
float currentRandomVal;
|
||||
uint32_t len;
|
||||
uint32_t lastTriggerTick = 0xFFFFFFFF;
|
||||
uint64_t startTimeUs;
|
||||
uint32_t pulseDurationUs;
|
||||
|
||||
public:
|
||||
Gate(uint8_t pin);
|
||||
|
||||
WaveShape shape = SQUARE;
|
||||
uint32_t startTick = 0;
|
||||
uint32_t pulseWidthTicks = 0;
|
||||
bool sticky = false;
|
||||
int8_t modifierSelectionIndex;
|
||||
uint8_t divideMode;
|
||||
uint8_t swing = 50;
|
||||
uint16_t modifier;
|
||||
uint16_t tickInterval;
|
||||
uint8_t level;
|
||||
uint8_t width;
|
||||
uint8_t p;
|
||||
|
||||
void turnOn() override;
|
||||
void update();
|
||||
void turnOff() override;
|
||||
|
||||
void calculatePulseWidth();
|
||||
void writeAnalog(uint16_t val);
|
||||
void setLen(uint32_t currentPeriod);
|
||||
void setDiv(uint8_t modifier_selection_index);
|
||||
void setWidth(uint16_t newWidth);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,29 @@ static constexpr uint8_t PPQN = 96;
|
|||
extern volatile uint32_t MASTER_TICK;
|
||||
|
||||
|
||||
enum WaveShape { SQUARE, TRIANGLE, SAW, RAMP, EXP, HALFSINE, REXP, LOG, SINE, BOUNCE, SIGMO, WOBBLE, STEPDW, STEPUP, SH, SHAPE_COUNT};
|
||||
|
||||
inline const char* waveShapeToString(WaveShape shape) {
|
||||
switch (shape) {
|
||||
case SQUARE: return "SQR";
|
||||
case SINE: return "SINE";
|
||||
case TRIANGLE: return "TRI";
|
||||
case SAW: return "SAW";
|
||||
case EXP: return "EXP";
|
||||
case REXP: return "REXP";
|
||||
case RAMP: return "RAMP";
|
||||
case LOG: return "LOG";
|
||||
case BOUNCE: return "BNC";
|
||||
case WOBBLE: return "WOB";
|
||||
case SIGMO: return "SIG";
|
||||
case STEPDW: return "STPD";
|
||||
case STEPUP: return "STPU";
|
||||
case SH: return "S&H";
|
||||
case HALFSINE: return "HUMP";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
// Modifiers in UI order
|
||||
static std::array<uint8_t, 17> MODIFIERS = {32, 16, 12, 8, 6, 4, 3, 2, 0, 1, 2, 3, 4, 6, 8, 16, 32};
|
||||
// Modifier type; 0 = multiplicaton, 1 = division; matched with MODIFIERS
|
||||
|
|
|
|||
153
master_clock.drawio
Normal file
153
master_clock.drawio
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" version="29.5.2">
|
||||
<diagram name="Page-1" id="-HQHJa_EQfKjo97XYqHl">
|
||||
<mxGraphModel dx="2038" dy="736" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="kG_PlTG_f92uMrFnHzwW-1" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="<font face="Lucida Console">&nbsp; BPM: 120&nbsp;&nbsp;</font><div><font face="Lucida Console">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*<br></font><div><font face="Lucida Console">&nbsp; 1&nbsp; &nbsp; 2&nbsp; &nbsp; 3&nbsp; &nbsp; 4&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</font></div><div><font face="Lucida Console">&nbsp; 5&nbsp; &nbsp; 6&nbsp; &nbsp; 7&nbsp; &nbsp; 8&nbsp;</font></div></div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="180" y="170" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-16" edge="1" parent="1" source="kG_PlTG_f92uMrFnHzwW-3" style="edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontSize=12;startSize=8;endSize=8;" target="7CsQrmOhY3FsypGgTNEZ-15" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="kG_PlTG_f92uMrFnHzwW-3" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: Division<div><br></div><div>&nbsp; /4<span style="background-color: transparent; color: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));">&nbsp;</span></div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="330" y="170" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="kG_PlTG_f92uMrFnHzwW-4" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: Width<div><br></div><div>&nbsp; 50%</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="330" y="260" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="kG_PlTG_f92uMrFnHzwW-5" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: Shape<div><br></div><div>&nbsp; Pulse</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="330" y="350" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="kG_PlTG_f92uMrFnHzwW-6" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: Level<div><br></div><div>&nbsp; 90%</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="330" y="440" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="kG_PlTG_f92uMrFnHzwW-7" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: Probability<div><br></div><div>&nbsp; 100%</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="330" y="530" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="kG_PlTG_f92uMrFnHzwW-10" parent="1" style="triangle;whiteSpace=wrap;html=1;" value="" vertex="1">
|
||||
<mxGeometry height="10" width="10" x="280" y="178" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-11" parent="1" style="pointerEvents=1;verticalLabelPosition=bottom;shadow=0;dashed=0;align=center;html=1;verticalAlign=top;shape=mxgraph.electrical.waveforms.sine_wave;" value="" vertex="1">
|
||||
<mxGeometry height="6.18" width="10" x="280" y="210" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-12" connectable="0" parent="1" style="group" value="" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="-120" y="170" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-1" parent="7CsQrmOhY3FsypGgTNEZ-12" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="<font size="1">&nbsp; 1</font>" vertex="1">
|
||||
<mxGeometry height="70" width="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-2" parent="7CsQrmOhY3FsypGgTNEZ-12" style="pointerEvents=1;verticalLabelPosition=bottom;shadow=0;dashed=0;align=center;html=1;verticalAlign=top;shape=mxgraph.electrical.waveforms.sine_wave;" value="" vertex="1">
|
||||
<mxGeometry height="40" width="100" x="10" y="15" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-3" parent="7CsQrmOhY3FsypGgTNEZ-12" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" value="" vertex="1">
|
||||
<mxGeometry height="10" width="10" x="20" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-4" parent="7CsQrmOhY3FsypGgTNEZ-12" style="rounded=0;whiteSpace=wrap;html=1;" value="" vertex="1">
|
||||
<mxGeometry height="10" width="10" x="30" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-5" parent="7CsQrmOhY3FsypGgTNEZ-12" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" value="" vertex="1">
|
||||
<mxGeometry height="10" width="10" x="40" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-6" parent="7CsQrmOhY3FsypGgTNEZ-12" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" value="" vertex="1">
|
||||
<mxGeometry height="10" width="10" x="50" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-7" parent="7CsQrmOhY3FsypGgTNEZ-12" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" value="" vertex="1">
|
||||
<mxGeometry height="10" width="10" x="60" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-8" parent="7CsQrmOhY3FsypGgTNEZ-12" style="rounded=0;whiteSpace=wrap;html=1;" value="" vertex="1">
|
||||
<mxGeometry height="10" width="10" x="70" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-9" parent="7CsQrmOhY3FsypGgTNEZ-12" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" value="" vertex="1">
|
||||
<mxGeometry height="10" width="10" x="80" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-10" parent="7CsQrmOhY3FsypGgTNEZ-12" style="rounded=0;whiteSpace=wrap;html=1;" value="" vertex="1">
|
||||
<mxGeometry height="10" width="10" x="90" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-13" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="scope mode,&nbsp;<div>long press to main<div>scroll thru channels</div><div>squares at bottom light up when signal is high</div></div>" vertex="1">
|
||||
<mxGeometry height="30" width="120" x="-120" y="280" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-18" edge="1" parent="1" source="7CsQrmOhY3FsypGgTNEZ-15" style="edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontSize=12;startSize=8;endSize=8;" target="7CsQrmOhY3FsypGgTNEZ-17" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-15" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="long press anywhere to change output mode" vertex="1">
|
||||
<mxGeometry height="30" width="120" x="480" y="190" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-20" edge="1" parent="1" source="7CsQrmOhY3FsypGgTNEZ-17" style="edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fontSize=12;startSize=8;endSize=8;">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="540" y="360" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-17" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: MODE<div><br></div><div>GATE, LFO, STRANGE</div><div>TURING, ETC</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="480" y="260" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-19" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="On Select, go back to settings, they will change based on mode" vertex="1">
|
||||
<mxGeometry height="30" width="150" x="470" y="370" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-21" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="GATE MODE" vertex="1">
|
||||
<mxGeometry height="30" width="120" x="330" y="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-22" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="HOME PAGE" vertex="1">
|
||||
<mxGeometry height="30" width="120" x="180" y="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-23" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="SCOPE" vertex="1">
|
||||
<mxGeometry height="30" width="120" x="-120" y="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-24" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="MODE SELECT" vertex="1">
|
||||
<mxGeometry height="30" width="120" x="480" y="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-25" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="STRANGE ATTRACTOR" vertex="1">
|
||||
<mxGeometry height="30" width="120" x="630" y="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-26" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: TYPE<div><br></div><div>&nbsp; LORENZ</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="630" y="170" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-27" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: SPEED<div><br></div><div>&nbsp; SLOW</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="630" y="260" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-28" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: OUTPUT<div><br></div><div>&nbsp; X, Y, Z</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="630" y="350" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-29" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: RAND TARGET<div><br></div><div>&nbsp; X, Y, Z</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="630" y="440" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-30" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: RAND AMT<div><br></div><div>&nbsp; 100%</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="630" y="530" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-43" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="SETTINGS" vertex="1">
|
||||
<mxGeometry height="30" width="120" x="30" y="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-44" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; SAVE/LOAD<div><br></div><div>&nbsp; SAVE</div><div><div><br></div><div>&nbsp;&nbsp;</div></div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="30" y="170" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-46" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; PPQN<div><br></div><div>&nbsp; 24</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="30" y="260" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-47" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; RESET<div><br></div><div>&nbsp; YES</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="30" y="350" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-48" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; EXIT<div><br></div><div>&nbsp; &lt;--</div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="30" y="440" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-49" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: CV SOURCE<div><br><div>&nbsp; EXT 1, EXT 2, INT 1</div></div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="330" y="620" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-50" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: CV TARGET<div><br><div>&nbsp; Width</div></div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="330" y="710" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-51" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: CV LEVEL<div><br><div>&nbsp; 100%</div></div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="330" y="800" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-52" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: CV SOURCE<div><br><div>&nbsp; EXT 1, EXT 2, INT 1</div></div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="630" y="620" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-53" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: CV TARGET<div><br><div>&nbsp; Width</div></div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="630" y="710" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7CsQrmOhY3FsypGgTNEZ-54" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;align=left;verticalAlign=top;" value="&nbsp; 1: CV LEVEL<div><br><div>&nbsp; 100%</div></div>" vertex="1">
|
||||
<mxGeometry height="70" width="120" x="630" y="800" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
|
@ -78,7 +78,43 @@ void DisplayHandler::moveCursor(bool dir) {
|
|||
outputs[currentOut]->modifierSelectionIndex = std::size(MOD_TYPES) - 1;
|
||||
}
|
||||
|
||||
} else if (currentScreen == 2) { // width control
|
||||
} else if (currentScreen == 2) { // shape control
|
||||
int currentShape = (int)outputs[currentOut]->shape;
|
||||
|
||||
if (dir == 1) {
|
||||
currentShape++;
|
||||
} else {
|
||||
currentShape--;
|
||||
}
|
||||
|
||||
if (currentShape >= SHAPE_COUNT) {
|
||||
currentShape = 0;
|
||||
}
|
||||
|
||||
if (currentShape < 0) {
|
||||
currentShape = SHAPE_COUNT - 1;
|
||||
}
|
||||
|
||||
outputs[currentOut]->shape = (WaveShape)currentShape;
|
||||
outputs[currentOut]->writeAnalog(0);
|
||||
|
||||
} else if (currentScreen == 3) { // level control
|
||||
outputs[currentOut]->editing = 1;
|
||||
if (dir == 1) {
|
||||
outputs[currentOut]->level++;
|
||||
} else {
|
||||
outputs[currentOut]->level--;
|
||||
}
|
||||
|
||||
if (outputs[currentOut]->level > 100) {
|
||||
outputs[currentOut]->level = 100;
|
||||
}
|
||||
|
||||
if (outputs[currentOut]->level < 1) {
|
||||
outputs[currentOut]->level = 1;
|
||||
}
|
||||
|
||||
} else if (currentScreen == 4) { // width control
|
||||
outputs[currentOut]->editing = 1;
|
||||
if (dir == 1) {
|
||||
outputs[currentOut]->width++;
|
||||
|
|
@ -96,7 +132,23 @@ void DisplayHandler::moveCursor(bool dir) {
|
|||
|
||||
outputs[currentOut]->setWidth(outputs[currentOut]->width);
|
||||
|
||||
} else if (currentScreen == 3) { // PROBABILITY
|
||||
} else if (currentScreen == 5) { // SWING
|
||||
|
||||
outputs[currentOut]->editing = 1;
|
||||
if (dir == 1) {
|
||||
outputs[currentOut]->swing++;
|
||||
} else {
|
||||
outputs[currentOut]->swing--;
|
||||
}
|
||||
|
||||
if (outputs[currentOut]->swing > 100) {
|
||||
outputs[currentOut]->swing = 100;
|
||||
}
|
||||
|
||||
if (outputs[currentOut]->swing < 50) {
|
||||
outputs[currentOut]->swing = 50;
|
||||
}
|
||||
} else if (currentScreen == 6) { // PROBABILITY
|
||||
|
||||
outputs[currentOut]->editing = 1;
|
||||
if (dir == 1) {
|
||||
|
|
@ -112,7 +164,10 @@ void DisplayHandler::moveCursor(bool dir) {
|
|||
if (outputs[currentOut]->p < 0) {
|
||||
outputs[currentOut]->p = 0;
|
||||
}
|
||||
} else if (currentScreen == 4) { // MUTE
|
||||
} else if (currentScreen == 7) { // STICKY
|
||||
outputs[currentOut]->sticky ^= true;
|
||||
|
||||
} else if (currentScreen == 8) { // MUTE
|
||||
|
||||
outputs[currentOut]->editing = 1;
|
||||
outputs[currentOut]->isEnabled ^= true;
|
||||
|
|
@ -267,12 +322,25 @@ void DisplayHandler::renderOutPage() {
|
|||
uint8_t modifier_selection_index = outputs[currentOut]->modifierSelectionIndex;
|
||||
param_string = MODIFIER_STRINGS[modifier_selection_index];
|
||||
|
||||
} else if (currentScreen == 2) { // Width screen
|
||||
} else if (currentScreen == 2) { // shape screen
|
||||
param_string = waveShapeToString(outputs[currentOut]->shape);
|
||||
|
||||
} else if (currentScreen == 3) { // level screen
|
||||
param_string = std::to_string(outputs[currentOut]->level) + "%";
|
||||
|
||||
} else if (currentScreen == 4) { // Width screen
|
||||
param_string = std::to_string(outputs[currentOut]->width) + "%";
|
||||
|
||||
} else if (currentScreen == 3) { // Probability screen
|
||||
} else if (currentScreen == 5) { // Swing screen
|
||||
param_string = std::to_string(outputs[currentOut]->swing) + "%";
|
||||
|
||||
} else if (currentScreen == 6) { // Probability screen
|
||||
param_string = std::to_string(outputs[currentOut]->p) + "%";
|
||||
} else if (currentScreen == 4) { // Mute Screen
|
||||
|
||||
} else if (currentScreen == 7) { // STICKY Screen
|
||||
param_string = outputs[currentOut]->sticky ? "ON" : "OFF";
|
||||
|
||||
} else if (currentScreen == 8) { // Mute Screen
|
||||
param_string = outputs[currentOut]->isEnabled ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
|
|
|
|||
151
src/Gate.cpp
151
src/Gate.cpp
|
|
@ -1,10 +1,11 @@
|
|||
// Gate.cpp
|
||||
#include "Gate.h"
|
||||
#include "globals.h"
|
||||
#include "hardware/pwm.h"
|
||||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
Gate::Gate(uint8_t pin) : Output(pin){
|
||||
Gate::Gate(uint8_t pin) : Output(pin) {
|
||||
this->pin = pin;
|
||||
state = 0;
|
||||
|
||||
|
|
@ -19,16 +20,15 @@ Gate::Gate(uint8_t pin) : Output(pin){
|
|||
len = 0; // max len a pulse can be on, as determined by width
|
||||
|
||||
p = 100; // probability of a pulse
|
||||
level = 100;
|
||||
}
|
||||
|
||||
|
||||
void Gate::setLen(uint32_t currentPeriod) {
|
||||
len = (uint32_t)((double)currentPeriod * (width / 100.0) / 1000.0);
|
||||
}
|
||||
|
||||
|
||||
void Gate::setDiv(uint8_t modifier_selecton_index) {
|
||||
switch(modifier_selecton_index) {
|
||||
switch (modifier_selecton_index) {
|
||||
case 0: // x32
|
||||
tickInterval = 3;
|
||||
isEnabled = true;
|
||||
|
|
@ -137,11 +137,11 @@ void Gate::setDiv(uint8_t modifier_selecton_index) {
|
|||
divideMode = 1;
|
||||
}
|
||||
|
||||
// TODO: check if this is actually needed
|
||||
setWidth(this->width);
|
||||
// this is called in width, check if needed still?
|
||||
calculatePulseWidth();
|
||||
};
|
||||
|
||||
|
||||
void Gate::setWidth(uint16_t newWidth) {
|
||||
this->width = newWidth;
|
||||
|
||||
|
|
@ -151,46 +151,147 @@ void Gate::setWidth(uint16_t newWidth) {
|
|||
|
||||
this->len = (uint32_t)(ms_between_triggers * (this->width / 100.0));
|
||||
|
||||
uint32_t max_allowed_len = (ms_between_triggers > 5) ? (uint32_t)ms_between_triggers - 2 : 1;
|
||||
uint32_t max_allowed_len =
|
||||
(ms_between_triggers > 5) ? (uint32_t)ms_between_triggers - 2 : 1;
|
||||
|
||||
if (this->len > max_allowed_len) {
|
||||
this->len = max_allowed_len;
|
||||
}
|
||||
|
||||
if (this->len < 1) this->len = 1;
|
||||
if (this->len < 1)
|
||||
this->len = 1;
|
||||
|
||||
double us_per_tick = 625000.0 / (double)BPM;
|
||||
|
||||
calculatePulseWidth();
|
||||
|
||||
this->pulseDurationUs =
|
||||
(uint32_t)(us_per_tick * (double)this->pulseWidthTicks);
|
||||
|
||||
if (this->pulseDurationUs < 100)
|
||||
this->pulseDurationUs = 100;
|
||||
}
|
||||
|
||||
void Gate::calculatePulseWidth() {
|
||||
if (tickInterval == 0 || !isEnabled) {
|
||||
pulseWidthTicks = 0;
|
||||
return;
|
||||
}
|
||||
// If tickInterval is 96 and width is 50, pulseWidthTicks becomes 48
|
||||
this->pulseWidthTicks =
|
||||
(uint32_t)((float)this->tickInterval * (this->width / 100.0f));
|
||||
|
||||
// Safety: ensure a pulse is at least 1 tick long if width > 0
|
||||
if (this->width > 0 && this->pulseWidthTicks == 0) {
|
||||
this->pulseWidthTicks = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Gate::turnOn() {
|
||||
if (!isEnabled || tickInterval == 0) return;
|
||||
if (!isEnabled || tickInterval == 0)
|
||||
return;
|
||||
|
||||
if (MASTER_TICK % tickInterval == 0) {
|
||||
if (MASTER_TICK != lastTriggerTick) {
|
||||
lastTriggerTick = MASTER_TICK;
|
||||
|
||||
uint8_t pRes = 1;
|
||||
if (p < 100) {
|
||||
if ((rand() % 100) + 1 > p) pRes = 0;
|
||||
if (p < 100 && (rand() % 100) + 1 > p) {
|
||||
scheduledTick = 0xFFFFFFFF; // ignore interval
|
||||
return;
|
||||
}
|
||||
|
||||
if (pRes == 1) {
|
||||
// swing
|
||||
triggerCount++;
|
||||
|
||||
uint32_t swingDelayTicks =
|
||||
(uint32_t)((float)tickInterval * ((float)swing - 50.0f) / 100.0f);
|
||||
|
||||
if (triggerCount % 2 == 0) {
|
||||
scheduledTick = MASTER_TICK + swingDelayTicks;
|
||||
} else {
|
||||
scheduledTick = MASTER_TICK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MASTER_TICK == scheduledTick && !state) {
|
||||
state = 1;
|
||||
gpio_put(pin, 1);
|
||||
dur = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
lastTriggerTick = 0xFFFFFFFF;
|
||||
startTick = MASTER_TICK;
|
||||
startTimeUs = time_us_64();
|
||||
currentRandomVal = (float)rand() / (float)RAND_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void Gate::update() {
|
||||
if (!state && !sticky)
|
||||
return;
|
||||
|
||||
void Gate::turnOff() {
|
||||
if (state == 1) {
|
||||
if (millis() - dur >= len) {
|
||||
uint64_t now = time_us_64();
|
||||
uint32_t elapsedUs = (uint32_t)(now - startTimeUs);
|
||||
|
||||
if (elapsedUs >= pulseDurationUs) {
|
||||
state = 0;
|
||||
gpio_put(pin, 0);
|
||||
if (!sticky)
|
||||
writeAnalog(0);
|
||||
return;
|
||||
}
|
||||
|
||||
float phase = (float)elapsedUs / (float)pulseDurationUs;
|
||||
float outVal = 0;
|
||||
|
||||
switch (shape) {
|
||||
case SINE:
|
||||
outVal = (sinf(phase * 2.0f * 3.14159f) * 0.5f) + 0.5f;
|
||||
break;
|
||||
case HALFSINE: // AKA HUMP
|
||||
outVal = sinf(phase * 3.14159f);
|
||||
break;
|
||||
case TRIANGLE:
|
||||
outVal = (phase < 0.5f) ? (phase * 2.0f) : (2.0f - (phase * 2.0f));
|
||||
break;
|
||||
case SAW:
|
||||
outVal = 1.0f - phase;
|
||||
break;
|
||||
case RAMP:
|
||||
outVal = phase;
|
||||
break;
|
||||
case EXP:
|
||||
outVal = expf(-5.0f * phase);
|
||||
break;
|
||||
case REXP:
|
||||
outVal = expf(5.0f * (phase - 1.0f));
|
||||
break;
|
||||
case LOG:
|
||||
outVal = 1.0f - expf(-5.0f * phase);
|
||||
break;
|
||||
case SQUARE:
|
||||
outVal = 1.0f;
|
||||
break;
|
||||
case BOUNCE:
|
||||
outVal = fabsf(sinf(phase * 3.14159f * 2.0f));
|
||||
break;
|
||||
case SIGMO:
|
||||
outVal = phase * phase * (3.0f - 2.0f * phase);
|
||||
break;
|
||||
case WOBBLE:
|
||||
outVal = expf(-3.0f * phase) * cosf(phase * 3.14159f * 4.0f);
|
||||
if (outVal < 0)
|
||||
outVal = 0;
|
||||
break;
|
||||
case STEPDW:
|
||||
outVal = 1.0f - (floorf(phase * 4.0f) / 3.0f);
|
||||
break;
|
||||
case STEPUP:
|
||||
outVal = floorf(phase * 4.0f) / 3.0f;
|
||||
break;
|
||||
case SH:
|
||||
outVal = currentRandomVal;
|
||||
break;
|
||||
}
|
||||
|
||||
writeAnalog((outVal * 1023.0f) * ((float)level / 100));
|
||||
}
|
||||
|
||||
void Gate::writeAnalog(uint16_t val) { pwm_set_gpio_level(pin, val); }
|
||||
|
||||
void Gate::turnOff() { writeAnalog(0); }
|
||||
|
|
|
|||
17
src/main.cpp
17
src/main.cpp
|
|
@ -10,6 +10,7 @@
|
|||
#include "Gate.h"
|
||||
#include "DisplayHandler.h"
|
||||
#include "EncoderHandler.h"
|
||||
#include "hardware/pwm.h"
|
||||
|
||||
|
||||
// Time based operations
|
||||
|
|
@ -38,7 +39,6 @@ static DisplayHandler display_handler(outputs);
|
|||
static EncoderHandler encoder_handler(&display_handler);
|
||||
|
||||
|
||||
|
||||
bool timer_callback(struct repeating_timer *t) {
|
||||
if (PLAY == 1) {
|
||||
MASTER_TICK += 1;
|
||||
|
|
@ -67,6 +67,11 @@ void update_BPM(bool up) {
|
|||
}
|
||||
|
||||
update_period();
|
||||
|
||||
|
||||
for (auto g : outputs) {
|
||||
g->setWidth(g->width);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -86,6 +91,14 @@ void setup_outs() {
|
|||
for (auto g : outputs) {
|
||||
gpio_init(g->pin);
|
||||
gpio_set_dir(g->pin, GPIO_OUT);
|
||||
|
||||
gpio_set_function(g->pin, GPIO_FUNC_PWM);
|
||||
uint slice_num = pwm_gpio_to_slice_num(g->pin);
|
||||
pwm_set_wrap(slice_num, 1023);
|
||||
pwm_set_clkdiv(slice_num, 1.0f);
|
||||
|
||||
pwm_set_gpio_level(g->pin, 0);
|
||||
pwm_set_enabled(slice_num, true);
|
||||
g->setLen(period_us);
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +111,7 @@ void setup_outs() {
|
|||
void handle_outs() {
|
||||
for (Gate* g: outputs) {
|
||||
g->turnOn();
|
||||
g->turnOff();
|
||||
g->update();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue