Sierra Audio: Difference between revisions
No edit summary |
(Add Sierra audio format doc) |
||
(5 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
* Extension: sol | |||
* Company: [[Sierra Entertainment]] | * Company: [[Sierra Entertainment]] | ||
* Samples: [http://samples.mplayerhq.hu/game-formats/sol/ http://samples.mplayerhq.hu/game-formats/sol/] | |||
=== File Format | This page describes audio format and codecs used in different games by Sierra. Multi-byte numbers are stored in little-endian format. | ||
==Note== | |||
Basic information about the format is below; a more detailed description is further down the page. | |||
== File Format == | |||
Byte Value | Byte Value | ||
---------------- | ---------------- | ||
0 | 0 Version | ||
1 | 1 Header size | ||
2-5 String "SOL" | 2-5 String "SOL" | ||
6-7 Sample rate | 6-7 Sample rate | ||
Line 36: | Line 40: | ||
use 8-bit mono PCM; | use 8-bit mono PCM; | ||
* Island of Dr. Brain | == Credit == | ||
* King's Quest | The information below was originally based on one of the many format documents written up by Valery V. Anisimovsky, available on http://wotsit.org/ and many other sites across the internet. | ||
* King's Quest | |||
* King's Quest | == AUD File Header == | ||
* Leisure Suit Larry 5 | The AUD file has the following header: | ||
* Leisure Suit Larry 6 | |||
* Leisure Suit Larry 7 | struct AUDHeader | ||
* Mixed-Up Mother Goose | { | ||
* Pepper's Adventures in Time | BYTE bID; | ||
* Phantasmagoria | BYTE bShift; | ||
* Space Quest | char szID[4]; | ||
* Space Quest | WORD wSampleRate; | ||
* Space Quest 6 | BYTE bFlags; | ||
* Torin's Passage | DWORD dwDataSize; | ||
}; | |||
''bID'' -- is equal to 0x8D in all Sierra On-Line games I've seen, except for | |||
King's Quest 8, where it equals to 0x0D. | |||
''bShift'' -- defines where audio data starts: (''bShift+2'') is the starting | |||
position of the audio data relative to the file start (NOT to the start of | |||
RESOURCE.SFX/RESOURCE.AUD containing this file). | |||
''szID'' -- always "SOL\0". Note that there're four bytes including terminating | |||
zero! | |||
''wSampleRate'' -- sample rate for the file. | |||
''bFlags'' -- bit-mapped flags: | |||
bit 0 -- if set, audio data is compressed (otherwise it's PCM), | |||
bit 1 -- ??? (I've never seen it set), | |||
bit 2 -- if set, audio data is 16-bit (8-bit otherwise), | |||
bit 3 -- if set, audio data is in signed format (unsigned otherwise): 16-bit | |||
sound is signed and 8-bit is unsigned, | |||
bit 4 -- if set, sound is stereo (mono otherwise). | |||
''dwDataSize'' -- size of the audio data (in bytes). | |||
== AUD File Data == | |||
Starting at (''bShift+2'') from the file start, comes AUD audio data. | |||
If bit 0 of bFlags is not set, it's just PCM: 8-bit or 16-bit, signed or unsigned. | |||
Otherwise it's compressed with the algorithm, which I refer to as SOL ADPCM. | |||
SOL ADPCM has two types: 8-bit (for 8-bit sound) and 16-bit (for 16-bit sound). | |||
== 8-bit SOL ADPCM Decompression Algorithm == | |||
Let's (''CurSample'') be current sample value and (''InputBuffer'') contain SOL ADPCM | |||
compressed data: | |||
SHORT CurSample; | |||
BYTE InputBuffer[InputBufferSize]; | |||
BYTE code; | |||
DWORD i; // index into InputBuffer | |||
CurSample=0x80; // unsigned 8-bit | |||
for (i=0;i<InputBufferSize;i++) | |||
{ | |||
code=HINIBBLE(InputBuffer[i]); // get HIGHER 4-bit nibble | |||
if (code & 8) // sign bit | |||
CurSample-=SOLTable3bit[INDEX4(code)]; | |||
else | |||
CurSample+=SOLTable3bit[code]; | |||
CurSample=Clip8BitSample(CurSample); // clip to 8-bit unsigned value range | |||
Output((BYTE)CurSample); // send to the output stream | |||
code=LONIBBLE(InputBuffer[i]); // get LOWER 4-bit nibble | |||
...the same for lower nibble | |||
} | |||
HINIBBLE and LONIBBLE are higher and lower 4-bit nibbles: | |||
#define HINIBBLE(byte) ((byte) >> 4) | |||
#define LONIBBLE(byte) ((byte) & 0x0F) | |||
Note that depending on your compiler you may need to use additional nibble | |||
separation in these defines, e.g. (((byte) >> 4) & 0x0F). | |||
Output() is just a placeholder for any action you would like to perform for | |||
decompressed sample value. | |||
''SOLTable3bit'' is the delta table given near the end of this document. | |||
''INDEX4(code)'' is really a tricky thing. In some games (mostly older ones) it | |||
should be the following: | |||
#define INDEX4(code) (0xF-(code)) | |||
While in some other games it's the following: | |||
#define INDEX4(code) ((code) & 7) | |||
"Old" INDEX4 is used, for example, in King's Quest 6, Quest For Glory 3, | |||
Gabriel Knight. | |||
"New" INDEX4 is used in Torin's Passage, maybe in other games. | |||
I do not know the reliable way to figure out which of those you should use | |||
for particular file, but currently I use the simplest technique: I just | |||
decode first, say, 1Kb of data using both approaches and look if one of | |||
them results in the output stream which is far from reasonable 8-bit unsigned | |||
sound (that is, its mean sample value is far from 0x80). | |||
Clip8BitSample is quite evident: | |||
SHORT Clip8BitSample(SHORT sample) | |||
{ | |||
if (sample>255) | |||
return 255; | |||
else if (sample<0) | |||
return 0; | |||
else | |||
return sample; | |||
} | |||
Note that the HIGHER nibble is processed first. | |||
== 16-bit SOL ADPCM Decompression Algorithm == | |||
It's just analoguous to the 8-bit decompression scheme: | |||
LONG CurSample; | |||
BYTE InputBuffer[InputBufferSize]; | |||
BYTE code; | |||
DWORD i; | |||
CurSample=0x0000; // signed 16-bit | |||
for (i=0;i<InputBufferSize;i++) | |||
{ | |||
code=InputBuffer[i]; | |||
if (code & 0x80) // sign bit | |||
CurSample-=SOLTable7bit[INDEX8(code)]; | |||
else | |||
CurSample+=SOLTable7bit[code]; | |||
CurSample=Clip16BitSample(CurSample); // clip to 16-bit signed value range | |||
Output((SHORT)CurSample); // send to the output stream | |||
} | |||
''SOLTable7bit'' is the delta table given near the end of this document. | |||
''INDEX8''(code) might be as tricky as for 8-bit sound. But in all games I've | |||
seen where compressed 16-bit sound is used it's just the following: | |||
#define INDEX8(code) ((code) & 0x7F) | |||
At least it's true for Torin's Passage, King's Quest 8, Gabriel Knight, etc. | |||
Clip16BitSample is quite evident, too: | |||
LONG Clip16BitSample(LONG sample) | |||
{ | |||
if (sample>32767) | |||
return 32767; | |||
else if (sample<-32768) | |||
return (-32768); | |||
else | |||
return sample; | |||
} | |||
Note that the decompression schemes are given ONLY for unsigned 8-bit sound | |||
and signed 16-bit sound. I've never seen signed 8-bit or unsigned 16-bit sound | |||
in AUD format, but to support these you should only support the correspondent | |||
clipping (-128..127 for signed 8-bit and 0..65535 for unsigned 16-bit) and | |||
make additional conversion before outputting the sample value: | |||
signed->unsigned for 8-bit sound or unsigned->signed for 16-bit sound, | |||
provided that you've initialized (''CurSample'') to the correspondent value: | |||
0x00 for signed 8-bit and 0x8000 for unsigned 16-bit. | |||
Also, those algorithms are ONLY for mono sound, but their improvement for | |||
stereo is simple: for 8-bit sound left channel is in HIGHER nibble and right | |||
is in LOWER one, while for 16-bit sound left channel is first byte and right | |||
channel is second one. Note that you should maintain two different (''CurSample'') | |||
variables for left and right channels: (''CurSampleLeft'') and (''CurSampleRight''). | |||
Of course, both decompression routines described above may be greatly | |||
optimized. | |||
== SOL ADPCM Tables == | |||
BYTE SOLTable3bit[]= | |||
{ | |||
0, | |||
1, | |||
2, | |||
3, | |||
6, | |||
0xA, | |||
0xF, | |||
0x15 | |||
}; | |||
WORD SOLTable7bit[]= | |||
{ | |||
0x0, 0x8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, | |||
0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, | |||
0xF0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160, | |||
0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, 0x1D0, 0x1E0, | |||
0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230, | |||
0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, | |||
0x278, 0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, | |||
0x2B8, 0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0, | |||
0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330, | |||
0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370, | |||
0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0, | |||
0x3B8, 0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0, | |||
0x3F8, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580, | |||
0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780, | |||
0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00, | |||
0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 | |||
}; | |||
== SOL Low-Pass Filter == | |||
If decompressed as described above, SOL ADPCM compressed 8-bit files from | |||
Torin's Passage seem to have some minor noise. It appears that some Sierra | |||
On-Line games use a kind of strange low-pass filter after the decompression | |||
of SOL APDCM compressed 8-bit files. SOL ADPCM compressed 16-bit files does | |||
not seem to need such enhancement (as well as SOL ADPCM compressed 8-bit | |||
files in some other Sierra games). The SOL LPF scheme looks like to be the | |||
following. For unsigned 8-bit sound: | |||
BYTE Sound[BufferSize]; // decompressed sound buffer | |||
BYTE FilteredSound[BufferSize]; // filtered sound buffer | |||
DWORD i; // index | |||
for (i=0;i<(BufferSize-2);i++) | |||
FilteredSound[i]=(BYTE)((WORD)Sound[i]+(WORD)Sound[i+2])/2; | |||
For 16-bit sound the implementation is just analoguous. | |||
== AUD Resources: RESOURCE.AUD and RESOURCE.SFX == | |||
When stored in .SFX/.AUD resources, the audio files are stored "as is", | |||
without compression (unlike other Sierra On-Line resource files) or encryption. | |||
That means if you want to play/extract AUD file from the RESOURCE.SFX/.AUD | |||
resource you just need to search for szID id-string ("SOL\0") and | |||
read AUDHeader starting at the position two bytes before found id-string. | |||
This will give you starting point of the file and the size of the file will | |||
be (''dwDataSize+bShift+2''). | |||
== Games Using This Format == | |||
* [http://www.mobygames.com/game/dos/dagger-of-amon-ra The Dagger of Amon Ra (a.k.a. Laura Bow 2)] | |||
* [http://www.mobygames.com/game/dos/island-of-dr-brain The Island of Dr. Brain] | |||
* [http://www.mobygames.com/game/dos/kings-quest-v-absence-makes-the-heart-go-yonder King's Quest V: Absence Makes the Heart Go Yonder] | |||
* [http://www.mobygames.com/game/dos/kings-quest-vi-heir-today-gone-tomorrow King's Quest VI: Heir Today, Gone Tomorrow] | |||
* [http://www.mobygames.com/game/dos/roberta-williams-kings-quest-vii-the-princeless-bride King's Quest VII: The Princeless Bride] | |||
* [http://www.mobygames.com/game/dos/leisure-suit-larry-5-passionate-patti-does-a-little-undercover-w Leisure Suit Larry 5: Passionate Patti Does a Little Undercover Work!] | |||
* [http://www.mobygames.com/game/dos/leisure-suit-larry-6-shape-up-or-slip-out Leisure Suit Larry 6: Shape Up or Slip Out!] | |||
* [http://www.mobygames.com/game/dos/leisure-suit-larry-love-for-sail Leisure Suit Larry 7: Love For Sail] | |||
* [http://www.mobygames.com/game/dos/roberta-williams-mixed-up-mother-goose Mixed-Up Mother Goose] | |||
* [http://www.mobygames.com/game/dos/peppers-adventures-in-time Pepper's Adventures in Time] | |||
* [http://www.mobygames.com/game/dos/roberta-williams-phantasmagoria Phantasmagoria] | |||
* [http://www.mobygames.com/game/dos/space-quest-iv-roger-wilco-and-the-time-rippers Space Quest IV: Roger Wilco and the Time Rippers] | |||
* [http://www.mobygames.com/game/dos/space-quest-v-the-next-mutation Space Quest V: The Next Mutation] | |||
* [http://www.mobygames.com/game/dos/space-quest-6-roger-wilco-in-the-spinal-frontier Space Quest 6: Roger Wilco in the Spinal Frontier] | |||
* [http://www.mobygames.com/game/dos/torins-passage Torin's Passage] | |||
[[Category:Game Formats]] | [[Category:Game Formats]] |
Latest revision as of 17:15, 21 August 2006
- Extension: sol
- Company: Sierra Entertainment
- Samples: http://samples.mplayerhq.hu/game-formats/sol/
This page describes audio format and codecs used in different games by Sierra. Multi-byte numbers are stored in little-endian format.
Note
Basic information about the format is below; a more detailed description is further down the page.
File Format
Byte Value ---------------- 0 Version 1 Header size 2-5 String "SOL" 6-7 Sample rate 8 Flags 9-10 Size
Flags are used to determine audio format and compression:
0x01 DPCM 0x04 Stereo 0x10 16-bit
Working scheme to determine what decompressor to use:
if(Version == 0x8D) { if(Flags & USE_DPCM) use old DPCM variant; else use 8-bit unsigned mono PCM; } if(Flags == USE_DPCM | USE_16BIT) use 8->16 bit DPCM; else if(Flags == USE_DPCM) use new DPCM variant; else if(Flags & USE_16BIT) use 16-bit mono or stereo PCM; else use 8-bit mono PCM;
Credit
The information below was originally based on one of the many format documents written up by Valery V. Anisimovsky, available on http://wotsit.org/ and many other sites across the internet.
AUD File Header
The AUD file has the following header:
struct AUDHeader { BYTE bID; BYTE bShift; char szID[4]; WORD wSampleRate; BYTE bFlags; DWORD dwDataSize; };
bID -- is equal to 0x8D in all Sierra On-Line games I've seen, except for King's Quest 8, where it equals to 0x0D.
bShift -- defines where audio data starts: (bShift+2) is the starting position of the audio data relative to the file start (NOT to the start of RESOURCE.SFX/RESOURCE.AUD containing this file).
szID -- always "SOL\0". Note that there're four bytes including terminating zero!
wSampleRate -- sample rate for the file.
bFlags -- bit-mapped flags: bit 0 -- if set, audio data is compressed (otherwise it's PCM), bit 1 -- ??? (I've never seen it set), bit 2 -- if set, audio data is 16-bit (8-bit otherwise), bit 3 -- if set, audio data is in signed format (unsigned otherwise): 16-bit sound is signed and 8-bit is unsigned, bit 4 -- if set, sound is stereo (mono otherwise).
dwDataSize -- size of the audio data (in bytes).
AUD File Data
Starting at (bShift+2) from the file start, comes AUD audio data. If bit 0 of bFlags is not set, it's just PCM: 8-bit or 16-bit, signed or unsigned. Otherwise it's compressed with the algorithm, which I refer to as SOL ADPCM. SOL ADPCM has two types: 8-bit (for 8-bit sound) and 16-bit (for 16-bit sound).
8-bit SOL ADPCM Decompression Algorithm
Let's (CurSample) be current sample value and (InputBuffer) contain SOL ADPCM compressed data:
SHORT CurSample; BYTE InputBuffer[InputBufferSize]; BYTE code; DWORD i; // index into InputBuffer CurSample=0x80; // unsigned 8-bit for (i=0;i<InputBufferSize;i++) { code=HINIBBLE(InputBuffer[i]); // get HIGHER 4-bit nibble if (code & 8) // sign bit CurSample-=SOLTable3bit[INDEX4(code)]; else CurSample+=SOLTable3bit[code]; CurSample=Clip8BitSample(CurSample); // clip to 8-bit unsigned value range Output((BYTE)CurSample); // send to the output stream code=LONIBBLE(InputBuffer[i]); // get LOWER 4-bit nibble ...the same for lower nibble }
HINIBBLE and LONIBBLE are higher and lower 4-bit nibbles:
#define HINIBBLE(byte) ((byte) >> 4) #define LONIBBLE(byte) ((byte) & 0x0F)
Note that depending on your compiler you may need to use additional nibble separation in these defines, e.g. (((byte) >> 4) & 0x0F).
Output() is just a placeholder for any action you would like to perform for decompressed sample value.
SOLTable3bit is the delta table given near the end of this document.
INDEX4(code) is really a tricky thing. In some games (mostly older ones) it should be the following:
#define INDEX4(code) (0xF-(code))
While in some other games it's the following:
#define INDEX4(code) ((code) & 7)
"Old" INDEX4 is used, for example, in King's Quest 6, Quest For Glory 3, Gabriel Knight. "New" INDEX4 is used in Torin's Passage, maybe in other games. I do not know the reliable way to figure out which of those you should use for particular file, but currently I use the simplest technique: I just decode first, say, 1Kb of data using both approaches and look if one of them results in the output stream which is far from reasonable 8-bit unsigned sound (that is, its mean sample value is far from 0x80).
Clip8BitSample is quite evident:
SHORT Clip8BitSample(SHORT sample) { if (sample>255) return 255; else if (sample<0) return 0; else return sample; }
Note that the HIGHER nibble is processed first.
16-bit SOL ADPCM Decompression Algorithm
It's just analoguous to the 8-bit decompression scheme:
LONG CurSample; BYTE InputBuffer[InputBufferSize]; BYTE code; DWORD i; CurSample=0x0000; // signed 16-bit for (i=0;i<InputBufferSize;i++) { code=InputBuffer[i]; if (code & 0x80) // sign bit CurSample-=SOLTable7bit[INDEX8(code)]; else CurSample+=SOLTable7bit[code]; CurSample=Clip16BitSample(CurSample); // clip to 16-bit signed value range Output((SHORT)CurSample); // send to the output stream }
SOLTable7bit is the delta table given near the end of this document.
INDEX8(code) might be as tricky as for 8-bit sound. But in all games I've seen where compressed 16-bit sound is used it's just the following:
#define INDEX8(code) ((code) & 0x7F)
At least it's true for Torin's Passage, King's Quest 8, Gabriel Knight, etc.
Clip16BitSample is quite evident, too:
LONG Clip16BitSample(LONG sample) { if (sample>32767) return 32767; else if (sample<-32768) return (-32768); else return sample; }
Note that the decompression schemes are given ONLY for unsigned 8-bit sound and signed 16-bit sound. I've never seen signed 8-bit or unsigned 16-bit sound in AUD format, but to support these you should only support the correspondent clipping (-128..127 for signed 8-bit and 0..65535 for unsigned 16-bit) and make additional conversion before outputting the sample value: signed->unsigned for 8-bit sound or unsigned->signed for 16-bit sound, provided that you've initialized (CurSample) to the correspondent value: 0x00 for signed 8-bit and 0x8000 for unsigned 16-bit.
Also, those algorithms are ONLY for mono sound, but their improvement for stereo is simple: for 8-bit sound left channel is in HIGHER nibble and right is in LOWER one, while for 16-bit sound left channel is first byte and right channel is second one. Note that you should maintain two different (CurSample) variables for left and right channels: (CurSampleLeft) and (CurSampleRight).
Of course, both decompression routines described above may be greatly optimized.
SOL ADPCM Tables
BYTE SOLTable3bit[]= { 0, 1, 2, 3, 6, 0xA, 0xF, 0x15 }; WORD SOLTable7bit[]= { 0x0, 0x8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, 0x1D0, 0x1E0, 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230, 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, 0x278, 0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8, 0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0, 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330, 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370, 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0, 0x3B8, 0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0, 0x3F8, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580, 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780, 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00, 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 };
SOL Low-Pass Filter
If decompressed as described above, SOL ADPCM compressed 8-bit files from Torin's Passage seem to have some minor noise. It appears that some Sierra On-Line games use a kind of strange low-pass filter after the decompression of SOL APDCM compressed 8-bit files. SOL ADPCM compressed 16-bit files does not seem to need such enhancement (as well as SOL ADPCM compressed 8-bit files in some other Sierra games). The SOL LPF scheme looks like to be the following. For unsigned 8-bit sound:
BYTE Sound[BufferSize]; // decompressed sound buffer BYTE FilteredSound[BufferSize]; // filtered sound buffer DWORD i; // index for (i=0;i<(BufferSize-2);i++) FilteredSound[i]=(BYTE)((WORD)Sound[i]+(WORD)Sound[i+2])/2;
For 16-bit sound the implementation is just analoguous.
AUD Resources: RESOURCE.AUD and RESOURCE.SFX
When stored in .SFX/.AUD resources, the audio files are stored "as is", without compression (unlike other Sierra On-Line resource files) or encryption. That means if you want to play/extract AUD file from the RESOURCE.SFX/.AUD resource you just need to search for szID id-string ("SOL\0") and read AUDHeader starting at the position two bytes before found id-string. This will give you starting point of the file and the size of the file will be (dwDataSize+bShift+2).
Games Using This Format
- The Dagger of Amon Ra (a.k.a. Laura Bow 2)
- The Island of Dr. Brain
- King's Quest V: Absence Makes the Heart Go Yonder
- King's Quest VI: Heir Today, Gone Tomorrow
- King's Quest VII: The Princeless Bride
- Leisure Suit Larry 5: Passionate Patti Does a Little Undercover Work!
- Leisure Suit Larry 6: Shape Up or Slip Out!
- Leisure Suit Larry 7: Love For Sail
- Mixed-Up Mother Goose
- Pepper's Adventures in Time
- Phantasmagoria
- Space Quest IV: Roger Wilco and the Time Rippers
- Space Quest V: The Next Mutation
- Space Quest 6: Roger Wilco in the Spinal Frontier
- Torin's Passage