aboutsummaryrefslogtreecommitdiff
path: root/engines/mortevielle/sound.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mortevielle/sound.cpp')
-rw-r--r--engines/mortevielle/sound.cpp144
1 files changed, 143 insertions, 1 deletions
diff --git a/engines/mortevielle/sound.cpp b/engines/mortevielle/sound.cpp
index f2b70cf8ee..08dbe0ba02 100644
--- a/engines/mortevielle/sound.cpp
+++ b/engines/mortevielle/sound.cpp
@@ -27,15 +27,125 @@
#include "common/scummsys.h"
#include "mortevielle/sound.h"
+#include "mortevielle/mortevielle.h"
namespace Mortevielle {
+/**
+ * Constructor
+ */
+PCSpeaker::PCSpeaker(int rate) {
+ _rate = rate;
+ _oscLength = 0;
+ _oscSamples = 0;
+ _remainingSamples = 0;
+ _volume = 255;
+}
+
+/**
+ * Destructor
+ */
+PCSpeaker::~PCSpeaker() {
+}
+
+/**
+ * Adds a new note to the queue of notes to be played.
+ */
+void PCSpeaker::play(int freq, uint32 length) {
+ assert((freq > 0) && (length > 0));
+ Common::StackLock lock(_mutex);
+
+ _pendingNotes.push(SpeakerNote(freq, length));
+}
+
+/**
+ * Stops the currently playing song
+ */
+void PCSpeaker::stop() {
+ Common::StackLock lock(_mutex);
+
+ _remainingSamples = 0;
+ _pendingNotes.clear();
+}
+
+void PCSpeaker::setVolume(byte volume) {
+ _volume = volume;
+}
+
+/**
+ * Return true if a song is currently playing
+ */
+bool PCSpeaker::isPlaying() const {
+ return !_pendingNotes.empty() || (_remainingSamples != 0);
+}
+
+/**
+ * Method used by the mixer to pull off pending samples to play
+ */
+int PCSpeaker::readBuffer(int16 *buffer, const int numSamples) {
+ Common::StackLock lock(_mutex);
+
+ int i;
+
+ for (i = 0; (_remainingSamples || !_pendingNotes.empty()) && (i < numSamples); i++) {
+ if (!_remainingSamples)
+ // Used up the current note, so queue the next one
+ dequeueNote();
+
+ buffer[i] = generateSquare(_oscSamples, _oscLength) * _volume;
+ if (_oscSamples++ >= _oscLength)
+ _oscSamples = 0;
+
+ _remainingSamples--;
+ }
+
+ // Clear the rest of the buffer
+ if (i < numSamples)
+ memset(buffer + i, 0, (numSamples - i) * sizeof(int16));
+
+ return numSamples;
+}
+
+/**
+ * Dequeues a note from the pending note list
+ */
+void PCSpeaker::dequeueNote() {
+ SpeakerNote note = _pendingNotes.pop();
+
+ _oscLength = _rate / note.freq;
+ _oscSamples = 0;
+ _remainingSamples = (_rate * note.length) / 1000000;
+ assert((_oscLength > 0) && (_remainingSamples > 0));
+}
+
+/**
+ * Support method for generating a square wave
+ */
+int8 PCSpeaker::generateSquare(uint32 x, uint32 oscLength) {
+ return (x < (oscLength / 2)) ? 127 : -128;
+}
+
+/*-------------------------------------------------------------------------*/
+
const int tab[16] = { -96, -72, -48, -32, -20, -12, -8, -4, 0, 4, 8, 12, 20, 32, 48, 72 };
+SoundManager::SoundManager(Audio::Mixer *mixer) {
+ _mixer = mixer;
+ _speakerStream = new PCSpeaker(mixer->getOutputRate());
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle,
+ _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+}
+
+SoundManager::~SoundManager() {
+ _mixer->stopHandle(_speakerHandle);
+ delete _speakerStream;
+
+}
+
/**
* Decode music data
*/
-void demus(const byte *PSrc, byte *PDest, int NbreSeg) {
+void SoundManager::demus(const byte *PSrc, byte *PDest, int NbreSeg) {
int seed = 128;
int v;
@@ -53,4 +163,36 @@ void demus(const byte *PSrc, byte *PDest, int NbreSeg) {
}
}
+void SoundManager::litph(tablint &t, int typ, int tempo) {
+ return;
+}
+
+void SoundManager::playNote(int frequency, int32 length) {
+ _speakerStream->play(frequency, length);
+}
+
+
+void SoundManager::musyc(tablint &tb, int nbseg, int att) {
+#ifdef DEBUG
+ const byte *pSrc = &mem[0x5000 * 16];
+
+ // Convert the countdown amount to a tempo rate, and then to note length in microseconds
+ int tempo = 1193180 / att;
+ int length = 1000000 / tempo;
+
+ for (int noteIndex = 0; noteIndex < (nbseg * 16); ++noteIndex) {
+ int lookupValue = *pSrc++;
+ int noteCountdown = tb[lookupValue];
+ int noteFrequency = 1193180 / noteCountdown;
+
+ playNote(noteFrequency, length);
+ }
+
+ // Keep waiting until the song has been finished
+ while (_speakerStream->isPlaying() && !g_vm->shouldQuit()) {
+ g_vm->delay(10);
+ }
+#endif
+}
+
} // End of namespace Mortevielle