https://wiki.multimedia.cx/index.php?title=Origin_MGI&feed=atom&action=historyOrigin MGI - Revision history2024-03-29T05:36:21ZRevision history for this page on the wikiMediaWiki 1.39.5https://wiki.multimedia.cx/index.php?title=Origin_MGI&diff=7640&oldid=prevMultimedia Mike: Reverted edits by SpdC4c (Talk); changed back to last version by Dashcloud2007-04-10T22:53:10Z<p>Reverted edits by <a href="/index.php/Special:Contributions/SpdC4c" title="Special:Contributions/SpdC4c">SpdC4c</a> (<a href="/index.php?title=User_talk:SpdC4c&action=edit&redlink=1" class="new" title="User talk:SpdC4c (page does not exist)">Talk</a>); changed back to last version by <a href="/index.php/User:Dashcloud" title="User:Dashcloud">Dashcloud</a></p>
<a href="https://wiki.multimedia.cx/index.php?title=Origin_MGI&diff=7640&oldid=7620">Show changes</a>Multimedia Mikehttps://wiki.multimedia.cx/index.php?title=Origin_MGI&diff=7620&oldid=prevSpdC4c at 22:19, 10 April 20072007-04-10T22:19:23Z<p></p>
<a href="https://wiki.multimedia.cx/index.php?title=Origin_MGI&diff=7620&oldid=6944">Show changes</a>SpdC4chttps://wiki.multimedia.cx/index.php?title=Origin_MGI&diff=6944&oldid=prevDashcloud: Update website address2007-02-05T05:08:39Z<p>Update website address</p>
<table style="background-color: #fff; color: #202122;" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en">
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">← Older revision</td>
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">Revision as of 22:08, 4 February 2007</td>
</tr><tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l3">Line 3:</td>
<td colspan="2" class="diff-lineno">Line 3:</td></tr>
<tr><td class="diff-marker"></td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><br/></td><td class="diff-marker"></td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><br/></td></tr>
<tr><td class="diff-marker"></td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>==Credit==</div></td><td class="diff-marker"></td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>==Credit==</div></td></tr>
<tr><td class="diff-marker" data-marker="−"></td><td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div>This document comes from wotsit.org, and originated on GAP's (Game Audio Player) website (now defunct).</div></td><td class="diff-marker" data-marker="+"></td><td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div>This document comes from <ins style="font-weight: bold; text-decoration: none;">[http://www.wotsit.org </ins>wotsit.org<ins style="font-weight: bold; text-decoration: none;">]</ins>, and originated on GAP's (Game Audio Player) website (now defunct).</div></td></tr>
<tr><td class="diff-marker"></td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>By Valery V. Anisimovsky (no valid email address known)</div></td><td class="diff-marker"></td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>By Valery V. Anisimovsky (no valid email address known)</div></td></tr>
<tr><td class="diff-marker"></td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>Dmitry Kirnocenskij (ejt@mail.ru) is credited with working out EA ADPCM decompression algorithm.</div></td><td class="diff-marker"></td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>Dmitry Kirnocenskij (ejt@mail.ru) is credited with working out EA ADPCM decompression algorithm.</div></td></tr>
</table>Dashcloudhttps://wiki.multimedia.cx/index.php?title=Origin_MGI&diff=5681&oldid=prevDashcloud: Correct formatting on page2006-08-14T20:19:06Z<p>Correct formatting on page</p>
<a href="https://wiki.multimedia.cx/index.php?title=Origin_MGI&diff=5681&oldid=5679">Show changes</a>Dashcloudhttps://wiki.multimedia.cx/index.php?title=Origin_MGI&diff=5679&oldid=prevDashcloud: Adding Origin MGI format2006-08-14T20:00:14Z<p>Adding Origin MGI format</p>
<p><b>New page</b></p><div>* Extension: mgi, tre<br />
* Company: [[Origin Systems]]<br />
<br />
==Credit==<br />
This document comes from wotsit.org, and originated on GAP's (Game Audio Player) website (now defunct).<br />
By Valery V. Anisimovsky (no valid email address known)<br />
Dmitry Kirnocenskij (ejt@mail.ru) is credited with working out EA ADPCM decompression algorithm.<br />
<br />
==MGI File Header==<br />
<br />
The MGI file has the following header:<br />
<br />
struct MGIHeader<br />
{<br />
char szID[4];<br />
DWORD dwUnknown1;<br />
DWORD dwNumSecIndices;<br />
DWORD dwUnknown2;<br />
DWORD dwNumIntIndices;<br />
};<br />
<br />
szID -- string ID, which is equal to "\x8F\xC2\x35\x3F".<br />
<br />
dwUnknown1, dwUnknown2 -- seem to be always 0.<br />
<br />
dwNumSecIndices -- the number of section indices used in section descriptors<br />
(see below).<br />
<br />
dwNumIntIndices -- seems to be the number of indices used in interactive<br />
playback descriptors (see below).<br />
<br />
After the header comes the table of interactive playback descriptors. Each<br />
descriptor has the following format:<br />
<br />
struct MGIIntDesc<br />
{<br />
LONG lIndex;<br />
DWORD dwSection;<br />
};<br />
<br />
lIndex -- seems to be the index of interactive sequence. Note that some<br />
indices are negative values.<br />
<br />
dwSection -- the pointer to the section (that is, the index of the section<br />
descriptor correspondent to the section, NOT the index of section given in<br />
the descriptor itself!)<br />
<br />
The number of descriptors in this table (its size) is very uncertain. I use<br />
a kind of heuristic approach to get past this table, outlined below.<br />
<br />
After the table of interactive playback descriptors comes the (DWORD) number<br />
of sections in the file (let it be denoted as dwNumSections). After this<br />
number comes the table of (dwNumSections) section descriptors. Each descriptor<br />
has the following format:<br />
<br />
struct MGISecDesc<br />
{<br />
DWORD dwStart;<br />
DWORD dwIndex;<br />
DWORD dwOutSize;<br />
};<br />
<br />
dwStart -- the starting position of the audio data for the section.<br />
<br />
dwIndex -- the index of the section (NOT the index of the correspondent<br />
descriptor). Several different sections may have the same index. The meaning<br />
of this index seems to be quite uncertain, though it is not required for<br />
non-interactive playback of MGI files.<br />
<br />
dwOutSize -- the output size of the audio stream stored in the section<br />
(in bytes). May be used for section length (in seconds) calculation.<br />
Includes the outsizes for both compressed and non-compressed parts of the<br />
section, that is, it's the whole outsize of the section.<br />
<br />
Now, here's the approach I use to get to the start of section descriptors<br />
table. First, we should read MGIHeader. Then, we may read the interactive<br />
playback table -- descriptor by descriptor and for each descriptor we should<br />
check whether its (dwIndex) is less than header values (dwNumSecIndices)<br />
and (dwNumIntIndices). If the suspicious descriptor is found (for which<br />
the index value is out of range -- note that the descriptors with negative<br />
indices are correct!) we may check whether this descriptors is really the<br />
beginning of the section descriptors table. This check is simple to perform:<br />
assume that audio data for the first section starts right after the section<br />
descriptors table, then we can get the following equation:<br />
(dwDescPos)+4+(lIndex)*sizeof(MGISecDesc)=(dwSection),<br />
where (dwDescPos) is the position in MGI file at which starts the suspicious<br />
descriptor, (lIndex) and (dwSection) are the values from that descriptor.<br />
When this equation holds we most likely found the beginning of the section<br />
descriptors table.<br />
<br />
After the section descriptors table comes the audio data for the sections.<br />
<br />
== MGI Section Audio Data ==<br />
<br />
For each section we can get the starting position of the audio data from<br />
the section's descriptor. Note that the last section seems to be always<br />
empty (it starts at the end of the MGI file, has zero outsize and zero index).<br />
Each section consists of two parts: EA ADPCM compressed and non-compressed.<br />
First comes the compressed part and right after that comes non-compressed<br />
part. To get the size of non-compressed tail you can use the following formula:<br />
dwTailSize=(dwSectionSize*0x70-dwOutSize*0x1E)/0x52,<br />
where (dwSectionSize) is the size of the whole section (which may be calculated<br />
as the difference between the start positions of the next and the current<br />
sections), (dwOutSize) is the value from the section's descriptor. This<br />
formula can be easily derived knowing the fact the compressed data is composed<br />
of blocks (0x1E bytes each -- for stereo stream) which are decompressed into<br />
0x1C*4 bytes each (for stereo stream). Note that this formula is valid for<br />
both stereo and mono MGI files.<br />
<br />
The compressed part contains EA ADPCM compressed stream. It's devided into<br />
small blocks of 0x1E (stereo) or 0xF (mono) bytes. The non-compressed part<br />
contains raw (16-bit signed) PCM data. All MGI files I've seen are stereo<br />
22050 Hz 16-bit. The non-compressed part may be played right after the<br />
compressed part.<br />
<br />
All sections may be played consequently right in their turn. Some MGI files<br />
contain several quite independent tunes, though when played consequently,<br />
those tunes form relatively seamless composition.<br />
<br />
== EA ADPCM Decompression Algorithm ==<br />
<br />
During the decompression four LONG variables must be maintained for stereo<br />
stream: lCurSampleLeft, lCurSampleRight, lPrevSampleLeft, lPrevSampleRight<br />
and two -- for mono stream: lCurSample, lPrevSample. At the beginning of each<br />
section you must initialize these variables to zeros.<br />
Note that LONG here is signed.<br />
<br />
The stream is divided into small blocks of 0x1E (stereo) or 0xF (mono) bytes.<br />
You should process all blocks in their turn. Here's the code which<br />
decompresses one stereo stream block.<br />
<br />
<br />
BYTE InputBuffer[InputBufferSize]; // buffer containing data for one block<br />
BYTE bInput;<br />
DWORD i;<br />
LONG c1left,c2left,c1right,c2right,left,right;<br />
BYTE dleft,dright;<br />
<br />
bInput=InputBuffer[0];<br />
c1left=EATable[HINIBBLE(bInput)]; // predictor coeffs for left channel<br />
c2left=EATable[HINIBBLE(bInput)+4];<br />
c1right=EATable[LONIBBLE(bInput)]; // predictor coeffs for right channel<br />
c2right=EATable[LONIBBLE(bInput)+4];<br />
<br />
bInput=InputBuffer[1];<br />
dleft=HINIBBLE(bInput)+8; // shift value for left channel<br />
dright=LONIBBLE(bInput)+8; // shift value for right channel<br />
<br />
for (i=2;i<0x1E;i++)<br />
{<br />
left=HINIBBLE(InputBuffer[i]); // HIGHER nibble for left channel<br />
left=(left<<0x1c)>>dleft;<br />
left=(left+lCurSampleLeft*c1left+lPrevSampleLeft*c2left+0x80)>>8;<br />
left=Clip16BitSample(left);<br />
lPrevSampleLeft=lCurSampleLeft;<br />
lCurSampleLeft=left;<br />
<br />
right=LONIBBLE(InputBuffer[i]); // LOWER nibble for right channel<br />
right=(right<<0x1c)>>dright;<br />
right=(right+lCurSampleRight*c1right+lPrevSampleRight*c2right+0x80)>>8;<br />
right=Clip16BitSample(right);<br />
lPrevSampleRight=lCurSampleRight;<br />
lCurSampleRight=right;<br />
<br />
// Now we've got lCurSampleLeft and lCurSampleRight which form one stereo<br />
// sample and all is set for the next step...<br />
Output((SHORT)lCurSampleLeft,(SHORT)lCurSampleRight); // send the sample to output<br />
}<br />
<br />
HINIBBLE and LONIBBLE are higher and lower 4-bit nibbles:<br />
#define HINIBBLE(byte) ((byte) >> 4)<br />
#define LONIBBLE(byte) ((byte) & 0x0F)<br />
Note that depending on your compiler you may need to use additional nibble<br />
separation in these defines, e.g. (((byte) >> 4) & 0x0F).<br />
<br />
EATable is the table given in the next section of this document.<br />
<br />
Output() is just a placeholder for any action you would like to perform for<br />
decompressed sample value.<br />
<br />
Clip16BitSample is quite evident:<br />
<br />
LONG Clip16BitSample(LONG sample)<br />
{<br />
if (sample>32767)<br />
return 32767;<br />
else if (sample<-32768)<br />
return (-32768);<br />
else<br />
return sample;<br />
}<br />
<br />
As to mono sound, it's just analoguous -- you should process the blocks each<br />
being 0xF bytes long:<br />
<br />
<br />
bInput=InputBuffer[0];<br />
c1=EATable[HINIBBLE(bInput)]; // predictor coeffs<br />
c2=EATable[HINIBBLE(bInput)+4];<br />
d=LONIBBLE(bInput)+8; // shift value<br />
<br />
for (i=1;i<0xF;i++)<br />
{<br />
left=HINIBBLE(InputBuffer[i]); // HIGHER nibble for left channel<br />
left=(left<<0x1c)>>dleft;<br />
left=(left+lCurSampleLeft*c1left+lPrevSampleLeft*c2left+0x80)>>8;<br />
left=Clip16BitSample(left);<br />
lPrevSampleLeft=lCurSampleLeft;<br />
lCurSampleLeft=left;<br />
<br />
// Now we've got lCurSampleLeft which is one mono sample and all is set<br />
// for the next input nibble...<br />
Output((SHORT)lCurSampleLeft); // send the sample to output<br />
<br />
left=LONIBBLE(InputBuffer[i]); // LOWER nibble for left channel<br />
left=(left<<0x1c)>>dleft;<br />
left=(left+lCurSampleLeft*c1left+lPrevSampleLeft*c2left+0x80)>>8;<br />
left=Clip16BitSample(left);<br />
lPrevSampleLeft=lCurSampleLeft;<br />
lCurSampleLeft=left;<br />
<br />
// Now we've got lCurSampleLeft which is one mono sample and all is set<br />
// for the next input byte...<br />
Output((SHORT)lCurSampleLeft); // send the sample to output<br />
}<br />
<br />
Note that HIGHER nibble is processed first for mono sound and corresponds to<br />
LEFT channel for stereo.<br />
<br />
Of course, this decompression routine may be greatly optimized.<br />
<br />
== EA ADPCM Table ==<br />
<br />
LONG EATable[]=<br />
{<br />
0x00000000,<br />
0x000000F0,<br />
0x000001CC,<br />
0x00000188,<br />
0x00000000,<br />
0x00000000,<br />
0xFFFFFF30,<br />
0xFFFFFF24,<br />
0x00000000,<br />
0x00000001,<br />
0x00000003,<br />
0x00000004,<br />
0x00000007,<br />
0x00000008,<br />
0x0000000A,<br />
0x0000000B,<br />
0x00000000,<br />
0xFFFFFFFF,<br />
0xFFFFFFFD,<br />
0xFFFFFFFC<br />
};<br />
<br />
== MGI Audio Files in TRE Archives ==<br />
<br />
When stored in .TRE resources, MGI audio files are stored "as is", without<br />
compression or encryption. That means if you want to play/extract MGI<br />
file from the TRE resource you just need to search for (szID) id-string<br />
("\x8F\xC2\x35\x3F"), read MGI header starting at the beginning position of<br />
found id-string and then use the approach outlined above to find the<br />
section descriptors table. The found id-string will give you starting point<br />
of MGI file and the size of the file will be the (dwStart) value in the<br />
descriptor of the last section.<br />
<br />
==PC Games Using Origin MGI==<br />
*[http://www.mobygames.com/game/windows/wing-commander-prophecy Wing Commander Prophecy]<br />
[[Category:Game Formats]]</div>Dashcloud