X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FATCDCL%2FATCVoice.cxx;h=07825f78c3f5c64239c7e94e9f4c0e922e6a95c8;hb=8b57675aef4930245a964816469be922e3004287;hp=023dde22cb72b71c13a3049d752be32cf39dae55;hpb=86f462933d0d7130e4e688183976620ed2ddb5ae;p=flightgear.git diff --git a/src/ATCDCL/ATCVoice.cxx b/src/ATCDCL/ATCVoice.cxx index 023dde22c..07825f78c 100644 --- a/src/ATCDCL/ATCVoice.cxx +++ b/src/ATCDCL/ATCVoice.cxx @@ -28,10 +28,8 @@ #include #include #include -#include #include - -#include +#include #include #include @@ -41,12 +39,6 @@ #include
-#include - -#ifdef _MSC_VER -#define strtok_r strtok_s -#endif - using namespace std; FGATCVoice::FGATCVoice() { @@ -72,9 +64,10 @@ bool FGATCVoice::LoadVoice(const string& voice) { string full_path = path.str(); int format, freq; - SGSoundMgr *smgr = (SGSoundMgr *)globals->get_subsystem("soundmgr"); + SGSoundMgr *smgr = globals->get_soundmgr(); void *data; - smgr->load(full_path, &data, &format, &rawDataSize, &freq); + if (!smgr->load(full_path, &data, &format, &rawDataSize, &freq)) + return false; rawSoundData = (char*)data; #ifdef VOICE_TEST cout << "ATCVoice: format: " << format @@ -117,7 +110,7 @@ bool FGATCVoice::LoadVoice(const string& voice) { *p = tolower(*p); if (*p == '-') *p = '_'; } - if (wrdstr != ws2) wordMap[ws2] = wd; + if (wrdstr != ws2) wordMap[ws2] = wd; //cout << wrd << "\t\t" << wrdOffset << "\t\t" << wrdLength << '\n'; //cout << i << '\n'; @@ -128,93 +121,84 @@ bool FGATCVoice::LoadVoice(const string& voice) { } -typedef list < string > tokenList_type; -typedef tokenList_type::iterator tokenList_iterator; - // Given a desired message, return a string containing the // sound-sample data -string FGATCVoice::WriteMessage(const char* message, bool& dataOK) { +void* FGATCVoice::WriteMessage(const string& message, size_t* len) { // What should we do here? // First - parse the message into a list of tokens. // Sort the tokens into those we understand and those we don't. // Add all the raw lengths of the token sound data, allocate enough space, and fill it with the rqd data. - tokenList_type tokenList; - tokenList_iterator tokenListItr; - - // TODO - at the moment we're effectively taking 3 passes through the data. - // There is no need for this - 2 should be sufficient - we can probably ditch the tokenList. - size_t n1 = 1+strlen(message); - boost::shared_array msg(new char[n1]); - strncpy(msg.get(), message, n1); // strtok requires a non-const char* - char* token; - int numWords = 0; + + vector sound; const char delimiters[] = " \t.,;:\"\n"; - char* context; - token = strtok_r(msg.get(), delimiters, &context); - while(token != NULL) { - for (char *t = token; *t; t++) { - *t = tolower(*t); // canonicalize the case, to - if (*t == '-') *t = '_'; // match what's in the index - } - tokenList.push_back(token); - ++numWords; - SG_LOG(SG_ATC, SG_DEBUG, "voice synth: token: '" - << token << "'"); - token = strtok_r(NULL, delimiters, &context); - } + string::size_type token_start = message.find_first_not_of(delimiters); + while(token_start != string::npos) { + string::size_type token_end = message.find_first_of(delimiters, token_start); + string token; + if (token_end == string::npos) { + token = message.substr(token_start); + token_start = string::npos; + } else { + token = message.substr(token_start, token_end - token_start); + token_start = message.find_first_not_of(delimiters, token_end); + } - vector wdptr; - wdptr.reserve(numWords); - unsigned int cumLength = 0; + if (token == "/_") continue; - tokenListItr = tokenList.begin(); - while(tokenListItr != tokenList.end()) { - if(wordMap.find(*tokenListItr) == wordMap.end()) { - // Oh dear - the token isn't in the sound file - SG_LOG(SG_ATC, SG_ALERT, "voice synth: word '" - << *tokenListItr << "' not found"); + for(string::iterator t = token.begin(); t != token.end(); t++) { + // canonicalize the token, to match what's in the index + *t = (*t == '-') ? '_' : tolower(*t); + } + SG_LOG(SG_ATC, SG_DEBUG, "voice synth: token: '" + << token << "'"); + + atc_word_map_const_iterator wordIt = wordMap.find(token); + if(wordIt == wordMap.end()) { + // Oh dear - the token isn't in the sound file + SG_LOG(SG_ATC, SG_ALERT, "voice synth: word '" + << token << "' not found"); } else { - wdptr.push_back(wordMap[*tokenListItr]); - cumLength += wdptr.back().length; + const WordData& word = wordIt->second; + /* + * Sanity check for corrupt/mismatched sound data input - avoids a seg fault + * (As long as the calling function checks the return value!!) + * This check should be left in even when the default Flightgear files are known + * to be OK since it checks for mis-indexing of voice files by 3rd party developers. + */ + if((word.offset + word.length) > rawDataSize) { + SG_LOG(SG_ATC, SG_ALERT, "ERROR - mismatch between ATC .wav and .vce file in ATCVoice.cxx\n"); + SG_LOG(SG_ATC, SG_ALERT, "Offset + length: " << word.offset + word.length + << " exceeds rawdata size: " << rawDataSize << endl); + + *len = 0; + return 0; + } + sound.insert(sound.end(), rawSoundData + word.offset, rawSoundData + word.offset + word.length); } - ++tokenListItr; } - const size_t word = wdptr.size(); - + // Check for no tokens found else slScheduler can be crashed - if(!word) { - dataOK = false; - return ""; + *len = sound.size(); + if (*len == 0) { + return 0; } - boost::shared_array tmpbuf(new char[cumLength]); - unsigned int bufpos = 0; - for(int i=0; i rawDataSize) { - SG_LOG(SG_ATC, SG_ALERT, "ERROR - mismatch between ATC .wav and .vce file in ATCVoice.cxx\n"); - SG_LOG(SG_ATC, SG_ALERT, "Offset + length: " << wdptr[i].offset + wdptr[i].length - << " exceeds rawdata size: " << rawDataSize << endl); - - dataOK = false; - return ""; - } - memcpy(tmpbuf.get() + bufpos, rawSoundData + wdptr[i].offset, wdptr[i].length); - bufpos += wdptr[i].length; + + char* data = (char*)malloc(*len); + if (data == 0) { + SG_LOG(SG_ATC, SG_ALERT, "ERROR - could not allocate " << *len << " bytes of memory for ATIS sound\n"); + *len = 0; + return 0; } - - // tmpbuf now contains the message starting at the beginning - but we want it to start at a random position. - unsigned int offsetIn = (int)(cumLength * sg_random()); - if(offsetIn > cumLength) offsetIn = cumLength; - string front(tmpbuf.get(), offsetIn); - string back(tmpbuf.get() + offsetIn, cumLength - offsetIn); + // randomize start position + unsigned int offsetIn = (unsigned int)(*len * sg_random()); + if (offsetIn > 0 && offsetIn < *len) { + copy(sound.begin() + offsetIn, sound.end(), data); + copy(sound.begin(), sound.begin() + offsetIn, data + *len - offsetIn); + } else { + copy(sound.begin(), sound.end(), data); + } - dataOK = true; - return back + front; + return data; }