TDME2  1.9.200
Sound.cpp
Go to the documentation of this file.
1 #include <tdme/audio/Sound.h>
2 
3 #if defined(__APPLE__)
4  #include <OpenAL/al.h>
5 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__linux__) || defined(_WIN32) || defined(__HAIKU__)
6  #include <AL/al.h>
7 #endif
8 
9 #include <memory>
10 #include <string>
11 
12 #include <tdme/tdme.h>
16 #include <tdme/audio/Audio.h>
19 #include <tdme/math/Vector3.h>
23 #include <tdme/utilities/Console.h>
24 
25 using tdme::audio::Sound;
26 
27 using std::string;
28 using std::to_string;
29 using std::unique_ptr;
30 
33 using tdme::audio::Audio;
40 
41 bool Sound::isPlaying()
42 {
43  ALint state;
44  alGetSourcei(alSourceId, AL_SOURCE_STATE, &state);
45  return (state == AL_PLAYING);
46 }
47 
49 {
50  if (initiated == false)
51  return;
52 
53  alSourceRewind(alSourceId);
54  if (alGetError() != AL_NO_ERROR) {
55  Console::println(string("Audio sound: '" + id + "': Could not rewind"));
56  }
57 }
58 
60 {
61  if (initiated == false)
62  return;
63  // update
64  update();
65  // play
66  alSourcePlay(alSourceId);
67  if (alGetError() != AL_NO_ERROR) {
68  Console::println(string("Audio sound: '" + id + "': Could not play"));
69  }
70 }
71 
73 {
74  if (initiated == false)
75  return;
76 
77  alSourcePause(alSourceId);
78  if (alGetError() != AL_NO_ERROR) {
79  Console::println(string("Audio sound: '" + id+ "': Could not pause"));
80  }
81 }
82 
84 {
85  if (initiated == false)
86  return;
87 
88  alSourceStop(alSourceId);
89  if (alGetError() != AL_NO_ERROR) {
90  Console::println(string("Audio sound: '" + id + "': Could not stop"));
91  }
92 }
93 
95 {
96  // check if we already have this buffer
97  auto audioBufferManaged = Audio::instance->audioBufferManager.addAudioBuffer(bufferId);
98  if (audioBufferManaged->alId == Audio::ALBUFFERID_NONE) {
99  // nope, generate al buffer
100  int alError;
101  alGenBuffers(1, &alBufferId);
102  if (alGetError() != AL_NO_ERROR) {
103  Console::println(string("Audio sound: '" + id + "': Could not generate buffer"));
104  return false;
105  }
106  // set up al id in audio buffer managed
107  audioBufferManaged->setAlId(alBufferId);
108  auto format = -1;
109  auto frequency = -1;
110 
111  // decode audio sound
112  VorbisDecoder decoder;
113  unique_ptr<ByteBuffer> data;
114  try {
115  // decode ogg vorbis
116  decoder.openFile(pathName, fileName);
117  Console::println(
118  string(
119  "Audio sound: '" +
120  id +
121  "' with " +
122  to_string(decoder.getBitsPerSample()) +
123  " bits per sample, " +
124  to_string(decoder.getChannels()) +
125  " channels, " +
126  to_string(decoder.getSampleRate()) +
127  " samplerate"
128  )
129  );
130  frequency = decoder.getSampleRate();
131  switch (decoder.getChannels()) {
132  case(1): format = AL_FORMAT_MONO16; break;
133  case(2): format = AL_FORMAT_STEREO16; break;
134  default:
135  Console::println(string("Audio sound: '" + id + "': Unsupported number of channels"));
136  }
137  data = unique_ptr<ByteBuffer>(ByteBuffer::allocate(2 * 2 * decoder.getSamples()));
138  if (decoder.readFromStream(data.get()) == 0) throw AudioDecoderException("no audio data was decoded");
139  Console::println(
140  string(
141  "Audio sound: '" +
142  id +
143  "' with length " +
144  to_string((float)data->getPosition() / 2.0f / (float)decoder.getChannels() / (float)decoder.getSampleRate()) +
145  " seconds" +
146  "(" +
147  to_string(data->getPosition()) +
148  " bytes)"
149  )
150  );
151  } catch (FileSystemException& fse) {
152  Console::println(string("Audio sound: '" + (id) + "': " + fse.what()));
153  decoder.close();
154  dispose();
155  return false;
156  } catch (AudioDecoderException& ade) {
157  Console::println(string("Audio sound: '" + (id) + "': " + ade.what()));
158  decoder.close();
159  dispose();
160  return false;
161  }
162  decoder.close();
163  // check for valid format and frequency
164  if (format == -1 || frequency == -1) {
165  Console::println(string("Audio sound: '" + id + "': Format or frequency invalid"));
166  dispose();
167  return false;
168  }
169  // upload to al
170  alBufferData(alBufferId, format, data->getBuffer(), data->getPosition(), frequency);
171  if (alGetError() != AL_NO_ERROR) {
172  Console::println(string("Audio sound: '" + id + "': Could not upload buffer data"));
173  dispose();
174  return false;
175  }
176  } else {
177  alBufferId = audioBufferManaged->alId;
178  }
179 
180  // create source
181  alGenSources(1, &alSourceId);
182  if (alGetError() != AL_NO_ERROR) {
183  Console::println(string("Audio sound: '" + id + "': Could not generate source"));
184  dispose();
185  return false;
186  }
187 
188  // initiate sound properties
189  alSourcei(alSourceId, AL_BUFFER, alBufferId);
190  update();
191 
192  //
193  initiated = true;
194  return true;
195 }
196 
198 {
199  // update sound properties
200  alSourcef(alSourceId, AL_PITCH, pitch);
201  alSourcef(alSourceId, AL_GAIN, gain);
202  alSourcefv(alSourceId, AL_POSITION, sourcePosition.getArray().data());
203  alSourcefv(alSourceId, AL_DIRECTION, sourceDirection.getArray().data());
204  alSourcefv(alSourceId, AL_VELOCITY, sourceVelocity.getArray().data());
205  alSourcei(alSourceId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
206  if (fixed == true) {
207  alSourcef(alSourceId, AL_ROLLOFF_FACTOR, 0.0f);
208  alSourcei(alSourceId, AL_SOURCE_RELATIVE, AL_TRUE);
209  } else {
210  alSourcef(alSourceId, AL_ROLLOFF_FACTOR, 1.0f);
211  alSourcei(alSourceId, AL_SOURCE_RELATIVE, AL_FALSE);
212  }
213 }
214 
216 {
218  alDeleteSources(1, &alSourceId);
219  if (alGetError() != AL_NO_ERROR) {
220  Console::println(string("Audio sound: '" + id + "': Could not delete source"));
221  }
223  }
224  if (alBufferId != Audio::ALBUFFERID_NONE && Audio::instance->audioBufferManager.removeAudioBuffer(bufferId) == true) {
225  alDeleteBuffers(1, &alBufferId);
226  if (alGetError() != AL_NO_ERROR) {
227  Console::println(string("Audio sound: '" + id + "': Could not delete buffers"));
228  }
230  }
231  initiated = false;
232 }
AudioBufferManager_AudioBufferManaged * addAudioBuffer(const string &id)
Adds a audio buffer to manager / open al stack.
Interface to audio module.
Definition: Audio.h:29
static constexpr uint32_t ALSOURCEID_NONE
Definition: Audio.h:36
static constexpr uint32_t ALBUFFERID_NONE
Definition: Audio.h:35
static STATIC_DLL_IMPEXT Audio * instance
Definition: Audio.h:37
AudioBufferManager audioBufferManager
Definition: Audio.h:44
Sound audio entity implementation.
Definition: Sound.h:19
void play() override
Plays this audio entity.
Definition: Sound.cpp:59
void rewind() override
Rewinds this audio entity.
Definition: Sound.cpp:48
void dispose() override
Dispose this entity from OpenAL.
Definition: Sound.cpp:215
uint32_t alSourceId
Definition: Sound.h:28
void update() override
Commits properties to OpenAl.
Definition: Sound.cpp:197
bool initiated
Definition: Sound.h:23
bool initialize() override
Initiates this OpenAL entity to OpenAl.
Definition: Sound.cpp:94
string fileName
Definition: Sound.h:25
string pathName
Definition: Sound.h:24
uint32_t alBufferId
Definition: Sound.h:27
void stop() override
Stops this audio entity.
Definition: Sound.cpp:83
string bufferId
Definition: Sound.h:26
void pause() override
Pauses this audio entity.
Definition: Sound.cpp:72
OGG/Vorbis audio decoder.
Definition: VorbisDecoder.h:31
void close() override
Closes the audio file.
int64_t readFromStream(ByteBuffer *data) override
Read raw PCM data from stream.
void openFile(const string &pathName, const string &fileName) override
Open a local file.
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
const array< float, 3 > & getArray() const
Definition: Vector3.h:366
Byte buffer class.
Definition: ByteBuffer.h:27
Console class.
Definition: Console.h:29