aboutsummaryrefslogtreecommitdiff
path: root/engines/agi/sound.h
diff options
context:
space:
mode:
authorKari Salminen2007-08-14 12:44:44 +0000
committerKari Salminen2007-08-14 12:44:44 +0000
commitaf85709cfd31a9688c3542caf6e0e62ffed3da57 (patch)
tree684112ffe72d6e8066b26dc2c658321ba378c3a6 /engines/agi/sound.h
parent27ea9d581be498aa79f286daeda02305a6e2a4bb (diff)
downloadscummvm-rg350-af85709cfd31a9688c3542caf6e0e62ffed3da57.tar.gz
scummvm-rg350-af85709cfd31a9688c3542caf6e0e62ffed3da57.tar.bz2
scummvm-rg350-af85709cfd31a9688c3542caf6e0e62ffed3da57.zip
Defined some functions in Agi::SoundMgr and moved stuff generally around between AGI's sound.h and sound.cpp. Assimilated calcTrueSampleSize into another function.
svn-id: r28613
Diffstat (limited to 'engines/agi/sound.h')
-rw-r--r--engines/agi/sound.h218
1 files changed, 218 insertions, 0 deletions
diff --git a/engines/agi/sound.h b/engines/agi/sound.h
index adde156f75..03b243cd58 100644
--- a/engines/agi/sound.h
+++ b/engines/agi/sound.h
@@ -70,6 +70,200 @@ private:
bool _isPlaying; ///< Is the sound playing?
};
+struct IIgsEnvelopeSegment {
+ uint8 bp;
+ uint16 inc; ///< 8b.8b fixed point, big endian?
+};
+
+#define ENVELOPE_SEGMENT_COUNT 8
+struct IIgsEnvelope {
+ IIgsEnvelopeSegment seg[ENVELOPE_SEGMENT_COUNT];
+
+ /** Reads an Apple IIGS envelope from then given stream. */
+ bool read(Common::SeekableReadStream &stream) {
+ for (int segNum = 0; segNum < ENVELOPE_SEGMENT_COUNT; segNum++) {
+ seg[segNum].bp = stream.readByte();
+ seg[segNum].inc = stream.readUint16BE();
+ }
+ return !stream.ioFailed();
+ }
+};
+
+// 2**(1/12) i.e. the 12th root of 2
+#define SEMITONE 1.059463094359295
+
+// Size of the SIERRASTANDARD file (i.e. the wave file i.e. the sample data used by the instruments).
+#define SIERRASTANDARD_SIZE 65536
+
+// Maximum number of instruments in an Apple IIGS instrument set.
+// Chosen empirically based on Apple IIGS AGI game data, increase if needed.
+#define MAX_INSTRUMENTS 28
+
+struct IIgsWaveInfo {
+ uint8 top;
+ uint addr;
+ uint size;
+// Oscillator channel
+#define OSC_CHANNEL_RIGHT 0
+#define OSC_CHANNEL_LEFT 1
+ uint channel;
+// Oscillator mode
+#define OSC_MODE_LOOP 0
+#define OSC_MODE_ONESHOT 1
+#define OSC_MODE_SYNC_AM 2
+#define OSC_MODE_SWAP 3
+ uint mode;
+ bool halt;
+ uint16 relPitch; ///< 8b.8b fixed point, big endian?
+
+ /** Reads an Apple IIGS wave information structure from the given stream. */
+ bool read(Common::SeekableReadStream &stream, bool ignoreAddr = false) {
+ top = stream.readByte();
+ addr = stream.readByte() * 256;
+ size = (1 << (stream.readByte() & 7)) * 256;
+
+ // Read packed mode byte and parse it into parts
+ byte packedModeByte = stream.readByte();
+ channel = (packedModeByte >> 4) & 1; // Bit 4
+ mode = (packedModeByte >> 1) & 3; // Bits 1-2
+ halt = (packedModeByte & 1) != 0; // Bit 0 (Converted to boolean)
+
+ relPitch = stream.readUint16BE();
+
+ // Zero the wave address if we want to ignore the wave address info
+ if (ignoreAddr)
+ addr = 0;
+
+ return !stream.ioFailed();
+ }
+
+ bool finalize(Common::SeekableReadStream &uint8Wave) {
+ uint32 startPos = uint8Wave.pos(); // Save stream's starting position
+ uint8Wave.seek(addr, SEEK_CUR); // Seek to wave's address
+
+ // Calculate the true sample size (A zero ends the sample prematurely)
+ uint trueSize = size; // Set a default value for the result
+ for (uint i = 0; i < size; i++) {
+ if (uint8Wave.readByte() == 0) {
+ trueSize = i;
+ break;
+ }
+ }
+ size = trueSize; // Set the true sample size
+
+ uint8Wave.seek(startPos); // Seek back to the stream's starting position
+ return true;
+ }
+};
+
+// Number of waves per Apple IIGS sound oscillator
+#define WAVES_PER_OSCILLATOR 2
+
+/** An Apple IIGS sound oscillator. Consists always of two waves. */
+struct IIgsOscillator {
+ IIgsWaveInfo waves[WAVES_PER_OSCILLATOR];
+
+ bool finalize(Common::SeekableReadStream &uint8Wave) {
+ for (uint i = 0; i < WAVES_PER_OSCILLATOR; i++)
+ if (!waves[i].finalize(uint8Wave))
+ return false;
+ return true;
+ }
+};
+
+// Maximum number of oscillators in an Apple IIGS instrument.
+// Chosen empirically based on Apple IIGS AGI game data, increase if needed.
+#define MAX_OSCILLATORS 4
+
+/** An Apple IIGS sound oscillator list. */
+struct IIgsOscillatorList {
+ uint count; ///< Oscillator count
+ IIgsOscillator osc[MAX_OSCILLATORS]; ///< The oscillators
+
+ bool read(Common::SeekableReadStream &stream, uint oscillatorCount, bool ignoreAddr = false) {
+ // First read the A waves and then the B waves for the oscillators
+ for (uint waveNum = 0; waveNum < WAVES_PER_OSCILLATOR; waveNum++)
+ for (uint oscNum = 0; oscNum < oscillatorCount; oscNum++)
+ if (!osc[oscNum].waves[waveNum].read(stream, ignoreAddr))
+ return false;
+
+ count = oscillatorCount; // Set the oscillator count
+ return true;
+ }
+
+ bool finalize(Common::SeekableReadStream &uint8Wave) {
+ for (uint i = 0; i < count; i++)
+ if (!osc[i].finalize(uint8Wave))
+ return false;
+ return true;
+ }
+};
+
+struct IIgsInstrumentHeader {
+ IIgsEnvelope env;
+ uint8 relseg;
+ uint8 bendrange;
+ uint8 vibdepth;
+ uint8 vibspeed;
+ IIgsOscillatorList oscList;
+
+ /**
+ * Read an Apple IIGS instrument header from the given stream.
+ * @param stream The source stream from which to read the data.
+ * @param ignoreAddr Should we ignore wave infos' wave address variable's value?
+ * @return True if successful, false otherwise.
+ */
+ bool read(Common::SeekableReadStream &stream, bool ignoreAddr = false) {
+ env.read(stream);
+ relseg = stream.readByte();
+ byte priority = stream.readByte(); // Not needed? 32 in all tested data.
+ bendrange = stream.readByte();
+ vibdepth = stream.readByte();
+ vibspeed = stream.readByte();
+ byte spare = stream.readByte(); // Not needed? 0 in all tested data.
+ byte wac = stream.readByte(); // Read A wave count
+ byte wbc = stream.readByte(); // Read B wave count
+ oscList.read(stream, wac, ignoreAddr); // Read the oscillators
+ return (wac == wbc) && !stream.ioFailed(); // A and B wave counts must match
+ }
+
+ bool finalize(Common::SeekableReadStream &uint8Wave) {
+ return oscList.finalize(uint8Wave);
+ }
+};
+
+struct IIgsSampleHeader {
+ uint16 type;
+ uint8 pitch; ///< Logarithmic, base is 2**(1/12), unknown multiplier (Possibly in range 1040-1080)
+ uint8 unknownByte_Ofs3; // 0x7F in Gold Rush's sound resource 60, 0 in all others.
+ uint8 volume; ///< Current guess: Logarithmic in 6 dB steps
+ uint8 unknownByte_Ofs5; ///< 0 in all tested samples.
+ uint16 instrumentSize; ///< Little endian. 44 in all tested samples. A guess.
+ uint16 sampleSize; ///< Little endian. Accurate in all tested samples excluding Manhunter I's sound resource 16.
+ IIgsInstrumentHeader instrument;
+
+ /**
+ * Read an Apple IIGS AGI sample header from the given stream.
+ * @param stream The source stream from which to read the data.
+ * @return True if successful, false otherwise.
+ */
+ bool read(Common::SeekableReadStream &stream) {
+ type = stream.readUint16LE();
+ pitch = stream.readByte();
+ unknownByte_Ofs3 = stream.readByte();
+ volume = stream.readByte();
+ unknownByte_Ofs5 = stream.readByte();
+ instrumentSize = stream.readUint16LE();
+ sampleSize = stream.readUint16LE();
+ // Read the instrument header *ignoring* its wave address info
+ return instrument.read(stream, true);
+ }
+
+ bool finalize(Common::SeekableReadStream &uint8Wave) {
+ return instrument.finalize(uint8Wave);
+ }
+};
+
#include "common/pack-start.h"
/**
@@ -112,6 +306,24 @@ struct ChannelInfo {
uint32 env;
};
+/** Apple IIGS AGI instrument set information. */
+struct instrumentSetInfo {
+ uint byteCount; ///< Length of the whole instrument set in bytes
+ uint instCount; ///< Amount of instrument in the set
+ const char *md5; ///< MD5 hex digest of the whole instrument set
+ const char *waveFileMd5; ///< MD5 hex digest of the wave file (i.e. the sample data used by the instruments)
+};
+
+/** Apple IIGS AGI executable file information. */
+struct IIgsExeInfo {
+ enum AgiGameID gameid; ///< Game ID
+ const char *exePrefix; ///< Prefix of the Apple IIGS AGI executable (e.g. "SQ", "PQ", "KQ4" etc)
+ uint agiVer; ///< Apple IIGS AGI version number, not strictly needed
+ uint exeSize; ///< Size of the Apple IIGS AGI executable file in bytes
+ uint instSetStart; ///< Starting offset of the instrument set inside the executable file
+ const instrumentSetInfo &instSet; ///< Information about the used instrument set
+};
+
class AgiEngine;
class SoundMgr : public Audio::AudioStream {
@@ -165,6 +377,12 @@ public:
#ifdef USE_IIGS_SOUND
void playMidiSound();
void playSampleSound();
+ bool finalizeInstruments(Common::SeekableReadStream &uint8Wave);
+ Audio::AudioStream *makeIIgsSampleStream(Common::SeekableReadStream &stream, int resnum = -1);
+ const IIgsExeInfo *getIIgsExeInfo(enum AgiGameID gameid) const;
+ bool loadInstrumentHeaders(const Common::String &exePath, const IIgsExeInfo &exeInfo);
+ bool convertWave(Common::SeekableReadStream &source, int16 *dest, uint length);
+ Common::MemoryReadStream *loadWaveFile(const Common::String &wavePath, const IIgsExeInfo &exeInfo);
#endif
};