Skip to content

Commit 4183999

Browse files
authored
Merge pull request #67 from Laguna1989/FEATURE_ReviewFindings
Feature review findings
2 parents 7248719 + 0e18a88 commit 4183999

14 files changed

+140
-123
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.19)
2-
project(OpenALpp)
2+
project(OpenALpp VERSION 0.1.0)
33

44
option(OALPP_ENABLE_UNIT_TESTS "Enable unit tests" ON)
55
option(OALPP_ENABLE_INTEGRATION_TESTS "Enable integration tests" ON)

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,24 @@ Code Example
2525
2626
SoundContext ctx;
2727
SoundData buffer { "audio.mp3" };
28-
Sound snd { buffer, ctx };
28+
Sound snd { buffer };
2929
snd.play();
30+
31+
while (snd.isPlaying()) {
32+
snd.update();
33+
}
3034
```
3135

36+
Common Pitfalls
37+
------------
38+
39+
* Sound has a dependency to the `SoundData` that is passed in the constructor. You need to keep the `SoundData` alive as
40+
long as any `Sound` might access it.
41+
* You can bundle `SoundData` and `Sound` together in your implementation.
42+
* Alternatively you can write your own `SoundDataManager` to avoid creating multiple `SoundData`s for the same file.
43+
* Your sound will stop after some seconds, even if the audio file contains a longer sound. `Sound`s do not update
44+
themselves. You need to call `update()` regularly.
45+
3246
How to include OpenALpp in your project
3347
---------------------------------------
3448

@@ -52,7 +66,7 @@ CMake Options
5266

5367
* `OALPP_ENABLE_UNIT_TESTS` - Enable unit tests - default `ON`
5468
* `OALPP_ENABLE_INTEGRATION_TESTS` - Enable integration test - default `ON`
55-
* `OALPP_STATIC_LIBRARY` - Build OpenALpp and dependencies as static library - default `OFF`
69+
* `OALPP_STATIC_LIBRARY` - Build OpenALpp and dependencies as static library - default `ON`
5670

5771
Compiler compatibility
5872
----------------------
@@ -68,4 +82,4 @@ Dependencies
6882
* CMake 3.19
6983
* One of the compatible compilers
7084

71-
All other dependencies (openal-soft and libnyquist) are automatically fetched via CMake.
85+
All other dependencies (`openal-soft` and `libnyquist`) are automatically fetched via CMake.

impl/oalpp/audio_exceptions.hpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,34 @@
22
#define OPENALPP_AUDIO_EXCEPTIONS_HPP
33

44
#include <stdexcept>
5+
#include <string>
6+
#include <utility>
57

68
namespace oalpp {
79
class AudioException : public std::exception {
810
public:
9-
explicit AudioException(char const* const message)
10-
: m_message { message }
11+
explicit AudioException(std::string message)
12+
: m_message { std::move(message) }
1113
{
1214
}
1315

14-
[[nodiscard]] char const* what() const noexcept override { return m_message; }
16+
[[nodiscard]] char const* what() const noexcept override { return m_message.c_str(); }
1517

1618
private:
17-
char const* m_message;
19+
std::string m_message;
1820
};
1921

2022
class AudioSystemException : public std::exception {
2123
public:
22-
explicit AudioSystemException(char const* const message)
23-
: m_message { message }
24+
explicit AudioSystemException(std::string message)
25+
: m_message { std::move(message) }
2426
{
2527
}
2628

27-
[[nodiscard]] char const* what() const noexcept override { return m_message; }
29+
[[nodiscard]] char const* what() const noexcept override { return m_message.c_str(); }
2830

2931
private:
30-
char const* m_message;
32+
std::string m_message;
3133
};
3234

3335
} // namespace oalpp

impl/oalpp/position.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include "position.hpp"
2+
3+
namespace oalpp {
4+
5+
bool operator==(Position const& lhs, Position const& rhs)
6+
{
7+
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
8+
}
9+
10+
} // namespace oalpp

impl/oalpp/position.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef OPENALPP_POSITION_HPP
2+
#define OPENALPP_POSITION_HPP
3+
4+
namespace oalpp {
5+
6+
struct Position {
7+
float x { 0.0f };
8+
float y { 0.0f };
9+
float z { 0.0f };
10+
};
11+
12+
bool operator==(Position const& lhs, Position const& rhs);
13+
14+
} // namespace oalpp
15+
16+
#endif // OPENALPP_POSITION_HPP

impl/oalpp/sound.cpp

Lines changed: 46 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "sound.hpp"
22
#include "audio_exceptions.hpp"
3-
#include "sound_context.hpp"
43
#include <cmath>
54
#include <stdexcept>
65

@@ -13,83 +12,64 @@ Sound::Sound(SoundDataInterface const& soundData)
1312
m_format = AL_FORMAT_STEREO_FLOAT32;
1413
}
1514

16-
createSource();
17-
18-
// Create and fill buffers
19-
createBuffers();
20-
fillBufferFromStart();
15+
initSourceAndBuffers();
2116

2217
auto const errorIfAny = alGetError();
2318
if (errorIfAny != AL_NO_ERROR) {
24-
auto const errorMessage
25-
= "Could not create OpenAL soundData, error code: " + std::to_string(errorIfAny);
26-
throw oalpp::AudioException { errorMessage.c_str() };
19+
throw oalpp::AudioException { "Could not create OpenAL soundData, error code: "
20+
+ std::to_string(errorIfAny) };
2721
}
2822
}
29-
30-
Sound::~Sound()
31-
{
32-
deleteSource();
33-
deleteBuffers();
34-
}
35-
36-
void Sound::deleteBuffers()
23+
void Sound::initSourceAndBuffers()
3724
{
38-
alDeleteBuffers(static_cast<ALsizei>(m_bufferIds.size()), m_bufferIds.data());
39-
}
25+
// Create source
26+
alGenSources(1, &m_sourceId);
27+
alSourcef(m_sourceId, AL_PITCH, 1.0f);
28+
alSourcef(m_sourceId, AL_GAIN, m_volume);
29+
alSource3f(m_sourceId, AL_POSITION, 0.0f, 0, -1.0f);
30+
alSource3f(m_sourceId, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
31+
alSourcei(m_sourceId, AL_LOOPING, AL_FALSE);
32+
alSourcef(m_sourceId, AL_ROLLOFF_FACTOR, 0.0f);
33+
alSourcei(m_sourceId, AL_SOURCE_RELATIVE, true);
4034

41-
void Sound::deleteSource() const { alDeleteSources(1, &m_sourceId); }
35+
alGenBuffers(static_cast<ALsizei>(m_bufferIds.size()), m_bufferIds.data());
4236

43-
void Sound::fillBufferFromStart()
44-
{
4537
m_cursor = 0;
4638
for (auto const& bufferId : m_bufferIds) {
4739
selectSamplesForBuffer(bufferId);
4840
}
4941
}
5042

51-
void Sound::createBuffers()
52-
{
53-
alGenBuffers(static_cast<ALsizei>(m_bufferIds.size()), m_bufferIds.data());
54-
}
43+
Sound::~Sound() { deleteSourceAndBuffers(); }
5544

56-
void Sound::createSource()
45+
void Sound::deleteSourceAndBuffers()
5746
{
58-
// Create source
59-
alGenSources(1, &m_sourceId);
60-
alSourcef(m_sourceId, AL_PITCH, 1.0f);
61-
alSourcef(m_sourceId, AL_GAIN, m_volume);
62-
alSource3f(m_sourceId, AL_POSITION, 0.0f, 0, -1.0f);
63-
alSource3f(m_sourceId, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
64-
alSourcei(m_sourceId, AL_LOOPING, AL_FALSE);
65-
alSourcef(m_sourceId, AL_ROLLOFF_FACTOR, 0.0f);
66-
alSourcei(m_sourceId, AL_SOURCE_RELATIVE, true);
47+
alDeleteSources(1, &m_sourceId);
48+
alDeleteBuffers(static_cast<ALsizei>(m_bufferIds.size()), m_bufferIds.data());
6749
}
6850

6951
void Sound::play()
7052
{
7153
alSourcePlay(m_sourceId);
7254
auto const errorIfAny = alGetError();
7355
if (errorIfAny != AL_NO_ERROR) {
74-
auto const errorMessage = "Could not play sound, error code: " + std::to_string(errorIfAny);
75-
throw oalpp::AudioException { errorMessage.c_str() };
56+
throw oalpp::AudioException { "Could not play sound, error code: "
57+
+ std::to_string(errorIfAny) };
7658
}
7759
}
7860

7961
void Sound::stop()
8062
{
8163
alSourceStop(m_sourceId);
8264

83-
deleteSource();
84-
deleteBuffers();
85-
createSource();
86-
createBuffers();
87-
fillBufferFromStart();
65+
deleteSourceAndBuffers();
66+
67+
initSourceAndBuffers();
8868

8969
auto const errorIfAny = alGetError();
9070
if (errorIfAny != AL_NO_ERROR) {
91-
auto const errorMessage = "Could not stop sound, error code: " + std::to_string(errorIfAny);
92-
throw oalpp::AudioException { errorMessage.c_str() };
71+
throw oalpp::AudioException { "Could not stop sound, error code: "
72+
+ std::to_string(errorIfAny) };
9373
}
9474
}
9575

@@ -98,8 +78,8 @@ void Sound::pause()
9878
alSourcePause(m_sourceId);
9979
auto const errorIfAny = alGetError();
10080
if (errorIfAny != AL_NO_ERROR) {
101-
auto const errorMessage = "Could not stop sound, error code: " + std::to_string(errorIfAny);
102-
throw oalpp::AudioException { errorMessage.c_str() };
81+
throw oalpp::AudioException { "Could not stop sound, error code: "
82+
+ std::to_string(errorIfAny) };
10383
}
10484
}
10585

@@ -115,9 +95,7 @@ float Sound::getVolume() const { return m_volume; }
11595
void Sound::setVolume(float newVolume)
11696
{
11797
if (newVolume < 0 || newVolume > 1.0f) {
118-
auto const errorMessage
119-
= std::string { "Could not set volume value: " } + std::to_string(newVolume);
120-
throw std::invalid_argument { errorMessage.c_str() };
98+
throw std::invalid_argument { "Could not set volume value: " + std::to_string(newVolume) };
12199
}
122100
m_volume = newVolume;
123101
alSourcef(m_sourceId, AL_GAIN, newVolume);
@@ -126,35 +104,32 @@ void Sound::setVolume(float newVolume)
126104
void Sound::setPan(float newPan)
127105
{
128106
if (newPan < -1.0f || newPan > 1.0f) {
129-
auto const errorMessage
130-
= std::string { "Could not set pan value: " } + std::to_string(newPan);
131-
throw std::invalid_argument { errorMessage.c_str() };
107+
throw std::invalid_argument {
108+
("Could not set pan value: " + std::to_string(newPan)).c_str()
109+
};
132110
}
133111

134-
setPosition(
135-
std::array<float, 3> { newPan, 0, -static_cast<float>(sqrt(1.0f - newPan * newPan)) });
112+
setPosition(Position { newPan, 0, -static_cast<float>(sqrt(1.0f - newPan * newPan)) });
136113
}
137114

138-
std::array<float, 3> Sound::getPosition() const { return m_position; }
115+
Position Sound::getPosition() const { return m_position; }
139116

140-
void Sound::setPosition(std::array<float, 3> const& newPos)
117+
void Sound::setPosition(Position const& newPosition)
141118
{
142119
if (m_format == AL_FORMAT_STEREO_FLOAT32) {
143120
throw oalpp::AudioException { "Could not set position on non-mono file" };
144121
}
145122

146-
m_position = newPos;
147-
alSource3f(m_sourceId, AL_POSITION, newPos[0], newPos[1], newPos[2]);
123+
m_position = newPosition;
124+
alSource3f(m_sourceId, AL_POSITION, newPosition.x, newPosition.y, newPosition.z);
148125
}
149126

150127
float Sound::getPitch() const { return m_pitch; }
151128

152129
void Sound::setPitch(float const newPitch)
153130
{
154131
if (newPitch <= 0.0f) {
155-
auto const errorMessage
156-
= std::string { "Could not set pitch value: " } + std::to_string(newPitch);
157-
throw std::invalid_argument { errorMessage.c_str() };
132+
throw std::invalid_argument { "Could not set pitch value: " + std::to_string(newPitch) };
158133
}
159134
m_pitch = newPitch;
160135
alSourcef(m_sourceId, AL_PITCH, newPitch);
@@ -192,10 +167,12 @@ void Sound::update()
192167

193168
void Sound::selectSamplesForBuffer(ALuint bufferId)
194169
{
195-
if (m_cursor >= m_soundData.getSamples().size()) {
170+
if (!hasDataToEnqueue()) {
196171
// do not queue any buffer
197172
return;
198-
} else if (m_cursor + BUFFER_SIZE <= m_soundData.getSamples().size()) {
173+
}
174+
175+
if (hasDataForFullBufferToEnqueue()) {
199176
// queue a full buffer
200177
enqueueSamplesToBuffer(bufferId, BUFFER_SIZE);
201178
} else {
@@ -210,6 +187,11 @@ void Sound::selectSamplesForBuffer(ALuint bufferId)
210187
}
211188
}
212189
}
190+
bool Sound::hasDataForFullBufferToEnqueue() const
191+
{
192+
return m_cursor + BUFFER_SIZE <= m_soundData.getSamples().size();
193+
}
194+
bool Sound::hasDataToEnqueue() const { return m_cursor < m_soundData.getSamples().size(); }
213195

214196
bool Sound::getIsLooping() const { return m_isLooping; }
215197
void Sound::setIsLooping(bool value) { m_isLooping = value; }

impl/oalpp/sound.hpp

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@
22
#define OPENALPP_SOUND_HPP
33

44
#include "al.hpp"
5+
#include "position.hpp"
56
#include "sound_data_interface.hpp"
67
#include <array>
7-
#include <memory>
8-
#include <string>
9-
#include <vector>
108

119
namespace oalpp {
1210

13-
// fwd decl.
14-
class SoundContext;
15-
1611
class Sound {
1712
public:
1813
explicit Sound(SoundDataInterface const& soundData);
@@ -26,13 +21,13 @@ class Sound {
2621
float getVolume() const;
2722
void setVolume(float newVolume);
2823

29-
std::array<float, 3> getPosition() const;
24+
Position getPosition() const;
3025

31-
void setPosition(std::array<float, 3> const& newPos);
26+
void setPosition(Position const& newPosition);
3227
void setPan(float newPan);
3328

3429
float getPitch() const;
35-
void setPitch(float const newPitch);
30+
void setPitch(float newPitch);
3631

3732
bool getIsLooping() const;
3833
void setIsLooping(bool value);
@@ -59,18 +54,18 @@ class Sound {
5954
std::size_t m_cursor { 0 };
6055

6156
float m_volume { 1.0f };
62-
std::array<float, 3> m_position { 0.0f, 0.0f, -1.0f };
57+
Position m_position { 0.0f, 0.0f, -1.0f };
6358
float m_pitch { 1.0f };
6459

6560
bool m_isLooping { false };
6661

6762
void enqueueSamplesToBuffer(ALuint buffer, size_t samplesToQueue);
6863
void selectSamplesForBuffer(ALuint bufferId);
69-
void createSource();
70-
void createBuffers();
71-
void fillBufferFromStart();
72-
void deleteSource() const;
73-
void deleteBuffers();
64+
bool hasDataToEnqueue() const;
65+
bool hasDataForFullBufferToEnqueue() const;
66+
67+
void initSourceAndBuffers();
68+
void deleteSourceAndBuffers();
7469
};
7570

7671
} // namespace oalpp

0 commit comments

Comments
 (0)