10#include "kgameopenalruntime_p.h"
11#include "virtualfileqt-openal.h"
12#include <kdegames_audio_logging.h>
16class KGameSoundPrivate
24 ALuint m_buffer = AL_NONE;
27 KGameSoundPrivate() =
default;
34 , d_ptr(new KGameSoundPrivate)
38 VirtualFileQt fileInterface(file);
39 if (!fileInterface.open()) {
40 qCWarning(KDEGAMES_AUDIO_LOG) <<
"Failed to open sound file" << file;
45 SndfileHandle handle(VirtualFileQt::getSndfileVirtualIO(), &fileInterface);
47 qCWarning(KDEGAMES_AUDIO_LOG) <<
"Failed to load sound file" << file <<
". Error message from libsndfile follows.";
48 qCWarning(KDEGAMES_AUDIO_LOG) << handle.strError();
51 const int channelCount = handle.channels();
52 const int sampleCount = channelCount * handle.frames();
53 const int sampleRate = handle.samplerate();
56 if (handle.read(samples.
data(), sampleCount) < sampleCount) {
57 qCWarning(KDEGAMES_AUDIO_LOG) <<
"Failed to read sound file" << file;
58 qCWarning(KDEGAMES_AUDIO_LOG) <<
"File ended unexpectedly.";
63 switch (channelCount) {
65 format = AL_FORMAT_MONO16;
68 format = AL_FORMAT_STEREO16;
71 qCWarning(KDEGAMES_AUDIO_LOG) <<
"Failed to read sound file" << file;
72 qCWarning(KDEGAMES_AUDIO_LOG) <<
"More than two channels are not supported.";
76 KGameOpenALRuntime::instance();
80 alGenBuffers(1, &d->m_buffer);
81 if ((error = alGetError()) != AL_NO_ERROR) {
82 qCWarning(KDEGAMES_AUDIO_LOG) <<
"Failed to create OpenAL buffer: Error code" << error;
85 alBufferData(d->m_buffer, format, samples.
data(), sampleCount *
sizeof(ALshort), sampleRate);
86 if ((error = alGetError()) != AL_NO_ERROR) {
87 qCWarning(KDEGAMES_AUDIO_LOG) <<
"Failed to fill OpenAL buffer: Error code" << error;
88 alDeleteBuffers(1, &d->m_buffer);
101 KGameOpenALRuntime::instance()->m_soundsEvents.remove(
this);
102 alDeleteBuffers(1, &d->m_buffer);
124 if (d->m_type == type)
127 Q_EMIT playbackTypeChanged(type);
147qreal KGameSound::volume()
const
158 if (d->m_volume == volume)
160 d->m_volume = volume;
161 Q_EMIT volumeChanged(volume);
183 KGameOpenALRuntime *runtime = KGameOpenALRuntime::instance();
184 if (!runtime->instance()->m_soundsEvents[
this].isEmpty()) {
185 if (runtime->instance()->m_soundsEvents[
this].last()->replay(pos) ==
false) {
186 new KGamePlaybackEvent(
this, pos);
189 new KGamePlaybackEvent(
this, pos);
196 qDeleteAll(KGameOpenALRuntime::instance()->m_soundsEvents.take(
this));
206 KGameOpenALRuntime *runtime = KGameOpenALRuntime::instance();
211 alGenSources(1, &m_source);
212 if ((error = alGetError()) != AL_NO_ERROR) {
213 qCWarning(KDEGAMES_AUDIO_LOG) <<
"Failed to create OpenAL source: Error code" << error;
217 runtime->m_soundsEvents[sound] <<
this;
220 alSource3f(m_source, AL_POSITION, pos.
x(), pos.
y(), 0);
221 alSourcef(m_source, AL_PITCH, 1.0);
222 alSourcef(m_source, AL_GAIN, sound->volume());
223 alSourcei(m_source, AL_BUFFER, sound->d_ptr->m_buffer);
227 if ((error = alGetError()) != AL_NO_ERROR) {
228 qCWarning(KDEGAMES_AUDIO_LOG) <<
"Failed to setup OpenAL source: Error code" <<
error;
232 alSourcePlay(m_source);
235KGamePlaybackEvent::~KGamePlaybackEvent()
237 if (alIsSource(m_source) == AL_TRUE) {
238 alSourceStop(m_source);
239 alDeleteSources(1, &m_source);
243bool KGamePlaybackEvent::isRunning()
const
246 alGetSourcei(m_source, AL_SOURCE_STATE, &state);
247 return state == AL_PLAYING;
250bool KGamePlaybackEvent::replay(
QPointF pos)
const
252 if (alIsSource(m_source) == AL_TRUE) {
253 alSourceStop(m_source);
254 alSource3f(m_source, AL_POSITION, pos.
x(), pos.
y(), 0);
255 alSourcePlay(m_source);
264#include "moc_kgamesound.cpp"
This class models a sound file.
void setVolume(qreal volume)
Sets the volume of this sound.
~KGameSound() override
Destroys this KGameSound instance.
void stop()
Stops any playbacks of this sounds.
void setPlaybackType(KGameSound::PlaybackType type)
Sets the playback type for this sound.
PlaybackType
This enumeration describes how a sound can be played back.
@ RelativePlayback
Positional playback enabled.
@ AmbientPlayback
Positional playback disabled.
void setPos(QPointF pos)
Sets the position of this sound.
void start()
Starts a new playback instance of this sound.
KGameSound(const QString &file, QObject *parent=nullptr)
Loads a new sound from the given file.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)