├── 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 | 
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