Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

load_s3m.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is  free software; you can redistribute it  and modify it
00003  * under the terms of the GNU  General Public License as published by the
00004  * Free Software Foundation; either version 2  of the license or (at your
00005  * option) any later version.
00006  *
00007  * Authors: Olivier Lapicque <olivierl@jps.net>,
00008  *          Adam Goode       <adam@evdebs.org> (endian and char fixes for PPC)
00009 */
00010 
00011 #include "stdafx.h"
00012 #include "sndfile.h"
00013 
00014 //#pragma warning(disable:4244)
00015 
00016 extern WORD S3MFineTuneTable[16];
00017 
00019 // ScreamTracker S3M file support
00020 
00021 typedef struct tagS3MSAMPLESTRUCT
00022 {
00023         BYTE type;
00024         CHAR dosname[12];
00025         BYTE hmem;
00026         WORD memseg;
00027         DWORD length;
00028         DWORD loopbegin;
00029         DWORD loopend;
00030         BYTE vol;
00031         BYTE bReserved;
00032         BYTE pack;
00033         BYTE flags;
00034         DWORD finetune;
00035         DWORD dwReserved;
00036         WORD intgp;
00037         WORD int512;
00038         DWORD lastused;
00039         CHAR name[28];
00040         CHAR scrs[4];
00041 } Q_PACKED S3MSAMPLESTRUCT;
00042 
00043 
00044 typedef struct tagS3MFILEHEADER
00045 {
00046         CHAR name[28];
00047         BYTE b1A;
00048         BYTE type;
00049         WORD reserved1;
00050         WORD ordnum;
00051         WORD insnum;
00052         WORD patnum;
00053         WORD flags;
00054         WORD cwtv;
00055         WORD version;
00056         DWORD scrm;     // "SCRM" = 0x4D524353
00057         BYTE globalvol;
00058         BYTE speed;
00059         BYTE tempo;
00060         BYTE mastervol;
00061         BYTE ultraclicks;
00062         BYTE panning_present;
00063         BYTE reserved2[8];
00064         WORD special;
00065         BYTE channels[32];
00066 } Q_PACKED S3MFILEHEADER;
00067 
00068 
00069 void CSoundFile::S3MConvert(MODCOMMAND *m, BOOL bIT) const
00070 //--------------------------------------------------------
00071 {
00072         UINT command = m->command;
00073         UINT param = m->param;
00074         switch (command + 0x40)
00075         {
00076         case 'A':       command = CMD_SPEED; break;
00077         case 'B':       command = CMD_POSITIONJUMP; break;
00078         case 'C':       command = CMD_PATTERNBREAK; if (!bIT) param = (param >> 4) * 10 + (param & 0x0F); break;
00079         case 'D':       command = CMD_VOLUMESLIDE; break;
00080         case 'E':       command = CMD_PORTAMENTODOWN; break;
00081         case 'F':       command = CMD_PORTAMENTOUP; break;
00082         case 'G':       command = CMD_TONEPORTAMENTO; break;
00083         case 'H':       command = CMD_VIBRATO; break;
00084         case 'I':       command = CMD_TREMOR; break;
00085         case 'J':       command = CMD_ARPEGGIO; break;
00086         case 'K':       command = CMD_VIBRATOVOL; break;
00087         case 'L':       command = CMD_TONEPORTAVOL; break;
00088         case 'M':       command = CMD_CHANNELVOLUME; break;
00089         case 'N':       command = CMD_CHANNELVOLSLIDE; break;
00090         case 'O':       command = CMD_OFFSET; break;
00091         case 'P':       command = CMD_PANNINGSLIDE; break;
00092         case 'Q':       command = CMD_RETRIG; break;
00093         case 'R':       command = CMD_TREMOLO; break;
00094         case 'S':       command = CMD_S3MCMDEX; break;
00095         case 'T':       command = CMD_TEMPO; break;
00096         case 'U':       command = CMD_FINEVIBRATO; break;
00097         case 'V':       command = CMD_GLOBALVOLUME; break;
00098         case 'W':       command = CMD_GLOBALVOLSLIDE; break;
00099         case 'X':       command = CMD_PANNING8; break;
00100         case 'Y':       command = CMD_PANBRELLO; break;
00101         case 'Z':       command = CMD_MIDI; break;
00102         default:        command = 0;
00103         }
00104         m->command = command;
00105         m->param = param;
00106 }
00107 
00108 
00109 void CSoundFile::S3MSaveConvert(UINT *pcmd, UINT *pprm, BOOL bIT) const
00110 //---------------------------------------------------------------------
00111 {
00112         UINT command = *pcmd;
00113         UINT param = *pprm;
00114         switch(command)
00115         {
00116         case CMD_SPEED:                         command = 'A'; break;
00117         case CMD_POSITIONJUMP:          command = 'B'; break;
00118         case CMD_PATTERNBREAK:          command = 'C'; if (!bIT) param = ((param / 10) << 4) + (param % 10); break;
00119         case CMD_VOLUMESLIDE:           command = 'D'; break;
00120         case CMD_PORTAMENTODOWN:        command = 'E'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break;
00121         case CMD_PORTAMENTOUP:          command = 'F'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break;
00122         case CMD_TONEPORTAMENTO:        command = 'G'; break;
00123         case CMD_VIBRATO:                       command = 'H'; break;
00124         case CMD_TREMOR:                        command = 'I'; break;
00125         case CMD_ARPEGGIO:                      command = 'J'; break;
00126         case CMD_VIBRATOVOL:            command = 'K'; break;
00127         case CMD_TONEPORTAVOL:          command = 'L'; break;
00128         case CMD_CHANNELVOLUME:         command = 'M'; break;
00129         case CMD_CHANNELVOLSLIDE:       command = 'N'; break;
00130         case CMD_OFFSET:                        command = 'O'; break;
00131         case CMD_PANNINGSLIDE:          command = 'P'; break;
00132         case CMD_RETRIG:                        command = 'Q'; break;
00133         case CMD_TREMOLO:                       command = 'R'; break;
00134         case CMD_S3MCMDEX:                      command = 'S'; break;
00135         case CMD_TEMPO:                         command = 'T'; break;
00136         case CMD_FINEVIBRATO:           command = 'U'; break;
00137         case CMD_GLOBALVOLUME:          command = 'V'; break;
00138         case CMD_GLOBALVOLSLIDE:        command = 'W'; break;
00139         case CMD_PANNING8:                      
00140                 command = 'X';
00141                 if ((bIT) && (m_nType != MOD_TYPE_IT) && (m_nType != MOD_TYPE_XM))
00142                 {
00143                         if (param == 0xA4) { command = 'S'; param = 0x91; }     else
00144                         if (param <= 0x80) { param <<= 1; if (param > 255) param = 255; } else
00145                         command = param = 0;
00146                 } else
00147                 if ((!bIT) && ((m_nType == MOD_TYPE_IT) || (m_nType == MOD_TYPE_XM)))
00148                 {
00149                         param >>= 1;
00150                 }
00151                 break;
00152         case CMD_PANBRELLO:                     command = 'Y'; break;
00153         case CMD_MIDI:                          command = 'Z'; break;
00154         case CMD_XFINEPORTAUPDOWN:
00155                 if (param & 0x0F) switch(param & 0xF0)
00156                 {
00157                 case 0x10:      command = 'F'; param = (param & 0x0F) | 0xE0; break;
00158                 case 0x20:      command = 'E'; param = (param & 0x0F) | 0xE0; break;
00159                 case 0x90:      command = 'S'; break;
00160                 default:        command = param = 0;
00161                 } else command = param = 0;
00162                 break;
00163         case CMD_MODCMDEX:
00164                 command = 'S';
00165                 switch(param & 0xF0)
00166                 {
00167                 case 0x00:      command = param = 0; break;
00168                 case 0x10:      command = 'F'; param |= 0xF0; break;
00169                 case 0x20:      command = 'E'; param |= 0xF0; break;
00170                 case 0x30:      param = (param & 0x0F) | 0x10; break;
00171                 case 0x40:      param = (param & 0x0F) | 0x30; break;
00172                 case 0x50:      param = (param & 0x0F) | 0x20; break;
00173                 case 0x60:      param = (param & 0x0F) | 0xB0; break;
00174                 case 0x70:      param = (param & 0x0F) | 0x40; break;
00175                 case 0x90:      command = 'Q'; param &= 0x0F; break;
00176                 case 0xA0:      if (param & 0x0F) { command = 'D'; param = (param << 4) | 0x0F; } else command=param=0; break;
00177                 case 0xB0:      if (param & 0x0F) { command = 'D'; param |= 0xF0; } else command=param=0; break;
00178                 }
00179                 break;
00180         default:        command = param = 0;
00181         }
00182         command &= ~0x40;
00183         *pcmd = command;
00184         *pprm = param;
00185 }
00186 
00187 
00188 BOOL CSoundFile::ReadS3M(const BYTE *lpStream, DWORD dwMemLength)
00189 //---------------------------------------------------------------
00190 {
00191         UINT insnum,patnum,nins,npat;
00192         DWORD insfile[128];
00193         WORD ptr[256];
00194         BYTE s[1024];
00195         DWORD dwMemPos;
00196         BYTE insflags[128], inspack[128];
00197         S3MFILEHEADER psfh = *(S3MFILEHEADER *)lpStream;
00198 
00199         psfh.reserved1 = bswapLE16(psfh.reserved1);
00200         psfh.ordnum = bswapLE16(psfh.ordnum);
00201         psfh.insnum = bswapLE16(psfh.insnum);
00202         psfh.patnum = bswapLE16(psfh.patnum);
00203         psfh.flags = bswapLE16(psfh.flags);
00204         psfh.cwtv = bswapLE16(psfh.cwtv);
00205         psfh.version = bswapLE16(psfh.version);
00206         psfh.scrm = bswapLE32(psfh.scrm);
00207         psfh.special = bswapLE16(psfh.special);
00208 
00209         if ((!lpStream) || (dwMemLength <= sizeof(S3MFILEHEADER)+sizeof(S3MSAMPLESTRUCT)+64)) return FALSE;
00210         if (psfh.scrm != 0x4D524353) return FALSE;
00211         dwMemPos = 0x60;
00212         m_nType = MOD_TYPE_S3M;
00213         memset(m_szNames,0,sizeof(m_szNames));
00214         memcpy(m_szNames[0], psfh.name, 28);
00215         // Speed
00216         m_nDefaultSpeed = psfh.speed;
00217         if (m_nDefaultSpeed < 1) m_nDefaultSpeed = 6;
00218         if (m_nDefaultSpeed > 0x1F) m_nDefaultSpeed = 0x1F;
00219         // Tempo
00220         m_nDefaultTempo = psfh.tempo;
00221         if (m_nDefaultTempo < 40) m_nDefaultTempo = 40;
00222         if (m_nDefaultTempo > 240) m_nDefaultTempo = 240;
00223         // Global Volume
00224         m_nDefaultGlobalVolume = psfh.globalvol << 2;
00225         if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256;
00226         m_nSongPreAmp = psfh.mastervol & 0x7F;
00227         // Channels
00228         m_nChannels = 4;
00229         for (UINT ich=0; ich<32; ich++)
00230         {
00231                 ChnSettings[ich].nPan = 128;
00232                 ChnSettings[ich].nVolume = 64;
00233 
00234                 ChnSettings[ich].dwFlags = CHN_MUTE;
00235                 if (psfh.channels[ich] != 0xFF)
00236                 {
00237                         m_nChannels = ich+1;
00238                         UINT b = psfh.channels[ich] & 0x0F;
00239                         ChnSettings[ich].nPan = (b & 8) ? 0xC0 : 0x40;
00240                         ChnSettings[ich].dwFlags = 0;
00241                 }
00242         }
00243         if (m_nChannels < 4) m_nChannels = 4;
00244         if ((psfh.cwtv < 0x1320) || (psfh.flags & 0x40)) m_dwSongFlags |= SONG_FASTVOLSLIDES;
00245         // Reading pattern order
00246         UINT iord = psfh.ordnum;
00247         if (iord<1) iord = 1;
00248         if (iord > MAX_ORDERS) iord = MAX_ORDERS;
00249         if (iord)
00250         {
00251                 memcpy(Order, lpStream+dwMemPos, iord);
00252                 dwMemPos += iord;
00253         }
00254         if ((iord & 1) && (lpStream[dwMemPos] == 0xFF)) dwMemPos++;
00255         // Reading file pointers
00256         insnum = nins = psfh.insnum;
00257         if (insnum >= MAX_SAMPLES) insnum = MAX_SAMPLES-1;
00258         m_nSamples = insnum;
00259         patnum = npat = psfh.patnum;
00260         if (patnum > MAX_PATTERNS) patnum = MAX_PATTERNS;
00261         memset(ptr, 0, sizeof(ptr));
00262         if (nins+npat)
00263         {
00264                 memcpy(ptr, lpStream+dwMemPos, 2*(nins+npat));
00265                 dwMemPos += 2*(nins+npat);
00266                 for (UINT j = 0; j < (nins+npat); ++j) {
00267                         ptr[j] = bswapLE16(ptr[j]);
00268                 }
00269                 if (psfh.panning_present == 252)
00270                 {
00271                         const BYTE *chnpan = lpStream+dwMemPos;
00272                         for (UINT i=0; i<32; i++) if (chnpan[i] & 0x20)
00273                         {
00274                                 ChnSettings[i].nPan = ((chnpan[i] & 0x0F) << 4) + 8;
00275                         }
00276                 }
00277         }
00278         if (!m_nChannels) return TRUE;
00279         // Reading instrument headers
00280         memset(insfile, 0, sizeof(insfile));
00281         for (UINT iSmp=1; iSmp<=insnum; iSmp++)
00282         {
00283                 UINT nInd = ((DWORD)ptr[iSmp-1])*16;
00284                 if ((!nInd) || (nInd + 0x50 > dwMemLength)) continue;
00285                 memcpy(s, lpStream+nInd, 0x50);
00286                 memcpy(Ins[iSmp].name, s+1, 12);
00287                 insflags[iSmp-1] = s[0x1F];
00288                 inspack[iSmp-1] = s[0x1E];
00289                 s[0x4C] = 0;
00290                 lstrcpy(m_szNames[iSmp], (LPCSTR)&s[0x30]);
00291                 if ((s[0]==1) && (s[0x4E]=='R') && (s[0x4F]=='S'))
00292                 {
00293                         UINT j = bswapLE32(*((LPDWORD)(s+0x10)));
00294                         if (j > MAX_SAMPLE_LENGTH) j = MAX_SAMPLE_LENGTH;
00295                         if (j < 4) j = 0;
00296                         Ins[iSmp].nLength = j;
00297                         j = bswapLE32(*((LPDWORD)(s+0x14)));
00298                         if (j >= Ins[iSmp].nLength) j = Ins[iSmp].nLength - 1;
00299                         Ins[iSmp].nLoopStart = j;
00300                         j = bswapLE32(*((LPDWORD)(s+0x18)));
00301                         if (j > MAX_SAMPLE_LENGTH) j = MAX_SAMPLE_LENGTH;
00302                         if (j < 4) j = 0;
00303                         if (j > Ins[iSmp].nLength) j = Ins[iSmp].nLength;
00304                         Ins[iSmp].nLoopEnd = j;
00305                         j = s[0x1C];
00306                         if (j > 64) j = 64;
00307                         Ins[iSmp].nVolume = j << 2;
00308                         Ins[iSmp].nGlobalVol = 64;
00309                         if (s[0x1F]&1) Ins[iSmp].uFlags |= CHN_LOOP;
00310                         j = bswapLE32(*((LPDWORD)(s+0x20)));
00311                         if (!j) j = 8363;
00312                         if (j < 1024) j = 1024;
00313                         Ins[iSmp].nC4Speed = j;
00314                         insfile[iSmp] = ((DWORD)bswapLE16(*((LPWORD)(s+0x0E)))) << 4;
00315                         insfile[iSmp] += ((DWORD)(BYTE)s[0x0D]) << 20;
00316                         if (insfile[iSmp] > dwMemLength) insfile[iSmp] &= 0xFFFF;
00317                         if ((Ins[iSmp].nLoopStart >= Ins[iSmp].nLoopEnd) || (Ins[iSmp].nLoopEnd - Ins[iSmp].nLoopStart < 8))
00318                                 Ins[iSmp].nLoopStart = Ins[iSmp].nLoopEnd = 0;
00319                         Ins[iSmp].nPan = 0x80;
00320                 }
00321         }
00322         // Reading patterns
00323         for (UINT iPat=0; iPat<patnum; iPat++)
00324         {
00325                 UINT nInd = ((DWORD)ptr[nins+iPat]) << 4;
00326                 if (nInd + 0x40 > dwMemLength) continue;
00327                 WORD len = bswapLE16(*((WORD *)(lpStream+nInd)));
00328                 nInd += 2;
00329                 PatternSize[iPat] = 64;
00330                 if ((!len) || (nInd + len > dwMemLength - 6)
00331                  || ((Patterns[iPat] = AllocatePattern(64, m_nChannels)) == NULL)) continue;
00332                 LPBYTE src = (LPBYTE)(lpStream+nInd);
00333                 // Unpacking pattern
00334                 MODCOMMAND *p = Patterns[iPat];
00335                 UINT row = 0;
00336                 UINT j = 0;
00337                 while (j < len)
00338                 {
00339                         BYTE b = src[j++];
00340                         if (!b)
00341                         {
00342                                 if (++row >= 64) break;
00343                         } else
00344                         {
00345                                 UINT chn = b & 0x1F;
00346                                 if (chn < m_nChannels)
00347                                 {
00348                                         MODCOMMAND *m = &p[row*m_nChannels+chn];
00349                                         if (b & 0x20)
00350                                         {
00351                                                 m->note = src[j++];
00352                                                 if (m->note < 0xF0) m->note = (m->note & 0x0F) + 12*(m->note >> 4) + 13;
00353                                                 else if (m->note == 0xFF) m->note = 0;
00354                                                 m->instr = src[j++];
00355                                         }
00356                                         if (b & 0x40)
00357                                         {
00358                                                 UINT vol = src[j++];
00359                                                 if ((vol >= 128) && (vol <= 192))
00360                                                 {
00361                                                         vol -= 128;
00362                                                         m->volcmd = VOLCMD_PANNING;
00363                                                 } else
00364                                                 {
00365                                                         if (vol > 64) vol = 64;
00366                                                         m->volcmd = VOLCMD_VOLUME;
00367                                                 }
00368                                                 m->vol = vol;
00369                                         }
00370                                         if (b & 0x80)
00371                                         {
00372                                                 m->command = src[j++];
00373                                                 m->param = src[j++];
00374                                                 if (m->command) S3MConvert(m, FALSE);
00375                                         }
00376                                 } else
00377                                 {
00378                                         if (b & 0x20) j += 2;
00379                                         if (b & 0x40) j++;
00380                                         if (b & 0x80) j += 2;
00381                                 }
00382                                 if (j >= len) break;
00383                         }
00384                 }
00385         }
00386         // Reading samples
00387         for (UINT iRaw=1; iRaw<=insnum; iRaw++) if ((Ins[iRaw].nLength) && (insfile[iRaw]))
00388         {
00389                 UINT flags = (psfh.version == 1) ? RS_PCM8S : RS_PCM8U;
00390                 if (insflags[iRaw-1] & 4) flags += 5;
00391                 if (insflags[iRaw-1] & 2) flags |= RSF_STEREO;
00392                 if (inspack[iRaw-1] == 4) flags = RS_ADPCM4;
00393                 dwMemPos = insfile[iRaw];
00394                 dwMemPos += ReadSample(&Ins[iRaw], flags, (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
00395         }
00396         m_nMinPeriod = 64;
00397         m_nMaxPeriod = 32767;
00398         if (psfh.flags & 0x10) m_dwSongFlags |= SONG_AMIGALIMITS;
00399         return TRUE;
00400 }
00401 
00402 
00403 #ifndef MODPLUG_NO_FILESAVE
00404 #pragma warning(disable:4100)
00405 
00406 static const BYTE S3MFiller[16] =
00407 {
00408         0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
00409         0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
00410 };
00411 
00412 
00413 BOOL CSoundFile::SaveS3M(LPCSTR lpszFileName, UINT nPacking)
00414 //----------------------------------------------------------
00415 {
00416         FILE *f;
00417         BYTE header[0x60];
00418         UINT nbo,nbi,nbp,i;
00419         WORD patptr[128];
00420         WORD insptr[128];
00421         BYTE buffer[5*1024];
00422         S3MSAMPLESTRUCT insex[128];
00423 
00424         if ((!m_nChannels) || (!lpszFileName)) return FALSE;
00425         if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
00426         // Writing S3M header
00427         memset(header, 0, sizeof(header));
00428         memset(insex, 0, sizeof(insex));
00429         memcpy(header, m_szNames[0], 0x1C);
00430         header[0x1B] = 0;
00431         header[0x1C] = 0x1A;
00432         header[0x1D] = 0x10;
00433         nbo = (GetNumPatterns() + 15) & 0xF0;
00434         if (!nbo) nbo = 16;
00435         header[0x20] = nbo & 0xFF;
00436         header[0x21] = nbo >> 8;
00437         nbi = m_nInstruments;
00438         if (!nbi) nbi = m_nSamples;
00439         if (nbi > 99) nbi = 99;
00440         header[0x22] = nbi & 0xFF;
00441         header[0x23] = nbi >> 8;
00442         nbp = 0;
00443         for (i=0; Patterns[i]; i++) { nbp = i+1; if (nbp >= MAX_PATTERNS) break; }
00444         for (i=0; i<MAX_ORDERS; i++) if ((Order[i] < MAX_PATTERNS) && (Order[i] >= nbp)) nbp = Order[i] + 1;
00445         header[0x24] = nbp & 0xFF;
00446         header[0x25] = nbp >> 8;
00447         if (m_dwSongFlags & SONG_FASTVOLSLIDES) header[0x26] |= 0x40;
00448         if ((m_nMaxPeriod < 20000) || (m_dwSongFlags & SONG_AMIGALIMITS)) header[0x26] |= 0x10;
00449         header[0x28] = 0x20;
00450         header[0x29] = 0x13;
00451         header[0x2A] = 0x02; // Version = 1 => Signed samples
00452         header[0x2B] = 0x00;
00453         header[0x2C] = 'S';
00454         header[0x2D] = 'C';
00455         header[0x2E] = 'R';
00456         header[0x2F] = 'M';
00457         header[0x30] = m_nDefaultGlobalVolume >> 2;
00458         header[0x31] = m_nDefaultSpeed;
00459         header[0x32] = m_nDefaultTempo;
00460         header[0x33] = ((m_nSongPreAmp < 0x20) ? 0x20 : m_nSongPreAmp) | 0x80;  // Stereo
00461         header[0x35] = 0xFC;
00462         for (i=0; i<32; i++)
00463         {
00464                 if (i < m_nChannels)
00465                 {
00466                         UINT tmp = (i & 0x0F) >> 1;
00467                         header[0x40+i] = (i & 0x10) | ((i & 1) ? 8+tmp : tmp);
00468                 } else header[0x40+i] = 0xFF;
00469         }
00470         fwrite(header, 0x60, 1, f);
00471         fwrite(Order, nbo, 1, f);
00472         memset(patptr, 0, sizeof(patptr));
00473         memset(insptr, 0, sizeof(insptr));
00474         UINT ofs0 = 0x60 + nbo;
00475         UINT ofs1 = ((0x60 + nbo + nbi*2 + nbp*2 + 15) & 0xFFF0) + 0x20;
00476         UINT ofs = ofs1;
00477 
00478         for (i=0; i<nbi; i++) insptr[i] = (WORD)((ofs + i*0x50) / 16);
00479         for (i=0; i<nbp; i++) patptr[i] = (WORD)((ofs + nbi*0x50) / 16);
00480         fwrite(insptr, nbi, 2, f);
00481         fwrite(patptr, nbp, 2, f);
00482         if (header[0x35] == 0xFC)
00483         {
00484                 BYTE chnpan[32];
00485                 for (i=0; i<32; i++)
00486                 {
00487                         chnpan[i] = 0x20 | (ChnSettings[i].nPan >> 4);
00488                 }
00489                 fwrite(chnpan, 0x20, 1, f);
00490         }
00491         if ((nbi*2+nbp*2) & 0x0F)
00492         {
00493                 fwrite(S3MFiller, 0x10 - ((nbi*2+nbp*2) & 0x0F), 1, f);
00494         }
00495         ofs1 = ftell(f);
00496         fwrite(insex, nbi, 0x50, f);
00497         // Packing patterns
00498         ofs += nbi*0x50;
00499         for (i=0; i<nbp; i++)
00500         {
00501                 WORD len = 64;
00502                 memset(buffer, 0, sizeof(buffer));
00503                 patptr[i] = ofs / 16;
00504                 if (Patterns[i])
00505                 {
00506                         len = 2;
00507                         MODCOMMAND *p = Patterns[i];
00508                         for (int row=0; row<64; row++) if (row < PatternSize[i])
00509                         {
00510                                 for (UINT j=0; j<m_nChannels; j++)
00511                                 {
00512                                         UINT b = j;
00513                                         MODCOMMAND *m = &p[row*m_nChannels+j];
00514                                         UINT note = m->note;
00515                                         UINT volcmd = m->volcmd;
00516                                         UINT vol = m->vol;
00517                                         UINT command = m->command;
00518                                         UINT param = m->param;
00519 
00520                                         if ((note) || (m->instr)) b |= 0x20;
00521                                         if (!note) note = 0xFF; else
00522                                         if (note >= 0xFE) note = 0xFE; else
00523                                         if (note < 13) note = 0; else note -= 13;
00524                                         if (note < 0xFE) note = (note % 12) + ((note / 12) << 4);
00525                                         if (command == CMD_VOLUME)
00526                                         {
00527                                                 command = 0;
00528                                                 if (param > 64) param = 64;
00529                                                 volcmd = VOLCMD_VOLUME;
00530                                                 vol = param;
00531                                         }
00532                                         if (volcmd == VOLCMD_VOLUME) b |= 0x40; else
00533                                         if (volcmd == VOLCMD_PANNING) { vol |= 0x80; b |= 0x40; }
00534                                         if (command)
00535                                         {
00536                                                 S3MSaveConvert(&command, &param, FALSE);
00537                                                 if (command) b |= 0x80;
00538                                         }
00539                                         if (b & 0xE0)
00540                                         {
00541                                                 buffer[len++] = b;
00542                                                 if (b & 0x20)
00543                                                 {
00544                                                         buffer[len++] = note;
00545                                                         buffer[len++] = m->instr;
00546                                                 }
00547                                                 if (b & 0x40)
00548                                                 {
00549                                                         buffer[len++] = vol;
00550                                                 }
00551                                                 if (b & 0x80)
00552                                                 {
00553                                                         buffer[len++] = command;
00554                                                         buffer[len++] = param;
00555                                                 }
00556                                                 if (len > sizeof(buffer) - 20) break;
00557                                         }
00558                                 }
00559                                 buffer[len++] = 0;
00560                                 if (len > sizeof(buffer) - 20) break;
00561                         }
00562                 }
00563                 buffer[0] = (len - 2) & 0xFF;
00564                 buffer[1] = (len - 2) >> 8;
00565                 len = (len+15) & (~0x0F);
00566                 fwrite(buffer, len, 1, f);
00567                 ofs += len;
00568         }
00569         // Writing samples
00570         for (i=1; i<=nbi; i++)
00571         {
00572                 MODINSTRUMENT *pins = &Ins[i];
00573                 if (m_nInstruments)
00574                 {
00575                         pins = Ins;
00576                         if (Headers[i])
00577                         {
00578                                 for (UINT j=0; j<128; j++)
00579                                 {
00580                                         UINT n = Headers[i]->Keyboard[j];
00581                                         if ((n) && (n < MAX_INSTRUMENTS))
00582                                         {
00583                                                 pins = &Ins[n];
00584                                                 break;
00585                                         }
00586                                 }
00587                         }
00588                 }
00589                 memcpy(insex[i-1].dosname, pins->name, 12);
00590                 memcpy(insex[i-1].name, m_szNames[i], 28);
00591                 memcpy(insex[i-1].scrs, "SCRS", 4);
00592                 insex[i-1].hmem = (BYTE)((DWORD)ofs >> 20);
00593                 insex[i-1].memseg = (WORD)((DWORD)ofs >> 4);
00594                 if (pins->pSample)
00595                 {
00596                         insex[i-1].type = 1;
00597                         insex[i-1].length = pins->nLength;
00598                         insex[i-1].loopbegin = pins->nLoopStart;
00599                         insex[i-1].loopend = pins->nLoopEnd;
00600                         insex[i-1].vol = pins->nVolume / 4;
00601                         insex[i-1].flags = (pins->uFlags & CHN_LOOP) ? 1 : 0;
00602                         if (pins->nC4Speed)
00603                                 insex[i-1].finetune = pins->nC4Speed;
00604                         else
00605                                 insex[i-1].finetune = TransposeToFrequency(pins->RelativeTone, pins->nFineTune);
00606                         UINT flags = RS_PCM8U;
00607 #ifndef NO_PACKING
00608                         if (nPacking)
00609                         {
00610                                 if ((!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
00611                                  && (CanPackSample(pins->pSample, pins->nLength, nPacking)))
00612                                 {
00613                                         insex[i-1].pack = 4;
00614                                         flags = RS_ADPCM4;
00615                                 }
00616                         } else
00617 #endif // NO_PACKING
00618                         {
00619                                 if (pins->uFlags & CHN_16BIT)
00620                                 {
00621                                         insex[i-1].flags |= 4;
00622                                         flags = RS_PCM16U;
00623                                 }
00624                                 if (pins->uFlags & CHN_STEREO)
00625                                 {
00626                                         insex[i-1].flags |= 2;
00627                                         flags = (pins->uFlags & CHN_16BIT) ? RS_STPCM16U : RS_STPCM8U;
00628                                 }
00629                         }
00630                         DWORD len = WriteSample(f, pins, flags);
00631                         if (len & 0x0F)
00632                         {
00633                                 fwrite(S3MFiller, 0x10 - (len & 0x0F), 1, f);
00634                         }
00635                         ofs += (len + 15) & (~0x0F);
00636                 } else
00637                 {
00638                         insex[i-1].length = 0;
00639                 }
00640         }
00641         // Updating parapointers
00642         fseek(f, ofs0, SEEK_SET);
00643         fwrite(insptr, nbi, 2, f);
00644         fwrite(patptr, nbp, 2, f);
00645         fseek(f, ofs1, SEEK_SET);
00646         fwrite(insex, 0x50, nbi, f);
00647         fclose(f);
00648         return TRUE;
00649 }
00650 
00651 #pragma warning(default:4100)
00652 #endif // MODPLUG_NO_FILESAVE
00653 

Generated on Sat Nov 5 16:15:40 2005 for OPIE by  doxygen 1.4.2