aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/adpcm.cpp2
-rw-r--r--sound/aiff.cpp6
-rw-r--r--sound/audiocd.cpp116
-rw-r--r--sound/audiocd.h24
-rw-r--r--sound/flac.cpp90
-rw-r--r--sound/flac.h3
-rw-r--r--sound/iff.cpp80
-rw-r--r--sound/iff.h73
-rw-r--r--sound/mixer.h2
-rw-r--r--sound/mods/paula.h4
-rw-r--r--sound/mods/protracker.h11
-rw-r--r--sound/mods/soundfx.cpp306
-rw-r--r--sound/mods/soundfx.h39
-rw-r--r--sound/module.mk2
-rw-r--r--sound/mp3.cpp87
-rw-r--r--sound/mp3.h3
-rw-r--r--sound/softsynth/ym2612.cpp38
-rw-r--r--sound/vorbis.cpp80
-rw-r--r--sound/vorbis.h3
19 files changed, 570 insertions, 399 deletions
diff --git a/sound/adpcm.cpp b/sound/adpcm.cpp
index c6feb45aee..72564d7022 100644
--- a/sound/adpcm.cpp
+++ b/sound/adpcm.cpp
@@ -69,7 +69,7 @@ private:
public:
ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int rate, int channels = 2, uint32 blockAlign = 0);
- ~ADPCMInputStream() {};
+ ~ADPCMInputStream() {}
int readBuffer(int16 *buffer, const int numSamples);
int readBufferOKI(int16 *buffer, const int numSamples);
diff --git a/sound/aiff.cpp b/sound/aiff.cpp
index 4942a66762..5d8d823756 100644
--- a/sound/aiff.cpp
+++ b/sound/aiff.cpp
@@ -46,7 +46,7 @@ uint32 readExtended(Common::SeekableReadStream &stream) {
byte buf[10];
uint32 mantissa;
- uint32 last;
+ uint32 last = 0;
byte exp;
stream.read(buf, 10);
@@ -89,8 +89,8 @@ bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate
bool foundCOMM = false;
bool foundSSND = false;
- uint16 numChannels, bitsPerSample;
- uint32 numSampleFrames, offset, blockSize, soundOffset;
+ uint16 numChannels = 0, bitsPerSample = 0;
+ uint32 numSampleFrames = 0, offset = 0, blockSize = 0, soundOffset = 0;
while ((!foundCOMM || !foundSSND) && !stream.ioFailed()) {
uint32 length, pos;
diff --git a/sound/audiocd.cpp b/sound/audiocd.cpp
index 44fb35a5ef..2635c2a0a6 100644
--- a/sound/audiocd.cpp
+++ b/sound/audiocd.cpp
@@ -23,6 +23,7 @@
#include "common/stdafx.h"
#include "sound/audiocd.h"
+#include "sound/audiostream.h"
#include "sound/mp3.h"
#include "sound/vorbis.h"
#include "sound/flac.h"
@@ -31,91 +32,76 @@
#include "common/util.h"
#include "common/system.h"
-DECLARE_SINGLETON(Audio::AudioCDManager);
-
namespace Audio {
-struct TrackFormat {
- /** Decodername */
- const char* decoderName;
- /**
- * Pointer to a function which tries to open the specified track - the only argument
- * is the number of the track to be played.
- * Returns either a DigitalTrackInfo object representing the requested track or null
- * in case of an error
- */
- DigitalTrackInfo* (*openTrackFunction)(int);
-};
-
-static const TrackFormat s_trackFormats[] = {
- /* decoderName, openTrackFunction */
-#ifdef USE_FLAC
- { "Flac", getFlacTrack },
-#endif
-#ifdef USE_VORBIS
- { "Ogg Vorbis", getVorbisTrack },
-#endif
-#ifdef USE_MAD
- { "MPEG Layer 3", getMP3Track },
-#endif
-
- { NULL, NULL } // Terminator
-};
-
-
AudioCDManager::AudioCDManager() {
- memset(_cachedTracks, 0, sizeof(_cachedTracks));
- memset(_trackInfo, 0, sizeof(_trackInfo));
_cd.playing = false;
_cd.track = 0;
_cd.start = 0;
_cd.duration = 0;
_cd.numLoops = 0;
- _currentCacheIdx = 0;
_mixer = g_system->getMixer();
assert(_mixer);
}
void AudioCDManager::play(int track, int numLoops, int startFrame, int duration) {
if (numLoops != 0 || startFrame != 0) {
- // Try to load the track from a .mp3/.ogg file, and if found, use
- // that. If not found, attempt to do regular Audio CD playback of
- // the requested track.
- int index = getCachedTrack(track);
-
_cd.track = track;
_cd.numLoops = numLoops;
_cd.start = startFrame;
_cd.duration = duration;
- if (index >= 0) {
- _mixer->stopHandle(_cd.handle);
- _cd.playing = true;
+ // Try to load the track from a compressed data file, and if found, use
+ // that. If not found, attempt to start regular Audio CD playback of
+ // the requested track.
+ char trackName[2][16];
+ sprintf(trackName[0], "track%d", track);
+ sprintf(trackName[1], "track%02d", track);
+ Audio::AudioStream *stream = 0;
+
+ for (int i = 0; !stream && i < 2; ++i) {
/*
FIXME: Seems numLoops == 0 and numLoops == 1 both indicate a single repetition,
while all other positive numbers indicate precisely the number of desired
repetitions. Finally, -1 means infinitely many
*/
- numLoops = (numLoops < 1) ? numLoops + 1 : numLoops;
- _trackInfo[index]->play(_mixer, &_cd.handle, numLoops, _cd.start, _cd.duration);
+ // We multiply by 40 / 3 = 1000 / 75 to convert frames to milliseconds
+ stream = AudioStream::openStreamFile(trackName[i], startFrame * 40 / 3, duration * 40 / 3, (numLoops < 1) ? numLoops + 1 : numLoops);
+ }
+
+ // Stop any currently playing emulated track
+ _mixer->stopHandle(_cd.handle);
+
+ // HACK: We abuse _cd.playing to store whether we are playing a real or an emulated track.
+ if (stream != 0) {
+ _cd.playing = true;
+ _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_cd.handle, stream);
} else {
- g_system->playCD(track, numLoops, startFrame, duration);
_cd.playing = false;
+ g_system->playCD(track, numLoops, startFrame, duration);
}
}
}
void AudioCDManager::stop() {
if (_cd.playing) {
+ // Audio CD emulation
_mixer->stopHandle(_cd.handle);
_cd.playing = false;
} else {
+ // Real Audio CD
g_system->stopCD();
}
}
bool AudioCDManager::isPlaying() const {
- return _cd.playing || g_system->pollCD();
+ if (_cd.playing) {
+ // Audio CD emulation
+ return _mixer->isSoundHandleActive(_cd.handle);
+ } else {
+ // Real Audio CD
+ return g_system->pollCD();
+ }
}
void AudioCDManager::updateCD() {
@@ -125,7 +111,8 @@ void AudioCDManager::updateCD() {
// FIXME: We do not update the numLoops parameter here (and in fact,
// currently can't do that). Luckily, only one engine ever checks
// this part of the AudioCD status, namely the SCUMM engine; and it
- // only checks
+ // only checks whether the track is currently set to infinite looping
+ // or not.
_cd.playing = false;
}
} else {
@@ -141,41 +128,4 @@ AudioCDManager::Status AudioCDManager::getStatus() const {
return info;
}
-int AudioCDManager::getCachedTrack(int track) {
- // See if we find the track in the cache
- for (int i = 0; i < CACHE_TRACKS; i++)
- if (_cachedTracks[i] == track) {
- return _trackInfo[i] ? i : -1;
- }
-
- // The track is not already in the cache. Try and see if
- // we can load it.
- DigitalTrackInfo *newTrack = 0;
- for (const TrackFormat *format = s_trackFormats;
- format->openTrackFunction != NULL && newTrack == NULL;
- ++format) {
- newTrack = format->openTrackFunction(track);
- }
-
- int currentIndex = -1;
-
- if (newTrack != NULL) {
- // We successfully loaded a digital track. Store it into _trackInfo.
-
- currentIndex = _currentCacheIdx++;
- _currentCacheIdx %= CACHE_TRACKS;
-
- // First, delete the previous track info object
- delete _trackInfo[currentIndex];
-
- // Then, store the new track info object
- _trackInfo[currentIndex] = newTrack;
- _cachedTracks[currentIndex] = track;
- } else {
- debug(2, "Track %d not available in compressed format", track);
- }
-
- return currentIndex;
-}
-
} // End of namespace Audio
diff --git a/sound/audiocd.h b/sound/audiocd.h
index 23367ba262..281bf1b1b4 100644
--- a/sound/audiocd.h
+++ b/sound/audiocd.h
@@ -32,15 +32,6 @@
namespace Audio {
-class DigitalTrackInfo {
-public:
- virtual ~DigitalTrackInfo() {}
-
- virtual void play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration) = 0;
-// virtual void stop();
-};
-
-
class AudioCDManager : public Common::Singleton<AudioCDManager> {
public:
struct Status {
@@ -73,27 +64,12 @@ private:
friend class Common::Singleton<SingletonBaseType>;
AudioCDManager();
- int getCachedTrack(int track);
-
-private:
/* used for emulated CD music */
struct ExtStatus : Status {
SoundHandle handle;
};
ExtStatus _cd;
- enum {
-#if defined(__PSP__)
- CACHE_TRACKS = 4 //the PSP can't have more than 8 files open simultaneously
- //so don't use more than 4 filehandles for CD tracks
-#else
- CACHE_TRACKS = 10
-#endif
- };
- int _cachedTracks[CACHE_TRACKS];
- DigitalTrackInfo *_trackInfo[CACHE_TRACKS];
- int _currentCacheIdx;
-
Mixer *_mixer;
};
diff --git a/sound/flac.cpp b/sound/flac.cpp
index 61e8800c31..215ccee26e 100644
--- a/sound/flac.cpp
+++ b/sound/flac.cpp
@@ -770,96 +770,6 @@ AudioStream *makeFlacStream(
return input;
}
-
-#pragma mark -
-#pragma mark --- Flac Audio CD emulation ---
-#pragma mark -
-
-
-class FlacTrackInfo : public DigitalTrackInfo {
-private:
- Common::String _filename;
- bool _errorFlag;
-
-public:
- FlacTrackInfo(const char *filename);
- bool error() { return _errorFlag; }
- void play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration);
-};
-
-FlacTrackInfo::FlacTrackInfo(const char *filename) :
- _filename(filename),
- _errorFlag(false) {
-
- // Try to open the file
- Common::File file;
- if (!file.open(_filename)) {
- _errorFlag = true;
- return;
- }
-
- // Next, try to create a FlacInputStream from it
- FlacInputStream *tempStream = new FlacInputStream(&file, false);
-
- // If initialising the stream fails, we set the error flag
- if (!tempStream || !tempStream->isStreamDecoderReady())
- _errorFlag = true;
-
- delete tempStream;
-}
-
-void FlacTrackInfo::play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration) {
- assert(!_errorFlag);
-
- if (error()) {
- debug(1, "FlacTrackInfo::play: invalid state, method should not been called");
- }
-
- // Open the file
- Common::File *file = new Common::File();
- if (!file || !file->open(_filename)) {
- warning("FlacTrackInfo::play: failed to open '%s'", _filename.c_str());
- delete file;
- return;
- }
-
- // Convert startFrame & duration from frames (1/75 s) to milliseconds (1/1000s)
- uint start = startFrame * 1000 / 75;
- uint end = duration ? ((startFrame + duration) * 1000 / 75) : 0;
-
- // ... create an AudioStream ...
- FlacInputStream *input = new FlacInputStream(file, true, start, end, numLoops);
- if (!input->isStreamDecoderReady()) {
- delete input;
- return;
- }
-
- // ... and play it
- mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input);
-}
-
-DigitalTrackInfo* getFlacTrack(int track) {
- assert(track >= 1);
- char trackName[4][32];
-
- sprintf(trackName[0], "track%d.flac", track);
- sprintf(trackName[1], "track%02d.flac", track);
- sprintf(trackName[2], "track%d.fla", track);
- sprintf(trackName[3], "track%02d.fla", track);
-
- for (int i = 0; i < 4; ++i) {
- if (Common::File::exists(trackName[i])) {
- FlacTrackInfo *trackInfo = new FlacTrackInfo(trackName[i]);
- if (!trackInfo->error())
- return trackInfo;
- delete trackInfo;
- }
- }
-
- return NULL;
-}
-
-
} // End of namespace Audio
#endif // #ifdef USE_FLAC
diff --git a/sound/flac.h b/sound/flac.h
index 787a8ad79c..4b4acb3228 100644
--- a/sound/flac.h
+++ b/sound/flac.h
@@ -36,9 +36,6 @@ namespace Common {
namespace Audio {
class AudioStream;
-class DigitalTrackInfo;
-
-DigitalTrackInfo *getFlacTrack(int track);
/**
* Create a new AudioStream from the FLAC data in the given
diff --git a/sound/iff.cpp b/sound/iff.cpp
new file mode 100644
index 0000000000..2fd6378b13
--- /dev/null
+++ b/sound/iff.cpp
@@ -0,0 +1,80 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "sound/iff.h"
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+
+namespace Audio {
+
+
+void A8SVXDecoder::readVHDR(Common::IFFChunk &chunk) {
+ _header.oneShotHiSamples = chunk.readUint32BE();
+ _header.repeatHiSamples = chunk.readUint32BE();
+ _header.samplesPerHiCycle = chunk.readUint32BE();
+ _header.samplesPerSec = chunk.readUint16BE();
+ _header.octaves = chunk.readByte();
+ _header.compression = chunk.readByte();
+ _header.volume = chunk.readUint32BE();
+}
+
+void A8SVXDecoder::readBODY(Common::IFFChunk &chunk) {
+
+ switch (_header.compression) {
+ case 0:
+ _dataSize = chunk.size;
+ _data = (byte*)malloc(_dataSize);
+ chunk.read(_data, _dataSize);
+ break;
+
+ case 1:
+ warning("compressed IFF audio is not supported");
+ break;
+ }
+
+}
+
+
+A8SVXDecoder::A8SVXDecoder(Common::ReadStream &input, Voice8Header &header, byte *&data, uint32 &dataSize) :
+ IFFParser(input), _header(header), _data(data), _dataSize(dataSize) {
+ if (_typeId != ID_8SVX)
+ error("unknown audio format");
+}
+
+void A8SVXDecoder::decode() {
+
+ Common::IFFChunk *chunk;
+
+ while ((chunk = nextChunk()) != 0) {
+ switch (chunk->id) {
+ case ID_VHDR:
+ readVHDR(*chunk);
+ break;
+
+ case ID_BODY:
+ readBODY(*chunk);
+ break;
+ }
+ }
+}
+
+}
diff --git a/sound/iff.h b/sound/iff.h
new file mode 100644
index 0000000000..592cf9c2f0
--- /dev/null
+++ b/sound/iff.h
@@ -0,0 +1,73 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SOUND_IFF_H
+#define SOUND_IFF_H
+
+#include "common/iff_container.h"
+
+namespace Audio {
+
+struct Voice8Header {
+ uint32 oneShotHiSamples;
+ uint32 repeatHiSamples;
+ uint32 samplesPerHiCycle;
+ uint16 samplesPerSec;
+ byte octaves;
+ byte compression;
+ uint32 volume;
+
+ Voice8Header() {
+ memset(this, 0, sizeof(Voice8Header));
+ }
+};
+
+
+/*
+ A8SVX decoder reads 8SVX subtype of IFF files.
+
+ TODO: make a factory function for this kind of stream?
+ */
+class A8SVXDecoder : public Common::IFFParser {
+
+protected:
+ Voice8Header &_header;
+ byte* &_data;
+ uint32 &_dataSize;
+
+protected:
+ void readVHDR(Common::IFFChunk &chunk);
+ void readBODY(Common::IFFChunk &chunk);
+
+public:
+ A8SVXDecoder(Common::ReadStream &input, Voice8Header &header, byte *&data, uint32 &dataSize);
+ void decode();
+};
+
+
+/*
+ TODO: Implement a parser for AIFF subtype.
+ */
+
+}
+
+#endif
diff --git a/sound/mixer.h b/sound/mixer.h
index 5dfef06090..a0a7c93aed 100644
--- a/sound/mixer.h
+++ b/sound/mixer.h
@@ -132,7 +132,7 @@ public:
*
* @return whether the mixer is ready and setup
*/
- bool isReady() const { return _mixerReady; };
+ bool isReady() const { return _mixerReady; }
diff --git a/sound/mods/paula.h b/sound/mods/paula.h
index 134ea8f845..b0c9bc96b8 100644
--- a/sound/mods/paula.h
+++ b/sound/mods/paula.h
@@ -41,7 +41,7 @@ public:
~Paula();
bool playing() const { return _playing; }
- void setInterruptFreq(int freq) { _intFreq = freq; }
+ void setInterruptFreq(int freq) { _curInt = _intFreq = freq; }
void setPanning(byte voice, byte panning) {
assert(voice < NUM_VOICES);
_voice[voice].panning = panning;
@@ -86,7 +86,7 @@ protected:
} else
*buf++ += tmp;
}
- virtual void interrupt(void) {};
+ virtual void interrupt(void) {}
};
} // End of namespace Audio
diff --git a/sound/mods/protracker.h b/sound/mods/protracker.h
index 939b336b2f..7fefddd20c 100644
--- a/sound/mods/protracker.h
+++ b/sound/mods/protracker.h
@@ -31,6 +31,17 @@ namespace Audio {
class AudioStream;
+/*
+ * Factory function for ProTracker streams. Reads all data from the
+ * given ReadStream and creates an AudioStream from this. No reference
+ * to the 'stream' object is kept, so you can safely delete it after
+ * invoking this factory.
+ *
+ * @param stream the ReadStream from which to read the ProTracker data
+ * @param rate TODO
+ * @param stereo TODO
+ * @return a new AudioStream, or NULL, if an error occured
+ */
AudioStream *makeProtrackerStream(Common::ReadStream *stream, int rate = 44100, bool stereo = true);
} // End of namespace Audio
diff --git a/sound/mods/soundfx.cpp b/sound/mods/soundfx.cpp
new file mode 100644
index 0000000000..27e596ac3b
--- /dev/null
+++ b/sound/mods/soundfx.cpp
@@ -0,0 +1,306 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2007 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/endian.h"
+
+#include "sound/mods/paula.h"
+#include "sound/mods/soundfx.h"
+#include "sound/audiostream.h"
+
+namespace Audio {
+
+struct SoundFxInstrument {
+ char name[23];
+ uint16 len;
+ uint8 finetune;
+ uint8 volume;
+ uint16 repeatPos;
+ uint16 repeatLen;
+ int8 *data;
+};
+
+class SoundFx : public Paula {
+public:
+
+ enum {
+ NUM_CHANNELS = 4,
+ NUM_INSTRUMENTS = 15,
+ CIA_FREQ = 715909
+ };
+
+ SoundFx(int rate, bool stereo);
+ virtual ~SoundFx();
+
+ bool load(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb);
+ void play();
+
+protected:
+
+ void handlePattern(int ch, uint32 pat);
+ void updateEffects(int ch);
+ void handleTick();
+
+ void startPaula();
+ void stopPaula();
+ void setPaulaChannelPeriod(uint8 channel, int16 period);
+ void setPaulaChannelVolume(uint8 channel, uint8 volume);
+ void enablePaulaChannel(uint8 channel);
+ void disablePaulaChannel(uint8 channel);
+ void setupPaulaChannel(uint8 channel, const int8 *data, uint16 len, uint16 repeatPos, uint16 repeatLen);
+
+ virtual void interrupt();
+
+ uint8 _ticks;
+ uint16 _delay;
+ SoundFxInstrument _instruments[NUM_INSTRUMENTS];
+ uint8 _numOrders;
+ uint8 _curOrder;
+ uint16 _curPos;
+ uint8 _ordersTable[128];
+ uint8 *_patternData;
+ int _eventsFreq;
+ uint16 _effects[NUM_CHANNELS];
+};
+
+SoundFx::SoundFx(int rate, bool stereo)
+ : Paula(stereo, rate) {
+ _ticks = 0;
+ _delay = 0;
+ memset(_instruments, 0, sizeof(_instruments));
+ _numOrders = 0;
+ _curOrder = 0;
+ _curPos = 0;
+ memset(_ordersTable, 0, sizeof(_ordersTable));
+ _patternData = 0;
+ _eventsFreq = 0;
+ memset(_effects, 0, sizeof(_effects));
+}
+
+SoundFx::~SoundFx() {
+ free(_patternData);
+ for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
+ free(_instruments[i].data);
+ }
+}
+
+bool SoundFx::load(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb) {
+ int instrumentsSize[15];
+ if (!loadCb) {
+ for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
+ instrumentsSize[i] = data->readUint32BE();
+ }
+ }
+ uint8 tag[4];
+ data->read(tag, 4);
+ if (memcmp(tag, "SONG", 4) != 0) {
+ return false;
+ }
+ _delay = data->readUint16BE();
+ data->skip(7 * 2);
+ for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
+ SoundFxInstrument *ins = &_instruments[i];
+ data->read(ins->name, 22); ins->name[22] = 0;
+ ins->len = data->readUint16BE();
+ ins->finetune = data->readByte();
+ ins->volume = data->readByte();
+ ins->repeatPos = data->readUint16BE();
+ ins->repeatLen = data->readUint16BE();
+ }
+ _numOrders = data->readByte();
+ data->skip(1);
+ data->read(_ordersTable, 128);
+ int maxOrder = 0;
+ for (int i = 0; i < _numOrders; ++i) {
+ if (_ordersTable[i] > maxOrder) {
+ maxOrder = _ordersTable[i];
+ }
+ }
+ int patternSize = (maxOrder + 1) * 4 * 4 * 64;
+ _patternData = (uint8 *)malloc(patternSize);
+ if (!_patternData) {
+ return false;
+ }
+ data->read(_patternData, patternSize);
+ for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
+ SoundFxInstrument *ins = &_instruments[i];
+ if (!loadCb) {
+ if (instrumentsSize[i] != 0) {
+ assert(ins->len <= 1 || ins->len * 2 <= instrumentsSize[i]);
+ assert(ins->repeatLen <= 1 || (ins->repeatPos + ins->repeatLen) * 2 <= instrumentsSize[i]);
+ ins->data = (int8 *)malloc(instrumentsSize[i]);
+ if (!ins->data) {
+ return false;
+ }
+ data->read(ins->data, instrumentsSize[i]);
+ }
+ } else {
+ if (ins->name[0]) {
+ ins->name[8] = '\0';
+ ins->data = (int8 *)(*loadCb)(ins->name, 0);
+ if (!ins->data) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void SoundFx::play() {
+ _curPos = 0;
+ _curOrder = 0;
+ _ticks = 0;
+ _eventsFreq = CIA_FREQ / _delay;
+ setInterruptFreq(_rate / _eventsFreq);
+ startPaula();
+}
+
+void SoundFx::handlePattern(int ch, uint32 pat) {
+ uint16 note1 = pat >> 16;
+ uint16 note2 = pat & 0xFFFF;
+ if (note1 != 0xFFFD) {
+ int ins = (note2 & 0xF000) >> 12;
+ if (ins != 0) {
+ SoundFxInstrument *i = &_instruments[ins - 1];
+ setupPaulaChannel(ch, i->data, i->len, i->repeatPos, i->repeatLen);
+ int effect = (note2 & 0xF00) >> 8;
+ int volume = i->volume;
+ switch (effect) {
+ case 5: // volume up
+ volume += (note2 & 0xFF);
+ if (volume > 63) {
+ volume = 63;
+ }
+ break;
+ case 6: // volume down
+ volume -= (note2 & 0xFF);
+ if (volume < 0) {
+ volume = 0;
+ }
+ break;
+ }
+ setPaulaChannelVolume(ch, volume);
+ }
+ }
+ _effects[ch] = note2;
+ if (note1 == 0xFFFD) { // PIC
+ _effects[ch] = 0;
+ } else if (note1 == 0xFFFE) { // STP
+ disablePaulaChannel(ch);
+ } else if (note1 != 0) {
+ setPaulaChannelPeriod(ch, note1);
+ enablePaulaChannel(ch);
+ }
+}
+
+void SoundFx::updateEffects(int ch) {
+ // updateEffects() is a no-op in all Delphine Software games using SoundFx : FW,OS,Cruise,AW
+ if (_effects[ch] != 0) {
+ switch (_effects[ch]) {
+ case 1: // appreggiato
+ case 2: // pitchbend
+ case 3: // ledon, enable low-pass filter
+ case 4: // ledoff, disable low-pass filter
+ case 7: // set step up
+ case 8: // set step down
+ warning("Unhandled effect %d\n", _effects[ch]);
+ break;
+ }
+ }
+}
+
+void SoundFx::handleTick() {
+ ++_ticks;
+ if (_ticks != 6) {
+ for (int ch = 0; ch < 4; ++ch) {
+ updateEffects(ch);
+ }
+ } else {
+ _ticks = 0;
+ const uint8 *patternData = _patternData + _ordersTable[_curOrder] * 1024 + _curPos;
+ for (int ch = 0; ch < 4; ++ch) {
+ handlePattern(ch, READ_BE_UINT32(patternData));
+ patternData += 4;
+ }
+ _curPos += 4 * 4;
+ if (_curPos >= 1024) {
+ _curPos = 0;
+ ++_curOrder;
+ if (_curOrder == _numOrders) {
+ stopPaula();
+ }
+ }
+ }
+}
+
+void SoundFx::startPaula() {
+ _playing = true;
+ _end = false;
+}
+
+void SoundFx::stopPaula() {
+ _playing = false;
+ _end = true;
+}
+
+void SoundFx::setPaulaChannelPeriod(uint8 channel, int16 period) {
+ _voice[channel].period = period;
+}
+
+void SoundFx::setPaulaChannelVolume(uint8 channel, uint8 volume) {
+ _voice[channel].volume = volume;
+}
+
+void SoundFx::enablePaulaChannel(uint8 channel) {
+}
+
+void SoundFx::disablePaulaChannel(uint8 channel) {
+ _voice[channel].period = 0;
+}
+
+void SoundFx::setupPaulaChannel(uint8 channel, const int8 *data, uint16 len, uint16 repeatPos, uint16 repeatLen) {
+ if (data && len > 1) {
+ Channel *ch = &_voice[channel];
+ ch->data = data;
+ ch->dataRepeat = data + repeatPos * 2;
+ ch->length = len * 2;
+ ch->lengthRepeat = repeatLen * 2;
+ ch->offset = 0;
+ }
+}
+
+void SoundFx::interrupt() {
+ handleTick();
+}
+
+AudioStream *makeSoundFxStream(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb, int rate, bool stereo) {
+ SoundFx *stream = new SoundFx(rate, stereo);
+ if (stream->load(data, loadCb)) {
+ stream->play();
+ return stream;
+ }
+ delete stream;
+ return 0;
+}
+
+} // End of namespace Audio
diff --git a/sound/mods/soundfx.h b/sound/mods/soundfx.h
new file mode 100644
index 0000000000..353aa6ecdc
--- /dev/null
+++ b/sound/mods/soundfx.h
@@ -0,0 +1,39 @@
+
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2007 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SOUND_MODS_SOUNDFX_H
+#define SOUND_MODS_SOUNDFX_H
+
+#include "common/stream.h"
+
+namespace Audio {
+
+class AudioStream;
+
+typedef byte *(*LoadSoundFxInstrumentCallback)(const char *name, uint32 *size);
+
+AudioStream *makeSoundFxStream(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb, int rate = 44100, bool stereo = true);
+
+} // End of namespace Audio
+
+#endif
diff --git a/sound/module.mk b/sound/module.mk
index dce7ace08e..a204dbadb9 100644
--- a/sound/module.mk
+++ b/sound/module.mk
@@ -5,6 +5,7 @@ MODULE_OBJS := \
aiff.o \
audiocd.o \
audiostream.o \
+ iff.o \
flac.o \
fmopl.o \
mididrv.o \
@@ -24,6 +25,7 @@ MODULE_OBJS := \
mods/protracker.o \
mods/paula.o \
mods/rjp1.o \
+ mods/soundfx.o \
softsynth/adlib.o \
softsynth/ym2612.o \
softsynth/fluidsynth.o \
diff --git a/sound/mp3.cpp b/sound/mp3.cpp
index ff0e3d61dd..f9efdc4e8c 100644
--- a/sound/mp3.cpp
+++ b/sound/mp3.cpp
@@ -339,93 +339,6 @@ AudioStream *makeMP3Stream(
return new MP3InputStream(stream, disposeAfterUse, start, end, numLoops);
}
-
-#pragma mark -
-#pragma mark --- MP3 Audio CD emulation ---
-#pragma mark -
-
-
-class MP3TrackInfo : public DigitalTrackInfo {
-private:
- Common::String _filename;
- bool _errorFlag;
-
-public:
- MP3TrackInfo(const char *filename);
- bool error() { return _errorFlag; }
- void play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration);
-};
-
-MP3TrackInfo::MP3TrackInfo(const char *filename) :
- _filename(filename),
- _errorFlag(false) {
-
- // Try to open the file
- Common::File file;
- if (!file.open(_filename)) {
- _errorFlag = true;
- return;
- }
-
- // Next, try to create an MP3InputStream from it
- MP3InputStream *tempStream = new MP3InputStream(&file, false);
-
- // If we see EOS here then that means that not (enough) valid input
- // data was given.
- _errorFlag = tempStream->endOfData();
-
- // Clean up again
- delete tempStream;
-}
-
-void MP3TrackInfo::play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration) {
- assert(!_errorFlag);
-
- mad_timer_t start;
- mad_timer_t end;
-
- // Both startFrame and duration are given in frames, where 75 frames are one second.
- // Calculate the appropriate mad_timer_t values from them.
- mad_timer_set(&start, startFrame / 75, startFrame % 75, 75);
- if (duration == 0) {
- end = mad_timer_zero;
- } else {
- int endFrame = startFrame + duration;
- mad_timer_set(&end, endFrame / 75, endFrame % 75, 75);
- }
-
- // Open the file
- Common::File *file = new Common::File();
- if (!file || !file->open(_filename)) {
- warning("MP3TrackInfo::play: failed to open '%s'", _filename.c_str());
- delete file;
- return;
- }
-
- // ... create an AudioStream ...
- MP3InputStream *input = new MP3InputStream(file, true, start, end, numLoops);
-
- // ... and play it
- mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input);
-}
-
-DigitalTrackInfo *getMP3Track(int track) {
- char trackName[2][32];
-
- sprintf(trackName[0], "track%d.mp3", track);
- sprintf(trackName[1], "track%02d.mp3", track);
-
- for (int i = 0; i < 2; ++i) {
- if (Common::File::exists(trackName[i])) {
- MP3TrackInfo *trackInfo = new MP3TrackInfo(trackName[i]);
- if (!trackInfo->error())
- return trackInfo;
- delete trackInfo;
- }
- }
- return NULL;
-}
-
} // End of namespace Audio
#endif // #ifdef USE_MAD
diff --git a/sound/mp3.h b/sound/mp3.h
index 354e880404..d4992ce10f 100644
--- a/sound/mp3.h
+++ b/sound/mp3.h
@@ -36,9 +36,6 @@ namespace Common {
namespace Audio {
class AudioStream;
-class DigitalTrackInfo;
-
-DigitalTrackInfo *getMP3Track(int track);
/**
* Create a new AudioStream from the MP3 data in the given
diff --git a/sound/softsynth/ym2612.cpp b/sound/softsynth/ym2612.cpp
index 5ee864b168..e48f44ebc0 100644
--- a/sound/softsynth/ym2612.cpp
+++ b/sound/softsynth/ym2612.cpp
@@ -90,15 +90,15 @@ void Operator2612::setInstrument(byte const *instrument) {
_specifiedSustainRate = instrument[24] & 31;
_specifiedSustainLevel = (instrument[28] >> 4) & 15;
_specifiedReleaseRate = instrument[28] & 15;
- _state = _s_ready; // 本物ではどうなのかな?
+ _state = _s_ready;
velocity(_velocity);
}
void Operator2612::keyOn() {
_state = _s_attacking;
_tickCount = 0;
- _phase = 0; // どうも、実際こうらしい
- _currentLevel = ((int32)0x7f << 15); // これも、実際こうらしい
+ _phase = 0;
+ _currentLevel = ((int32)0x7f << 15);
}
void Operator2612::keyOff() {
@@ -116,7 +116,7 @@ void Operator2612::frequency(int freq) {
if (r != 0) {
r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
if (r >= 64)
- r = 63; // するべきなんだろうとは思うんだけど (赤p.207)
+ r = 63;
}
r = 63 - r;
@@ -125,7 +125,7 @@ void Operator2612::frequency(int freq) {
else {
value = powtbl[(r&3) << 7];
value *= 1 << (r >> 2);
- value *= 41; // r == 20 のとき、0-96[db] が 10.01[ms] == 41.00096
+ value *= 41;
value /= 1 << (15 + 5);
value *= 127 - _specifiedTotalLevel;
value /= 127;
@@ -156,7 +156,7 @@ void Operator2612::frequency(int freq) {
if (r != 0) {
r = r * 2 + 1; // (Translated) I cannot know whether the timing is a good choice or not
r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- // KS による補正はあるらしい。赤p.206 では記述されてないけど。
+ // KS
if (r >= 64)
r = 63;
}
@@ -229,11 +229,11 @@ void Operator2612::nextTick(const int *phasebuf, int *outbuf, int buflen) {
}
if (level < zero_level) {
- int phaseShift = *phasebuf >> 2; // 正しい変調量は? 3 じゃ小さすぎで 2 じゃ大きいような。
+ int phaseShift = *phasebuf >> 2;
if (_feedbackLevel)
phaseShift += (output << (_feedbackLevel - 1)) / 1024;
output = sintbl[((_phase >> 7) + phaseShift) & 0x7ff];
- output >>= (level >> 18); // 正しい減衰量は?
+ output >>= (level >> 18);
// Here is the original code, which requires 64-bit ints
// output *= powtbl[511 - ((level>>25)&511)];
// output >>= 16;
@@ -438,13 +438,13 @@ void Voice2612::pitchBend(int value) {
}
void Voice2612::recalculateFrequency() {
- // MIDI とも違うし....
- // どういう仕様なんだろうか?
- // と思ったら、なんと、これ (↓) が正解らしい。
+ //
+ //
+ //
int32 basefreq = frequencyTable[_note];
int cfreq = frequencyTable[_note - (_note % 12)];
int oct = _note / 12;
- int fnum = (int) (((double)basefreq * (1 << 13)) / cfreq); // OPL の fnum と同じようなもの。
+ int fnum = (int) (((double)basefreq * (1 << 13)) / cfreq);
fnum += _frequencyOffs - 0x2000;
if (fnum < 0x2000) {
fnum += 0x2000;
@@ -455,7 +455,7 @@ void Voice2612::recalculateFrequency() {
oct++;
}
- // _frequency は最終的にバイアス 256*1024 倍
+ //
_frequency = (int) ((frequencyTable[oct*12] * (double)fnum) / 8);
int i;
@@ -515,7 +515,7 @@ void MidiChannel_YM2612::noteOff(byte note) {
}
void MidiChannel_YM2612::controlChange(byte control, byte value) {
- // いいのかこれで?
+ //
if (control == 121) {
// Reset controller
removeAllVoices();
@@ -537,7 +537,7 @@ void MidiChannel_YM2612::sysEx_customInstrument(uint32 type, const byte *fmInst)
}
void MidiChannel_YM2612::pitchBend(int16 value) {
- // いいのかこれで?
+ //
Voice2612 *voice = _voices;
for (; voice; voice = voice->next)
voice->pitchBend(value);
@@ -696,8 +696,8 @@ void MidiDriver_YM2612::createLookupTables() {
0x03d5, 0x0410, 0x044e, 0x048f,
};
- // (int)(880.0 * 256.0 * pow(2.0, (note-0x51)/12.0)); // バイアス 256 倍
- // 0x45 が 440Hz (a4)、0x51 が 880Hz (a5) らしい
+ // (int)(880.0 * 256.0 * pow(2.0, (note-0x51)/12.0))
+ //
frequencyTable = new int [120];
for (block = -1; block < 9; block++) {
for (i = 0; i < 12; i++) {
@@ -707,7 +707,7 @@ void MidiDriver_YM2612::createLookupTables() {
}
keycodeTable = new int [120];
- // detune 量の計算や KS による rate 変換に使うんじゃないかな
+ // detune
for (block = -1; block < 9; block++) {
for (i = 0; i < 12; i++) {
// see p.204
@@ -730,7 +730,7 @@ void MidiDriver_YM2612::createLookupTables() {
keyscaleTable[0] = 0;
for (freq = 1; freq < 8192; freq++) {
keyscaleTable[freq] = (int)(log((double)freq) / 9.03 * 32.0) - 1;
- // 8368[Hz] (o9c) で 32くらい。9.03 =:= ln 8368
+ // 8368[Hz] (o9c)
}
}
diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp
index 9b88020974..7e9d9dc286 100644
--- a/sound/vorbis.cpp
+++ b/sound/vorbis.cpp
@@ -293,86 +293,6 @@ AudioStream *makeVorbisStream(
}
-#pragma mark -
-#pragma mark --- Ogg Vorbis Audio CD emulation ---
-#pragma mark -
-
-
-class VorbisTrackInfo : public DigitalTrackInfo {
-private:
- Common::String _filename;
- bool _errorFlag;
-
-public:
- VorbisTrackInfo(const char *filename);
- bool error() { return _errorFlag; }
- void play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration);
-};
-
-VorbisTrackInfo::VorbisTrackInfo(const char *filename) :
- _filename(filename),
- _errorFlag(false) {
-
-
- // Try to open the file
- Common::File file;
- if (!file.open(_filename)) {
- _errorFlag = true;
- return;
- }
-
- // Next, try to create a VorbisInputStream from it
- VorbisInputStream *tempStream = new VorbisInputStream(&file, false);
-
- // If an error occured...
- // TODO: add an error or init method to VorbisInputStream
- _errorFlag = tempStream->endOfData();
-
- // Clean up again
- delete tempStream;
-}
-
-void VorbisTrackInfo::play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration) {
- assert(!_errorFlag);
-
- // Open the file
- Common::File *file = new Common::File();
- if (!file || !file->open(_filename)) {
- warning("VorbisTrackInfo::play: failed to open '%s'", _filename.c_str());
- delete file;
- return;
- }
-
- // Convert startFrame & duration from frames (1/75 s) to milliseconds (1/1000s),
- // i.e. multiply with a factor of 1000/75 = 40/3.
- uint start = startFrame * 40 / 3;
- uint end = duration ? ((startFrame + duration) * 40 / 3) : 0;
-
- // ... create an AudioStream ...
- VorbisInputStream *input = new VorbisInputStream(file, true, start, end, numLoops);
-
- // ... and play it
- mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input);
-}
-
-DigitalTrackInfo *getVorbisTrack(int track) {
- char trackName[2][32];
-
- sprintf(trackName[0], "track%d.ogg", track);
- sprintf(trackName[1], "track%02d.ogg", track);
-
- for (int i = 0; i < 2; ++i) {
- if (Common::File::exists(trackName[i])) {
- VorbisTrackInfo *trackInfo = new VorbisTrackInfo(trackName[i]);
- if (!trackInfo->error())
- return trackInfo;
- delete trackInfo;
- }
- }
- return NULL;
-}
-
-
} // End of namespace Audio
#endif // #ifdef USE_VORBIS
diff --git a/sound/vorbis.h b/sound/vorbis.h
index 9d702172df..88ef913360 100644
--- a/sound/vorbis.h
+++ b/sound/vorbis.h
@@ -36,9 +36,6 @@ namespace Common {
namespace Audio {
class AudioStream;
-class DigitalTrackInfo;
-
-DigitalTrackInfo *getVorbisTrack(int track);
/**
* Create a new AudioStream from the Ogg Vorbis data in the given