ScummVM API documentation
sound_2gs.h
1/* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef AGI_SOUND_2GS_H
23#define AGI_SOUND_2GS_H
24
25#include "common/frac.h"
26#include "audio/audiostream.h"
27
28namespace Agi {
29
30// Sample data in SIERRASTANDARD files is in unsigned 8-bit format. A zero
31// occurring in the sample data causes the ES5503 wavetable sound chip in
32// Apple IIGS to halt the corresponding oscillator immediately. We preprocess
33// the sample data by converting it to signed values and the instruments by
34// detecting prematurely stopping samples beforehand.
35//
36// Note: None of the tested SIERRASTANDARD files have zeroes in them. So in
37// practice there is no need to check for them. However, they still do exist
38// in the sample resources.
39#define ZERO_OFFSET 0x80
40
41// Apple IIGS envelope update frequency defaults to 100Hz. It can be changed,
42// so there might be differences per game, for example.
43#define ENVELOPE_COEF 100 / _sampleRate
44
45// MIDI player commands
46#define MIDI_NOTE_OFF 0x8
47#define MIDI_NOTE_ON 0x9
48#define MIDI_CONTROLLER 0xB
49#define MIDI_PROGRAM_CHANGE 0xC
50#define MIDI_PITCH_WHEEL 0xE
51
52#define MIDI_STOP_SEQUENCE 0xFC
53#define MIDI_TIMER_SYNC 0xF8
54
55// Size of the SIERRASTANDARD file (i.e. the wave file i.e. the sample data used by the instruments).
56#define SIERRASTANDARD_SIZE 65536
57
58// Maximum number of instruments in an Apple IIGS instrument set.
59// Chosen empirically based on Apple IIGS AGI game data, increase if needed.
60#define MAX_INSTRUMENTS 28
61
62// The MIDI player allocates one generator for each note it starts to play.
63// Here the maximum number of generators is defined. Feel free to increase
64// this if it does not seem to be enough.
65#define MAX_GENERATORS 16
66
67#define ENVELOPE_SEGMENT_COUNT 8
68#define MAX_OSCILLATOR_WAVES 127 // Maximum is one for every MIDI key
69
71 struct {
74 } env[ENVELOPE_SEGMENT_COUNT];
75 uint8 seg;
76 uint8 bend;
77 uint8 vibDepth;
78 uint8 vibSpeed;
79 uint8 waveCount[2];
80 struct {
81 uint8 key;
82 uint32 offset;
83 uint32 size;
84 bool halt;
85 bool loop;
86 bool swap;
88 int16 tune;
89 } wave[2][MAX_OSCILLATOR_WAVES];
90
92
99 bool read(Common::SeekableReadStream &stream, bool ignoreAddr = false);
100 bool finalize(int8 *wavetable, uint32 wavetableSize);
101};
102
104 uint16 type;
105 uint8 pitch;
106 uint8 unknownByte_Ofs3; // 0x7F in Gold Rush's sound resource 60, 0 in all others.
107 uint8 volume;
110 uint16 sampleSize;
111 IIgsInstrumentHeader instrument;
112
119 bool finalize(int8 *sampleData);
120};
121
123public:
124 IIgsGenerator() : curInstrument(nullptr), key(-1), channel(-1) {
125 memset(&osc, 0, sizeof(osc));
126 seg = 0;
127 a = 0;
128 velocity = 0;
129 }
130
132 int key;
135 struct {
136 int8 *base;
137 uint size;
140 bool halt;
141 bool loop;
142 bool swap;
144 } osc[2];
145 int seg;
147};
148
149class IIgsMidi : public AgiSound {
150public:
151 IIgsMidi(byte resourceNr, byte *data, uint32 length, uint16 type);
152 virtual const uint8 *getPtr() { return _ptr; }
153 virtual void setPtr(const uint8 *ptr) { _ptr = ptr; }
154 virtual void rewind() { _ptr = _data + 2; _ticks = 0; }
155protected:
156 const uint8 *_ptr;
157public:
158 uint _ticks;
159};
160
161class IIgsSample : public AgiSound {
162public:
163 IIgsSample(byte resourceNr, byte *data, uint32 length, uint16 type);
164 ~IIgsSample() override { delete[] _sample; }
165 uint16 type() override { return _header.type; }
166 const IIgsSampleHeader &getHeader() const { return _header; }
167 bool isValid() override { return _isValid; }
168protected:
170 int8 *_sample;
171 bool _isValid;
172};
173
176 byte midiProgToInst[44];
178
179 // Maps the MIDI program number to an instrument number
180 byte map(uint midiProg) const {
181 return midiProg < ARRAYSIZE(midiProgToInst) ? midiProgToInst[midiProg] : undefinedInst;
182 }
183};
184
189 const char *md5;
190 const char *waveFileMd5;
192};
193
196 enum AgiGameID gameid;
197 const char *exePrefix;
198 uint agiVer;
199 uint exeSize;
202};
203
205public:
206 IIgsMidiChannel() : _instrument(NULL), _volume(127) {}
207 void setInstrument(const IIgsInstrumentHeader *instrument) { _instrument = instrument; }
208 const IIgsInstrumentHeader *getInstrument() { return _instrument; }
209 void setVolume(int volume) { _volume = volume; }
210 int getVolume() { return _volume; }
211private:
212 const IIgsInstrumentHeader *_instrument;
213 int _volume;
214};
215
217public:
218 SoundGen2GS(AgiBase *vm, Audio::Mixer *pMixer);
219 ~SoundGen2GS() override;
220
221 void play(int resnum) override;
222 void stop() override;
223
224 int readBuffer(int16 *buffer, const int numSamples) override;
225
226 bool isStereo() const override { return true; }
227 bool endOfData() const override { return false; }
228 int getRate() const override { return _sampleRate; }
229
230private:
231 // Loader methods
232 bool loadInstruments();
233 bool loadInstrumentHeaders(const Common::Path &exePath, const IIgsExeInfo &exeInfo);
234 bool loadWaveFile(const Common::Path &wavePath, const IIgsExeInfo &exeInfo);
235
236 const IIgsExeInfo *getIIgsExeInfo(enum AgiGameID gameid) const;
237 void setProgramChangeMapping(const IIgsMidiProgramMapping *mapping);
238
239 // Player methods
240 void advancePlayer();
241 void advanceMidiPlayer();
242 uint generateOutput();
243
244 void haltGenerators();
245 uint activeGenerators();
246
247 void midiNoteOff(int channel, int note, int velocity);
248 void midiNoteOn(int channel, int note, int velocity);
249 double midiKeyToFreq(int key, double finetune);
250 IIgsInstrumentHeader *getInstrument(uint8 program) { return &_instruments[_progToInst->map(program)]; }
251 IIgsGenerator *allocateGenerator() { IIgsGenerator *g = &_generators[_nextGen++]; _nextGen %= 16; return g; }
252
253 bool _disableMidi;
254 int _playingSound;
255 bool _playing;
256
257 IIgsGenerator _generators[MAX_GENERATORS];
258 uint _nextGen;
259 IIgsMidiChannel _channels[16];
261 const IIgsMidiProgramMapping *_progToInst;
262 int8 *_wavetable;
263 uint _ticks;
264 int16 *_out;
265 uint _outSize;
266
267 static const int kSfxMidiChannel = 15;
268};
269
270} // End of namespace Agi
271
272#endif /* AGI_SOUND_2GS_H */
Definition: agi.h:573
Definition: sound.h:76
Definition: sound_2gs.h:122
frac_t p
Sample pointer.
Definition: sound_2gs.h:138
int8 * base
Sample base pointer.
Definition: sound_2gs.h:136
bool loop
Is looping enabled?
Definition: sound_2gs.h:141
frac_t a
Current envelope amplitude.
Definition: sound_2gs.h:146
bool swap
Is swapping enabled?
Definition: sound_2gs.h:142
int seg
Current envelope segment.
Definition: sound_2gs.h:145
uint size
Sample size.
Definition: sound_2gs.h:137
bool halt
Is oscillator halted?
Definition: sound_2gs.h:140
int key
MIDI key.
Definition: sound_2gs.h:132
const IIgsInstrumentHeader * curInstrument
Currently used instrument.
Definition: sound_2gs.h:131
bool rightChannel
Output channel (left / right)
Definition: sound_2gs.h:143
int velocity
MIDI velocity (& channel volume)
Definition: sound_2gs.h:133
int channel
MIDI channel.
Definition: sound_2gs.h:134
frac_t pd
Sample pointer delta.
Definition: sound_2gs.h:139
Definition: sound_2gs.h:204
Definition: sound_2gs.h:149
uint _ticks
MIDI song position in ticks (1/60ths of a second)
Definition: sound_2gs.h:158
const uint8 * _ptr
Pointer to the current position in the MIDI data.
Definition: sound_2gs.h:156
Definition: sound_2gs.h:161
int8 * _sample
Sample data (8-bit signed format)
Definition: sound_2gs.h:170
IIgsSampleHeader _header
Apple IIGS AGI sample header.
Definition: sound_2gs.h:169
Definition: sound_2gs.h:216
int readBuffer(int16 *buffer, const int numSamples) override
bool endOfData() const override
Definition: sound_2gs.h:227
bool isStereo() const override
Definition: sound_2gs.h:226
int getRate() const override
Definition: sound_2gs.h:228
Definition: sound.h:57
Definition: audiostream.h:50
Definition: mixer.h:70
Definition: array.h:52
Definition: path.h:52
Definition: stream.h:745
int32 frac_t
Definition: frac.h:52
#define ARRAYSIZE(x)
Definition: util.h:114
Definition: agi.h:64
Definition: sound_2gs.h:195
const char * exePrefix
Prefix of the Apple IIGS AGI executable (e.g. "SQ", "PQ", "KQ4" etc)
Definition: sound_2gs.h:197
uint instSetStart
Starting offset of the instrument set inside the executable file.
Definition: sound_2gs.h:200
uint agiVer
Apple IIGS AGI version number, not strictly needed.
Definition: sound_2gs.h:198
const IIgsInstrumentSetInfo * instSet
Information about the used instrument set.
Definition: sound_2gs.h:201
enum AgiGameID gameid
Game ID.
Definition: sound_2gs.h:196
uint exeSize
Size of the Apple IIGS AGI executable file in bytes.
Definition: sound_2gs.h:199
Definition: sound_2gs.h:70
uint32 size
Wave size.
Definition: sound_2gs.h:83
uint8 seg
Envelope release segment.
Definition: sound_2gs.h:75
uint8 key
Highest MIDI key to use this wave.
Definition: sound_2gs.h:81
frac_t bp
Envelope segment breakpoint.
Definition: sound_2gs.h:72
uint8 vibDepth
Vibrato depth.
Definition: sound_2gs.h:77
int8 * wavetableBase
Base of wave data.
Definition: sound_2gs.h:91
frac_t inc
Envelope segment velocity.
Definition: sound_2gs.h:73
bool swap
Swap mode?
Definition: sound_2gs.h:86
uint8 vibSpeed
Vibrato speed.
Definition: sound_2gs.h:78
bool loop
Loop mode?
Definition: sound_2gs.h:85
uint8 bend
Maximum range for pitch bend.
Definition: sound_2gs.h:76
bool read(Common::SeekableReadStream &stream, bool ignoreAddr=false)
uint32 offset
Offset of wave data, relative to base.
Definition: sound_2gs.h:82
bool halt
Oscillator halted?
Definition: sound_2gs.h:84
int16 tune
Fine tune in semitones (8.8 fixed point)
Definition: sound_2gs.h:88
uint8 waveCount[2]
Wave count for both generators.
Definition: sound_2gs.h:79
bool rightChannel
Output channel (left / right)
Definition: sound_2gs.h:87
Definition: sound_2gs.h:186
uint instCount
Amount of instrument in the set.
Definition: sound_2gs.h:188
const char * md5
MD5 hex digest of the whole instrument set.
Definition: sound_2gs.h:189
const char * waveFileMd5
MD5 hex digest of the wave file (i.e. the sample data used by the instruments)
Definition: sound_2gs.h:190
uint byteCount
Length of the whole instrument set in bytes.
Definition: sound_2gs.h:187
const IIgsMidiProgramMapping * progToInst
Program change to instrument number mapping.
Definition: sound_2gs.h:191
Definition: sound_2gs.h:175
byte midiProgToInst[44]
Lookup table for the MIDI program number to instrument number mapping.
Definition: sound_2gs.h:176
byte undefinedInst
The undefined instrument number.
Definition: sound_2gs.h:177
Definition: sound_2gs.h:103
bool read(Common::SeekableReadStream &stream)
uint8 unknownByte_Ofs5
0 in all tested samples.
Definition: sound_2gs.h:108
uint8 volume
Current guess: Logarithmic in 6 dB steps.
Definition: sound_2gs.h:107
uint16 sampleSize
Accurate in all tested samples excluding Manhunter I's sound resource 16.
Definition: sound_2gs.h:110
uint16 instrumentSize
44 in all tested samples. A guess.
Definition: sound_2gs.h:109
uint8 pitch
Logarithmic, base is 2**(1/12), unknown multiplier (Possibly in range 1040-1080)
Definition: sound_2gs.h:105