#include #include #include #include "gadgety.h" #include #include using namespace std; #define TIMESTEPS 80000 // 1 millisecond #define LINES_NUM 4 const unsigned LINE_PIN_MAP[] = { 13, 14, 12, 16 }; typedef unsigned int line_time_t; enum { EVENT_NOTEON, EVENT_NOTEOFF, EVENT_JUMP, EVENT_BARRIER, EVENT_ENVELOPE // Todo }; typedef struct { unsigned type; line_time_t time; unsigned tone; line_time_t new_cursor; unsigned lines_mask; } event_t; typedef struct { line_time_t cursor; // ADSR? Other line/synth parameters? list events; list::iterator next_event; } line_t; line_t lines[LINES_NUM]; void sequencer_init(void) { unsigned i; for(i = 0; i < LINES_NUM; ++i) { lines[i].cursor = 0; lines[i].next_event = lines[i].events.begin(); pinMode(LINE_PIN_MAP[i], OUTPUT); } } // Call every TIMESTEPS seconds void sequencer_main_loop(void) { unsigned i; line_time_t new_cursor; // Restart main loop timer timer0_write(ESP.getCycleCount() + TIMESTEPS); for(i = 0; i < LINES_NUM; ++i) { while(lines[i].next_event != lines[i].events.end() && lines[i].next_event->time == lines[i].cursor) { // Peform event: lines[i].next_event switch(lines[i].next_event->type) { case EVENT_NOTEON: digitalWrite(LINE_PIN_MAP[i], 1); ++lines[i].next_event; break; case EVENT_NOTEOFF: digitalWrite(LINE_PIN_MAP[i], 0); ++lines[i].next_event; break; case EVENT_JUMP: new_cursor = lines[i].cursor = lines[i].next_event->new_cursor; for(list::iterator it = lines[i].events.begin(); it != lines[i].events.end(); ++it) { if(it->time >= new_cursor) { lines[i].next_event = it; break; } } break; // Todo: tone, barrier, envelope } } if(lines[i].next_event != lines[i].events.end()) ++lines[i].cursor; } } const byte DNS_PORT = 53; ESP8266WebServer server(80); //Server on port 80 IPAddress myIP; //Get IP address DNSServer dnsServer; void serve_play(void) { unsigned lineno, t; event_t event; JsonArray::iterator it; const char *p; if(server.args() != 1) return; StaticJsonBuffer<512> jsonbuf; JsonObject &model = jsonbuf.parseObject(server.arg(0)); JsonArray &model_lines = model["lines"]; unsigned millis_per_slot = model["millis_per_slot"]; // Critical section noInterrupts(); for(lineno = 0; lineno < LINES_NUM; ++lineno) { lines[lineno].cursor = 0; lines[lineno].events.clear(); } for(it = model_lines.begin(), lineno = 0; it != model_lines.end() && lineno < LINES_NUM; ++it, ++lineno) { for(p = (const char*)(*it), t = 0; *p; ++p, ++t) { if(*p != '0') { event.type = EVENT_NOTEON; event.time = t * millis_per_slot; lines[lineno].events.push_back(event); event.type = EVENT_NOTEOFF; event.time += millis_per_slot / 2; lines[lineno].events.push_back(event); } } event.type = EVENT_JUMP; event.time = t * millis_per_slot; event.new_cursor = 0; lines[lineno].events.push_back(event); } for(lineno = 0; lineno < LINES_NUM; ++lineno) lines[lineno].next_event = lines[lineno].events.begin(); interrupts(); } void setup() { // Start sequencer sequencer_init(); // SPIFFS.begin(); Serial.begin(115200); //WiFi.mode(WIFI_AP); //Only Access point WiFi.softAP("Gadgety", "gadgety123"); //Start HOTspot removing password will disable security myIP = WiFi.softAPIP(); //Get IP address server.begin(); gadgety_static_init_server(&server); server.on("/play.ws", serve_play); dnsServer.start(DNS_PORT, "gadgety.com", myIP); noInterrupts(); timer0_isr_init(); timer0_attachInterrupt(sequencer_main_loop); timer0_write(ESP.getCycleCount() + TIMESTEPS); interrupts(); } void loop() { dnsServer.processNextRequest(); server.handleClient(); //Handle client requests if (server.arg(1)=="1") { Serial.print("Acceso"); } else if (server.arg(1)=="0") { Serial.print("Spento"); } }