Leviathan  0.8.0.0
Leviathan game engine
SoundDevice.cpp
Go to the documentation of this file.
1 // ------------------------------------ //
2 #include "SoundDevice.h"
3 
4 #include "SoundInternalTypes.h"
5 
8 #include "Engine.h"
10 
11 #include "cAudio/cAudio.h"
12 
13 #include <boost/filesystem.hpp>
14 
15 #include <algorithm>
16 using namespace Leviathan;
17 using namespace Leviathan::Sound;
18 // ------------------------------------ //
19 
22 {
23  Release();
24 }
25 // ------------------------------------ //
26 bool SoundDevice::Init(bool simulatesound /*= false*/, bool noconsolelog /*= false*/)
27 {
28  AudioLogPath = StringOperations::RemoveExtension(Logger::Get()->GetLogFile(), false) +
29  "cAudioLog.html";
30 
31  AudioManager = cAudio::createAudioManager(
32  // No default init, we want to select the device
33  false,
34  // And write to a program specific log file
35  AudioLogPath.c_str(), noconsolelog);
36 
37  LEVIATHAN_ASSERT(AudioManager, "Failed to create cAudio manager");
38 
39  size_t defaultDevice = 0;
40  const auto devices = GetAudioDevices(&defaultDevice);
41 
42  if(simulatesound == true) {
43 
44  LOG_WARNING("SoundDevice: simulating not having a playing device");
45  return true;
46  }
47 
48  if(devices.empty() || defaultDevice >= devices.size()) {
49 
50  LOG_ERROR("SoundDevice: no sound devices detected");
51  return false;
52  }
53 
54  if(std::find(devices.begin(), devices.end(), devices[defaultDevice]) == devices.end()) {
55  // I have no clue how it would ever get here, but you never know
56  LOG_ERROR("SoundDevice: Default device doesn't exist. The code should not have "
57  "been able to get here.");
58  }
59 
60  LOG_INFO("Detected audio devices: ");
61 
62  for(const auto& dev : devices)
63  LOG_INFO("> " + dev);
64 
65  LOG_INFO("End of devices");
66 
67  std::string selectedDevice;
68  // There's no print error here if missing to make tests run
69  ObjectFileProcessor::LoadValueFromNamedVars<std::string>(
70  Engine::Get()->GetDefinition()->GetValues(), "AudioDevice", selectedDevice, "default");
71 
72  if(selectedDevice == "default") {
73 
74  selectedDevice = devices[defaultDevice];
75 
76  } else if(std::find(devices.begin(), devices.end(), selectedDevice) == devices.end()) {
77  LOG_ERROR("SoundDevice: selected audio device \"" + selectedDevice +
78  "\" doesn't exists. Using default");
79  selectedDevice = devices[defaultDevice];
80  }
81 
82  LOG_INFO("SoundDevice: Initializing sound with device: " + selectedDevice);
83 
84  if(!AudioManager->initialize(selectedDevice.c_str())) {
85 
86  LOG_ERROR("SoundDevice: initializing failed");
87  return false;
88  }
89 
90  ListeningPosition = AudioManager->getListener();
91 
92  // setup global volume //
93  SetGlobalVolume(1.f);
94 
95  ListeningPosition->setUpVector(cAudio::cVector3(0, 1, 0));
96 
97  return true;
98 }
100 {
101  HandledAudioSources.clear();
102 
103  if(AudioManager) {
104 
105  cAudio::destroyAudioManager(AudioManager);
106  AudioManager = nullptr;
107  }
108 }
109 // ------------------------------------ //
110 void SoundDevice::Tick(int PassedMs)
111 {
112  for(auto iter = HandledAudioSources.begin(); iter != HandledAudioSources.end(); ++iter) {
113 
114  if(!(*iter)->Get()->isPlaying()) {
115 
116  iter = HandledAudioSources.erase(iter);
117  }
118  }
119 }
120 
122  const Float3& pos, const Float4& orientation)
123 {
124  // we need to create a vector from the angles //
125  // Float3 vec = Float3(-sin(pitchyawroll.X*DEGREES_TO_RADIANS),
126  // sin(pitchyawroll.Y*DEGREES_TO_RADIANS), -cos(pitchyawroll.X*DEGREES_TO_RADIANS));
127 
128  if(!ListeningPosition)
129  return;
130 
131  ListeningPosition->move(cAudio::cVector3(pos.X, pos.Y, pos.Z));
132 
133  Ogre::Quaternion quaternion(orientation);
134 
135  Ogre::Radian angle;
136  Ogre::Vector3 direction;
137 
138  quaternion.ToAngleAxis(angle, direction);
139 
140  ListeningPosition->setDirection(cAudio::cVector3(direction.x, direction.y, direction.z));
141 }
142 
144 {
145  if(!AudioManager)
146  return;
147 
148  vol = std::clamp(vol, 0.f, 1.f);
149 
150  AudioManager->setMasterVolume(vol);
151 }
152 // ------------------------------------ //
153 DLLEXPORT void SoundDevice::Play2DSoundEffect(const std::string& filename)
154 {
155  if(!AudioManager)
156  return;
157 
158  cAudio::IAudioSource* source = AudioManager->play2D(filename.c_str(), false, false);
159 
160  if(source) {
161 
162  LOG_ERROR("SoundDevice: Play2DSoundEffect: shouldn't return a source but it did. "
163  "Babysitting it");
164 
166  [=]() { this->BabysitAudio(AudioSource::MakeShared<AudioSource>(source, this)); });
167  }
168 }
169 
171  const std::string& filename, bool looping, bool startpaused)
172 {
173  if(!AudioManager)
174  return nullptr;
175 
176  if(!looping && !startpaused)
177  LOG_WARNING("SoundDevice: Play2DSound: called with same settings that "
178  "Play2DSoundEffect uses. looping or startpaused must be true to return an "
179  "AudioSource.");
180 
181  cAudio::IAudioSource* source =
182  AudioManager->play2D(filename.c_str(), looping, startpaused);
183 
184  if(!source) {
185  LOG_ERROR(
186  "SoundDevice: Play2DSound: failed to create IAudioSource from file: " + filename);
187 
188  if(!boost::filesystem::is_regular(filename))
189  LOG_INFO("SoundDevice: file '" + filename + "' doesn't exist");
190 
191  return nullptr;
192  }
193 
194  return AudioSource::MakeShared<AudioSource>(source, this);
195 }
196 
198  ProceduralSoundData::pointer data, const char* soundname)
199 {
200  if(!AudioManager || !data)
201  return nullptr;
202 
203  return AudioSource::MakeShared<AudioSource>(
204  AudioManager->createFromAudioDecoder(soundname, data->Properties.SourceName.c_str(),
205  CAUDIO_NEW ProceduralSoundStream(data)),
206  this);
207 }
208 // ------------------------------------ //
210 {
212 
213  HandledAudioSources.push_back(audio);
214 }
215 // ------------------------------------ //
216 DLLEXPORT std::vector<std::string> SoundDevice::GetAudioDevices(
217  size_t* indexofdefault /*= nullptr*/)
218 {
219  std::vector<std::string> result;
220 
221  cAudio::IAudioDeviceList* devices = cAudio::createAudioDeviceList();
222 
223  if(!devices) {
224  LOG_ERROR("SoundDevice: GetAudioDevices: failed to get audio device list");
225  return {};
226  }
227 
228  const auto deviceCount = devices->getDeviceCount();
229  result.reserve(deviceCount);
230 
231  const auto defaultDeviceName = devices->getDefaultDeviceName();
232 
233  for(unsigned int i = 0; i < deviceCount; ++i) {
234 
235  const auto deviceName = devices->getDeviceName(i);
236 
237  if(deviceName.compare(defaultDeviceName) == 0 && indexofdefault) {
238 
239  *indexofdefault = i;
240  }
241 
242  result.push_back(deviceName);
243  }
244 
245  CAUDIO_DELETE devices;
246 
247  return result;
248 }
Used to feed data retrieved from a callback to cAudio::IAudioSource.
DLLEXPORT bool Init(bool simulatesound=false, bool noconsolelog=false)
Definition: SoundDevice.cpp:26
#define LOG_INFO(x)
Definition: Define.h:81
#define LOG_ERROR(x)
Definition: Define.h:83
DLLEXPORT void Tick(int PassedMs)
DLLEXPORT void SetGlobalVolume(float vol)
static const StringTypeN RemoveExtension(const StringTypeN &filepath, bool delpath=true)
#define LOG_WARNING(x)
Definition: Define.h:82
DLLEXPORT NamedVars * GetValues()
Definition: AppDefine.cpp:40
DLLEXPORT void RunOnMainThread(const std::function< void()> &function)
Runs the function now if on the main thread otherwise calls Invoke.
Definition: Engine.cpp:1161
DLLEXPORT AudioSource::pointer Play2DSound(const std::string &filename, bool looping, bool startpaused)
Plays a 2d sound with options.
DLLEXPORT void BabysitAudio(AudioSource::pointer audio)
This class holds the audio source until it has finished playing and then releases the reference...
static DLLEXPORT std::vector< std::string > GetAudioDevices(size_t *indexofdefault=nullptr)
Returns a list of audio playback devices.
DLLEXPORT AudioSource::pointer CreateProceduralSound(ProceduralSoundData::pointer data, const char *soundname)
Opens an audio source from a procedural data stream.
DLLEXPORT void Play2DSoundEffect(const std::string &filename)
Plays a 2d sound without possibility of interrupting.
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
DLLEXPORT void SetSoundListenerPosition(const Float3 &pos, const Float4 &orientation)
Loads the file and plays the sound.
DLLEXPORT ~SoundDevice()
Definition: SoundDevice.cpp:21
AppDef * GetDefinition()
Definition: Engine.h:198
boost::intrusive_ptr< JSProxyable > pointer
Definition: JSProxyable.h:15
#define DLLEXPORT
Definition: Include.h:115
DLLEXPORT void Release()
Definition: SoundDevice.cpp:99
static DLLEXPORT Engine * Get()
Definition: Engine.cpp:84
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
DLLEXPORT void AssertIfNotMainThread() const
Asserts if not called on the main thread.
Definition: Engine.h:104