diff --git a/.github/workflows/build-plugin.yaml b/.github/workflows/build-plugin.yaml index 92259f9..513edb8 100644 --- a/.github/workflows/build-plugin.yaml +++ b/.github/workflows/build-plugin.yaml @@ -10,7 +10,7 @@ on: - '.github/workflows/deploy-pages.yaml' env: - rack-sdk-version: 2.3.0 + rack-sdk-version: 2.4.0 rack-plugin-toolchain-dir: /home/build/rack-plugin-toolchain defaults: @@ -45,7 +45,7 @@ jobs: options: --user root strategy: matrix: - platform: [win-x64, linux-x64] + platform: [win-x64, lin-x64] steps: - uses: actions/checkout@v3 with: @@ -59,6 +59,9 @@ jobs: run: | export PLUGIN_DIR=$GITHUB_WORKSPACE pushd ${{ env.rack-plugin-toolchain-dir }} + sed -i 's/\(RACK_SDK_VERSION \:\= \)[0-9\.]\+$/\1${{ env.rack-sdk-version }}/' Makefile + make rack-sdk-clean + make rack-sdk-${{ matrix.platform }} make plugin-build-${{ matrix.platform }} - name: Upload artifact uses: actions/upload-artifact@v3 diff --git a/.gitmodules b/.gitmodules index f072541..57b5f4c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/Dewb/whitewhale branch = vcvrack_pr [submodule "firmware/teletype"] - path = firmware/teletype + path = firmware/teletype4 url = https://github.com/Dewb/teletype branch = vcvrack-4.0.0 [submodule "firmware/meadowphysics"] @@ -17,3 +17,12 @@ [submodule "firmware/ansible"] path = firmware/ansible url = https://github.com/Dewb/ansible + branch = vcvrack +[submodule "firmware/firmware/teletype-5"] + path = firmware/teletype5 + url = https://github.com/Dewb/teletype + branch = vcvrack-5 +[submodule "firmware/whitewhale-kria"] + path = firmware/whitewhale-kria + url = https://github.com/Dewb/kria + branch = vcvrack diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e323a39..1c5e20f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -70,7 +70,7 @@ "focus": false, "panel": "shared" }, - "command": "make clean; rm -rf firmware/build; rm -rf res/firmware/*.*", + "command": "make clean", "options": { "cwd": "${workspaceRoot}", "env": { diff --git a/Makefile b/Makefile index e474137..9b308f6 100644 --- a/Makefile +++ b/Makefile @@ -59,17 +59,18 @@ $(ragel): firmware-build: export PATH := $(PWD)/dep/bin:$(PATH) firmware-build: export RACK_DIR := $(realpath $(RACK_DIR)) firmware-build: firmware/*.mk firmware/**/*.c firmware/**/*.h firmware/**/**/*.rl - cd firmware && $(MAKE) -f whitewhale.mk + cd firmware && $(MAKE) -f whitewhale.mk TARGET_NAME=whitewhale + cd firmware && $(MAKE) -f whitewhale.mk TARGET_NAME=whitewhale-kria cd firmware && $(MAKE) -f meadowphysics.mk cd firmware && $(MAKE) -f earthsea.mk - cd firmware && $(MAKE) -f teletype.mk + cd firmware && $(MAKE) -f teletype.mk TARGET_NAME=teletype4 + cd firmware && $(MAKE) -f teletype.mk TARGET_NAME=teletype5 cd firmware && $(MAKE) -f ansible.mk firmware-clean: - rm -rfv firmware/build - rm -fv res/firmware/*.so rm -fv res/firmware/*.dll - rm -fv res/firmware/*.dylib + rm -fv res/firmware/*.dylib + rm -fv res/firmware/*.so DISTRIBUTABLES += $(wildcard res) DISTRIBUTABLES += $(wildcard LICENSE*) diff --git a/README.md b/README.md index eda09c0..82323f9 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This plugin currently includes: * [white whale](https://monome.org/docs/whitewhale/), a probabilistic step sequencer * [meadowphysics](https://monome.org/docs/meadowphysics/), an event sequencer for polyrhythms and rule-based evolving patterns * [earthsea](https://monome.org/docs/earthsea/), a live keyboard that can sequence melodies and recall CV with shape memory gestures -* Support for [monome grid](https://monome.org/docs/grid/) and [monome arc](https://monome.org/docs/arc/) hardware controllers, both current editions and older models, plus virtual versions of the controllers within VCV Rack, in 64, 128, and 256-key flavors. +* Support for [monome grid](https://monome.org/docs/grid/) and [monome arc](https://monome.org/docs/arc/) hardware controllers, both current editions and older models, plus virtual versions of the grid controller within VCV Rack, in 64, 128, and 256-key flavors. All of the modules can connect to either a virtual grid or a real hardware grid controller. ([Serialosc](https://monome.org/docs/setup/) is required to use real hardware, but no drivers are required for the virtual grids.) @@ -35,7 +35,7 @@ To install the latest library release: * Right-click the `white whale` module and select your virtual grid from the list of devices. It should light up. * If you have a hardware grid connected, right-click the module and select your hardware grid from the list. The virtual grid should go dark and your physical grid should light up. -### Deeping learning and getting help +### Deeper learning and getting help See the [online manual](https://dewb.github.io/monome-rack), specifically the [Getting Help section](https://dewb.github.io/monome-rack/help/). diff --git a/docs/content/modules/teletype.md b/docs/content/modules/teletype.md index 2fe5b28..55a0442 100644 --- a/docs/content/modules/teletype.md +++ b/docs/content/modules/teletype.md @@ -127,6 +127,14 @@ For advanced scripting techniques, see `@scanner-darkly`'s [GRID INTEGRATION stu You can use either a physical or virtual grid to take advantage of the grid operators or Grid Control Mode. Hardware versions of Teletype can't use both the grid and the keyboard at the same time, and there are [some precautions to follow](https://monome.org/docs/grid/grid-modular/#teletype) regarding power loads, but thankfully the software version has none of these restrictions, making it an excellent environment for developing complex grid scenes that you can later transfer to hardware. +# Alternate firmware + +Choose **Firmware Tools > Switch Firmware** to see alternate firmware options for Teletype. + +Currently there are firmware builds for the teletype 4.0 and 5.0-beta release streams. 4.0 is the default; at some point after 5.0 is out of beta, it will become the default for newly placed modules, but modules already placed in your patch will remain 4.0. + +Switching firmware will reset the VRAM and NVRAM for the module, so export any scenes you want to keep before to text files before switching firmware editions. + # Further reading * Teletype [hardware documentation](http://monome.org/docs/teletype/) diff --git a/docs/content/modules/whitewhale.md b/docs/content/modules/whitewhale.md index 67f603d..a0a7325 100644 --- a/docs/content/modules/whitewhale.md +++ b/docs/content/modules/whitewhale.md @@ -67,6 +67,12 @@ This quickstart example uses White Whale alongside modules from VCV's [Free coll - Hold *ALT* on the grid and enter the **CV B** region on grid -- this will show put **CV B** into a [Scale Map](https://monome.org/docs/whitewhale/#cv-map), which quantizes **CV B**'s output to a musical note range. - As the pattern plays, enter new notes for each step in the *Scale Map*. +# Alternate firmware + +Choose **Firmware Tools > Switch Firmware** to see alternate firmware options for White Whale. + +White Whale offers the standard firmware plus the Kria alternate firmware, an early form of the Kria sequencer mode in Ansible. [Read about the original version of Kria here](https://llllllll.co/t/kria-0-3-initial-release/2409). + # Further reading * White Whale [hardware documentation](http://monome.org/docs/whitewhale/) @@ -79,3 +85,5 @@ This quickstart example uses White Whale alongside modules from VCV's [Free coll * [white whale tutorial part 2](https://vimeo.com/105368874) * [white whale tutorial part 3](https://vimeo.com/105408057) * [white whale tutorial part 4](https://vimeo.com/105408747) +* [kria demo](https://vimeo.com/152756139) +* [kria lesson](https://vimeo.com/153923660) diff --git a/firmware/common.mk b/firmware/common.mk index bc22d1b..60a9536 100644 --- a/firmware/common.mk +++ b/firmware/common.mk @@ -2,6 +2,7 @@ SHELL := /bin/bash -O extglob RACK_DIR ?= ../../.. TARGET_DIR := ../res/firmware/ +BUILD_DIR := ../build/firmware/$(TARGET_NAME) FLAGS += \ -DDEBUG \ @@ -33,7 +34,7 @@ ifeq ($(ARCH_WIN), 1) TARGET = $(TARGET_DIR)$(TARGET_NAME).dll endif -include $(RACK_DIR)/compile.mk +include compile.mk all: $(TARGET) diff --git a/firmware/compile.mk b/firmware/compile.mk new file mode 100644 index 0000000..3b19f4f --- /dev/null +++ b/firmware/compile.mk @@ -0,0 +1,114 @@ +# Rack SDK compile.mk modified to support configurable build products folder + +ifndef RACK_DIR +$(error RACK_DIR is not defined) +endif + +include $(RACK_DIR)/arch.mk + +BUILD_DIR ?= build +OBJCOPY ?= objcopy +STRIP ?= strip +INSTALL_NAME_TOOL ?= install_name_tool +OTOOL ?= otool + +# Generate dependency files alongside the object files +FLAGS += -MMD -MP +# Debugger symbols. These are removed with `strip`. +FLAGS += -g +# Optimization +FLAGS += -O3 -funsafe-math-optimizations -fno-omit-frame-pointer +# Warnings +FLAGS += -Wall -Wextra -Wno-unused-parameter +# C++ standard +CXXFLAGS += -std=c++11 + +# Define compiler/linker target if cross-compiling +ifdef CROSS_COMPILE + FLAGS += --target=$(MACHINE) + LDFLAGS += --target=$(MACHINE) +endif + +# Architecture-independent flags +ifdef ARCH_X64 + FLAGS += -DARCH_X64 + FLAGS += -march=nehalem +endif +ifdef ARCH_ARM64 + FLAGS += -DARCH_ARM64 + FLAGS += -march=armv8-a+fp+simd +endif + +ifdef ARCH_LIN + FLAGS += -DARCH_LIN + CXXFLAGS += -Wsuggest-override +endif +ifdef ARCH_MAC + FLAGS += -DARCH_MAC + CXXFLAGS += -stdlib=libc++ + LDFLAGS += -stdlib=libc++ + MAC_SDK_FLAGS := -mmacosx-version-min=10.9 + FLAGS += $(MAC_SDK_FLAGS) + LDFLAGS += $(MAC_SDK_FLAGS) +endif +ifdef ARCH_WIN + FLAGS += -DARCH_WIN + FLAGS += -D_USE_MATH_DEFINES + FLAGS += -municode + CXXFLAGS += -Wsuggest-override +endif + +# Allow *appending* rather than prepending to common flags. +# This is useful to force-redefine compiler settings instead of merely setting defaults that may be overwritten. +FLAGS += $(EXTRA_FLAGS) +CFLAGS += $(EXTRA_CFLAGS) +CXXFLAGS += $(EXTRA_CXXFLAGS) +LDFLAGS += $(EXTRA_LDFLAGS) + +# Apply FLAGS to language-specific flags +CFLAGS += $(FLAGS) +CXXFLAGS += $(FLAGS) + +# Derive object files from sources and place them before user-defined objects +OBJECTS := $(patsubst %, $(BUILD_DIR)/%.o, $(SOURCES)) $(OBJECTS) +OBJECTS += $(patsubst %, $(BUILD_DIR)/%.bin.o, $(BINARIES)) +DEPENDENCIES := $(patsubst %, $(BUILD_DIR)/%.d, $(SOURCES)) + +# Final targets + +$(TARGET): $(OBJECTS) + $(CXX) -o $@ $^ $(LDFLAGS) + +-include $(DEPENDENCIES) + +$(BUILD_DIR)/%.c.o: %.c + @mkdir -p $(@D) + $(CC) $(CFLAGS) -c -o $@ $< + +$(BUILD_DIR)/%.cpp.o: %.cpp + @mkdir -p $(@D) + $(CXX) $(CXXFLAGS) -c -o $@ $< + +$(BUILD_DIR)/%.cc.o: %.cc + @mkdir -p $(@D) + $(CXX) $(CXXFLAGS) -c -o $@ $< + +$(BUILD_DIR)/%.m.o: %.m + @mkdir -p $(@D) + $(CC) $(CFLAGS) -c -o $@ $< + +$(BUILD_DIR)/%.bin.o: % + @mkdir -p $(@D) +ifdef ARCH_LIN + $(OBJCOPY) -I binary -O elf64-x86-64 -B i386:x86-64 --rename-section .data=.rodata,alloc,load,readonly,data,contents $< $@ +endif +ifdef ARCH_WIN + $(OBJCOPY) -I binary -O pe-x86-64 -B i386:x86-64 --rename-section .data=.rodata,alloc,load,readonly,data,contents $< $@ +endif +ifdef ARCH_MAC + @# Apple makes this needlessly complicated, so just generate a C file with an array. + xxd -i $< | $(CC) $(MAC_SDK_FLAGS) -c -o $@ -xc - +endif + +$(BUILD_DIR)/%.html: %.md + markdown $< > $@ diff --git a/firmware/mock_hardware/mock_hardware_api.h b/firmware/mock_hardware/mock_hardware_api.h index a63d920..c1fb4fe 100644 --- a/firmware/mock_hardware/mock_hardware_api.h +++ b/firmware/mock_hardware/mock_hardware_api.h @@ -1,5 +1,5 @@ #ifndef MOCK_API_SKIP_TYPES -#include "../teletype/src/serializer.h" +#include "../teletype4/src/serializer.h" #include #include #endif diff --git a/firmware/mock_hardware/modules/teletype/adapter_teletype.c b/firmware/mock_hardware/modules/teletype/adapter_teletype.c index bf2cf04..a8bc4b8 100644 --- a/firmware/mock_hardware/modules/teletype/adapter_teletype.c +++ b/firmware/mock_hardware/modules/teletype/adapter_teletype.c @@ -1,5 +1,6 @@ #include "mock_hardware_api.h" #include "mock_hardware_api_private.h" +#include "flashc.h" #include "module/edit_mode.h" #include "module/flash.h" @@ -7,10 +8,20 @@ #include "module/globals.h" #include "module/live_mode.h" #include "module/preset_w_mode.h" -#include "src/serialize.h" +#include "src/scene_serialization.h" #include "src/teletype_io.h" #include "types.h" +extern nvram_data_t f; +extern scene_state_t scene_state; + +#ifdef DECLARE_NVRAM +DECLARE_NVRAM(&f, sizeof(nvram_data_t)) +#endif +#ifdef DECLARE_VRAM +DECLARE_VRAM(&scene_state, sizeof(scene_state)) +#endif + void clock_null(uint8_t phase) { } typedef void (*clock_pulse_t)(uint8_t phase); volatile uint8_t clock_external; @@ -51,8 +62,16 @@ void fake_flash_read(scene_state_t* src_scene, scene_state_t* dest_scene, uint8_t init_i2c_op_address) { memcpy(ss_scripts_ptr(dest_scene), ss_scripts_ptr(src_scene), + +// handle difference in macros between TT 5 and 4 +#ifdef EDITABLE_SCRIPT_COUNT + ss_scripts_size(EDITABLE_SCRIPT_COUNT) +#else // Exclude size of TEMP script as above - ss_scripts_size() - sizeof(scene_script_t)); + ss_scripts_size() - sizeof(scene_script_t) +#endif + + ); if (init_pattern) { @@ -66,7 +85,13 @@ void fake_flash_read(scene_state_t* src_scene, scene_state_t* dest_scene, memcpy(dest_text, src_text, SCENE_TEXT_LINES * SCENE_TEXT_CHARS); // need to reset timestamps uint32_t ticks = tele_get_ticks(); + +// handle difference in macros between TT 5 and 4 +#ifdef TOTAL_SCRIPT_COUNT + for (size_t i = 0; i < TOTAL_SCRIPT_COUNT; i++) +#else for (size_t i = 0; i < TEMP_SCRIPT; i++) +#endif dest_scene->scripts[i].last_time = ticks; dest_scene->variables.time = 0; diff --git a/firmware/mock_hardware/modules/teletype/usb_disk_mode.c b/firmware/mock_hardware/modules/teletype/usb_disk_mode.c new file mode 100644 index 0000000..e189ea8 --- /dev/null +++ b/firmware/mock_hardware/modules/teletype/usb_disk_mode.c @@ -0,0 +1,10 @@ +#include + +void handler_usb_PollADC(int32_t data) { +} + +void handler_usb_Front(int32_t data) { +} + +void handler_usb_ScreenRefresh(int32_t data) { +} \ No newline at end of file diff --git a/firmware/teletype b/firmware/teletype deleted file mode 160000 index efd6503..0000000 --- a/firmware/teletype +++ /dev/null @@ -1 +0,0 @@ -Subproject commit efd6503778573c0268886ed8758468d61ebaceab diff --git a/firmware/teletype.mk b/firmware/teletype.mk index 0f326da..50653c3 100644 --- a/firmware/teletype.mk +++ b/firmware/teletype.mk @@ -1,59 +1,57 @@ -TARGET_NAME := teletype - FLAGS += \ -D__AVR32_UC3B0512__ \ -Imock_hardware \ -Imock_hardware/include \ - -Iteletype/libavr32/src \ - -Iteletype/libavr32/src/usb/midi \ - -Iteletype/libavr32/src/usb/hid \ - -Iteletype/libavr32/src/usb/cdc \ - -Iteletype/libavr32/src/usb/ftdi \ - -Iteletype/libavr32/conf \ - -Iteletype/libavr32/conf/teletype \ - -Iteletype/libavr32/asf/common/services/usb \ - -Iteletype/libavr32/asf/common/services/usb/uhc \ - -Iteletype/libavr32/asf/common/services/usb/class/hid \ - -Iteletype/src \ - -Iteletype/src/ops \ - -Iteletype/ \ + -I$(TARGET_NAME)/libavr32/src \ + -I$(TARGET_NAME)/libavr32/src/usb/midi \ + -I$(TARGET_NAME)/libavr32/src/usb/hid \ + -I$(TARGET_NAME)/libavr32/src/usb/cdc \ + -I$(TARGET_NAME)/libavr32/src/usb/ftdi \ + -I$(TARGET_NAME)/libavr32/conf \ + -I$(TARGET_NAME)/libavr32/conf/teletype \ + -I$(TARGET_NAME)/libavr32/asf/common/services/usb \ + -I$(TARGET_NAME)/libavr32/asf/common/services/usb/uhc \ + -I$(TARGET_NAME)/libavr32/asf/common/services/usb/class/hid \ + -I$(TARGET_NAME)/src \ + -I$(TARGET_NAME)/src/ops \ + -I$(TARGET_NAME)/ \ SOURCES = \ - $(wildcard teletype/src/*.c) \ - teletype/src/scanner.c \ - teletype/src/match_token.c \ - teletype/module/gitversion.c \ - $(wildcard teletype/src/ops/*.c) \ - $(wildcard teletype/module/*.c) \ - teletype/libavr32/src/events.c \ - teletype/libavr32/src/timers.c \ - teletype/libavr32/src/util.c \ - teletype/libavr32/src/font.c \ - teletype/libavr32/src/kbd.c \ - teletype/libavr32/src/region.c \ - teletype/libavr32/src/random.c \ - teletype/libavr32/src/usb/hid/hid.c \ - teletype/libavr32/src/music.c \ - teletype/libavr32/src/midi_common.c \ - $(wildcard teletype/libavr32/src/euclidean/*.c) \ + $(wildcard $(TARGET_NAME)/src/*.c) \ + $(TARGET_NAME)/src/scanner.c \ + $(TARGET_NAME)/src/match_token.c \ + $(TARGET_NAME)/module/gitversion.c \ + $(wildcard $(TARGET_NAME)/src/ops/*.c) \ + $(wildcard $(TARGET_NAME)/module/*.c) \ + $(TARGET_NAME)/libavr32/src/events.c \ + $(TARGET_NAME)/libavr32/src/timers.c \ + $(TARGET_NAME)/libavr32/src/util.c \ + $(TARGET_NAME)/libavr32/src/font.c \ + $(TARGET_NAME)/libavr32/src/kbd.c \ + $(TARGET_NAME)/libavr32/src/region.c \ + $(TARGET_NAME)/libavr32/src/random.c \ + $(TARGET_NAME)/libavr32/src/usb/hid/hid.c \ + $(TARGET_NAME)/libavr32/src/music.c \ + $(TARGET_NAME)/libavr32/src/midi_common.c \ + $(wildcard $(TARGET_NAME)/libavr32/src/euclidean/*.c) \ $(wildcard mock_hardware/*.c) \ $(wildcard mock_hardware/common/*.c) \ $(wildcard mock_hardware/modules/teletype/*.c) \ -SOURCES := $(filter-out teletype/module/usb_disk_mode.c, $(SOURCES)) +SOURCES := $(filter-out $(TARGET_NAME)/module/usb_disk_mode.c, $(SOURCES)) RAGEL ?= ragel # Add a rule to build match_token.c from match_token.rl -teletype/src/match_token.c: teletype/src/match_token.rl - $(RAGEL) -C -G2 teletype/src/match_token.rl -o teletype/src/match_token.c +$(TARGET_NAME)/src/match_token.c: $(TARGET_NAME)/src/match_token.rl + $(RAGEL) -C -G2 $(TARGET_NAME)/src/match_token.rl -o $(TARGET_NAME)/src/match_token.c # Add a rule to build scanner.c from scanner.rl -teletype/src/scanner.c: teletype/src/scanner.rl - $(RAGEL) -C -G2 teletype/src/scanner.rl -o teletype/src/scanner.c +$(TARGET_NAME)/src/scanner.c: $(TARGET_NAME)/src/scanner.rl + $(RAGEL) -C -G2 $(TARGET_NAME)/src/scanner.rl -o $(TARGET_NAME)/src/scanner.c # Add the git commit id to a file for use when printing out the version -teletype/module/gitversion.c: teletype - echo "const char *git_version = \"$(shell cut -d '-' -f 1 <<< $(shell cd teletype; git describe --tags | cut -c 1-)) $(shell cd teletype; git describe --always --dirty --exclude '*' | tr '[a-z]' '[A-Z]')\";" > $@ +$(TARGET_NAME)/module/gitversion.c: $(TARGET_NAME) + echo "const char *git_version = \"$(shell cut -d '-' -f 1 <<< $(shell cd $(TARGET_NAME); git describe --tags | cut -c 1-)) $(shell cd $(TARGET_NAME); git describe --always --dirty --exclude '*' | tr '[a-z]' '[A-Z]')\";" > $@ include common.mk diff --git a/firmware/teletype4 b/firmware/teletype4 new file mode 160000 index 0000000..a34da87 --- /dev/null +++ b/firmware/teletype4 @@ -0,0 +1 @@ +Subproject commit a34da87afb779b993cd0a6bce4e6102cd35c4a95 diff --git a/firmware/teletype5 b/firmware/teletype5 new file mode 160000 index 0000000..0a20747 --- /dev/null +++ b/firmware/teletype5 @@ -0,0 +1 @@ +Subproject commit 0a20747a2da7d80bbe2f59e590ab76371ac9dced diff --git a/firmware/whitewhale-kria b/firmware/whitewhale-kria new file mode 160000 index 0000000..1e0e2fb --- /dev/null +++ b/firmware/whitewhale-kria @@ -0,0 +1 @@ +Subproject commit 1e0e2fbb2a81a31ad14ad996c393ed5f6b2c4fbe diff --git a/firmware/whitewhale.mk b/firmware/whitewhale.mk index fca10d7..48a2cbd 100644 --- a/firmware/whitewhale.mk +++ b/firmware/whitewhale.mk @@ -1,27 +1,25 @@ -TARGET_NAME := whitewhale - FLAGS += \ -D__AVR32_UC3B0256__ \ -Imock_hardware \ -Imock_hardware/include \ - -Iwhitewhale/libavr32/src \ - -Iwhitewhale/libavr32/src/usb/midi \ - -Iwhitewhale/libavr32/src/usb/hid \ - -Iwhitewhale/libavr32/src/usb/cdc \ - -Iwhitewhale/libavr32/asf/common/services/usb \ - -Iwhitewhale/libavr32/asf/common/services/usb/uhc \ - -Iwhitewhale/libavr32/conf \ - -Iwhitewhale/libavr32/conf/trilogy \ + -I$(TARGET_NAME)/libavr32/src \ + -I$(TARGET_NAME)/libavr32/src/usb/midi \ + -I$(TARGET_NAME)/libavr32/src/usb/hid \ + -I$(TARGET_NAME)/libavr32/src/usb/cdc \ + -I$(TARGET_NAME)/libavr32/asf/common/services/usb \ + -I$(TARGET_NAME)/libavr32/asf/common/services/usb/uhc \ + -I$(TARGET_NAME)/libavr32/conf \ + -I$(TARGET_NAME)/libavr32/conf/trilogy \ SOURCES = \ - whitewhale/src/main.c \ - whitewhale/libavr32/src/events.c \ - whitewhale/libavr32/src/timers.c \ - whitewhale/libavr32/src/util.c \ + $(TARGET_NAME)/src/main.c \ + $(TARGET_NAME)/libavr32/src/events.c \ + $(TARGET_NAME)/libavr32/src/timers.c \ + $(TARGET_NAME)/libavr32/src/util.c \ $(wildcard mock_hardware/*.c) \ $(wildcard mock_hardware/common/*.c) \ $(wildcard mock_hardware/modules/trilogy/*.c) \ -FLAGS += -DGIT_VERSION="\"$(shell cut -d '-' -f 1 <<< $(shell cd whitewhale; git describe --tags | cut -c 1-)) $(shell cd whitewhale; git describe --always --dirty --exclude '*' | tr '[a-z]' '[A-Z]')\"" +FLAGS += -DGIT_VERSION="\"$(shell cut -d '-' -f 1 <<< $(shell cd $(TARGET_NAME); git describe --tags | cut -c 1-)) $(shell cd $(TARGET_NAME); git describe --always --dirty --exclude '*' | tr '[a-z]' '[A-Z]')\"" include common.mk diff --git a/plugin.json b/plugin.json index b952615..dc3f811 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,8 @@ { "slug": "monome", "name": "monome", - "version": "2.1.3", + "version": "2.1.5", + "minRackVersion": "2.4.0", "license": "GPL-2.0-only", "author": "Michael Dewberry", "authorEmail": "", diff --git a/presets/teletype/MINIM.vcvm b/presets/teletype/MINIM.vcvm new file mode 100644 index 0000000..5e7a65f --- /dev/null +++ b/presets/teletype/MINIM.vcvm @@ -0,0 +1,22 @@ +{ + "plugin": "monome", + "model": "teletype", + "version": "2.1.5", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + } + ], + "data": { + "loadScript": { + "active": true, + "flash": 0, + "data": "M I N I M \n@MODULARBEAT\n\n\nSCALE: %8\nCV IN: %9\n\nA CHORD+ARP SEQUENCER...\n\nLEFT SIDE: CHORD SEQ\nCENTER: SET LOOP START+END\nRIGHT SIDE: ARP SEQ\n\nIN 1: ADVANCE CHORD\nIN 2: RESET ARP\nIN 3: ADVANCE ARP\n\nCV IN: CHORD VOICING\nPARAM KNOB: SCALE\nTR 1: CHORD TRIGGER\nTR 2: LIVE CHORD TRIGGER\nTR 3: ARP TRIGGER\nTR 4: LIVE ARP TRIGGER\n\nCV 1-3: CHORD\nCV 4: ARP\n\n\n\n#1\nG.GBTN.L + PN.I 0 10 0 0\nZ 0; $ * A 4; C PN.HERE 0\nK PN.I 0; G.GBTN.L + K 10 6 6\nL 1 3: $ 2\nIF ! A: TR.P * == G.BTNY K 2\nTR.P A; A 1\n\n#2\nJ / * - I 1 R 6; K * / J 4 12\nCV I N.CS K PRM C J\nIF ! STATE 2: BRK\nL 0 7: G.GBTN.L I 0 0\nG.GBTN.L PN.I 1 6 6\nP 13 0; B 4; P 15 0\n\n#3\nZ 1; G.GBTN.L PN.I 1 0 0; $ B\nT PN.I 1; G.GBTN.L T 6 6\nJ PN.HERE 1; K * / J 4 12\nCV - 7 PN 2 T N.CS K PRM C J\nIF ! B: TR.P * == G.BTNY T 4\nTR.P * PN 2 T / B 4; B 4\n\n#4\nJ + P + Z 12 > P + Z 8 PN.I Z\nIF * J P + Z 14: S.POP\nPN.START Z P Z; PN.L Z P + Z 2\nPN.I Z * P Z P + Z 14; J + Z 8\nP J - P + Z 0 1; P + Z 14 1\n$ 5\n\n#5\nELIF == PN.I Z P Z: P + Z 12 1\nS: PN.NEXT Z; $ 5; BRK\nIF || P + Z 12 ! P + Z 14: BRK\nJ * ! Z 10; K + P + Z 8 J\nL + PN.I Z J K: G.GBTN.L I 2 2\nG.GBTN.L + PN.I Z J 6 6\n\n#6\nX G.GRPI; J G.BTNV\nK ! + P + X 2 J\nIF K: G.GBTN.L X 5 5; $ 7; BRK\nIF J: P - X 2 + G.GBTN.Y2 X 1\nIF J: P - X 4 G.GBTN.Y1 X\nP + X 2 MAX - G.GBTN.C X 1 0\n\n#7\nJ P - X 4; K P - X 2\nP X ? P + X 4 - P - X 6 1 P X\nP - X 8 J; P - X 6 K\nY - X 8; Z Y; J + J * Y 8\nK - + K * Y 8 1; P + X 4 0\nL J K: G.BTN.L I 15; $ 5\n\n#8\nJ G.BTNV; K G.GRPI; D ! / K 9\nPN D - K * ! D 10 + G.BTNX ! D\nIF D: PN.- 1 K 9; B 0\nIF ! D: A 0; $ 1\nIF ! && ! J D: G.BTN.SW G.BTNI\nIF D: PN 2 K * J 3; $ 3\n\n#M\nJ == + PRT 7 1 8; R * + IN 2 3\nIF J: PRT 8 PRM; PRT 9 IN; BRK\nPRT 7 O; J PRT 7; X + J 10\nD + * J 7 16; K + D 56; P.N 3\nG.GBX X K 0 J 1 1 1 0 8 7 1\nG.GBX J D 9 J 1 1 1 0 8 7 1\n\n#I\nINIT.DATA; Q.GRW 1\nPARAM.SCALE 0 8; IN.SCALE 0 17\nPRT 7 0; M 25; M.ACT 1\nG.GBX 8 0 7 0 1 1 0 5 6 1 8\nG.GBX 9 8 8 0 1 1 0 5 6 1 8\nLIVE.DASH 1; $ 5\n\n#P\n1\t1\t8\t8\n1\t1\t1\t1\n0\t0\t0\t0\n7\t7\t7\t7\n\n1\t6\t3\t0\n1\t6\t3\t0\n1\t6\t3\t1\n1\t6\t3\t1\n1\t6\t3\t1\n1\t6\t3\t1\n1\t6\t3\t1\n1\t6\t3\t1\n0\t0\t0\t-1\n0\t0\t0\t-1\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t1\n0\t0\t0\t1\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n0\t0\t0\t0\n\n#G\n0000000000000000\n0000001000000100\n0000100000010000\n0010000001000000\n1000000110000001\n0000001000000100\n0000100000010000\n0010000001000000\n0000000000000000\n0000000000000000\n0000000000000000\n0000000000000000\n0000000000000000\n0000000000000000\n0000000000000000\n0000000000000000\n\n1\t2\t4\t4\t1\t2\t4\t5\t1\t1\t1\t1\t1\t1\t1\t1\n5\t7\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\n7\t3\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\n0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\n" + } + } +} \ No newline at end of file diff --git a/res/ansible-dark.svg b/res/ansible-dark.svg new file mode 100644 index 0000000..d9b73f3 --- /dev/null +++ b/res/ansible-dark.svg @@ -0,0 +1,260 @@ + +image/svg+xml diff --git a/res/ansible.svg b/res/ansible.svg index 2bbc225..f26a22d 100644 --- a/res/ansible.svg +++ b/res/ansible.svg @@ -10,7 +10,6 @@ xml:space="preserve" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" @@ -20,20 +19,20 @@ inkscape:document-rotation="0" units="px" inkscape:window-maximized="1" - inkscape:window-y="-8" - inkscape:window-x="2552" - inkscape:window-height="1017" - inkscape:window-width="1920" + inkscape:window-y="-9" + inkscape:window-x="2551" + inkscape:window-height="1361" + inkscape:window-width="2560" fit-margin-bottom="0" fit-margin-right="0" fit-margin-left="0" fit-margin-top="0" showgrid="false" - inkscape:current-layer="layer1" + inkscape:current-layer="layer4" inkscape:document-units="mm" - inkscape:cy="205.65118" - inkscape:cx="118.70171" - inkscape:zoom="2.7084698" + inkscape:cy="349.44544" + inkscape:cx="73.361352" + inkscape:zoom="3.8303547" inkscape:pageshadow="2" inkscape:pageopacity="0.0" borderopacity="1.0" @@ -52,23 +51,9 @@ sodipodi:insensitive="true" transform="scale(1.277826)"> + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/earthsea.svg b/res/earthsea.svg index e017e81..60bde2e 100644 --- a/res/earthsea.svg +++ b/res/earthsea.svg @@ -16,25 +16,48 @@ xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + id="defs4535"> + + + + + + - - - - - + style="fill:url(#linearGradient47118);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.243982" + d="m 61.978028,53.744307 h 23.85 V 154.24031 h -23.85 z m 0,0" + id="path1140" /> + inkscape:label="Stroked Marks"> + style="display:inline;fill:none;stroke:#000000;stroke-width:0.165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 68.989539,70.091992 -1.93483,3.482696 m 5.236219,-3.460864 1.859624,3.381135 m -3.468978,-9.504744 0.04065,-3.25183" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccc" + transform="translate(1.2916667e-6)" /> + id="path6189-5" + style="display:inline;fill:none;stroke:#000000;stroke-width:0.165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 68.952971,92.745091 -1.93483,3.482696 m 5.236219,-3.460864 1.859624,3.381135 m -3.468978,-9.504744 0.04065,-3.25183" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccc" + transform="translate(1.2916667e-6)" /> + sodipodi:nodetypes="cccccc" + transform="translate(1.2916667e-6)" /> @@ -194,110 +191,110 @@ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.94028px;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">pos + style="font-style:italic;font-size:50.8px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> diff --git a/res/grid-dark.svg b/res/grid-dark.svg new file mode 100644 index 0000000..edd4ac6 --- /dev/null +++ b/res/grid-dark.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/res/grid.svg b/res/grid.svg new file mode 100644 index 0000000..2fbbc13 --- /dev/null +++ b/res/grid.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/res/meadowphysics-dark.svg b/res/meadowphysics-dark.svg new file mode 100644 index 0000000..94a0941 --- /dev/null +++ b/res/meadowphysics-dark.svg @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/meadowphysics.svg b/res/meadowphysics.svg index a95c339..8e67e8a 100644 --- a/res/meadowphysics.svg +++ b/res/meadowphysics.svg @@ -16,15 +16,38 @@ xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + id="defs4535"> + + + + + + + style="display:inline;fill:url(#linearGradient47118);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.243982" + d="M 0,0 H 23.85 V 100.496 H 0 Z m 0,0" + id="path1140" /> - - - - + inkscape:label="Stroked Marks"> @@ -245,193 +242,193 @@ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.94028px;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">out + style="font-style:italic;font-size:50.8px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94049px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264612px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> diff --git a/res/teletype-dark.svg b/res/teletype-dark.svg new file mode 100644 index 0000000..76a9647 --- /dev/null +++ b/res/teletype-dark.svg @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/teletype-expander.svg b/res/teletype-expander.svg deleted file mode 100644 index 365e1c1..0000000 --- a/res/teletype-expander.svg +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/teletype.svg b/res/teletype.svg index 73cc24b..6db7572 100644 --- a/res/teletype.svg +++ b/res/teletype.svg @@ -17,6 +17,18 @@ xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + @@ -31,6 +43,15 @@ d="M 0,612 H 792 V 0 H 0 Z" id="path855" /> + - - - - - - - - - + transform="translate(-61.978028,-53.744307)" + style="display:inline;stroke:none;fill:#b2b2b0;fill-opacity:1"> + transform="matrix(0.35277777,0,0,-0.35277777,100.31641,97.409012)" + style="stroke:#b2b2b0;fill:none;fill-opacity:1;stroke-opacity:1"> + transform="matrix(0.35277777,0,0,-0.35277777,113.5242,97.409012)" + style="stroke:#b2b2b0;fill:none;fill-opacity:1;stroke-opacity:1"> + transform="matrix(0.35277777,0,0,-0.35277777,126.98627,97.409012)" + style="stroke:#b2b2b0;fill:none;fill-opacity:1;stroke-opacity:1"> + id="g995" + transform="matrix(0.35277777,0,0,-0.35277777,90.942645,96.587847)" + style="stroke:none;fill:#b2b2b0;fill-opacity:1"> - - + d="m 0,0 h -0.926 l -0.233,-1.904 h 1.056 c 0.554,0 0.913,0.533 0.913,1.046 C 0.81,-0.438 0.41,0 0,0 M 0.277,-2.372 1.104,-3.791 C 1.176,-3.914 1.131,-4.074 1.008,-4.146 0.885,-4.218 0.725,-4.177 0.653,-4.054 l -0.95,1.631 h -0.927 l -0.188,-1.528 c -0.017,-0.144 -0.147,-0.246 -0.29,-0.229 -0.144,0.02 -0.243,0.15 -0.226,0.29 l 0.513,4.184 c 0.017,0.13 0.126,0.229 0.26,0.229 H 0 c 0.711,0 1.333,-0.684 1.333,-1.381 0,-0.66 -0.4,-1.326 -1.056,-1.514" + style="fill:#b2b2b0;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path997" /> + d="m 0,0 h -1.34 l -0.485,-3.955 c -0.017,-0.143 -0.147,-0.242 -0.287,-0.225 -0.144,0.017 -0.246,0.147 -0.229,0.29 L -1.863,0 h -1.275 c -0.143,0 -0.259,0.116 -0.259,0.26 0,0.147 0.116,0.263 0.259,0.263 H 0 C 0.144,0.523 0.26,0.407 0.26,0.26 0.26,0.116 0.144,0 0,0" + style="display:inline;fill:#b2b2b0;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path993" + transform="translate(-2.4404012)" /> + id="g1003" + transform="matrix(0.35277777,0,0,-0.35277777,97.208225,111.47514)" + style="stroke:none;fill:#b2b2b0;fill-opacity:1"> - - + d="m 0,0 c -0.051,-0.099 -0.154,-0.15 -0.26,-0.14 -0.109,0.014 -0.195,0.089 -0.222,0.195 l -1.056,4.159 c -0.034,0.14 0.051,0.277 0.191,0.315 0.137,0.034 0.281,-0.048 0.315,-0.188 L -0.147,0.848 1.699,4.419 C 1.767,4.549 1.921,4.597 2.047,4.532 2.177,4.464 2.225,4.31 2.16,4.184 Z" + style="fill:#b2b2b0;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path1005" /> + d="m 0,0 c -0.075,0.031 -0.509,0.144 -0.892,0.144 -1.289,0 -1.894,-0.978 -1.894,-2.161 0,-0.963 0.612,-1.606 1.59,-1.606 0.184,0 0.458,0.02 0.717,0.113 0.134,0.048 0.284,-0.021 0.332,-0.157 0.048,-0.134 -0.02,-0.288 -0.157,-0.335 -0.263,-0.096 -0.564,-0.144 -0.892,-0.144 -1.265,0 -2.109,0.875 -2.109,2.126 0,1.473 0.83,2.683 2.413,2.683 0.478,0 0.984,-0.14 1.083,-0.178 C 0.325,0.431 0.39,0.28 0.338,0.147 0.284,0.014 0.133,-0.051 0,0" + style="display:inline;fill:#b2b2b0;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path1001" + transform="translate(-2.3548954,3.9546108)" /> + id="g1059" + transform="matrix(0.35277777,0,0,-0.35277777,106.92066,110.87104)" + style="stroke:#b2b2b0;fill:none;fill-opacity:1;stroke-opacity:1"> + d="M 0,0 H 20.341" + style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#b2b2b0;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1" + id="path1061" /> + id="g1063" + transform="matrix(0.35277777,0,0,-0.35277777,120.31863,110.87104)" + style="stroke:#b2b2b0;fill:none;fill-opacity:1;stroke-opacity:1"> + d="M 0,0 H 20.341" + style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#b2b2b0;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1" + id="path1065" /> + id="g1067" + transform="matrix(0.35277777,0,0,-0.35277777,133.59051,110.87104)" + style="stroke:#b2b2b0;fill:none;fill-opacity:1;stroke-opacity:1"> + d="M 0,0 H 20.341" + style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#b2b2b0;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1" + id="path1069" /> + + + + aria-label="TELETYPE" + id="text13207" + style="font-style:italic;font-size:2.46944px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + d="m 13.290186,1.5929965 c 0,-0.051849 -0.041,-0.092845 -0.09164,-0.092845 h -1.106908 c -0.05064,0 -0.09164,0.040996 -0.09164,0.092845 0,0.050643 0.041,0.091639 0.09164,0.091639 h 0.449757 l -0.16881,1.372179 c -0.006,0.050643 0.03014,0.096462 0.08079,0.1024915 0.04944,0.00603 0.09526,-0.028939 0.101285,-0.079582 L 12.72588,1.6846359 h 0.472667 c 0.05064,0 0.09164,-0.040997 0.09164,-0.091639 z" + style="fill:#000000;stroke:none;fill-opacity:1" + id="path13211" /> + + + + + + + + id="g1055" + transform="matrix(0.35277777,0,0,-0.35277777,53.917083,19.975904)" + style="display:inline"> + d="M 0,0 C -0.065,-0.13 -0.227,-0.178 -0.353,-0.113 -0.479,-0.048 -0.53,0.109 -0.465,0.236 L 1.463,4.04 h -1.895 c -0.146,0 -0.262,0.116 -0.262,0.263 0,0.144 0.116,0.26 0.262,0.26 H 1.887 C 1.975,4.563 2.061,4.515 2.108,4.437 2.156,4.361 2.16,4.266 2.119,4.184 Z" + style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path1057" /> + id="g1051" + transform="matrix(0.35277777,0,0,-0.35277777,41.035012,18.55047)" + style="display:inline"> + d="m 0,0 h -1.702 l -0.236,-1.237 0.67,-0.113 c 1.203,-0.202 1.367,-0.961 1.292,-1.566 -0.099,-0.823 -0.803,-1.315 -1.873,-1.315 -0.325,0 -0.643,0.047 -0.656,0.047 -0.141,0.021 -0.24,0.154 -0.219,0.298 0.02,0.14 0.15,0.239 0.294,0.219 0.003,0 0.294,-0.041 0.581,-0.041 0.376,0 1.258,0.082 1.353,0.854 0.072,0.591 -0.174,0.878 -0.858,0.991 l -0.933,0.154 c -0.143,0.024 -0.239,0.161 -0.212,0.304 l 0.325,1.716 c 0.024,0.123 0.13,0.212 0.253,0.212 H 0 c 0.144,0 0.26,-0.116 0.26,-0.26 C 0.26,0.116 0.144,0 0,0" + style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path1053" /> + id="g1047" + transform="matrix(0.35277777,0,0,-0.35277777,27.665479,19.207625)" + style="display:inline"> + id="path1049" /> + id="g1043" + transform="matrix(0.35277777,0,0,-0.35277777,60.764571,31.741572)" + style="display:inline"> + id="path1045" /> + id="g1039" + transform="matrix(0.35277777,0,0,-0.35277777,47.238793,32.449563)" + style="display:inline"> + id="path1041" /> + id="g1035" + transform="matrix(0.35277777,0,0,-0.35277777,34.782699,32.85695)" + style="display:inline"> + d="m 0,0 h -0.475 l -0.103,-0.841 c -0.017,-0.14 -0.15,-0.242 -0.29,-0.225 -0.144,0.017 -0.246,0.147 -0.229,0.29 L -1.001,0 h -1.966 c -0.205,0 -0.328,0.226 -0.219,0.4 l 1.976,3.151 c 0.075,0.12 0.239,0.157 0.359,0.082 0.123,-0.078 0.157,-0.239 0.082,-0.359 L -2.495,0.523 h 1.558 l 0.117,0.95 c 0.017,0.144 0.147,0.25 0.29,0.229 0.14,-0.017 0.243,-0.15 0.226,-0.29 L -0.414,0.523 H 0 c 0.144,0 0.26,-0.116 0.26,-0.26 C 0.26,0.116 0.144,0 0,0" + style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path1037" /> + id="g1031" + transform="matrix(0.35277777,0,0,-0.35277777,20.702597,32.526713)" + style="display:inline"> + d="m 0,0 c -0.232,-0.116 -0.472,-0.239 -0.714,-0.414 -0.428,-0.314 -0.622,-0.738 -0.708,-1.069 h 1.911 c 0.143,0 0.26,-0.117 0.26,-0.26 0,-0.144 -0.117,-0.26 -0.26,-0.26 h -2.225 c -0.158,0 -0.277,0.137 -0.26,0.294 0.051,0.41 0.246,1.183 0.974,1.716 0.28,0.201 0.55,0.338 0.79,0.458 0.533,0.266 0.793,0.42 0.851,0.912 0.065,0.52 -0.339,0.852 -0.834,0.852 -0.318,0 -0.786,-0.093 -0.937,-0.137 -0.14,-0.045 -0.284,0.034 -0.325,0.171 -0.044,0.14 0.035,0.283 0.171,0.324 0.219,0.069 0.739,0.161 1.087,0.161 0.814,0 1.46,-0.602 1.357,-1.435 C 1.039,0.523 0.537,0.267 0,0" + style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path1033" /> + id="g1027" + transform="matrix(0.35277777,0,0,-0.35277777,87.868522,59.527122)" + style="display:inline"> + d="m 0,0 h -0.475 l -0.102,-0.841 c -0.017,-0.14 -0.151,-0.242 -0.29,-0.225 -0.145,0.017 -0.246,0.147 -0.23,0.29 L -1.001,0 h -1.966 c -0.205,0 -0.328,0.226 -0.219,0.4 l 1.977,3.151 c 0.074,0.12 0.238,0.157 0.358,0.082 0.123,-0.078 0.158,-0.239 0.082,-0.359 L -2.494,0.523 h 1.558 l 0.116,0.95 c 0.017,0.144 0.147,0.25 0.291,0.229 0.14,-0.017 0.242,-0.15 0.225,-0.29 L -0.413,0.523 H 0 c 0.145,0 0.26,-0.116 0.26,-0.26 C 0.26,0.116 0.145,0 0,0" + style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path1029" /> + id="g1023" + transform="matrix(0.35277777,0,0,-0.35277777,74.147373,59.085834)" + style="display:inline"> + d="m 0,0 c 0.342,-0.273 0.492,-0.714 0.441,-1.148 -0.072,-0.588 -0.543,-1.221 -1.661,-1.221 -0.342,0 -0.85,0.099 -0.872,0.103 -0.139,0.027 -0.235,0.164 -0.208,0.304 0.028,0.14 0.164,0.236 0.308,0.209 0.004,-0.004 0.482,-0.093 0.772,-0.093 0.67,0 1.087,0.277 1.146,0.759 0.064,0.544 -0.319,0.855 -0.834,0.855 h -0.517 c -0.143,0 -0.26,0.119 -0.26,0.263 0,0.143 0.117,0.26 0.26,0.26 h 0.571 c 0.646,0 0.93,0.417 0.977,0.81 0.068,0.557 -0.424,0.81 -0.912,0.81 -0.277,0 -0.77,-0.086 -0.775,-0.086 -0.141,-0.024 -0.278,0.069 -0.301,0.212 -0.025,0.14 0.068,0.277 0.211,0.301 0.021,0.003 0.544,0.096 0.865,0.096 0.813,0 1.535,-0.52 1.429,-1.398 C 0.592,0.639 0.38,0.243 0,0" + style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path1025" /> + transform="matrix(0.35277777,0,0,-0.35277777,54.230593,45.988784)" + style="display:inline"> + transform="matrix(0.35277777,0,0,-0.35277777,67.543482,45.877662)" + style="display:inline"> + transform="matrix(0.35277777,0,0,-0.35277777,81.264943,46.318984)" + style="display:inline"> + transform="matrix(0.35277777,0,0,-0.35277777,60.834841,59.196752)" + style="display:inline"> + id="g955" + transform="matrix(0.35277777,0,0,-0.35277777,81.828582,33.087772)" + style="display:inline"> - - + d="m 0,0 c -0.017,-0.144 -0.146,-0.243 -0.29,-0.226 -0.144,0.018 -0.243,0.147 -0.226,0.291 l 0.233,1.846 c 0.061,0.482 -0.123,0.782 -0.633,0.782 -0.397,0 -0.752,-0.259 -0.867,-0.382 C -1.77,2.194 -1.767,1.996 -1.787,1.846 L -2.02,0.007 c -0.017,-0.144 -0.15,-0.243 -0.291,-0.226 -0.142,0.017 -0.246,0.147 -0.228,0.291 l 0.236,1.839 c 0.061,0.471 -0.127,0.782 -0.626,0.782 -0.362,0 -0.834,-0.382 -0.834,-0.382 L -4.036,0.007 c -0.017,-0.144 -0.148,-0.243 -0.29,-0.226 -0.145,0.017 -0.243,0.147 -0.227,0.291 l 0.35,2.864 c 0.016,0.14 0.146,0.243 0.29,0.226 0.112,-0.014 0.202,-0.099 0.222,-0.205 0.209,0.143 0.468,0.259 0.762,0.259 0.38,0 0.725,-0.133 0.954,-0.441 0.233,0.195 0.612,0.441 1.059,0.441 0.824,0 1.248,-0.577 1.148,-1.37 z" + style="fill:#100f0d;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path957" /> - - + d="m 0,0 c -0.219,0 -0.622,-0.126 -0.748,-0.185 l -0.25,-2.074 c 0.232,-0.086 0.598,-0.195 0.779,-0.195 0.834,0 1.221,0.632 1.221,1.394 C 1.002,-0.455 0.625,0 0,0 m -0.219,-2.974 c -0.25,0 -0.619,0.11 -0.844,0.185 l -0.15,-1.2 c -0.017,-0.143 -0.147,-0.246 -0.291,-0.229 -0.143,0.017 -0.242,0.147 -0.225,0.291 l 0.512,4.17 c 0.018,0.14 0.147,0.242 0.287,0.225 0.082,-0.01 0.147,-0.054 0.188,-0.119 0.205,0.075 0.506,0.171 0.742,0.171 0.92,0 1.524,-0.691 1.524,-1.586 0,-1.046 -0.628,-1.908 -1.743,-1.908" + style="display:inline;fill:#100f0d;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path941" + transform="translate(-16.976611,2.6967969)" /> - - + d="m 0,0 c -0.1,0.051 -0.328,0.147 -0.639,0.147 -0.824,0 -1.268,-0.629 -1.268,-1.398 0,-0.578 0.331,-1.056 0.946,-1.056 0.268,0 0.66,0.171 0.719,0.249 z m 0.212,-2.55 c -0.017,-0.143 -0.148,-0.242 -0.29,-0.225 -0.082,0.01 -0.154,0.058 -0.192,0.126 -0.181,-0.096 -0.418,-0.178 -0.691,-0.178 -0.905,0 -1.469,0.708 -1.469,1.576 0,1.053 0.68,1.918 1.791,1.918 0.318,0 0.577,-0.076 0.748,-0.144 0.059,0.061 0.144,0.096 0.229,0.085 0.141,-0.017 0.243,-0.15 0.226,-0.29 z" + style="display:inline;fill:#100f0d;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path953" + transform="translate(-5.9063257,2.5499019)" /> - - + d="m 0,0 c -0.055,0.024 -0.223,0.082 -0.363,0.082 -0.167,0 -0.543,-0.123 -0.776,-0.267 l -0.287,-2.419 c -0.017,-0.144 -0.15,-0.243 -0.291,-0.226 -0.142,0.017 -0.246,0.147 -0.228,0.29 l 0.351,2.865 c 0.018,0.143 0.148,0.242 0.291,0.225 0.103,-0.013 0.185,-0.085 0.215,-0.177 0.227,0.116 0.506,0.232 0.725,0.232 0.277,0 0.544,-0.116 0.571,-0.126 C 0.342,0.417 0.399,0.263 0.342,0.133 0.283,0 0.129,-0.058 0,0" + style="display:inline;fill:#100f0d;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path949" + transform="translate(-8.9942183,2.6045019)" /> + d="m 0,0 c -0.099,0.051 -0.328,0.147 -0.64,0.147 -0.823,0 -1.267,-0.629 -1.267,-1.398 0,-0.578 0.332,-1.056 0.947,-1.056 0.266,0 0.659,0.171 0.717,0.249 z m 0.212,-2.55 c -0.018,-0.143 -0.147,-0.242 -0.291,-0.225 -0.082,0.01 -0.153,0.058 -0.192,0.126 -0.18,-0.096 -0.416,-0.178 -0.689,-0.178 -0.906,0 -1.471,0.708 -1.471,1.576 0,1.053 0.681,1.918 1.791,1.918 0.319,0 0.578,-0.076 0.749,-0.144 0.058,0.061 0.144,0.096 0.23,0.085 0.14,-0.017 0.242,-0.15 0.224,-0.29 z" + style="display:inline;fill:#100f0d;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path945" + transform="translate(-12.290116,2.5499019)" /> + id="g963-3" + transform="matrix(-0.35277777,0,0,-0.35277777,78.482423,23.337652)" + style="display:inline"> - - + d="M -5.5330983,-9.5830189 -12.24,-21.199" + style="fill:none;stroke:#100f0d;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path965-9" + sodipodi:nodetypes="cc" /> - - + d="M -5.5330983,-9.5830189 -12.24,-21.199" + style="display:inline;fill:none;stroke:#100f0d;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path965" + sodipodi:nodetypes="cc" + transform="matrix(-1,0,0,1,0.51293015,-0.27283434)" /> + d="M 0,10.493614 V 25.2" + style="display:inline;fill:none;stroke:#100f0d;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path961" + sodipodi:nodetypes="cc" + transform="matrix(-1,0,0,1,0.15154264,0.35166368)" /> + id="g975" + transform="matrix(0.35277777,0,0,-0.35277777,68.537391,19.98243)" + style="display:inline"> - - + d="m 0,0 c -0.017,-0.144 -0.15,-0.242 -0.29,-0.226 -0.144,0.017 -0.243,0.148 -0.226,0.29 l 0.226,1.782 c 0.065,0.512 -0.14,0.847 -0.684,0.847 -0.516,0 -1.039,-0.41 -1.039,-0.41 L -2.286,0.007 c -0.017,-0.144 -0.148,-0.243 -0.29,-0.226 -0.145,0.018 -0.243,0.147 -0.227,0.291 l 0.35,2.864 c 0.016,0.14 0.146,0.243 0.29,0.226 0.126,-0.017 0.222,-0.12 0.229,-0.243 0.249,0.157 0.58,0.298 0.96,0.298 0.865,0 1.306,-0.61 1.201,-1.44 z" + style="fill:#100f0d;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path977" /> + d="m 0,0 c -0.123,-0.126 -0.324,-0.134 -0.451,-0.011 -0.127,0.123 -0.13,0.325 -0.007,0.451 l 0.144,0.151 C -0.191,0.718 0.01,0.722 0.137,0.602 0.264,0.479 0.267,0.276 0.144,0.15 Z m -0.461,-4.323 c -0.018,-0.145 -0.147,-0.246 -0.291,-0.23 -0.144,0.017 -0.242,0.148 -0.226,0.29 l 0.349,2.862 c 0.018,0.143 0.147,0.25 0.291,0.228 0.14,-0.016 0.242,-0.15 0.225,-0.29 z" + style="display:inline;fill:#100f0d;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path973" + transform="translate(-3.482394,4.327098)" /> + id="g979" + transform="matrix(0.35277777,0,0,-0.35277777,14.337252,20.025152)" + style="display:inline"> + d="m 0,0 h -2.334 c -0.144,0 -0.26,0.116 -0.26,0.26 0,0.143 0.116,0.26 0.26,0.26 h 0.95 l 0.441,3.578 -0.889,-0.222 c -0.14,-0.034 -0.28,0.051 -0.314,0.191 -0.035,0.141 0.051,0.281 0.188,0.315 l 1.254,0.311 c 0.085,0.02 0.171,0 0.236,-0.055 0.065,-0.058 0.095,-0.143 0.085,-0.229 L -0.858,0.52 H 0 C 0.144,0.52 0.263,0.403 0.263,0.26 0.263,0.116 0.144,0 0,0" + style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path981" /> + id="g983" + transform="matrix(0.35277777,0,0,-0.35277777,47.611181,59.903182)" + style="display:inline"> + d="m 0,0 h -2.334 c -0.145,0 -0.26,0.116 -0.26,0.26 0,0.143 0.115,0.26 0.26,0.26 h 0.949 l 0.442,3.578 -0.889,-0.222 c -0.141,-0.034 -0.28,0.051 -0.314,0.191 -0.035,0.141 0.05,0.281 0.187,0.315 l 1.255,0.311 c 0.085,0.02 0.171,0 0.235,-0.055 0.066,-0.058 0.096,-0.143 0.086,-0.229 L -0.857,0.52 H 0 C 0.144,0.52 0.264,0.403 0.264,0.26 0.264,0.116 0.144,0 0,0" + style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path985" /> - - - TELETYPE - - - - - - - - - + id="g987" + transform="matrix(0.35277777,0,0,-0.35277777,41.007281,46.695182)" + style="display:inline"> + d="m 0,0 h -2.334 c -0.144,0 -0.26,0.116 -0.26,0.26 0,0.143 0.116,0.26 0.26,0.26 h 0.95 l 0.441,3.578 -0.889,-0.222 c -0.14,-0.034 -0.28,0.051 -0.314,0.191 -0.035,0.141 0.051,0.281 0.188,0.315 l 1.254,0.311 c 0.085,0.02 0.171,0 0.236,-0.055 0.065,-0.058 0.095,-0.143 0.085,-0.229 L -0.858,0.52 H 0 C 0.144,0.52 0.263,0.403 0.263,0.26 0.263,0.116 0.144,0 0,0" + style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path989" /> diff --git a/res/whitewhale-dark.svg b/res/whitewhale-dark.svg new file mode 100644 index 0000000..9a91a77 --- /dev/null +++ b/res/whitewhale-dark.svg @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/whitewhale.svg b/res/whitewhale.svg index aedebaa..39a9aae 100644 --- a/res/whitewhale.svg +++ b/res/whitewhale.svg @@ -16,25 +16,48 @@ xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> + id="defs4535"> + + + + + + + style="display:inline;fill:url(#linearGradient47118);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.243982" + d="m 61.978028,53.744307 h 23.85 V 154.24031 h -23.85 z m 0,0" + id="path1140" /> - - - + inkscape:label="Stroked Marks"> + d="m 68.897677,70.146518 -1.931925,3.477466 m 5.242769,-3.448952 1.853074,3.369225 m -3.463941,-9.907574 c 0.01187,-0.949667 0.02374,-1.899333 0.03561,-2.849" + style="fill:none;stroke:#000000;stroke-width:0.165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path8099" + sodipodi:nodetypes="cccccc" /> + sodipodi:nodetypes="cccc" /> @@ -230,188 +237,188 @@ sodipodi:role="line">out + style="font-style:italic;font-size:50.8px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94049px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264612px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> + style="font-style:italic;font-size:1.94028px;line-height:100%;font-family:CoreHumanistSans;-inkscape-font-specification:'CoreHumanistSans, Italic';letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;stroke:none;stroke-width:0.264583px;fill-opacity:1"> diff --git a/src/ansible/AnsibleModule.hpp b/src/ansible/AnsibleModule.hpp index 4a1f560..8e3c3b2 100644 --- a/src/ansible/AnsibleModule.hpp +++ b/src/ansible/AnsibleModule.hpp @@ -54,7 +54,7 @@ struct AnsibleModule : LibAVR32Module rack::dsp::SchmittTrigger inputTriggers[2]; AnsibleModule() - : LibAVR32Module("ansible") + : LibAVR32Module("ansible", "ansible") { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configButton(KEY1_PARAM, "KEY 1"); diff --git a/src/ansible/AnsibleWidget.hpp b/src/ansible/AnsibleWidget.hpp index 1e390fd..13eab7a 100644 --- a/src/ansible/AnsibleWidget.hpp +++ b/src/ansible/AnsibleWidget.hpp @@ -17,31 +17,33 @@ struct AnsibleWidget : LibAVR32ModuleWidget box.size = Vec(15 * 6, 380); { - auto panel = new SvgPanel(); - panel->setBackground(APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/ansible.svg"))); + auto panel = new ThemedSvgPanel(); + panel->setBackground( + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/ansible.svg")), + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/ansible-dark.svg"))); panel->box.size = box.size; addChild(panel); } - addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, 0))); - addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addParam(createParam(Vec(7, 333), module, AnsibleModule::USB_PARAM)); addParam(createParam(Vec(62, 336), module, AnsibleModule::MODE_PARAM)); addParam(createParam(Vec(19, 256), module, AnsibleModule::KEY1_PARAM)); addParam(createParam(Vec(54, 256), module, AnsibleModule::KEY2_PARAM)); - addOutput(createOutput(Vec(15, 54), module, AnsibleModule::TR1_OUTPUT)); - addOutput(createOutput(Vec(50, 75), module, AnsibleModule::CV1_OUTPUT)); - addOutput(createOutput(Vec(15, 92), module, AnsibleModule::TR2_OUTPUT)); - addOutput(createOutput(Vec(50, 111), module, AnsibleModule::CV2_OUTPUT)); - addOutput(createOutput(Vec(15, 130), module, AnsibleModule::TR3_OUTPUT)); - addOutput(createOutput(Vec(50, 149), module, AnsibleModule::CV3_OUTPUT)); - addOutput(createOutput(Vec(15, 168), module, AnsibleModule::TR4_OUTPUT)); - addOutput(createOutput(Vec(50, 187), module, AnsibleModule::CV4_OUTPUT)); - - addInput(createInput(Vec(15, 286), module, AnsibleModule::IN1_INPUT)); - addInput(createInput(Vec(50, 286), module, AnsibleModule::IN2_INPUT)); + addOutput(createOutput(Vec(15, 54), module, AnsibleModule::TR1_OUTPUT)); + addOutput(createOutput(Vec(50, 75), module, AnsibleModule::CV1_OUTPUT)); + addOutput(createOutput(Vec(15, 92), module, AnsibleModule::TR2_OUTPUT)); + addOutput(createOutput(Vec(50, 111), module, AnsibleModule::CV2_OUTPUT)); + addOutput(createOutput(Vec(15, 130), module, AnsibleModule::TR3_OUTPUT)); + addOutput(createOutput(Vec(50, 149), module, AnsibleModule::CV3_OUTPUT)); + addOutput(createOutput(Vec(15, 168), module, AnsibleModule::TR4_OUTPUT)); + addOutput(createOutput(Vec(50, 187), module, AnsibleModule::CV4_OUTPUT)); + + addInput(createInput(Vec(15, 286), module, AnsibleModule::IN1_INPUT)); + addInput(createInput(Vec(50, 286), module, AnsibleModule::IN2_INPUT)); addChild(createLight>(Vec(3, 72), module, AnsibleModule::TR1_LIGHT)); addChild(createLight>(Vec(77, 72), module, AnsibleModule::CV1_LIGHT)); diff --git a/src/common/core/FirmwareManager.cpp b/src/common/core/FirmwareManager.cpp index 9fa9986..51729fa 100644 --- a/src/common/core/FirmwareManager.cpp +++ b/src/common/core/FirmwareManager.cpp @@ -6,6 +6,9 @@ #include #include #include +#include + +namespace fs = ghc::filesystem; extern rack::Plugin* pluginInstance; @@ -108,6 +111,14 @@ struct FirmwareManagerImpl std::string librarySource; librarySource = rack::asset::plugin(pluginInstance, "res/firmware/" + firmwareName + LIB_EXTENSION); + + std::error_code ec; + if (!fs::is_regular_file(fs::status(librarySource, ec))) + { + WARN("Requested firmware not found or invalid"); + return false; + } + std::string libraryToLoad = librarySource; // If we have already loaded this firmware at least once, create a temp copy so it will have its own address space @@ -181,12 +192,19 @@ struct FirmwareManagerImpl #if ARCH_WIN - wchar_t* libName = new wchar_t[4096]; - MultiByteToWideChar(CP_ACP, 0, libraryToLoad.c_str(), -1, libName, 4096); + int wideLength = MultiByteToWideChar(CP_UTF8, 0, libraryToLoad.c_str(), -1, nullptr, 0); + if (wideLength > 0) + { + std::vector wideLibName(wideLength); + wideLength = MultiByteToWideChar(CP_UTF8, 0, libraryToLoad.c_str(), -1, wideLibName.data(), wideLength); + if (wideLength > 0) + { + SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + handle = LoadLibraryW(wideLibName.data()); + SetErrorMode(0); + } + } - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); - handle = LoadLibrary(libName); - SetErrorMode(0); if (!handle) { int error = GetLastError(); @@ -230,16 +248,23 @@ FirmwareManager::~FirmwareManager() delete impl; } -bool FirmwareManager::load(std::string modulePath) +const std::string FirmwareManager::getLibExtension() +{ + return LIB_EXTENSION; +} + +bool FirmwareManager::load(std::string firmwareName) { delete impl; impl = new FirmwareManagerImpl(); - if (!impl->load(modulePath)) + if (!impl->load(firmwareName)) { + delete impl; impl = nullptr; - WARN("Could not load firmware %s", modulePath.c_str()); + WARN("Could not load firmware %s", firmwareName.c_str()); return false; } + loadedName = firmwareName; return true; } diff --git a/src/common/core/FirmwareManager.hpp b/src/common/core/FirmwareManager.hpp index 603168e..d6401f0 100644 --- a/src/common/core/FirmwareManager.hpp +++ b/src/common/core/FirmwareManager.hpp @@ -16,9 +16,13 @@ struct FirmwareManager FirmwareManager(); ~FirmwareManager(); - bool load(std::string firmwarePath); + const std::string getLibExtension(); + + bool load(std::string firmwareName); void unload(); + const std::string& getLoadedName() const { return loadedName; } + void setClockPeriod(float seconds); void advanceClock(float seconds); @@ -30,4 +34,6 @@ struct FirmwareManager #include "mock_hardware_api.h" struct FirmwareManagerImpl* impl; +protected: + std::string loadedName; }; \ No newline at end of file diff --git a/src/common/core/LibAVR32Module.cpp b/src/common/core/LibAVR32Module.cpp index 518de00..81bf3e4 100644 --- a/src/common/core/LibAVR32Module.cpp +++ b/src/common/core/LibAVR32Module.cpp @@ -1,16 +1,23 @@ #include "LibAVR32Module.hpp" +#include "SerialOscInterface.hpp" #include "base64.h" #include -LibAVR32Module::LibAVR32Module(std::string firmwareName) +LibAVR32Module::LibAVR32Module(std::string firmwarePrefix, std::string defaultFirmwareName) : lastConnectedDeviceId("") , currentConnectedDeviceId("") -, firmwareName(firmwareName) +, firmwarePrefix(firmwarePrefix) +, firmwareName(defaultFirmwareName) +, defaultFirmwareName(defaultFirmwareName) , usbParamId(-1) , theme(GridTheme::Yellow) { gridConnection = nullptr; + // make sure serialosc is fully initialized by the time + // the user needs to interact with it + SerialOscInterface::get(); + dacOffsetVolts = 0.0007; triggerHighThreshold = 2.21; triggerLowThreshold = 0.8; @@ -279,16 +286,21 @@ void LibAVR32Module::readSerialMessages() } } -void LibAVR32Module::requestReloadFirmware(bool preserveMemory) +void LibAVR32Module::requestReloadFirmware(bool preserveMemory, const std::string& firmwareName) { - audioThreadActions.push([this, preserveMemory]() { this->reloadFirmware(preserveMemory); }); + audioThreadActions.push([this, preserveMemory, firmwareName]() { this->reloadFirmware(preserveMemory, firmwareName); }); } -void LibAVR32Module::reloadFirmware(bool preserveMemory) +void LibAVR32Module::reloadFirmware(bool preserveMemory, const std::string& newName) { void *data, *nvram_copy, *vram_copy = 0; uint32_t nvram_size, vram_size = 0; + firmwareName = newName.empty() ? firmware.getLoadedName() : newName; + if (firmwareName != firmware.getLoadedName()) { + preserveMemory = false; + } + if (preserveMemory) { firmware.readNVRAM(&data, &nvram_size); nvram_copy = malloc(nvram_size); @@ -356,6 +368,7 @@ json_t* LibAVR32Module::dataToJson() } json_t* rootJ = json_object(); + json_object_set_new(rootJ, "firmwareName", json_string(firmwareName.c_str())); json_object_set_new(rootJ, "connectedDeviceId", json_string(deviceId.c_str())); json_object_set_new(rootJ, "connectionOwned", json_boolean(connectionOwned)); json_object_set_new(rootJ, "inputRate", json_integer(inputRate)); @@ -381,6 +394,14 @@ json_t* LibAVR32Module::dataToJson() void LibAVR32Module::dataFromJson(json_t* rootJ) { + json_t* jsonFirmwareName = json_object_get(rootJ, "firmwareName"); + std::string newFirmwareName = jsonFirmwareName ? json_string_value(jsonFirmwareName) : defaultFirmwareName; + + if (newFirmwareName != firmwareName) + { + reloadFirmware(false, newFirmwareName); + } + json_t* id = json_object_get(rootJ, "connectedDeviceId"); if (id) { diff --git a/src/common/core/LibAVR32Module.hpp b/src/common/core/LibAVR32Module.hpp index 71b2cf4..dc5186b 100644 --- a/src/common/core/LibAVR32Module.hpp +++ b/src/common/core/LibAVR32Module.hpp @@ -34,7 +34,7 @@ struct LibAVR32Module : rack::engine::Module, GridConsumer { FirmwareManager firmware; - LibAVR32Module(std::string firmwareName); + LibAVR32Module(std::string firmwarePrefix, std::string defaultFirmwareName); ~LibAVR32Module(); // Rack module methods @@ -60,7 +60,7 @@ struct LibAVR32Module : rack::engine::Module, GridConsumer void userToggleGridConnection(Grid* grid); virtual void readSerialMessages(); - void requestReloadFirmware(bool preserveMemory); + void requestReloadFirmware(bool preserveMemory, const std::string& firmwareName = ""); float dacToVolts(uint16_t adc); uint16_t voltsToAdc(float volts); @@ -69,7 +69,9 @@ struct LibAVR32Module : rack::engine::Module, GridConsumer std::string currentConnectedDeviceId; bool connectionOwned; + std::string firmwarePrefix; std::string firmwareName; + std::string defaultFirmwareName; int inputRate; int outputRate; @@ -79,7 +81,7 @@ struct LibAVR32Module : rack::engine::Module, GridConsumer virtual uint8_t* getScreenBuffer() { return 0; } protected: - void reloadFirmware(bool preserveMemory); + void reloadFirmware(bool preserveMemory, const std::string& newFirmware = ""); void toggleGridConnection(Grid* grid); Grid* gridConnection; diff --git a/src/common/core/LibAVR32ModuleWidget.cpp b/src/common/core/LibAVR32ModuleWidget.cpp index 6619851..a40fc87 100644 --- a/src/common/core/LibAVR32ModuleWidget.cpp +++ b/src/common/core/LibAVR32ModuleWidget.cpp @@ -5,6 +5,10 @@ #include "SerialOscInterface.hpp" #include "Screenshot.hpp" +#include + +namespace fs = ghc::filesystem; + using namespace rack; struct ConnectGridItem : rack::ui::MenuItem @@ -31,6 +35,54 @@ struct ReloadFirmwareItem : rack::ui::MenuItem } }; +struct SwitchFirmwareItem : rack::ui::MenuItem +{ + LibAVR32Module* module; + + ui::Menu* createChildMenu() override + { + // duplicate filenames that may be left in res folder by prior versions + std::vector ignoreList = {"teletype", "ansible 2", "earthsea 2", "meadowphysics 2", "teletype 2", "whitewhale 2"}; + std::vector fwNames = {}; + + const fs::path fwPath{rack::asset::plugin(pluginInstance, "res/firmware")}; + for (auto const& file : fs::directory_iterator{fwPath}) + { + auto name = file.path().stem().string(); + auto extension = file.path().extension().string(); + if (extension == module->firmware.getLibExtension() && + name.substr(0, module->firmwarePrefix.size()) == module->firmwarePrefix && + std::find(std::begin(ignoreList), std::end(ignoreList), name) == std::end(ignoreList)) + { + fwNames.push_back(name); + } + } + + bool currentMissing = false; + if (std::find(std::begin(fwNames), std::end(fwNames), module->firmwareName) == std::end(fwNames)) + { + fwNames.push_back(module->firmwareName); + currentMissing = true; + } + + ui::Menu* menu = new ui::Menu; + + for (auto const& name : fwNames) + { + menu->addChild(createCheckMenuItem( + name, + (currentMissing && (module->firmwareName == name)) ? "(missing)" : "", + [=]() + { return module->firmwareName == name; }, + [=]() + { module->requestReloadFirmware(false, name); } + )); + } + + return menu; + } +}; + struct ioRateItem : rack::ui::MenuItem { int* target = nullptr; @@ -91,6 +143,11 @@ struct FirmwareSubmenuItem : MenuItem menu->addChild(new MenuSeparator()); + menu->addChild(construct( + &MenuItem::text, "Switch Firmware", &MenuItem::rightText, RIGHT_ARROW, + &SwitchFirmwareItem::module, m + )); + auto reloadItem = new ReloadFirmwareItem(); reloadItem->text = "Reload & Restart"; reloadItem->module = m; diff --git a/src/earthsea/EarthseaModule.hpp b/src/earthsea/EarthseaModule.hpp index 0bf0dc5..55830f0 100644 --- a/src/earthsea/EarthseaModule.hpp +++ b/src/earthsea/EarthseaModule.hpp @@ -40,7 +40,7 @@ struct EarthseaModule : LibAVR32Module }; EarthseaModule() - : LibAVR32Module("earthsea") + : LibAVR32Module("earthsea", "earthsea") { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); diff --git a/src/earthsea/EarthseaWidget.hpp b/src/earthsea/EarthseaWidget.hpp index e862f76..0e749ad 100644 --- a/src/earthsea/EarthseaWidget.hpp +++ b/src/earthsea/EarthseaWidget.hpp @@ -16,15 +16,17 @@ struct EarthseaWidget : LibAVR32ModuleWidget box.size = Vec(15 * 6, 380); { - auto panel = new SvgPanel(); - panel->setBackground(APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/earthsea.svg"))); + auto panel = new ThemedSvgPanel(); + panel->setBackground( + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/earthsea.svg")), + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/earthsea-dark.svg"))); panel->box.size = box.size; addChild(panel); } // Screws positioned for sliding nuts :) - addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, 0))); - addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addParam(createParam(Vec(7, 333), module, EarthseaModule::USB_PARAM)); addParam(createParam(Vec(62, 336), module, EarthseaModule::BUTTON_PARAM)); @@ -32,11 +34,11 @@ struct EarthseaWidget : LibAVR32ModuleWidget addParam(createParam(Vec(12.5, 116), module, EarthseaModule::CV2_PARAM)); addParam(createParam(Vec(12.5, 202), module, EarthseaModule::CV3_PARAM)); - addOutput(createOutput(Vec(50, 82), module, EarthseaModule::CV1_OUTPUT)); - addOutput(createOutput(Vec(50, 166), module, EarthseaModule::CV2_OUTPUT)); - addOutput(createOutput(Vec(50, 248), module, EarthseaModule::CV3_OUTPUT)); - addOutput(createOutput(Vec(50, 286), module, EarthseaModule::POS_OUTPUT)); - addOutput(createOutput(Vec(15, 265), module, EarthseaModule::EDGE_OUTPUT)); + addOutput(createOutput(Vec(50, 82), module, EarthseaModule::CV1_OUTPUT)); + addOutput(createOutput(Vec(50, 166), module, EarthseaModule::CV2_OUTPUT)); + addOutput(createOutput(Vec(50, 248), module, EarthseaModule::CV3_OUTPUT)); + addOutput(createOutput(Vec(50, 286), module, EarthseaModule::POS_OUTPUT)); + addOutput(createOutput(Vec(15, 265), module, EarthseaModule::EDGE_OUTPUT)); addChild(createLight>(Vec(77, 78), module, EarthseaModule::CV1_LIGHT)); addChild(createLight>(Vec(77, 162), module, EarthseaModule::CV2_LIGHT)); diff --git a/src/faderbank/FaderbankWidget.cpp b/src/faderbank/FaderbankWidget.cpp index 3cd26da..b568884 100644 --- a/src/faderbank/FaderbankWidget.cpp +++ b/src/faderbank/FaderbankWidget.cpp @@ -35,7 +35,7 @@ FaderbankWidget::FaderbankWidget(FaderbankModule* module) for (int i = 0; i < NUM_FADERS; i++) { - addOutput(createOutput(Vec(26 + 43 * i, 26), module, i)); + addOutput(createOutput(Vec(26 + 43 * i, 26), module, i)); addParam(createParam(Vec(23 + 43 * i, 66), module, i)); } } diff --git a/src/meadowphysics/MeadowphysicsModule.hpp b/src/meadowphysics/MeadowphysicsModule.hpp index 4511dc4..ac395cb 100644 --- a/src/meadowphysics/MeadowphysicsModule.hpp +++ b/src/meadowphysics/MeadowphysicsModule.hpp @@ -50,7 +50,7 @@ struct MeadowphysicsModule : LibAVR32Module rack::dsp::SchmittTrigger clockTrigger; MeadowphysicsModule() - : LibAVR32Module("meadowphysics") + : LibAVR32Module("meadowphysics", "meadowphysics") { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configButton(BUTTON_PARAM, "PRESET"); diff --git a/src/meadowphysics/MeadowphysicsWidget.hpp b/src/meadowphysics/MeadowphysicsWidget.hpp index ca95098..e2b2377 100644 --- a/src/meadowphysics/MeadowphysicsWidget.hpp +++ b/src/meadowphysics/MeadowphysicsWidget.hpp @@ -15,30 +15,32 @@ struct MeadowphysicsWidget : LibAVR32ModuleWidget box.size = Vec(15 * 6, 380); { - auto panel = new SvgPanel(); - panel->setBackground(APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/meadowphysics.svg"))); + auto panel = new ThemedSvgPanel(); + panel->setBackground( + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/meadowphysics.svg")), + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/meadowphysics-dark.svg"))); panel->box.size = box.size; addChild(panel); } // Screws positioned for sliding nuts :) - addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, 0))); - addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addParam(createParam(Vec(7, 333), module, MeadowphysicsModule::USB_PARAM)); addParam(createParam(Vec(62, 336), module, MeadowphysicsModule::BUTTON_PARAM)); addParam(createParam(Vec(12, 232), module, MeadowphysicsModule::CLOCK_PARAM)); - addOutput(createOutput(Vec(15, 54), module, MeadowphysicsModule::TR1_OUTPUT)); - addOutput(createOutput(Vec(50, 75), module, MeadowphysicsModule::TR2_OUTPUT)); - addOutput(createOutput(Vec(15, 92), module, MeadowphysicsModule::TR3_OUTPUT)); - addOutput(createOutput(Vec(50, 113), module, MeadowphysicsModule::TR4_OUTPUT)); - addOutput(createOutput(Vec(15, 130), module, MeadowphysicsModule::TR5_OUTPUT)); - addOutput(createOutput(Vec(50, 151), module, MeadowphysicsModule::TR6_OUTPUT)); - addOutput(createOutput(Vec(15, 168), module, MeadowphysicsModule::TR7_OUTPUT)); - addOutput(createOutput(Vec(50, 189), module, MeadowphysicsModule::TR8_OUTPUT)); - addInput(createInput(Vec(15, 286), module, MeadowphysicsModule::CLOCK_INPUT)); - addOutput(createOutput(Vec(50, 286), module, MeadowphysicsModule::CLOCK_OUTPUT)); + addOutput(createOutput(Vec(15, 54), module, MeadowphysicsModule::TR1_OUTPUT)); + addOutput(createOutput(Vec(50, 75), module, MeadowphysicsModule::TR2_OUTPUT)); + addOutput(createOutput(Vec(15, 92), module, MeadowphysicsModule::TR3_OUTPUT)); + addOutput(createOutput(Vec(50, 113), module, MeadowphysicsModule::TR4_OUTPUT)); + addOutput(createOutput(Vec(15, 130), module, MeadowphysicsModule::TR5_OUTPUT)); + addOutput(createOutput(Vec(50, 151), module, MeadowphysicsModule::TR6_OUTPUT)); + addOutput(createOutput(Vec(15, 168), module, MeadowphysicsModule::TR7_OUTPUT)); + addOutput(createOutput(Vec(50, 189), module, MeadowphysicsModule::TR8_OUTPUT)); + addInput(createInput(Vec(15, 286), module, MeadowphysicsModule::CLOCK_INPUT)); + addOutput(createOutput(Vec(50, 286), module, MeadowphysicsModule::CLOCK_OUTPUT)); addChild(createLight>(Vec(3, 71), module, MeadowphysicsModule::TR1_LIGHT)); addChild(createLight>(Vec(77, 71), module, MeadowphysicsModule::TR2_LIGHT)); diff --git a/src/teletype/TeletypeModule.cpp b/src/teletype/TeletypeModule.cpp index 17ceed4..10c39e1 100644 --- a/src/teletype/TeletypeModule.cpp +++ b/src/teletype/TeletypeModule.cpp @@ -32,7 +32,7 @@ struct TTParamQuantity : rack::engine::ParamQuantity }; TeletypeModule::TeletypeModule() -: LibAVR32Module("teletype") +: LibAVR32Module("teletype", "teletype4") , _iiDevice(this) , screenBuffer{} { diff --git a/src/teletype/TeletypeWidget.cpp b/src/teletype/TeletypeWidget.cpp index 97ceb4e..f3a35a4 100644 --- a/src/teletype/TeletypeWidget.cpp +++ b/src/teletype/TeletypeWidget.cpp @@ -12,28 +12,22 @@ TeletypeWidget::TeletypeWidget(TeletypeModule* module) box.size = Vec(15 * 18, 380); { - auto panel = new SvgPanel(); - panel->setBackground(APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/teletype.svg"))); + auto panel = new ThemedSvgPanel(); + panel->setBackground( + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/teletype.svg")), + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/teletype-dark.svg"))); panel->box.size = box.size; addChild(panel); } - - // addChild(createScrew(Vec(15, 0))); - // addChild(createScrew(Vec(15, 365))); - // addChild(createScrew(Vec(239, 0))); - // addChild(createScrew(Vec(239, 365))); - 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))); + 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))); addParam(createParam(Vec(7, 333), module, TeletypeModule::USB_PARAM)); addParam(createParam(Vec(62, 337), module, TeletypeModule::BUTTON_PARAM)); - // addChild(createScrew(Vec(11, 312))); - // addChild(createScrew(Vec(244, 312))); - screen = new TeletypeScreenWidget(module); screen->box.pos = Vec(30, 200); screen->box.size = Vec(210, 112); @@ -41,25 +35,25 @@ TeletypeWidget::TeletypeWidget(TeletypeModule* module) addParam(createParam(Vec(211, 47.5), module, TeletypeModule::PARAM_PARAM)); - addInput(createInput(Vec(11, 38.5), module, TeletypeModule::TRIG1_INPUT)); - addInput(createInput(Vec(50.5, 38.5), module, TeletypeModule::TRIG3_INPUT)); - addInput(createInput(Vec(90, 38.5), module, TeletypeModule::TRIG5_INPUT)); - addInput(createInput(Vec(130, 38.5), module, TeletypeModule::TRIG7_INPUT)); - addInput(createInput(Vec(30, 77.5), module, TeletypeModule::TRIG2_INPUT)); - addInput(createInput(Vec(69.5, 77.5), module, TeletypeModule::TRIG4_INPUT)); - addInput(createInput(Vec(109, 77.5), module, TeletypeModule::TRIG6_INPUT)); - addInput(createInput(Vec(148.5, 77.5), module, TeletypeModule::TRIG8_INPUT)); - - addInput(createInput(Vec(169, 38.5), module, TeletypeModule::IN_INPUT)); - - addOutput(createOutput(Vec(90, 117.5), module, TeletypeModule::TR1_OUTPUT)); - addOutput(createOutput(Vec(129.5, 117.5), module, TeletypeModule::TR2_OUTPUT)); - addOutput(createOutput(Vec(169, 117.5), module, TeletypeModule::TR3_OUTPUT)); - addOutput(createOutput(Vec(208.5, 117.5), module, TeletypeModule::TR4_OUTPUT)); - addOutput(createOutput(Vec(109, 157.5), module, TeletypeModule::CV1_OUTPUT)); - addOutput(createOutput(Vec(148.5, 157.5), module, TeletypeModule::CV2_OUTPUT)); - addOutput(createOutput(Vec(188, 157.5), module, TeletypeModule::CV3_OUTPUT)); - addOutput(createOutput(Vec(227.5, 157.5), module, TeletypeModule::CV4_OUTPUT)); + addInput(createInput(Vec(11, 38.5), module, TeletypeModule::TRIG1_INPUT)); + addInput(createInput(Vec(50.5, 38.5), module, TeletypeModule::TRIG3_INPUT)); + addInput(createInput(Vec(90, 38.5), module, TeletypeModule::TRIG5_INPUT)); + addInput(createInput(Vec(130, 38.5), module, TeletypeModule::TRIG7_INPUT)); + addInput(createInput(Vec(30, 77.5), module, TeletypeModule::TRIG2_INPUT)); + addInput(createInput(Vec(69.5, 77.5), module, TeletypeModule::TRIG4_INPUT)); + addInput(createInput(Vec(109, 77.5), module, TeletypeModule::TRIG6_INPUT)); + addInput(createInput(Vec(148.5, 77.5), module, TeletypeModule::TRIG8_INPUT)); + + addInput(createInput(Vec(169, 38.5), module, TeletypeModule::IN_INPUT)); + + addOutput(createOutput(Vec(90, 117.5), module, TeletypeModule::TR1_OUTPUT)); + addOutput(createOutput(Vec(129.5, 117.5), module, TeletypeModule::TR2_OUTPUT)); + addOutput(createOutput(Vec(169, 117.5), module, TeletypeModule::TR3_OUTPUT)); + addOutput(createOutput(Vec(208.5, 117.5), module, TeletypeModule::TR4_OUTPUT)); + addOutput(createOutput(Vec(109, 157.5), module, TeletypeModule::CV1_OUTPUT)); + addOutput(createOutput(Vec(148.5, 157.5), module, TeletypeModule::CV2_OUTPUT)); + addOutput(createOutput(Vec(188, 157.5), module, TeletypeModule::CV3_OUTPUT)); + addOutput(createOutput(Vec(227.5, 157.5), module, TeletypeModule::CV4_OUTPUT)); addChild(createLight>(Vec(117, 112), module, TeletypeModule::TR1_LIGHT)); addChild(createLight>(Vec(156.5, 112), module, TeletypeModule::TR2_LIGHT)); diff --git a/src/teletype/screen/TeletypeScreenWidget.cpp b/src/teletype/screen/TeletypeScreenWidget.cpp index cef72df..02fb54f 100644 --- a/src/teletype/screen/TeletypeScreenWidget.cpp +++ b/src/teletype/screen/TeletypeScreenWidget.cpp @@ -206,23 +206,26 @@ void TeletypeScreenWidget::drawLayer(const DrawArgs& args, int layer) void TeletypeScreenWidget::drawFrame(NVGcontext* vg) { + NVGcolor hiColor = !settings::preferDarkPanels ? nvgRGB(250, 250, 250) : nvgRGB(96, 96, 94); + NVGcolor loColor = !settings::preferDarkPanels ? nvgRGB(140, 140, 130) : nvgRGB(20, 20, 5); + // draw skeumorphic shadow around screen float t = 0.95; float r = 2.75; nvgBeginPath(vg); nvgRoundedRect(vg, box.size.x - t, -t, 2 * t, box.size.y + t, r); - nvgFillColor(vg, nvgRGB(250, 250, 240)); + nvgFillColor(vg, hiColor); nvgFill(vg); nvgBeginPath(vg); nvgRoundedRect(vg, -t, -t, box.size.x + 2 * t, 2 * t, r); nvgRoundedRect(vg, -t, -t, 2 * t, box.size.y + t, r); - nvgFillColor(vg, nvgRGB(140, 140, 130)); + nvgFillColor(vg, loColor); nvgFill(vg); nvgBeginPath(vg); nvgRoundedRect(vg, -t, box.size.y - t, box.size.x + 2 * t, 2 * t, r); - nvgFillColor(vg, nvgRGB(250, 250, 240)); + nvgFillColor(vg, hiColor); nvgFill(vg); // draw the empty screen diff --git a/src/virtualgrid/VirtualGridKey.hpp b/src/virtualgrid/VirtualGridKey.hpp index ee44227..b241da4 100644 --- a/src/virtualgrid/VirtualGridKey.hpp +++ b/src/virtualgrid/VirtualGridKey.hpp @@ -60,14 +60,9 @@ struct VirtualGridKey : rack::app::ParamWidget &color2 ); - // if (isLocked()) - // { - // // draw highlight rect around key - // nvgBeginPath(vg); - // nvgRoundedRect(vg, 0, pushAmount, rect.x + 2 * margin, rect.y + margin, 5.3); - // nvgFillColor(vg, nvgRGB(190, 180, 0)); - // nvgFill(vg); - // } + NVGcolor edgeColor = !rack::settings::preferDarkPanels ? nvgRGB(180, 180, 180) : nvgRGB(96, 96, 94); + NVGcolor shadowColor = !rack::settings::preferDarkPanels ? nvgRGB(140, 140, 140) : nvgRGB(60, 60, 50); + NVGcolor faceColor = !rack::settings::preferDarkPanels ? nvgRGB(58, 58, 58) : nvgRGB(20, 20, 10); if (!pushed) { @@ -75,7 +70,7 @@ struct VirtualGridKey : rack::app::ParamWidget if ((val > 0 && layer == 1) || (val == 0 && layer == 0)) { nvgBeginPath(vg); nvgRoundedRect(vg, x - 0.3, y - 0.3, rect.x + 0.6, rect.y + 0.3, cornerRadius); - nvgFillColor(vg, val > 0 ? color1 : nvgRGB(180, 180, 180)); + nvgFillColor(vg, val > 0 ? color1 : edgeColor); nvgFill(vg); } @@ -83,7 +78,7 @@ struct VirtualGridKey : rack::app::ParamWidget if (layer == 0) { nvgBeginPath(vg); nvgRoundedRect(vg, x, y + pushAmount, rect.x, rect.y - pushAmount + 1.2, innerCornerRadius); - nvgFillColor(vg, nvgRGB(160, 160, 160)); + nvgFillColor(vg, shadowColor); nvgFill(vg); } } else { @@ -91,14 +86,14 @@ struct VirtualGridKey : rack::app::ParamWidget if ((val > 0 && layer == 1) || (val == 0 && layer == 0)) { nvgBeginPath(vg); nvgRoundedRect(vg, x - 0.3, y - 0.3 + pushAmount, rect.x + 0.6, rect.y - pushAmount + 0.3, cornerRadius); - nvgFillColor(vg, val > 0 ? color1 : nvgRGB(180, 180, 180)); + nvgFillColor(vg, val > 0 ? color1 : edgeColor); nvgFill(vg); } // shadow if (layer == 0) { nvgBeginPath(vg); nvgRoundedRect(vg, x, y + pushAmount, rect.x, rect.y - pushAmount + 0.8, innerCornerRadius); - nvgFillColor(vg, nvgRGB(160, 160, 160)); + nvgFillColor(vg, shadowColor); nvgFill(vg); } } @@ -108,7 +103,7 @@ struct VirtualGridKey : rack::app::ParamWidget if ((val > 0 && layer == 1) || (val == 0 && layer == 0)) { nvgBeginPath(vg); nvgRoundedRect(vg, x, y + rect.y - (pushAmount + 10), rect.x, pushAmount + 10, innerCornerRadius); - nvgFillColor(vg, val > 0 ? color2 : nvgRGB(58, 58, 58)); + nvgFillColor(vg, val > 0 ? color2 : faceColor); nvgFill(vg); } } @@ -138,41 +133,10 @@ struct VirtualGridKey : rack::app::ParamWidget levelToGradient(theme ? *theme : GridTheme::Yellow, 14, &lockColor, nullptr); } - // drawLock(args, x, y + rect.y/2, rect.x/2, rect.y/2, lockColor); drawDot(args, x + rect.x / 4, y + 3 * rect.y / 4, rect.x / 4 - 1.5 * margin, lockColor); - // drawPin(args, x + 1.5 * margin, y + rect.y * 0.6, rect.x * 0.4 - 1.5 * margin, rect.y * 0.4 - 1.5 * margin, lockColor); } } - void drawPin(const DrawArgs& args, float x, float y, float w, float h, NVGcolor& color) - { - auto vg = args.vg; - - float d = w / (2 / 1.41421356 + 1); - float s = w - d; - - nvgBeginPath(vg); - nvgMoveTo(vg, x, y + w); - nvgLineTo(vg, x + s, y + d); - nvgStrokeColor(vg, color); - nvgStrokeWidth(vg, h * 0.12); - nvgLineCap(vg, NVG_ROUND); - nvgStroke(vg); - - nvgBeginPath(vg); - nvgMoveTo(vg, x, y + d); - nvgLineTo(vg, x + s, y + w); - - nvgLineTo(vg, x + s, y + 2 * d); - nvgLineTo(vg, x + w, y + d); - nvgLineTo(vg, x + s, y); - nvgLineTo(vg, x + s - d, y + d); - nvgLineTo(vg, x, y + d); - nvgFillColor(vg, color); - nvgLineJoin(vg, NVG_ROUND); - nvgFill(vg); - } - void drawDot(const DrawArgs& args, float cx, float cy, float r, NVGcolor& color) { auto vg = args.vg; @@ -183,31 +147,6 @@ struct VirtualGridKey : rack::app::ParamWidget nvgFill(vg); } - void drawLock(const DrawArgs& args, float x, float y, float w, float h, NVGcolor& color) - { - auto vg = args.vg; - - float cx = x + w / 2; - float cy = y + h / 2; - float bend = y + h / 2.3; - float r = w / 6.4; - - nvgBeginPath(vg); - nvgRoundedRect(vg, x + w / 4, cy, w / 2, h / 3, 1.0); - nvgFillColor(vg, color); - nvgFill(vg); - - nvgBeginPath(vg); - nvgMoveTo(vg, cx + r, cy + 2.0); - nvgLineTo(vg, cx + r, bend); - nvgArcTo(vg, cx + r, bend - r, cx, bend - r, r); - nvgArcTo(vg, cx - r, bend - r, cx - r, bend, r); - nvgLineTo(vg, cx - r, cy + 2.0); - nvgStrokeColor(vg, color); - nvgStrokeWidth(vg, h * 0.09); - nvgStroke(vg); - } - rack::engine::ParamQuantity* getSecondaryParamQuantity() { if (!module) @@ -358,5 +297,5 @@ struct VirtualGridKey : rack::app::ParamWidget } protected: - bool _locked; + bool _locked; }; \ No newline at end of file diff --git a/src/virtualgrid/VirtualGridWidget.cpp b/src/virtualgrid/VirtualGridWidget.cpp index 774aa9c..b2bba2d 100644 --- a/src/virtualgrid/VirtualGridWidget.cpp +++ b/src/virtualgrid/VirtualGridWidget.cpp @@ -66,6 +66,15 @@ VirtualGridWidget::VirtualGridWidget(VirtualGridModule* module, unsigned w, unsi box.size = Vec(rackWidth, 380); + { + auto panel = new ThemedSvgPanel(); + panel->setBackground( + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/grid.svg")), + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/grid-dark.svg"))); + panel->box.size = box.size; + addChild(panel); + } + // create an opaque child underneath the keys to defeat module dragging in between the buttons auto gridZone = new OpaqueWidget(); gridZone->setSize(Vec(box.size.x - 2 * margins.x, box.size.y - 2 * margins.y)); @@ -101,10 +110,6 @@ VirtualGridWidget::VirtualGridWidget(VirtualGridModule* module, unsigned w, unsi addParam(key); } } - - PanelBorder* pb = new PanelBorder; - pb->box.size = box.size; - addChild(pb); } VirtualGridWidget::~VirtualGridWidget() @@ -115,16 +120,6 @@ VirtualGridWidget::~VirtualGridWidget() } } -void VirtualGridWidget::draw(const DrawArgs& args) -{ - nvgBeginPath(args.vg); - nvgRect(args.vg, 0.0, 0.0, box.size.x, box.size.y); - nvgFillColor(args.vg, nvgRGB(0xf0, 0xf0, 0xf0)); - nvgFill(args.vg); - - rack::app::ModuleWidget::draw(args); -} - void VirtualGridWidget::clearHeldKeys() { for (auto p : getParams()) diff --git a/src/virtualgrid/VirtualGridWidget.hpp b/src/virtualgrid/VirtualGridWidget.hpp index 0f2b7ea..e1798f7 100644 --- a/src/virtualgrid/VirtualGridWidget.hpp +++ b/src/virtualgrid/VirtualGridWidget.hpp @@ -2,6 +2,8 @@ #pragma once +extern rack::Plugin* pluginInstance; + struct VirtualGridKey; struct VirtualGridModule; @@ -10,7 +12,6 @@ struct VirtualGridWidget : rack::app::ModuleWidget VirtualGridWidget(VirtualGridModule* module, unsigned w, unsigned h); ~VirtualGridWidget(); - void draw(const DrawArgs& args) override; void onDragEnter(const rack::event::DragEnter& e) override; void onDragStart(const rack::event::DragStart& e) override; void onDragEnd(const rack::event::DragEnd& e) override; diff --git a/src/whitewhale/WhiteWhaleModule.hpp b/src/whitewhale/WhiteWhaleModule.hpp index 7b17bfb..323fee4 100644 --- a/src/whitewhale/WhiteWhaleModule.hpp +++ b/src/whitewhale/WhiteWhaleModule.hpp @@ -47,7 +47,7 @@ struct WhiteWhaleModule : LibAVR32Module rack::dsp::SchmittTrigger clockTrigger; WhiteWhaleModule() - : LibAVR32Module("whitewhale") + : LibAVR32Module("whitewhale", "whitewhale") { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configButton(BUTTON_PARAM, "PRESET"); diff --git a/src/whitewhale/WhiteWhaleWidget.hpp b/src/whitewhale/WhiteWhaleWidget.hpp index 071f5c7..3eb3ed2 100644 --- a/src/whitewhale/WhiteWhaleWidget.hpp +++ b/src/whitewhale/WhiteWhaleWidget.hpp @@ -16,29 +16,31 @@ struct WhiteWhaleWidget : LibAVR32ModuleWidget box.size = Vec(15 * 6, 380); { - auto panel = new rack::SvgPanel(); - panel->setBackground(APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/whitewhale.svg"))); + auto panel = new ThemedSvgPanel(); + panel->setBackground( + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/whitewhale.svg")), + APP->window->loadSvg(rack::asset::plugin(pluginInstance, "res/whitewhale-dark.svg"))); panel->box.size = box.size; addChild(panel); } // Screws positioned for sliding nuts :) - addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, 0))); - addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH / 2, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addParam(createParam(Vec(7, 333), module, WhiteWhaleModule::USB_PARAM)); addParam(createParam(Vec(62, 336), module, WhiteWhaleModule::BUTTON_PARAM)); addParam(createParam(Vec(12, 30), module, WhiteWhaleModule::PARAM_PARAM)); addParam(createParam(Vec(12, 232), module, WhiteWhaleModule::CLOCK_PARAM)); - addOutput(createOutput(Vec(50, 83), module, WhiteWhaleModule::TR1_OUTPUT)); - addOutput(createOutput(Vec(50, 121), module, WhiteWhaleModule::TR2_OUTPUT)); - addOutput(createOutput(Vec(50, 159), module, WhiteWhaleModule::TR3_OUTPUT)); - addOutput(createOutput(Vec(50, 197), module, WhiteWhaleModule::TR4_OUTPUT)); - addOutput(createOutput(Vec(15, 101), module, WhiteWhaleModule::CVA_OUTPUT)); - addOutput(createOutput(Vec(15, 139), module, WhiteWhaleModule::CVB_OUTPUT)); - addInput(createInput(Vec(13, 286), module, WhiteWhaleModule::CLOCK_INPUT)); - addOutput(createOutput(Vec(50, 286), module, WhiteWhaleModule::CLOCK_OUTPUT)); + addOutput(createOutput(Vec(50, 83), module, WhiteWhaleModule::TR1_OUTPUT)); + addOutput(createOutput(Vec(50, 121), module, WhiteWhaleModule::TR2_OUTPUT)); + addOutput(createOutput(Vec(50, 159), module, WhiteWhaleModule::TR3_OUTPUT)); + addOutput(createOutput(Vec(50, 197), module, WhiteWhaleModule::TR4_OUTPUT)); + addOutput(createOutput(Vec(15, 101), module, WhiteWhaleModule::CVA_OUTPUT)); + addOutput(createOutput(Vec(15, 139), module, WhiteWhaleModule::CVB_OUTPUT)); + addInput(createInput(Vec(13, 286), module, WhiteWhaleModule::CLOCK_INPUT)); + addOutput(createOutput(Vec(50, 286), module, WhiteWhaleModule::CLOCK_OUTPUT)); addChild(createLight>(Vec(77, 79), module, WhiteWhaleModule::TR1_LIGHT)); addChild(createLight>(Vec(77, 117), module, WhiteWhaleModule::TR2_LIGHT));