aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--audio/decoders/mp3.h1
-rw-r--r--engines/glk/events.cpp5
-rw-r--r--engines/glk/frotz/sound_folder.cpp2
-rw-r--r--engines/glk/glk_api.cpp41
-rw-r--r--engines/glk/sound.cpp83
-rw-r--r--engines/glk/sound.h34
6 files changed, 143 insertions, 23 deletions
diff --git a/audio/decoders/mp3.h b/audio/decoders/mp3.h
index 4740d5279a..5054cac98b 100644
--- a/audio/decoders/mp3.h
+++ b/audio/decoders/mp3.h
@@ -25,6 +25,7 @@
* Sound decoder used in engines:
* - agos
* - draci
+ * - glk
* - kyra
* - mohawk
* - queen
diff --git a/engines/glk/events.cpp b/engines/glk/events.cpp
index 8f3d5ef190..e6f046ca25 100644
--- a/engines/glk/events.cpp
+++ b/engines/glk/events.cpp
@@ -25,6 +25,7 @@
#include "glk/glk.h"
#include "glk/screen.h"
#include "glk/selection.h"
+#include "glk/sound.h"
#include "glk/windows.h"
#include "graphics/cursorman.h"
@@ -107,7 +108,9 @@ void Events::checkForNextFrameCounter() {
g_vm->_windows->redraw();
_redraw = false;
g_vm->_screen->update();
- return;
+
+ // Poll for any finished sounds
+ g_vm->_sounds->poll();
}
}
diff --git a/engines/glk/frotz/sound_folder.cpp b/engines/glk/frotz/sound_folder.cpp
index 20f22a83b4..91916c4ddc 100644
--- a/engines/glk/frotz/sound_folder.cpp
+++ b/engines/glk/frotz/sound_folder.cpp
@@ -71,7 +71,7 @@ const Common::ArchiveMemberPtr SoundSubfolder::getMember(const Common::String &n
Common::SeekableReadStream *SoundSubfolder::createReadStreamForMember(const Common::String &name) const {
Common::File *f = new Common::File();
- if (f->open(_folder.getChild(name)))
+ if (_filenames.contains(name) && f->open(_folder.getChild(_filenames[name])))
return f;
delete f;
diff --git a/engines/glk/glk_api.cpp b/engines/glk/glk_api.cpp
index 11047893ef..c24d452a50 100644
--- a/engines/glk/glk_api.cpp
+++ b/engines/glk/glk_api.cpp
@@ -975,7 +975,11 @@ schanid_t GlkAPI::glk_schannel_create(glui32 rock) {
}
void GlkAPI::glk_schannel_destroy(schanid_t chan) {
- delete chan;
+ if (chan) {
+ delete chan;
+ } else {
+ warning("schannel_dest roy: invalid ref");
+ }
}
schanid_t GlkAPI::glk_schannel_iterate(schanid_t chan, glui32 *rockptr) {
@@ -983,21 +987,38 @@ schanid_t GlkAPI::glk_schannel_iterate(schanid_t chan, glui32 *rockptr) {
}
glui32 GlkAPI::glk_schannel_get_rock(schanid_t chan) {
- return chan->_rock;
+ if (chan) {
+ return chan->_rock;
+ } else {
+ warning("schannel_get_rock: invalid ref");
+ return 0;
+ }
}
glui32 GlkAPI::glk_schannel_play(schanid_t chan, glui32 snd) {
- // TODO
- return 0;
+ if (chan) {
+ return chan->play(snd);
+ } else {
+ warning("schannel_play_ext: invalid ref");
+ return 0;
+ }
}
glui32 GlkAPI::glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats, glui32 notify) {
- // TODO
- return 0;
+ if (chan) {
+ chan->play(snd, repeats, notify);
+ } else {
+ warning("schannel_play_ext: invalid ref");
+ return 0;
+ }
}
void GlkAPI::glk_schannel_stop(schanid_t chan) {
- // TODO
+ if (chan) {
+ chan->stop();
+ } else {
+ warning("schannel_stop: invalid ref");
+ }
}
void GlkAPI::glk_schannel_set_volume(schanid_t chan, glui32 vol) {
@@ -1005,17 +1026,17 @@ void GlkAPI::glk_schannel_set_volume(schanid_t chan, glui32 vol) {
}
void GlkAPI::glk_sound_load_hint(glui32 snd, glui32 flag) {
- // TODO
+ // No implementation
}
schanid_t GlkAPI::glk_schannel_create_ext(glui32 rock, glui32 volume) {
- // TODO
+ // No implementation
return nullptr;
}
glui32 GlkAPI::glk_schannel_play_multi(schanid_t *chanarray, glui32 chancount,
glui32 *sndarray, glui32 soundcount, glui32 notify) {
- // TODO
+ // No implementation
return 0;
}
diff --git a/engines/glk/sound.cpp b/engines/glk/sound.cpp
index 5c98b93e09..85f7e01702 100644
--- a/engines/glk/sound.cpp
+++ b/engines/glk/sound.cpp
@@ -21,6 +21,13 @@
*/
#include "glk/sound.h"
+#include "glk/glk.h"
+#include "glk/events.h"
+#include "common/file.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+#include "audio/decoders/mp3.h"
+#include "audio/decoders/wave.h"
namespace Glk {
@@ -39,7 +46,7 @@ void Sounds::removeSound(schanid_t snd) {
}
schanid_t Sounds::create(glui32 rock) {
- schanid_t snd = new SoundChannel();
+ schanid_t snd = new SoundChannel(this);
_sounds.push_back(snd);
return snd;
}
@@ -58,15 +65,83 @@ schanid_t Sounds::iterate(schanid_t chan, glui32 *rockptr) {
return nullptr;
}
+void Sounds::poll() {
+ for (uint idx = 0; idx < _sounds.size(); ++idx)
+ _sounds[idx]->poll();
+}
+
/*--------------------------------------------------------------------------*/
+SoundChannel::SoundChannel(Sounds *owner) : _owner(owner), _soundNum(0),
+ _rock(0), _notify(0) {
+}
+
SoundChannel::~SoundChannel() {
+ stop();
_owner->removeSound(this);
- delete _stream;
}
-void SoundChannel::play(uint soundNum) {
- // TODO
+glui32 SoundChannel::play(glui32 soundNum, glui32 repeats, glui32 notify) {
+ stop();
+ if (repeats == 0)
+ return 1;
+
+ // Find a sound of the given name
+ Audio::AudioStream *stream;
+ Common::File f;
+ Common::String nameSnd = Common::String::format("sound%u.snd", soundNum);
+ Common::String nameMp3 = Common::String::format("sound%u.mp3", soundNum);
+ Common::String nameWav = Common::String::format("sound%u.wav", soundNum);
+
+ if (f.exists(nameSnd) && f.open(nameSnd)) {
+ if (f.readUint16BE() != (f.size() - 2))
+ error("Invalid sound filesize");
+ repeats = f.readByte();
+ f.skip(1);
+ uint freq = f.readUint16BE();
+ f.skip(2);
+ uint size = f.readUint16BE();
+
+ Common::SeekableReadStream *s = f.readStream(size);
+ stream = Audio::makeRawStream(s, freq, Audio::FLAG_UNSIGNED);
+
+ } else if (f.exists(nameMp3) && f.open(nameMp3)) {
+ Common::SeekableReadStream *s = f.readStream(f.size());
+ stream = Audio::makeMP3Stream(s, DisposeAfterUse::YES);
+
+ } else if (f.exists(nameWav) && f.open(nameWav)) {
+ Common::SeekableReadStream *s = f.readStream(f.size());
+ stream = Audio::makeWAVStream(s, DisposeAfterUse::YES);
+
+ } else {
+ warning("Could not find sound %u", soundNum);
+ return 1;
+ }
+
+ _soundNum = soundNum;
+ _notify = notify;
+
+ // Set up a repeat if multiple repeats are specified
+ if (repeats > 1) {
+ Audio::RewindableAudioStream *rwStream = dynamic_cast<Audio::RewindableAudioStream *>(stream);
+ assert(rwStream);
+ stream = new Audio::LoopingAudioStream(rwStream, repeats, DisposeAfterUse::YES);
+ }
+
+ // Start playing the audio
+ g_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, stream);
+ return 0;
+}
+
+void SoundChannel::stop() {
+ g_vm->_mixer->stopHandle(_handle);
+}
+
+void SoundChannel::poll() {
+ if (!g_vm->_mixer->isSoundHandleActive(_handle) && _notify != 0)
+ g_vm->_events->store(evtype_SoundNotify, 0,
+ _soundNum, _notify);
+
}
} // End of namespace Glk
diff --git a/engines/glk/sound.h b/engines/glk/sound.h
index 05875eaa32..514a5f6ad2 100644
--- a/engines/glk/sound.h
+++ b/engines/glk/sound.h
@@ -25,6 +25,7 @@
#include "glk/glk_types.h"
#include "audio/audiostream.h"
+#include "audio/mixer.h"
#include "common/array.h"
namespace Glk {
@@ -34,15 +35,19 @@ class Sounds;
/**
* Holds the data for a playing sound
*/
-struct SoundChannel {
+class SoundChannel {
+private:
Sounds *_owner;
- Audio::AudioStream *_stream;
+ glui32 _soundNum;
+ glui32 _notify;
+ Audio::SoundHandle _handle;
+public:
glui32 _rock;
-
+public:
/**
- * Destructor
+ * Constructor
*/
- SoundChannel() : _stream(nullptr), _rock(0) {}
+ SoundChannel(Sounds *owner);
/**
* Destructor
@@ -52,7 +57,17 @@ struct SoundChannel {
/**
* Play a sound
*/
- void play(uint soundNum);
+ glui32 play(glui32 soundNum, glui32 repeats = 1, glui32 notify = 0);
+
+ /**
+ * Stop playing sound
+ */
+ void stop();
+
+ /**
+ * Poll for whether a playing sound was finished
+ */
+ void poll();
};
typedef SoundChannel *schanid_t;
@@ -60,7 +75,7 @@ typedef SoundChannel *schanid_t;
* Sound manager
*/
class Sounds {
- friend struct SoundChannel;
+ friend class SoundChannel;
private:
Common::Array<schanid_t> _sounds;
private:
@@ -80,6 +95,11 @@ public:
* Used to iterate over the current list of sound channels
*/
schanid_t iterate(schanid_t chan, glui32 *rockptr = nullptr);
+
+ /**
+ * Poll for whether any playing sounds are finished
+ */
+ void poll();
};
} // End of namespace Glk