├── 3dprint ├── OTTOsonics volume control body.stl ├── OTTOsonics volume control knob.stl ├── OTTOsonics volume control lid.stl └── Readme.md ├── IMG_0427.jpg ├── README.md ├── schematic.jpg └── src ├── Free_Fonts.h ├── Readme.md └── avb-volume-knob-mute.ino /3dprint/OTTOsonics volume control body.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultranoise/MOTU_AVB_ESP32_Controller/218a2eb48b72a1071b9f50c1540413029eb733c6/3dprint/OTTOsonics volume control body.stl -------------------------------------------------------------------------------- /3dprint/OTTOsonics volume control knob.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultranoise/MOTU_AVB_ESP32_Controller/218a2eb48b72a1071b9f50c1540413029eb733c6/3dprint/OTTOsonics volume control knob.stl -------------------------------------------------------------------------------- /3dprint/OTTOsonics volume control lid.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultranoise/MOTU_AVB_ESP32_Controller/218a2eb48b72a1071b9f50c1540413029eb733c6/3dprint/OTTOsonics volume control lid.stl -------------------------------------------------------------------------------- /3dprint/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /IMG_0427.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultranoise/MOTU_AVB_ESP32_Controller/218a2eb48b72a1071b9f50c1540413029eb733c6/IMG_0427.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MOTU_AVB_ESP32_Controller 2 | Building a simple volume controller with a ESP32 for MOTU AVB audio interfaces. Part of the [Ottosonics](https://tamlab.kunstuni-linz.at/projects/ottosonics/) project . 3 | 4 | 5 | 6 | MOTU AVB interfaces have a particular method for receiving HTTP POST messages. First read the MOTU API Reference: 7 | 8 | https://cdn-data.motu.com/downloads/audio/AVB/docs/OSC%20Quick%20Reference.pdf 9 | 10 | The principle to GET and POST with MOTU AVB interfaces is rather simple with cURL: 11 | 12 | * get the datastore: ``` curl http://192.168.0.5/datastore ``` (use the IP of your interface here) 13 | 14 | * read value of mic1 trim: ``` curl http://192.168.0.5/datastore/ext/ibank/0/ch/0/trim ``` 15 | 16 | * set value of mic1 trim: ``` curl --data 'json={"value":"45"}' http://192.168.0.5/datastore/ext/ibank/0/ch/0/trim ``` 17 | 18 | * set mixer fader 0 (ch1) value: ``` curl --data 'json={"value":"0.7"}' http://192.168.0.5/datastore/mix/chan/0/matrix/fader ``` 19 | 20 | * set mixer fader 1 (ch2) value: ``` curl --data 'json={"value":"0.7"}' http://192.168.0.5/datastore/mix/chan/1/matrix/fader ``` 21 | 22 | * set mixer fader 1 and fader 2 at the same time: ``` curl --data 'json={"0/matrix/fader":"0.2","1/matrix/fader":"0.1"}' http://192.168.0.5/datastore/mix/chan/ ``` 23 | 24 | # Hardware 25 | 26 | We used a ESP32 with ethernet by [Olimex](https://www.olimex.com/Products/IoT/ESP32/ESP32-GATEWAY/open-source-hardware) and a [SPI TFT display](https://www.amazon.de/gp/product/B07YTWRZGR/ref=ppx_yo_dt_b_asin_title_o06_s01?ie=UTF8&psc=1) that we connected as follows: 27 | ![alt text](https://github.com/ultranoise/MOTU_AVB_ESP32_Controller/blob/main/schematic.jpg) 28 | Please note that a WLAN version of this code could be easily implemented with the same board (call wlan functions instead of ethernet). 29 | 30 | # Code 31 | 32 | * If you want to download our solution please go to the source folder of this repository 33 | 34 | * With our ESP32, the following code can be used to read the datastore: 35 | 36 | ``` 37 | #define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT 38 | #define ETH_PHY_POWER 5 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | #define USE_SERIAL Serial 45 | 46 | static bool eth_connected = false; 47 | 48 | #include 49 | #include 50 | 51 | WiFiMulti wifiMulti; 52 | 53 | void WiFiEvent(WiFiEvent_t event) 54 | { 55 | switch (event) { 56 | case ARDUINO_EVENT_ETH_START: 57 | USE_SERIAL.println("ETH Started"); 58 | //set eth hostname here 59 | ETH.setHostname("esp32-ethernet"); 60 | break; 61 | case ARDUINO_EVENT_ETH_CONNECTED: 62 | USE_SERIAL.println("ETH Connected"); 63 | //eth_connected = true; 64 | break; 65 | case ARDUINO_EVENT_ETH_GOT_IP: 66 | USE_SERIAL.print("ETH MAC: "); 67 | USE_SERIAL.print(ETH.macAddress()); 68 | USE_SERIAL.print(", IPv4: "); 69 | USE_SERIAL.print(ETH.localIP()); 70 | if (ETH.fullDuplex()) { 71 | USE_SERIAL.print(", FULL_DUPLEX"); 72 | } 73 | USE_SERIAL.print(", "); 74 | USE_SERIAL.print(ETH.linkSpeed()); 75 | USE_SERIAL.println("Mbps"); 76 | eth_connected = true; 77 | break; 78 | case ARDUINO_EVENT_ETH_DISCONNECTED: 79 | USE_SERIAL.println("ETH Disconnected"); 80 | eth_connected = false; 81 | break; 82 | case ARDUINO_EVENT_ETH_STOP: 83 | USE_SERIAL.println("ETH Stopped"); 84 | eth_connected = false; 85 | break; 86 | default: 87 | break; 88 | } 89 | } 90 | 91 | void testClient(const char * host, uint16_t port) 92 | { 93 | USE_SERIAL.print("\nconnecting to "); 94 | USE_SERIAL.println(host); 95 | 96 | WiFiClient client; 97 | if (!client.connect(host, port)) { 98 | USE_SERIAL.println("connection failed"); 99 | return; 100 | } 101 | client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); 102 | while (client.connected() && !client.available()); 103 | while (client.available()) { 104 | USE_SERIAL.write(client.read()); 105 | } 106 | 107 | USE_SERIAL.println("closing connection\n"); 108 | client.stop(); 109 | } 110 | 111 | void testAvb(const char * host, uint16_t port) 112 | { 113 | HTTPClient http; 114 | 115 | USE_SERIAL.print("[HTTP] begin...\n"); 116 | // configure traged server and url 117 | http.begin("http://192.168.0.5/datastore/"); //HTTP 118 | 119 | USE_SERIAL.print("[HTTP] GET...\n"); 120 | // start connection and send HTTP header 121 | int httpCode = http.GET(); 122 | 123 | // httpCode will be negative on error 124 | if(httpCode > 0) { 125 | // HTTP header has been send and Server response header has been handled 126 | USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); 127 | 128 | // file found at server 129 | if(httpCode == HTTP_CODE_OK) { 130 | String payload = http.getString(); 131 | USE_SERIAL.println(payload); 132 | } 133 | } else { 134 | USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); 135 | } 136 | 137 | http.end(); 138 | } 139 | 140 | 141 | void setup() 142 | { 143 | USE_SERIAL.begin(115200); 144 | WiFi.onEvent(WiFiEvent); 145 | ETH.begin(); 146 | } 147 | 148 | 149 | void loop() 150 | { 151 | if (eth_connected) { 152 | testAvb("google.com", 80); 153 | } 154 | delay(10000); 155 | } 156 | ``` 157 | 158 | * The issues begin when you try to POST messages. The logic of posting with JSON encoding doesn't work. If you typically use the following code you will get an error: 159 | 160 | ``` 161 | 162 | void postDataToServer() { 163 | 164 | HTTPClient http; 165 | 166 | http.begin("http://192.168.0.5/datastore/ext/obank/2/ch/0/name"); 167 | 168 | http.addHeader("Content-Type", "application/json"); 169 | 170 | int httpResponseCode = http.POST("{\"value\":\"My favorite channel\"}"); 171 | 172 | if (httpResponseCode > 0) { 173 | 174 | String response = http.getString(); 175 | 176 | Serial.println(httpResponseCode); 177 | Serial.println(response); 178 | 179 | } else { 180 | 181 | Serial.print("Error on sending PUT Request: "); 182 | Serial.println(httpResponseCode); 183 | 184 | } 185 | 186 | http.end(); 187 | 188 | } 189 | ``` 190 | 191 | you get a (-5) or (-1) error: 192 | 193 | ``` 194 | ETH Connected 195 | POSTing to Server... 196 | -5 197 | 198 | ``` 199 | 200 | So clearly there is a difference in how headers or formatting are set. I used the online service httpbin.org to debug the messages. Basically httpbin.org replied me a copy of what we have to send. 201 | 202 | This is what you get if you use the cURL command which works with the MOTU: 203 | 204 | ``` 205 | curl --data 'json={"value":"My favorite channel"}' https://httpbin.org/post 206 | { 207 | "args": {}, 208 | "data": "", 209 | "files": {}, 210 | "form": { 211 | "json": "{\"value\":\"My favorite channel\"}" 212 | }, 213 | "headers": { 214 | "Accept": "*/*", 215 | "Content-Length": "36", 216 | "Content-Type": "application/x-www-form-urlencoded", 217 | "Host": "httpbin.org", 218 | "User-Agent": "curl/7.64.1", 219 | "X-Amzn-Trace-Id": "Root=1-62a2ec58-01489dc01c52f8201f03eccb" 220 | }, 221 | "json": null, 222 | "origin": "188.23.136.201", 223 | "url": "https://httpbin.org/post" 224 | } 225 | ``` 226 | 227 | However, with the previous Arduino code (which doesn't work with the MOTU interface) 228 | 229 | ``` 230 | 200 231 | { 232 | "args": {}, 233 | "data": "{\"value\":\"My favorite channel\"}", 234 | "files": {}, 235 | "form": {}, 236 | "headers": { 237 | "Accept-Encoding": "identity;q=1,chunked;q=0.1,*;q=0", 238 | "Content-Length": "31", 239 | "Content-Type": "application/json", 240 | "Host": "httpbin.org", 241 | "User-Agent": "ESP32HTTPClient", 242 | "X-Amzn-Trace-Id": "Root=1-62a2e98e-0825a5fe531b2c493b88287d" 243 | }, 244 | "json": { 245 | "value": "My favorite channel" 246 | }, 247 | "origin": "188.23.136.201", 248 | "url": "https://httpbin.org/post" 249 | } 250 | 251 | ``` 252 | 253 | Ergo-> there are quite noticeable differences!! 254 | 255 | If we use the same arduino code with a different header ("application/x-www-form-urlencoded") instead of (application/json") 256 | 257 | ``` 258 | //http.addHeader("Content-Type", "application/json"); 259 | http.addHeader("Content-Type", "application/x-www-form-urlencoded"); 260 | ``` 261 | 262 | We get 263 | 264 | ``` 265 | 200 266 | { 267 | "args": {}, 268 | "data": "", 269 | "files": {}, 270 | "form": { 271 | "{\"value\":\"My favorite channel\"}": "" 272 | }, 273 | "headers": { 274 | "Accept-Encoding": "identity;q=1,chunked;q=0.1,*;q=0", 275 | "Content-Length": "31", 276 | "Content-Type": "application/x-www-form-urlencoded", 277 | "Host": "httpbin.org", 278 | "User-Agent": "ESP32HTTPClient", 279 | "X-Amzn-Trace-Id": "Root=1-62a2ee48-42acf6c158c472cf4e3d67b8" 280 | }, 281 | "json": null, 282 | "origin": "188.23.136.201", 283 | "url": "https://httpbin.org/post" 284 | } 285 | ``` 286 | 287 | Which looks better, but to accommondate the format that the MOTU interface expects ( json={} ) this is the final code which finally works: 288 | 289 | ``` 290 | void postDataToServerTwo() { 291 | HTTPClient http; 292 | 293 | http.begin("http://192.168.0.5/datastore/mix/chan/0/matrix/fader"); 294 | 295 | http.addHeader("Content-Type", "application/x-www-form-urlencoded"); 296 | 297 | int httpResponseCode = http.POST("json={\"value\":\"0.7\"}"); 298 | 299 | 300 | if (httpResponseCode > 0) { 301 | 302 | String response = http.getString(); 303 | 304 | Serial.println(httpResponseCode); 305 | Serial.println(response); 306 | 307 | } else { 308 | 309 | Serial.print("Error on sending PUT Request: "); 310 | Serial.println(httpResponseCode); 311 | 312 | } 313 | 314 | http.end(); 315 | } 316 | ``` 317 | 318 | This simple produces a "204" response and moves the fader! 319 | 320 | You can take a look at a complete example in the src folder. 321 | -------------------------------------------------------------------------------- /schematic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultranoise/MOTU_AVB_ESP32_Controller/218a2eb48b72a1071b9f50c1540413029eb733c6/schematic.jpg -------------------------------------------------------------------------------- /src/Free_Fonts.h: -------------------------------------------------------------------------------- 1 | // Attach this header file to your sketch to use the GFX Free Fonts. You can write 2 | // sketches without it, but it makes referencing them easier. 3 | 4 | // This calls up ALL the fonts but they only get loaded if you actually 5 | // use them in your sketch. 6 | // 7 | // No changes are needed to this header file unless new fonts are added to the 8 | // library "Fonts/GFXFF" folder. 9 | // 10 | // To save a lot of typing long names, each font can easily be referenced in the 11 | // sketch in three ways, either with: 12 | // 13 | // 1. Font file name with the & in front such as &FreeSansBoldOblique24pt7b 14 | // an example being: 15 | // 16 | // tft.setFreeFont(&FreeSansBoldOblique24pt7b); 17 | // 18 | // 2. FF# where # is a number determined by looking at the list below 19 | // an example being: 20 | // 21 | // tft.setFreeFont(FF32); 22 | // 23 | // 3. An abbreviation of the file name. Look at the list below to see 24 | // the abbreviations used, for example: 25 | // 26 | // tft.setFreeFont(FSSBO24) 27 | // 28 | // Where the letters mean: 29 | // F = Free font 30 | // M = Mono 31 | // SS = Sans Serif (double S to distinguish is form serif fonts) 32 | // S = Serif 33 | // B = Bold 34 | // O = Oblique (letter O not zero) 35 | // I = Italic 36 | // # = point size, either 9, 12, 18 or 24 37 | // 38 | // Setting the font to NULL will select the GLCD font: 39 | // 40 | // tft.setFreeFont(NULL); // Set font to GLCD 41 | 42 | #ifdef LOAD_GFXFF // Only include the fonts if LOAD_GFXFF is defined in User_Setup.h 43 | 44 | // Use these when printing or drawing text in GLCD and high rendering speed fonts 45 | #define GFXFF 1 46 | #define GLCD 0 47 | #define FONT2 2 48 | #define FONT4 4 49 | #define FONT6 6 50 | #define FONT7 7 51 | #define FONT8 8 52 | 53 | // Use the following when calling setFont() 54 | // 55 | // Reserved for GLCD font // FF0 56 | // 57 | 58 | #define TT1 &TomThumb 59 | 60 | #define FM9 &FreeMono9pt7b 61 | #define FM12 &FreeMono12pt7b 62 | #define FM18 &FreeMono18pt7b 63 | #define FM24 &FreeMono24pt7b 64 | 65 | #define FMB9 &FreeMonoBold9pt7b 66 | #define FMB12 &FreeMonoBold12pt7b 67 | #define FMB18 &FreeMonoBold18pt7b 68 | #define FMB24 &FreeMonoBold24pt7b 69 | 70 | #define FMO9 &FreeMonoOblique9pt7b 71 | #define FMO12 &FreeMonoOblique12pt7b 72 | #define FMO18 &FreeMonoOblique18pt7b 73 | #define FMO24 &FreeMonoOblique24pt7b 74 | 75 | #define FMBO9 &FreeMonoBoldOblique9pt7b 76 | #define FMBO12 &FreeMonoBoldOblique12pt7b 77 | #define FMBO18 &FreeMonoBoldOblique18pt7b 78 | #define FMBO24 &FreeMonoBoldOblique24pt7b 79 | 80 | #define FSS9 &FreeSans9pt7b 81 | #define FSS12 &FreeSans12pt7b 82 | #define FSS18 &FreeSans18pt7b 83 | #define FSS24 &FreeSans24pt7b 84 | 85 | #define FSSB9 &FreeSansBold9pt7b 86 | #define FSSB12 &FreeSansBold12pt7b 87 | #define FSSB18 &FreeSansBold18pt7b 88 | #define FSSB24 &FreeSansBold24pt7b 89 | 90 | #define FSSO9 &FreeSansOblique9pt7b 91 | #define FSSO12 &FreeSansOblique12pt7b 92 | #define FSSO18 &FreeSansOblique18pt7b 93 | #define FSSO24 &FreeSansOblique24pt7b 94 | 95 | #define FSSBO9 &FreeSansBoldOblique9pt7b 96 | #define FSSBO12 &FreeSansBoldOblique12pt7b 97 | #define FSSBO18 &FreeSansBoldOblique18pt7b 98 | #define FSSBO24 &FreeSansBoldOblique24pt7b 99 | 100 | #define FS9 &FreeSerif9pt7b 101 | #define FS12 &FreeSerif12pt7b 102 | #define FS18 &FreeSerif18pt7b 103 | #define FS24 &FreeSerif24pt7b 104 | 105 | #define FSI9 &FreeSerifItalic9pt7b 106 | #define FSI12 &FreeSerifItalic12pt7b 107 | #define FSI19 &FreeSerifItalic18pt7b 108 | #define FSI24 &FreeSerifItalic24pt7b 109 | 110 | #define FSB9 &FreeSerifBold9pt7b 111 | #define FSB12 &FreeSerifBold12pt7b 112 | #define FSB18 &FreeSerifBold18pt7b 113 | #define FSB24 &FreeSerifBold24pt7b 114 | 115 | #define FSBI9 &FreeSerifBoldItalic9pt7b 116 | #define FSBI12 &FreeSerifBoldItalic12pt7b 117 | #define FSBI18 &FreeSerifBoldItalic18pt7b 118 | #define FSBI24 &FreeSerifBoldItalic24pt7b 119 | 120 | #define FF0 NULL //ff0 reserved for GLCD 121 | #define FF1 &FreeMono9pt7b 122 | #define FF2 &FreeMono12pt7b 123 | #define FF3 &FreeMono18pt7b 124 | #define FF4 &FreeMono24pt7b 125 | 126 | #define FF5 &FreeMonoBold9pt7b 127 | #define FF6 &FreeMonoBold12pt7b 128 | #define FF7 &FreeMonoBold18pt7b 129 | #define FF8 &FreeMonoBold24pt7b 130 | 131 | #define FF9 &FreeMonoOblique9pt7b 132 | #define FF10 &FreeMonoOblique12pt7b 133 | #define FF11 &FreeMonoOblique18pt7b 134 | #define FF12 &FreeMonoOblique24pt7b 135 | 136 | #define FF13 &FreeMonoBoldOblique9pt7b 137 | #define FF14 &FreeMonoBoldOblique12pt7b 138 | #define FF15 &FreeMonoBoldOblique18pt7b 139 | #define FF16 &FreeMonoBoldOblique24pt7b 140 | 141 | #define FF17 &FreeSans9pt7b 142 | #define FF18 &FreeSans12pt7b 143 | #define FF19 &FreeSans18pt7b 144 | #define FF20 &FreeSans24pt7b 145 | 146 | #define FF21 &FreeSansBold9pt7b 147 | #define FF22 &FreeSansBold12pt7b 148 | #define FF23 &FreeSansBold18pt7b 149 | #define FF24 &FreeSansBold24pt7b 150 | 151 | #define FF25 &FreeSansOblique9pt7b 152 | #define FF26 &FreeSansOblique12pt7b 153 | #define FF27 &FreeSansOblique18pt7b 154 | #define FF28 &FreeSansOblique24pt7b 155 | 156 | #define FF29 &FreeSansBoldOblique9pt7b 157 | #define FF30 &FreeSansBoldOblique12pt7b 158 | #define FF31 &FreeSansBoldOblique18pt7b 159 | #define FF32 &FreeSansBoldOblique24pt7b 160 | 161 | #define FF33 &FreeSerif9pt7b 162 | #define FF34 &FreeSerif12pt7b 163 | #define FF35 &FreeSerif18pt7b 164 | #define FF36 &FreeSerif24pt7b 165 | 166 | #define FF37 &FreeSerifItalic9pt7b 167 | #define FF38 &FreeSerifItalic12pt7b 168 | #define FF39 &FreeSerifItalic18pt7b 169 | #define FF40 &FreeSerifItalic24pt7b 170 | 171 | #define FF41 &FreeSerifBold9pt7b 172 | #define FF42 &FreeSerifBold12pt7b 173 | #define FF43 &FreeSerifBold18pt7b 174 | #define FF44 &FreeSerifBold24pt7b 175 | 176 | #define FF45 &FreeSerifBoldItalic9pt7b 177 | #define FF46 &FreeSerifBoldItalic12pt7b 178 | #define FF47 &FreeSerifBoldItalic18pt7b 179 | #define FF48 &FreeSerifBoldItalic24pt7b 180 | 181 | // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 182 | // Now we define "s"tring versions for easy printing of the font name so: 183 | // tft.println(sFF5); 184 | // will print 185 | // Mono bold 9 186 | // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 187 | 188 | #define sFF0 "GLCD" 189 | #define sTT1 "Tom Thumb" 190 | #define sFF1 "Mono 9" 191 | #define sFF2 "Mono 12" 192 | #define sFF3 "Mono 18" 193 | #define sFF4 "Mono 24" 194 | 195 | #define sFF5 "Mono bold 9" 196 | #define sFF6 "Mono bold 12" 197 | #define sFF7 "Mono bold 18" 198 | #define sFF8 "Mono bold 24" 199 | 200 | #define sFF9 "Mono oblique 9" 201 | #define sFF10 "Mono oblique 12" 202 | #define sFF11 "Mono oblique 18" 203 | #define sFF12 "Mono oblique 24" 204 | 205 | #define sFF13 "Mono bold oblique 9" 206 | #define sFF14 "Mono bold oblique 12" 207 | #define sFF15 "Mono bold oblique 18" 208 | #define sFF16 "Mono bold obl. 24" // Full text line is too big for 480 pixel wide screen 209 | 210 | #define sFF17 "Sans 9" 211 | #define sFF18 "Sans 12" 212 | #define sFF19 "Sans 18" 213 | #define sFF20 "Sans 24" 214 | 215 | #define sFF21 "Sans bold 9" 216 | #define sFF22 "Sans bold 12" 217 | #define sFF23 "Sans bold 18" 218 | #define sFF24 "Sans bold 24" 219 | 220 | #define sFF25 "Sans oblique 9" 221 | #define sFF26 "Sans oblique 12" 222 | #define sFF27 "Sans oblique 18" 223 | #define sFF28 "Sans oblique 24" 224 | 225 | #define sFF29 "Sans bold oblique 9" 226 | #define sFF30 "Sans bold oblique 12" 227 | #define sFF31 "Sans bold oblique 18" 228 | #define sFF32 "Sans bold oblique 24" 229 | 230 | #define sFF33 "Serif 9" 231 | #define sFF34 "Serif 12" 232 | #define sFF35 "Serif 18" 233 | #define sFF36 "Serif 24" 234 | 235 | #define sFF37 "Serif italic 9" 236 | #define sFF38 "Serif italic 12" 237 | #define sFF39 "Serif italic 18" 238 | #define sFF40 "Serif italic 24" 239 | 240 | #define sFF41 "Serif bold 9" 241 | #define sFF42 "Serif bold 12" 242 | #define sFF43 "Serif bold 18" 243 | #define sFF44 "Serif bold 24" 244 | 245 | #define sFF45 "Serif bold italic 9" 246 | #define sFF46 "Serif bold italic 12" 247 | #define sFF47 "Serif bold italic 18" 248 | #define sFF48 "Serif bold italic 24" 249 | 250 | #else // LOAD_GFXFF not defined so setup defaults to prevent error messages 251 | 252 | // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 253 | // Free fonts are not loaded in User_Setup.h so we must define all as font 1 254 | // to prevent compile error messages 255 | // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 256 | 257 | #define GFXFF 1 258 | #define GLCD 1 259 | #define FONT2 2 260 | #define FONT4 4 261 | #define FONT6 6 262 | #define FONT7 7 263 | #define FONT8 8 264 | 265 | #define TT1 1 266 | 267 | #define FF0 1 268 | #define FF1 1 269 | #define FF2 1 270 | #define FF3 1 271 | #define FF4 1 272 | #define FF5 1 273 | #define FF6 1 274 | #define FF7 1 275 | #define FF8 1 276 | #define FF9 1 277 | #define FF10 1 278 | #define FF11 1 279 | #define FF12 1 280 | #define FF13 1 281 | #define FF14 1 282 | #define FF15 1 283 | #define FF16 1 284 | #define FF17 1 285 | #define FF18 1 286 | #define FF19 1 287 | #define FF20 1 288 | #define FF21 1 289 | #define FF22 1 290 | #define FF23 1 291 | #define FF24 1 292 | #define FF25 1 293 | #define FF26 1 294 | #define FF27 1 295 | #define FF28 1 296 | #define FF29 1 297 | #define FF30 1 298 | #define FF31 1 299 | #define FF32 1 300 | #define FF33 1 301 | #define FF34 1 302 | #define FF35 1 303 | #define FF36 1 304 | #define FF37 1 305 | #define FF38 1 306 | #define FF39 1 307 | #define FF40 1 308 | #define FF41 1 309 | #define FF42 1 310 | #define FF43 1 311 | #define FF44 1 312 | #define FF45 1 313 | #define FF46 1 314 | #define FF47 1 315 | #define FF48 1 316 | 317 | #define FM9 1 318 | #define FM12 1 319 | #define FM18 1 320 | #define FM24 1 321 | 322 | #define FMB9 1 323 | #define FMB12 1 324 | #define FMB18 1 325 | #define FMB24 1 326 | 327 | #define FMO9 1 328 | #define FMO12 1 329 | #define FMO18 1 330 | #define FMO24 1 331 | 332 | #define FMBO9 1 333 | #define FMBO12 1 334 | #define FMBO18 1 335 | #define FMBO24 1 336 | 337 | #define FSS9 1 338 | #define FSS12 1 339 | #define FSS18 1 340 | #define FSS24 1 341 | 342 | #define FSSB9 1 343 | #define FSSB12 1 344 | #define FSSB18 1 345 | #define FSSB24 1 346 | 347 | #define FSSO9 1 348 | #define FSSO12 1 349 | #define FSSO18 1 350 | #define FSSO24 1 351 | 352 | #define FSSBO9 1 353 | #define FSSBO12 1 354 | #define FSSBO18 1 355 | #define FSSBO24 1 356 | 357 | #define FS9 1 358 | #define FS12 1 359 | #define FS18 1 360 | #define FS24 1 361 | 362 | #define FSI9 1 363 | #define FSI12 1 364 | #define FSI19 1 365 | #define FSI24 1 366 | 367 | #define FSB9 1 368 | #define FSB12 1 369 | #define FSB18 1 370 | #define FSB24 1 371 | 372 | #define FSBI9 1 373 | #define FSBI12 1 374 | #define FSBI18 1 375 | #define FSBI24 1 376 | 377 | #endif // LOAD_GFXFF 378 | -------------------------------------------------------------------------------- /src/Readme.md: -------------------------------------------------------------------------------- 1 | Example of posting and retrieving data from a MOTU AVB interface. This code uses ethernet instead of Wifi (just take the GET/POST functions and use them in your code) 2 | 3 | -------------------------------------------------------------------------------- /src/avb-volume-knob-mute.ino: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////// 2 | // AVB VOLUME KNOB 3 | // PRESS KNOB FOR PANIC MODE (-24DB) 4 | // enrique.tomas@kunstuni-linz.at 2022 5 | // use this code at your own risk, 6 | // no responsabilities granted. 7 | ////////////////////////////////////// 8 | 9 | #include "SPI.h" 10 | #include "TFT_eSPI.h" 11 | #include "Free_Fonts.h" // Include the header file attached to this sketch 12 | // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts 13 | #define LOAD_GFXFF 14 | 15 | #define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT 16 | #define ETH_PHY_POWER 5 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define USE_SERIAL Serial 26 | static bool eth_connected = false; 27 | 28 | WiFiMulti wifiMulti; 29 | 30 | const char* server = "http://192.168.0.101/datastore/mix/chan/0/matrix/fader"; 31 | 32 | 33 | //Sensor vars 34 | ESP32Encoder encoder; //encoder variable 35 | int encoderValue = 0; 36 | int encoderValue_past = 0; 37 | int encoderIncrement = 0; 38 | int encoderIncrement_past; 39 | int pushButton = 35; //push button in the encoder 40 | int pushValue = 1; 41 | int pushValue_past = 0; 42 | bool newIncValue = false; 43 | 44 | //fader values etc 45 | float faderVolume; 46 | float dbVolume; 47 | float incVol; 48 | bool firstConnection = true; 49 | bool in_connection = true; 50 | bool init_end = false; 51 | 52 | // Use hardware SPI 53 | TFT_eSPI tft = TFT_eSPI(); 54 | 55 | unsigned long drawTime = 0; 56 | int xpos, ypos; 57 | 58 | String devices_ip[10]; 59 | String uids[10]; 60 | String IPdevices2control[10]; 61 | int counter_device2control = 0; 62 | int devices_number = 0; 63 | int selected_device = 0; 64 | 65 | int studio = 2; //0 -> tamlab, 1->alter bauhof, 2-> tamlab second rack 66 | 67 | //controlling various faders 68 | //we have to build 'json={"0/matrix/fader":"0.2","1/matrix/fader":"0.1"}' http://192.168.0.5/datastore/mix/chan/ 69 | 70 | StaticJsonDocument<400> doc_mul; 71 | 72 | void WiFiEvent(WiFiEvent_t event) 73 | { 74 | switch (event) { 75 | case ARDUINO_EVENT_ETH_START: 76 | USE_SERIAL.println("ETH Started"); 77 | //set eth hostname here 78 | ETH.setHostname("esp32-ethernet"); 79 | break; 80 | case ARDUINO_EVENT_ETH_CONNECTED: 81 | USE_SERIAL.println("ETH Connected"); 82 | //eth_connected = true; 83 | break; 84 | case ARDUINO_EVENT_ETH_GOT_IP: 85 | USE_SERIAL.print("ETH MAC: "); 86 | USE_SERIAL.print(ETH.macAddress()); 87 | USE_SERIAL.print(", IPv4: "); 88 | USE_SERIAL.print(ETH.localIP()); 89 | if (ETH.fullDuplex()) { 90 | USE_SERIAL.print(", FULL_DUPLEX"); 91 | } 92 | USE_SERIAL.print(", "); 93 | USE_SERIAL.print(ETH.linkSpeed()); 94 | USE_SERIAL.println("Mbps"); 95 | eth_connected = true; 96 | break; 97 | case ARDUINO_EVENT_ETH_DISCONNECTED: 98 | USE_SERIAL.println("ETH Disconnected"); 99 | eth_connected = false; 100 | break; 101 | case ARDUINO_EVENT_ETH_STOP: 102 | USE_SERIAL.println("ETH Stopped"); 103 | eth_connected = false; 104 | break; 105 | default: 106 | break; 107 | } 108 | } 109 | 110 | 111 | 112 | 113 | float retrieveDevices(String ip_devices) 114 | { 115 | HTTPClient http; 116 | 117 | USE_SERIAL.println(" "); 118 | USE_SERIAL.print("retrieving UUID information...\n"); 119 | // configure traged server and url 120 | 121 | http.begin(ip_devices + "/datastore/avb/devs"); 122 | 123 | //USE_SERIAL.print("[HTTP] GET...\n"); 124 | // start connection and send HTTP header 125 | int httpCode = http.GET(); 126 | 127 | // httpCode will be negative on error 128 | if(httpCode > 0) { 129 | // HTTP header has been send and Server response header has been handled 130 | //USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); 131 | 132 | // file found at server 133 | if(httpCode == HTTP_CODE_OK) { 134 | String payload = http.getString(); 135 | 136 | //USE_SERIAL.println("payload"); 137 | //USE_SERIAL.println(payload); 138 | 139 | //fader payload is a String like {"value":0.7} 140 | //from where we have to extract the value 141 | 142 | DynamicJsonDocument doc(200); 143 | DeserializationError error =deserializeJson(doc, payload); 144 | 145 | // Test if parsing succeeds. 146 | if (error) { 147 | 148 | USE_SERIAL.print(F("deserializeJson() failed: ")); 149 | USE_SERIAL.println(error.f_str()); 150 | http.end(); 151 | return -1.0; 152 | } else { 153 | String f = doc["value"]; 154 | USE_SERIAL.println("UID values"); 155 | USE_SERIAL.println(f); 156 | 157 | int l = f.length(); //length of the string obtained e.g. 0001f2fffe008f93:0001f2fffe00f7c9 158 | //USE_SERIAL.println(l); 159 | 160 | int n = l / 16; //each device is 16 characters, separated by :, n is the number of devices 161 | USE_SERIAL.print("number of devices: "); 162 | USE_SERIAL.println(n); 163 | 164 | //necessary variables to extract each uid and ip: 165 | 166 | HTTPClient http2; 167 | 168 | String uid_ip; 169 | String uid_path; 170 | 171 | //RETRIEVE IPS OF EACH DEVICE 172 | USE_SERIAL.println(" "); 173 | USE_SERIAL.print("retrieving IP information of each device...\n"); 174 | 175 | for(int i=0;i 0) { 194 | 195 | // file found at server 196 | if(httpCode == HTTP_CODE_OK) { 197 | 198 | String payload2 = http2.getString(); 199 | 200 | //USE_SERIAL.println("payload"); 201 | USE_SERIAL.println(payload2); 202 | 203 | //fader payload is a String like {"value":0.7} 204 | //from where we have to extract the value 205 | DynamicJsonDocument doc2(200); 206 | DeserializationError error2 = deserializeJson(doc2, payload2); 207 | 208 | // Test if parsing succeeds. 209 | if (error2) { 210 | USE_SERIAL.print(F("deserializeJson() failed: ")); 211 | USE_SERIAL.println(error2.f_str()); 212 | http2.end(); 213 | return -1.0; 214 | 215 | } else { 216 | String ff = doc2["value"]; 217 | devices_ip[i] = ff; 218 | devices_number = devices_number + 1; 219 | USE_SERIAL.print("IP value: "); 220 | USE_SERIAL.println(ff); 221 | USE_SERIAL.println("index: " + i); 222 | } 223 | 224 | 225 | } 226 | } else { 227 | USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); 228 | http2.end(); 229 | return -1.0; 230 | } 231 | 232 | http2.end(); 233 | 234 | //END OF IP RETRIEVEMENT 235 | 236 | }//END OF FOR 237 | 238 | 239 | http.end(); 240 | return 1.0; 241 | } 242 | 243 | 244 | } 245 | } else { 246 | USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); 247 | http.end(); 248 | return -1.0; 249 | } 250 | 251 | 252 | } 253 | 254 | 255 | float getTrimValue() { 256 | HTTPClient http; 257 | 258 | //USE_SERIAL.print("[HTTP] begin...\n"); 259 | // configure traged server and url 260 | String path = "http://" + IPdevices2control[0] + "/datastore/ext/obank/0/ch/0/trim"; //try with the first obank 261 | USE_SERIAL.println("retrieving fader values from the following path: "); 262 | USE_SERIAL.println(path); 263 | 264 | http.begin(path); 265 | 266 | 267 | //USE_SERIAL.print("[HTTP] GET...\n"); 268 | // start connection and send HTTP header 269 | int httpCode = http.GET(); 270 | 271 | // httpCode will be negative on error 272 | if(httpCode > 0) { 273 | // HTTP header has been send and Server response header has been handled 274 | //USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); 275 | 276 | // file found at server 277 | if(httpCode == HTTP_CODE_OK) { 278 | String payload = http.getString(); 279 | 280 | USE_SERIAL.println("payload"); 281 | USE_SERIAL.println(payload); 282 | 283 | //fader payload is a String like {"value":0.7} 284 | //from where we have to extract the value 285 | 286 | 287 | DynamicJsonDocument doc(200); 288 | DeserializationError error =deserializeJson(doc, payload); 289 | 290 | // Test if parsing succeeds. 291 | if (error) { 292 | 293 | USE_SERIAL.print(F("deserializeJson() failed: ")); 294 | USE_SERIAL.println(error.f_str()); 295 | http.end(); 296 | return -1.0; 297 | } else { 298 | float f = doc["value"]; 299 | USE_SERIAL.println("extracted value"); 300 | USE_SERIAL.println(f); 301 | http.end(); 302 | return f; 303 | } 304 | 305 | 306 | } 307 | } else { 308 | USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); 309 | http.end(); 310 | return -1.0; 311 | } 312 | 313 | 314 | } 315 | 316 | 317 | float getFaderValue() { 318 | HTTPClient http; 319 | 320 | //USE_SERIAL.print("[HTTP] begin...\n"); 321 | // configure traged server and url 322 | String path = "http://" + devices_ip[selected_device] + "/datastore/mix/chan/0/matrix/fader"; 323 | http.begin(path); 324 | //http.begin("http://192.168.0.101/datastore/mix/chan/0/matrix/fader"); 325 | 326 | //USE_SERIAL.print("[HTTP] GET...\n"); 327 | // start connection and send HTTP header 328 | int httpCode = http.GET(); 329 | 330 | // httpCode will be negative on error 331 | if(httpCode > 0) { 332 | // HTTP header has been send and Server response header has been handled 333 | //USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); 334 | 335 | // file found at server 336 | if(httpCode == HTTP_CODE_OK) { 337 | String payload = http.getString(); 338 | 339 | //USE_SERIAL.println("payload"); 340 | //USE_SERIAL.println(payload); 341 | 342 | //fader payload is a String like {"value":0.7} 343 | //from where we have to extract the value 344 | 345 | 346 | DynamicJsonDocument doc(200); 347 | DeserializationError error =deserializeJson(doc, payload); 348 | 349 | // Test if parsing succeeds. 350 | if (error) { 351 | 352 | USE_SERIAL.print(F("deserializeJson() failed: ")); 353 | USE_SERIAL.println(error.f_str()); 354 | http.end(); 355 | return -1.0; 356 | } else { 357 | float f = doc["value"]; 358 | //USE_SERIAL.println("extracted value"); 359 | //USE_SERIAL.println(f); 360 | http.end(); 361 | return f; 362 | } 363 | 364 | 365 | } 366 | } else { 367 | USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); 368 | http.end(); 369 | return -1.0; 370 | } 371 | 372 | 373 | 374 | } 375 | 376 | 377 | void postDataToServerJSON(float vol) { 378 | 379 | StaticJsonDocument<200> doc; 380 | doc["value"] = vol; 381 | 382 | //Serial.println("deserialized doc" ); 383 | //serializeJson(doc, Serial); // Generate the minified JSON and send it to the Serial port. 384 | // The above should print: 385 | // {"value":0.3} 386 | 387 | // Start a new line 388 | //Serial.println(); 389 | 390 | String s; 391 | serializeJson(doc, s); 392 | 393 | //Serial.println("string s" ); 394 | //Serial.println(s); 395 | 396 | HTTPClient http; 397 | 398 | //path to one fader 399 | http.begin("http://192.168.0.101/datastore/mix/chan/0/matrix/fader"); 400 | 401 | //http.addHeader("Content-Type", "application/json"); 402 | http.addHeader("Content-Type", "application/x-www-form-urlencoded"); 403 | 404 | 405 | //int httpResponseCode = http.POST("json={\"value\":\"My favorite channel\"}"); (this is ok) 406 | //int httpResponseCode = http.POST("json={\"value\":\"0.7\"}"); //(this is ok) 407 | int httpResponseCode = http.POST("json=" + s); 408 | 409 | if (httpResponseCode > 0) { 410 | 411 | String response = http.getString(); 412 | 413 | //Serial.println(httpResponseCode); 414 | //Serial.println(response); 415 | 416 | } else { 417 | 418 | Serial.print("Error on sending PUT Request: "); 419 | Serial.println(httpResponseCode); 420 | 421 | } 422 | 423 | http.end(); 424 | 425 | } 426 | 427 | 428 | void postDataToServerJSONmultipleIP(float vol, int device_nr, String ipNumber) { 429 | 430 | //TO ACT ON THE TRIMMS : {"ext/obank/0/ch/0/trim":-18} -> but this has to be done for each of the devices 431 | 432 | 433 | String s; 434 | serializeJson(doc_mul, s); 435 | 436 | //Serial.println("string s" ); 437 | //Serial.println(s); 438 | 439 | HTTPClient http; 440 | //http.begin("http://" + devices_ip[device_nr] + "/datastore/"); //root for adding the doc[] 441 | 442 | //http.begin("http://192.168.0.102/datastore/"); //root for adding the doc[] 443 | 444 | http.begin("http://" + ipNumber + "/datastore/"); //root for adding the doc[] 445 | 446 | http.addHeader("Content-Type", "application/x-www-form-urlencoded"); 447 | 448 | int httpResponseCode = http.POST("json=" + s); 449 | 450 | if (httpResponseCode > 0) { 451 | 452 | String response = http.getString(); 453 | 454 | //Serial.println(httpResponseCode); 455 | //Serial.println(response); 456 | 457 | } else { 458 | 459 | Serial.print("Error on sending PUT Request: "); 460 | Serial.println(httpResponseCode); 461 | 462 | } 463 | 464 | http.end(); 465 | 466 | } 467 | 468 | 469 | 470 | void setup(void) { 471 | 472 | USE_SERIAL.begin(115200); 473 | //Serial.begin(115200); 474 | 475 | 476 | ///TFT 477 | tft.begin(); 478 | 479 | tft.setRotation(1); 480 | 481 | xpos = 0; 482 | ypos = 40; 483 | 484 | // tft.fillScreen(TFT_SKYBLUE); // Clear screen to navy background 485 | tft.setTextColor(TFT_GOLD, TFT_NAVY); 486 | 487 | tft.setTextDatum(TC_DATUM); // Centre text on x,y position 488 | 489 | xpos = tft.width() / 2; // Half the screen width 490 | ypos = 50; 491 | 492 | //tft.setFreeFont(FSB24); 493 | //tft.setTextFont(7); 494 | 495 | tft.fillScreen(TFT_NAVY); // Clear screen to navy background 496 | 497 | //tft.setTextFont(GLCD); 498 | tft.setFreeFont(FF18); 499 | tft.drawString("...", xpos, ypos, GFXFF); 500 | //clear screen 501 | //tft.fillScreen(TFT_BLACK); 502 | 503 | 504 | ///network 505 | WiFi.onEvent(WiFiEvent); 506 | ETH.begin(); 507 | 508 | //sensors 509 | pinMode(pushButton, INPUT_PULLUP); //prepare encoder push button input 510 | pinMode(36, INPUT_PULLUP); 511 | pinMode(39, INPUT_PULLUP); 512 | 513 | // ENCODER SETUP /// 514 | ESP32Encoder::useInternalWeakPullResistors=UP; 515 | encoder.clearCount(); // set starting count value 516 | USE_SERIAL.println("Encoder Start = "+String((int32_t)encoder.getCount())); 517 | //encoder.attachFullQuad(39, 36); //set precision of four values per step 518 | encoder.attachHalfQuad(39, 36); //set precision of four values per step 519 | 520 | 521 | firstConnection = true; 522 | encoderValue_past = encoderValue; 523 | 524 | //tft.fillScreen(TFT_BLACK); 525 | //tft.setFreeFont(FSB24); 526 | //tft.setTextSize(3); 527 | tft.setFreeFont(FF20); 528 | tft.drawString("Ottosonics", xpos, ypos, GFXFF); 529 | 530 | tft.drawString("AVB Controller", xpos, ypos + 50, GFXFF); 531 | tft.drawString("TAMLAB", xpos, ypos + 100, GFXFF); 532 | 533 | delay(2000); 534 | //wait for connection 535 | while(eth_connected == false){ 536 | delay(1000); 537 | } 538 | 539 | if (eth_connected){ 540 | //retrieve general information 541 | int resultDevices = retrieveDevices("http://192.168.0.100"); 542 | if(resultDevices<0) { 543 | //there was an error mostly with the ip used to retrieve devices 544 | USE_SERIAL.println("error with initial ip"); 545 | 546 | //try with other ips 547 | int resultDevices_afterError = retrieveDevices("http://192.168.0.101"); 548 | if(resultDevices_afterError<0) { 549 | int resultDevices_afterError2 = retrieveDevices("http://192.168.0.102"); 550 | //USE_SERIAL.println("error with secondary ip"); 551 | if(resultDevices_afterError2<0) { 552 | int resultDevices_afterError3 = retrieveDevices("http://192.168.0.103"); 553 | if(resultDevices_afterError3 <0) USE_SERIAL.println("error with secondary ip"); 554 | } 555 | 556 | } 557 | //show other possibilities to the user 558 | //clear screen 559 | tft.fillScreen(TFT_NAVY); 560 | //tft.setFreeFont(FSB24); 561 | 562 | //tft.drawString("No devices found", xpos, ypos, GFXFF); 563 | //tft.drawString("choose another IP", xpos, ypos + 20, GFXFF); 564 | } 565 | 566 | //ok so here i have obtained all devices from the network 567 | USE_SERIAL.println("++++++++++++++++"); 568 | for(int i=0;i returns value in dB already 690 | 691 | //dbVolume = 20*log10(faderVolume); //transform to dB 692 | 693 | //display in tft 694 | tft.fillScreen(TFT_NAVY); 695 | //tft.setFreeFont(FSB24); 696 | tft.setTextSize(3); 697 | tft.setFreeFont(FF18); 698 | tft.drawString(String(faderVolume), xpos - 50, 100, GFXFF); //tft.drawString(String(dbVolume), xpos, 100, GFXFF); 699 | tft.drawString("dB", xpos + 100, 100, GFXFF); 700 | 701 | firstConnection = false; 702 | USE_SERIAL.println("Ready!"); 703 | delay(3000); 704 | //initial encoder value is 0 705 | 706 | } //end of if(first connection) 707 | else { 708 | //encoder reading 709 | 710 | pushValue = digitalRead(pushButton); //push button in the encoder 711 | if(pushValue == 0){ 712 | faderVolume = -24.0; 713 | 714 | //quiza crear aqui los doc de json y no en cada loop 715 | doc_mul["ext/obank/0/ch/0/trim"] = faderVolume; 716 | doc_mul["ext/obank/0/ch/1/trim"] = faderVolume; 717 | doc_mul["ext/obank/0/ch/2/trim"] = faderVolume; 718 | doc_mul["ext/obank/0/ch/3/trim"] = faderVolume; 719 | doc_mul["ext/obank/0/ch/4/trim"] = faderVolume; 720 | doc_mul["ext/obank/0/ch/5/trim"] = faderVolume; 721 | doc_mul["ext/obank/0/ch/6/trim"] = faderVolume; 722 | doc_mul["ext/obank/0/ch/7/trim"] = faderVolume; 723 | doc_mul["ext/obank/0/ch/8/trim"] = faderVolume; 724 | doc_mul["ext/obank/0/ch/9/trim"] = faderVolume; 725 | doc_mul["ext/obank/0/ch/10/trim"] = faderVolume; 726 | doc_mul["ext/obank/0/ch/11/trim"] = faderVolume; 727 | doc_mul["ext/obank/0/ch/12/trim"] = faderVolume; 728 | doc_mul["ext/obank/0/ch/13/trim"] = faderVolume; 729 | doc_mul["ext/obank/0/ch/14/trim"] = faderVolume; 730 | doc_mul["ext/obank/0/ch/15/trim"] = faderVolume; 731 | doc_mul["ext/obank/0/ch/16/trim"] = faderVolume; 732 | doc_mul["ext/obank/0/ch/17/trim"] = faderVolume; 733 | doc_mul["ext/obank/0/ch/18/trim"] = faderVolume; 734 | doc_mul["ext/obank/0/ch/19/trim"] = faderVolume; 735 | doc_mul["ext/obank/0/ch/20/trim"] = faderVolume; 736 | doc_mul["ext/obank/0/ch/21/trim"] = faderVolume; 737 | doc_mul["ext/obank/0/ch/22/trim"] = faderVolume; 738 | doc_mul["ext/obank/0/ch/23/trim"] = faderVolume; 739 | 740 | 741 | 742 | 743 | for(int i=0;i 0) faderVolume = 0.0; 791 | if(faderVolume < -24) faderVolume = -24.0; 792 | 793 | //USE_SERIAL.print("faderVolume "); 794 | //USE_SERIAL.println(faderVolume); 795 | encoderValue_past = encoderValue; 796 | 797 | 798 | //quiza crear aqui los doc de json y no en cada loop 799 | doc_mul["ext/obank/0/ch/0/trim"] = faderVolume; 800 | doc_mul["ext/obank/0/ch/1/trim"] = faderVolume; 801 | doc_mul["ext/obank/0/ch/2/trim"] = faderVolume; 802 | doc_mul["ext/obank/0/ch/3/trim"] = faderVolume; 803 | doc_mul["ext/obank/0/ch/4/trim"] = faderVolume; 804 | doc_mul["ext/obank/0/ch/5/trim"] = faderVolume; 805 | doc_mul["ext/obank/0/ch/6/trim"] = faderVolume; 806 | doc_mul["ext/obank/0/ch/7/trim"] = faderVolume; 807 | doc_mul["ext/obank/0/ch/8/trim"] = faderVolume; 808 | doc_mul["ext/obank/0/ch/9/trim"] = faderVolume; 809 | doc_mul["ext/obank/0/ch/10/trim"] = faderVolume; 810 | doc_mul["ext/obank/0/ch/11/trim"] = faderVolume; 811 | doc_mul["ext/obank/0/ch/12/trim"] = faderVolume; 812 | doc_mul["ext/obank/0/ch/13/trim"] = faderVolume; 813 | doc_mul["ext/obank/0/ch/14/trim"] = faderVolume; 814 | doc_mul["ext/obank/0/ch/15/trim"] = faderVolume; 815 | doc_mul["ext/obank/0/ch/16/trim"] = faderVolume; 816 | doc_mul["ext/obank/0/ch/17/trim"] = faderVolume; 817 | doc_mul["ext/obank/0/ch/18/trim"] = faderVolume; 818 | doc_mul["ext/obank/0/ch/19/trim"] = faderVolume; 819 | doc_mul["ext/obank/0/ch/20/trim"] = faderVolume; 820 | doc_mul["ext/obank/0/ch/21/trim"] = faderVolume; 821 | doc_mul["ext/obank/0/ch/22/trim"] = faderVolume; 822 | doc_mul["ext/obank/0/ch/23/trim"] = faderVolume; 823 | 824 | 825 | for(int i=0;i