X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FATCDCL%2FATCVoice.cxx;h=07825f78c3f5c64239c7e94e9f4c0e922e6a95c8;hb=49677f512b8edaaf22c76761dbbf9c0850c79aad;hp=682cd24a4ed72b4f70e321f26c05a8ef191686df;hpb=aacebaf4b8f101dbad17f20e5136f50cd6991a6f;p=flightgear.git diff --git a/src/ATCDCL/ATCVoice.cxx b/src/ATCDCL/ATCVoice.cxx index 682cd24a4..07825f78c 100644 --- a/src/ATCDCL/ATCVoice.cxx +++ b/src/ATCDCL/ATCVoice.cxx @@ -23,15 +23,23 @@ # include #endif +#include "ATCVoice.hxx" + +#include +#include +#include +#include +#include + +#include #include #include #include #include -#include
-#include "ATCVoice.hxx" +#include
-#include +using namespace std; FGATCVoice::FGATCVoice() { SoundData = 0; @@ -40,27 +48,31 @@ 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 causign problemcs - // return false; - - ifstream fin; + std::ifstream fin; SGPath path = globals->get_fg_root(); + string file = voice + ".wav"; path.append( "ATC" ); - - string file = voice + ".wav"; - - SoundData = new SGSoundSample(); - rawSoundData = (char *)SoundData->load_file(path.c_str(), file.c_str()); - rawDataSize = SoundData->get_size(); + path.append( file ); + 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 + cout << "ATCVoice: format: " << format + << " size: " << rawDataSize << endl; +#endif path = globals->get_fg_root(); string wordPath = "ATC/" + voice + ".vce"; path.append(wordPath); @@ -93,6 +105,13 @@ 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; + //cout << wrd << "\t\t" << wrdOffset << "\t\t" << wrdLength << '\n'; //cout << i << '\n'; } @@ -102,90 +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 pointer to the data buffer and write the buffer length into len. -unsigned char* FGATCVoice::WriteMessage(char* message, int& len, bool& dataOK) { +// Given a desired message, return a string containing the +// sound-sample data +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. - char* token; - char mes[1000]; - int numWords = 0; - strcpy(mes, message); - const char delimiters[] = " \t.,;:\""; - token = strtok(mes, delimiters); - while(token != NULL) { - tokenList.push_back(token); - ++numWords; - //cout << "token = " << token << '\n'; - token = strtok(NULL, delimiters); - } - WordData* wdptr = new WordData[numWords]; - int word = 0; - unsigned int cumLength = 0; + vector sound; + const char delimiters[] = " \t.,;:\"\n"; + 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; + + 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()) { + atc_word_map_const_iterator wordIt = wordMap.find(token); + if(wordIt == wordMap.end()) { // Oh dear - the token isn't in the sound file - //cout << "word " << *tokenListItr << " not found :-(\n"; + 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(NULL); + *len = sound.size(); + if (*len == 0) { + return 0; } - unsigned char* tmpbuf = new unsigned char[cumLength]; - unsigned char* outbuf = new unsigned char[cumLength]; - len = 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); - delete[] wdptr; - dataOK = false; - return(NULL); - } - 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; + } + + // 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); } - - // 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; - memcpy(outbuf, tmpbuf + offsetIn, (cumLength - offsetIn)); - memcpy(outbuf + (cumLength - offsetIn), tmpbuf, offsetIn); - - delete[] tmpbuf; - delete[] wdptr; - dataOK = true; - return(outbuf); + return data; }