Beispiel #1
0
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
}
Beispiel #2
0
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);	
}
Beispiel #3
0
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);	
}
Beispiel #4
0
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);
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}	
Beispiel #7
0
void insertSoundFile(int idxFile) {
	insertSound(&pkgSystem.files[idxFile],NULL,FALSE);
}
Beispiel #8
0
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);
}
Beispiel #9
0
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;
}	
Beispiel #10
0
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)
}
Beispiel #11
0
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)
}