marius
5 months ago
18 changed files with 3644 additions and 69 deletions
@ -0,0 +1,47 @@
|
||||
FROM espressif/idf |
||||
|
||||
ARG DEBIAN_FRONTEND=nointeractive |
||||
ARG CONTAINER_USER=esp |
||||
ARG USER_UID=1000 |
||||
ARG USER_GID=$USER_UID |
||||
|
||||
RUN apt-get update \ |
||||
&& apt install -y -q \ |
||||
cmake \ |
||||
git \ |
||||
libglib2.0-0 \ |
||||
libnuma1 \ |
||||
libpixman-1-0 \ |
||||
&& rm -rf /var/lib/apt/lists/* |
||||
|
||||
# QEMU |
||||
ENV QEMU_REL=esp_develop_8.2.0_20240122 |
||||
ENV QEMU_SHA256=e7c72ef5705ad1444d391711088c8717fc89f42e9bf6d1487f9c2a326b8cfa83 |
||||
ENV QEMU_DIST=qemu-xtensa-softmmu-${QEMU_REL}-x86_64-linux-gnu.tar.xz |
||||
ENV QEMU_URL=https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/${QEMU_DIST} |
||||
|
||||
ENV LC_ALL=C.UTF-8 |
||||
ENV LANG=C.UTF-8 |
||||
|
||||
RUN wget --no-verbose ${QEMU_URL} \ |
||||
&& echo "${QEMU_SHA256} *${QEMU_DIST}" | sha256sum --check --strict - \ |
||||
&& tar -xf $QEMU_DIST -C /opt \ |
||||
&& rm ${QEMU_DIST} |
||||
|
||||
ENV PATH=/opt/qemu/bin:${PATH} |
||||
|
||||
RUN groupadd --gid $USER_GID $CONTAINER_USER \ |
||||
&& adduser --uid $USER_UID --gid $USER_GID --disabled-password --gecos "" ${CONTAINER_USER} \ |
||||
&& usermod -a -G root $CONTAINER_USER && usermod -a -G dialout $CONTAINER_USER |
||||
|
||||
RUN chmod -R 775 /opt/esp/python_env/ |
||||
|
||||
USER ${CONTAINER_USER} |
||||
ENV USER=${CONTAINER_USER} |
||||
WORKDIR /home/${CONTAINER_USER} |
||||
|
||||
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc |
||||
|
||||
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] |
||||
|
||||
CMD ["/bin/bash", "-c"] |
@ -0,0 +1,45 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: |
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.183.0/containers/ubuntu |
||||
{ |
||||
"name": "ESP-IDF QEMU", |
||||
"build": { |
||||
"dockerfile": "Dockerfile" |
||||
}, |
||||
// Add the IDs of extensions you want installed when the container is created |
||||
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind", |
||||
/* the path of workspace folder to be opened after container is running |
||||
*/ |
||||
"workspaceFolder": "${localWorkspaceFolder}", |
||||
"mounts": [ |
||||
"source=extensionCache,target=/root/.vscode-server/extensions,type=volume" |
||||
], |
||||
"customizations": { |
||||
"vscode": { |
||||
"settings": { |
||||
"terminal.integrated.defaultProfile.linux": "bash", |
||||
"idf.espIdfPath": "/opt/esp/idf", |
||||
"idf.customExtraPaths": "", |
||||
"idf.pythonBinPath": "/opt/esp/python_env/idf5.3_py3.10_env/bin/python", |
||||
"idf.toolsPath": "/opt/esp", |
||||
"idf.gitPath": "/usr/bin/git" |
||||
}, |
||||
"extensions": [ |
||||
"espressif.esp-idf-extension" |
||||
], |
||||
}, |
||||
"codespaces": { |
||||
"settings": { |
||||
"terminal.integrated.defaultProfile.linux": "bash", |
||||
"idf.espIdfPath": "/opt/esp/idf", |
||||
"idf.customExtraPaths": "", |
||||
"idf.pythonBinPath": "/opt/esp/python_env/idf5.3_py3.10_env/bin/python", |
||||
"idf.toolsPath": "/opt/esp", |
||||
"idf.gitPath": "/usr/bin/git" |
||||
}, |
||||
"extensions": [ |
||||
"espressif.esp-idf-extension" |
||||
], |
||||
} |
||||
}, |
||||
"runArgs": ["--privileged"] |
||||
} |
@ -0,0 +1,4 @@
|
||||
.pio |
||||
.vscode |
||||
build |
||||
managed_components |
@ -0,0 +1,6 @@
|
||||
# The following five lines of boilerplate have to be in your project's |
||||
# CMakeLists in this exact order for cmake to work correctly |
||||
cmake_minimum_required(VERSION 3.16) |
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake) |
||||
project(maddius_joy) |
@ -0,0 +1,83 @@
|
||||
| Supported Targets | ESP32-S2 | ESP32-S3 | |
||||
| ----------------- | -------- | -------- | |
||||
|
||||
# TinyUSB MIDI Device Example |
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.) |
||||
|
||||
This example shows how to set up ESP chip to work as a USB MIDI Device. |
||||
It outputs a MIDI note sequence via the native USB port. |
||||
|
||||
As a USB stack, a TinyUSB component is used. |
||||
|
||||
## How to use example |
||||
|
||||
### Hardware Required |
||||
|
||||
Any ESP board that have USB-OTG supported. |
||||
|
||||
#### Pin Assignment |
||||
|
||||
_Note:_ In case your board doesn't have micro-USB connector connected to USB-OTG peripheral, you may have to DIY a cable and connect **D+** and **D-** to the pins listed below. |
||||
|
||||
See common pin assignments for USB Device examples from [upper level](../../README.md#common-pin-assignments). |
||||
|
||||
### Build and Flash |
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output: |
||||
|
||||
```bash |
||||
idf.py -p PORT flash monitor |
||||
``` |
||||
|
||||
(Replace PORT with the name of the serial port to use.) |
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.) |
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. |
||||
|
||||
## MIDI output |
||||
|
||||
You can use several programs on your computer to listen to the ESP's MIDI output depending on your operating system, e.g.: |
||||
|
||||
* Windows: `MIDI-OX` |
||||
* Linux: `qsynth` with `qjackctl` |
||||
* macOS: `SimpleSynth` |
||||
|
||||
## Example Output |
||||
|
||||
After the flashing you should see the output at idf monitor: |
||||
|
||||
``` |
||||
I (285) example: USB initialization |
||||
I (285) tusb_desc: |
||||
┌─────────────────────────────────┐ |
||||
│ USB Device Descriptor Summary │ |
||||
├───────────────────┬─────────────┤ |
||||
│bDeviceClass │ 0 │ |
||||
├───────────────────┼─────────────┤ |
||||
│bDeviceSubClass │ 0 │ |
||||
├───────────────────┼─────────────┤ |
||||
│bDeviceProtocol │ 0 │ |
||||
├───────────────────┼─────────────┤ |
||||
│bMaxPacketSize0 │ 64 │ |
||||
├───────────────────┼─────────────┤ |
||||
│idVendor │ 0x303a │ |
||||
├───────────────────┼─────────────┤ |
||||
│idProduct │ 0x4008 │ |
||||
├───────────────────┼─────────────┤ |
||||
│bcdDevice │ 0x100 │ |
||||
├───────────────────┼─────────────┤ |
||||
│iManufacturer │ 0x1 │ |
||||
├───────────────────┼─────────────┤ |
||||
│iProduct │ 0x2 │ |
||||
├───────────────────┼─────────────┤ |
||||
│iSerialNumber │ 0x3 │ |
||||
├───────────────────┼─────────────┤ |
||||
│bNumConfigurations │ 0x1 │ |
||||
└───────────────────┴─────────────┘ |
||||
I (455) TinyUSB: TinyUSB Driver installed |
||||
I (465) example: USB initialization DONE |
||||
``` |
||||
|
||||
Disconnect UART-to-USB port and connect the native USB port to a computer then the device should show up as a USB MIDI Device while outputting notes. |
@ -0,0 +1,147 @@
|
||||
dependencies: |
||||
chmorgan/esp-libhelix-mp3: |
||||
component_hash: cbb76089dc2c5749f7b470e2e70aedc44c9da519e04eb9a67d4c7ec275229e53 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.0.3 |
||||
espressif/arduino-esp32: |
||||
component_hash: c518a55e52a50d662a7c71202e42a90a64bd2122a08089cbb1f76d925e812afc |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 3.0.1 |
||||
espressif/cbor: |
||||
component_hash: 440f4ee4504841cc9b4f3a8ef755776a612ac9dace355514c68b999868f990ff |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 0.6.0~1 |
||||
espressif/esp-dsp: |
||||
component_hash: 3e7bbd487f1357a1d4944d0c85966d049501ea281b8a4c7f93f7cfedd5b7f23d |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.4.12 |
||||
espressif/esp-sr: |
||||
component_hash: 16af25295f531495fe7e36cf2e8c8bb49629be42c38a56f55f4ded825ada0ffc |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.7.1 |
||||
espressif/esp-zboss-lib: |
||||
component_hash: c7020f631cd4ad25e159ddb812bdc80906b5b424457abc81c9b8b0e92687837a |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.3.2 |
||||
espressif/esp-zigbee-lib: |
||||
component_hash: 752dbc8abb2befd2d49ee902051699fac5e32c6962950d64cd888d75d6566ca0 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.3.2 |
||||
espressif/esp_diag_data_store: |
||||
component_hash: 8849195251dbb8a2d7268335277cfa310cef36e4ac1e90cd59ad3be4269a30d7 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.0.1 |
||||
espressif/esp_diagnostics: |
||||
component_hash: 2350938db074002ef088c05cd32d80a528185e47afdb3642427156256c3e13c5 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.1.0 |
||||
espressif/esp_insights: |
||||
component_hash: 72ece1dcf0146275e1df976c713a9b193af0907931f3810957ee68a0a84b077d |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.1.0 |
||||
espressif/esp_modem: |
||||
component_hash: e48da33fee082dd9d9a97a354a228057e07a14ac108766b40ad84e018205410a |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.1.0 |
||||
espressif/esp_rainmaker: |
||||
component_hash: 232425d1c9b9dbdaa5c109b3e359fba0e6956e35fcf22725f07ed7e4389e1191 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.1.0 |
||||
espressif/esp_schedule: |
||||
component_hash: 80d3694717a537156f61a072dfe1d1498a2a4f32819a5735bf8a50bcadf79941 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.1.1 |
||||
espressif/esp_secure_cert_mgr: |
||||
component_hash: a20007d67e65a000670ab77e45d7554c943eb8dcb0abeada0a57dd9adac3a703 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 2.4.1 |
||||
espressif/esp_tinyusb: |
||||
component_hash: 5e37c53a10518f40b288a48afec4ab549784be9e6eb74add699a30395543418a |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.0.3 |
||||
espressif/jsmn: |
||||
component_hash: d80350c41bbaa827c98a25b6072df00884e72f54885996fab4a4f0aebce6b6c3 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.1.0 |
||||
espressif/json_generator: |
||||
component_hash: 45033e1c199b13f1c8c1b544fb7d4e2df6a8e3071ebdcb1b22582b61a7974ff2 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.1.2 |
||||
espressif/json_parser: |
||||
component_hash: d74b81729ad06ec11ff5eb5b1b0d7df1d00e6027fc11471f4b139c70dcf1b1e4 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.0.3 |
||||
espressif/mdns: |
||||
component_hash: 31117d76cae83a6d83ffd7f035f6fdae5bd05b914fc30b641afeb208b84de19a |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.3.2 |
||||
espressif/qrcode: |
||||
component_hash: 3b493771bc5d6ad30cbf87c25bf784aada8a08c941504355b55d6b75518ed7bc |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 0.1.0~2 |
||||
espressif/rmaker_common: |
||||
component_hash: 021c02465e4996dd3292db36ea47b5e3122e7e2d3514797735a96bc12598b44f |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.4.5 |
||||
espressif/tinyusb: |
||||
component_hash: 256fd8aee92ae9f1014538b8601508907a2da386b64f6d42f35a67f9288d1b20 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 0.15.0~9 |
||||
idf: |
||||
component_hash: null |
||||
source: |
||||
type: idf |
||||
version: 5.1.4 |
||||
joltwallet/littlefs: |
||||
component_hash: 8373229a6c63ccc08747117cd937b35de5721ba49468e4ca29dad006235e655e |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.14.5 |
||||
manifest_hash: 534b60a796c994201c1fe175ee341e4e13962f7a0dcbdbb550f369327daedf28 |
||||
target: esp32s3 |
||||
version: 1.0.0 |
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "tusb_midi_main.c" "controls.cpp" "ezButton.cpp" |
||||
INCLUDE_DIRS "." |
||||
) |
@ -0,0 +1,282 @@
|
||||
// #include "Adafruit_Keypad.h"
|
||||
// #include "led_strip_rmt_ws2812.cpp"
|
||||
// #include "ESPRotary.h"
|
||||
#include <Wire.h> // I2C |
||||
#include "driver/gpio.h" |
||||
#include "controls.h" |
||||
#include "tinyusb.h" |
||||
#include <ezButton.h> |
||||
|
||||
#define LED_STRIP_LED_NUMBERS 30 |
||||
#define I2C_INTERRUPT_REQUEST 57 //
|
||||
|
||||
#define ROWS 5 // rows
|
||||
#define COLS 6 // columns
|
||||
|
||||
#define CLICKS_PER_STEP 4 // this number depends on your rotary encoder
|
||||
#define BUTTON_PIN 1 |
||||
|
||||
#define BUTTON_DEBOUNCE 20 |
||||
|
||||
// buttons
|
||||
ezButton button[1] = {{7}}; |
||||
|
||||
// joystick
|
||||
#define BUTTON_PIN2 41 |
||||
#define JOY_X 40 |
||||
#define JOY_Y 39 |
||||
// I2C
|
||||
#define I2C_SDA 37 |
||||
#define I2C_SCL 36 |
||||
|
||||
#define I2C_INTERUPT GPIO_NUM_38 |
||||
|
||||
static const char *TAG = "controls"; |
||||
// #define SERIAL_SPEED 115200
|
||||
|
||||
uint8_t controls[512] = {0}; |
||||
|
||||
// Basic MIDI Messages
|
||||
#define NOTE_OFF 0x80 |
||||
#define NOTE_ON 0x90 |
||||
#define SET_CONTROL 0xB0 |
||||
|
||||
void setControl(uint16_t controlNum, uint8_t value) |
||||
{ |
||||
uint16_t keynum = controlNum; |
||||
bool litValue = false; |
||||
if (value > 0) |
||||
{ |
||||
litValue = true; |
||||
} |
||||
if ((controlNum / 6) % 2 == 1) |
||||
{ |
||||
keynum = controlNum + 5 - (controlNum % 6) * 2; |
||||
} |
||||
ESP_LOGI(TAG, "begin litValue %i ,%i, %i", (controlNum % 6), controlNum, keynum); |
||||
// lit[keynum] = litValue; // invert neopixel status
|
||||
controls[controlNum] = value; |
||||
} |
||||
|
||||
|
||||
void task_read_all(void *args) |
||||
{ |
||||
// init
|
||||
static uint8_t const cable_num = 0; // MIDI jack associated with USB endpoint
|
||||
static uint8_t const channel = 0; // 0 for channel 1
|
||||
bool changeDetected = false; |
||||
// BUTTON
|
||||
for (int i = 0; i < 1; i++) |
||||
{ |
||||
button[i].setDebounceTime(BUTTON_DEBOUNCE); |
||||
} |
||||
uint8_t buttonLastState[9] = {0, 0, 0, 0, 0, 0, 0, 0}; |
||||
uint8_t buttonNextState[9] = {0, 0, 0, 0, 0, 0, 0, 0}; |
||||
uint8_t buttonExternalState[9] = {0}; |
||||
// FADER
|
||||
ESP_LOGI(TAG, "begin "); |
||||
uint16_t threshold = 250; |
||||
uint16_t speed = 100; |
||||
uint16_t joy_x_init = 0; |
||||
uint16_t joy_y_init = 0; |
||||
uint16_t joy_zoom_init = 0; |
||||
for (int i=0;i<10;i++) |
||||
{ |
||||
joy_x_init += analogRead(4); |
||||
joy_y_init += analogRead(5); |
||||
joy_zoom_init += analogRead(6); |
||||
} |
||||
joy_x_init = joy_x_init/10; |
||||
joy_y_init = joy_y_init/10; |
||||
joy_zoom_init = joy_zoom_init/10; |
||||
ESP_LOGI(TAG, "joy_x_init %i",joy_x_init); |
||||
ESP_LOGI(TAG, "joy_y_init %i",joy_y_init); |
||||
ESP_LOGI(TAG, "joy_zoom_init %i",joy_zoom_init); |
||||
uint16_t joy_x = 0; |
||||
uint16_t joy_y = 0; |
||||
uint16_t joy_zoom = 0; |
||||
int16_t joy_x_dir = 0; |
||||
int16_t joy_y_dir = 0; |
||||
int16_t joy_zoom_dir = 0; |
||||
float joy_float_x = 0; |
||||
float joy_float_y = 0; |
||||
float joy_float_zoom = 0; |
||||
// uint8_t controls[64] = 0;
|
||||
// uint8_t controls[65] = 0;
|
||||
// uint8_t controls[66] = 0;
|
||||
uint8_t faderLastState[3] = {0, 0, 0}; |
||||
for (;;) |
||||
{ |
||||
// BUTTON
|
||||
for (int i = 0; i < 1; i++) |
||||
{ |
||||
// uint8_t buttonValue = digitalRead(buttonPins[i]);
|
||||
// buttonNextState[i] = buttonValue ? 0 : 255;
|
||||
button[i].loop(); |
||||
if (button[i].isPressed()) |
||||
{ |
||||
buttonNextState[i] = 255; |
||||
} |
||||
else if (button[i].isReleased()) |
||||
{ |
||||
buttonNextState[i] = 0; |
||||
} |
||||
// Serial.print("r");
|
||||
// Serial.print(read);
|
||||
// Serial.print(": ");
|
||||
// Serial.println(faderNextState[i]);
|
||||
} |
||||
// JOY
|
||||
if(controls[64] != (uint8_t)round(joy_float_x)){ |
||||
ESP_LOGI(TAG, "joy_float_x = controls[64] %f %i",joy_float_x,controls[64]); |
||||
joy_float_x = controls[64]; |
||||
} |
||||
if(controls[65] != (uint8_t)round(joy_float_y)){ |
||||
joy_float_y = controls[65]; |
||||
} |
||||
|
||||
joy_x = analogRead(4); |
||||
joy_y = analogRead(5); |
||||
|
||||
joy_x_dir = joy_x_init-joy_x; |
||||
joy_y_dir = joy_y_init-joy_y; |
||||
if(abs(joy_x_dir)>threshold){ |
||||
joy_x_dir = joy_x_dir+ (joy_x_dir <0 ? threshold:-threshold); |
||||
// ESP_LOGI(TAG, "joy_x_dir %i",joy_x_dir);
|
||||
joy_float_x = joy_float_x + ((float)joy_x_dir / 900000 * speed); |
||||
if(joy_float_x > 255){ |
||||
joy_float_x = 255; |
||||
} |
||||
if(joy_float_x < 0){ |
||||
joy_float_x = 0; |
||||
} |
||||
} |
||||
if(abs(joy_y_dir)>threshold){ |
||||
joy_y_dir = joy_y_dir+ (joy_y_dir <0 ? threshold:-threshold); |
||||
// ESP_LOGI(TAG, "joy_y_dir %i",joy_y_dir);
|
||||
joy_float_y = joy_float_y + ((float)joy_y_dir / 900000 * speed); |
||||
if(joy_float_y > 255){ |
||||
joy_float_y = 255; |
||||
} |
||||
if(joy_float_y < 0){ |
||||
joy_float_y = 0; |
||||
} |
||||
} |
||||
if(controls[64] != (uint8_t)round(joy_float_x)){ |
||||
controls[64] = (uint8_t)round(joy_float_x); |
||||
ESP_LOGI(TAG, "controls[64] %i",controls[64]); |
||||
uint8_t control[3] = {SET_CONTROL | channel, 64, (uint8_t)(controls[64]>>1)}; |
||||
tud_midi_stream_write(cable_num, control, 3); |
||||
} |
||||
if(controls[65] != (uint8_t)round(joy_float_y)){ |
||||
controls[65] = (uint8_t)round(joy_float_y); |
||||
ESP_LOGI(TAG, "controls[65] %i",controls[65]); |
||||
uint8_t control[3] = {SET_CONTROL | channel, 65, (uint8_t)(controls[65]>>1)}; |
||||
tud_midi_stream_write(cable_num, control, 3); |
||||
} |
||||
|
||||
// ZOOM
|
||||
if(controls[66] != (uint8_t)round(joy_float_zoom)){ |
||||
joy_float_zoom = controls[66]; |
||||
} |
||||
joy_zoom = analogRead(6); |
||||
joy_zoom_dir = joy_zoom_init-joy_zoom; |
||||
if(abs(joy_zoom_dir)>threshold){ |
||||
joy_zoom_dir = joy_zoom_dir+ (joy_zoom_dir <0 ? threshold:-threshold); |
||||
joy_float_zoom = joy_float_zoom + ((float)joy_zoom_dir / 900000 * speed); |
||||
if(joy_float_zoom > 255){ |
||||
joy_float_zoom = 255; |
||||
} |
||||
if(joy_float_zoom < 0){ |
||||
joy_float_zoom = 0; |
||||
} |
||||
} |
||||
if(controls[66] != (uint8_t)round(joy_float_zoom)){ |
||||
controls[66] = (uint8_t)round(joy_float_zoom); |
||||
ESP_LOGI(TAG, "controls[66] %i",controls[66]); |
||||
uint8_t control[3] = {SET_CONTROL | channel, 66, (uint8_t)(controls[66]>>1)}; |
||||
tud_midi_stream_write(cable_num, control, 3); |
||||
} |
||||
// WIRE I2C
|
||||
bool nextChangeDetected = false; |
||||
// better only on change?
|
||||
for (uint8_t i = 0; i < 1; i++) |
||||
{ |
||||
// Buttons
|
||||
if (buttonNextState[i] != buttonLastState[i]) |
||||
{ |
||||
buttonLastState[i] = buttonNextState[i]; |
||||
Serial.print("B"); |
||||
Serial.print(i); |
||||
Serial.print(": "); |
||||
Serial.println(buttonNextState[i]); |
||||
nextChangeDetected = true; |
||||
uint8_t control[3] = {SET_CONTROL | channel, i, 127}; |
||||
ESP_LOGI(TAG, "buttonNextState[%i] %i",i,buttonNextState[i]); |
||||
tud_midi_stream_write(cable_num, control, 3); |
||||
} |
||||
if (buttonLastState[i] == 255 || buttonExternalState[i] == 255) |
||||
{ |
||||
// digitalWrite(ledPins[i], HIGH);
|
||||
|
||||
} |
||||
else |
||||
{ |
||||
// digitalWrite(ledPins[i], LOW);
|
||||
} |
||||
} |
||||
if (nextChangeDetected && !changeDetected) |
||||
{ |
||||
changeDetected = nextChangeDetected; |
||||
// pinMode(I2C_INTERRUPT_REQUEST, OUTPUT);
|
||||
// resetIRQCount++;
|
||||
} |
||||
else if (!changeDetected) |
||||
{ |
||||
// pinMode(I2C_INTERRUPT_REQUEST, INPUT);
|
||||
} |
||||
|
||||
vTaskDelay(1); |
||||
} |
||||
|
||||
// bool lastAvailable = false;
|
||||
// I2C
|
||||
// Wire.begin(I2C_SDA, I2C_SCL, 400000L);
|
||||
// pinMode(I2C_INTERUPT, INPUT_PULLUP); // i2c available
|
||||
// for (;;)
|
||||
// {
|
||||
// // i2c
|
||||
// bool nextAvailable = gpio_get_level(I2C_INTERUPT) == 0;
|
||||
// if (nextAvailable) // || lastAvailable
|
||||
// {
|
||||
|
||||
// // ESP_LOGI(TAG, "i2cAvailable: %i", i2cAvailable);
|
||||
// // fader9
|
||||
// Wire.requestFrom(55, 18);
|
||||
// while (Wire.available())
|
||||
// { // peripheral may send less than requested
|
||||
// int c = Wire.read(); // receive a byte
|
||||
// ESP_LOGI(TAG, "value: %i", c);
|
||||
// }
|
||||
// // button8
|
||||
// Wire.requestFrom(56, 8);
|
||||
// while (Wire.available())
|
||||
// { // peripheral may send less than requested
|
||||
// int c = Wire.read(); // receive a byte
|
||||
// ESP_LOGI(TAG, "value: %i", c);
|
||||
// }
|
||||
// // lastAvailable = nextAvailable;
|
||||
// }
|
||||
// // task delay time?
|
||||
// vTaskDelay(1);
|
||||
// }
|
||||
} |
||||
|
||||
void init_controls(controls_config *cfg) |
||||
{ |
||||
// ESP_LOGI(TAG, "cfg.matrix_keys.led_io: %i", cfg->matrix_keys.led_io);
|
||||
for (int i = 0; i < 9; i++) |
||||
{ |
||||
button[i].setDebounceTime(BUTTON_DEBOUNCE); |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
#include <stdlib.h> |
||||
#ifdef __cplusplus |
||||
extern "C" |
||||
{ |
||||
#endif |
||||
typedef struct |
||||
{ |
||||
uint16_t *row_io; |
||||
uint16_t rows; |
||||
uint16_t *col_io; |
||||
uint16_t cols; |
||||
uint16_t led_io; |
||||
} matrix_keys_config; |
||||
|
||||
typedef struct |
||||
{ |
||||
matrix_keys_config matrix_keys; |
||||
} controls_config; |
||||
|
||||
void setControl(uint16_t controlNum, uint8_t value); |
||||
void task_read_all(void *args); |
||||
void task_led_strip(void *arg); |
||||
void init_controls(controls_config *cfg); |
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ArduinoGetStarted.com. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* - Neither the name of the ArduinoGetStarted.com nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY ARDUINOGETSTARTED.COM "AS IS" AND ANY EXPRESS OR |
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
* DISCLAIMED. IN NO EVENT SHALL ARDUINOGETSTARTED.COM BE LIABLE FOR ANY DIRECT, |
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
#include <ezButton.h> |
||||
|
||||
ezButton::ezButton(int pin): ezButton(pin, INPUT_PULLUP) {}; |
||||
|
||||
ezButton::ezButton(int pin, int mode) { |
||||
btnPin = pin; |
||||
debounceTime = 0; |
||||
count = 0; |
||||
countMode = COUNT_FALLING; |
||||
|
||||
pinMode(btnPin, mode); |
||||
|
||||
previousSteadyState = digitalRead(btnPin); |
||||
lastSteadyState = previousSteadyState; |
||||
lastFlickerableState = previousSteadyState; |
||||
|
||||
lastDebounceTime = 0; |
||||
} |
||||
|
||||
void ezButton::setDebounceTime(unsigned long time) { |
||||
debounceTime = time; |
||||
} |
||||
|
||||
int ezButton::getState(void) { |
||||
return lastSteadyState; |
||||
} |
||||
|
||||
int ezButton::getStateRaw(void) { |
||||
return digitalRead(btnPin); |
||||
} |
||||
|
||||
bool ezButton::isPressed(void) { |
||||
if(previousSteadyState == HIGH && lastSteadyState == LOW) |
||||
return true; |
||||
else |
||||
return false; |
||||
} |
||||
|
||||
bool ezButton::isReleased(void) { |
||||
if(previousSteadyState == LOW && lastSteadyState == HIGH) |
||||
return true; |
||||
else |
||||
return false; |
||||
} |
||||
|
||||
void ezButton::setCountMode(int mode) { |
||||
countMode = mode; |
||||
} |
||||
|
||||
unsigned long ezButton::getCount(void) { |
||||
return count; |
||||
} |
||||
|
||||
void ezButton::resetCount(void) { |
||||
count = 0; |
||||
} |
||||
|
||||
void ezButton::loop(void) { |
||||
// read the state of the switch/button:
|
||||
int currentState = digitalRead(btnPin); |
||||
unsigned long currentTime = millis(); |
||||
|
||||
// check to see if you just pressed the button
|
||||
// (i.e. the input went from LOW to HIGH), and you've waited long enough
|
||||
// since the last press to ignore any noise:
|
||||
|
||||
// If the switch/button changed, due to noise or pressing:
|
||||
if (currentState != lastFlickerableState) { |
||||
// reset the debouncing timer
|
||||
lastDebounceTime = currentTime; |
||||
// save the the last flickerable state
|
||||
lastFlickerableState = currentState; |
||||
} |
||||
|
||||
if ((currentTime - lastDebounceTime) >= debounceTime) { |
||||
// whatever the reading is at, it's been there for longer than the debounce
|
||||
// delay, so take it as the actual current state:
|
||||
|
||||
// save the the steady state
|
||||
previousSteadyState = lastSteadyState; |
||||
lastSteadyState = currentState; |
||||
} |
||||
|
||||
if(previousSteadyState != lastSteadyState){ |
||||
if(countMode == COUNT_BOTH) |
||||
count++; |
||||
else if(countMode == COUNT_FALLING){ |
||||
if(previousSteadyState == HIGH && lastSteadyState == LOW) |
||||
count++; |
||||
} |
||||
else if(countMode == COUNT_RISING){ |
||||
if(previousSteadyState == LOW && lastSteadyState == HIGH) |
||||
count++; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ArduinoGetStarted.com. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* - Neither the name of the ArduinoGetStarted.com nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY ARDUINOGETSTARTED.COM "AS IS" AND ANY EXPRESS OR |
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
* DISCLAIMED. IN NO EVENT SHALL ARDUINOGETSTARTED.COM BE LIABLE FOR ANY DIRECT, |
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
#ifndef ezButton_h |
||||
#define ezButton_h |
||||
|
||||
#include <Arduino.h> |
||||
|
||||
#define COUNT_FALLING 0 |
||||
#define COUNT_RISING 1 |
||||
#define COUNT_BOTH 2 |
||||
|
||||
class ezButton |
||||
{ |
||||
private: |
||||
int btnPin; |
||||
unsigned long debounceTime; |
||||
unsigned long count; |
||||
int countMode; |
||||
|
||||
int previousSteadyState; // the previous steady state from the input pin, used to detect pressed and released event
|
||||
int lastSteadyState; // the last steady state from the input pin
|
||||
int lastFlickerableState; // the last flickerable state from the input pin
|
||||
|
||||
unsigned long lastDebounceTime; // the last time the output pin was toggled
|
||||
|
||||
public: |
||||
ezButton(int pin); |
||||
ezButton(int pin, int mode); |
||||
void setDebounceTime(unsigned long time); |
||||
int getState(void); |
||||
int getStateRaw(void); |
||||
bool isPressed(void); |
||||
bool isReleased(void); |
||||
void setCountMode(int mode); |
||||
unsigned long getCount(void); |
||||
void resetCount(void); |
||||
void loop(void); |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File |
||||
dependencies: |
||||
esp_tinyusb: "~1.0.0" |
||||
idf: "^5.1" |
||||
espressif/arduino-esp32: "^3.0.0" |
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Ha Thach (tinyusb.org) |
||||
* |
||||
* SPDX-License-Identifier: MIT |
||||
* |
||||
* SPDX-FileContributor: 2022-2023 Espressif Systems (Shanghai) CO LTD |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include "esp_log.h" |
||||
#include "freertos/FreeRTOS.h" |
||||
#include "freertos/task.h" |
||||
#include "tinyusb.h" |
||||
#include "esp_timer.h" |
||||
#include "controls.h" |
||||
|
||||
static const char *TAG = "example"; |
||||
|
||||
/** Helper defines **/ |
||||
|
||||
// Interface counter
|
||||
enum interface_count { |
||||
#if CFG_TUD_MIDI |
||||
ITF_NUM_MIDI = 0, |
||||
ITF_NUM_MIDI_STREAMING, |
||||
#endif |
||||
ITF_COUNT |
||||
}; |
||||
|
||||
// USB Endpoint numbers
|
||||
enum usb_endpoints { |
||||
// Available USB Endpoints: 5 IN/OUT EPs and 1 IN EP
|
||||
EP_EMPTY = 0, |
||||
#if CFG_TUD_MIDI |
||||
EPNUM_MIDI, |
||||
#endif |
||||
}; |
||||
|
||||
/** TinyUSB descriptors **/ |
||||
|
||||
#define TUSB_DESCRIPTOR_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_MIDI * TUD_MIDI_DESC_LEN) |
||||
// Basic MIDI Messages
|
||||
#define NOTE_OFF 0x80 |
||||
#define NOTE_ON 0x90 |
||||
#define SET_CONTROL 0xB0 |
||||
/**
|
||||
* @brief String descriptor |
||||
*/ |
||||
static const char* s_str_desc[5] = { |
||||
// array of pointer to string descriptors
|
||||
(char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
|
||||
"TinyUSB", // 1: Manufacturer
|
||||
"TinyUSB Device", // 2: Product
|
||||
"123456", // 3: Serials, should use chip ID
|
||||
"Example MIDI device", // 4: MIDI
|
||||
}; |
||||
|
||||
/**
|
||||
* @brief Configuration descriptor |
||||
* |
||||
* This is a simple configuration descriptor that defines 1 configuration and a MIDI interface |
||||
*/ |
||||
static const uint8_t s_midi_cfg_desc[] = { |
||||
// Configuration number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_COUNT, 0, TUSB_DESCRIPTOR_TOTAL_LEN, 0, 100), |
||||
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 4, EPNUM_MIDI, (0x80 | EPNUM_MIDI), 64), |
||||
}; |
||||
|
||||
static void midi_task_read_example(void *arg) |
||||
{ |
||||
// The MIDI interface always creates input and output port/jack descriptors
|
||||
// regardless of these being used or not. Therefore incoming traffic should be read
|
||||
// (possibly just discarded) to avoid the sender blocking in IO
|
||||
uint8_t packet[4]; |
||||
bool read = false; |
||||
for (;;) { |
||||
vTaskDelay(1); |
||||
while (tud_midi_available()) { |
||||
read = tud_midi_packet_read(packet); |
||||
if (read) { |
||||
if(packet[1] == SET_CONTROL){ |
||||
setControl(packet[2], packet[3]<<1); |
||||
ESP_LOGI(TAG, "setControl(packet[2]%i, packet[3]%i<1/%i)", packet[2], packet[3],packet[3]<<1); |
||||
} |
||||
|
||||
ESP_LOGI(TAG, "Read - Time (ms since boot): %lld, Data: %02hhX %02hhX %02hhX %02hhX", |
||||
esp_timer_get_time(), packet[0], packet[1], packet[2], packet[3]); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
static void periodic_midi_write_example_cb(void *arg) |
||||
{ |
||||
// Example melody stored as an array of note values
|
||||
uint8_t const note_sequence[] = { |
||||
74, 78, 81, 86, 90, 93, 98, 102, 57, 61, 66, 69, 73, 78, 81, 85, 88, 92, 97, 100, 97, 92, 88, 85, 81, 78, |
||||
74, 69, 66, 62, 57, 62, 66, 69, 74, 78, 81, 86, 90, 93, 97, 102, 97, 93, 90, 85, 81, 78, 73, 68, 64, 61, |
||||
56, 61, 64, 68, 74, 78, 81, 86, 90, 93, 98, 102 |
||||
}; |
||||
|
||||
static uint8_t const cable_num = 0; // MIDI jack associated with USB endpoint
|
||||
static uint8_t const channel = 0; // 0 for channel 1
|
||||
static uint32_t note_pos = 0; |
||||
|
||||
// Previous positions in the note sequence.
|
||||
int previous = note_pos - 1; |
||||
|
||||
// If we currently are at position 0, set the
|
||||
// previous position to the last note in the sequence.
|
||||
if (previous < 0) { |
||||
previous = sizeof(note_sequence) - 1; |
||||
} |
||||
|
||||
// Send Note On for current position at full velocity (127) on channel 1.
|
||||
ESP_LOGI(TAG, "Writing MIDI data %d", note_sequence[note_pos]); |
||||
|
||||
if (tud_midi_mounted()) { |
||||
uint8_t note_on[3] = {NOTE_ON | channel, note_sequence[note_pos], 127}; |
||||
tud_midi_stream_write(cable_num, note_on, 3); |
||||
|
||||
// Send Note Off for previous note.
|
||||
uint8_t note_off[3] = {NOTE_OFF | channel, note_sequence[previous], 0}; |
||||
tud_midi_stream_write(cable_num, note_off, 3); |
||||
} |
||||
|
||||
// Increment position
|
||||
note_pos++; |
||||
|
||||
// If we are at the end of the sequence, start over.
|
||||
if (note_pos >= sizeof(note_sequence)) { |
||||
note_pos = 0; |
||||
} |
||||
} |
||||
|
||||
void app_main(void) |
||||
{ |
||||
ESP_LOGI(TAG, "USB initialization"); |
||||
|
||||
tinyusb_config_t const tusb_cfg = { |
||||
.device_descriptor = NULL, // If device_descriptor is NULL, tinyusb_driver_install() will use Kconfig
|
||||
.string_descriptor = s_str_desc, |
||||
|
||||
.external_phy = false, |
||||
.configuration_descriptor = s_midi_cfg_desc, |
||||
}; |
||||
// .string_descriptor_count = sizeof(s_str_desc) / sizeof(s_str_desc[0]),
|
||||
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); |
||||
|
||||
ESP_LOGI(TAG, "USB initialization DONE"); |
||||
|
||||
// // Periodically send MIDI packets
|
||||
// int const tempo = 286;
|
||||
// const esp_timer_create_args_t periodic_midi_args = {
|
||||
// .callback = &periodic_midi_write_example_cb,
|
||||
// /* name is optional, but may help identify the timer when debugging */
|
||||
// .name = "periodic_midi"
|
||||
// };
|
||||
|
||||
// ESP_LOGI(TAG, "MIDI write task init");
|
||||
// esp_timer_handle_t periodic_midi_timer;
|
||||
// ESP_ERROR_CHECK(esp_timer_create(&periodic_midi_args, &periodic_midi_timer));
|
||||
// ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_midi_timer, tempo * 1000));
|
||||
|
||||
// Read recieved MIDI packets
|
||||
ESP_LOGI(TAG, "MIDI read task init"); |
||||
xTaskCreate(midi_task_read_example, "midi_task_read_example", 8 * 1024, NULL, 5, NULL); |
||||
ESP_LOGI(TAG, "read inputs task init"); |
||||
xTaskCreate(task_read_all, "task_read_all", 8 * 1024, NULL, 21, NULL); |
||||
} |
@ -0,0 +1,13 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD |
||||
# SPDX-License-Identifier: CC0-1.0 |
||||
import pytest |
||||
from pytest_embedded import Dut |
||||
|
||||
|
||||
@pytest.mark.esp32s2 |
||||
@pytest.mark.usb_device |
||||
def test_usb_device_midi_example(dut: Dut) -> None: |
||||
dut.expect_exact('USB initialization DONE') |
||||
dut.expect_exact('MIDI write task init') |
||||
dut.expect_exact('MIDI read task init') |
||||
dut.expect_exact('Writing MIDI data 74') |
@ -0,0 +1 @@
|
||||
CONFIG_TINYUSB_MIDI_COUNT=1 |
@ -1,69 +0,0 @@
|
||||
dependencies: |
||||
chmorgan/esp-libhelix-mp3: |
||||
component_hash: cbb76089dc2c5749f7b470e2e70aedc44c9da519e04eb9a67d4c7ec275229e53 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.0.3 |
||||
espressif/button: |
||||
component_hash: ba2b069cc8d7d485f3d528c5187fd80599144e8d9ef53a883bc09b46cd608aab |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 3.1.3 |
||||
espressif/cmake_utilities: |
||||
component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 0.5.3 |
||||
espressif/esp_tinyusb: |
||||
component_hash: f8682cfddb743297ec1350d7cc52dff6b535c737c60c6a388cdcf2e9dc0eca4b |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.4.2~2 |
||||
espressif/esp_websocket_client: |
||||
component_hash: af69df6a85b26a1e129814ba033fd0c704cdf925b114d9bf90f885db1bb3f8a9 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.2.1 |
||||
espressif/jsmn: |
||||
component_hash: d80350c41bbaa827c98a25b6072df00884e72f54885996fab4a4f0aebce6b6c3 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.1.0 |
||||
espressif/json_parser: |
||||
component_hash: d74b81729ad06ec11ff5eb5b1b0d7df1d00e6027fc11471f4b139c70dcf1b1e4 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.0.3 |
||||
espressif/led_strip: |
||||
component_hash: ed1d5c6113fa545e20c7be17e6e7c09d43b18fcb43068e2b2b27a412de6a405a |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 2.5.2 |
||||
espressif/mdns: |
||||
component_hash: 810ec139689ae93bf42520d05de4855fbb68f7140ef67797d91d8d61829589cb |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 1.2.2 |
||||
espressif/tinyusb: |
||||
component_hash: 632ddbd9c73bee5005e7684eed3142649a08d1f304dbe42abed8110b7384e2c2 |
||||
source: |
||||
service_url: https://api.components.espressif.com/ |
||||
type: service |
||||
version: 0.15.0~3 |
||||
idf: |
||||
component_hash: null |
||||
source: |
||||
type: idf |
||||
version: 5.1.2 |
||||
manifest_hash: 4ed6e24795a74233b024b7c04a08daf95687434889ce45bc5fc86b8074fae5f6 |
||||
target: esp32s3 |
||||
version: 1.0.0 |
@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE Workspace> |
||||
<Workspace xmlns="http://www.qlcplus.org/Workspace" CurrentWindow="InputOutputManager"> |
||||
<Creator> |
||||
<Name>Q Light Controller Plus</Name> |
||||
<Version>4.12.7</Version> |
||||
<Author>maxei</Author> |
||||
</Creator> |
||||
<Engine> |
||||
<InputOutputMap> |
||||
<Universe Name="Universe 1" ID="0"> |
||||
<Input Plugin="OSC" UID="169.254.14.165" Line="1" Profile="Maddius JOY"/> |
||||
<Output Plugin="ArtNet" UID="169.254.14.165" Line="1"/> |
||||
</Universe> |
||||
<Universe Name="Universe 2" ID="1"/> |
||||
<Universe Name="Universe 3" ID="2"/> |
||||
<Universe Name="Universe 4" ID="3"> |
||||
<Input Plugin="MIDI" UID="Example MIDI device" Line="0" Profile="Maddius JOY"/> |
||||
<Feedback Plugin="MIDI" UID="Example MIDI device" Line="1"/> |
||||
</Universe> |
||||
</InputOutputMap> |
||||
<Fixture> |
||||
<Manufacturer>Varytec</Manufacturer> |
||||
<Model>BAT.PAR 6 RGBUV</Model> |
||||
<Mode>1 channel</Mode> |
||||
<ID>0</ID> |
||||
<Name>BAT.PAR 6 RGBUV</Name> |
||||
<Universe>0</Universe> |
||||
<Address>0</Address> |
||||
<Channels>1</Channels> |
||||
</Fixture> |
||||
<Fixture> |
||||
<Manufacturer>UKing</Manufacturer> |
||||
<Model>LED Spot Moving Head 100W</Model> |
||||
<Mode>9 Channel</Mode> |
||||
<ID>1</ID> |
||||
<Name>moving</Name> |
||||
<Universe>0</Universe> |
||||
<Address>1</Address> |
||||
<Channels>9</Channels> |
||||
</Fixture> |
||||
<Function ID="0" Type="RGBMatrix" Name="Neue RGB Matrix 0"> |
||||
<Speed FadeIn="0" FadeOut="0" Duration="500"/> |
||||
<Direction>Forward</Direction> |
||||
<RunOrder>Loop</RunOrder> |
||||
<Algorithm Type="Script">Stripes</Algorithm> |
||||
<MonoColor>4294901760</MonoColor> |
||||
<ControlMode>RGB</ControlMode> |
||||
<FixtureGroup>4294967295</FixtureGroup> |
||||
</Function> |
||||
<Function ID="1" Type="EFX" Name="Neuer Effekt 1"> |
||||
<PropagationMode>Parallel</PropagationMode> |
||||
<Speed FadeIn="0" FadeOut="0" Duration="20000"/> |
||||
<Direction>Forward</Direction> |
||||
<RunOrder>Loop</RunOrder> |
||||
<Algorithm>Circle</Algorithm> |
||||
<Width>127</Width> |
||||
<Height>127</Height> |
||||
<Rotation>0</Rotation> |
||||
<StartOffset>0</StartOffset> |
||||
<IsRelative>0</IsRelative> |
||||
<Axis Name="X"> |
||||
<Offset>127</Offset> |
||||
<Frequency>2</Frequency> |
||||
<Phase>90</Phase> |
||||
</Axis> |
||||
<Axis Name="Y"> |
||||
<Offset>127</Offset> |
||||
<Frequency>3</Frequency> |
||||
<Phase>0</Phase> |
||||
</Axis> |
||||
</Function> |
||||
<Function ID="2" Type="Scene" Name="Neue Szene 2"> |
||||
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||
<FixtureVal ID="0">0,179</FixtureVal> |
||||
</Function> |
||||
<Function ID="3" Type="Script" Name="Neues Skript 3"> |
||||
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||
<Direction>Forward</Direction> |
||||
<RunOrder>Loop</RunOrder> |
||||
</Function> |
||||
<Function ID="4" Type="Scene" Name="Neue Szene 4"> |
||||
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||
<FixtureVal ID="0">0,52</FixtureVal> |
||||
</Function> |
||||
<Function ID="5" Type="Scene" Name="New Scene" Hidden="True"> |
||||
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||
</Function> |
||||
<Function ID="6" Type="Sequence" Name="Neue Sequenz 6" BoundScene="5"> |
||||
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||
<Direction>Forward</Direction> |
||||
<RunOrder>Loop</RunOrder> |
||||
<SpeedModes FadeIn="Default" FadeOut="Default" Duration="Common"/> |
||||
<Step Number="0" FadeIn="0" Hold="0" FadeOut="0" Values="0"/> |
||||
<Step Number="1" FadeIn="0" Hold="0" FadeOut="0" Values="0"/> |
||||
</Function> |
||||
<Function ID="7" Type="Chaser" Name="Neuer Chaser 7"> |
||||
<Speed FadeIn="0" FadeOut="0" Duration="100000"/> |
||||
<Direction>Forward</Direction> |
||||
<RunOrder>Loop</RunOrder> |
||||
<SpeedModes FadeIn="Default" FadeOut="Default" Duration="Common"/> |
||||
<Step Number="0" FadeIn="0" Hold="0" FadeOut="0">2</Step> |
||||
<Step Number="1" FadeIn="0" Hold="0" FadeOut="0">4</Step> |
||||
</Function> |
||||
</Engine> |
||||
<VirtualConsole> |
||||
<Frame Caption=""> |
||||
<Appearance> |
||||
<FrameStyle>None</FrameStyle> |
||||
<ForegroundColor>Default</ForegroundColor> |
||||
<BackgroundColor>Default</BackgroundColor> |
||||
<BackgroundImage>None</BackgroundImage> |
||||
<Font>Default</Font> |
||||
</Appearance> |
||||
<Button Caption="Schalter 0" ID="0" Icon=""> |
||||
<WindowState Visible="False" X="290" Y="160" Width="50" Height="50"/> |
||||
<Appearance> |
||||
<FrameStyle>None</FrameStyle> |
||||
<ForegroundColor>Default</ForegroundColor> |
||||
<BackgroundColor>Default</BackgroundColor> |
||||
<BackgroundImage>None</BackgroundImage> |
||||
<Font>Default</Font> |
||||
</Appearance> |
||||
<Function ID="4294967295"/> |
||||
<Action>Toggle</Action> |
||||
<Intensity Adjust="False">100</Intensity> |
||||
</Button> |
||||
<Frame Caption="" ID="1"> |
||||
<Appearance> |
||||
<FrameStyle>Sunken</FrameStyle> |
||||
<ForegroundColor>Default</ForegroundColor> |
||||
<BackgroundColor>Default</BackgroundColor> |
||||
<BackgroundImage>None</BackgroundImage> |
||||
<Font>Default</Font> |
||||
</Appearance> |
||||
<WindowState Visible="False" X="475" Y="140" Width="845" Height="665"/> |
||||
<AllowChildren>True</AllowChildren> |
||||
<AllowResize>True</AllowResize> |
||||
<ShowHeader>True</ShowHeader> |
||||
<ShowEnableButton>True</ShowEnableButton> |
||||
<Collapsed>False</Collapsed> |
||||
<Disabled>False</Disabled> |
||||
<Button Caption="Neue RGB Matrix 0" ID="2" Icon=""> |
||||
<WindowState Visible="False" X="45" Y="95" Width="50" Height="50"/> |
||||
<Appearance> |
||||
<FrameStyle>None</FrameStyle> |
||||
<ForegroundColor>Default</ForegroundColor> |
||||
<BackgroundColor>Default</BackgroundColor> |
||||
<BackgroundImage>None</BackgroundImage> |
||||
<Font>Default</Font> |
||||
</Appearance> |
||||
<Function ID="4"/> |
||||
<Action>Toggle</Action> |
||||
<Intensity Adjust="False">100</Intensity> |
||||
<Input Universe="3" Channel="0"/> |
||||
</Button> |
||||
<XYPad Caption="XY Pad" ID="3" InvertedAppearance="0"> |
||||
<WindowState Visible="False" X="165" Y="140" Width="230" Height="230"/> |
||||
<Appearance> |
||||
<FrameStyle>Sunken</FrameStyle> |
||||
<ForegroundColor>Default</ForegroundColor> |
||||
<BackgroundColor>Default</BackgroundColor> |
||||
<BackgroundImage>None</BackgroundImage> |
||||
<Font>Default</Font> |
||||
</Appearance> |
||||
<Pan Position="114"> |
||||
<Input Universe="3" Channel="64"/> |
||||
</Pan> |
||||
<Tilt Position="162"> |
||||
<Input Universe="3" Channel="65"/> |
||||
</Tilt> |
||||
</XYPad> |
||||
<Slider Caption="Schieberegler 4" ID="4" WidgetStyle="Slider" InvertedAppearance="false"> |
||||
<WindowState Visible="False" X="435" Y="140" Width="85" Height="230"/> |
||||
<Appearance> |
||||
<FrameStyle>Sunken</FrameStyle> |
||||
<ForegroundColor>Default</ForegroundColor> |
||||
<BackgroundColor>Default</BackgroundColor> |
||||
<BackgroundImage>None</BackgroundImage> |
||||
<Font>Default</Font> |
||||
</Appearance> |
||||
<Input Universe="3" Channel="66"/> |
||||
<SliderMode ValueDisplayStyle="Exact" ClickAndGoType="None">Playback</SliderMode> |
||||
<Level LowLimit="0" HighLimit="255" Value="0"/> |
||||
<Playback> |
||||
<Function>4294967295</Function> |
||||
</Playback> |
||||
</Slider> |
||||
<CueList Caption="Cue-Liste" ID="5"> |
||||
<WindowState Visible="False" X="245" Y="395" Width="300" Height="220"/> |
||||
<Appearance> |
||||
<FrameStyle>Sunken</FrameStyle> |
||||
<ForegroundColor>Default</ForegroundColor> |
||||
<BackgroundColor>Default</BackgroundColor> |
||||
<BackgroundImage>None</BackgroundImage> |
||||
<Font>Default</Font> |
||||
</Appearance> |
||||
<Chaser>7</Chaser> |
||||
<NextPrevBehavior>3</NextPrevBehavior> |
||||
<Next> |
||||
<Input Universe="3" Channel="0"/> |
||||
</Next> |
||||
<Previous/> |
||||
<Playback/> |
||||
<Stop/> |
||||
<SlidersMode>Steps</SlidersMode> |
||||
</CueList> |
||||
</Frame> |
||||
</Frame> |
||||
<Properties> |
||||
<Size Width="1920" Height="1080"/> |
||||
<GrandMaster ChannelMode="Intensity" ValueMode="Reduce" SliderMode="Normal"/> |
||||
</Properties> |
||||
</VirtualConsole> |
||||
<SimpleDesk> |
||||
<Engine/> |
||||
</SimpleDesk> |
||||
</Workspace> |
Loading…
Reference in new issue