X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FATCDCL%2FATCVoice.cxx;h=07825f78c3f5c64239c7e94e9f4c0e922e6a95c8;hb=49677f512b8edaaf22c76761dbbf9c0850c79aad;hp=05f24daac4934b828bb3db79221b377d45f8451e;hpb=7a14ec7e320bd2786a041e8801b79cd87d6dc1d1;p=flightgear.git diff --git a/src/ATCDCL/ATCVoice.cxx b/src/ATCDCL/ATCVoice.cxx index 05f24daac..07825f78c 100644 --- a/src/ATCDCL/ATCVoice.cxx +++ b/src/ATCDCL/ATCVoice.cxx @@ -28,16 +28,19 @@ #include #include #include -#include +#include +#include +#include #include #include #include #include -#include #include
+using namespace std; + FGATCVoice::FGATCVoice() { SoundData = 0; rawSoundData = 0; @@ -45,29 +48,29 @@ FGATCVoice::FGATCVoice() { FGATCVoice::~FGATCVoice() { if (rawSoundData) - free( rawSoundData ); + free( rawSoundData ); delete SoundData; } // Load the two voice files - one containing the raw sound data (.wav) and one containing the word positions (.vce). // Return true if successful. bool FGATCVoice::LoadVoice(const string& voice) { - // FIXME CLO: disabled to try to see if this is causing problemcs - // return false; - std::ifstream fin; SGPath path = globals->get_fg_root(); + string file = voice + ".wav"; path.append( "ATC" ); - - string file = voice + ".wav"; + path.append( file ); - SGSoundSample SoundData; - rawSoundData = (char *)SoundData.load_file(path.c_str(), file.c_str()); - rawDataSize = SoundData.get_size(); + string full_path = path.str(); + int format, freq; + SGSoundMgr *smgr = globals->get_soundmgr(); + void *data; + if (!smgr->load(full_path, &data, &format, &rawDataSize, &freq)) + return false; + rawSoundData = (char*)data; #ifdef VOICE_TEST - ALenum fmt = SoundData.get_format(); - cout << "ATCVoice: format: " << fmt + cout << "ATCVoice: format: " << format << " size: " << rawDataSize << endl; #endif path = globals->get_fg_root(); @@ -102,12 +105,12 @@ bool FGATCVoice::LoadVoice(const string& voice) { wd.offset = wrdOffset; wd.length = wrdLength; wordMap[wrdstr] = wd; - string ws2 = wrdstr; - for(string::iterator p = ws2.begin(); p != ws2.end(); p++){ - *p = tolower(*p); - if (*p == '-') *p = '_'; - } - if (wrdstr != ws2) wordMap[ws2] = wd; + string ws2 = wrdstr; + for(string::iterator p = ws2.begin(); p != ws2.end(); p++){ + *p = tolower(*p); + if (*p == '-') *p = '_'; + } + if (wrdstr != ws2) wordMap[ws2] = wd; //cout << wrd << "\t\t" << wrdOffset << "\t\t" << wrdLength << '\n'; //cout << i << '\n'; @@ -118,95 +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); - char msg[n1]; - strncpy(msg, 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, 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); + } + + if (token == "/_") continue; - WordData wdptr[numWords]; - int word = 0; - unsigned int cumLength = 0; + 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 << "'"); - 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"); + 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[word] = wordMap[*tokenListItr]; - cumLength += wdptr[word].length; - //cout << *tokenListItr << " found at offset " << wdptr[word].offset << " with length " << wdptr[word].length << endl; - word++; + 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; } // Check for no tokens found else slScheduler can be crashed - if(!word) { - dataOK = false; - return ""; + *len = sound.size(); + if (*len == 0) { + return 0; } - char tmpbuf[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 + 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, offsetIn); - string back(tmpbuf+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; }