1
0
Fork 0

Merge branch 'ehofman/sound'

This commit is contained in:
Tim Moore 2009-12-20 11:11:16 +01:00
commit b5c46a8d59
46 changed files with 1338 additions and 796 deletions

View file

@ -128,6 +128,17 @@ Configuration description:
in-transit: the sample plays continuously,
while the property is changing its value.
<type>
This defines the type os this sample:
fx: this is the default type and doesn't need to be defined.
avionics: sounds set to this type don't have a position and
orientation but are treated as if it's mounted to
the aircraft panel. it's up to the user to define
if it can always be heard or only when in cockpit
view.
<volume> / <pitch>
Volume or Pitch definition. Currently there may be up to 5

View file

@ -841,7 +841,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
// TODO - At hot 'n high airports this may be 500ft AGL though - need to make this a variable.
if((_pos.getElevationM() - rwy.threshold_pos.getElevationM()) * SG_METER_TO_FEET > 700) {
double cc = 0.0;
if(tower->GetCrosswindConstraint(cc)) {
if(tower && tower->GetCrosswindConstraint(cc)) {
if(orthopos.y() > cc) {
//cout << "Turning to crosswind, distance from threshold = " << orthopos.y() << '\n';
leg = TURN1;
@ -884,7 +884,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
// turn 1000m out for now, taking other traffic into accout
if(fabs(orthopos.x()) > 900) {
double dd = 0.0;
if(tower->GetDownwindConstraint(dd)) {
if(tower && tower->GetDownwindConstraint(dd)) {
if(fabs(orthopos.x()) > fabs(dd)) {
//cout << "Turning to downwind, distance from centerline = " << fabs(orthopos.x()) << '\n';
leg = TURN2;
@ -930,7 +930,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
// For now we're assuming that we aim to follow the same glidepath regardless of wind.
double d1;
double d2;
CalculateSoD((tower->GetBaseConstraint(d1) ? d1 : -1000.0), (tower->GetDownwindConstraint(d2) ? d2 : 1000.0 * patternDirection), (patternDirection ? true : false));
CalculateSoD(((tower && tower->GetBaseConstraint(d1)) ? d1 : -1000.0), ((tower && tower->GetDownwindConstraint(d2)) ? d2 : 1000.0 * patternDirection), (patternDirection ? true : false));
if(SoD.leg == DOWNWIND) {
descending = (orthopos.y() < SoD.y ? true : false);
}
@ -950,7 +950,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
if(orthopos.y() < -1000.0 + turn_radius) {
//if(orthopos.y() < -980) {
double bb = 0.0;
if(tower->GetBaseConstraint(bb)) {
if(tower && tower->GetBaseConstraint(bb)) {
if(fabs(orthopos.y()) > fabs(bb)) {
//cout << "Turning to base, distance from threshold = " << fabs(orthopos.y()) << '\n';
leg = TURN3;
@ -982,7 +982,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
double d1;
// Make downwind leg position artifically large to avoid any chance of SoD being returned as
// on downwind when we are already on base.
CalculateSoD((tower->GetBaseConstraint(d1) ? d1 : -1000.0), (10000.0 * patternDirection), (patternDirection ? true : false));
CalculateSoD(((tower && tower->GetBaseConstraint(d1)) ? d1 : -1000.0), (10000.0 * patternDirection), (patternDirection ? true : false));
if(SoD.leg == BASE) {
descending = (fabs(orthopos.y()) < fabs(SoD.y) ? true : false);
}
@ -1207,10 +1207,11 @@ void FGAILocalTraffic::CalculateSoD(double base_leg_pos, double downwind_leg_pos
void FGAILocalTraffic::TransmitPatternPositionReport(void) {
// airport name + "traffic" + airplane callsign + pattern direction + pattern leg + rwy + ?
string trns = "";
string trns;
int code = 0;
trns += tower->get_name();
const string& apt_name = tower ? tower->get_name() : airportID;
trns += apt_name;
trns += " Traffic ";
trns += plane.callsign;
if(patternDirection == 1) {
@ -1249,10 +1250,10 @@ void FGAILocalTraffic::TransmitPatternPositionReport(void) {
}
trns += ConvertRwyNumToSpokenString(rwy.rwyID);
trns += " ";
trns += ' ';
// And add the airport name again
trns += tower->get_name();
trns += apt_name;
pending_transmission = trns;
ConditionalTransmit(60.0, code); // Assume a report of this leg will be invalid if we can't transmit within a minute.

View file

@ -47,6 +47,12 @@ FGAIPlane::FGAIPlane() {
_trackSet = false;
_tgtRoll = 0.0;
_rollSuspended = false;
if ( !_sgr ) {
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("atc", true);
_sgr->tie_to_listener();
}
}
FGAIPlane::~FGAIPlane() {
@ -106,7 +112,7 @@ void FGAIPlane::Update(double dt) {
// For now assume in range !!!
// TODO - implement range checking
// TODO - at the moment the volume is always set off comm1
double volume = fgGetDouble("/instrumentation/comm[0]/volume");
float volume = fgGetFloat("/instrumentation/comm[0]/volume");
Render(plane.callsign, volume, false);
}
}
@ -167,8 +173,9 @@ void FGAIPlane::ConditionalTransmit(double timeout, int callback_code) {
}
void FGAIPlane::ImmediateTransmit(int callback_code) {
// TODO - at the moment the volume is always set off comm1
double volume = fgGetDouble("/instrumentation/comm[0]/volume");
// TODO - at the moment the volume is always set off comm1
float volume = fgGetFloat("/instrumentation/comm[0]/volume");
Render(plane.callsign, volume, false);
if(callback_code) {
ProcessCallback(callback_code);
@ -183,24 +190,18 @@ void FGAIPlane::ProcessCallback(int code) {
// Outputs the transmission either on screen or as audio depending on user preference
// The refname is a string to identify this sample to the sound manager
// The repeating flag indicates whether the message should be repeated continuously or played once.
void FGAIPlane::Render(const string& refname, const double volume, bool repeating) {
void FGAIPlane::Render(const string& refname, const float volume, bool repeating) {
fgSetString("/sim/messages/ai-plane", pending_transmission.c_str());
#ifdef ENABLE_AUDIO_SUPPORT
voice = (voiceOK && fgGetBool("/sim/sound/voice"));
if(voice) {
string buf = vPtr->WriteMessage((char*)pending_transmission.c_str(), voice);
if(voice) {
SGSoundSample* simple =
new SGSoundSample((unsigned char*)buf.c_str(), buf.length(), 8000, AL_FORMAT_MONO8 );
// TODO - at the moment the volume can't be changed
// after the transmission has started.
size_t len;
void* buf = vPtr->WriteMessage(pending_transmission, &len);
if(voice && (volume > 0.05)) {
SGSoundSample* simple = new SGSoundSample(&buf, len, 8000 );
simple->set_volume(volume);
globals->get_soundmgr()->add(simple, refname);
if(repeating) {
globals->get_soundmgr()->play_looped(refname);
} else {
globals->get_soundmgr()->play_once(refname);
}
_sgr->add(simple, refname);
_sgr->play(refname, repeating);
}
}
#endif // ENABLE_AUDIO_SUPPORT
@ -221,8 +222,8 @@ void FGAIPlane::NoRender(const string& refname) {
if(playing) {
if(voice) {
#ifdef ENABLE_AUDIO_SUPPORT
globals->get_soundmgr()->stop(refname);
globals->get_soundmgr()->remove(refname);
_sgr->stop(refname);
_sgr->remove(refname);
#endif
}
playing = false;

View file

@ -24,6 +24,8 @@
#include "AIEntity.hxx"
#include "ATC.hxx"
class SGSampleGroup;
enum PatternLeg {
TAKEOFF_ROLL,
CLIMBOUT,
@ -140,7 +142,7 @@ private:
// Outputs the transmission either on screen or as audio depending on user preference
// The refname is a string to identify this sample to the sound manager
// The repeating flag indicates whether the message should be repeated continuously or played once.
void Render(const string& refname, const double volume, bool repeating);
void Render(const string& refname, const float volume, bool repeating);
// Cease rendering a transmission.
// Requires the sound manager refname if audio, else "".
@ -157,6 +159,8 @@ private:
bool _trackSet; // Set true if tgtTrack is to be followed
double _tgtRoll;
bool _rollSuspended; // Set true when a derived class has suspended AIPlane's roll control
SGSharedPtr<SGSampleGroup> _sgr;
};
#endif // _FG_AI_PLANE_HXX

View file

@ -35,7 +35,9 @@
FGATC::FGATC() :
_voiceOK(false),
_voiceOK(false),
_playing(false),
_sgr(NULL),
freqClear(true),
receiving(false),
respond(false),
@ -55,6 +57,13 @@ FGATC::FGATC() :
_counter(0.0),
_max_count(5.0)
{
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("atc", true);
_volume = fgGetNode("/sim/sound/atc/volume", true);
_enabled = fgGetNode("/sim/sound/atc/enabled", true);
_atc_external = fgGetNode("/sim/sound/atc/external-view", true);
_internal = fgGetNode("/sim/current-view/internal", true);
}
FGATC::~FGATC() {
@ -103,6 +112,18 @@ void FGATC::Update(double dt) {
}
}
#ifdef ENABLE_AUDIO_SUPPORT
bool active = _atc_external->getBoolValue() ||
_internal->getBoolValue();
if ( active && _enabled->getBoolValue() ) {
_sgr->set_volume( _volume->getFloatValue() );
_sgr->resume(); // no-op if already in resumed state
} else {
_sgr->suspend();
}
#endif
if(_transmit) {
_counter = 0.0;
_max_count = 5.0; // FIXME - hardwired length of message - need to calculate it!
@ -203,7 +224,7 @@ int FGATC::RemovePlane() {
}
void FGATC::SetData(ATCData* d) {
_type = d->type;
_type = d->type;
_geod = d->geod;
_cart = d->cart;
range = d->range;
@ -216,41 +237,36 @@ void FGATC::SetData(ATCData* d) {
// Outputs the transmission either on screen or as audio depending on user preference
// The refname is a string to identify this sample to the sound manager
// The repeating flag indicates whether the message should be repeated continuously or played once.
void FGATC::Render(string& msg, const double volume,
const string& refname, const bool repeating) {
void FGATC::Render(string& msg, const float volume,
const string& refname, const bool repeating) {
if (volume < 0.05) return;
if (repeating)
fgSetString("/sim/messages/atis", msg.c_str());
else
fgSetString("/sim/messages/atc", msg.c_str());
#ifdef ENABLE_AUDIO_SUPPORT
#ifdef ENABLE_AUDIO_SUPPORT
_voice = (_voiceOK && fgGetBool("/sim/sound/voice"));
if(_voice) {
string buf = _vPtr->WriteMessage((char*)msg.c_str(), _voice);
if(_voice) {
NoRender(refname);
try {
size_t len;
void* buf = _vPtr->WriteMessage((char*)msg.c_str(), &len);
if(buf) {
NoRender(refname);
try {
// >>> Beware: must pass a (new) object to the (add) method,
// >>> because the (remove) method is going to do a (delete)
// >>> whether that's what you want or not.
SGSoundSample *simple =
new SGSoundSample((unsigned char*) buf.c_str(),
buf.length(), 8000, AL_FORMAT_MONO8);
// TODO - at the moment the volume can't be changed
// after the transmission has started.
simple->set_volume(volume);
globals->get_soundmgr()->add(simple, refname);
if(repeating) {
globals->get_soundmgr()->play_looped(refname);
} else {
globals->get_soundmgr()->play_once(refname);
}
} catch ( sg_io_exception &e ) {
SG_LOG(SG_GENERAL, SG_ALERT, e.getFormattedMessage());
SGSoundSample *simple = new SGSoundSample(&buf, len, 8000);
simple->set_volume(volume);
_sgr->add(simple, refname);
_sgr->play(refname, repeating);
} catch ( sg_io_exception &e ) {
SG_LOG(SG_GENERAL, SG_ALERT, e.getFormattedMessage());
}
}
}
}
#endif // ENABLE_AUDIO_SUPPORT
#endif // ENABLE_AUDIO_SUPPORT
if(!_voice) {
// first rip the underscores and the pause hints out of the string - these are for the convienience of the voice parser
for(unsigned int i = 0; i < msg.length(); ++i) {
@ -268,8 +284,8 @@ void FGATC::NoRender(const string& refname) {
if(_playing) {
if(_voice) {
#ifdef ENABLE_AUDIO_SUPPORT
globals->get_soundmgr()->stop(refname);
globals->get_soundmgr()->remove(refname);
_sgr->stop(refname);
_sgr->remove(refname);
#endif
}
_playing = false;
@ -283,14 +299,14 @@ string FGATC::GenText(const string& m, int c) {
ostream& operator << (ostream& os, atc_type atc) {
switch(atc) {
case(AWOS): return(os << "AWOS");
case(ATIS): return(os << "ATIS");
case(GROUND): return(os << "GROUND");
case(TOWER): return(os << "TOWER");
case(AWOS): return(os << "AWOS");
case(ATIS): return(os << "ATIS");
case(GROUND): return(os << "GROUND");
case(TOWER): return(os << "TOWER");
case(APPROACH): return(os << "APPROACH");
case(DEPARTURE): return(os << "DEPARTURE");
case(ENROUTE): return(os << "ENROUTE");
case(INVALID): return(os << "INVALID");
case(ENROUTE): return(os << "ENROUTE");
case(INVALID): return(os << "INVALID");
}
return(os << "ERROR - Unknown switch in atc_type operator << ");
}
@ -325,8 +341,8 @@ std::istream& operator >> ( std::istream& fin, ATCData& a )
return fin >> skipeol;
}
double lat, lon, elev;
double lat, lon, elev;
fin >> lat >> lon >> elev >> f >> a.range >> a.ident;
a.geod = SGGeod::fromDegM(lon, lat, elev);
a.name = "";
@ -349,7 +365,7 @@ std::istream& operator >> ( std::istream& fin, ATCData& a )
// cout << a.ident << endl;
// generate cartesian coordinates
a.cart = SGVec3d::fromGeod(a.geod);
a.cart = SGVec3d::fromGeod(a.geod);
return fin >> skipeol;
}

View file

@ -24,15 +24,19 @@
#include <simgear/constants.h>
#include <simgear/compiler.h>
#include <simgear/props/props.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <iosfwd>
#include <string>
#include "ATCVoice.hxx"
class SGSampleGroup;
// Convert a frequency in MHz to tens of kHz
// so we can use it e.g. as an index into commlist_freq
//
@ -76,7 +80,7 @@ enum atc_type {
APPROACH,
DEPARTURE,
ENROUTE,
INVALID /* must be last element; see ATC_NUM_TYPES */
INVALID /* must be last element; see ATC_NUM_TYPES */
};
const int ATC_NUM_TYPES = 1 + INVALID;
@ -84,8 +88,8 @@ const int ATC_NUM_TYPES = 1 + INVALID;
// DCL - new experimental ATC data store
struct ATCData {
atc_type type;
SGGeod geod;
SGVec3d cart;
SGGeod geod;
SGVec3d cart;
unsigned short int freq;
unsigned short int range;
std::string ident;
@ -114,7 +118,7 @@ public:
FGATC();
virtual ~FGATC();
virtual void Init()=0;
virtual void Init()=0;
// Run the internal calculations
// Derived classes should call this method from their own Update methods if they
@ -176,15 +180,15 @@ protected:
// Outputs the transmission either on screen or as audio depending on user preference
// The refname is a string to identify this sample to the sound manager
// The repeating flag indicates whether the message should be repeated continuously or played once.
void Render(std::string& msg, const double volume = 1.0,
const std::string& refname = "", bool repeating = false);
void Render(std::string& msg, const float volume = 1.0,
const std::string& refname = "", bool repeating = false);
// Cease rendering all transmission from this station.
// Requires the sound manager refname if audio, else "".
void NoRender(const std::string& refname);
// Transmit a message when channel becomes free of other dialog
void Transmit(int callback_code = 0);
void Transmit(int callback_code = 0);
// Transmit a message if channel becomes free within timeout (seconds). timeout of zero implies no limit
void ConditionalTransmit(double timeout, int callback_code = 0);
@ -197,44 +201,46 @@ protected:
SGGeod _geod;
SGVec3d _cart;
int freq;
std::map<std::string,int> active_on;
std::map<std::string,int> active_on;
int range;
std::string ident; // Code of the airport its at.
std::string name; // Name transmitted in the broadcast.
std::string ident; // Code of the airport its at.
std::string name; // Name transmitted in the broadcast.
// Rendering related stuff
bool _voice; // Flag - true if we are using voice
bool _playing; // Indicates a message in progress
bool _voiceOK; // Flag - true if at least one voice has loaded OK
bool _voice; // Flag - true if we are using voice
bool _playing; // Indicates a message in progress
bool _voiceOK; // Flag - true if at least one voice has loaded OK
FGATCVoice* _vPtr;
SGSharedPtr<SGSampleGroup> _sgr; // default sample group;
bool freqClear; // Flag to indicate if the frequency is clear of ongoing dialog
bool receiving; // Flag to indicate we are receiving a transmission
bool freqClear; // Flag to indicate if the frequency is clear of ongoing dialog
bool receiving; // Flag to indicate we are receiving a transmission
double responseTime; // Time to take from end of request transmission to beginning of response
// The idea is that this will be slightly random.
double responseTime; // Time to take from end of request transmission to beginning of response
// The idea is that this will be slightly random.
bool respond; // Flag to indicate now is the time to respond - ie set following the count down of the response timer.
bool respond; // Flag to indicate now is the time to respond - ie set following the count down of the response timer.
std::string responseID; // ID of the plane to respond to
bool runResponseCounter; // Flag to indicate the response counter should be run
double responseCounter; // counter to implement the above
bool runResponseCounter; // Flag to indicate the response counter should be run
double responseCounter; // counter to implement the above
// Derived classes only need monitor this flag, and use the response ID, as long as they call FGATC::Update(...)
bool _runReleaseCounter; // A timer for releasing the frequency after giving the message enough time to display
bool responseReqd; // Flag to indicate we should be responding to a request/report
bool responseReqd; // Flag to indicate we should be responding to a request/report
double _releaseTime;
double _releaseCounter;
atc_type _type;
bool _display; // Flag to indicate whether we should be outputting to the ATC display.
std::string pending_transmission; // derived classes set this string before calling Transmit(...)
bool _display; // Flag to indicate whether we should be outputting to the ATC display.
std::string pending_transmission; // derived classes set this string before calling Transmit(...)
private:
// Transmission timing stuff.
double _timeout;
bool _pending;
bool _pending;
int _callback_code; // A callback code to be notified and processed by the derived classes
// A value of zero indicates no callback required
@ -242,6 +248,11 @@ private:
bool _transmitting; // we are transmitting
double _counter;
double _max_count;
SGPropertyNode_ptr _volume;
SGPropertyNode_ptr _enabled;
SGPropertyNode_ptr _atc_external;
SGPropertyNode_ptr _internal;
};
std::istream& operator>> ( std::istream& fin, ATCData& a );

View file

@ -28,25 +28,17 @@
#include <stdlib.h>
#include <ctype.h>
#include <fstream>
#include <list>
#include <vector>
#include <algorithm>
#include <boost/shared_array.hpp>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/sound/sample_openal.hxx>
#include <Main/globals.hxx>
#include <stdio.h>
#ifdef _MSC_VER
#define strtok_r strtok_s
#endif
using namespace std;
FGATCVoice::FGATCVoice() {
@ -56,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();
@ -113,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';
@ -129,93 +121,82 @@ 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<char> msg(new char[n1]);
strncpy(msg.get(), message, n1); // strtok requires a non-const char*
char* token;
int numWords = 0;
vector<char> 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);
}
vector<WordData> wdptr;
wdptr.reserve(numWords);
unsigned int cumLength = 0;
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");
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 {
wdptr.push_back(wordMap[*tokenListItr]);
cumLength += wdptr.back().length;
token = message.substr(token_start, token_end - token_start);
token_start = message.find_first_not_of(delimiters, token_end);
}
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 {
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<char> tmpbuf(new char[cumLength]);
unsigned int bufpos = 0;
for(int i=0; i<word; ++i) {
/*
* 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((wdptr[i].offset + wdptr[i].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: " << 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;
}

View file

@ -22,6 +22,7 @@
#define _FG_ATC_VOICE
#include <simgear/compiler.h>
#include <simgear/structure/SGSharedPtr.hxx>
#include <map>
#include <string>
@ -49,15 +50,15 @@ public:
bool LoadVoice(const std::string& voice);
// Given a desired message, return a pointer to the data buffer and write the buffer length into len.
// Sets dataOK = true if the returned buffer is valid.
std::string WriteMessage(const char* message, bool& dataOK);
// Sets len to something other than 0 if the returned buffer is valid.
void* WriteMessage(const std::string& message, size_t *len);
private:
// the sound and word position data
char* rawSoundData;
unsigned int rawDataSize;
SGSoundSample *SoundData;
size_t rawDataSize;
SGSharedPtr<SGSoundSample> SoundData;
// A map of words vs. byte position and length in rawSoundData
atc_word_map_type wordMap;

View file

@ -34,6 +34,7 @@
#include <simgear/misc/sg_path.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <Main/globals.hxx>
#include <Main/fg_init.hxx>
@ -226,12 +227,9 @@ fgLoadAircraft (const SGPropertyNode * arg)
t = fgInitTime();
globals->set_time_params( t );
// Reinitialize some subsystems
//
globals->get_viewmgr()->reinit();
globals->get_controls()->reset_all();
globals->get_aircraft_model()->reinit();
globals->get_subsystem("fx")->reinit();
globals->get_subsystem("xml-autopilot")->reinit();
fgReInitSubsystems();

View file

@ -40,6 +40,7 @@
// forward decls
class SGPropertyNode;
class SGSampleGroup;
class FGMetar;
/**

View file

@ -68,9 +68,10 @@ void FGClouds::init(void) {
snd_lightning = new SGSoundSample(globals->get_fg_root().c_str(), "Sounds/thunder.wav");
snd_lightning->set_max_dist(7000.0f);
snd_lightning->set_reference_dist(3000.0f);
SGSoundMgr *soundMgr = globals->get_soundmgr();
soundMgr->add( snd_lightning, "thunder" );
sgEnviro.set_soundMgr( soundMgr );
SGSoundMgr *smgr = globals->get_soundmgr();
SGSampleGroup *sgr = smgr->find("weather", true);
sgr->add( snd_lightning, "thunder" );
sgEnviro.set_sampleGroup( sgr );
}
}

View file

@ -34,10 +34,11 @@
using std::string;
class SGNewCloud;
class SGSampleGroup;
class SGCloudField;
class SGNewCloud;
class FGMetar;
class FGEnvironmentCtrl;
//class FGEnvironmentCtrl;
class FGClouds {

View file

@ -69,7 +69,8 @@ ADF::ADF (SGPropertyNode *node )
_transmitter_range_nm(0),
_ident_count(0),
_last_ident_time(0),
_last_volume(-1)
_last_volume(-1),
_sgr(0)
{
}
@ -101,6 +102,10 @@ ADF::init ()
_ident_node = node->getChild("ident", 0, true);
_ident_audible_node = node->getChild("ident-audible", 0, true);
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("avionics", true);
_sgr->tie_to_listener();
morse.init();
std::ostringstream temp;
@ -156,6 +161,7 @@ ADF::update (double delta_time_sec)
double range_nm = adjust_range(_transmitter_pos.getElevationFt(),
altitude_m * SG_METER_TO_FEET,
_transmitter_range_nm);
if (distance_nm <= range_nm) {
double bearing, az2, s;
@ -171,9 +177,9 @@ ADF::update (double delta_time_sec)
set_bearing(delta_time_sec, bearing);
// adf ident sound
double volume;
float volume;
if ( _ident_audible_node->getBoolValue() )
volume = _volume_node->getDoubleValue();
volume = _volume_node->getFloatValue();
else
volume = 0.0;
@ -181,7 +187,7 @@ ADF::update (double delta_time_sec)
_last_volume = volume;
SGSoundSample *sound;
sound = globals->get_soundmgr()->find( _adf_ident );
sound = _sgr->find( _adf_ident );
if ( sound != NULL )
sound->set_volume( volume );
else
@ -195,8 +201,8 @@ ADF::update (double delta_time_sec)
}
if ( _ident_count < 4 ) {
if ( !globals->get_soundmgr()->is_playing(_adf_ident) ) {
globals->get_soundmgr()->play_once( _adf_ident );
if ( !_sgr->is_playing(_adf_ident) && (volume > 0.05) ) {
_sgr->play_once( _adf_ident );
++_ident_count;
}
}
@ -204,7 +210,7 @@ ADF::update (double delta_time_sec)
_in_range_node->setBoolValue(false);
set_bearing(delta_time_sec, 90);
_ident_node->setStringValue("");
globals->get_soundmgr()->stop( _adf_ident );
_sgr->stop( _adf_ident );
}
}
@ -234,16 +240,16 @@ ADF::search (double frequency_khz, double longitude_rad,
_last_ident = ident;
_ident_node->setStringValue(ident.c_str());
if ( globals->get_soundmgr()->exists( _adf_ident ) ) {
if ( _sgr->exists( _adf_ident ) ) {
// stop is required! -- remove alone wouldn't stop immediately
globals->get_soundmgr()->stop( _adf_ident );
globals->get_soundmgr()->remove( _adf_ident );
_sgr->stop( _adf_ident );
_sgr->remove( _adf_ident );
}
SGSoundSample *sound;
sound = morse.make_ident( ident, LO_FREQUENCY );
sound->set_volume(_last_volume = 0);
globals->get_soundmgr()->add( sound, _adf_ident );
_sgr->add( sound, _adf_ident );
int offset = (int)(sg_random() * 30.0);
_ident_count = offset / 4;

View file

@ -21,6 +21,8 @@
using std::string;
class SGSampleGroup;
/**
* Model an ADF radio.
*
@ -93,8 +95,10 @@ private:
FGMorse morse;
int _ident_count;
time_t _last_ident_time;
double _last_volume;
float _last_volume;
string _adf_ident;
SGSharedPtr<SGSampleGroup> _sgr;
};

View file

@ -105,7 +105,8 @@ FGKR_87::FGKR_87( SGPropertyNode *node ) :
flight_timer(0.0),
elapsed_timer(0.0),
tmp_timer(0.0),
_time_before_search_sec(0)
_time_before_search_sec(0),
_sgr(NULL)
{
}
@ -116,6 +117,9 @@ FGKR_87::~FGKR_87() {
void FGKR_87::init () {
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("avionics", true);
_sgr->tie_to_listener();
morse.init();
}
@ -463,7 +467,7 @@ void FGKR_87::update( double dt_sec ) {
// otherwise turn it off
if ( vol_btn >= 0.01 && audio_btn ) {
SGSoundSample *sound;
sound = globals->get_soundmgr()->find( "adf-ident" );
sound = _sgr->find( "adf-ident" );
if ( sound != NULL ) {
if ( !adf_btn ) {
sound->set_volume( vol_btn );
@ -480,13 +484,13 @@ void FGKR_87::update( double dt_sec ) {
}
if ( play_count < 4 ) {
// play ADF ident
if ( !globals->get_soundmgr()->is_playing("adf-ident") ) {
globals->get_soundmgr()->play_once( "adf-ident" );
if ( !_sgr->is_playing("adf-ident") && (vol_btn > 0.05) ) {
_sgr->play_once( "adf-ident" );
++play_count;
}
}
} else {
globals->get_soundmgr()->stop( "adf-ident" );
_sgr->stop( "adf-ident" );
}
}
}
@ -527,13 +531,13 @@ void FGKR_87::search() {
effective_range = kludgeRange(stn_elev, pos.getElevationM(), range);
xyz = adf->cart();
if ( globals->get_soundmgr()->exists( "adf-ident" ) ) {
globals->get_soundmgr()->remove( "adf-ident" );
if ( _sgr->exists( "adf-ident" ) ) {
_sgr->remove( "adf-ident" );
}
SGSoundSample *sound;
sound = morse.make_ident( trans_ident, LO_FREQUENCY );
sound->set_volume( 0.3 );
globals->get_soundmgr()->add( sound, "adf-ident" );
_sgr->add( sound, "adf-ident" );
int offset = (int)(sg_random() * 30.0);
play_count = offset / 4;
@ -551,7 +555,7 @@ void FGKR_87::search() {
valid = false;
ident = "";
trans_ident = "";
globals->get_soundmgr()->remove( "adf-ident" );
_sgr->remove( "adf-ident" );
last_ident = "";
// cout << "not picking up adf. :-(" << endl;
}

View file

@ -34,6 +34,7 @@
#include <Navaids/navlist.hxx>
#include <Sound/morse.hxx>
class SGSampleGroup;
class FGKR_87 : public SGSubsystem
{
@ -104,6 +105,8 @@ class FGKR_87 : public SGSubsystem
// internal periodic station search timer
double _time_before_search_sec;
SGSharedPtr<SGSampleGroup> _sgr;
public:
FGKR_87( SGPropertyNode *node );

View file

@ -49,7 +49,8 @@ FGMarkerBeacon::FGMarkerBeacon(SGPropertyNode *node) :
inner_blink(false),
name("marker-beacon"),
num(0),
_time_before_search_sec(0.0)
_time_before_search_sec(0.0),
_sgr(NULL)
{
SGPath path( globals->get_fg_root() );
SGPath term = path;
@ -99,7 +100,7 @@ FGMarkerBeacon::init ()
SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
// Inputs
sound_pause = fgGetNode("/sim/sound/pause", false);
sound_working = fgGetNode("/sim/sound/working", true);
lon_node = fgGetNode("/position/longitude-deg", true);
lat_node = fgGetNode("/position/latitude-deg", true);
alt_node = fgGetNode("/position/altitude-ft", true);
@ -116,6 +117,10 @@ FGMarkerBeacon::init ()
if (serviceable->getType() == simgear::props::NONE)
serviceable->setBoolValue( true );
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("avionics", true);
_sgr->tie_to_listener();
morse.init();
beacon.init();
blink.stamp();
@ -171,7 +176,7 @@ FGMarkerBeacon::update(double dt)
}
if ( has_power() && serviceable->getBoolValue()
&& !sound_pause->getBoolValue()) {
&& sound_working->getBoolValue()) {
// marker beacon blinking
bool light_on = ( outer_blink || middle_blink || inner_blink );
@ -300,9 +305,9 @@ void FGMarkerBeacon::search()
if ( b == NULL || !inrange || !has_power() || !serviceable->getBoolValue() )
{
// cout << "no marker" << endl;
globals->get_soundmgr()->stop( "outer-marker" );
globals->get_soundmgr()->stop( "middle-marker" );
globals->get_soundmgr()->stop( "inner-marker" );
_sgr->stop( "outer-marker" );
_sgr->stop( "middle-marker" );
_sgr->stop( "inner-marker" );
} else {
string current_sound_name;
@ -312,63 +317,63 @@ void FGMarkerBeacon::search()
current_sound_name = "outer-marker";
// cout << "OUTER MARKER" << endl;
if ( last_beacon != OUTER ) {
if ( ! globals->get_soundmgr()->exists( current_sound_name ) ) {
if ( ! _sgr->exists( current_sound_name ) ) {
SGSoundSample *sound = beacon.get_outer();
if ( sound ) {
globals->get_soundmgr()->add( sound, current_sound_name );
_sgr->add( sound, current_sound_name );
}
}
}
if ( audio_btn->getBoolValue() ) {
if ( !globals->get_soundmgr()->is_playing(current_sound_name) ) {
globals->get_soundmgr()->play_looped( current_sound_name );
if ( !_sgr->is_playing(current_sound_name) ) {
_sgr->play_looped( current_sound_name );
}
} else {
globals->get_soundmgr()->stop( current_sound_name );
_sgr->stop( current_sound_name );
}
} else if ( beacon_type == MIDDLE ) {
middle_marker = true;
current_sound_name = "middle-marker";
// cout << "MIDDLE MARKER" << endl;
if ( last_beacon != MIDDLE ) {
if ( ! globals->get_soundmgr()->exists( current_sound_name ) ) {
if ( ! _sgr->exists( current_sound_name ) ) {
SGSoundSample *sound = beacon.get_middle();
if ( sound ) {
globals->get_soundmgr()->add( sound, current_sound_name );
_sgr->add( sound, current_sound_name );
}
}
}
if ( audio_btn->getBoolValue() ) {
if ( !globals->get_soundmgr()->is_playing(current_sound_name) ) {
globals->get_soundmgr()->play_looped( current_sound_name );
if ( !_sgr->is_playing(current_sound_name) ) {
_sgr->play_looped( current_sound_name );
}
} else {
globals->get_soundmgr()->stop( current_sound_name );
_sgr->stop( current_sound_name );
}
} else if ( beacon_type == INNER ) {
inner_marker = true;
current_sound_name = "inner-marker";
// cout << "INNER MARKER" << endl;
if ( last_beacon != INNER ) {
if ( ! globals->get_soundmgr()->exists( current_sound_name ) ) {
if ( ! _sgr->exists( current_sound_name ) ) {
SGSoundSample *sound = beacon.get_inner();
if ( sound ) {
globals->get_soundmgr()->add( sound, current_sound_name );
_sgr->add( sound, current_sound_name );
}
}
}
if ( audio_btn->getBoolValue() ) {
if ( !globals->get_soundmgr()->is_playing(current_sound_name) ) {
globals->get_soundmgr()->play_looped( current_sound_name );
if ( !_sgr->is_playing(current_sound_name) ) {
_sgr->play_looped( current_sound_name );
}
} else {
globals->get_soundmgr()->stop( current_sound_name );
_sgr->stop( current_sound_name );
}
}
// cout << "VOLUME " << audio_vol->getDoubleValue() << endl;
SGSoundSample * mkr = globals->get_soundmgr()->find( current_sound_name );
SGSoundSample * mkr = _sgr->find( current_sound_name );
if (mkr)
mkr->set_volume( audio_vol->getDoubleValue() );
mkr->set_volume( audio_vol->getFloatValue() );
}
if ( inrange ) {

View file

@ -35,6 +35,7 @@
#include <Sound/beacon.hxx>
#include <Sound/morse.hxx>
class SGSampleGroup;
class FGMarkerBeacon : public SGSubsystem
{
@ -54,7 +55,7 @@ class FGMarkerBeacon : public SGSubsystem
SGPropertyNode_ptr audio_btn;
SGPropertyNode_ptr audio_vol;
SGPropertyNode_ptr serviceable;
SGPropertyNode_ptr sound_pause;
SGPropertyNode_ptr sound_working;
bool need_update;
@ -73,6 +74,8 @@ class FGMarkerBeacon : public SGSubsystem
// internal periodic station search timer
double _time_before_search_sec;
SGSharedPtr<SGSampleGroup> _sgr;
public:
enum fgMkrBeacType {

View file

@ -2106,34 +2106,17 @@ MK_VIII::VoicePlayer::Speaker::bind (SGPropertyNode *node)
// uses xmlsound property names
tie(node, "volume", &volume);
tie(node, "pitch", &pitch);
tie(node, "position/x", &position[0]);
tie(node, "position/y", &position[1]);
tie(node, "position/z", &position[2]);
tie(node, "orientation/x", &orientation[0]);
tie(node, "orientation/y", &orientation[1]);
tie(node, "orientation/z", &orientation[2]);
tie(node, "orientation/inner-cone", &inner_cone);
tie(node, "orientation/outer-cone", &outer_cone);
tie(node, "reference-dist", &reference_dist);
tie(node, "max-dist", &max_dist);
}
void
MK_VIII::VoicePlayer::Speaker::update_configuration ()
{
map<string, SGSoundSample *>::iterator iter;
map< string, SGSharedPtr<SGSoundSample> >::iterator iter;
for (iter = player->samples.begin(); iter != player->samples.end(); iter++)
{
SGSoundSample *sample = (*iter).second;
sample->set_pitch(pitch);
sample->set_offset_pos(position);
sample->set_orientation(orientation,
inner_cone,
outer_cone,
outer_gain);
sample->set_reference_dist(reference_dist);
sample->set_max_dist(max_dist);
}
if (player->voice)
@ -2172,7 +2155,7 @@ MK_VIII::VoicePlayer::Voice::stop (bool now)
}
void
MK_VIII::VoicePlayer::Voice::set_volume (double _volume)
MK_VIII::VoicePlayer::Voice::set_volume (float _volume)
{
volume = _volume;
volume_changed();
@ -2209,15 +2192,6 @@ MK_VIII::VoicePlayer::~VoicePlayer ()
for (iter1 = _voices.begin(); iter1 != _voices.end(); iter1++)
delete *iter1;
_voices.clear();
/* sound mgr already destroyed - samples already deleted
map<string, SGSoundSample *>::iterator iter2;
for (iter2 = samples.begin(); iter2 != samples.end(); iter2++)
{
bool status = globals->get_soundmgr()->remove((*iter2).first);
assert(status);
}
*/
samples.clear();
}
@ -2226,6 +2200,10 @@ MK_VIII::VoicePlayer::init ()
{
#define STDPAUSE 0.75 // [SPEC] 6.4.4: "the standard 0.75 second delay"
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("avionics", true);
_sgr->tie_to_listener();
make_voice(&voices.application_data_base_failed, "application-data-base-failed");
make_voice(&voices.bank_angle, "bank-angle");
make_voice(&voices.bank_angle_bank_angle, "bank-angle", "bank-angle");
@ -2270,13 +2248,7 @@ MK_VIII::VoicePlayer::get_sample (const char *name)
std::ostringstream refname;
refname << mk->name << "[" << mk->num << "]" << "/" << name;
SGSoundMgr *soundmgr = globals->get_soundmgr();
if (soundmgr->is_working() == false)
{
return NULL;
}
SGSoundSample *sample = soundmgr->find(refname.str());
SGSoundSample *sample = _sgr->find(refname.str());
if (! sample)
{
SGPath sample_path(globals->get_fg_root());
@ -2293,7 +2265,7 @@ MK_VIII::VoicePlayer::get_sample (const char *name)
exit(1);
}
soundmgr->add(sample, refname.str());
_sgr->add(sample, refname.str());
samples[refname.str()] = sample;
}
@ -2338,7 +2310,7 @@ MK_VIII::VoicePlayer::stop (unsigned int flags)
}
void
MK_VIII::VoicePlayer::set_volume (double _volume)
MK_VIII::VoicePlayer::set_volume (float _volume)
{
volume = _volume;
if (voice)
@ -4130,7 +4102,7 @@ MK_VIII::Mode6Handler::leave_takeoff ()
}
void
MK_VIII::Mode6Handler::set_volume (double volume)
MK_VIII::Mode6Handler::set_volume (float volume)
{
mk_voice(minimums_minimums)->set_volume(volume);
mk_voice(five_hundred_above)->set_volume(volume);

View file

@ -36,6 +36,8 @@ using std::vector;
using std::deque;
using std::map;
class SGSampleGroup;
#include <Airports/runways.hxx>
#include <Airports/simple.hxx>
#include <Main/globals.hxx>
@ -733,10 +735,10 @@ public:
public:
bool silence;
virtual inline void play (double volume) {}
virtual inline void play (float volume) {}
virtual inline void stop () {}
virtual bool is_playing () = 0;
virtual inline void set_volume (double volume) {}
virtual inline void set_volume (float volume) {}
};
/////////////////////////////////////////////////////////////////////////
@ -745,17 +747,17 @@ public:
class SampleElement : public Element
{
SGSoundSample *_sample;
double _volume;
SGSharedPtr<SGSoundSample> _sample;
float _volume;
public:
inline SampleElement (SGSoundSample *sample, double volume = 1.0)
inline SampleElement (SGSharedPtr<SGSoundSample> sample, float volume = 1.0)
: _sample(sample), _volume(volume) { silence = false; }
virtual inline void play (double volume) { if (_sample) { set_volume(volume); _sample->play_once(); } }
virtual inline void play (float volume) { if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); } }
virtual inline void stop () { if (_sample) _sample->stop(); }
virtual inline bool is_playing () { return _sample ? _sample->is_playing() : false; }
virtual inline void set_volume (double volume) { if (_sample) _sample->set_volume(volume * _volume); }
virtual inline void set_volume (float volume) { if (_sample) _sample->set_volume(volume * _volume); }
};
/////////////////////////////////////////////////////////////////////////
@ -771,7 +773,7 @@ public:
inline SilenceElement (double duration)
: _duration(duration) { silence = true; }
virtual inline void play (double volume) { start_time = globals->get_sim_time_sec(); }
virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
};
@ -790,19 +792,19 @@ public:
void play ();
void stop (bool now);
void set_volume (double _volume);
void set_volume (float _volume);
void volume_changed ();
void update ();
private:
VoicePlayer *player;
double volume;
float volume;
vector<Element *> elements;
vector<Element *>::iterator iter;
inline double get_volume () const { return player->volume * player->speaker.volume * volume; }
inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
};
///////////////////////////////////////////////////////////////////////////
@ -811,10 +813,10 @@ public:
struct
{
double volume;
float volume;
} conf;
double volume;
float volume;
Voice *voice;
Voice *next_voice;
@ -871,7 +873,7 @@ public:
};
void stop (unsigned int flags = 0);
void set_volume (double _volume);
void set_volume (float _volume);
void update ();
inline void bind (SGPropertyNode *node) { speaker.bind(node); }
@ -887,13 +889,6 @@ public:
VoicePlayer *player;
double pitch;
float position[3];
float orientation[3];
float inner_cone;
float outer_cone;
float outer_gain;
float reference_dist;
float max_dist;
template <class T>
inline void tie (SGPropertyNode *node, const char *name, T *ptr)
@ -913,20 +908,13 @@ public:
template <class T>
inline T get_property (T *ptr) const { return *ptr; }
double volume;
float volume;
inline Speaker (VoicePlayer *_player)
: player(_player),
pitch(1),
inner_cone(360),
outer_cone(360),
outer_gain(0),
reference_dist(3),
max_dist(10),
volume(1)
{
position[0] = 0; position[1] = 0; position[2] = 0;
orientation[0] = 0; orientation[1] = 0; orientation[2] = 0;
}
void bind (SGPropertyNode *node);
@ -940,9 +928,10 @@ public:
MK_VIII *mk;
SGSharedPtr<SGSampleGroup> _sgr;
Speaker speaker;
map<string, SGSoundSample *> samples;
map< string, SGSharedPtr<SGSoundSample> > samples;
vector<Voice *> _voices;
bool looped;
@ -1465,7 +1454,7 @@ private:
void power_off ();
void enter_takeoff ();
void leave_takeoff ();
void set_volume (double volume);
void set_volume (float volume);
bool altitude_callouts_enabled ();
void update ();

View file

@ -156,7 +156,8 @@ FGNavRadio::FGNavRadio(SGPropertyNode *node) :
_name(node->getStringValue("name", "nav")),
_num(node->getIntValue("number", 0)),
_time_before_search_sec(-1.0),
_falseCoursesEnabled(true)
_falseCoursesEnabled(true),
_sgr(NULL)
{
SGPath path( globals->get_fg_root() );
SGPath term = path;
@ -184,6 +185,10 @@ FGNavRadio::~FGNavRadio()
void
FGNavRadio::init ()
{
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("avionics", true);
_sgr->tie_to_listener();
morse.init();
string branch;
@ -575,6 +580,8 @@ void FGNavRadio::updateGlideSlope(double dt, const SGVec3d& aircraft, double sig
if (!_gs || !inrange_node->getBoolValue()) {
gs_dist_node->setDoubleValue( 0.0 );
gs_inrange_node->setBoolValue(false);
_gsNeedleDeflection = 0.0;
_gsNeedleDeflectionNorm = 0.0;
return;
}
@ -584,6 +591,8 @@ void FGNavRadio::updateGlideSlope(double dt, const SGVec3d& aircraft, double sig
gs_inrange_node->setBoolValue(gsInRange);
if (!gsInRange) {
_gsNeedleDeflection = 0.0;
_gsNeedleDeflectionNorm = 0.0;
return;
}
@ -790,17 +799,17 @@ void FGNavRadio::updateAudio()
// play station ident via audio system if on + ident,
// otherwise turn it off
if (!power_btn_node->getBoolValue()
if (!power_btn_node->getBoolValue()
|| !(bus_power_node->getDoubleValue() > 1.0)
|| !ident_btn_node->getBoolValue()
|| !audio_btn_node->getBoolValue() ) {
globals->get_soundmgr()->stop( nav_fx_name );
globals->get_soundmgr()->stop( dme_fx_name );
_sgr->stop( nav_fx_name );
_sgr->stop( dme_fx_name );
return;
}
SGSoundSample *sound = globals->get_soundmgr()->find( nav_fx_name );
double vol = vol_btn_node->getDoubleValue();
SGSoundSample *sound = _sgr->find( nav_fx_name );
double vol = vol_btn_node->getFloatValue();
SG_CLAMP_RANGE(vol, 0.0, 1.0);
if ( sound != NULL ) {
@ -809,7 +818,7 @@ void FGNavRadio::updateAudio()
SG_LOG( SG_COCKPIT, SG_ALERT, "Can't find nav-vor-ident sound" );
}
sound = globals->get_soundmgr()->find( dme_fx_name );
sound = _sgr->find( dme_fx_name );
if ( sound != NULL ) {
sound->set_volume( vol );
} else {
@ -832,16 +841,16 @@ void FGNavRadio::updateAudio()
play_count = ++play_count % NUM_IDENT_SLOTS;
// Previous ident is out of time; if still playing, cut it off:
globals->get_soundmgr()->stop( nav_fx_name );
globals->get_soundmgr()->stop( dme_fx_name );
_sgr->stop( nav_fx_name );
_sgr->stop( dme_fx_name );
if (play_count == 0) { // the DME slot
if (_dmeInRange && dme_serviceable_node->getBoolValue()) {
// play DME ident
globals->get_soundmgr()->play_once( dme_fx_name );
if (vol > 0.05) _sgr->play_once( dme_fx_name );
}
} else { // NAV slot
if (inrange_node->getBoolValue() && nav_serviceable_node->getBoolValue()) {
globals->get_soundmgr()->play_once(nav_fx_name);
if (vol > 0.05) _sgr->play_once(nav_fx_name);
}
}
}
@ -924,8 +933,9 @@ void FGNavRadio::search()
_gs = NULL;
_dme = NULL;
nav_id_node->setStringValue("");
globals->get_soundmgr()->remove( nav_fx_name );
globals->get_soundmgr()->remove( dme_fx_name );
_sgr->remove( nav_fx_name );
_sgr->remove( dme_fx_name );
}
is_valid_node->setBoolValue(nav != NULL);
@ -967,25 +977,25 @@ double FGNavRadio::localizerWidth(FGNavRecord* aLOC)
void FGNavRadio::audioNavidChanged()
{
if ( globals->get_soundmgr()->exists(nav_fx_name)) {
globals->get_soundmgr()->remove(nav_fx_name);
if (_sgr->exists(nav_fx_name)) {
_sgr->remove(nav_fx_name);
}
try {
string trans_ident(_navaid->get_trans_ident());
SGSoundSample* sound = morse.make_ident(trans_ident, LO_FREQUENCY);
sound->set_volume( 0.3 );
if (!globals->get_soundmgr()->add( sound, nav_fx_name )) {
if (!_sgr->add( sound, nav_fx_name )) {
SG_LOG(SG_COCKPIT, SG_WARN, "Failed to add v1-vor-ident sound");
}
if ( globals->get_soundmgr()->exists( dme_fx_name ) ) {
globals->get_soundmgr()->remove( dme_fx_name );
if ( _sgr->exists( dme_fx_name ) ) {
_sgr->remove( dme_fx_name );
}
sound = morse.make_ident( trans_ident, HI_FREQUENCY );
sound->set_volume( 0.3 );
globals->get_soundmgr()->add( sound, dme_fx_name );
_sgr->add( sound, dme_fx_name );
int offset = (int)(sg_random() * 30.0);
play_count = offset / 4;

View file

@ -35,6 +35,7 @@
// forward decls
class SGInterpTable;
class SGSampleGroup;
class FGNavRecord;
typedef SGSharedPtr<FGNavRecord> FGNavRecordPtr;
@ -162,6 +163,8 @@ class FGNavRadio : public SGSubsystem
// realism setting, are false courses and GS lobes enabled?
bool _falseCoursesEnabled;
SGSharedPtr<SGSampleGroup> _sgr;
bool updateWithPower(double aDt);

View file

@ -20,6 +20,7 @@
#include <simgear/structure/commands.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <Cockpit/panel.hxx>
#include <Cockpit/panel_io.hxx>
@ -33,7 +34,7 @@
#include <Scenery/tilemgr.hxx>
#include <Scenery/scenery.hxx>
#include <Scripting/NasalSys.hxx>
#include <Sound/fg_fx.hxx>
#include <Sound/sample_queue.hxx>
#include <Time/sunsolver.hxx>
#include <Time/tmp.hxx>
@ -1251,13 +1252,22 @@ do_set_cursor (const SGPropertyNode * arg)
static bool
do_play_audio_sample (const SGPropertyNode * arg)
{
FGFX *fx = (FGFX *)globals->get_subsystem("fx");
string path = arg->getStringValue("path");
string file = arg->getStringValue("file");
double volume = arg->getDoubleValue("volume");
float volume = arg->getFloatValue("volume");
// cout << "playing " << path << " / " << file << endl;
try {
fx->play_message( path, file, volume );
static FGSampleQueue *queue = 0;
if ( !queue ) {
SGSoundMgr *smgr = globals->get_soundmgr();
queue = new FGSampleQueue(smgr, "chatter");
queue->tie_to_listener();
}
SGSoundSample *msg = new SGSoundSample(path.c_str(), file.c_str());
msg->set_volume( volume );
queue->add( msg );
return true;
} catch (const sg_io_exception&) {

View file

@ -58,6 +58,7 @@
#include <simgear/misc/interpolator.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/model/particles.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/timing/sg_time.hxx>
#include <simgear/timing/lowleveltime.h>
@ -106,9 +107,6 @@
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Scripting/NasalSys.hxx>
#include <Sound/fg_fx.hxx>
#include <Sound/beacon.hxx>
#include <Sound/morse.hxx>
#include <Sound/voice.hxx>
#include <Systems/system_mgr.hxx>
#include <Time/light.hxx>
@ -138,9 +136,7 @@
using std::string;
class Sound;
extern const char *default_root;
float init_volume;
// Scan the command line options for the specified option and return
@ -1456,6 +1452,21 @@ bool fgInitSubsystems() {
globals->get_event_mgr()->init();
globals->get_event_mgr()->setRealtimeProperty(fgGetNode("/sim/time/delta-realtime-sec", true));
////////////////////////////////////////////////////////////////////
// Initialize the sound manager subsystem.
////////////////////////////////////////////////////////////////////
globals->get_soundmgr()->bind();
globals->get_soundmgr()->init(fgGetString("/sim/sound/device-name", NULL));
vector <const char*>devices =
globals->get_soundmgr()->get_available_devices();
for (unsigned int i=0; i<devices.size(); i++) {
SGPropertyNode *p = fgGetNode("/sim/sound/devices/device", i, true);
p->setStringValue(devices[i]);
}
devices.clear();
////////////////////////////////////////////////////////////////////
// Initialize the property interpolator subsystem. Put into the INIT
// group because the "nasal" subsystem may need it at GENERAL take-down.
@ -1524,7 +1535,6 @@ bool fgInitSubsystems() {
// Initialize the ridgelift subsystem
globals->add_subsystem("ridgelift", new FGRidgeLift);
////////////////////////////////////////////////////////////////////
// Initialize the aircraft systems and instrumentation (before the
// autopilot.)
@ -1587,22 +1597,9 @@ bool fgInitSubsystems() {
fgGetBool("/sim/rendering/bump-mapping", false);
#ifdef ENABLE_AUDIO_SUPPORT
////////////////////////////////////////////////////////////////////
// Initialize the sound subsystem.
////////////////////////////////////////////////////////////////////
init_volume = fgGetFloat("/sim/sound/volume");
fgSetFloat("/sim/sound/volume", 0.0f);
globals->set_soundmgr(new SGSoundMgr);
globals->get_soundmgr()->init();
globals->get_soundmgr()->bind();
////////////////////////////////////////////////////////////////////
// Initialize the sound-effects subsystem.
////////////////////////////////////////////////////////////////////
globals->add_subsystem("fx", new FGFX);
globals->add_subsystem("voice", new FGVoiceMgr);
#endif
@ -1685,6 +1682,7 @@ bool fgInitSubsystems() {
////////////////////////////////////////////////////////////////////
globals->add_subsystem("replay", new FGReplay);
////////////////////////////////////////////////////////////////////
// Bind and initialize subsystems.
////////////////////////////////////////////////////////////////////

View file

@ -222,12 +222,12 @@ setFreeze (bool f)
frozen = f;
// Stop sound on a pause
SGSoundMgr *s = globals->get_soundmgr();
if ( s != NULL ) {
SGSoundMgr *smgr = globals->get_soundmgr();
if ( smgr != NULL ) {
if ( f ) {
s->pause();
} else if (!fgGetBool("/sim/sound/pause")) {
s->resume();
smgr->suspend();
} else if (fgGetBool("/sim/sound/working")) {
smgr->resume();
}
}
}

View file

@ -15,8 +15,8 @@
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
@ -24,7 +24,6 @@
# include <config.h>
#endif
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/timing/sg_time.hxx>
@ -33,6 +32,7 @@
#include <simgear/scene/material/matlib.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <Aircraft/controls.hxx>
#include <Airports/runways.hxx>
@ -73,6 +73,7 @@ FGGlobals::FGGlobals() :
renderer( new FGRenderer ),
subsystem_mgr( new SGSubsystemMgr ),
event_mgr( new SGEventMgr ),
soundmgr( new SGSoundMgr ),
sim_time_sec( 0.0 ),
fg_root( "" ),
warp( 0 ),
@ -83,7 +84,6 @@ FGGlobals::FGGlobals() :
matlib( NULL ),
route_mgr( NULL ),
current_panel( NULL ),
soundmgr( NULL ),
ATC_mgr( NULL ),
AI_mgr( NULL ),
controls( NULL ),
@ -127,6 +127,7 @@ FGGlobals::~FGGlobals()
// deleted subsystems.
subsystem_mgr->get_group(SGSubsystemMgr::GENERAL)->remove_subsystem("input");
subsystem_mgr->get_group(SGSubsystemMgr::GENERAL)->remove_subsystem("gui");
subsystem_mgr->unbind();
delete subsystem_mgr;
delete event_mgr;
delete time_params;
@ -135,7 +136,6 @@ FGGlobals::~FGGlobals()
delete matlib;
delete route_mgr;
delete current_panel;
delete soundmgr;
delete ATC_mgr;
delete AI_mgr;
@ -160,6 +160,9 @@ FGGlobals::~FGGlobals()
delete channellist;
delete airwaynet;
delete multiplayer_mgr;
soundmgr->unbind();
delete soundmgr;
}
@ -261,6 +264,11 @@ FGGlobals::add_subsystem (const char * name,
subsystem_mgr->add(name, subsystem, type, min_time_sec);
}
SGSoundMgr *
FGGlobals::get_soundmgr () const
{
return soundmgr;
}
SGEventMgr *
FGGlobals::get_event_mgr () const

View file

@ -49,10 +49,10 @@ class SGMagVar;
class SGMaterialLib;
class SGPropertyNode;
class SGTime;
class SGSoundMgr;
class SGEventMgr;
class SGSubsystemMgr;
class SGSubsystem;
class SGSoundMgr;
class FGAIMgr;
class FGATCMgr;
@ -94,6 +94,7 @@ private:
FGRenderer *renderer;
SGSubsystemMgr *subsystem_mgr;
SGEventMgr *event_mgr;
SGSoundMgr *soundmgr;
// Number of milliseconds elapsed since the start of the program.
double sim_time_sec;
@ -132,9 +133,6 @@ private:
// 2D panel
FGPanel *current_panel;
// sound manager
SGSoundMgr *soundmgr;
// ATC manager
FGATCMgr *ATC_mgr;
@ -202,6 +200,8 @@ public:
virtual SGEventMgr *get_event_mgr () const;
virtual SGSoundMgr *get_soundmgr () const;
inline double get_sim_time_sec () const { return sim_time_sec; }
inline void inc_sim_time_sec (double dt) { sim_time_sec += dt; }
inline void set_sim_time_sec (double t) { sim_time_sec = t; }
@ -244,9 +244,6 @@ public:
inline FGPanel *get_current_panel() const { return current_panel; }
inline void set_current_panel( FGPanel *cp ) { current_panel = cp; }
inline SGSoundMgr *get_soundmgr() const { return soundmgr; }
inline void set_soundmgr( SGSoundMgr *sm ) { soundmgr = sm; }
inline FGControls *get_controls() const { return controls; }
inline void set_controls( FGControls *c ) { controls = c; }
@ -305,7 +302,7 @@ public:
inline void set_tile_mgr ( FGTileMgr *t ) { tile_mgr = t; }
inline FGFontCache *get_fontcache() const { return fontcache; }
inline FGNavList *get_navlist() const { return navlist; }
inline void set_navlist( FGNavList *n ) { navlist = n; }
inline FGNavList *get_loclist() const { return loclist; }

View file

@ -61,6 +61,7 @@
#include <Model/acmodel.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Sound/fg_fx.hxx>
#include <Sound/beacon.hxx>
#include <Sound/morse.hxx>
#include <Sound/fg_fx.hxx>
@ -86,7 +87,6 @@
static double real_delta_time_sec = 0.0;
double delta_time_sec = 0.0;
extern float init_volume;
using namespace flightgear;
@ -104,6 +104,8 @@ long global_multi_loop;
SGTimeStamp last_time_stamp;
SGTimeStamp current_time_stamp;
void fgSetNewSoundDevice(const char *);
// The atexit() function handler should know when the graphical subsystem
// is initialized.
extern int _bootstrap_OSInit;
@ -460,8 +462,8 @@ static void fgMainLoop( void ) {
// we may want to move this to its own class at some point
//
double visibility_meters = fgGetDouble("/environment/visibility-m");
globals->get_tile_mgr()->prep_ssg_nodes( visibility_meters );
// update tile manager for view...
SGVec3d viewPos = globals->get_current_view()->get_view_pos();
SGGeod geodViewPos = SGGeod::fromCart(viewPos);
@ -477,10 +479,26 @@ static void fgMainLoop( void ) {
// update the view angle as late as possible, but before sound calculations
globals->get_viewmgr()->update(real_delta_time_sec);
// Run audio scheduler
// Update the sound manager last so it can use the CPU while the GPU
// is processing the scenery (doubled the frame-rate for me) -EMH-
#ifdef ENABLE_AUDIO_SUPPORT
FGFX* fx = (FGFX*) globals->get_subsystem("fx");
fx->update_fx_late(delta_time_sec);
static SGPropertyNode *sound_enabled = fgGetNode("/sim/sound/enabled");
static SGSoundMgr *smgr = globals->get_soundmgr();
static bool smgr_enabled = true;
if (smgr_enabled != sound_enabled->getBoolValue()) {
if (smgr_enabled == true) { // request to suspend
smgr->suspend();
} else {
smgr->resume();
}
smgr_enabled = sound_enabled->getBoolValue();
}
if (smgr_enabled == true) {
static SGPropertyNode *volume = fgGetNode("/sim/sound/volume");
smgr->set_volume(volume->getFloatValue());
smgr->update(delta_time_sec);
}
#endif
// END Tile Manager udpates
@ -488,8 +506,13 @@ static void fgMainLoop( void ) {
if (!scenery_loaded && globals->get_tile_mgr()->isSceneryLoaded()
&& cur_fdm_state->get_inited()) {
fgSetBool("sim/sceneryloaded",true);
fgSetFloat("/sim/sound/volume", init_volume);
globals->get_soundmgr()->set_volume(init_volume);
if (fgGetBool("/sim/sound/working")) {
smgr->activate();
} else {
smgr->stop();
}
globals->get_props()->tie("/sim/sound/devices/name",
SGRawValueFunctions<const char *>(0, fgSetNewSoundDevice), false);
}
fgRequestRedraw();
@ -497,6 +520,14 @@ static void fgMainLoop( void ) {
SG_LOG( SG_ALL, SG_DEBUG, "" );
}
void fgSetNewSoundDevice(const char *device)
{
globals->get_soundmgr()->suspend();
globals->get_soundmgr()->stop();
globals->get_soundmgr()->init(device);
globals->get_soundmgr()->resume();
}
// Operation for querying OpenGL parameters. This must be done in a
// valid OpenGL context, potentially in another thread.
namespace
@ -627,6 +658,7 @@ static void fgIdleFunction ( void ) {
} else if ( idle_state == 5 ) {
idle_state++;
////////////////////////////////////////////////////////////////////
// Initialize the 3D aircraft model subsystem (has a dependency on
// the scenery subsystem.)
@ -723,13 +755,13 @@ static void fgIdleFunction ( void ) {
SG_LOG( SG_GENERAL, SG_INFO,
"Starting intro music: " << mp3file.str() );
#if defined( __CYGWIN__ )
# if defined( __CYGWIN__ )
string command = "start /m `cygpath -w " + mp3file.str() + "`";
#elif defined( WIN32 )
# elif defined( WIN32 )
string command = "start /m " + mp3file.str();
#else
# else
string command = "mpg123 " + mp3file.str() + "> /dev/null 2>&1";
#endif
# endif
system ( command.c_str() );
}

View file

@ -45,6 +45,7 @@
#include <simgear/misc/sgstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/scene/material/mat.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
// #include <Include/general.hxx>
// #include <Airports/simple.hxx>
@ -81,7 +82,8 @@ enum
FG_OPTIONS_ERROR = 2,
FG_OPTIONS_EXIT = 3,
FG_OPTIONS_VERBOSE_HELP = 4,
FG_OPTIONS_SHOW_AIRCRAFT = 5
FG_OPTIONS_SHOW_AIRCRAFT = 5,
FG_OPTIONS_SHOW_SOUND_DEVICES = 6
};
static double
@ -186,7 +188,8 @@ fgSetDefaults ()
fgSetBool("/sim/hud/enable3d", true);
fgSetBool("/sim/hud/visibility", false);
fgSetBool("/sim/panel/visibility", true);
fgSetBool("/sim/sound/pause", false);
fgSetBool("/sim/sound/enabled", true);
fgSetBool("/sim/sound/working", true);
// Flight Model options
fgSetString("/sim/flight-model", "jsb");
@ -201,7 +204,7 @@ fgSetDefaults ()
fgSetBool("/sim/rendering/shading", true);
fgSetBool("/sim/rendering/skyblend", true);
fgSetBool("/sim/rendering/textures", true);
fgTie( "/sim/rendering/filtering", SGGetTextureFilter, SGSetTextureFilter, false);
fgTie( "/sim/rendering/filtering", SGGetTextureFilter, SGSetTextureFilter, false);
fgSetInt("/sim/rendering/filtering", 1);
fgSetBool("/sim/rendering/wireframe", false);
fgSetBool("/sim/rendering/horizon-effect", false);
@ -1290,8 +1293,9 @@ struct OptionDesc {
{"enable-hud", false, OPTION_BOOL, "/sim/hud/visibility", true, "", 0 },
{"disable-panel", false, OPTION_BOOL, "/sim/panel/visibility", false, "", 0 },
{"enable-panel", false, OPTION_BOOL, "/sim/panel/visibility", true, "", 0 },
{"disable-sound", false, OPTION_BOOL, "/sim/sound/pause", true, "", 0 },
{"enable-sound", false, OPTION_BOOL, "/sim/sound/pause", false, "", 0 },
{"disable-sound", false, OPTION_BOOL, "/sim/sound/working", false, "", 0 },
{"enable-sound", false, OPTION_BOOL, "/sim/sound/working", true, "", 0 },
{"sound-device", true, OPTION_STRING, "/sim/sound/device-name", false, "", 0 },
{"airport", true, OPTION_STRING, "/sim/presets/airport-id", false, "", 0 },
{"runway", true, OPTION_FUNC, "", false, "", fgOptRunway },
{"vor", true, OPTION_FUNC, "", false, "", fgOptVOR },
@ -1501,6 +1505,8 @@ parse_option (const string& arg)
return(FG_OPTIONS_VERBOSE_HELP);
} else if ( arg.find( "--show-aircraft") == 0) {
return(FG_OPTIONS_SHOW_AIRCRAFT);
} else if ( arg.find( "--show-sound-devices") == 0) {
return(FG_OPTIONS_SHOW_SOUND_DEVICES);
} else if ( arg.find( "--prop:" ) == 0 ) {
if (!set_property(arg.substr(7))) {
SG_LOG( SG_GENERAL, SG_ALERT, "Bad property assignment: " << arg );
@ -1616,11 +1622,20 @@ fgParseArgs (int argc, char **argv)
verbose = true;
else if (result == FG_OPTIONS_SHOW_AIRCRAFT) {
fgOptLogLevel( "alert" );
SGPath path( globals->get_fg_root() );
path.append("Aircraft");
fgShowAircraft(path, true);
exit(0);
fgOptLogLevel( "alert" );
SGPath path( globals->get_fg_root() );
path.append("Aircraft");
fgShowAircraft(path, true);
exit(0);
} else if (result == FG_OPTIONS_SHOW_SOUND_DEVICES) {
SGSoundMgr smgr;
vector <const char*>devices = smgr.get_available_devices();
for (int i=0; i<devices.size(); i++) {
printf("%i. \"%s\"\n", i, devices[i]);
}
devices.clear();
exit(0);
}
else if (result == FG_OPTIONS_EXIT)

View file

@ -380,7 +380,7 @@ FGViewer::recalcLookFrom ()
SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
// The rotation offset, don't know why heading is negative here ...
SGQuatd viewOffsetOr
mViewOffsetOr
= SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
_roll_offset_deg);
@ -396,7 +396,7 @@ FGViewer::recalcLookFrom ()
SGQuatd q(-0.5, -0.5, 0.5, 0.5);
_absolute_view_pos = position + (ec2body*q).backTransform(_offset_m);
mViewOrientation = ec2body*viewOffsetOr*q;
mViewOrientation = ec2body*mViewOffsetOr*q;
}
void
@ -437,7 +437,7 @@ FGViewer::recalcLookAt ()
SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(_position);
// the rotation offset, don't know why heading is negative here ...
SGQuatd eyeOffsetOr =
mViewOffsetOr =
SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
_roll_offset_deg);
@ -445,7 +445,7 @@ FGViewer::recalcLookAt ()
SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
SGVec3d eyeCart = SGVec3d::fromGeod(_position);
eyeCart += (ec2eye*eyeOffsetOr).backTransform(eyeOff);
eyeCart += (ec2eye*mViewOffsetOr).backTransform(eyeOff);
SGVec3d atCart = SGVec3d::fromGeod(_target);

View file

@ -119,6 +119,7 @@ public:
// orientation rotations listed below. This has the effect of the
// eye moving around and "looking at" the object (model) from
// different angles.
virtual SGVec3d getOffset_m () const { return _offset_m; }
virtual double getXOffset_m () const { return _offset_m.x(); }
virtual double getYOffset_m () const { return _offset_m.y(); }
virtual double getZOffset_m () const { return _offset_m.z(); }
@ -201,6 +202,7 @@ public:
const SGVec3d& get_view_pos() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
const SGVec3d& getViewPosition() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
const SGQuatd& getViewOrientation() { if ( _dirty ) { recalc(); } return mViewOrientation; }
const SGQuatd& getViewOrientationOffset() { if ( _dirty ) { recalc(); } return mViewOffsetOr; }
//////////////////////////////////////////////////////////////////////
// Part 4: View and frustrum data setters and getters
@ -247,6 +249,7 @@ private:
bool _dirty;
SGQuatd mViewOrientation;
SGQuatd mViewOffsetOr;
SGVec3d _absolute_view_pos;
SGGeod _position;

View file

@ -30,6 +30,7 @@
#include <string.h> // strcmp
#include <simgear/compiler.h>
#include <simgear/sound/soundmgr_openal.hxx>
#include <Model/acmodel.hxx>
#include <Main/viewer.hxx>
#include <Main/fg_props.hxx>
@ -42,6 +43,7 @@ FGViewMgr::FGViewMgr( void ) :
config_list(fgGetNode("/sim", true)->getChildren("view")),
current(0)
{
smgr = globals->get_soundmgr();
}
// Destructor
@ -214,6 +216,38 @@ FGViewMgr::bind ()
n->tie("viewer-x-m", SGRawValuePointer<double>(&abs_viewer_position[0]));
n->tie("viewer-y-m", SGRawValuePointer<double>(&abs_viewer_position[1]));
n->tie("viewer-z-m", SGRawValuePointer<double>(&abs_viewer_position[2]));
// for automatic untying:
#define x(str) ((void)tied_props.push_back(str), str)
fgTie(x("/sim/current-view/debug/orientation-w"), this,
&FGViewMgr::getCurrentViewOrientation_w);
fgTie(x("/sim/current-view/debug/orientation-x"), this,
&FGViewMgr::getCurrentViewOrientation_x);
fgTie(x("/sim/current-view/debug/orientation-y"), this,
&FGViewMgr::getCurrentViewOrientation_y);
fgTie(x("/sim/current-view/debug/orientation-z"), this,
&FGViewMgr::getCurrentViewOrientation_z);
fgTie(x("/sim/current-view/debug/orientation_offset-w"), this,
&FGViewMgr::getCurrentViewOrOffset_w);
fgTie(x("/sim/current-view/debug/orientation_offset-x"), this,
&FGViewMgr::getCurrentViewOrOffset_x);
fgTie(x("/sim/current-view/debug/orientation_offset-y"), this,
&FGViewMgr::getCurrentViewOrOffset_y);
fgTie(x("/sim/current-view/debug/orientation_offset-z"), this,
&FGViewMgr::getCurrentViewOrOffset_z);
fgTie(x("/sim/current-view/debug/frame-w"), this,
&FGViewMgr::getCurrentViewFrame_w);
fgTie(x("/sim/current-view/debug/frame-x"), this,
&FGViewMgr::getCurrentViewFrame_x);
fgTie(x("/sim/current-view/debug/frame-y"), this,
&FGViewMgr::getCurrentViewFrame_y);
fgTie(x("/sim/current-view/debug/frame-z"), this,
&FGViewMgr::getCurrentViewFrame_z);
#undef x
}
void
@ -234,16 +268,21 @@ FGViewMgr::unbind ()
fgUntie("/sim/current-view/viewer-x-m");
fgUntie("/sim/current-view/viewer-y-m");
fgUntie("/sim/current-view/viewer-z-m");
list<const char*>::const_iterator it;
for (it = tied_props.begin(); it != tied_props.end(); it++){
fgUntie(*it);
}
}
void
FGViewMgr::update (double dt)
{
FGViewer * view = get_current_view();
if (view == 0)
return;
FGViewer *loop_view = (FGViewer *)get_view(current);
FGViewer *loop_view = (FGViewer *)get_current_view();
if (loop_view == 0) return;
SGPropertyNode *n = config_list[current];
double lon_deg, lat_deg, alt_ft, roll_deg, pitch_deg, heading_deg;
@ -289,10 +328,25 @@ FGViewMgr::update (double dt)
setViewTargetYOffset_m(fgGetDouble("/sim/current-view/target-y-offset-m"));
setViewTargetZOffset_m(fgGetDouble("/sim/current-view/target-z-offset-m"));
current_view_orientation = loop_view->getViewOrientation();
current_view_or_offset = loop_view->getViewOrientationOffset();
// Update the current view
do_axes();
view->update(dt);
loop_view->update(dt);
abs_viewer_position = loop_view->getViewPosition();
// update audio listener values
// set the viewer posotion in Cartesian coordinates in meters
smgr->set_position( abs_viewer_position, loop_view->getPosition() );
smgr->set_orientation( current_view_orientation );
// get the model velocity
SGVec3d velocity = SGVec3d::zeros();
if ( !stationary() ) {
velocity = globals->get_aircraft_model()->getVelocity();
}
smgr->set_velocity( velocity );
}
void
@ -562,6 +616,20 @@ FGViewMgr::setViewZOffset_m (double z)
}
}
bool
FGViewMgr::stationary () const
{
const FGViewer * view = get_current_view();
if (view != 0) {
if (((FGViewer *)view)->getXOffset_m() == 0.0 &&
((FGViewer *)view)->getYOffset_m() == 0.0 &&
((FGViewer *)view)->getZOffset_m() == 0.0)
return true;
}
return false;
}
double
FGViewMgr::getViewTargetXOffset_m () const
{
@ -720,6 +788,101 @@ FGViewMgr::setViewAxisLat (double axis)
axis_lat = axis;
}
// reference frame orientation.
// This is the view orientation you get when you have no
// view offset, i.e. the offset operator is the identity.
//
// For example, in the familiar "cockpit lookfrom" view,
// the reference frame is equal to the aircraft attitude,
// i.e. it is the view looking towards 12:00 straight ahead.
//
// FIXME: Somebody needs to figure out what is the reference
// frame view for the other view modes.
//
// Conceptually, this quat represents a rotation relative
// to the ECEF reference orientation, as described at
// http://www.av8n.com/physics/coords.htm#sec-orientation
//
// See the NOTE concerning reference orientations, below.
//
// The components of this quat are expressed in
// the conventional aviation basis set,
// i.e. x=forward, y=starboard, z=bottom
double FGViewMgr::getCurrentViewFrame_w() const{
return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).w();
}
double FGViewMgr::getCurrentViewFrame_x() const{
return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).x();
}
double FGViewMgr::getCurrentViewFrame_y() const{
return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).y();
}
double FGViewMgr::getCurrentViewFrame_z() const{
return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).z();
}
// view offset.
// This rotation takes you from the aforementioned
// reference frame view orientation to whatever
// actual current view orientation is.
//
// The components of this quaternion are expressed in
// the conventional aviation basis set,
// i.e. x=forward, y=starboard, z=bottom
double FGViewMgr::getCurrentViewOrOffset_w() const{
return current_view_or_offset.w();
}
double FGViewMgr::getCurrentViewOrOffset_x() const{
return current_view_or_offset.x();
}
double FGViewMgr::getCurrentViewOrOffset_y() const{
return current_view_or_offset.y();
}
double FGViewMgr::getCurrentViewOrOffset_z() const{
return current_view_or_offset.z();
}
// current view orientation.
// This is a rotation relative to the earth-centered (ec)
// reference frame.
//
// NOTE: Here we remove a factor of fsb2sta so that
// the components of this quat are displayed using the
// conventional ECEF basis set. This is *not* the way
// the view orientation is stored in the views[] array,
// but is easier for non-graphics hackers to understand.
// If we did not remove this factor of fsb2sta here and
// in getCurrentViewFrame, that would be equivalent to
// the following peculiar reference orientation:
// Suppose you are over the Gulf of Guinea, at (lat,lon) = (0,0).
// Then the reference frame orientation can be achieved via:
// -- The aircraft X-axis (nose) headed south.
// -- The aircraft Y-axis (starboard wingtip) pointing up.
// -- The aircraft Z-axis (belly) pointing west.
// To say the same thing in other words, and perhaps more to the
// point: If we use the OpenGL camera orientation conventions,
// i.e. Xprime=starboard, Yprime=top, Zprime=aft, then the
// aforementioned peculiar reference orientation at (lat,lon)
// = (0,0) can be described as:
// -- aircraft Xprime axis (starboard) pointed up
// -- aircraft Yprime axis (top) pointed east
// -- aircraft Zprime axis (aft) pointed north
// meaning the OpenGL axes are aligned with the ECEF axes.
double FGViewMgr::getCurrentViewOrientation_w() const{
return (current_view_orientation * conj(fsb2sta())).w();
}
double FGViewMgr::getCurrentViewOrientation_x() const{
return (current_view_orientation * conj(fsb2sta())).x();
}
double FGViewMgr::getCurrentViewOrientation_y() const{
return (current_view_orientation * conj(fsb2sta())).y();
}
double FGViewMgr::getCurrentViewOrientation_z() const{
return (current_view_orientation * conj(fsb2sta())).z();
}
void
FGViewMgr::do_axes ()
{

View file

@ -25,6 +25,7 @@
#define _VIEWMGR_HXX
#include <vector>
#include <list>
#include <simgear/compiler.h>
#include <simgear/structure/subsystem_mgr.hxx>
@ -32,6 +33,7 @@
// forward decls
class FGViewer;
class SGSoundMgr;
typedef SGSharedPtr<FGViewer> FGViewerPtr;
// Define a structure containing view information
@ -75,6 +77,8 @@ public:
private:
list<const char*> tied_props;
double axis_long;
double axis_lat;
@ -116,6 +120,22 @@ private:
int getView () const;
void setView (int newview);
// quaternion accessors, for debugging:
double getCurrentViewOrientation_w() const;
double getCurrentViewOrientation_x() const;
double getCurrentViewOrientation_y() const;
double getCurrentViewOrientation_z() const;
double getCurrentViewOrOffset_w() const;
double getCurrentViewOrOffset_x() const;
double getCurrentViewOrOffset_y() const;
double getCurrentViewOrOffset_z() const;
double getCurrentViewFrame_w() const;
double getCurrentViewFrame_x() const;
double getCurrentViewFrame_y() const;
double getCurrentViewFrame_z() const;
bool stationary () const;
SGPropertyNode_ptr view_number;
vector<SGPropertyNode_ptr> config_list;
typedef std::vector<FGViewerPtr> viewer_list;
@ -123,8 +143,20 @@ private:
SGVec3d abs_viewer_position;
int current;
SGQuatd current_view_orientation, current_view_or_offset;
SGSoundMgr *smgr;
};
// This takes the conventional aviation XYZ body system
// i.e. x=forward, y=starboard, z=bottom
// which is widely used in FGFS
// and rotates it into the OpenGL camera system
// i.e. Xprime=starboard, Yprime=top, Zprime=aft.
inline const SGQuatd fsb2sta()
{
return SGQuatd(-0.5, -0.5, 0.5, 0.5);
}
#endif // _VIEWMGR_HXX

View file

@ -22,19 +22,35 @@
#include <Main/viewmgr.hxx>
#include <Main/viewer.hxx>
#include <Scenery/scenery.hxx>
#include <Sound/fg_fx.hxx>
#include "model_panel.hxx"
#include "acmodel.hxx"
////////////////////////////////////////////////////////////////////////
// Implementation of FGAircraftModel
////////////////////////////////////////////////////////////////////////
FGAircraftModel::FGAircraftModel ()
: _aircraft(0)
: _aircraft(0),
_velocity(SGVec3d::zeros()),
_fx(0),
_lon(0),
_lat(0),
_alt(0),
_pitch(0),
_roll(0),
_heading(0),
_speed_n(0),
_speed_e(0),
_speed_d(0)
{
SGSoundMgr *smgr = globals->get_soundmgr();
_fx = new FGFX(smgr, "fx");
_fx->init();
}
FGAircraftModel::~FGAircraftModel ()
@ -70,7 +86,15 @@ FGAircraftModel::init ()
void
FGAircraftModel::bind ()
{
// No-op
_lon = fgGetNode("position/longitude-deg", true);
_lat = fgGetNode("position/latitude-deg", true);
_alt = fgGetNode("position/altitude-ft", true);
_pitch = fgGetNode("orientation/pitch-deg", true);
_roll = fgGetNode("orientation/roll-deg", true);
_heading = fgGetNode("orientation/heading-deg", true);
_speed_n = fgGetNode("velocities/speed-north-fps", true);
_speed_e = fgGetNode("velocities/speed-east-fps", true);
_speed_d = fgGetNode("velocities/speed-down-fps", true);
}
void
@ -91,13 +115,27 @@ FGAircraftModel::update (double dt)
_aircraft->setVisible(true);
}
_aircraft->setPosition(fgGetDouble("/position/longitude-deg"),
fgGetDouble("/position/latitude-deg"),
fgGetDouble("/position/altitude-ft"));
_aircraft->setOrientation(fgGetDouble("/orientation/roll-deg"),
fgGetDouble("/orientation/pitch-deg"),
fgGetDouble("/orientation/heading-deg"));
_aircraft->setPosition(_lon->getDoubleValue(),
_lat->getDoubleValue(),
_alt->getDoubleValue());
_aircraft->setOrientation(_roll->getDoubleValue(),
_pitch->getDoubleValue(),
_heading->getDoubleValue());
_aircraft->update();
// update model's audio sample values
SGGeod position = _aircraft->getPosition();
_fx->set_position_geod( position );
SGQuatd orient = SGQuatd::fromYawPitchRollDeg(_heading->getDoubleValue(),
_pitch->getDoubleValue(),
_roll->getDoubleValue());
_fx->set_orientation( orient );
_velocity = SGVec3d( _speed_n->getDoubleValue(),
_speed_e->getDoubleValue(),
_speed_d->getDoubleValue() );
_fx->set_velocity( _velocity );
}

View file

@ -25,7 +25,7 @@ using std::vector;
// Don't pull in the headers, since we don't need them here.
class SGModelPlacement;
class FGFX;
class FGAircraftModel : public SGSubsystem
{
@ -39,10 +39,23 @@ public:
virtual void unbind ();
virtual void update (double dt);
virtual SGModelPlacement * get3DModel() { return _aircraft; }
virtual SGVec3d& getVelocity() { return _velocity; }
private:
SGModelPlacement * _aircraft;
SGVec3d _velocity;
SGSharedPtr<FGFX> _fx;
SGPropertyNode_ptr _lon;
SGPropertyNode_ptr _lat;
SGPropertyNode_ptr _alt;
SGPropertyNode_ptr _pitch;
SGPropertyNode_ptr _roll;
SGPropertyNode_ptr _heading;
SGPropertyNode_ptr _speed_n;
SGPropertyNode_ptr _speed_e;
SGPropertyNode_ptr _speed_d;
};
#endif // __ACMODEL_HXX

View file

@ -4,6 +4,7 @@ libSound_a_SOURCES = \
beacon.cxx beacon.hxx \
fg_fx.cxx fg_fx.hxx \
morse.cxx morse.hxx \
voice.cxx voice.hxx
voice.cxx voice.hxx \
sample_queue.cxx sample_queue.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src

View file

@ -21,11 +21,11 @@
// $Id$
#include <stdlib.h>
#include "beacon.hxx"
#include <simgear/structure/exception.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
// constructor
FGBeacon::FGBeacon()
@ -39,17 +39,12 @@ FGBeacon::~FGBeacon() {
// allocate and initialize sound samples
bool FGBeacon::init() {
int i;
int len;
unsigned char *ptr;
size_t i, len;
if (globals->get_soundmgr()->is_working() == false) {
return false;
}
unsigned char inner_buf[ INNER_SIZE ] ;
unsigned char middle_buf[ MIDDLE_SIZE ] ;
unsigned char outer_buf[ OUTER_SIZE ] ;
const unsigned char* inner_buf = (const unsigned char*)malloc( INNER_SIZE );
const unsigned char* middle_buf = (const unsigned char*)malloc(MIDDLE_SIZE);
const unsigned char* outer_buf = (const unsigned char*)malloc( OUTER_SIZE );
// Make inner marker beacon sound
len= (int)(INNER_DIT_LEN / 2.0 );
@ -57,14 +52,14 @@ bool FGBeacon::init() {
make_tone( inner_dit, INNER_FREQ, len, INNER_DIT_LEN,
TRANSITION_BYTES );
ptr = inner_buf;
ptr = (unsigned char*)inner_buf;
for ( i = 0; i < 6; ++i ) {
memcpy( ptr, inner_dit, INNER_DIT_LEN );
ptr += INNER_DIT_LEN;
}
try {
inner = new SGSoundSample( inner_buf, INNER_SIZE, BYTES_PER_SECOND );
inner = new SGSoundSample( &inner_buf, INNER_SIZE, BYTES_PER_SECOND );
inner->set_reference_dist( 10.0 );
inner->set_max_dist( 20.0 );
@ -79,12 +74,12 @@ bool FGBeacon::init() {
make_tone( middle_dah, MIDDLE_FREQ, len, MIDDLE_DAH_LEN,
TRANSITION_BYTES );
ptr = middle_buf;
ptr = (unsigned char*)middle_buf;
memcpy( ptr, middle_dit, MIDDLE_DIT_LEN );
ptr += MIDDLE_DIT_LEN;
memcpy( ptr, middle_dah, MIDDLE_DAH_LEN );
middle = new SGSoundSample( middle_buf, MIDDLE_SIZE, BYTES_PER_SECOND );
middle = new SGSoundSample( &middle_buf, MIDDLE_SIZE, BYTES_PER_SECOND);
middle->set_reference_dist( 10.0 );
middle->set_max_dist( 20.0 );
@ -94,12 +89,12 @@ bool FGBeacon::init() {
make_tone( outer_dah, OUTER_FREQ, len, OUTER_DAH_LEN,
TRANSITION_BYTES );
ptr = outer_buf;
ptr = (unsigned char*)outer_buf;
memcpy( ptr, outer_dah, OUTER_DAH_LEN );
ptr += OUTER_DAH_LEN;
memcpy( ptr, outer_dah, OUTER_DAH_LEN );
outer = new SGSoundSample( outer_buf, OUTER_SIZE, BYTES_PER_SECOND);
outer = new SGSoundSample( &outer_buf, OUTER_SIZE, BYTES_PER_SECOND );
outer->set_reference_dist( 10.0 );
outer->set_max_dist( 20.0 );
} catch ( sg_io_exception &e ) {

View file

@ -31,43 +31,38 @@
#include "fg_fx.hxx"
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/sound/xmlsound.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <Main/fg_props.hxx>
#include <simgear/scene/model/placement.hxx>
#include <Model/acmodel.hxx>
#include <Main/viewer.hxx>
#include <simgear/props/props.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/sound/xmlsound.hxx>
FGFX::FGFX () :
last_visitor_pos(SGVec3d::zeros()),
last_model_pos(SGVec3d::zeros()),
last_pause( true ),
last_volume( 0.0 ),
_pause( fgGetNode("/sim/sound/pause") ),
_volume( fgGetNode("/sim/sound/volume") )
FGFX::FGFX ( SGSoundMgr *smgr, const string &refname ) :
_enabled( fgGetNode("/sim/sound/effects/enabled", true) ),
_volume( fgGetNode("/sim/sound/effects/volume", true) ),
_avionics_enabled( fgGetNode("/sim/sound/avionics/enabled", true) ),
_avionics_volume( fgGetNode("/sim/sound/avionics/volume", true) ),
_avionics_external( fgGetNode("/sim/sound/avionics/external-view", true) ),
_internal( fgGetNode("/sim/current-view/internal", true) )
{
SGSampleGroup::_smgr = smgr;
SGSampleGroup::_refname = refname;
SGSampleGroup::_smgr->add(this, refname);
_avionics = _smgr->find("avionics", true);
_avionics->tie_to_listener();
}
FGFX::~FGFX ()
{
unsigned int i;
for ( i = 0; i < _sound.size(); i++ ) {
for (unsigned int i = 0; i < _sound.size(); i++ ) {
delete _sound[i];
}
_sound.clear();
while ( _samplequeue.size() > 0 ) {
delete _samplequeue.front();
_samplequeue.pop();
}
}
void
FGFX::init()
{
@ -99,8 +94,8 @@ FGFX::init()
SGXmlSound *sound = new SGXmlSound();
try {
sound->init(globals->get_props(), node->getChild(i),
globals->get_soundmgr(), globals->get_fg_root());
sound->init(globals->get_props(), node->getChild(i), this,
_avionics, globals->get_fg_root());
_sound.push_back(sound);
} catch ( sg_exception &e ) {
@ -111,192 +106,40 @@ FGFX::init()
}
}
void
FGFX::reinit()
{
_sound.clear();
init();
_sound.clear();
init();
};
void
FGFX::bind ()
{
}
void
FGFX::unbind ()
{
}
void
FGFX::update (double dt)
{
SGSoundMgr *smgr = globals->get_soundmgr();
bool active = _avionics_external->getBoolValue() ||
_internal->getBoolValue();
if (smgr->is_working() == false) {
return;
}
if ( active && _avionics_enabled->getBoolValue() )
_avionics->resume(); // no-op if already in resumed state
else
_avionics->suspend();
_avionics->set_volume( _avionics_volume->getFloatValue() );
// command sound manger
bool pause = _pause->getBoolValue();
if ( pause != last_pause ) {
if ( pause ) {
smgr->pause();
} else {
smgr->resume();
}
last_pause = pause;
}
if ( _enabled->getBoolValue() ) {
set_volume( _volume->getDoubleValue() );
resume();
// process mesage queue
const string msgid = "Sequential Audio Message";
bool is_playing = false;
if ( smgr->exists( msgid ) ) {
if ( smgr->is_playing( msgid ) ) {
// still playing, do nothing
is_playing = true;
} else {
// current message finished, stop and remove
smgr->stop( msgid ); // removes source
smgr->remove( msgid ); // removes buffer
}
}
if ( !is_playing ) {
// message queue idle, add next sound if we have one
if ( _samplequeue.size() > 0 ) {
smgr->add( _samplequeue.front(), msgid );
_samplequeue.pop();
smgr->play_once( msgid );
}
}
double volume = _volume->getDoubleValue();
if ( volume != last_volume ) {
smgr->set_volume( volume );
last_volume = volume;
}
if ( !pause ) {
// update sound effects if not paused
for ( unsigned int i = 0; i < _sound.size(); i++ ) {
_sound[i]->update(dt);
}
SGSampleGroup::update(dt);
}
}
void
FGFX::update_fx_late(double dt)
{
SGSoundMgr *smgr = globals->get_soundmgr();
if (!smgr->is_working()) {
return;
}
smgr->update(dt);
update_pos_and_orientation(smgr, dt);
}
/**
* add a sound sample to the message queue which is played sequentially
* in order.
*/
void
FGFX::play_message( SGSoundSample *_sample )
{
_samplequeue.push( _sample );
}
void
FGFX::play_message( const std::string& path, const std::string& fname, double volume )
{
if (globals->get_soundmgr()->is_working() == true) {
SGSoundSample *sample;
sample = new SGSoundSample( path.c_str(), fname.c_str() );
sample->set_volume( volume );
play_message( sample );
}
}
void
FGFX::update_pos_and_orientation(SGSoundMgr *smgr, double dt)
{
SGModelPlacement *model = globals->get_aircraft_model()->get3DModel();
FGViewer *observer = globals->get_current_view();
// Right now we make a simplifying assumption that the primary
// aircraft is the source of all sounds and that all sounds are
// positioned in the aircraft base
// EMH: Note: this is fine, to hear multiple aircraft simulataniously
// we just have to trigger one instance of the FGFX class for every
// aircraft
// get the orientation
const SGQuatd view_or = observer->getViewOrientation();
SGQuatd surf_or = SGQuatd::fromLonLat(observer->getPosition());
SGQuatd model_or = SGQuatd::fromYawPitchRollDeg(
model->getHeadingDeg(),
model->getPitchDeg(),
model->getRollDeg());
// get the up and at vector in the aircraft base
// (ok, the up vector is a down vector, but the coordinates
// are finally calculated in a left hand system and openal
// lives in a right hand system. Therefore we need to pass
// the down vector to get correct stereo sound.)
SGVec3d sgv_up
= model_or.rotateBack(surf_or.rotateBack(view_or.rotate(SGVec3d(0,1,0))));
SGVec3d sgv_at
= model_or.rotateBack(surf_or.rotateBack(view_or.rotate(SGVec3d(0,0,1))));
// get the location data for the primary FDM (now hardcoded to ac model)...
// EMH: to add multiple sound sources this should be replaced
SGVec3d absolute_view_pos = SGVec3d::fromGeod(model->getPosition());
// calculate speed of visitor and model
SGVec3d moved = last_visitor_pos - observer->get_view_pos();
last_visitor_pos = observer->get_view_pos();
SGVec3f listener_vel(model_or.rotateBack(surf_or.rotateBack(moved)));
moved = last_model_pos - absolute_view_pos;
last_model_pos = absolute_view_pos;
SGVec3f model_vel(model_or.rotateBack(surf_or.rotateBack(moved)));
if (dt > 0) {
model_vel /= dt;
listener_vel /= dt;
}
// checking, if the listener pos has moved suddenly
if (length(listener_vel) > 1000) {
// check if the relative speed model vs listener has moved suddenly, too
SGVec3f delta_vel = listener_vel - model_vel;
if (length(delta_vel) > 1000)
// a sane value
smgr->set_listener_vel(model_vel.data());
else
smgr->set_listener_vel(listener_vel.data());
} else {
smgr->set_listener_vel( listener_vel.data());
}
// set positional offset for sources
SGVec3d dsource_pos_offset = observer->get_view_pos() - absolute_view_pos;
dsource_pos_offset = model_or.rotateBack(surf_or.rotateBack(
dsource_pos_offset
));
smgr->set_source_pos_all( SGVec3f(dsource_pos_offset).data() );
smgr->set_source_vel_all(model_vel.data() );
float orient[6];
for (int i = 0; i < 3; i++) {
orient[i] = sgv_at[i];
orient[i + 3] = sgv_up[i];
}
smgr->set_listener_orientation( orient );
// The listener is always positioned at the origin.
smgr->set_listener_pos( SGVec3f::zeros().data() );
else
suspend();
}
// end of fg_fx.cxx

View file

@ -26,73 +26,46 @@
#include <simgear/compiler.h>
#include <queue>
#include <vector>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/sound/sample_group.hxx>
class SGXmlSound;
class SGSoundSample;
class SGSoundMgr;
/**
* Generator for FlightGear sound effects.
*
* This module uses FGSoundMgr to generate sound effects based
* on current flight conditions. The sound manager must be initialized
* This module uses a FGSampleGroup class to generate sound effects based
* on current flight conditions. The sound manager must be initialized
* before this object is.
*
* Note: this module supports two separate sound mechanisms concurrently.
*
* 1. This module will load and play a set of sound effects defined in an
* This module will load and play a set of sound effects defined in an
* xml file and tie them to various property states.
* 2. This modules also maintains a queue of 'message' audio files. These
* are played sequentially with no overlap until the queue is finished.
* This second mechanims is useful for things like tutorial messages or
* background atc chatter.
*/
class FGFX : public SGSubsystem
class FGFX : public SGSampleGroup
{
public:
FGFX ();
FGFX ( SGSoundMgr *smgr, const string &refname );
virtual ~FGFX ();
virtual void init ();
virtual void reinit ();
virtual void bind ();
virtual void unbind ();
virtual void update (double dt);
/**
* add a sound sample to the message queue which is played sequentially
* in order.
*/
void play_message( SGSoundSample *_sample );
void play_message( const std::string& path, const std::string& fname, double volume );
/**
* Explicit late update hook, to avoid problems which occur if done during
* normal SGSubsytem updating.
*/
void update_fx_late(double dt);
private:
void update_pos_and_orientation(SGSoundMgr *smgr, double dt);
SGVec3d last_visitor_pos;
SGVec3d last_model_pos;
SGSharedPtr<SGSampleGroup> _avionics;
std::vector<SGXmlSound *> _sound;
std::queue<SGSoundSample *> _samplequeue;
bool last_pause;
double last_volume;
SGPropertyNode_ptr _pause;
SGPropertyNode_ptr _enabled;
SGPropertyNode_ptr _volume;
SGPropertyNode_ptr _avionics_enabled;
SGPropertyNode_ptr _avionics_volume;
SGPropertyNode_ptr _avionics_external;
SGPropertyNode_ptr _internal;
};

View file

@ -23,9 +23,6 @@
#include <simgear/constants.h>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include "morse.hxx"
@ -171,10 +168,6 @@ bool FGMorse::cust_init(const int freq ) {
// make a SGSoundSample morse code transmission for the specified string
SGSoundSample *FGMorse::make_ident( const string& id, const int freq ) {
if (globals->get_soundmgr()->is_working() == false) {
return 0;
}
char *idptr = (char *)id.c_str();
int length = 0;
@ -226,10 +219,10 @@ SGSoundSample *FGMorse::make_ident( const string& id, const int freq ) {
length += 2 * SPACE_SIZE;
// 2. Allocate space for the message
unsigned char *buffer = new unsigned char[length];
const unsigned char* buffer = (const unsigned char *)malloc(length);
// 3. Assemble the message;
unsigned char *buf_ptr = buffer;
unsigned char *buf_ptr = (unsigned char*)buffer;
for ( i = 0; i < (int)id.length(); ++i ) {
if ( idptr[i] >= 'A' && idptr[i] <= 'Z' ) {
@ -268,12 +261,9 @@ SGSoundSample *FGMorse::make_ident( const string& id, const int freq ) {
buf_ptr += SPACE_SIZE;
// 4. create the simple sound and return
SGSoundSample *sample = new SGSoundSample( buffer, length,
SGSoundSample *sample = new SGSoundSample( &buffer, length,
BYTES_PER_SECOND );
// clean up the buffer
delete [] buffer;
sample->set_reference_dist( 10.0 );
sample->set_max_dist( 20.0 );

108
src/Sound/sample_queue.cxx Normal file
View file

@ -0,0 +1,108 @@
// _samplequeue.cxx -- Sound effect management class implementation
//
// Started by David Megginson, October 2001
// (Reuses some code from main.cxx, probably by Curtis Olson)
//
// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef _MSC_VER
#pragma warning (disable: 4786)
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "sample_queue.hxx"
#include <Main/fg_props.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/sound/sample_openal.hxx>
FGSampleQueue::FGSampleQueue ( SGSoundMgr *smgr, const string &refname ) :
last_enabled( true ),
last_volume( 0.0 ),
_enabled( fgGetNode("/sim/sound/chatter/enabled", true) ),
_volume( fgGetNode("/sim/sound/chatter/volume", true) )
{
SGSampleGroup::_smgr = smgr;
SGSampleGroup::_smgr->add(this, refname);
SGSampleGroup::_refname = refname;
_enabled->setBoolValue(true);
_volume->setFloatValue(1.0);
}
FGSampleQueue::~FGSampleQueue ()
{
while ( _messages.size() > 0 ) {
delete _messages.front();
_messages.pop();
}
}
void
FGSampleQueue::update (double dt)
{
// command sound manger
bool new_enabled = _enabled->getBoolValue();
if ( new_enabled != last_enabled ) {
if ( new_enabled ) {
resume();
} else {
suspend();
}
last_enabled = new_enabled;
}
if ( new_enabled ) {
double volume = _volume->getDoubleValue();
if ( volume != last_volume ) {
set_volume( volume );
last_volume = volume;
}
// process mesage queue
const string msgid = "Sequential Audio Message";
bool now_playing = false;
if ( exists( msgid ) ) {
now_playing = is_playing( msgid );
if ( !now_playing ) {
// current message finished, stop and remove
stop( msgid ); // removes source
remove( msgid ); // removes buffer
}
}
if ( !now_playing ) {
// message queue idle, add next sound if we have one
if ( _messages.size() > 0 ) {
SGSampleGroup::add( _messages.front(), msgid );
_messages.pop();
play_once( msgid );
}
}
SGSampleGroup::update(dt);
}
}
// end of _samplequeue.cxx

View file

@ -0,0 +1,70 @@
// sample_queue.hxx -- sample queue management class
//
// Started by David Megginson, October 2001
// (Reuses some code from main.cxx, probably by Curtis Olson)
//
// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef __FGSAMPLE_QUEUE_HXX
#define __FGSAMPLE_QUEUE_HXX 1
#include <simgear/compiler.h>
#include <queue>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/sound/sample_group.hxx>
class SGSoundSample;
/**
* FlightGear sample queue class
*
* This modules maintains a queue of 'message' audio files. These
* are played sequentially with no overlap until the queue is finished.
* This second mechanims is useful for things like tutorial messages or
* background atc chatter.
*/
class FGSampleQueue : public SGSampleGroup
{
public:
FGSampleQueue ( SGSoundMgr *smgr, const string &refname );
virtual ~FGSampleQueue ();
virtual void update (double dt);
inline void add (SGSharedPtr<SGSoundSample> msg) { _messages.push(msg); }
private:
std::queue< SGSharedPtr<SGSoundSample> > _messages;
bool last_enabled;
double last_volume;
SGPropertyNode_ptr _enabled;
SGPropertyNode_ptr _volume;
};
#endif
// end of fg_fx.hxx

View file

@ -35,7 +35,7 @@ FGVoiceMgr::FGVoiceMgr() :
_host(fgGetString(VOICE "/host", "localhost")),
_port(fgGetString(VOICE "/port", "1314")),
_enabled(fgGetBool(VOICE "/enabled", false)),
_pausedNode(fgGetNode("/sim/sound/pause", true))
_pausedNode(fgGetNode("/sim/sound/working", true))
{
#if defined(ENABLE_THREADS)
if (!_enabled)
@ -83,7 +83,7 @@ void FGVoiceMgr::update(double)
if (!_enabled)
return;
_paused = _pausedNode->getBoolValue();
_paused = !_pausedNode->getBoolValue();
for (unsigned int i = 0; i < _voices.size(); i++) {
_voices[i]->update();
#if !defined(ENABLE_THREADS)

View file

@ -1,4 +1,4 @@
bin_PROGRAMS = est-epsilon gl-info al-info
bin_PROGRAMS = est-epsilon gl-info alcinfo
noinst_PROGRAMS = test-gethostname test-mktime test-text test-up test-env-map
@ -14,8 +14,8 @@ est_epsilon_LDADD = $(opengl_LIBS)
gl_info_SOURCES = gl-info.c
gl_info_LDADD = $(opengl_LIBS)
al_info_SOURCES = al-info.c
al_info_LDADD = $(openal_LIBS)
alcinfo_SOURCES = alcinfo.cxx
alcinfo_LDADD = $(openal_LIBS)
test_env_map_SOURCES = test-env-map.cxx
test_env_map_LDADD = $(opengl_LIBS)

View file

@ -1,114 +0,0 @@
#include <stdio.h>
#ifdef __APPLE__
# include <OpenAL/al.h>
# include <OpenAL/alc.h>
#else
# include <AL/al.h>
# include <AL/alc.h>
# ifndef __CYGWIN__
# include <AL/alext.h>
# endif
#endif
#ifndef AL_VERSION_1_1
# ifdef __APPLE__
# include <OpenAL/altypes.h>
# include <OpenAL/alctypes.h>
#else
# include <AL/altypes.h>
# include <AL/alctypes.h>
# endif
#endif
#define MAX_DATA 16
int main()
{
ALCint data[MAX_DATA];
ALCdevice *device = NULL;
ALCcontext *context = NULL;
const ALchar *s;
ALCenum error;
device = alcOpenDevice(NULL);
if (device == NULL)
{
printf("No default audio device available.\n");
return -1;
}
context = alcCreateContext(device, NULL);
if (context == NULL)
{
printf("Could not create a valid context.\n");
return -2;
}
alcMakeContextCurrent(context);
s = alGetString(AL_VENDOR);
printf("AL_VENDOR = \"%s\"\n", s);
s = alGetString(AL_RENDERER);
printf("AL_RENDERER = \"%s\"\n", s);
s = alGetString(AL_VERSION);
printf("AL_VERSION = \"%s\"\n", s);
s = alGetString(AL_EXTENSIONS);
printf("AL_EXTENSIONS = \"%s\"\n", s);
alcGetError(device);
printf("\n");
if (alcIsExtensionPresent(NULL, (const ALchar *)"ALC_ENUMERATION_EXT") == AL_TRUE)
{
s = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
printf("ALC_DEVICE_SPECIFIER = \"%s\"\n", s);
}
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, data);
printf("ALC_MAJOR_VERSION = %i\n", *data);
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, data);
printf("ALC_MINOR_VERSION = %i\n", *data);
s = alcGetString(device, ALC_EXTENSIONS);
printf("ALC_EXTENSIONS = \"%s\"\n", s);
if ((error = alcGetError(device)))
{
printf("Error #%i occured\n", error);
return error;
}
s = alcGetString(device, ALC_DEFAULT_DEVICE_SPECIFIER);
printf("ALC_DEFAULT_DEVICE_SPECIFIER = \"%s\"\n", s);
if ((error = alcGetError(device)))
{
printf("Error #%i occured\n", error);
return error;
}
#if 0
alcGetIntegerv(device, ALC_ATTRIBUTES_SIZE, 1, &i);
printf("ALC attributes(%i): ", i);
alcGetIntegerv(device, ALC_ALL_ATTRIBUTES, i, data);
for (j=0; j<i; j++)
{
printf("%i ", data[j]);
}
printf("\n");
if ((error = alcGetError(device)))
{
printf("Error #%i occured\n", error);
return error;
}
#endif
alcCloseDevice(device);
return 0;
}

341
tests/alcinfo.cxx Normal file
View file

@ -0,0 +1,341 @@
/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
* vi:set ts=8:
*
* alcinfo.x
*
* alcinfo display info about a ALC extension and OpenAL renderer
*
* This file is in the Public Domain and comes with no warranty.
* Erik Hofman <erik@ehofman.com>
*
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef __APPLE__
# include <OpenAL/al.h>
# include <OpenAL/alc.h>
#else
# include <AL/al.h>
# include <AL/alc.h>
# include <AL/alext.h>
#endif
#ifndef AL_VERSION_1_1
# ifdef __APPLE__
# include <OpenAL/altypes.h>
# include <OpenAL/alctypes.h>
#else
# include <AL/altypes.h>
# include <AL/alctypes.h>
# endif
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <string>
using std::string;
#ifndef ALC_ALL_DEVICES_SPECIFIER
# define ALC_ALL_DEVICES_SPECIFIER 0x1013
#endif
#define MAX_DATA 16
static const int indentation = 4;
static const int maxmimumWidth = 79;
void printExtensions (const char *, char, const char *);
void displayDevices(const char *, const char *);
char *getDeviceName(int, char **);
void testForError(void *, const string&);
void testForALCError(ALCdevice *);
int main(int argc, char **argv)
{
ALCint data[MAX_DATA];
ALCdevice *device = NULL;
ALCcontext *context = NULL;
ALenum error;
char *s;
if (alcIsExtensionPresent(NULL, "ALC_enumeration_EXT") == AL_TRUE)
{
if (alcIsExtensionPresent(NULL, "ALC_enumerate_all_EXT") == AL_FALSE)
s = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
else
s = (char *)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
displayDevices("output", s);
s = (char *)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
displayDevices("input", s);
}
s = getDeviceName(argc, argv);
device = alcOpenDevice(s);
testForError(device, "Audio device not available.");
context = alcCreateContext(device, NULL);
testForError(context, "Unable to create a valid context.");
alcMakeContextCurrent(context);
testForALCError(device);
s = (char *)alcGetString(device, ALC_DEFAULT_DEVICE_SPECIFIER);
printf("default output device: %s\n", s);
testForALCError(device);
error = alcIsExtensionPresent(device, "ALC_EXT_capture");
if (error)
{
s = (char *)alcGetString(device, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
printf("default input device: %s\n", s);
testForALCError(device);
}
printf("capture support: %s\n", (error) ? "yes" : "no");
alcGetIntegerv(device, ALC_FREQUENCY, 1, data);
printf("mixer frequency: %u hz\n", data[0]);
testForALCError(device);
alcGetIntegerv(device, ALC_REFRESH, 1, data+1);
printf("refresh rate : %u hz\n", data[0]/data[1]);
testForALCError(device);
data[0] = 0;
alcGetIntegerv(device, ALC_MONO_SOURCES, 1, data);
error = alcGetError(device);
if (error == AL_NONE) {
printf("supported sources; mono: %u, ", data[0]);
data[0] = 0;
alcGetIntegerv(device, ALC_STEREO_SOURCES, 1, data);
printf("stereo: %u\n", data[0]);
testForALCError(device);
}
printf("ALC version: ");
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, data);
printf("%i.", *data);
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, data);
printf("%i\n", *data);
testForALCError(device);
s = (char *)alcGetString(device, ALC_EXTENSIONS);
printExtensions ("ALC extensions", ' ', s);
testForALCError(device);
s = (char *)alGetString(AL_VENDOR);
error = alGetError();
if ((error = alGetError()) != AL_NO_ERROR)
printf("Error #%x: %s\n", error, alGetString(error));
else
printf("OpenAL vendor string: %s\n", s);
s = (char *)alGetString(AL_RENDERER);
if ((error = alGetError()) != AL_NO_ERROR)
printf("Error #%x: %s\n", error, alGetString(error));
else
printf("OpenAL renderer string: %s\n", s);
s = (char *)alGetString(AL_VERSION);
if ((error = alGetError()) != AL_NO_ERROR)
printf("Error #%x: %s\n", error, alGetString(error));
else if (!s)
printf("Quering AL_VERSION returned NULL pointer!\n");
else
printf("OpenAL version string: %s\n", s);
s = (char *)alGetString(AL_EXTENSIONS);
printExtensions ("OpenAL extensions", ' ', s);
testForALCError(device);
/* alut testing mechanism */
context = alcGetCurrentContext();
if (context == NULL)
{
printf("Error: no current context\n");
}
else
{
if (alGetError () != AL_NO_ERROR)
{
printf("Alert: AL error on entry\n");
}
else
{
if (alcGetError (alcGetContextsDevice (context)) != ALC_NO_ERROR)
{
printf("Alert: ALC error on entry\n");
}
}
}
/* end of alut test */
if (alcMakeContextCurrent(NULL) == 0)
printf("alcMakeContextCurrent failed.\n");
device = alcGetContextsDevice(context);
alcDestroyContext(context);
testForALCError(device);
if (alcCloseDevice(device) == 0)
printf("alcCloseDevice failed.\n");
return 0;
}
/* -------------------------------------------------------------------------- */
void
printChar (int c, int *width)
{
putchar (c);
*width = (c == '\n') ? 0 : (*width + 1);
}
void
indent (int *width)
{
int i;
for (i = 0; i < indentation; i++)
{
printChar (' ', width);
}
}
void
printExtensions (const char *header, char separator, const char *extensions)
{
int width = 0, start = 0, end = 0;
printf ("%s:\n", header);
if (extensions == NULL || extensions[0] == '\0')
{
return;
}
indent (&width);
while (1)
{
if (extensions[end] == separator || extensions[end] == '\0')
{
if (width + end - start + 2 > maxmimumWidth)
{
printChar ('\n', &width);
indent (&width);
}
while (start < end)
{
printChar (extensions[start], &width);
start++;
}
if (extensions[end] == '\0')
{
break;
}
start++;
end++;
if (extensions[end] == '\0')
{
break;
}
printChar (',', &width);
printChar (' ', &width);
}
end++;
}
printChar ('\n', &width);
}
char *
getCommandLineOption(int argc, char **argv, const string& option)
{
int slen = option.size();
char *rv = 0;
int i;
for (i=0; i<argc; i++)
{
if (strncmp(argv[i], option.c_str(), slen) == 0)
{
i++;
if (i<argc) rv = argv[i];
}
}
return rv;
}
char *
getDeviceName(int argc, char **argv)
{
static char devname[255];
int len = 255;
char *s;
s = getCommandLineOption(argc, argv, "-d");
if (s)
{
strncpy((char *)&devname, s, len);
len -= strlen(s);
s = getCommandLineOption(argc, argv, "-r");
if (s)
{
strncat((char *)&devname, " on ", len);
len -= 4;
strncat((char *)&devname, s, len);
}
s = (char *)&devname;
}
return s;
}
void
displayDevices(const char *type, const char *list)
{
ALCchar *ptr, *nptr;
ptr = (ALCchar *)list;
printf("list of all available %s devices:\n", type);
if (!list)
{
printf("none\n");
}
else
{
nptr = ptr;
while (*(nptr += strlen(ptr)+1) != 0)
{
printf(" %s\n", ptr);
ptr = nptr;
}
printf(" %s\n", ptr);
}
}
void
testForError(void *p, const string& s)
{
if (p == NULL)
{
printf("\nError: %s\n\n", s.c_str());
exit(-1);
}
}
void
testForALCError(ALCdevice *device)
{
ALenum error;
error = alcGetError(device);
if (error != ALC_NO_ERROR)
printf("\nALC Error %x occurred: %s\n", error, alcGetString(device, error));
}