void mainLoop (void) { unsigned int getCurVoltageSample(); CtnrBlock *insertBlock; ListItem *list; int inactivityCheckCounter = 0; while(1) { // check if need to load in a new package if (context.queuedPackageType > PKG_NONE) { if (context.queuedPackageNameIndex != -1) loadPackage(context.queuedPackageType, pkgSystem.strHeapStack + context.queuedPackageNameIndex); else loadPackage(context.queuedPackageType, NULL); } // check for start or end event // todo: do we have to check SACM_Status() to see if stopped or can that be moved into the start/end event processing? if (SACM_Status() && !context.isPaused && compressTime(Snd_A1800_GetCurrentTime(),context.package->timePrecision) >= context.timeNextTimeframe) endOfTimeframe(context.idxTimeframe, FALSE); else if (!context.isStopped && !SACM_Status()) { // just stopped playing // this assume that stopped means end of audio file // todo: this should be checking end action for CtnrFile (doesn't exist yet) context.isStopped = TRUE; turnAmpOff(); markEndPlay(getRTCinSeconds()); flushLog(); if (GREEN_LED_WHEN_PLAYING) { setLED(LED_GREEN,FALSE); setLED(LED_RED,FALSE); } if (context.idxActiveList == -1) endOfTimeframe(context.idxTimeframe, TRUE); else { //process any end of play sound-insert //TODO: work this into other code; it's a bit of a one-off right now list = &context.package->lists[context.idxActiveList]; insertBlock = getEndInsert(list->actionStartEnd, list->idxFirstAction); if (insertBlock) insertSound(getFileFromBlock(insertBlock),insertBlock,FALSE); } if (context.package->pkg_type == PKG_MSG) { insertSound(&pkgSystem.files[POST_PLAY_FILE_IDX],NULL,FALSE); } } if (++inactivityCheckCounter > 10) { checkInactivity(!context.isStopped && !context.isPaused); inactivityCheckCounter = 0; if(vCur_1 < V_MIN_RUN_VOLTAGE) { refuse_lowvoltage(1); // not reached } } keyResponse(); } // end of while(1) loop }
void resetSystem(void) { // set watchdog timer to reset device; 0x780A (Watchdog Reset Control Register) // see GPL Programmer's Manual (V1.0 Dec 20,2006), Section 3.5, page 18 checkVoltage(); // USB may have been supplying sole power -- need to check if voltage dropping fast stop(); if (PLEASE_WAIT_IDX && context.package) { // prevents trying to insert this sound before config & control files are loaded. insertSound(&pkgSystem.files[PLEASE_WAIT_IDX],NULL,TRUE); } checkVoltage(); // USB may have been supplying sole power -- need to check if voltage dropping fast saveVolumeProfile(); logString((char *)"* RESET *",ASAP,LOG_ALWAYS); saveLogFile(0); fs_safexit(); // should close all open files disk_safe_exit(0); // try to get the sd card in a safe state - reverse what we do on startup _deviceunmount(0); fs_uninit(); SD_Uninitial(); turnSDoff(); playBip(); setLED(LED_ALL,FALSE); *P_WatchDog_Ctrl &= ~0x4001; // clear bits 14 and 0 for resetting system and time=0.125 sec *P_WatchDog_Ctrl |= 0x8004; // set bits 2 and 15 for 0.125 sec, system reset, and enable watchdog while(1); }
void resetSystem(void) { // set watchdog timer to reset device; 0x780A (Watchdog Reset Control Register) // see GPL Programmer's Manual (V1.0 Dec 20,2006), Section 3.5, page 18 stop(); if (PLEASE_WAIT_IDX && context.package) { // prevents trying to insert this sound before config & control files are loaded. insertSound(&pkgSystem.files[PLEASE_WAIT_IDX],NULL,TRUE); } playBip(); setLED(LED_ALL,FALSE); logString((char *)"* RESET *",ASAP,LOG_ALWAYS); fs_safexit(); // should close all open files *P_WatchDog_Ctrl &= ~0x4001; // clear bits 14 and 0 for resetting system and time=0.125 sec *P_WatchDog_Ctrl |= 0x8004; // set bits 2 and 15 for 0.125 sec, system reset, and enable watchdog while(1); }
static void processStartBlock(int idxBlock) { EnumAction actionCode; int idxAction; CtnrBlock *block, *insertBlock; block = &context.package->blocks[idxBlock]; insertBlock = getStartInsert(block->actionStartEnd, block->idxFirstAction); if (insertBlock) insertSound(getFileFromBlock(insertBlock),insertBlock,FALSE); actionCode = getStartCode(block,&idxAction,STARTING); if (idxAction >= 0) takeAction(&context.package->actions[idxAction],actionCode); else takeAction(NULL,actionCode); }
static EnumAction processEndBlock(int idxBlock) { // This fct checks for a sound insert and calls block's end action. // It returns the actionCode that was processed and calls TakeAction() if not continue. EnumAction actionCode; int idxAction; CtnrBlock *block, *insertBlock; block = &context.package->blocks[idxBlock]; insertBlock = getEndInsert(block->actionStartEnd, block->idxFirstAction); if (insertBlock) insertSound(getFileFromBlock(insertBlock),insertBlock,FALSE); actionCode = getEndCode(block,&idxAction,PLAYING); if (actionCode != NOP) { if (actionCode == PAUSE) context.idxPausedOnBorder = idxBlock; if (idxAction >= 0) takeAction(&context.package->actions[idxAction],actionCode); else takeAction(NULL,actionCode); } return actionCode; }
static int recordAudio(char *pkgName, char *cursor, BOOL relatedToLastPlayed) { unsigned long getAvailRand(); int handle, ret = -1; char temp[PATH_LENGTH]; char filepath[PATH_LENGTH]; char unique_id[PATH_LENGTH], digits[16]; long start, end, prev; CtnrFile *file; int key; int low_voltage, v; unsigned long wrk1; char *cp, *cp1, category[9]; long metadata_start; long metadata_numfields; unsigned long rand1; long previousBitRate; previousBitRate = BIT_RATE; // set to return BIT_RATE to orig value at end of fct, in case BIT_RATE is changed below rand1 = getAvailRand(); // pick random value to identify this recording unsignedlongToHexString((long)rand1,digits); if (strcmp(cursor,TRANSLATE_TEMP_DIR) == 0) { strcpy(filepath,LANGUAGES_PATH); strcat(filepath,TRANSLATE_TEMP_DIR); strcat(filepath,"/"); strcat(filepath,pkgName); strcat(filepath,AUDIO_FILE_EXT); BIT_RATE = MAX_BIT_RATE; } else if (*cursor == SYS_MSG_CHAR) { strcpy(filepath,LANGUAGES_PATH); catLangDir(filepath); // strcat(filepath,pkgName); cp1 = filepath + strlen(filepath); // save this position strcat(filepath, (char *)TB_SERIAL_NUMBER_ADDR + CONST_TB_SERIAL_PREFIX_LEN); strcat(filepath, "_"); strcat(filepath, digits); strcpy(pkgName, cp1); // change pkgName to show file name we used strcat(filepath,AUDIO_FILE_EXT); } else { strcpy(filepath,USER_PATH); // strcat(filepath,pkgName); cp1 = filepath + strlen(filepath); // save this position strcat(filepath, (char *)TB_SERIAL_NUMBER_ADDR + CONST_TB_SERIAL_PREFIX_LEN); strcat(filepath, "_"); strcat(filepath, digits); strcpy(pkgName, cp1); // change pkgName to show file name we used strcat(filepath,AUDIO_FILE_EXT); } file = getTempFileFromName(cursor,0); if (strcmp(cursor,TRANSLATE_TEMP_DIR) != 0) insertSound(file,NULL,FALSE); if (context.keystroke == KEY_HOME) { //let context.keystroke propogate through ret = 1; // signals no audio recorded but not necessary to throw exception } else { start = getRTCinSeconds(); strcpy(temp,"\x0d\x0a"); longToDecimalString(start,temp+2,8); strcat(temp,(const char *)": RECORD "); LBstrncat(temp,pkgName,60); LBstrncat(temp," -> ",60); LBstrncat(temp,cursor,60); logString(temp,BUFFER); // play record prompt message unless running translation app or if a button was just pressed if (!context.keystroke && strcmp(cursor,TRANSLATE_TEMP_DIR) != 0) { insertSound(&pkgSystem.files[SPEAK_SOUND_FILE_IDX],NULL,FALSE); if (context.keystroke == KEY_HOME) ret = 1; // signals no audio recorded but not necessary to throw exception else context.keystroke = 0; } else context.keystroke = 0; // reset context.keystroke so a second action doesn't take place stop(); start = getRTCinSeconds(); prev = end = start; //asm("INT OFF"); // to prevent recordings with bad blocks } // only open file to record if HOME was not pressed and only proceed if file opens correctly if (ret != 1 && ((handle = tbOpen((LPSTR)filepath,O_CREAT|O_RDWR)) != -1)) { setLED(LED_RED,TRUE); playBip(); turnAmpOff(); Snd_SACM_RecFAT(handle, C_CODEC_AUDIO1800, BIT_RATE); low_voltage = 0; do { end = getRTCinSeconds(); if (0==(end%2) && (prev != end)) { // blink LED every three seconds prev = end; setLED(LED_RED,FALSE); wait (100); setLED(LED_RED,TRUE); while((v = getCurVoltageSample()) == 0xffff); if(vCur_1 < V_MIN_SDWRITE_VOLTAGE) { low_voltage = 1; } } key = keyCheck(0); if (key == KEY_PLAY) { // pause TODO: this key press to pause shouldn't be hard coded pause(); setLED(LED_RED,FALSE); // insertSound(&pkgSystem.files[REC_PAUSED_FILE_IDX],NULL,FALSE); ---need to play this from memory do key = keyCheck(0); // TODO: NEED CODE HERE TO SAFELY SAVE FILE WHEN PAUSED FOR EXTENDED PERIOD OF TIME (maybe 60 min?) // checkInactivity(key); --- this would cause recording to be lost in just 30-300 sec inactivity while (!key); if (key == KEY_PLAY) { setLED(LED_RED,TRUE); resume(); } } } while ((!key || (key == KEY_PLAY)) && (low_voltage == 0)); // TODO: this key press to stop shouldn't be hard coded // while ((end - start) < 3) { // must be at least 2.0 second recording // end = getRTCinSeconds(); // } SACM_Stop(); //Snd_Stop(); // no need to call stop() and flush the log setLED(LED_RED,FALSE); turnAmpOn(); playDing(); //lseek(handle, 6, SEEK_SET ); //Seek to the start of the file input //write(handle,(LPSTR)header<<1,6); // write meta data to end of file close(handle); // rhm: I think its already closed, I can't write to it here systemCounts.recordingNumber++; // bump global recording number saveSystemCounts(); handle = tbOpen((LPSTR)filepath,O_RDWR); metadata_start = lseek(handle, 0L, SEEK_END); // offset to start of metadata metadata_numfields = 0L; // init num fields wrk1 = METADATA_VERSION; writeLE32(handle, wrk1, CURRENT_POS); //meta data version = 1 writeLE32(handle, metadata_numfields, CURRENT_POS); // 4 byte for num fields strcpy(unique_id, (char *)TB_SERIAL_NUMBER_ADDR + CONST_TB_SERIAL_PREFIX_LEN); // skip serial number prefix strcat(unique_id, "_"); strcat(unique_id, digits); addField(handle, DC_IDENTIFIER, unique_id, 1); metadata_numfields += 1; addField(handle, DTB_REVISION, (char *)"0", 1); metadata_numfields += 1; strcpy(unique_id, (char *)TB_SERIAL_NUMBER_ADDR + CONST_TB_SERIAL_PREFIX_LEN); // skip serial number prefix strcat(unique_id, "_"); longToDecimalString(systemCounts.powerUpNumber,(char *)temp,4); strcat(unique_id, temp); strcat(unique_id, "_"); longToDecimalString(systemCounts.recordingNumber,(char *)temp,4); strcat(unique_id, temp); strcat(unique_id, "_"); strncat(unique_id, digits, 8); addField(handle, DC_TITLE, unique_id, 1); metadata_numfields += 1; // strcpy(unique_id, (char *)TB_SERIAL_NUMBER_ADDR + CONST_TB_SERIAL_PREFIX_LEN); // skip serial number prefix // strcat(unique_id, "_"); // strcat(unique_id, digits); // addField(handle, DC_AUDIO_ITEM_ID, unique_id, 1); // metadata_numfields += 1; if (pkgSystem.idxLanguageCode != -1) { strcpy(unique_id,&pkgSystem.strHeapStack[pkgSystem.idxLanguageCode]); addField(handle, DC_LANGUAGE, unique_id, 1); metadata_numfields += 1; } cp = cursor; if(cp != NULL) { if(*cp >= '0' && *cp <= '9') { strcpy(category, cursor); } else if(!strncmp(cp, "AGR", 3)) strcpy(category, CAT_AGRICULTURE); else if(!strncmp(cp, "HEA", 3)) strcpy(category, CAT_HEALTH); else if(!strncmp(cp, "EDU", 3)) strcpy(category, CAT_EDUCATION); else if(!strncmp(cp, "STO", 3)) strcpy(category, CAT_STORIES); else if(!strncmp(cp, "BUS", 3)) strcpy(category, CAT_BUSINESS); else if(!strncmp(cp, "GOV", 3)) strcpy(category, CAT_GOVERNANCE); else if(!strncmp(cp, "MUS", 3)) strcpy(category, CAT_MUSIC); else if(!strncmp(cp, "DIA", 3)) strcpy(category, CAT_DIARY); else strcpy(category, CAT_OTHER); } addField(handle, DC_CATEGORY, category, 1); metadata_numfields += 1; if(relatedToLastPlayed) { strcpy(unique_id, STAT_FN); // DC_IDENTIFIER read at open if(strlen(unique_id)) { addField(handle,DC_RELATION,unique_id,1); metadata_numfields += 1; } } strcpy(unique_id, (char *)TB_SERIAL_NUMBER_ADDR + CONST_TB_SERIAL_PREFIX_LEN); // skip serial number prefix addField(handle,DC_SOURCE,unique_id,1); metadata_numfields += 1; longToDecimalString(systemCounts.powerUpNumber,(char *)temp,4); addField(handle,DC_DATE,temp,1); metadata_numfields += 1; // add other fields here writeLE32(handle, metadata_numfields, metadata_start + 4); // write correct num meta data fields close(handle); // done with meta data //asm("INT FIQ, IRQ"); -- see INT OFF above used once to prevent corrupted recordings (now possibly handled by SD_Initial() after USB Device mode // *P_WatchDog_Ctrl &= ~0x8000; // clear bit 15 to disable if (strcmp(cursor,TRANSLATE_TEMP_DIR) != 0) { insertSound(&pkgSystem.files[POST_REC_FILE_IDX],NULL,FALSE); if (!context.keystroke) insertSound(file,NULL,FALSE); // replay subject } // Leaving this out now, because I believe it gets created when it is first played if non-existent. // The delay of having it in recordAudio is too long. // createStatsFile(rand1); // Assumes no name collision from using a 32-bit semi-random number // Checking all past names was causing a long delay, but maybe (TODO:) we can // add in a check if the open() fails and then generate a new number in that unlikely case strcpy(temp,"TIME RECORDED (secs): "); longToDecimalString((long)end-start,temp+strlen(temp),4); strcat(temp,"\x0d\x0a"); logString(temp,BUFFER); //logString(temp,ASAP); ret = 0; // used to set this based on fileExists() check, but too slow } else if (ret == -1) { logException(16, filepath,RESET); //can't open file for new recording } BIT_RATE = previousBitRate; return ret; }
void insertSoundFile(int idxFile) { insertSound(&pkgSystem.files[idxFile],NULL,FALSE); }
SoundID Audio::addSound(const char *fileName, unsigned int flags){ Sound sound; // Clear error flag alGetError(); const char *ext = strrchr(fileName, '.') + 1; char str[256]; if (stricmp(ext, "ogg") == 0){ FILE *file = fopen(fileName, "rb"); if (file == NULL){ sprintf(str, "Couldn't open \"%s\"", fileName); ErrorMsg(str); return SOUND_NONE; } OggVorbis_File vf; memset(&vf, 0, sizeof(vf)); if (ov_open(file, &vf, NULL, 0) < 0){ fclose(file); sprintf(str, "\"%s\" is not an ogg file", fileName); ErrorMsg(str); return SOUND_NONE; } vorbis_info *vi = ov_info(&vf, -1); int nSamples = (uint) ov_pcm_total(&vf, -1); int nChannels = vi->channels; sound.format = nChannels == 1? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; sound.sampleRate = vi->rate; sound.size = nSamples * nChannels; sound.samples = new short[sound.size]; sound.size *= sizeof(short); int samplePos = 0; while (samplePos < sound.size){ char *dest = ((char *) sound.samples) + samplePos; int bitStream, readBytes = ov_read(&vf, dest, sound.size - samplePos, 0, 2, 1, &bitStream); if (readBytes <= 0) break; samplePos += readBytes; } ov_clear(&vf); } else { ALboolean al_bool; ALvoid *data; alutLoadWAVFile(fileName, &sound.format, &data, &sound.size, &sound.sampleRate, &al_bool); sound.samples = (short *) data; } alGenBuffers(1, &sound.buffer); alBufferData(sound.buffer, sound.format, sound.samples, sound.size, sound.sampleRate); if (alGetError() != AL_NO_ERROR){ alDeleteBuffers(1, &sound.buffer); sprintf(str, "Couldn't open \"%s\"", fileName); ErrorMsg(str); return SOUND_NONE; } return insertSound(sound); }
static int recordAudio(char *pkgName, char *cursor) { int handle, ret = -1; char temp[PATH_LENGTH]; char filepath[PATH_LENGTH]; long start, end, prev; CtnrFile *file; int key; strcpy(filepath,USER_PATH); strcat(filepath,pkgName); strcat(filepath,AUDIO_FILE_EXT); file = getListFile(cursor); insertSound(file,NULL,TRUE); start = getRTCinSeconds(); strcpy(temp,"\x0d\x0a"); longToDecimalString(start,temp+2,5); strcat(temp,(const char *)": RECORD "); LBstrncat(temp,pkgName,60); LBstrncat(temp," -> ",60); LBstrncat(temp,cursor,60); logString(temp,BUFFER); insertSound(&pkgSystem.files[SPEAK_SOUND_FILE_IDX],NULL,TRUE); stop(); start = getRTCinSeconds(); prev = end = start; handle = tbOpen((LPSTR)filepath,O_CREAT|O_RDWR); if (handle != -1) { setLED(LED_RED,TRUE); playBip(); while (SACM_Status()); Snd_SACM_RecFAT(handle, C_CODEC_AUDIO1800, BIT_RATE); do { end = getRTCinSeconds(); if (0==(end%2) && (prev != end)) { // blink LED every three seconds prev = end; setLED(LED_RED,FALSE); wait (100); setLED(LED_RED,TRUE); } key = keyCheck(0); if (key == KEY_PLAY) { // pause TODO: this key press to pause shouldn't be hard coded SACM_Pause(); setLED(LED_RED,FALSE); do key = keyCheck(0); while (key != KEY_PLAY && key != KEY_STAR); setLED(LED_RED,TRUE); SACM_Resume(); } } while (key != KEY_STAR); // TODO: this key press to stop shouldn't be hard coded // while ((end - start) < 3) { // must be at least 2.0 second recording // end = getRTCinSeconds(); // } SACM_Stop(); //Snd_Stop(); // no need to call stop() and flush the log //lseek(handle, 6, SEEK_SET ); //Seek to the start of the file input //write(handle,(LPSTR)header<<1,6); close(handle); // *P_WatchDog_Ctrl &= ~0x8000; // clear bit 15 to disable setLED(LED_RED,FALSE); insertSound(&pkgSystem.files[BEEP_SOUND_FILE_IDX],NULL,TRUE); insertSound(file,NULL,TRUE); // replay subject strcpy(temp,"TIME RECORDED (secs): "); longToDecimalString((long)end-start,temp+strlen(temp),4); strcat(temp,"\x0d\x0a"); logString(temp,BUFFER); strcpy(lastFilenameRecorded,filepath); ret = 0; // used to set this based on fileExists() check, but too slow } else { logException(16, filepath,RESET); //can't open file for new recording } return ret; }
static void takeAction (Action *action, EnumAction actionCode) { unsigned int newTime, oldTime; unsigned long longNewTime, longOldTime; int newIdxTimeframe, tempTime; CtnrFile *newFile; CtnrBlock *newBlock, *soundInsertBlock; int newIdxAction; EnumAction newActionCode; EnumBorderCrossing direction; signed long l; int destination, aux, i, ret; int status; BOOL reposition = FALSE; BOOL isTooFar = FALSE; ListItem *list, *tempList; char filename[PATH_LENGTH]; char *cursor, *cursor2; CtnrFile *replayFile; replayFile = NULL; list = NULL; oldTime = compressTime(Snd_A1800_GetCurrentTime(),context.package->timePrecision); newFile = 0; newTime = -1; newBlock = 0; if (actionCode == -1) actionCode = getActionCode(action); if (action) { aux = action->aux; destination = action->destination; } switch (actionCode) { case JUMP_LIST: stop(); list = &context.package->lists[destination]; context.idxActiveList = destination; switch (getListRotation(aux)) { case 0: cursor = getCurrentList(list); strcpy(filename,cursor); break; case 1: strcpy(filename,getNextList(list,TRUE)); break; case -1: strcpy(filename,getPreviousList(list)); break; } if (!filename[0]) { // empty list insertSound(&pkgSystem.files[EMPTY_LIST_FILE_IDX],NULL,FALSE); // empty list of packages; redirect to current point in list of lists list = &context.package->lists[0]; context.idxActiveList = 0; cursor = getCurrentList(list); strcpy(filename,cursor); } if (list->listType == LIST_OF_PACKAGES) { // load package switch (filename[0]) { case SYS_PKG_CHAR: context.queuedPackageType = PKG_SYS; destination = replaceStack(filename+1,&pkgSystem); break; case APP_PKG_CHAR: context.queuedPackageType = PKG_APP; destination = replaceStack(filename+1,&pkgSystem); break; default: context.queuedPackageType = PKG_MSG; destination = replaceStack(filename,&pkgSystem); break; } context.queuedPackageNameIndex = destination; } else { // list->listType != LIST_OF_PACKAGES // play sound of subject newFile = getListFile(filename); newTime = 0; reposition = TRUE; } break; case JUMP_PACKAGE: if (aux == PKG_VARIABLE) { strcpy(filename,getCurrentList(&pkgSystem.lists[destination])); switch (filename[0]) { case SYS_PKG_CHAR: aux = PKG_SYS; destination = replaceStack(filename+1,&pkgSystem); break; case APP_PKG_CHAR: aux = PKG_APP; destination = replaceStack(filename+1,&pkgSystem); break; default: aux = PKG_MSG; destination = replaceStack(filename,&pkgSystem); break; } } context.queuedPackageType = aux; context.queuedPackageNameIndex = destination; break; // sets up main loop to handle this, rather than building up a stack overflow case COPY: stop(); tempList = &context.package->lists[destination]; getListFilename(filename,destination,FALSE); cursor = getCurrentList(tempList); if (PRE_COPY_FILE_IDX) insertSound(&pkgSystem.files[PRE_COPY_FILE_IDX],NULL,TRUE); ret = d2dCopy((const char *)filename,(const char *)cursor); if (ret == 0 && POST_COPY_FILE_IDX) insertSound(&pkgSystem.files[POST_COPY_FILE_IDX],NULL,TRUE); // newBlock = &context.package->blocks[aux]; // newTime = newBlock->startTime; // reposition = TRUE; break; case DELETE: stop(); tempList = &context.package->lists[destination]; getListFilename(filename,destination,TRUE); cursor = getCurrentList(tempList); ret = findDeleteStringFromFile(LIST_PATH,filename,cursor,TRUE); tempList->currentFilePosition = -1; // forces next list action to reload if (ret != -1) ret = deletePackage(cursor); else logException(29,cursor,0); list = &context.package->lists[aux]; context.idxActiveList = aux; newFile = getListFile(getCurrentList(list)); newTime = 0; reposition = TRUE; // newBlock = &context.package->blocks[aux]; // newTime = newBlock->startTime; // reposition = TRUE; break; case TRIM: stop(); tempList = &context.package->lists[destination]; cursor = getCurrentList(tempList); strcpy(filename,USER_PATH); strcat(filename,cursor); //todo: address application packages strcat(filename,AUDIO_FILE_EXT); edit(filename); context.queuedPackageType = PKG_MSG; destination = replaceStack(cursor,context.package); context.queuedPackageNameIndex = destination; break; case SPEED_UP: adjustSpeed(SPEED_INCREMENT,TRUE); break; case SPEED_DOWN: adjustSpeed(-SPEED_INCREMENT,TRUE); break; case SPEED_NORMAL: adjustSpeed(NORMAL_SPEED,FALSE); break; case VOLUME_UP: adjustVolume(VOLUME_INCREMENT,TRUE,FALSE); break; case VOLUME_DOWN: adjustVolume(-VOLUME_INCREMENT,TRUE,FALSE); break; case VOLUME_NORMAL: adjustVolume(NORMAL_VOLUME,FALSE,FALSE); break; case LED_RED_ON: setLED(LED_RED,TRUE); break; case LED_RED_OFF: setLED(LED_RED,FALSE); break; case LED_GREEN_ON: setLED(LED_GREEN,TRUE); break; case LED_GREEN_OFF: setLED(LED_GREEN,FALSE); break; case LED_ALL_ON: setLED(LED_ALL,TRUE); break; case LED_ALL_OFF: setLED(LED_ALL,TRUE); break; case USB_DEVICE_ON: setUSBDevice(TRUE); newBlock = &context.package->blocks[destination]; newTime = newBlock->startTime; reposition = TRUE; break; case USB_HOST_ON: /* stop(); setUSBDevice(TRUE); newBlock = &context.package->blocks[destination]; newTime = newBlock->startTime; reposition = TRUE; */ break; case STOP: stop(); enterOrExitAllBlocks(context.idxTimeframe,EXITING); break; case PLAY_PAUSE: status = SACM_Status(); switch (status) { case 0: // if (context.package->pkg_type != PKG_SYS) markStartPlay(Snd_A1800_GetCurrentTime(),context.package->strHeapStack+context.package->idxName); if (context.idxActiveList == -1) { enterOrExitAllBlocks(context.idxTimeframe,ENTERING); i = getStartingBlockIdxFromTimeline(context.idxTimeframe); if (i != -1) processStartBlock(i); play(context.file,getCurrentTimeframeStart()); } else play(context.file,0); break; case C_SACM_RECORD: case C_SACM_PLAY: context.isPaused = TRUE; pause(); break; case C_SACM_PAUSE: context.isPaused = FALSE; resume(); break; default: if (context.isPaused) { context.isPaused = FALSE; resume(); } else { context.isPaused = TRUE; pause(); } break; } break; case PAUSE: pause(); context.isPaused = TRUE; break; case RECORD_TITLE: // deprecated case RECORD_MSG: stop(); /* // Not currently allowing sound inserts before record commands since aux is used for recording from another headphone jack // Although the SPINS part of the headphone jack thing isn't currently working. if (action && hasSoundInsert(action)) { soundInsertBlock = &pkgSystem.blocks[getSoundInsertIdxFromAux(aux)]; insertSound(getFileFromBlock(soundInsertBlock),soundInsertBlock,TRUE); wait(500); } */ if(vCur_1 < V_MIN_RECORD_VOLTAGE) { refuse_lowvoltage(0); break; } cursor = getCurrentList(&pkgSystem.lists[context.package->idxMasterList]); do { strcpy(filename,USER_PATH); getPkgNumber(filename+strlen(USER_PATH),TRUE); strcat(filename,(const char *)CATEGORY_DELIM_STR); strcat(filename,cursor); // adds current listname to new recording name cursor2 = filename + strlen(filename); strcat(filename,AUDIO_FILE_EXT); ret = fileExists((LPSTR)filename); // this causes approx 1 sec delay! } while (ret); *cursor2 = 0; // remove extension strcpy(filename,filename+strlen(USER_PATH)); //remove path ret = createRecording(filename,aux,cursor); if (ret != -1) { destination = replaceStack(filename,context.package); context.queuedPackageNameIndex = destination; context.queuedPackageType = PKG_MSG; } else logException(28,"recording failed",RESET); //todo: add voice error msg? break; case CALL_BLOCK: // TODO: handle error (return of -1) if stack is full stackPush(context.package,context.file,oldTime - getRewind(aux)); // times are compressed // this is designed to fall through case JUMP_BLOCK: newBlock = &context.package->blocks[destination]; newTime = newBlock->startTime; reposition = TRUE; break; case RETURN: if (stackPop(&context.package,&newFile,&newTime)) // times are compressed reposition = TRUE; break; case FWD: newActionCode = getStartEndCodeFromTimeframe(context.idxTimeframe,FORWARD_JUMPING, &newTime, &newIdxAction); switch (newActionCode) { case NOP: case PAUSE: break; case STOP: //rewind to give context before stopping newTime -= compressTime(BLOCK_END_LEADER,context.package->timePrecision); break; case JUMP_BLOCK: //follow this link newBlock = &context.package->blocks[context.package->actions[newIdxAction].destination]; newTime = newBlock->startTime; break; case RETURN: stackPop(&context.package,&newFile,&newTime); //todo: double verify there was something on stack (shouldn't have gotten RETURN if not) break; default: //no action needed break; } reposition = TRUE; break; case BACK: // test whether within the start leader to determine whether to go to last start or to previous start before that if ((oldTime - getCurrentTimeframeStart()) > compressTime(BLOCK_START_LEADER, context.package->timePrecision)) { // just move to start time of same timeframe newTime = getCurrentTimeframeStart(); // must make sure we call the Start event } else { newActionCode = getStartEndCodeFromTimeframe(context.idxTimeframe,BACKWARD_JUMPING, &newTime, &newIdxAction); switch (newActionCode) { case NOP: case PAUSE: case STOP: break; case JUMP_BLOCK: //follow this link newBlock = &context.package->blocks[context.package->actions[newIdxAction].destination]; newTime = newBlock->startTime; break; case RETURN: stackPop(&context.package,&newFile,&newTime); //todo: double verify there was something on stack (shouldn't have gotten RETURN if not) break; default: //no action needed break; } } reposition = TRUE; break; case JUMP_TIME: // skip forward/back from relative position // observe block boundary when they exist, but leap beyond them // todo:do not leap over newFile boundaries // if system package action, reset context to user package for this action if (context.returnPackage) context.package = context.returnPackage; if (context.package != &pkgSystem) { longOldTime = Snd_A1800_GetCurrentTime(); l = (signed long)extractSignedTime(destination,context.package->timePrecision); // hoping this brings back an originally negative number longNewTime = longOldTime + l; if (l >= 0) direction = FORWARD_JUMPING; else { direction = BACKWARD_JUMPING; if (abs(l) > longOldTime) longNewTime = 0; } newTime = compressTime(longNewTime,context.package->timePrecision); // check for interfering block events newIdxTimeframe = context.idxTimeframe; do { newActionCode = getStartEndCodeFromTimeframe(newIdxTimeframe,direction, &tempTime, &newIdxAction); if (direction == FORWARD_JUMPING) isTooFar = blockTimeline[++newIdxTimeframe].time > newTime; else isTooFar = blockTimeline[--newIdxTimeframe].time < newTime; } while (!isTooFar && newActionCode == NOP); switch (newActionCode) { case JUMP_BLOCK: newBlock = &context.package->blocks[context.package->actions[newIdxAction].destination]; newTime = newBlock->startTime; newFile = getFileFromBlock(newBlock); break; case RETURN: stackPop(&context.package,&newFile,&newTime); //todo: double verify there was something on stack (shouldn't have gotten RETURN if not) break; default: //no action needed break; } playActionSound(JUMP_TIME); reposition = TRUE; } // context is not system file break; case SLEEP: // call sleep function setOperationalMode((int)P_SLEEP); break; case HALT: // call sleep function setOperationalMode((int)P_HALT); break; case NOP: // no operation break; default: //nothing should default here logException(1,0,USB_MODE); break; } if (reposition) { //todo: am i catching every possible change in file? if (newBlock && !newFile) newFile = getFileFromBlock(newBlock); if (newFile && newFile != context.file) { enterOrExitAllBlocks(context.idxTimeframe,EXITING); context.file = newFile; if (!list) buildBlockTimelines(newFile); context.idxTimeframe = -1; // to signal it hasn't been set yet context.timeNextTimeframe = -1; // resets this -- necessary for lists that dont go to processTimelineJump } if (!list) { context.idxActiveList = -1; newIdxTimeframe = getIdxTimeline(newTime); if (newIdxTimeframe != context.idxTimeframe) processTimelineJump(context.idxTimeframe, newIdxTimeframe); // this resets context.idxTimeframe and context.timeNextTimeframe } } // now that context.idxTimeframe has been set for repositions, we can insert sounds if (action && hasSoundInsert(action)) { if (reposition) stop(); // stop currently playing audio first or insertSound() will return to it if (actionCode == JUMP_TIME) { if (context.returnPackage) context.package = &pkgSystem; soundInsertBlock = &context.package->blocks[getSoundInsertIdxFromAux(aux)]; insertSound(getFileFromBlock(soundInsertBlock),soundInsertBlock,TRUE); } else { soundInsertBlock = &context.package->blocks[getSoundInsertIdxFromAux(aux)]; insertSound(getFileFromBlock(soundInsertBlock),soundInsertBlock,FALSE); } } // process start block action if landing on the start of a new block if (reposition && newBlock && newTime == newBlock->startTime) processStartBlock(newBlock - context.package->blocks); if (list) { soundInsertBlock = getStartInsert(list->actionStartEnd, list->idxFirstAction); if (soundInsertBlock) insertSound(getFileFromBlock(soundInsertBlock),soundInsertBlock,FALSE); } if (actionCode == JUMP_TIME && context.returnPackage) { // returning to user package after possibly inserting a system sound above context.package = context.returnPackage; context.returnPackage = NULL; } if (actionCode == SPEED_UP || actionCode == SPEED_DOWN) { context.isPaused = FALSE; resume(); } if (reposition) play(context.file,newTime); //todo: chg to seek if same file //todo: maybe for JUMP_BLOCK (not CALL_BLOCK) , allow offsets within a block (stored in first 13 bits of aux) }
static void processBlockEnterExit (CtnrBlock *block, EnumEnterOrExit enteringOrExiting) { unsigned int code, LEDhyperlink, speedChange, volumeChange; BOOL red, green, onoff, fliponoff; APP_IRAM static unsigned int enteringVolume; code = block->actionEnterExit; if (enteringOrExiting == ENTERING) { code &= 0x00FF; enteringVolume = getVolume(); } else { if (context.isHyperlinked && ((code & 0x00FF) == 0x04)) { // checks if enter action was hyperlink context.isHyperlinked = FALSE; setLED(LED_RED,FALSE); } code >>= 8; } if (code) { LEDhyperlink = code & 0x0F; // bits 0-3 speedChange = (code & 0x30) >> 4; // bits 4-5 volumeChange = (code & 0xC0) >> 6; // bits 6-7 switch (speedChange) { case 0x01: adjustSpeed(3,TRUE); break; case 0x02: adjustSpeed(-3,TRUE); break; case 0x03: adjustSpeed(NORMAL_SPEED,FALSE); break; } switch (volumeChange) { case 0x01: adjustVolume(3,TRUE,TRUE); break; case 0x02: adjustVolume(-3,TRUE,TRUE); break; case 0x03: //return to user selected volume restoreVolume(FALSE); break; } // switch if (LEDhyperlink == 0x04) { if (enteringOrExiting == ENTERING) { context.isHyperlinked = TRUE; context.USB = FALSE; setLED(LED_RED,TRUE); insertSound(&pkgSystem.files[HYPERLINK_SOUND_FILE_IDX],NULL,TRUE); } else { context.isHyperlinked = FALSE; setLED(LED_RED,FALSE); } } else { if (LEDhyperlink == 0x08) { context.USB = TRUE; stop(); setUSBDevice(TRUE); } else { green = LEDhyperlink & 0x01; red = LEDhyperlink & 0x02; onoff = LEDhyperlink & 0x04; fliponoff = LEDhyperlink & 0x08; if ((green && onoff) || (green && fliponoff)) setLED(LED_GREEN,TRUE); else if ((green && !onoff) || (!green && fliponoff)) setLED(LED_GREEN,FALSE); if ((red && onoff) || (red && fliponoff)) setLED(LED_RED,TRUE); else if ((red && !onoff) || (!red && fliponoff)) setLED(LED_RED,FALSE); } } } // if (code) }