bool doCommand(char *command) { // new commands always turn off immediate autoplay immediateAutoplayStop(); int length = strlen(command); if(length == 0) { return true; } char commandChar = toupper(command[0]); char *parameters = &command[1]; bool noParameters = length == 1; char firstParameterChar = noParameters ? '\0' : toupper(*parameters); Serial.println(command); Playlist *playlist = Playlists::currentPlaylist(); switch(commandChar) { case '+': // see also default at end of switch for making chirps without preceding with + if( ! noParameters) { return makeNewChirp(parameters); } break; case ']': case ')': if(noParameters) { Serial.println(F("next")); playlist->playAdjacent(1, commandChar == ')'); // ] wraps, ) chains } break; case '[': case '(': if(noParameters) { Serial.println(F("back")); playlist->playAdjacent(-1, commandChar == '('); // [ wraps, ( chains } break; case ',': if(noParameters) { Serial.println(F("step")); playlist->playSequenced(); } break; case '@': // select playlist by index number.. if(noParameters) { playlist->setPlayIndex(0); // ..or reset play index to 0 in current playlist } else { playlist = Playlists::usePlaylist(number(parameters, playlist->playlistIndex)); } break; case '}': case '{': if(noParameters) { playlist = Playlists::useAdjacentPlaylist(commandChar == '}' ? 1 : -1); } break; case '!': // play current or supplied code if(noParameters) { playlist->play(); } else if(isAChirpCode(parameters)) { playlist->playChirpCode(parameters); } else { playlist->playIndexed(number(parameters, playlist->playIndex)); } break; case '?': if(noParameters) { Serial.println(F("lookup")); return ! playerLink.fetchChirpContent(playlist); } break; case '~': // clearing Serial.println(F("clear")); if(noParameters) { playlist->clear(CLEAR_LIST); } else if(firstParameterChar == '#') { playlist->clear(CLEAR_SCRIPT_URL); } else if(strcmp(parameters, "!") == 0) { Playlists::clearAll(); } else { playlist->clear(number(parameters)); } break; case '.': // autoplay order & chirping interval if( ! noParameters && strchr("FBRS", firstParameterChar)) { playlist->setPlayOrder(firstParameterChar); parameters++; if(*parameters == '\0') { return true; } } playlist->setInterval(number(parameters, DEFAULT_INTERVAL)); break; case ':': // sound if( ! noParameters && strchr("PNM", firstParameterChar)) { if(firstParameterChar == 'M') { muted = ! muted; Serial.print(F("muting ")); Serial.println(muted ? F("on") : F("off")); } else { playlist->setPortamento(firstParameterChar == 'P'); } parameters++; if(*parameters == '\0') { return true; } } playlist->setVolume(number(parameters, DEFAULT_VOLUME)); // noParam form will set volume to default break; case '*': // autoplay if(noParameters) { Serial.println(F("autoplay now")); immediateAutoplayStart(); return false; // don't show prompt } else { doAutoplaySettingsCommand(playlist, parameters); } break; case '|': Serial.println(F("limit")); playlist->setAutoplayChirpLimit(number(parameters, PLAYLIST_CAPACITY)); break; case '^': // times Serial.println(F("time")); if(noParameters) { return ! playerLink.fetchTimeNow(); } else if(firstParameterChar == '-') { adjustTimeSeconds(-number(¶meters[1])); } else if(firstParameterChar == '+') { adjustTimeSeconds(number(¶meters[1])); } if(stringToSeconds(parameters)) { setTimeUTC(parameters); } break; case '#': // scripts if(noParameters) { if( ! playlist->requestUpdate()) { Serial.println(F("no script")); } } else { if(length == 2) { if(firstParameterChar == '?') { // #? to print current playlist in script format playlist->printAsScript(); } else { playlist->setUpdateFlags(number(parameters)); } } else { playlist->setScriptAddress(parameters); } } break; case '/': // run named script, or update all playlists with scripts Serial.println(F("run")); if(noParameters) { Playlists::updateAll(false); // false => not conditional on playlist flags } else { return ! playerLink.fetchScript(-1, parameters); // -1 signals is general script, not one for a particular playlist } break; case '=': // invoke trigger from the command line Trigger::trigger(parameters); break; case '-': inactivityTrigger.setWaitSeconds(number(parameters)); break; case '%': // comment line; ignore break; default: if(isAChirpCode(command)) { playlist->add(command); } else { Serial.println(F("uh?")); } break; } return true; }
void autoplayLoop() { static int32_t then; // now field from last time in loop int32_t now = timeNowSecondsSinceMidnight(); int16_t nowMinute = now / 60; // start any new autoplays if(nowMinute > then / 60 || autoplayNow) { // its a new minute; check the playlists to see if any due to start autoplaying this minute autoplayNow = false; for(int ix = 0; ix < N_PLAYLISTS; ix++) { Playlist *p = Playlists::playlist(ix); if(p->nChirps > 0 && p->autoplayCount == 0) { // only check if playlist has chirps and isn't already playing AutoplayStructure settings; p->getAutoplaySettings(&settings); int16_t startMinute = settings.startMinute; // run through all start times for playlist // doesn't play before initial start time and doesn't continue repeating past midnight for(uint8_t n = 0; n < settings.count && nowMinute >= startMinute && startMinute < minutesInOneDay; n++) { if(startMinute == nowMinute) { if(p->getUpdateFlags() & UPDATE_WHEN_AUTOPLAY) { p->requestUpdate(); } // setting non-zero count makes autoplay active p->autoplayCount = min(settings.maxChirps, p->nChirps); p->autoplayTimeSeconds = 0; // play as soon as possible break; } startMinute += settings.repeatMinutes; } } } } // autoplay up to one chirp per new second if(now > then) { // it's a new second // first check to see if current playlist is being autoplayed from the command line if(immediateAutoplayCount > 0 && now >= immediateAutoplayTimeSeconds) { Playlist *p = Playlists::currentPlaylist(); if(p->playSequenced()) { immediateAutoplayCount--; immediateAutoplayTimeSeconds = now + p->getInterval(); } else { // empty playlist: turn off immediateAutoplayCount = 0; } if(immediateAutoplayCount == 0) { showPrompt(); } } else { // check any timed autoplaying playlists for any due to play now for(int ix = 0; ix < N_PLAYLISTS; ix++) { Playlist *p = Playlists::playlist(ix); if(p->autoplayCount > 0 && now >= p->autoplayTimeSeconds && p->awaitingUpdate == NOT_AWAITING_UPDATE) { if(p->playSequenced()) { p->autoplayCount--; p->autoplayTimeSeconds = now + p->getInterval(); break; // only one play per vsit to this function } else { p->autoplayCount = 0; // empty playlist (shouldn't happen here) } } } } } then = now; }