⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 core.c

📁 AVR source code for performing speech, the speech voice will be like a robot voice. sources are in c
💻 C
📖 第 1 页 / 共 2 页
字号:

#include "global.h"


// Random number seed
uint8_t seed0;
uint8_t seed1;
uint8_t seed2;

char phonemes[128];	
char modifier[128];	// must be same size as 'phonemes'
char g_text[64];

uint8_t default_pitch = 7;



#ifdef _AVR_
	// Define routines to log to the UART
	void loggerP(const char * s){
		rprintfProgStr(s);
	}

	void logger(const char * s){
		rprintfStr((char *)s);
	}

	void loggerc(char c){
		rprintfChar(c);
	}

	void logger_uint8(uint8_t n){
		rprintfNum(10, 3, 0, ' ', n);
	}
	void loggerCRLF(void){
		loggerP(PSTR("\n"));
	}
#else
		FILE * log_dest = stderr;
		void setLogFile(FILE * file){
			log_dest = file;
		}
		void logger(const char* s){
			fprintf(log_dest,"%s",s);
		}

		void loggerc(char c){
			fprintf(log_dest,"%c",c);
		}
		void logger_uint8(uint8_t n){
			fprintf(log_dest,"%03d",n);
		}
		void loggerCRLF(void){
			fprintf(log_dest,"\n");
		}
#endif



// Lookup user specified pitch changes
static const uint8_t PROGMEM PitchesP[]  = { 1, 2, 4, 6, 8, 10, 13, 16 };

/**
*
*  Find the single character 'token' in 'vocab'
*  and append its phonemes to dest[x]
*
*  Return new 'x'
*/

int copyToken(char token,char * dest, int x, const VOCAB* vocab){
	int ph;
	const char* src;

	for(ph = 0; ph < numVocab; ph++){
		const char *txt = (const char *)pgm_read_word(&vocab[ph].txt);
		if(pgm_read_byte(&txt[0]) == token && pgm_read_byte(&txt[1])==0){

			src = (const char *)pgm_read_word(&vocab[ph].phoneme);
			while(pgm_read_byte(src)!=0){
				dest[x++] = pgm_read_byte(src);
				src++;
			}
			break;
		}
	}

	return x;
}

uint8_t whitespace(char c){
	return (c==0 || c==' ' || c==',' || c=='.' || c=='?' || c=='\'' 
		|| c=='!' || c==':' || c=='/') ? 1 : 0;
}

/**
*  Enter:
*  src => English text in upper case
*  vocab => VOCAB array
*  dest => address to return result
*  return 1 if ok, or 0 if error
*/
int textToPhonemes(const char * src, const VOCAB* vocab, char * dest){
	int outIndex = 0;// Current offset into dest
	int inIndex = -1; // Starts at -1 so that a leading space is assumed

	while(inIndex==-1 || src[inIndex]!= 0){	// until end of text
		int maxMatch=0;	// Max chars matched on input text
		int numOut=0;	// Number of characters copied to output stream for the best match
		int ph;
		boolean endsInWhiteSpace=FALSE;
		int maxWildcardPos = 0;

		// Get next phoneme, P2
		for(ph = 0; ph < numVocab; ph++){
			int y,x;
			char wildcard=0; // modifier
			int wildcardInPos=0;
			boolean hasWhiteSpace=FALSE;
			const char* text = (const char*)pgm_read_word(&vocab[ph].txt); 
			const char* phon = (const char*)pgm_read_word(&vocab[ph].phoneme); 



			for(y=0;;y++){

				char nextVocabChar = pgm_read_byte(&text[y]);
				char nextCharIn = (y + inIndex==-1) ? ' ' : src[y + inIndex];
				if(nextCharIn>='a' && nextCharIn<='z'){
					nextCharIn = nextCharIn - 'a' + 'A';
				}
	
				if(nextVocabChar=='#' && nextCharIn >= 'A' && nextCharIn <= 'Z'){
					wildcard = nextCharIn; // The character equivalent to the '#'
					wildcardInPos=y;
					continue;
				}

				if(nextVocabChar=='_'){
					// try to match against a white space
					hasWhiteSpace=TRUE;
					if(whitespace(nextCharIn)){
						continue;
					}
					y--;
					break;
				}

				// check for end of either string
				if(nextVocabChar==0 || nextCharIn==0){
					break;
				}

				if(nextVocabChar != nextCharIn){
					break;
				}
			}

			// See if its the longest complete match so far
			if(y<=maxMatch || pgm_read_byte(&text[y])!=0){
				continue;
			}


			// This is the longest complete match
			maxMatch = y;
			maxWildcardPos = 0;
			x = outIndex; // offset into phoneme return data

			// Copy the matching phrase changing any '#' to the phoneme for the wildcard
			for(y=0;;y++){
				char c = pgm_read_byte(&phon[y]);
				if(c==0)
					break;
				if(c=='#'){
					if(pgm_read_byte(&phon[y+1])==0){
						// replacement ends in wildcard
						maxWildcardPos = wildcardInPos;
					}else{
						x = copyToken(wildcard,dest,x, vocab); // Copy the phonemes for the wildcard character
					}
				}else{
					dest[x++] = c;
				}
			}
			dest[x]=0;
			endsInWhiteSpace = hasWhiteSpace;

			// 14
			numOut = x - outIndex;	// The number of bytes added

		}// check next phoneme
		// 15 - end of vocab table

		//16
		if(endsInWhiteSpace==TRUE){
			maxMatch--;
		}

		//17
		if(maxMatch==0){
			loggerP(PSTR("Mistake in SAY, no token for ")); 
			logger(&src[inIndex]);
			loggerCRLF();
			return 0;
		}

		//20
		outIndex += numOut;
		if(outIndex > 256-16){
			loggerP(PSTR("Mistake in SAY, text too long\n"));
			return 0;
		}

		//21 
		
		inIndex += (maxWildcardPos>0) ? maxWildcardPos : maxMatch;
	}
	return 1;
}


/**
*
*   Convert phonemes to data string
*   Enter: textp = phonemes string
*   Return: phonemes = string of sound data
*			modifier = 2 bytes per sound data
*
*/
int phonemesToData(const char* textp, const PHONEME* phoneme){

	int phonemeOut = 0; // offset into the phonemes array
	int modifierOut = 0; // offset into the modifiers array
	unsigned int L81=0; // attenuate
	unsigned int L80=16;

	while(*textp != 0){
		// P20: Get next phoneme
		boolean anyMatch=FALSE;
		int longestMatch=0;
		int ph;
		int numOut=0;	// The number of bytes copied to the output for the longest match
		

		// Get next phoneme, P2
		for(ph = 0; ph<numPhoneme; ph++){
			int numChars;

			// Locate start of next phoneme 
			const char* ph_text = (const char*)pgm_read_word(&phoneme[ph].txt);

			
			// Set 'numChars' to the number of characters
			// that we match against this phoneme
			for(numChars=0;textp[numChars]!=0 ;numChars++){

				// get next input character and make lower case
				char nextChar = textp[numChars];
				if(nextChar>='A' && nextChar<='Z'){
					nextChar = nextChar - 'A' + 'a';
				}

				if(nextChar!=pgm_read_byte(&ph_text[numChars])){
					break;
				}
			}

			// if not the longest match so far then ignore
			if(numChars <= longestMatch) continue;

			if(pgm_read_byte(&ph_text[numChars])!=0){
				// partial phoneme match
				continue;

			}

			// P7: we have matched the whole phoneme
			longestMatch = numChars;

			// Copy phoneme data to 'phonemes'
			{
				const char* ph_ph = (const char*)pgm_read_word(&phoneme[ph].phoneme);
				for(numOut=0; pgm_read_byte(&ph_ph[numOut])!= 0; numOut++){
					phonemes[phonemeOut+numOut] = pgm_read_byte(&ph_ph[numOut]);
				}
			}
		    L81 = pgm_read_byte(&phoneme[ph].attenuate)+'0';
			anyMatch=TRUE; // phoneme match found

			modifier[modifierOut]=-1;
			modifier[modifierOut+1]=0;

			// Get char from text after the phoneme and test if it is a numeric
			if(textp[longestMatch]>='0' && textp[longestMatch]<='9'){
				// Pitch change requested
				modifier[modifierOut] = pgm_read_byte(&PitchesP[textp[longestMatch]-'1'] );
				modifier[modifierOut+1] = L81;
				longestMatch++;
			}

			// P10
			if(L81!='0' && L81 != L80 && modifier[modifierOut]>=0){
				modifier[modifierOut - 2] = modifier[modifierOut];
				modifier[modifierOut - 1] = '0';
				continue;
			}

			// P11
			if( (textp[longestMatch-1] | 0x20) == 0x20){
				// end of input string or a space
				modifier[modifierOut] = (modifierOut==0) ? 16 : modifier[modifierOut-2];
			}

		} // next phoneme

		// p13
		L80 = L81;
		if(longestMatch==0 && anyMatch==FALSE){
			loggerP(PSTR("Mistake in speech at "));
			logger(textp);
			loggerCRLF();
			return 0;
		}

		// Move over the bytes we have copied to the output
		phonemeOut += numOut;

		if(phonemeOut > sizeof(phonemes)-16){
			loggerP(PSTR("Line too long\n"));
			return 0;
		}

		// P16

		// Copy the modifier setting to each sound data element for this phoneme
		if(numOut > 2){
			int count;
			for(count=0; count != numOut; count+=2){
				modifier[modifierOut + count + 2] = modifier[modifierOut + count];
				modifier[modifierOut + count + 3] = 0;
			}
		}
		modifierOut += numOut;

		//p21
		textp += longestMatch;
	}

	phonemes[phonemeOut++]='z';
	phonemes[phonemeOut++]='z';
	phonemes[phonemeOut++]='z';
	phonemes[phonemeOut++]='z';
	
	while(phonemeOut < sizeof(phonemes)){
		phonemes[phonemeOut++]=0;
	}

	while(modifierOut < sizeof(modifier)){
		modifier[modifierOut++]=-1;
		modifier[modifierOut++]=0;
	}

	return 1; 
}




/*
*   A delay loop that doesn't change with different optimisation settings
*/
void loop(uint8_t delay){
#ifdef _AVR_
		__asm__ volatile (
			"1: dec %0" "\n\t"
			"brne 1b"
			: "=r" (delay)
			: "0" (delay)
		);
#endif
}

void pause(uint8_t delay){
	uint8_t r;
	for(r=TIME_FACTOR; r>0; r--){
		loop(delay);
	}

}

void delay(uint8_t d){
	while(d!=0){
		pause(0);	// 256
		pause(0);	// 256
		d--;
	}
}




/*
	Generate a random number
*/
uint8_t random(void){
	uint8_t tmp = (seed0 & 0x48) + 0x38;
	seed0<<=1;
	if(seed1 & 0x80){
		seed0++;
	}
	seed1<<=1;
	if(seed2 & 0x80){
		seed1++;
	}
	seed2<<=1;
	if(tmp & 0x40){
		seed2++;
	}
	return seed0;
}




void soundOff(void){
#ifdef _AVR_

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -