00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "stdafx.h"
00012 #include "sndfile.h"
00013
00014
00015
00016 extern WORD S3MFineTuneTable[16];
00017
00019
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;
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
00216 m_nDefaultSpeed = psfh.speed;
00217 if (m_nDefaultSpeed < 1) m_nDefaultSpeed = 6;
00218 if (m_nDefaultSpeed > 0x1F) m_nDefaultSpeed = 0x1F;
00219
00220 m_nDefaultTempo = psfh.tempo;
00221 if (m_nDefaultTempo < 40) m_nDefaultTempo = 40;
00222 if (m_nDefaultTempo > 240) m_nDefaultTempo = 240;
00223
00224 m_nDefaultGlobalVolume = psfh.globalvol << 2;
00225 if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256;
00226 m_nSongPreAmp = psfh.mastervol & 0x7F;
00227
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
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
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
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
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
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
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
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;
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;
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
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, ¶m, 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
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
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