#include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx>
+#include <simgear/math/sg_random.h>
#include <Main/globals.hxx>
#include "ATCVoice.hxx"
}
FGATCVoice::~FGATCVoice() {
- delete[] rawSoundData;
+ delete SoundData;
}
// Load the two voice files - one containing the raw sound data (.wav) and one containing the word positions (.vce).
string soundPath = "ATC/" + voice + ".wav";
path.append(soundPath);
- // Input data parameters - some of these might need to be class variables eventually
- // but at the moment we're just using them to find the header size to get the start
- // of the data properly.
- char chunkID[5];
- unsigned int chunkSize;
- char junk[100]; // WARNING - Assumes all non-data chunk sizes are < 100
+ SoundData = new slSample( (char*)path.c_str() );
+ rawDataSize = SoundData->getLength();
+ rawSoundData = (char*)SoundData->getBuffer();
- // do the sound data first
- SG_LOG(SG_GENERAL, SG_INFO, "Trying to open voice input...");
- fin.open(path.c_str(), ios::in|ios::binary);
- if(!fin) {
- SG_LOG(SG_GENERAL, SG_ALERT, "Unable to open input file " << path.c_str());
- return(false);
- }
- cout << "Opened voice input file " << soundPath << " OK...\n";
- // Strip the initial headers and ignore.
- // Note that this assumes we know the sound format etc - fix this eventually
- // (I've assumed sample-rate = 8000, bits = 8, mono, which is what the other FGFS sound samples seem to use.
- // The file should always start with the 12 byte RIFF header
- fin.read(chunkID, 4);
- // TODO - Should we check that the above == "RIFF" ?
- // read and discard the next 8 bytes
- fin.read(junk, 8);
- // Now it gets more complicated - although the format chunk is normally before the data chunk,
- // this is not guaranteed, and there may be a fact chunk as well. (And possibly more that I haven't heard of!).
- while(1) {
- fin.read(chunkID, 4);
- chunkID[4] = '\0';
- //cout << "sizeof(chunkID) = " << sizeof(chunkID) << '\n';
- //cout << "chunkID = " << chunkID << '\n';
- if(!strcmp(chunkID, "data")) {
- break;
- } else if((!strcmp(chunkID, "fmt ")) || (!strcmp(chunkID, "fact"))) {
- fin.read((char*)&chunkSize, sizeof(chunkSize));
- // Chunksizes must be word-aligned (ie every 2 bytes), but the given chunk size
- // is not guaranteed to be word-aligned, and there may be an extra padding byte.
- // Add 1 to chunkSize if it's odd.
- // Well, it is a microsoft file format!!!
- chunkSize += (chunkSize % 2);
- fin.read(junk, chunkSize);
- } else {
- // Oh dear - its all gone pear-shaped - abort :-(
- SG_LOG(SG_GENERAL, SG_ALERT, "Unknown chunk ID in input wave file in ATCVoice.cxx... aborting voice ATC load");
- fin.close();
- return(false);
- }
- }
-
- fin.read((char*)&rawDataSize, sizeof(rawDataSize));
- //cout << "rawDataSize = " << rawDataSize << endl;
- rawSoundData = new char[rawDataSize];
- fin.read(rawSoundData, rawDataSize);
- fin.close();
-
path = globals->get_fg_root();
string wordPath = "ATC/" + voice + ".vce";
path.append(wordPath);
// Now load the word data
fin.open(path.c_str(), ios::in);
if(!fin) {
- SG_LOG(SG_GENERAL, SG_ALERT, "Unable to open input file " << path.c_str() << '\n');
+ SG_LOG(SG_ATC, SG_ALERT, "Unable to open input file " << path.c_str());
return(false);
}
- cout << "Opened word data file " << wordPath << " OK...\n";
+ SG_LOG(SG_ATC, SG_INFO, "Opened word data file " << wordPath << " OK...");
char numwds[10];
char wrd[100];
string wrdstr;
}
+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) {
// 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.
- list < string > tokenList;
- list < string >::iterator tokenListItr;
+ 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.
dataOK = false;
return(NULL);
}
-
+
+ unsigned char* tmpbuf = new unsigned char[cumLength];
unsigned char* outbuf = new unsigned char[cumLength];
len = cumLength;
unsigned int bufpos = 0;
* to be OK since it checks for mis-indexing of voice files by 3rd party developers.
*/
if((wdptr[i].offset + wdptr[i].length) > rawDataSize) {
- SG_LOG(SG_GENERAL, SG_ALERT, "ERROR - mismatch between ATC .wav and .vce file in ATCVoice.cxx\n");
- SG_LOG(SG_GENERAL, SG_ALERT, "Offset + length: " << wdptr[i].offset + wdptr[i].length
+ 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;
- // I suppose we have to return something
return(NULL);
}
- memcpy(outbuf + bufpos, rawSoundData + wdptr[i].offset, wdptr[i].length);
+ memcpy(tmpbuf + bufpos, rawSoundData + wdptr[i].offset, wdptr[i].length);
bufpos += wdptr[i].length;
}
+ // 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;