10#include <simgear/sound/soundmgr.hxx>
11#include <simgear/structure/commands.hxx>
25#ifdef ENABLE_AUDIO_SUPPORT
29class Listener :
public SGPropertyChangeListener
32 Listener(FGSoundManager *wrapper) : _wrapper(wrapper) {}
33 virtual void valueChanged (SGPropertyNode * node);
36 FGSoundManager* _wrapper;
39void Listener::valueChanged(SGPropertyNode * node)
41 _wrapper->activate(node->getBoolValue());
46 _is_initialized(false),
48 _listener(new Listener(this))
56void FGSoundManager::init()
58 _sound_working =
fgGetNode(
"/sim/sound/working");
59 _sound_enabled =
fgGetNode(
"/sim/sound/enabled");
61 _device_name =
fgGetNode(
"/sim/sound/device-name");
63 _velocityNorthFPS =
fgGetNode(
"velocities/speed-north-fps",
true);
64 _velocityEastFPS =
fgGetNode(
"velocities/speed-east-fps",
true);
65 _velocityDownFPS =
fgGetNode(
"velocities/speed-down-fps",
true);
69 SGPropertyNode_ptr scenery_loaded =
fgGetNode(
"sim/sceneryloaded",
true);
70 scenery_loaded->addChangeListener(_listener.get());
72 globals->
get_commands()->addCommand(
"play-audio-sample",
this, &FGSoundManager::playAudioSampleCommand);
78void FGSoundManager::shutdown()
80 SGPropertyNode_ptr scenery_loaded =
fgGetNode(
"sim/sceneryloaded",
true);
81 scenery_loaded->removeChangeListener(_listener.get());
89 SGSoundMgr::shutdown();
92void FGSoundManager::reinit()
94 _is_initialized =
false;
96 if (_is_initialized && !_sound_working->getBoolValue())
103 if (!_sound_working->getBoolValue())
108 update_device_list();
110 select_device(_device_name->getStringValue().c_str());
111 SGSoundMgr::reinit();
112 _is_initialized =
true;
114 activate(
fgGetBool(
"sim/sceneryloaded",
true));
117void FGSoundManager::activate(
bool State)
123 SGSoundMgr::activate();
128void FGSoundManager::update_device_list()
130 std::vector <std::string>devices = get_available_devices();
131 for (
unsigned int i=0;
i<devices.size();
i++) {
132 SGPropertyNode *
p =
fgGetNode(
"/sim/sound/devices/device",
i,
true);
133 p->setStringValue(devices[
i].c_str());
138bool FGSoundManager::stationaryView()
const
152 if (is_working() && _is_initialized && _sound_working->getBoolValue())
154 bool enabled = _sound_enabled->getBoolValue() && !_frozen->getBoolValue();
155 if (enabled != _enabled)
169 SGVec3d velocity(SGVec3d::zeros());
170 if (!stationaryView()) {
171 velocity = SGVec3d(_velocityNorthFPS->getDoubleValue(),
172 _velocityEastFPS->getDoubleValue(),
173 _velocityDownFPS->getDoubleValue() );
176 set_velocity( velocity );
179 if (_active_dt < 5.0) {
181 vf = std::min(std::pow(_active_dt*0.2, 5.0), 1.0);
184 set_volume(vf*_volume->getFloatValue());
185 SGSoundMgr::update(dt);
196bool FGSoundManager::playAudioSampleCommand(
const SGPropertyNode * arg, SGPropertyNode * root)
198 std::string qname = arg->getStringValue(
"queue",
"");
199 std::string
name = !qname.empty() ? qname :
"chatter";
200 std::string path = arg->getStringValue(
"path");
201 std::string file = arg->getStringValue(
"file");
202 float volume = arg->getFloatValue(
"volume");
204 const auto fullPath = SGPath(path) / file;
207 if (!foundPath.exists()) {
208 SG_LOG(SG_GENERAL, SG_ALERT,
"play-audio-sample: no such file: '" <<
209 fullPath.utf8Str() <<
"'");
215 SGSoundSample *msg =
new SGSoundSample(foundPath);
216 msg->set_volume( volume );
218 if (
name ==
"instant")
220 static const char *r =
"0123456789abcdefghijklmnopqrstuvwxyz"
221 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
222 std::string rstr =
"NASAL: ";
223 for (
int i=0;
i<10;
i++) {
224 rstr.push_back( r[rand() % strlen(r)] );
229 SGSampleGroup* sgr = find(
"NASAL instant queue",
true);
230 sgr->tie_to_listener();
232 sgr->play_once(rstr);
236 if ( !_queue[
name] ) {
237 _queue[
name] =
new FGSampleQueue(
this,
name);
238 _queue[
name]->tie_to_listener();
240 _queue[
name]->add( msg );
245 }
catch (
const sg_io_exception&) {
246 SG_LOG(SG_GENERAL, SG_ALERT,
"play-audio-sample: "
247 "failed to load '" << foundPath.utf8Str() <<
"'");
252VoiceSynthesizer * FGSoundManager::getSynthesizer(
const std::string & voice )
254 std::map<std::string,VoiceSynthesizer*>::iterator it = _synthesizers.find(voice);
255 if( it == _synthesizers.end() ) {
256 VoiceSynthesizer * synthesizer =
new FLITEVoiceSynthesizer( voice );
257 _synthesizers[voice] = synthesizer;
267 SGSubsystemMgr::SOUND,
268 {{
"SGSoundMgr", SGSubsystemMgr::Dependency::HARD}});
flightgear::View * get_current_view() const
SGPath resolve_maybe_aircraft_path(const std::string &branch) const
Same as above, but test for non 'Aircraft/' branch paths, and always resolve them against fg_root.
SGCommandMgr * get_commands()
A Voice Synthesizer Interface.
const SGGeod & getPosition() const
double getXOffset_m() const
const SGQuatd & getViewOrientation()
double getYOffset_m() const
const SGVec3d & getViewPosition()
double getZOffset_m() const
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
SGSubsystemMgr::Registrant< FGSoundManager > registrantFGSoundManager(SGSubsystemMgr::SOUND, {{"SGSoundMgr", SGSubsystemMgr::Dependency::HARD}})