aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/adl/adl.cpp25
-rw-r--r--engines/adl/adl.h2
-rw-r--r--engines/adl/module.mk2
-rw-r--r--engines/adl/sound.cpp144
-rw-r--r--engines/adl/sound.h (renamed from engines/adl/speaker.h)43
-rw-r--r--engines/adl/speaker.cpp94
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