[Scummvm-git-logs] scummvm master -> 7c2ef344d817f37c2ae5331ac46540dd75bb66bc
sev-
noreply at scummvm.org
Sun Jun 14 22:15:10 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
7c2ef344d8 AUDIO: Separate generating sine waves from the PC Speaker code
Commit: 7c2ef344d817f37c2ae5331ac46540dd75bb66bc
https://github.com/scummvm/scummvm/commit/7c2ef344d817f37c2ae5331ac46540dd75bb66bc
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2026-06-15T00:15:07+02:00
Commit Message:
AUDIO: Separate generating sine waves from the PC Speaker code
Changed paths:
A audio/sine.h
audio/softsynth/pcspk.cpp
audio/softsynth/pcspk.h
engines/made/scriptfuncs.cpp
engines/made/scriptfuncs.h
engines/testbed/sound.cpp
diff --git a/audio/sine.h b/audio/sine.h
new file mode 100644
index 00000000000..2134fc696e6
--- /dev/null
+++ b/audio/sine.h
@@ -0,0 +1,72 @@
+/* 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/>.
+ *
+ */
+
+#ifndef AUDIO_SINE_H
+#define AUDIO_SINE_H
+
+#include "audio/audiostream.h"
+#include "common/util.h"
+
+namespace Audio {
+
+class SineStream : public AudioStream {
+public:
+ SineStream(int freq, int rate = 44100) {
+ _rate = rate;
+ _oscLength = rate / freq;
+ _oscSamples = 0;
+ _volume = 20; // The maximum volume is 255
+ }
+
+
+ int readBuffer(int16 *buffer, const int numSamples) override {
+ for (int i = 0; i < numSamples; i++) {
+ buffer[i] = generateSine(_oscSamples, _oscLength) * _volume;
+ if (_oscSamples++ >= _oscLength)
+ _oscSamples = 0;
+ }
+
+ return numSamples;
+ }
+
+ bool isStereo() const override { return false; }
+ bool endOfData() const override { return false; }
+ bool endOfStream() const override { return false; }
+ int getRate() const override { return _rate; }
+
+protected:
+ int _rate;
+ uint32 _oscLength;
+ uint32 _oscSamples;
+ byte _volume;
+
+ int8 generateSine(uint32 x, uint32 oscLength) const {
+ if (oscLength == 0)
+ return 0;
+
+ // TODO: Maybe using a look-up-table would be better?
+ return CLIP<int16>((int16) (128 * sin(2.0 * M_PI * x / oscLength)), -128, 127);
+ }
+};
+
+}
+
+#endif
diff --git a/audio/softsynth/pcspk.cpp b/audio/softsynth/pcspk.cpp
index c356eabf083..fd74b09e65e 100644
--- a/audio/softsynth/pcspk.cpp
+++ b/audio/softsynth/pcspk.cpp
@@ -31,9 +31,7 @@ PCSpeakerStream::Command::Command(PCSpeaker::WaveForm aWaveForm, float aFrequenc
waveForm(aWaveForm), frequency(aFrequency), length(aLength) { }
const PCSpeakerStream::generatorFunc PCSpeakerStream::generateWave[] =
- {&PCSpeakerStream::generateSquare, &PCSpeakerStream::generateSine,
- &PCSpeakerStream::generateSaw, &PCSpeakerStream::generateTriangle,
- &PCSpeakerStream::generateSilence};
+ {&PCSpeakerStream::generateSquare, &PCSpeakerStream::generateSilence};
PCSpeakerStream::PCSpeakerStream(int rate) {
_rate = rate;
@@ -55,7 +53,7 @@ PCSpeakerStream::~PCSpeakerStream() {
void PCSpeakerStream::play(PCSpeaker::WaveForm wave, int freq, int32 length) {
Common::StackLock lock(_mutex);
- assert((wave >= PCSpeaker::kWaveFormSquare) && (wave <= PCSpeaker::kWaveFormTriangle));
+ assert(wave == PCSpeaker::kWaveFormSquare);
if (_commandActive || !_commandQueue->empty())
// Currently playing back a queued instruction. Stop playback and clear
@@ -158,30 +156,6 @@ int8 PCSpeakerStream::generateSquare(uint32 x, uint32 oscLength) {
return (x < (oscLength / 2)) ? 127 : -128;
}
-int8 PCSpeakerStream::generateSine(uint32 x, uint32 oscLength) {
- if (oscLength == 0)
- return 0;
-
- // TODO: Maybe using a look-up-table would be better?
- return CLIP<int16>((int16) (128 * sin(2.0 * M_PI * x / oscLength)), -128, 127);
-}
-
-int8 PCSpeakerStream::generateSaw(uint32 x, uint32 oscLength) {
- if (oscLength == 0)
- return 0;
-
- return ((x * (65536 / oscLength)) >> 8) - 128;
-}
-
-int8 PCSpeakerStream::generateTriangle(uint32 x, uint32 oscLength) {
- if (oscLength == 0)
- return 0;
-
- int y = ((x * (65536 / (oscLength / 2))) >> 8) - 128;
-
- return (x <= (oscLength / 2)) ? y : (256 - y);
-}
-
int8 PCSpeakerStream::generateSilence(uint32 x, uint32 oscLength) {
return 0;
}
diff --git a/audio/softsynth/pcspk.h b/audio/softsynth/pcspk.h
index 9cdd3ae0b5d..88f5ddb0fdb 100644
--- a/audio/softsynth/pcspk.h
+++ b/audio/softsynth/pcspk.h
@@ -35,9 +35,6 @@ class PCSpeaker {
public:
enum WaveForm {
kWaveFormSquare = 0,
- kWaveFormSine,
- kWaveFormSaw,
- kWaveFormTriangle,
kWaveFormSilence
};
diff --git a/engines/made/scriptfuncs.cpp b/engines/made/scriptfuncs.cpp
index 5a7bec868e8..238a409b39b 100644
--- a/engines/made/scriptfuncs.cpp
+++ b/engines/made/scriptfuncs.cpp
@@ -26,7 +26,7 @@
#include "made/database.h"
#include "made/pmvplayer.h"
-#include "audio/softsynth/pcspk.h"
+#include "audio/sine.h"
#include "backends/audiocd/audiocd.h"
@@ -39,11 +39,6 @@
namespace Made {
ScriptFunctions::ScriptFunctions(MadeEngine *vm) : _vm(vm), _soundStarted(false), _gameAudioVolume(Audio::Mixer::kMaxChannelVolume) {
- // Initialize the two tone generators
- _pcSpeaker1 = new Audio::PCSpeaker();
- _pcSpeaker2 = new Audio::PCSpeaker();
- _pcSpeaker1->init();
- _pcSpeaker2->init();
_soundResource = nullptr;
_soundWasPlaying = false;
}
@@ -51,9 +46,6 @@ ScriptFunctions::ScriptFunctions(MadeEngine *vm) : _vm(vm), _soundStarted(false)
ScriptFunctions::~ScriptFunctions() {
for (uint i = 0; i < _externalFuncs.size(); ++i)
delete _externalFuncs[i];
-
- delete _pcSpeaker1;
- delete _pcSpeaker2;
}
typedef Common::Functor2Mem<int16, int16*, int16, ScriptFunctions> ExternalScriptFunc;
@@ -338,10 +330,14 @@ int16 ScriptFunctions::sfPlayNote(int16 argc, int16 *argv) {
debug(4, "sfPlayNote: Note = %d, Volume(?) = %d", argv[0] - 1, argv[1]);
- _pcSpeaker1->play(Audio::PCSpeaker::kWaveFormSine, freqTable[argv[0] - 1], -1);
+ _vm->_mixer->stopHandle(_sine1);
+
+ Audio::AudioStream *sine = new Audio::SineStream(freqTable[argv[0] - 1], _vm->_mixer->getOutputRate());
+
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sine1, sine);
// TODO: Figure out what to do with the second parameter
- //_pcSpeaker1->setVolume(argv[1]);
+ //_pcSpeaker1->setChannelVolume(_sine1, argv[1]);
return 0;
}
@@ -349,7 +345,7 @@ int16 ScriptFunctions::sfPlayNote(int16 argc, int16 *argv) {
int16 ScriptFunctions::sfStopNote(int16 argc, int16 *argv) {
// Used in the same place as sfPlayNote, with the same parameters
// We just stop the wave generator here
- _pcSpeaker1->stop();
+ _vm->_mixer->stopHandle(_sine1);
return 0;
}
@@ -375,16 +371,23 @@ int16 ScriptFunctions::sfPlayTele(int16 argc, int16 *argv) {
debug(4, "sfPlayTele: Button = %d", argv[0]);
- _pcSpeaker1->play(Audio::PCSpeaker::kWaveFormSine, freqTable1[argv[0]], -1);
- _pcSpeaker2->play(Audio::PCSpeaker::kWaveFormSine, freqTable2[argv[0]], -1);
+ _vm->_mixer->stopHandle(_sine1);
+ _vm->_mixer->stopHandle(_sine2);
+
+ Audio::AudioStream *sine1 = new Audio::SineStream(freqTable1[argv[0]], _vm->_mixer->getOutputRate());
+ Audio::AudioStream *sine2 = new Audio::SineStream(freqTable2[argv[0]], _vm->_mixer->getOutputRate());
+
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sine1, sine1);
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sine2, sine2);
+
return 0;
}
int16 ScriptFunctions::sfStopTele(int16 argc, int16 *argv) {
// Used in the same place as sfPlayTele, with the same parameters
// We just stop both wave generators here
- _pcSpeaker1->stop();
- _pcSpeaker2->stop();
+ _vm->_mixer->stopHandle(_sine1);
+ _vm->_mixer->stopHandle(_sine2);
return 0;
}
diff --git a/engines/made/scriptfuncs.h b/engines/made/scriptfuncs.h
index db6910e4d9d..b39a703d318 100644
--- a/engines/made/scriptfuncs.h
+++ b/engines/made/scriptfuncs.h
@@ -29,10 +29,6 @@
#include "common/debug.h"
#include "common/system.h"
-namespace Audio {
-class PCSpeaker;
-}
-
namespace Made {
class MadeEngine;
@@ -70,7 +66,7 @@ protected:
uint8 _gameAudioVolume;
// PlayNote/StopNote and PlayTele/StopTele wave generators
- Audio::PCSpeaker *_pcSpeaker1, *_pcSpeaker2;
+ Audio::SoundHandle _sine1, _sine2;
Common::Array<const ExternalFunc *> _externalFuncs;
Common::Array<const char *> _externalFuncNames;
diff --git a/engines/testbed/sound.cpp b/engines/testbed/sound.cpp
index 7daa7e1b9da..4800cef31a8 100644
--- a/engines/testbed/sound.cpp
+++ b/engines/testbed/sound.cpp
@@ -19,7 +19,8 @@
*
*/
-#include "audio/softsynth/pcspk.h"
+#include "audio/audiostream.h"
+#include "audio/sine.h"
#include "audio/mods/mod_xm_s3m.h"
#include "audio/mods/universaltracker.h"
@@ -55,14 +56,12 @@ SoundSubsystemDialog::SoundSubsystemDialog() : TestbedInteractionDialog(80, 60,
_mixer = g_system->getMixer();
- // the three streams to be mixed
- Audio::PCSpeakerStream *s1 = new Audio::PCSpeakerStream();
- Audio::PCSpeakerStream *s2 = new Audio::PCSpeakerStream();
- Audio::PCSpeakerStream *s3 = new Audio::PCSpeakerStream();
+ uint rate = _mixer->getOutputRate();
- s1->play(Audio::PCSpeaker::kWaveFormSine, 1000, -1);
- s2->play(Audio::PCSpeaker::kWaveFormSine, 1200, -1);
- s3->play(Audio::PCSpeaker::kWaveFormSine, 1400, -1);
+ // the three streams to be mixed
+ Audio::AudioStream *s1 = new Audio::SineStream(1000, rate);
+ Audio::AudioStream *s2 = new Audio::SineStream(1200, rate);
+ Audio::AudioStream *s3 = new Audio::SineStream(1400, rate);
_mixer->playStream(Audio::Mixer::kPlainSoundType, &_h1, s1);
_mixer->pauseHandle(_h1, true);
@@ -126,17 +125,18 @@ TestExitStatus SoundSubsystem::playBeeps() {
return kTestSkipped;
}
- Audio::PCSpeakerStream *speaker = new Audio::PCSpeakerStream();
Audio::Mixer *mixer = g_system->getMixer();
+ uint rate = mixer->getOutputRate();
+ Audio::AudioStream *stream;
Audio::SoundHandle handle;
- mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, speaker);
// Left Beep
Testsuite::writeOnScreen("Left Beep", Common::Point(0, 100));
+ stream = new Audio::SineStream(1000, rate);
+ mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, stream);
mixer->setChannelBalance(handle, -127);
- speaker->play(Audio::PCSpeaker::kWaveFormSine, 1000, -1);
g_system->delayMillis(500);
- mixer->pauseHandle(handle, true);
+ mixer->stopHandle(handle);
if (Testsuite::handleInteractiveInput(" Were you able to hear the left beep? ", "Yes", "No", kOptionRight)) {
Testsuite::logDetailedPrintf("Error! Left Beep couldn't be detected : Error with Mixer::setChannelBalance()\n");
@@ -145,10 +145,11 @@ TestExitStatus SoundSubsystem::playBeeps() {
// Right Beep
Testsuite::writeOnScreen("Right Beep", Common::Point(0, 100));
+ stream = new Audio::SineStream(1000, rate);
+ mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, stream);
mixer->setChannelBalance(handle, 127);
- mixer->pauseHandle(handle, false);
g_system->delayMillis(500);
- mixer->stopAll();
+ mixer->stopHandle(handle);
if (Testsuite::handleInteractiveInput("Were you able to hear the right beep?", "Yes", "No", kOptionRight)) {
Testsuite::logDetailedPrintf("Error! Right Beep couldn't be detected : Error with Mixer::setChannelBalance()\n");
@@ -160,7 +161,7 @@ TestExitStatus SoundSubsystem::playBeeps() {
TestExitStatus SoundSubsystem::mixSounds() {
Testsuite::clearScreen();
TestExitStatus passed = kTestPassed;
- Common::String info = "Testing Mixer Output by generating multichannel sound output using PC speaker emulator.\n"
+ Common::String info = "Testing Mixer Output by generating multichannel sound output using sine wave forms.\n"
"The mixer should be able to play them simultaneously\n";
if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) {
@@ -313,16 +314,13 @@ TestExitStatus SoundSubsystem::sampleRates() {
TestExitStatus passed = kTestPassed;
Audio::Mixer *mixer = g_system->getMixer();
+ uint rate = mixer->getOutputRate();
- Audio::PCSpeakerStream *s1 = new Audio::PCSpeakerStream();
+ Audio::AudioStream *s1 = new Audio::SineStream(1000, rate);
// Stream at half sampling rate
- Audio::PCSpeakerStream *s2 = new Audio::PCSpeakerStream(s1->getRate() - 10000);
+ Audio::AudioStream *s2 = new Audio::SineStream(1000, rate - 10000);
// Stream at twice sampling rate
- Audio::PCSpeakerStream *s3 = new Audio::PCSpeakerStream(s1->getRate() + 10000);
-
- s1->play(Audio::PCSpeaker::kWaveFormSine, 1000, -1);
- s2->play(Audio::PCSpeaker::kWaveFormSine, 1000, -1);
- s3->play(Audio::PCSpeaker::kWaveFormSine, 1000, -1);
+ Audio::AudioStream *s3 = new Audio::SineStream(1000, rate + 10000);
Audio::SoundHandle handle;
Common::Point pt(0, 100);
More information about the Scummvm-git-logs
mailing list