mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 13:50:13 +00:00
185 lines
5.1 KiB
C++
185 lines
5.1 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "glk/sound.h"
|
|
#include "glk/glk.h"
|
|
#include "glk/events.h"
|
|
#include "common/file.h"
|
|
#include "audio/audiostream.h"
|
|
#include "audio/decoders/aiff.h"
|
|
#include "audio/decoders/mp3.h"
|
|
#include "audio/decoders/raw.h"
|
|
#include "audio/decoders/wave.h"
|
|
|
|
namespace Glk {
|
|
|
|
Sounds::~Sounds() {
|
|
for (int idx = (int)_sounds.size() - 1; idx >= 0; --idx)
|
|
delete _sounds[idx];
|
|
}
|
|
|
|
void Sounds::removeSound(schanid_t snd) {
|
|
for (uint idx = 0; idx < _sounds.size(); ++idx) {
|
|
if (_sounds[idx] == snd) {
|
|
_sounds.remove_at(idx);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
schanid_t Sounds::create(uint rock, uint volume) {
|
|
schanid_t snd = new SoundChannel(this, volume);
|
|
_sounds.push_back(snd);
|
|
return snd;
|
|
}
|
|
|
|
schanid_t Sounds::iterate(schanid_t chan, uint *rockptr) {
|
|
for (int idx = 0; idx < (int)_sounds.size() - 1; ++idx) {
|
|
if (_sounds[idx] == chan) {
|
|
schanid_t next = _sounds[idx + 1];
|
|
if (*rockptr)
|
|
*rockptr = next->_rock;
|
|
|
|
return next;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void Sounds::poll() {
|
|
for (uint idx = 0; idx < _sounds.size(); ++idx)
|
|
_sounds[idx]->poll();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
SoundChannel::SoundChannel(Sounds *owner, uint volume) : _owner(owner),
|
|
_soundNum(0), _rock(0), _notify(0) {
|
|
_defaultVolume = MIN(volume, (uint)GLK_MAXVOLUME);
|
|
|
|
if (g_vm->gli_register_obj)
|
|
_dispRock = (*g_vm->gli_register_obj)(this, gidisp_Class_Schannel);
|
|
}
|
|
|
|
SoundChannel::~SoundChannel() {
|
|
stop();
|
|
_owner->removeSound(this);
|
|
|
|
if (g_vm->gli_unregister_obj)
|
|
(*g_vm->gli_unregister_obj)(this, gidisp_Class_Schannel, _dispRock);
|
|
}
|
|
|
|
uint SoundChannel::play(uint soundNum, uint repeats, uint notify) {
|
|
stop();
|
|
if (repeats == 0)
|
|
return 1;
|
|
|
|
// Find a sound of the given name
|
|
Audio::AudioStream *stream;
|
|
Common::File f;
|
|
Common::Path nameSnd(Common::String::format("sound%u.snd", soundNum));
|
|
Common::Path nameWav(Common::String::format("sound%u.wav", soundNum));
|
|
Common::Path nameAiff(Common::String::format("sound%u.aiff", soundNum));
|
|
#ifdef USE_MAD
|
|
Common::Path nameMp3(Common::String::format("sound%u.mp3", soundNum));
|
|
#endif
|
|
|
|
if (f.exists(nameSnd) && f.open(nameSnd)) {
|
|
if (f.readUint16BE() != (f.size() - 2))
|
|
error("Invalid sound filesize");
|
|
byte headerRepeats = f.readByte();
|
|
if (headerRepeats > 0)
|
|
repeats = headerRepeats;
|
|
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);
|
|
|
|
#ifdef USE_MAD
|
|
} else if (f.exists(nameMp3) && f.open(nameMp3)) {
|
|
Common::SeekableReadStream *s = f.readStream(f.size());
|
|
stream = Audio::makeMP3Stream(s, DisposeAfterUse::YES);
|
|
#endif
|
|
} else if (f.exists(nameWav) && f.open(nameWav)) {
|
|
Common::SeekableReadStream *s = f.readStream(f.size());
|
|
stream = Audio::makeWAVStream(s, DisposeAfterUse::YES);
|
|
|
|
} else if (f.exists(nameAiff) && f.open(nameAiff)) {
|
|
Common::SeekableReadStream *s = f.readStream(f.size());
|
|
stream = Audio::makeAIFFStream(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, -1,
|
|
_defaultVolume * 255 / GLK_MAXVOLUME);
|
|
return 0;
|
|
}
|
|
|
|
void SoundChannel::stop() {
|
|
g_vm->_mixer->stopHandle(_handle);
|
|
}
|
|
|
|
void SoundChannel::poll() {
|
|
if (!g_vm->_mixer->isSoundHandleActive(_handle) && _notify != 0) {
|
|
uint notify = _notify;
|
|
_notify = 0;
|
|
g_vm->_events->store(evtype_SoundNotify, nullptr, _soundNum, notify);
|
|
}
|
|
}
|
|
|
|
void SoundChannel::setVolume(uint volume, uint duration, uint notify) {
|
|
uint newVol = volume * 255 / GLK_MAXVOLUME;
|
|
g_vm->_mixer->setChannelVolume(_handle, newVol);
|
|
|
|
if (notify) {
|
|
warning("TODO: Gradual volume change");
|
|
g_vm->_events->store(evtype_VolumeNotify, nullptr, 0, notify);
|
|
}
|
|
}
|
|
|
|
void SoundChannel::pause() {
|
|
g_vm->_mixer->pauseHandle(_handle, true);
|
|
}
|
|
|
|
void SoundChannel::unpause() {
|
|
g_vm->_mixer->pauseHandle(_handle, false);
|
|
}
|
|
|
|
} // End of namespace Glk
|