1 /* 2 * This source code is public domain. 3 * 4 * Authors: Olivier Lapicque <olivierl@jps.net>, 5 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC) 6 */ 7 8 #include "stdafx.h" 9 #include "sndfile.h" 10 #include "tables.h" 11 12 #ifdef _MSC_VER 13 //#pragma warning(disable:4244) 14 #endif 15 16 ////////////////////////////////////////////////////// 17 // ScreamTracker S3M file support 18 19 #pragma pack(1) 20 typedef struct tagS3MSAMPLESTRUCT 21 { 22 BYTE type; 23 CHAR dosname[12]; 24 BYTE hmem; 25 WORD memseg; 26 DWORD length; 27 DWORD loopbegin; 28 DWORD loopend; 29 BYTE vol; 30 BYTE bReserved; 31 BYTE pack; 32 BYTE flags; 33 DWORD finetune; 34 DWORD dwReserved; 35 WORD intgp; 36 WORD int512; 37 DWORD lastused; 38 CHAR name[28]; 39 CHAR scrs[4]; 40 } S3MSAMPLESTRUCT; 41 42 43 typedef struct tagS3MFILEHEADER 44 { 45 CHAR name[28]; 46 BYTE b1A; 47 BYTE type; 48 WORD reserved1; 49 WORD ordnum; 50 WORD insnum; 51 WORD patnum; 52 WORD flags; 53 WORD cwtv; 54 WORD version; 55 DWORD scrm; // "SCRM" = 0x4D524353 56 BYTE globalvol; 57 BYTE speed; 58 BYTE tempo; 59 BYTE mastervol; 60 BYTE ultraclicks; 61 BYTE panning_present; 62 BYTE reserved2[8]; 63 WORD special; 64 BYTE channels[32]; 65 } S3MFILEHEADER; 66 67 68 void CSoundFile::S3MConvert(MODCOMMAND *m, BOOL bIT) const 69 //-------------------------------------------------------- 70 { 71 UINT command = m->command; 72 UINT param = m->param; 73 switch (command + 0x40) 74 { 75 case 'A': command = CMD_SPEED; break; 76 case 'B': command = CMD_POSITIONJUMP; break; 77 case 'C': command = CMD_PATTERNBREAK; if (!bIT) param = (param >> 4) * 10 + (param & 0x0F); break; 78 case 'D': command = CMD_VOLUMESLIDE; break; 79 case 'E': command = CMD_PORTAMENTODOWN; break; 80 case 'F': command = CMD_PORTAMENTOUP; break; 81 case 'G': command = CMD_TONEPORTAMENTO; break; 82 case 'H': command = CMD_VIBRATO; break; 83 case 'I': command = CMD_TREMOR; break; 84 case 'J': command = CMD_ARPEGGIO; break; 85 case 'K': command = CMD_VIBRATOVOL; break; 86 case 'L': command = CMD_TONEPORTAVOL; break; 87 case 'M': command = CMD_CHANNELVOLUME; break; 88 case 'N': command = CMD_CHANNELVOLSLIDE; break; 89 case 'O': command = CMD_OFFSET; break; 90 case 'P': command = CMD_PANNINGSLIDE; break; 91 case 'Q': command = CMD_RETRIG; break; 92 case 'R': command = CMD_TREMOLO; break; 93 case 'S': command = CMD_S3MCMDEX; break; 94 case 'T': command = CMD_TEMPO; break; 95 case 'U': command = CMD_FINEVIBRATO; break; 96 case 'V': command = CMD_GLOBALVOLUME; break; 97 case 'W': command = CMD_GLOBALVOLSLIDE; break; 98 case 'X': command = CMD_PANNING8; break; 99 case 'Y': command = CMD_PANBRELLO; break; 100 case 'Z': command = CMD_MIDI; break; 101 default: command = 0; 102 } 103 m->command = command; 104 m->param = param; 105 } 106 107 108 #ifndef MODPLUG_NO_FILESAVE 109 void CSoundFile::S3MSaveConvert(UINT *pcmd, UINT *pprm, BOOL bIT) const 110 //--------------------------------------------------------------------- 111 { 112 UINT command = *pcmd; 113 UINT param = *pprm; 114 switch(command) 115 { 116 case CMD_SPEED: command = 'A'; break; 117 case CMD_POSITIONJUMP: command = 'B'; break; 118 case CMD_PATTERNBREAK: command = 'C'; if (!bIT) param = ((param / 10) << 4) + (param % 10); break; 119 case CMD_VOLUMESLIDE: command = 'D'; break; 120 case CMD_PORTAMENTODOWN: command = 'E'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break; 121 case CMD_PORTAMENTOUP: command = 'F'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break; 122 case CMD_TONEPORTAMENTO: command = 'G'; break; 123 case CMD_VIBRATO: command = 'H'; break; 124 case CMD_TREMOR: command = 'I'; break; 125 case CMD_ARPEGGIO: command = 'J'; break; 126 case CMD_VIBRATOVOL: command = 'K'; break; 127 case CMD_TONEPORTAVOL: command = 'L'; break; 128 case CMD_CHANNELVOLUME: command = 'M'; break; 129 case CMD_CHANNELVOLSLIDE: command = 'N'; break; 130 case CMD_OFFSET: command = 'O'; break; 131 case CMD_PANNINGSLIDE: command = 'P'; break; 132 case CMD_RETRIG: command = 'Q'; break; 133 case CMD_TREMOLO: command = 'R'; break; 134 case CMD_S3MCMDEX: command = 'S'; break; 135 case CMD_TEMPO: command = 'T'; break; 136 case CMD_FINEVIBRATO: command = 'U'; break; 137 case CMD_GLOBALVOLUME: command = 'V'; break; 138 case CMD_GLOBALVOLSLIDE: command = 'W'; break; 139 case CMD_PANNING8: 140 command = 'X'; 141 if ((bIT) && (m_nType != MOD_TYPE_IT) && (m_nType != MOD_TYPE_XM)) 142 { 143 if (param == 0xA4) { command = 'S'; param = 0x91; } else 144 if (param <= 0x80) { param <<= 1; if (param > 255) param = 255; } else 145 command = param = 0; 146 } else 147 if ((!bIT) && ((m_nType == MOD_TYPE_IT) || (m_nType == MOD_TYPE_XM))) 148 { 149 param >>= 1; 150 } 151 break; 152 case CMD_PANBRELLO: command = 'Y'; break; 153 case CMD_MIDI: command = 'Z'; break; 154 case CMD_XFINEPORTAUPDOWN: 155 if (param & 0x0F) switch(param & 0xF0) 156 { 157 case 0x10: command = 'F'; param = (param & 0x0F) | 0xE0; break; 158 case 0x20: command = 'E'; param = (param & 0x0F) | 0xE0; break; 159 case 0x90: command = 'S'; break; 160 default: command = param = 0; 161 } else command = param = 0; 162 break; 163 case CMD_MODCMDEX: 164 command = 'S'; 165 switch(param & 0xF0) 166 { 167 case 0x00: command = param = 0; break; 168 case 0x10: command = 'F'; param |= 0xF0; break; 169 case 0x20: command = 'E'; param |= 0xF0; break; 170 case 0x30: param = (param & 0x0F) | 0x10; break; 171 case 0x40: param = (param & 0x0F) | 0x30; break; 172 case 0x50: param = (param & 0x0F) | 0x20; break; 173 case 0x60: param = (param & 0x0F) | 0xB0; break; 174 case 0x70: param = (param & 0x0F) | 0x40; break; 175 case 0x90: command = 'Q'; param &= 0x0F; break; 176 case 0xA0: if (param & 0x0F) { command = 'D'; param = (param << 4) | 0x0F; } else command=param=0; break; 177 case 0xB0: if (param & 0x0F) { command = 'D'; param |= 0xF0; } else command=param=0; break; 178 } 179 break; 180 default: command = param = 0; 181 } 182 command &= ~0x40; 183 *pcmd = command; 184 *pprm = param; 185 } 186 #endif // MODPLUG_NO_FILESAVE 187 188 static DWORD boundInput(DWORD input, DWORD smin, DWORD smax) 189 { 190 if (input > smax) input = smax; 191 else if (input < smin) input = 0; 192 return(input); 193 } 194 195 196 BOOL CSoundFile::ReadS3M(const BYTE *lpStream, DWORD dwMemLength) 197 //--------------------------------------------------------------- 198 { 199 UINT insnum,patnum,nins,npat; 200 DWORD insfile[MAX_SAMPLES]; 201 WORD ptr[256]; 202 DWORD dwMemPos; 203 BYTE insflags[MAX_SAMPLES], inspack[MAX_SAMPLES]; 204 205 if ((!lpStream) || (dwMemLength <= sizeof(S3MFILEHEADER)+sizeof(S3MSAMPLESTRUCT)+64)) return FALSE; 206 S3MFILEHEADER psfh = *(S3MFILEHEADER *)lpStream; 207 208 psfh.reserved1 = bswapLE16(psfh.reserved1); 209 psfh.ordnum = bswapLE16(psfh.ordnum); 210 psfh.insnum = bswapLE16(psfh.insnum); 211 psfh.patnum = bswapLE16(psfh.patnum); 212 psfh.flags = bswapLE16(psfh.flags); 213 psfh.cwtv = bswapLE16(psfh.cwtv); 214 psfh.version = bswapLE16(psfh.version); 215 psfh.scrm = bswapLE32(psfh.scrm); 216 psfh.special = bswapLE16(psfh.special); 217 218 if (psfh.scrm != 0x4D524353) return FALSE; 219 dwMemPos = 0x60; 220 m_nType = MOD_TYPE_S3M; 221 memset(m_szNames,0,sizeof(m_szNames)); 222 memcpy(m_szNames[0], psfh.name, 28); 223 // Speed 224 m_nDefaultSpeed = psfh.speed; 225 if (m_nDefaultSpeed < 1) m_nDefaultSpeed = 6; 226 if (m_nDefaultSpeed > 0x1F) m_nDefaultSpeed = 0x1F; 227 // Tempo 228 m_nDefaultTempo = psfh.tempo; 229 if (m_nDefaultTempo < 40) m_nDefaultTempo = 40; 230 if (m_nDefaultTempo > 240) m_nDefaultTempo = 240; 231 // Global Volume 232 m_nDefaultGlobalVolume = psfh.globalvol << 2; 233 if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256; 234 m_nSongPreAmp = psfh.mastervol & 0x7F; 235 // Channels 236 m_nChannels = 4; 237 for (UINT ich=0; ich<32; ich++) 238 { 239 ChnSettings[ich].nPan = 128; 240 ChnSettings[ich].nVolume = 64; 241 242 ChnSettings[ich].dwFlags = CHN_MUTE; 243 if (psfh.channels[ich] != 0xFF) 244 { 245 m_nChannels = ich+1; 246 UINT b = psfh.channels[ich] & 0x0F; 247 ChnSettings[ich].nPan = (b & 8) ? 0xC0 : 0x40; 248 ChnSettings[ich].dwFlags = 0; 249 } 250 } 251 if (m_nChannels < 4) m_nChannels = 4; 252 if ((psfh.cwtv < 0x1320) || (psfh.flags & 0x40)) m_dwSongFlags |= SONG_FASTVOLSLIDES; 253 // Reading pattern order 254 UINT iord = psfh.ordnum; 255 if (iord<1) iord = 1; 256 if (iord > MAX_ORDERS) iord = MAX_ORDERS; 257 if (iord) 258 { 259 memcpy(Order, lpStream+dwMemPos, iord); 260 dwMemPos += iord; 261 } 262 if ((iord & 1) && (lpStream[dwMemPos] == 0xFF)) dwMemPos++; 263 // Reading file pointers 264 insnum = nins = psfh.insnum; 265 if (insnum >= MAX_SAMPLES) insnum = MAX_SAMPLES-1; 266 m_nSamples = insnum; 267 patnum = npat = psfh.patnum; 268 if (patnum > MAX_PATTERNS) patnum = MAX_PATTERNS; 269 memset(ptr, 0, sizeof(ptr)); 270 271 // Ignore file if it has a corrupted header. 272 if (nins+npat > 256) return FALSE; 273 274 if (nins+npat) 275 { 276 memcpy(ptr, lpStream+dwMemPos, 2*(nins+npat)); 277 dwMemPos += 2*(nins+npat); 278 for (UINT j = 0; j < (nins+npat); ++j) { 279 ptr[j] = bswapLE16(ptr[j]); 280 } 281 if (psfh.panning_present == 252) 282 { 283 const BYTE *chnpan = lpStream+dwMemPos; 284 for (UINT i=0; i<32; i++) if (chnpan[i] & 0x20) 285 { 286 ChnSettings[i].nPan = ((chnpan[i] & 0x0F) << 4) + 8; 287 } 288 } 289 } 290 if (!m_nChannels) return TRUE; 291 // Reading instrument headers 292 memset(insfile, 0, sizeof(insfile)); 293 for (UINT iSmp=1; iSmp<=insnum; iSmp++) 294 { 295 UINT nInd = ((DWORD)ptr[iSmp-1])*16; 296 if ((!nInd) || (nInd + 0x50 > dwMemLength)) { 297 // initialize basic variables. 298 insflags[iSmp-1] = 0; 299 inspack[iSmp-1] = 0; 300 continue; 301 } 302 S3MSAMPLESTRUCT pSmp; 303 memcpy(&pSmp, lpStream+nInd, 0x50); 304 memcpy(Ins[iSmp].name, &pSmp.dosname, 12); 305 insflags[iSmp-1] = pSmp.flags; 306 inspack[iSmp-1] = pSmp.pack; 307 memcpy(m_szNames[iSmp], pSmp.name, 28); 308 m_szNames[iSmp][28] = 0; 309 if ((pSmp.type==1) && (pSmp.scrs[2]=='R') && (pSmp.scrs[3]=='S')) 310 { 311 Ins[iSmp].nLength = boundInput(bswapLE32(pSmp.length), 4, MAX_SAMPLE_LENGTH); 312 Ins[iSmp].nLoopStart = boundInput(bswapLE32(pSmp.loopbegin), 4, Ins[iSmp].nLength - 1); 313 Ins[iSmp].nLoopEnd = boundInput(bswapLE32(pSmp.loopend), 4, Ins[iSmp].nLength); 314 Ins[iSmp].nVolume = boundInput(pSmp.vol, 0, 64) << 2; 315 Ins[iSmp].nGlobalVol = 64; 316 if (pSmp.flags&1) Ins[iSmp].uFlags |= CHN_LOOP; 317 UINT j = bswapLE32(pSmp.finetune); 318 if (!j) j = 8363; 319 if (j < 1024) j = 1024; 320 Ins[iSmp].nC4Speed = j; 321 insfile[iSmp] = (pSmp.hmem << 20) + (bswapLE16(pSmp.memseg) << 4); 322 // offset is invalid - ignore this sample. 323 if (insfile[iSmp] > dwMemLength) insfile[iSmp] = 0; 324 else if (insfile[iSmp]) { 325 // ignore duplicate samples. 326 for (int z=iSmp-1; z>=0; z--) 327 if (insfile[iSmp] == insfile[z]) 328 insfile[iSmp] = 0; 329 } 330 if ((Ins[iSmp].nLoopStart >= Ins[iSmp].nLoopEnd) || (Ins[iSmp].nLoopEnd - Ins[iSmp].nLoopStart < 8)) 331 Ins[iSmp].nLoopStart = Ins[iSmp].nLoopEnd = 0; 332 Ins[iSmp].nPan = 0x80; 333 } 334 } 335 // Reading patterns 336 for (UINT iPat=0; iPat<patnum; iPat++) 337 { 338 UINT nInd = ((DWORD)ptr[nins+iPat]) << 4; 339 if (nInd + 0x40 > dwMemLength) continue; 340 WORD len = bswapLE16(*((WORD *)(lpStream+nInd))); 341 nInd += 2; 342 PatternSize[iPat] = 64; 343 if ((!len) || (nInd + len > dwMemLength - 6) 344 || ((Patterns[iPat] = AllocatePattern(64, m_nChannels)) == NULL)) continue; 345 LPBYTE src = (LPBYTE)(lpStream+nInd); 346 // Unpacking pattern 347 MODCOMMAND *p = Patterns[iPat]; 348 UINT row = 0; 349 UINT j = 0; 350 while (j < len) 351 { 352 BYTE b = src[j++]; 353 if (!b) 354 { 355 if (++row >= 64) break; 356 } else 357 { 358 UINT chn = b & 0x1F; 359 if (chn < m_nChannels) 360 { 361 MODCOMMAND *m = &p[row*m_nChannels+chn]; 362 if (b & 0x20) 363 { 364 m->note = src[j++]; 365 if (m->note < 0xF0) m->note = (m->note & 0x0F) + 12*(m->note >> 4) + 13; 366 else if (m->note == 0xFF) m->note = 0; 367 m->instr = src[j++]; 368 } 369 if (b & 0x40) 370 { 371 UINT vol = src[j++]; 372 if ((vol >= 128) && (vol <= 192)) 373 { 374 vol -= 128; 375 m->volcmd = VOLCMD_PANNING; 376 } else 377 { 378 if (vol > 64) vol = 64; 379 m->volcmd = VOLCMD_VOLUME; 380 } 381 m->vol = vol; 382 } 383 if (b & 0x80) 384 { 385 m->command = src[j++]; 386 m->param = src[j++]; 387 if (m->command) S3MConvert(m, FALSE); 388 } 389 } else 390 { 391 if (b & 0x20) j += 2; 392 if (b & 0x40) j++; 393 if (b & 0x80) j += 2; 394 } 395 if (j >= len) break; 396 } 397 } 398 } 399 // Reading samples 400 for (UINT iRaw=1; iRaw<=insnum; iRaw++) if ((Ins[iRaw].nLength) && (insfile[iRaw])) 401 { 402 UINT flags = (psfh.version == 1) ? RS_PCM8S : RS_PCM8U; 403 if (insflags[iRaw-1] & 4) flags += 5; 404 if (insflags[iRaw-1] & 2) flags |= RSF_STEREO; 405 if (inspack[iRaw-1] == 4) flags = RS_ADPCM4; 406 dwMemPos = insfile[iRaw]; 407 if (dwMemPos < dwMemLength) 408 ReadSample(&Ins[iRaw], flags, (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos); 409 } 410 m_nMinPeriod = 64; 411 m_nMaxPeriod = 32767; 412 if (psfh.flags & 0x10) m_dwSongFlags |= SONG_AMIGALIMITS; 413 return TRUE; 414 } 415 416 417 #ifndef MODPLUG_NO_FILESAVE 418 419 #ifdef _MSC_VER 420 #pragma warning(disable:4100) 421 #endif 422 423 static BYTE S3MFiller[16] = 424 { 425 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 426 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 427 }; 428 429 430 BOOL CSoundFile::SaveS3M(LPCSTR lpszFileName, UINT nPacking) 431 //---------------------------------------------------------- 432 { 433 FILE *f; 434 BYTE header[0x60]; 435 UINT nbo,nbi,nbp,i; 436 WORD patptr[128]; 437 WORD insptr[128]; 438 BYTE buffer[5*1024]; 439 S3MSAMPLESTRUCT insex[128]; 440 441 if ((!m_nChannels) || (!lpszFileName)) return FALSE; 442 if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE; 443 // Writing S3M header 444 memset(header, 0, sizeof(header)); 445 memset(insex, 0, sizeof(insex)); 446 memcpy(header, m_szNames[0], 0x1C); 447 header[0x1B] = 0; 448 header[0x1C] = 0x1A; 449 header[0x1D] = 0x10; 450 nbo = (GetNumPatterns() + 15) & 0xF0; 451 if (!nbo) nbo = 16; 452 header[0x20] = nbo & 0xFF; 453 header[0x21] = nbo >> 8; 454 nbi = m_nInstruments; 455 if (!nbi) nbi = m_nSamples; 456 if (nbi > 99) nbi = 99; 457 header[0x22] = nbi & 0xFF; 458 header[0x23] = nbi >> 8; 459 nbp = 0; 460 for (i=0; Patterns[i]; i++) { nbp = i+1; if (nbp >= MAX_PATTERNS) break; } 461 for (i=0; i<MAX_ORDERS; i++) if ((Order[i] < MAX_PATTERNS) && (Order[i] >= nbp)) nbp = Order[i] + 1; 462 header[0x24] = nbp & 0xFF; 463 header[0x25] = nbp >> 8; 464 if (m_dwSongFlags & SONG_FASTVOLSLIDES) header[0x26] |= 0x40; 465 if ((m_nMaxPeriod < 20000) || (m_dwSongFlags & SONG_AMIGALIMITS)) header[0x26] |= 0x10; 466 header[0x28] = 0x20; 467 header[0x29] = 0x13; 468 header[0x2A] = 0x02; // Version = 1 => Signed samples 469 header[0x2B] = 0x00; 470 header[0x2C] = 'S'; 471 header[0x2D] = 'C'; 472 header[0x2E] = 'R'; 473 header[0x2F] = 'M'; 474 header[0x30] = m_nDefaultGlobalVolume >> 2; 475 header[0x31] = m_nDefaultSpeed; 476 header[0x32] = m_nDefaultTempo; 477 header[0x33] = ((m_nSongPreAmp < 0x20) ? 0x20 : m_nSongPreAmp) | 0x80; // Stereo 478 header[0x35] = 0xFC; 479 for (i=0; i<32; i++) 480 { 481 if (i < m_nChannels) 482 { 483 UINT tmp = (i & 0x0F) >> 1; 484 header[0x40+i] = (i & 0x10) | ((i & 1) ? 8+tmp : tmp); 485 } else header[0x40+i] = 0xFF; 486 } 487 fwrite(header, 0x60, 1, f); 488 fwrite(Order, nbo, 1, f); 489 memset(patptr, 0, sizeof(patptr)); 490 memset(insptr, 0, sizeof(insptr)); 491 UINT ofs0 = 0x60 + nbo; 492 UINT ofs1 = ((0x60 + nbo + nbi*2 + nbp*2 + 15) & 0xFFF0) + 0x20; 493 UINT ofs = ofs1; 494 495 for (i=0; i<nbi; i++) insptr[i] = (WORD)((ofs + i*0x50) / 16); 496 for (i=0; i<nbp; i++) patptr[i] = (WORD)((ofs + nbi*0x50) / 16); 497 fwrite(insptr, nbi, 2, f); 498 fwrite(patptr, nbp, 2, f); 499 if (header[0x35] == 0xFC) 500 { 501 BYTE chnpan[32]; 502 for (i=0; i<32; i++) 503 { 504 chnpan[i] = 0x20 | (ChnSettings[i].nPan >> 4); 505 } 506 fwrite(chnpan, 0x20, 1, f); 507 } 508 if ((nbi*2+nbp*2) & 0x0F) 509 { 510 fwrite(S3MFiller, 0x10 - ((nbi*2+nbp*2) & 0x0F), 1, f); 511 } 512 ofs1 = ftell(f); 513 fwrite(insex, nbi, 0x50, f); 514 // Packing patterns 515 ofs += nbi*0x50; 516 for (i=0; i<nbp; i++) 517 { 518 WORD len = 64; 519 memset(buffer, 0, sizeof(buffer)); 520 patptr[i] = ofs / 16; 521 if (Patterns[i]) 522 { 523 len = 2; 524 MODCOMMAND *p = Patterns[i]; 525 for (int row=0; row<64; row++) if (row < PatternSize[i]) 526 { 527 for (UINT j=0; j<m_nChannels; j++) 528 { 529 UINT b = j; 530 MODCOMMAND *m = &p[row*m_nChannels+j]; 531 UINT note = m->note; 532 UINT volcmd = m->volcmd; 533 UINT vol = m->vol; 534 UINT command = m->command; 535 UINT param = m->param; 536 537 if ((note) || (m->instr)) b |= 0x20; 538 if (!note) note = 0xFF; else 539 if (note >= 0xFE) note = 0xFE; else 540 if (note < 13) note = 0; else note -= 13; 541 if (note < 0xFE) note = (note % 12) + ((note / 12) << 4); 542 if (command == CMD_VOLUME) 543 { 544 command = 0; 545 if (param > 64) param = 64; 546 volcmd = VOLCMD_VOLUME; 547 vol = param; 548 } 549 if (volcmd == VOLCMD_VOLUME) b |= 0x40; else 550 if (volcmd == VOLCMD_PANNING) { vol |= 0x80; b |= 0x40; } 551 if (command) 552 { 553 S3MSaveConvert(&command, ¶m, FALSE); 554 if (command) b |= 0x80; 555 } 556 if (b & 0xE0) 557 { 558 buffer[len++] = b; 559 if (b & 0x20) 560 { 561 buffer[len++] = note; 562 buffer[len++] = m->instr; 563 } 564 if (b & 0x40) 565 { 566 buffer[len++] = vol; 567 } 568 if (b & 0x80) 569 { 570 buffer[len++] = command; 571 buffer[len++] = param; 572 } 573 if (len > sizeof(buffer) - 20) break; 574 } 575 } 576 buffer[len++] = 0; 577 if (len > sizeof(buffer) - 20) break; 578 } 579 } 580 buffer[0] = (len - 2) & 0xFF; 581 buffer[1] = (len - 2) >> 8; 582 len = (len+15) & (~0x0F); 583 fwrite(buffer, len, 1, f); 584 ofs += len; 585 } 586 // Writing samples 587 for (i=1; i<=nbi; i++) 588 { 589 MODINSTRUMENT *pins = &Ins[i]; 590 if (m_nInstruments) 591 { 592 pins = Ins; 593 if (Headers[i]) 594 { 595 for (UINT j=0; j<128; j++) 596 { 597 UINT n = Headers[i]->Keyboard[j]; 598 if ((n) && (n < MAX_INSTRUMENTS)) 599 { 600 pins = &Ins[n]; 601 break; 602 } 603 } 604 } 605 } 606 memcpy(insex[i-1].dosname, pins->name, 12); 607 memcpy(insex[i-1].name, m_szNames[i], 28); 608 memcpy(insex[i-1].scrs, "SCRS", 4); 609 insex[i-1].hmem = (BYTE)((DWORD)ofs >> 20); 610 insex[i-1].memseg = (WORD)((DWORD)ofs >> 4); 611 if (pins->pSample) 612 { 613 insex[i-1].type = 1; 614 insex[i-1].length = pins->nLength; 615 insex[i-1].loopbegin = pins->nLoopStart; 616 insex[i-1].loopend = pins->nLoopEnd; 617 insex[i-1].vol = pins->nVolume / 4; 618 insex[i-1].flags = (pins->uFlags & CHN_LOOP) ? 1 : 0; 619 if (pins->nC4Speed) 620 insex[i-1].finetune = pins->nC4Speed; 621 else 622 insex[i-1].finetune = TransposeToFrequency(pins->RelativeTone, pins->nFineTune); 623 UINT flags = RS_PCM8U; 624 #ifndef NO_PACKING 625 if (nPacking) 626 { 627 if ((!(pins->uFlags & (CHN_16BIT|CHN_STEREO))) 628 && (CanPackSample((char *)pins->pSample, pins->nLength, nPacking))) 629 { 630 insex[i-1].pack = 4; 631 flags = RS_ADPCM4; 632 } 633 } else 634 #endif // NO_PACKING 635 { 636 if (pins->uFlags & CHN_16BIT) 637 { 638 insex[i-1].flags |= 4; 639 flags = RS_PCM16U; 640 } 641 if (pins->uFlags & CHN_STEREO) 642 { 643 insex[i-1].flags |= 2; 644 flags = (pins->uFlags & CHN_16BIT) ? RS_STPCM16U : RS_STPCM8U; 645 } 646 } 647 DWORD len = WriteSample(f, pins, flags); 648 if (len & 0x0F) 649 { 650 fwrite(S3MFiller, 0x10 - (len & 0x0F), 1, f); 651 } 652 ofs += (len + 15) & (~0x0F); 653 } else 654 { 655 insex[i-1].length = 0; 656 } 657 } 658 // Updating parapointers 659 fseek(f, ofs0, SEEK_SET); 660 fwrite(insptr, nbi, 2, f); 661 fwrite(patptr, nbp, 2, f); 662 fseek(f, ofs1, SEEK_SET); 663 fwrite(insex, 0x50, nbi, f); 664 fclose(f); 665 return TRUE; 666 } 667 668 #ifdef _MSC_VER 669 #pragma warning(default:4100) 670 #endif 671 672 #endif // MODPLUG_NO_FILESAVE 673