Skip to content

Commit

Permalink
ops to support dual w/2.0 (#332)
Browse files Browse the repository at this point in the history
  • Loading branch information
scanner-darkly committed Dec 18, 2023
1 parent aefeda4 commit 56c1268
Show file tree
Hide file tree
Showing 21 changed files with 246 additions and 90 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -34,6 +34,7 @@
- **NEW**: new Disting EX ops: `EX.CH`, `EX.#`, `EX.N#`, `EX.NO#`
- **NEW**: apply VCV Rack compatibility patches, so branches off main can be used in both hardware and software
- **FIX**: update Disting EX looper ops to work with Disting EX firmware 1.23+
- **NEW**: new dual W/ ops: `W/.SEL`, `W/S.POLY`, `W/S.POLY.RESET`, `W/1`, `W/2`

## v4.0.0

Expand Down
8 changes: 8 additions & 0 deletions docs/ops/wslash_shared.md
@@ -0,0 +1,8 @@
## W/2.0

More extensively covered in the [W/ Documentation](https://www.whimsicalraps.com/pages/w-type).

There are separate ops for each supported algorithm: delay, synth, tape. Two
units can be connected using a different i2c address (refer to the official
documentation for more details). The following section describes ops that
control which unit is selected. These ops apply to all algorithms.
11 changes: 11 additions & 0 deletions docs/ops/wslash_shared.toml
@@ -0,0 +1,11 @@
["W/.SEL"]
prototype = "W/.SEL x"
short = "Sets target W/2.0 unit (`1` = primary, `2` = secondary)."

["W/1"]
prototype = "W/1: ..."
short = "Send following W/2.0 OPs to unit 1 ignoring the currently selected unit."

["W/2"]
prototype = "W/2: ..."
short = "Send following W/2.0 OPs to unit 2 ignoring the currently selected unit."
8 changes: 8 additions & 0 deletions docs/ops/wslashsynth.toml
Expand Up @@ -14,6 +14,14 @@ short = "set `voice` (s8) to `pitch` (s16V) and strike the vactrol at `velocity`
prototype = "W/S.NOTE pitch level"
short = "dynamically assign a voice, set to `pitch` (s16V), strike with `velocity`(s16V)"

["W/S.POLY"]
prototype = "W/S.POLY pitch level"
short = "As `W/S.NOTE` but across dual W/. Switches between primary and secondary units every 4 notes or until reset using `W/S.POLY.RESET`."

["W/S.POLY.RESET"]
prototype = "W/S.POLY.RESET"
short = "Resets `W/S.POLY` note count."

["W/S.AR.MODE"]
prototype = "W/S.AR.MODE is_ar"
short = "in attack-release mode, all notes are `plucked` and no `release` is required'"
Expand Down
1 change: 1 addition & 0 deletions docs/whats_new.md
Expand Up @@ -32,6 +32,7 @@
- **NEW**: new Disting EX ops: `EX.CH`, `EX.#`, `EX.N#`, `EX.NO#`
- **NEW**: apply VCV Rack compatibility patches, so branches off main can be used in both hardware and software
- **FIX**: update Disting EX looper ops to work with Disting EX firmware 1.23+
- **NEW**: new dual W/ ops: `W/.SEL`, `W/S.POLY`, `W/S.POLY.RESET`, `W/1`, `W/2`

## v4.0.0

Expand Down
1 change: 1 addition & 0 deletions module/config.mk
Expand Up @@ -114,6 +114,7 @@ CSRCS = \
../src/ops/variables.c \
../src/ops/whitewhale.c \
../src/ops/wslash.c \
../src/ops/wslash_shared.c \
../src/ops/wslashsynth.c \
../src/ops/wslashdelay.c \
../src/ops/wslashtape.c \
Expand Down
2 changes: 1 addition & 1 deletion simulator/Makefile
Expand Up @@ -15,7 +15,7 @@ OBJ = tt.o ../src/teletype.o ../src/command.o ../src/helpers.o ../src/drum_helpe
../src/ops/fader.o ../src/ops/matrixarchate.o ../src/ops/wslash.o \
../src/ops/seed.o ../src/ops/i2c.o ../src/ops/disting.o \
../src/ops/wslashtape.o ../src/ops/wslashsynth.o ../src/ops/wslashdelay.o \
../src/ops/crow.o ../src/ops/i2c2midi.o\
../src/ops/wslash_shared.o ../src/ops/crow.o ../src/ops/i2c2midi.o\
../libavr32/src/euclidean/euclidean.o ../libavr32/src/euclidean/data.o \
../libavr32/src/music.o ../libavr32/src/util.o ../libavr32/src/random.o \
../src/ops/midi.o
Expand Down
35 changes: 21 additions & 14 deletions src/match_token.rl
Expand Up @@ -740,6 +740,7 @@
"WS.REC" => { MATCH_OP(E_OP_WS_REC); };
"WS.CUE" => { MATCH_OP(E_OP_WS_CUE); };
"WS.LOOP" => { MATCH_OP(E_OP_WS_LOOP); };
"W/.SEL" => { MATCH_OP(E_OP_WS_SEL); };

# disting ex
"EX" => { MATCH_OP(E_OP_EX); };
Expand Down Expand Up @@ -830,20 +831,22 @@
"EX.ZO2" => { MATCH_OP(E_OP_EX_ZO2); };

# w/s
"W/S.PITCH" => { MATCH_OP(E_OP_WS_S_PITCH); };
"W/S.VEL" => { MATCH_OP(E_OP_WS_S_VEL); };
"W/S.VOX" => { MATCH_OP(E_OP_WS_S_VOX); };
"W/S.NOTE" => { MATCH_OP(E_OP_WS_S_NOTE); };
"W/S.AR.MODE" => { MATCH_OP(E_OP_WS_S_AR_MODE); };
"W/S.LPG.TIME" => { MATCH_OP(E_OP_WS_S_LPG_TIME); };
"W/S.LPG.SYM" => { MATCH_OP(E_OP_WS_S_LPG_SYMMETRY); };
"W/S.CURVE" => { MATCH_OP(E_OP_WS_S_CURVE); };
"W/S.RAMP" => { MATCH_OP(E_OP_WS_S_RAMP); };
"W/S.FM.INDEX" => { MATCH_OP(E_OP_WS_S_FM_INDEX); };
"W/S.FM.RATIO" => { MATCH_OP(E_OP_WS_S_FM_RATIO); };
"W/S.FM.ENV" => { MATCH_OP(E_OP_WS_S_FM_ENV); };
"W/S.PATCH" => { MATCH_OP(E_OP_WS_S_PATCH); };
"W/S.VOICES" => { MATCH_OP(E_OP_WS_S_VOICES); };
"W/S.PITCH" => { MATCH_OP(E_OP_WS_S_PITCH); };
"W/S.VEL" => { MATCH_OP(E_OP_WS_S_VEL); };
"W/S.VOX" => { MATCH_OP(E_OP_WS_S_VOX); };
"W/S.NOTE" => { MATCH_OP(E_OP_WS_S_NOTE); };
"W/S.POLY" => { MATCH_OP(E_OP_WS_S_POLY); };
"W/S.POLY.RESET" => { MATCH_OP(E_OP_WS_S_POLY_RESET); };
"W/S.AR.MODE" => { MATCH_OP(E_OP_WS_S_AR_MODE); };
"W/S.LPG.TIME" => { MATCH_OP(E_OP_WS_S_LPG_TIME); };
"W/S.LPG.SYM" => { MATCH_OP(E_OP_WS_S_LPG_SYMMETRY); };
"W/S.CURVE" => { MATCH_OP(E_OP_WS_S_CURVE); };
"W/S.RAMP" => { MATCH_OP(E_OP_WS_S_RAMP); };
"W/S.FM.INDEX" => { MATCH_OP(E_OP_WS_S_FM_INDEX); };
"W/S.FM.RATIO" => { MATCH_OP(E_OP_WS_S_FM_RATIO); };
"W/S.FM.ENV" => { MATCH_OP(E_OP_WS_S_FM_ENV); };
"W/S.PATCH" => { MATCH_OP(E_OP_WS_S_PATCH); };
"W/S.VOICES" => { MATCH_OP(E_OP_WS_S_VOICES); };

# w/d
"W/D.FBK" => { MATCH_OP(E_OP_WS_D_FEEDBACK); };
Expand Down Expand Up @@ -1069,6 +1072,10 @@
"JF1" => { MATCH_MOD(E_MOD_JF1); };
"JF2" => { MATCH_MOD(E_MOD_JF2); };

# w/
"W/1" => { MATCH_MOD(E_MOD_WS1); };
"W/2" => { MATCH_MOD(E_MOD_WS2); };

# crow
"CROWN" => { MATCH_MOD(E_MOD_CROWN); };
"CROW1" => { MATCH_MOD(E_MOD_CROW1); };
Expand Down
8 changes: 6 additions & 2 deletions src/ops/op.c
Expand Up @@ -32,6 +32,7 @@
#include "ops/variables.h"
#include "ops/whitewhale.h"
#include "ops/wslash.h"
#include "ops/wslash_shared.h"
#include "ops/wslashdelay.h"
#include "ops/wslashsynth.h"
#include "ops/wslashtape.h"
Expand Down Expand Up @@ -166,13 +167,13 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = {
&op_JF_POLY_RESET, &op_JF_SEL,

// W/
&op_WS_PLAY, &op_WS_REC, &op_WS_CUE, &op_WS_LOOP,
&op_WS_PLAY, &op_WS_REC, &op_WS_CUE, &op_WS_LOOP, &op_WS_SEL,

// W/S
&op_WS_S_PITCH, &op_WS_S_VEL, &op_WS_S_VOX, &op_WS_S_NOTE, &op_WS_S_AR_MODE,
&op_WS_S_LPG_TIME, &op_WS_S_LPG_SYMMETRY, &op_WS_S_CURVE, &op_WS_S_RAMP,
&op_WS_S_FM_INDEX, &op_WS_S_FM_RATIO, &op_WS_S_FM_ENV, &op_WS_S_VOICES,
&op_WS_S_PATCH,
&op_WS_S_PATCH, &op_WS_S_POLY, &op_WS_S_POLY_RESET,

// W/D
&op_WS_D_FEEDBACK, &op_WS_D_MIX, &op_WS_D_LOWPASS, &op_WS_D_FREEZE,
Expand Down Expand Up @@ -346,6 +347,9 @@ const tele_mod_t *tele_mods[E_MOD__LENGTH] = {
// just friends
&mod_JF0, &mod_JF1, &mod_JF2,

// w/
&mod_WS1, &mod_WS2,

// crow
&mod_CROWN, &mod_CROW1, &mod_CROW2, &mod_CROW3, &mod_CROW4
};
Expand Down
5 changes: 5 additions & 0 deletions src/ops/op_enum.h
Expand Up @@ -451,6 +451,7 @@ typedef enum {
E_OP_WS_REC,
E_OP_WS_CUE,
E_OP_WS_LOOP,
E_OP_WS_SEL,
E_OP_WS_S_PITCH,
E_OP_WS_S_VEL,
E_OP_WS_S_VOX,
Expand All @@ -465,6 +466,8 @@ typedef enum {
E_OP_WS_S_FM_ENV,
E_OP_WS_S_VOICES,
E_OP_WS_S_PATCH,
E_OP_WS_S_POLY,
E_OP_WS_S_POLY_RESET,
E_OP_WS_D_FEEDBACK,
E_OP_WS_D_MIX,
E_OP_WS_D_LOWPASS,
Expand Down Expand Up @@ -990,6 +993,8 @@ typedef enum {
E_MOD_JF0,
E_MOD_JF1,
E_MOD_JF2,
E_MOD_WS1,
E_MOD_WS2,
E_MOD_CROWN,
E_MOD_CROW1,
E_MOD_CROW2,
Expand Down
47 changes: 47 additions & 0 deletions src/ops/wslash_shared.c
@@ -0,0 +1,47 @@
#include "ops/wslash_shared.h"

#include "helpers.h"
#include "teletype.h"

static void mod_WS1_func(scene_state_t *ss, exec_state_t *es,
command_state_t *cs,
const tele_command_t *post_command);
static void mod_WS2_func(scene_state_t *ss, exec_state_t *es,
command_state_t *cs,
const tele_command_t *post_command);
static void op_WS_SEL_get(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);

// clang-format off

const tele_mod_t mod_WS1 = MAKE_MOD(W/1, mod_WS1_func, 0);
const tele_mod_t mod_WS2 = MAKE_MOD(W/2, mod_WS2_func, 0);
const tele_op_t op_WS_SEL = MAKE_GET_OP(W/.SEL, op_WS_SEL_get , 1, false);

// clang-format on

uint8_t wslash_unit = 1;

static void mod_WS1_func(scene_state_t *ss, exec_state_t *es,
command_state_t *cs,
const tele_command_t *post_command) {
u8 u = wslash_unit;
wslash_unit = 1;
process_command(ss, es, post_command);
wslash_unit = u;
}

static void mod_WS2_func(scene_state_t *ss, exec_state_t *es,
command_state_t *cs,
const tele_command_t *post_command) {
u8 u = wslash_unit;
wslash_unit = 2;
process_command(ss, es, post_command);
wslash_unit = u;
}

static void op_WS_SEL_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es), command_state_t *cs) {
u8 unit = cs_pop(cs);
if (unit > 0 && unit < 3) wslash_unit = unit;
}
13 changes: 13 additions & 0 deletions src/ops/wslash_shared.h
@@ -0,0 +1,13 @@
#ifndef _OPS_WSLASH_SHARED_H_
#define _OPS_WSLASH_SHARED_H_

#include "ops/op.h"

extern const tele_mod_t mod_WS1;
extern const tele_mod_t mod_WS2;

extern const tele_op_t op_WS_SEL;

extern uint8_t wslash_unit;

#endif
53 changes: 28 additions & 25 deletions src/ops/wslashdelay.c
Expand Up @@ -3,33 +3,36 @@
#include "helpers.h"
#include "i2c.h"
#include "ii.h"
#include "ops/wslash_shared.h"
#include "teletype_io.h"

I2C_WRITE_16(op_WS_D_FEEDBACK_write, WS_D_ADDR, WS_D_FEEDBACK)
I2C_RECV_16(op_WS_D_FEEDBACK_recv, WS_D_ADDR, WS_D_FEEDBACK)
I2C_WRITE_16(op_WS_D_MIX_write, WS_D_ADDR, WS_D_MIX)
I2C_RECV_16(op_WS_D_MIX_recv, WS_D_ADDR, WS_D_MIX)
I2C_WRITE_16(op_WS_D_LOWPASS_write, WS_D_ADDR, WS_D_LOWPASS)
I2C_RECV_16(op_WS_D_LOWPASS_recv, WS_D_ADDR, WS_D_LOWPASS)
I2C_WRITE_8(op_WS_D_FREEZE_write, WS_D_ADDR, WS_D_FREEZE)
I2C_RECV_8(op_WS_D_FREEZE_recv, WS_D_ADDR, WS_D_FREEZE)
I2C_WRITE_16(op_WS_D_TIME_write, WS_D_ADDR, WS_D_TIME)
I2C_RECV_16(op_WS_D_TIME_recv, WS_D_ADDR, WS_D_TIME)
I2C_WRITE_8_8(op_WS_D_LENGTH_write, WS_D_ADDR, WS_D_LENGTH)
I2C_WRITE_8_8(op_WS_D_POSITION_write, WS_D_ADDR, WS_D_POSITION)
I2C_WRITE_8_8(op_WS_D_CUT_write, WS_D_ADDR, WS_D_CUT)
I2C_WRITE_8(op_WS_D_FREQ_RANGE_write, WS_D_ADDR, WS_D_FREQ_RANGE)
I2C_WRITE_16(op_WS_D_RATE_write, WS_D_ADDR, WS_D_RATE)
I2C_RECV_16(op_WS_D_RATE_recv, WS_D_ADDR, WS_D_RATE)
I2C_WRITE_16(op_WS_D_FREQ_write, WS_D_ADDR, WS_D_FREQ)
I2C_RECV_16(op_WS_D_FREQ_recv, WS_D_ADDR, WS_D_FREQ)
I2C_WRITE_0(op_WS_D_CLK_write, WS_D_ADDR, WS_D_CLK)
I2C_WRITE_8_8(op_WS_D_CLK_RATIO_write, WS_D_ADDR, WS_D_CLK_RATIO)
I2C_WRITE_16(op_WS_D_PLUCK_write, WS_D_ADDR, WS_D_PLUCK)
I2C_WRITE_16(op_WS_D_MOD_RATE_write, WS_D_ADDR, WS_D_MOD_RATE)
I2C_RECV_16(op_WS_D_MOD_RATE_recv, WS_D_ADDR, WS_D_MOD_RATE)
I2C_WRITE_16(op_WS_D_MOD_AMOUNT_write, WS_D_ADDR, WS_D_MOD_AMOUNT)
I2C_RECV_16(op_WS_D_MOD_AMOUNT_recv, WS_D_ADDR, WS_D_MOD_AMOUNT)
#define WS_ADDR (wslash_unit == 2 ? WS_D_ADDR_2 : WS_D_ADDR)

I2C_WRITE_16(op_WS_D_FEEDBACK_write, WS_ADDR, WS_D_FEEDBACK)
I2C_RECV_16(op_WS_D_FEEDBACK_recv, WS_ADDR, WS_D_FEEDBACK)
I2C_WRITE_16(op_WS_D_MIX_write, WS_ADDR, WS_D_MIX)
I2C_RECV_16(op_WS_D_MIX_recv, WS_ADDR, WS_D_MIX)
I2C_WRITE_16(op_WS_D_LOWPASS_write, WS_ADDR, WS_D_LOWPASS)
I2C_RECV_16(op_WS_D_LOWPASS_recv, WS_ADDR, WS_D_LOWPASS)
I2C_WRITE_8(op_WS_D_FREEZE_write, WS_ADDR, WS_D_FREEZE)
I2C_RECV_8(op_WS_D_FREEZE_recv, WS_ADDR, WS_D_FREEZE)
I2C_WRITE_16(op_WS_D_TIME_write, WS_ADDR, WS_D_TIME)
I2C_RECV_16(op_WS_D_TIME_recv, WS_ADDR, WS_D_TIME)
I2C_WRITE_8_8(op_WS_D_LENGTH_write, WS_ADDR, WS_D_LENGTH)
I2C_WRITE_8_8(op_WS_D_POSITION_write, WS_ADDR, WS_D_POSITION)
I2C_WRITE_8_8(op_WS_D_CUT_write, WS_ADDR, WS_D_CUT)
I2C_WRITE_8(op_WS_D_FREQ_RANGE_write, WS_ADDR, WS_D_FREQ_RANGE)
I2C_WRITE_16(op_WS_D_RATE_write, WS_ADDR, WS_D_RATE)
I2C_RECV_16(op_WS_D_RATE_recv, WS_ADDR, WS_D_RATE)
I2C_WRITE_16(op_WS_D_FREQ_write, WS_ADDR, WS_D_FREQ)
I2C_RECV_16(op_WS_D_FREQ_recv, WS_ADDR, WS_D_FREQ)
I2C_WRITE_0(op_WS_D_CLK_write, WS_ADDR, WS_D_CLK)
I2C_WRITE_8_8(op_WS_D_CLK_RATIO_write, WS_ADDR, WS_D_CLK_RATIO)
I2C_WRITE_16(op_WS_D_PLUCK_write, WS_ADDR, WS_D_PLUCK)
I2C_WRITE_16(op_WS_D_MOD_RATE_write, WS_ADDR, WS_D_MOD_RATE)
I2C_RECV_16(op_WS_D_MOD_RATE_recv, WS_ADDR, WS_D_MOD_RATE)
I2C_WRITE_16(op_WS_D_MOD_AMOUNT_write, WS_ADDR, WS_D_MOD_AMOUNT)
I2C_RECV_16(op_WS_D_MOD_AMOUNT_recv, WS_ADDR, WS_D_MOD_AMOUNT)

// clang-format off
const tele_op_t op_WS_D_FEEDBACK = MAKE_GET_SET_OP(W/D.FBK, op_WS_D_FEEDBACK_recv, op_WS_D_FEEDBACK_write, 0, true);
Expand Down
1 change: 1 addition & 0 deletions src/ops/wslashdelay.h
Expand Up @@ -2,6 +2,7 @@
#define _OPS_WSLASH_DELAY_H_

#include "ops/op.h"

extern const tele_op_t op_WS_D_FEEDBACK;
extern const tele_op_t op_WS_D_MIX;
extern const tele_op_t op_WS_D_LOWPASS;
Expand Down

0 comments on commit 56c1268

Please sign in to comment.