diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/adl/adl.cpp | 25 | ||||
-rw-r--r-- | engines/adl/adl.h | 2 | ||||
-rw-r--r-- | engines/adl/module.mk | 2 | ||||
-rw-r--r-- | engines/adl/sound.cpp | 144 | ||||
-rw-r--r-- | engines/adl/sound.h (renamed from engines/adl/speaker.h) | 43 | ||||
-rw-r--r-- | engines/adl/speaker.cpp | 94 |
6 files changed, 195 insertions, 115 deletions
diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index c1c3820b10..e92cd690c8 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -39,14 +39,13 @@ #include "adl/display.h" #include "adl/detection.h" #include "adl/graphics.h" -#include "adl/speaker.h" +#include "adl/sound.h" namespace Adl { AdlEngine::~AdlEngine() { delete _display; delete _graphics; - delete _speaker; delete _console; delete _dumpFile; } @@ -56,7 +55,6 @@ AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : _dumpFile(nullptr), _display(nullptr), _graphics(nullptr), - _speaker(nullptr), _isRestarting(false), _isRestoring(false), _isQuitting(false), @@ -461,7 +459,25 @@ void AdlEngine::drawPic(byte pic, Common::Point pos) const { } void AdlEngine::bell(uint count) const { - _speaker->bell(count); + Tones tones; + + for (uint i = 0; i < count - 1; ++i) { + tones.push_back(Tone(940.0, 100.0)); + tones.push_back(Tone(0.0, 12.0)); + } + + tones.push_back(Tone(940.0, 100.0)); + + Audio::SoundHandle handle; + Audio::AudioStream *stream = new Sound(tones); + + g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &handle, stream); + + while (!g_engine->shouldQuit() && g_system->getMixer()->isSoundHandleActive(handle)) { + Common::Event event; + pollEvent(event); + g_system->delayMillis(16); + } } const Region &AdlEngine::getRegion(uint i) const { @@ -644,7 +660,6 @@ Common::Error AdlEngine::run() { initGraphics(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, true); _console = new Console(this); - _speaker = new Speaker(); _display = new Display(); setupOpcodeTables(); diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 62c5ea1b8e..c9b97237c4 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -53,7 +53,6 @@ namespace Adl { class Console; class Display; class GraphicsMan; -class Speaker; struct AdlGameDescription; class ScriptEnv; @@ -347,7 +346,6 @@ protected: Display *_display; GraphicsMan *_graphics; - Speaker *_speaker; // Opcodes typedef Common::Functor1<ScriptEnv &, int> Opcode; diff --git a/engines/adl/module.mk b/engines/adl/module.mk index df9dd2d232..b23ea5b2ef 100644 --- a/engines/adl/module.mk +++ b/engines/adl/module.mk @@ -19,7 +19,7 @@ MODULE_OBJS := \ hires4.o \ hires5.o \ hires6.o \ - speaker.o + sound.o MODULE_DIRS += \ engines/adl diff --git a/engines/adl/sound.cpp b/engines/adl/sound.cpp new file mode 100644 index 0000000000..17f4955a12 --- /dev/null +++ b/engines/adl/sound.cpp @@ -0,0 +1,144 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/system.h" + +#include "audio/mixer.h" + +#include "adl/sound.h" + +namespace Adl { + +// Generic PC-speaker synth +// This produces more accurate frequencies than Audio::PCSpeaker, but only +// does square waves. +class Speaker { +public: + Speaker(int sampleRate); + + void startTone(double freq); + void stopTone(); + void generateSamples(int16 *buffer, int numSamples); + +private: + int _rate; + frac_t _halfWaveLen, _halfWaveRem; + int16 _curSample; +}; + +Speaker::Speaker(int sampleRate) : + _rate(sampleRate), + _curSample(32767) { + + stopTone(); +} + +void Speaker::startTone(double freq) { + _halfWaveLen = _halfWaveRem = doubleToFrac(_rate / freq / 2); + + if (_halfWaveLen < FRAC_ONE) { + // Tone out of range at this sample rate + stopTone(); + } +} + +void Speaker::stopTone() { + _halfWaveLen = 0; + _halfWaveRem = intToFrac(32767); +} + +void Speaker::generateSamples(int16 *buffer, int numSamples) { + int offset = 0; + + while (offset < numSamples) { + if (_halfWaveRem >= 0 && _halfWaveRem < FRAC_ONE) { + // Rising/falling edge + // Switch level + _curSample = ~_curSample; + // Use transition point fraction for current sample value + buffer[offset++] = _halfWaveRem ^ _curSample; + // Compute next transition point + _halfWaveRem += _halfWaveLen - FRAC_ONE; + } else { + // Low/high level (incl. silence) + // Generate as many samples as we can + const int samples = MIN(numSamples - offset, (int)fracToInt(_halfWaveRem)); + Common::fill(buffer + offset, buffer + offset + samples, _curSample); + offset += samples; + + // Count down to level transition point, unless we're playing silence + if (_halfWaveLen > 0) + _halfWaveRem -= intToFrac(samples); + } + } +} + +Sound::Sound(const Tones &tones) : + _tones(tones), + _toneIndex(0), + _samplesRem(0) { + + _rate = g_system->getMixer()->getOutputRate(); + _speaker = new Speaker(_rate); +} + +Sound::~Sound() { + delete _speaker; +} + +bool Sound::endOfData() const { + return _samplesRem == 0 && _toneIndex == _tones.size(); +} + +int Sound::readBuffer(int16 *buffer, const int numSamples) { + int offset = 0; + + while (offset < numSamples) { + if (_samplesRem == 0) { + // Set up next tone + + if (_toneIndex == _tones.size()) { + // No more tones + return offset; + } + + if (_tones[_toneIndex].freq == 0.0) + _speaker->stopTone(); + else + _speaker->startTone(_tones[_toneIndex].freq); + + // Compute length of tone + _samplesRem = _rate * _tones[_toneIndex++].len / 1000; + } + + // Generate as many samples as we can + const int samples = MIN(numSamples - offset, _samplesRem); + _speaker->generateSamples(buffer + offset, samples); + + _samplesRem -= samples; + offset += samples; + } + + return numSamples; +} + +} // End of namespace Adl diff --git a/engines/adl/speaker.h b/engines/adl/sound.h index 31aaac32d2..8fbeb805ff 100644 --- a/engines/adl/speaker.h +++ b/engines/adl/sound.h @@ -20,28 +20,45 @@ * */ -#ifndef ADL_SPEAKER_H -#define ADL_SPEAKER_H +#ifndef ADL_SOUND_H +#define ADL_SOUND_H -#include "common/types.h" +#include "audio/audiostream.h" -#include "audio/mixer.h" - -namespace Audio { -class AudioStream; -} +#include "common/array.h" +#include "common/frac.h" namespace Adl { -class Speaker { +class Speaker; + +struct Tone { + double freq; // Hz + double len; // ms + + Tone(double frequency, double length) : freq(frequency), len(length) { } +}; + +typedef Common::Array<Tone> Tones; + +class Sound : public Audio::AudioStream { public: - Speaker(); - ~Speaker(); + Sound(const Tones &tones); + ~Sound(); - void bell(uint count); + // AudioStream + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return false; } + bool endOfData() const; + int getRate() const { return _rate; } private: - byte *_bell, *_silence; + const Tones &_tones; + + Speaker *_speaker; + int _rate; + uint _toneIndex; + int _samplesRem; }; } // End of namespace Adl diff --git a/engines/adl/speaker.cpp b/engines/adl/speaker.cpp deleted file mode 100644 index 532d361cd9..0000000000 --- a/engines/adl/speaker.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* 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 2 - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "common/system.h" -#include "common/events.h" - -#include "engines/engine.h" - -#include "audio/audiostream.h" -#include "audio/decoders/raw.h" - -#include "adl/speaker.h" -#include "adl/adl.h" - -namespace Adl { - -// Number of times to duplicate each sample -#define SAMPLE_DUP 4 -// Bell frequency in Hz -#define BELL_FREQ 1000 -// Sample rate -#define SAMPLE_RATE (BELL_FREQ * SAMPLE_DUP * 2) -// Number of waves per 0.1 seconds (bell length) -#define BELL_WAVE_COUNT (SAMPLE_RATE / 10 / SAMPLE_DUP / 2) -// Length of bell in samples -#define BELL_LEN (BELL_WAVE_COUNT * SAMPLE_DUP * 2) -// Length of silence in samples -#define SILENCE_LEN (SAMPLE_RATE / 80) - -Speaker::~Speaker() { - delete[] _bell; - delete[] _silence; -} - -Speaker::Speaker() { - _bell = new byte[BELL_LEN]; - - byte *buf = _bell; - for (uint i = 0; i < BELL_WAVE_COUNT; ++i) { - for (uint j = 0; j < SAMPLE_DUP; ++j) - *buf++ = 0x00; - for (uint j = 0; j < SAMPLE_DUP; ++j) - *buf++ = 0xff; - } - - _silence = new byte[SILENCE_LEN]; - - buf = _silence; - for (uint i = 0; i < SILENCE_LEN; ++i) - *buf++ = 0x80; -} - -void Speaker::bell(uint count) { - Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(SAMPLE_RATE, false); - Audio::SoundHandle handle; - - stream->queueBuffer(_bell, BELL_LEN, DisposeAfterUse::NO, Audio::FLAG_UNSIGNED); - - for (uint i = 1; i < count; ++i) { - stream->queueBuffer(_silence, SILENCE_LEN, DisposeAfterUse::NO, Audio::FLAG_UNSIGNED); - stream->queueBuffer(_bell, BELL_LEN, DisposeAfterUse::NO, Audio::FLAG_UNSIGNED); - } - - stream->finish(); - - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &handle, stream); - - while (!g_engine->shouldQuit() && g_system->getMixer()->isSoundHandleActive(handle)) { - Common::Event event; - static_cast<AdlEngine *>(g_engine)->pollEvent(event); - g_system->delayMillis(16); - } -} - -} // End of namespace Adl |