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

load_xm.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 
00015 // FastTracker II XM file support
00016 
00017 #ifdef WIN32
00018 #pragma warning(disable:4244)
00019 #endif
00020 
00021 #pragma pack(1)
00022 typedef struct tagXMFILEHEADER
00023 {
00024         DWORD size;
00025         WORD norder;
00026         WORD restartpos;
00027         WORD channels;
00028         WORD patterns;
00029         WORD instruments;
00030         WORD flags;
00031         WORD speed;
00032         WORD tempo;
00033         BYTE order[256];
00034 } Q_PACKED XMFILEHEADER;
00035 
00036 
00037 typedef struct tagXMINSTRUMENTHEADER
00038 {
00039         DWORD size;
00040         CHAR name[22];
00041         BYTE type;
00042         BYTE samples;
00043         BYTE samplesh;
00044 } Q_PACKED XMINSTRUMENTHEADER;
00045 
00046 
00047 typedef struct tagXMSAMPLEHEADER
00048 {
00049         DWORD shsize;
00050         BYTE snum[96];
00051         WORD venv[24];
00052         WORD penv[24];
00053         BYTE vnum, pnum;
00054         BYTE vsustain, vloops, vloope, psustain, ploops, ploope;
00055         BYTE vtype, ptype;
00056         BYTE vibtype, vibsweep, vibdepth, vibrate;
00057         WORD volfade;
00058         WORD res;
00059         BYTE reserved1[20];
00060 } Q_PACKED XMSAMPLEHEADER;
00061 
00062 typedef struct tagXMSAMPLESTRUCT
00063 {
00064         DWORD samplen;
00065         DWORD loopstart;
00066         DWORD looplen;
00067         BYTE vol;
00068         signed char finetune;
00069         BYTE type;
00070         BYTE pan;
00071         signed char relnote;
00072         BYTE res;
00073         char name[22];
00074 } Q_PACKED XMSAMPLESTRUCT;
00075 
00076 typedef struct tagXMPATTERNHEADER
00077 {
00078     DWORD size;
00079     BYTE packing;
00080     WORD rows;
00081     WORD packsize;
00082 } Q_PACKED XMPATTERNHEADER;
00083 
00084 #pragma pack()
00085 
00086 
00087 BOOL CSoundFile::ReadXM(const BYTE *lpStream, DWORD dwMemLength)
00088 //--------------------------------------------------------------
00089 {
00090         XMSAMPLEHEADER xmsh;
00091         XMSAMPLESTRUCT xmss;
00092         DWORD dwMemPos, dwHdrSize;
00093         WORD norders=0, restartpos=0, channels=0, patterns=0, instruments=0;
00094         WORD xmflags=0, deftempo=125, defspeed=6;
00095         BOOL InstUsed[256];
00096         BYTE channels_used[MAX_CHANNELS];
00097         BYTE pattern_map[256];
00098         BOOL samples_used[MAX_SAMPLES];
00099         UINT unused_samples;
00100 
00101         m_nChannels = 0;
00102         if ((!lpStream) || (dwMemLength < 0x200)) return FALSE;
00103         if (strnicmp((LPCSTR)lpStream, "Extended Module", 15)) return FALSE;
00104 
00105         memcpy(m_szNames[0], lpStream+17, 20);
00106         dwHdrSize = bswapLE32(*((DWORD *)(lpStream+60)));
00107         norders = bswapLE16(*((WORD *)(lpStream+64)));
00108         if ((!norders) || (norders > MAX_ORDERS)) return FALSE;
00109         restartpos = bswapLE16(*((WORD *)(lpStream+66)));
00110         channels = bswapLE16(*((WORD *)(lpStream+68)));
00111         if ((!channels) || (channels > 64)) return FALSE;
00112         m_nType = MOD_TYPE_XM;
00113         m_nMinPeriod = 27;
00114         m_nMaxPeriod = 54784;
00115         m_nChannels = channels;
00116         if (restartpos < norders) m_nRestartPos = restartpos;
00117         patterns = bswapLE16(*((WORD *)(lpStream+70)));
00118         if (patterns > 256) patterns = 256;
00119         instruments = bswapLE16(*((WORD *)(lpStream+72)));
00120         if (instruments >= MAX_INSTRUMENTS) instruments = MAX_INSTRUMENTS-1;
00121         m_nInstruments = instruments;
00122         m_nSamples = 0;
00123         memcpy(&xmflags, lpStream+74, 2);
00124         xmflags = bswapLE16(xmflags);
00125         if (xmflags & 1) m_dwSongFlags |= SONG_LINEARSLIDES;
00126         if (xmflags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE;
00127         defspeed = bswapLE16(*((WORD *)(lpStream+76)));
00128         deftempo = bswapLE16(*((WORD *)(lpStream+78)));
00129         if ((deftempo >= 32) && (deftempo < 256)) m_nDefaultTempo = deftempo;
00130         if ((defspeed > 0) && (defspeed < 40)) m_nDefaultSpeed = defspeed;
00131         memcpy(Order, lpStream+80, norders);
00132         memset(InstUsed, 0, sizeof(InstUsed));
00133         if (patterns > MAX_PATTERNS)
00134         {
00135                 UINT i, j;
00136                 for (i=0; i<norders; i++)
00137                 {
00138                         if (Order[i] < patterns) InstUsed[Order[i]] = TRUE;
00139                 }
00140                 j = 0;
00141                 for (i=0; i<256; i++)
00142                 {
00143                         if (InstUsed[i]) pattern_map[i] = j++;
00144                 }
00145                 for (i=0; i<256; i++)
00146                 {
00147                         if (!InstUsed[i])
00148                         {
00149                                 pattern_map[i] = (j < MAX_PATTERNS) ? j : 0xFE;
00150                                 j++;
00151                         }
00152                 }
00153                 for (i=0; i<norders; i++)
00154                 {
00155                         Order[i] = pattern_map[Order[i]];
00156                 }
00157         } else
00158         {
00159                 for (UINT i=0; i<256; i++) pattern_map[i] = i;
00160         }
00161         memset(InstUsed, 0, sizeof(InstUsed));
00162         dwMemPos = dwHdrSize + 60;
00163         if (dwMemPos + 8 >= dwMemLength) return TRUE;
00164         // Reading patterns
00165         memset(channels_used, 0, sizeof(channels_used));
00166         for (UINT ipat=0; ipat<patterns; ipat++)
00167         {
00168                 UINT ipatmap = pattern_map[ipat];
00169                 DWORD dwSize = 0;
00170                 WORD rows=64, packsize=0;
00171                 XMPATTERNHEADER *patternHeader = (XMPATTERNHEADER *)(lpStream+dwMemPos);
00172                 //dwSize = bswapLE32(*((DWORD *)(lpStream+dwMemPos)));
00173                 dwSize = bswapLE32(patternHeader->size);
00174                 /*
00175                 while ((dwMemPos + dwSize >= dwMemLength) || (dwSize & 0xFFFFFF00))
00176                 {
00177                         if (dwMemPos + 4 >= dwMemLength) break;
00178                         dwMemPos++;
00179                         dwSize = bswapLE32(*((DWORD *)(lpStream+dwMemPos)));
00180                 }
00181                 */
00182                 //rows = bswapLE16(*((WORD *)(lpStream+dwMemPos+5)));
00183                 rows = bswapLE16(patternHeader->rows);
00184                 if ((!rows) || (rows > 256)) rows = 64;
00185                 //packsize = bswapLE16(*((WORD *)(lpStream+dwMemPos+7)));
00186                 packsize = bswapLE16(patternHeader->packsize);
00187                 if (dwMemPos + dwSize + 4 > dwMemLength) return TRUE;
00188                 dwMemPos += dwSize;
00189                 if (dwMemPos + packsize + 4 > dwMemLength) return TRUE;
00190                 MODCOMMAND *p;
00191                 if (ipatmap < MAX_PATTERNS)
00192                 {
00193                         PatternSize[ipatmap] = rows;
00194                         if ((Patterns[ipatmap] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
00195                         if (!packsize) continue;
00196                         p = Patterns[ipatmap];
00197                 } else p = NULL;
00198                 const BYTE *src = lpStream+dwMemPos;
00199                 UINT j=0;
00200                 for (UINT row=0; row<rows; row++)
00201                 {
00202                         for (UINT chn=0; chn<m_nChannels; chn++)
00203                         {
00204                                 if ((p) && (j < packsize))
00205                                 {
00206                                         BYTE b = src[j++];
00207                                         UINT vol = 0;
00208                                         if (b & 0x80)
00209                                         {
00210                                                 if (b & 1) p->note = src[j++];
00211                                                 if (b & 2) p->instr = src[j++];
00212                                                 if (b & 4) vol = src[j++];
00213                                                 if (b & 8) p->command = src[j++];
00214                                                 if (b & 16) p->param = src[j++];
00215                                         } else
00216                                         {
00217                                                 p->note = b;
00218                                                 p->instr = src[j++];
00219                                                 vol = src[j++];
00220                                                 p->command = src[j++];
00221                                                 p->param = src[j++];
00222                                         }
00223                                         if (p->note == 97) p->note = 0xFF; else
00224                                         if ((p->note) && (p->note < 97)) p->note += 12;
00225                                         if (p->note) channels_used[chn] = 1;
00226                                         if (p->command | p->param) ConvertModCommand(p);
00227                                         if (p->instr == 0xff) p->instr = 0;
00228                                         if (p->instr) InstUsed[p->instr] = TRUE;
00229                                         if ((vol >= 0x10) && (vol <= 0x50))
00230                                         {
00231                                                 p->volcmd = VOLCMD_VOLUME;
00232                                                 p->vol = vol - 0x10;
00233                                         } else
00234                                         if (vol >= 0x60)
00235                                         {
00236                                                 UINT v = vol & 0xF0;
00237                                                 vol &= 0x0F;
00238                                                 p->vol = vol;
00239                                                 switch(v)
00240                                                 {
00241                                                 // 60-6F: Volume Slide Down
00242                                                 case 0x60:      p->volcmd = VOLCMD_VOLSLIDEDOWN; break;
00243                                                 // 70-7F: Volume Slide Up:
00244                                                 case 0x70:      p->volcmd = VOLCMD_VOLSLIDEUP; break;
00245                                                 // 80-8F: Fine Volume Slide Down
00246                                                 case 0x80:      p->volcmd = VOLCMD_FINEVOLDOWN; break;
00247                                                 // 90-9F: Fine Volume Slide Up
00248                                                 case 0x90:      p->volcmd = VOLCMD_FINEVOLUP; break;
00249                                                 // A0-AF: Set Vibrato Speed
00250                                                 case 0xA0:      p->volcmd = VOLCMD_VIBRATOSPEED; break;
00251                                                 // B0-BF: Vibrato
00252                                                 case 0xB0:      p->volcmd = VOLCMD_VIBRATO; break;
00253                                                 // C0-CF: Set Panning
00254                                                 case 0xC0:      p->volcmd = VOLCMD_PANNING; p->vol = (vol << 2) + 2; break;
00255                                                 // D0-DF: Panning Slide Left
00256                                                 case 0xD0:      p->volcmd = VOLCMD_PANSLIDELEFT; break;
00257                                                 // E0-EF: Panning Slide Right
00258                                                 case 0xE0:      p->volcmd = VOLCMD_PANSLIDERIGHT; break;
00259                                                 // F0-FF: Tone Portamento
00260                                                 case 0xF0:      p->volcmd = VOLCMD_TONEPORTAMENTO; break;
00261                                                 }
00262                                         }
00263                                         p++;
00264                                 } else
00265                                 if (j < packsize)
00266                                 {
00267                                         BYTE b = src[j++];
00268                                         if (b & 0x80)
00269                                         {
00270                                                 if (b & 1) j++;
00271                                                 if (b & 2) j++;
00272                                                 if (b & 4) j++;
00273                                                 if (b & 8) j++;
00274                                                 if (b & 16) j++;
00275                                         } else j += 4;
00276                                 } else break;
00277                         }
00278                 }
00279                 dwMemPos += packsize;
00280         }
00281         /*
00282         // Wrong offset check
00283         while (dwMemPos + 4 < dwMemLength)
00284         {
00285                 DWORD d = bswapLE32(*((DWORD *)(lpStream+dwMemPos)));
00286                 if (d < 0x300) break;
00287                 dwMemPos++;
00288         }
00289         */
00290         memset(samples_used, 0, sizeof(samples_used));
00291         unused_samples = 0;
00292         // Reading instruments
00293         for (UINT iIns=1; iIns<=instruments; iIns++)
00294         {
00295                 XMINSTRUMENTHEADER *pih;
00296                 BYTE flags[32];
00297                 DWORD samplesize[32];
00298                 UINT samplemap[32];
00299                 WORD nsamples;
00300                                 
00301                 if (dwMemPos + sizeof(XMINSTRUMENTHEADER) >= dwMemLength) return TRUE;
00302                 pih = (XMINSTRUMENTHEADER *)(lpStream+dwMemPos);
00303                 if (dwMemPos + bswapLE32(pih->size) > dwMemLength) return TRUE;
00304                 if ((Headers[iIns] = new INSTRUMENTHEADER) == NULL) continue;
00305                 memset(Headers[iIns], 0, sizeof(INSTRUMENTHEADER));
00306                 memcpy(Headers[iIns]->name, pih->name, 22);
00307                 if ((nsamples = pih->samples) > 0)
00308                 {
00309                         if (dwMemPos + sizeof(XMSAMPLEHEADER) > dwMemLength) return TRUE;
00310                         memcpy(&xmsh, lpStream+dwMemPos+sizeof(XMINSTRUMENTHEADER), sizeof(XMSAMPLEHEADER));
00311                         xmsh.shsize = bswapLE32(xmsh.shsize);
00312                         for (int i = 0; i < 24; ++i) {
00313                           xmsh.venv[i] = bswapLE16(xmsh.venv[i]);
00314                           xmsh.penv[i] = bswapLE16(xmsh.penv[i]);
00315                         }
00316                         xmsh.volfade = bswapLE16(xmsh.volfade);
00317                         xmsh.res = bswapLE16(xmsh.res);
00318                         dwMemPos += bswapLE32(pih->size);
00319                 } else
00320                 {
00321                         if (bswapLE32(pih->size)) dwMemPos += bswapLE32(pih->size);
00322                         else dwMemPos += sizeof(XMINSTRUMENTHEADER);
00323                         continue;
00324                 }
00325                 memset(samplemap, 0, sizeof(samplemap));
00326                 if (nsamples > 32) return TRUE;
00327                 UINT newsamples = m_nSamples;
00328                 for (UINT nmap=0; nmap<nsamples; nmap++)
00329                 {
00330                         UINT n = m_nSamples+nmap+1;
00331                         if (n >= MAX_SAMPLES)
00332                         {
00333                                 n = m_nSamples;
00334                                 while (n > 0)
00335                                 {
00336                                         if (!Ins[n].pSample)
00337                                         {
00338                                                 for (UINT xmapchk=0; xmapchk < nmap; xmapchk++)
00339                                                 {
00340                                                         if (samplemap[xmapchk] == n) goto alreadymapped;
00341                                                 }
00342                                                 for (UINT clrs=1; clrs<iIns; clrs++) if (Headers[clrs])
00343                                                 {
00344                                                         INSTRUMENTHEADER *pks = Headers[clrs];
00345                                                         for (UINT ks=0; ks<128; ks++)
00346                                                         {
00347                                                                 if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0;
00348                                                         }
00349                                                 }
00350                                                 break;
00351                                         }
00352                                 alreadymapped:
00353                                         n--;
00354                                 }
00355 #ifndef FASTSOUNDLIB
00356                                 // Damn! more than 200 samples: look for duplicates
00357                                 if (!n)
00358                                 {
00359                                         if (!unused_samples)
00360                                         {
00361                                                 unused_samples = DetectUnusedSamples(samples_used);
00362                                                 if (!unused_samples) unused_samples = 0xFFFF;
00363                                         }
00364                                         if ((unused_samples) && (unused_samples != 0xFFFF))
00365                                         {
00366                                                 for (UINT iext=m_nSamples; iext>=1; iext--) if (!samples_used[iext])
00367                                                 {
00368                                                         unused_samples--;
00369                                                         samples_used[iext] = TRUE;
00370                                                         DestroySample(iext);
00371                                                         n = iext;
00372                                                         for (UINT mapchk=0; mapchk<nmap; mapchk++)
00373                                                         {
00374                                                                 if (samplemap[mapchk] == n) samplemap[mapchk] = 0;
00375                                                         }
00376                                                         for (UINT clrs=1; clrs<iIns; clrs++) if (Headers[clrs])
00377                                                         {
00378                                                                 INSTRUMENTHEADER *pks = Headers[clrs];
00379                                                                 for (UINT ks=0; ks<128; ks++)
00380                                                                 {
00381                                                                         if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0;
00382                                                                 }
00383                                                         }
00384                                                         memset(&Ins[n], 0, sizeof(Ins[0]));
00385                                                         break;
00386                                                 }
00387                                         }
00388                                 }
00389 #endif // FASTSOUNDLIB
00390                         }
00391                         if (newsamples < n) newsamples = n;
00392                         samplemap[nmap] = n;
00393                 }
00394                 m_nSamples = newsamples;
00395                 // Reading Volume Envelope
00396                 INSTRUMENTHEADER *penv = Headers[iIns];
00397                 penv->nMidiProgram = pih->type;
00398                 penv->nFadeOut = xmsh.volfade;
00399                 penv->nPan = 128;
00400                 penv->nPPC = 5*12;
00401                 if (xmsh.vtype & 1) penv->dwFlags |= ENV_VOLUME;
00402                 if (xmsh.vtype & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
00403                 if (xmsh.vtype & 4) penv->dwFlags |= ENV_VOLLOOP;
00404                 if (xmsh.ptype & 1) penv->dwFlags |= ENV_PANNING;
00405                 if (xmsh.ptype & 2) penv->dwFlags |= ENV_PANSUSTAIN;
00406                 if (xmsh.ptype & 4) penv->dwFlags |= ENV_PANLOOP;
00407                 if (xmsh.vnum > 12) xmsh.vnum = 12;
00408                 if (xmsh.pnum > 12) xmsh.pnum = 12;
00409                 penv->nVolEnv = xmsh.vnum;
00410                 if (!xmsh.vnum) penv->dwFlags &= ~ENV_VOLUME;
00411                 if (!xmsh.pnum) penv->dwFlags &= ~ENV_PANNING;
00412                 penv->nPanEnv = xmsh.pnum;
00413                 penv->nVolSustainBegin = penv->nVolSustainEnd = xmsh.vsustain;
00414                 if (xmsh.vsustain >= 12) penv->dwFlags &= ~ENV_VOLSUSTAIN;
00415                 penv->nVolLoopStart = xmsh.vloops;
00416                 penv->nVolLoopEnd = xmsh.vloope;
00417                 if (penv->nVolLoopEnd >= 12) penv->nVolLoopEnd = 0;
00418                 if (penv->nVolLoopStart >= penv->nVolLoopEnd) penv->dwFlags &= ~ENV_VOLLOOP;
00419                 penv->nPanSustainBegin = penv->nPanSustainEnd = xmsh.psustain;
00420                 if (xmsh.psustain >= 12) penv->dwFlags &= ~ENV_PANSUSTAIN;
00421                 penv->nPanLoopStart = xmsh.ploops;
00422                 penv->nPanLoopEnd = xmsh.ploope;
00423                 if (penv->nPanLoopEnd >= 12) penv->nPanLoopEnd = 0;
00424                 if (penv->nPanLoopStart >= penv->nPanLoopEnd) penv->dwFlags &= ~ENV_PANLOOP;
00425                 penv->nGlobalVol = 64;
00426                 for (UINT ienv=0; ienv<12; ienv++)
00427                 {
00428                         penv->VolPoints[ienv] = (WORD)xmsh.venv[ienv*2];
00429                         penv->VolEnv[ienv] = (BYTE)xmsh.venv[ienv*2+1];
00430                         penv->PanPoints[ienv] = (WORD)xmsh.penv[ienv*2];
00431                         penv->PanEnv[ienv] = (BYTE)xmsh.penv[ienv*2+1];
00432                         if (ienv)
00433                         {
00434                                 if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1])
00435                                 {
00436                                         penv->VolPoints[ienv] &= 0xFF;
00437                                         penv->VolPoints[ienv] += penv->VolPoints[ienv-1] & 0xFF00;
00438                                         if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1]) penv->VolPoints[ienv] += 0x100;
00439                                 }
00440                                 if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1])
00441                                 {
00442                                         penv->PanPoints[ienv] &= 0xFF;
00443                                         penv->PanPoints[ienv] += penv->PanPoints[ienv-1] & 0xFF00;
00444                                         if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1]) penv->PanPoints[ienv] += 0x100;
00445                                 }
00446                         }
00447                 }
00448                 for (UINT j=0; j<96; j++)
00449                 {
00450                         penv->NoteMap[j+12] = j+1+12;
00451                         if (xmsh.snum[j] < nsamples)
00452                                 penv->Keyboard[j+12] = samplemap[xmsh.snum[j]];
00453                 }
00454                 // Reading samples
00455                 for (UINT ins=0; ins<nsamples; ins++)
00456                 {
00457                         if ((dwMemPos + sizeof(xmss) > dwMemLength)
00458                          || (dwMemPos + xmsh.shsize > dwMemLength)) return TRUE;
00459                         memcpy(&xmss, lpStream+dwMemPos, sizeof(xmss));
00460                         xmss.samplen = bswapLE32(xmss.samplen);
00461                         xmss.loopstart = bswapLE32(xmss.loopstart);
00462                         xmss.looplen = bswapLE32(xmss.looplen);
00463                         dwMemPos += xmsh.shsize;
00464                         flags[ins] = (xmss.type & 0x10) ? RS_PCM16D : RS_PCM8D;
00465                         if (xmss.type & 0x20) flags[ins] = (xmss.type & 0x10) ? RS_STPCM16D : RS_STPCM8D;
00466                         samplesize[ins] = xmss.samplen;
00467                         if (!samplemap[ins]) continue;
00468                         if (xmss.type & 0x10)
00469                         {
00470                                 xmss.looplen >>= 1;
00471                                 xmss.loopstart >>= 1;
00472                                 xmss.samplen >>= 1;
00473                         }
00474                         if (xmss.type & 0x20)
00475                         {
00476                                 xmss.looplen >>= 1;
00477                                 xmss.loopstart >>= 1;
00478                                 xmss.samplen >>= 1;
00479                         }
00480                         if (xmss.samplen > MAX_SAMPLE_LENGTH) xmss.samplen = MAX_SAMPLE_LENGTH;
00481                         if (xmss.loopstart >= xmss.samplen) xmss.type &= ~3;
00482                         xmss.looplen += xmss.loopstart;
00483                         if (xmss.looplen > xmss.samplen) xmss.looplen = xmss.samplen;
00484                         if (!xmss.looplen) xmss.type &= ~3;
00485                         UINT imapsmp = samplemap[ins];
00486                         memcpy(m_szNames[imapsmp], xmss.name, 22);
00487                         m_szNames[imapsmp][22] = 0;
00488                         MODINSTRUMENT *pins = &Ins[imapsmp];
00489                         pins->nLength = (xmss.samplen > MAX_SAMPLE_LENGTH) ? MAX_SAMPLE_LENGTH : xmss.samplen;
00490                         pins->nLoopStart = xmss.loopstart;
00491                         pins->nLoopEnd = xmss.looplen;
00492                         if (pins->nLoopEnd > pins->nLength) pins->nLoopEnd = pins->nLength;
00493                         if (pins->nLoopStart >= pins->nLoopEnd)
00494                         {
00495                                 pins->nLoopStart = pins->nLoopEnd = 0;
00496                         }
00497                         if (xmss.type & 3) pins->uFlags |= CHN_LOOP;
00498                         if (xmss.type & 2) pins->uFlags |= CHN_PINGPONGLOOP;
00499                         pins->nVolume = xmss.vol << 2;
00500                         if (pins->nVolume > 256) pins->nVolume = 256;
00501                         pins->nGlobalVol = 64;
00502                         if ((xmss.res == 0xAD) && (!(xmss.type & 0x30)))
00503                         {
00504                                 flags[ins] = RS_ADPCM4;
00505                                 samplesize[ins] = (samplesize[ins]+1)/2 + 16;
00506                         }
00507                         pins->nFineTune = xmss.finetune;
00508                         pins->RelativeTone = (int)xmss.relnote;
00509                         pins->nPan = xmss.pan;
00510                         pins->uFlags |= CHN_PANNING;
00511                         pins->nVibType = xmsh.vibtype;
00512                         pins->nVibSweep = xmsh.vibsweep;
00513                         pins->nVibDepth = xmsh.vibdepth;
00514                         pins->nVibRate = xmsh.vibrate;
00515                         memcpy(pins->name, xmss.name, 22);
00516                         pins->name[21] = 0;
00517                 }
00518 #if 0
00519                 if ((xmsh.reserved2 > nsamples) && (xmsh.reserved2 <= 16))
00520                 {
00521                         dwMemPos += (((UINT)xmsh.reserved2) - nsamples) * xmsh.shsize;
00522                 }
00523 #endif
00524                 for (UINT ismpd=0; ismpd<nsamples; ismpd++)
00525                 {
00526                         if ((samplemap[ismpd]) && (samplesize[ismpd]) && (dwMemPos < dwMemLength))
00527                         {
00528                                 ReadSample(&Ins[samplemap[ismpd]], flags[ismpd], (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
00529                         }
00530                         dwMemPos += samplesize[ismpd];
00531                         if (dwMemPos >= dwMemLength) break;
00532                 }
00533         }
00534         // Read song comments: "TEXT"
00535         if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x74786574))
00536         {
00537                 UINT len = *((DWORD *)(lpStream+dwMemPos+4));
00538                 dwMemPos += 8;
00539                 if ((dwMemPos + len <= dwMemLength) && (len < 16384))
00540                 {
00541                         m_lpszSongComments = new char[len+1];
00542                         if (m_lpszSongComments)
00543                         {
00544                                 memcpy(m_lpszSongComments, lpStream+dwMemPos, len);
00545                                 m_lpszSongComments[len] = 0;
00546                         }
00547                         dwMemPos += len;
00548                 }
00549         }
00550         // Read midi config: "MIDI"
00551         if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4944494D))
00552         {
00553                 UINT len = *((DWORD *)(lpStream+dwMemPos+4));
00554                 dwMemPos += 8;
00555                 if (len == sizeof(MODMIDICFG))
00556                 {
00557                         memcpy(&m_MidiCfg, lpStream+dwMemPos, len);
00558                         m_dwSongFlags |= SONG_EMBEDMIDICFG;
00559                 }
00560         }
00561         // Read pattern names: "PNAM"
00562         if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e50))
00563         {
00564                 UINT len = *((DWORD *)(lpStream+dwMemPos+4));
00565                 dwMemPos += 8;
00566                 if ((dwMemPos + len <= dwMemLength) && (len <= MAX_PATTERNS*MAX_PATTERNNAME) && (len >= MAX_PATTERNNAME))
00567                 {
00568                         m_lpszPatternNames = new char[len];
00569 
00570                         if (m_lpszPatternNames)
00571                         {
00572                                 m_nPatternNames = len / MAX_PATTERNNAME;
00573                                 memcpy(m_lpszPatternNames, lpStream+dwMemPos, len);
00574                         }
00575                         dwMemPos += len;
00576                 }
00577         }
00578         // Read channel names: "CNAM"
00579         if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e43))
00580         {
00581                 UINT len = *((DWORD *)(lpStream+dwMemPos+4));
00582                 dwMemPos += 8;
00583                 if ((dwMemPos + len <= dwMemLength) && (len <= MAX_BASECHANNELS*MAX_CHANNELNAME))
00584                 {
00585                         UINT n = len / MAX_CHANNELNAME;
00586                         for (UINT i=0; i<n; i++)
00587                         {
00588                                 memcpy(ChnSettings[i].szName, (lpStream+dwMemPos+i*MAX_CHANNELNAME), MAX_CHANNELNAME);
00589                                 ChnSettings[i].szName[MAX_CHANNELNAME-1] = 0;
00590                         }
00591                         dwMemPos += len;
00592                 }
00593         }
00594         // Read mix plugins information
00595         if (dwMemPos + 8 < dwMemLength) 
00596         {
00597                 dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos);
00598         }
00599         return TRUE;
00600 }
00601 
00602 
00603 #ifndef MODPLUG_NO_FILESAVE
00604 
00605 BOOL CSoundFile::SaveXM(LPCSTR lpszFileName, UINT nPacking)
00606 //---------------------------------------------------------
00607 {
00608         BYTE s[64*64*5];
00609         XMFILEHEADER header;
00610         XMINSTRUMENTHEADER xmih;
00611         XMSAMPLEHEADER xmsh;
00612         XMSAMPLESTRUCT xmss;
00613         BYTE smptable[32];
00614         BYTE xmph[9];
00615         FILE *f;
00616         int i;
00617 
00618         if ((!m_nChannels) || (!lpszFileName)) return FALSE;
00619         if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
00620         fwrite("Extended Module: ", 17, 1, f);
00621         fwrite(m_szNames[0], 20, 1, f);
00622         s[0] = 0x1A;
00623         lstrcpy((LPSTR)&s[1], (nPacking) ? "MOD Plugin packed   " : "FastTracker v2.00   ");
00624         s[21] = 0x04;
00625         s[22] = 0x01;
00626         fwrite(s, 23, 1, f);
00627         // Writing song header
00628         memset(&header, 0, sizeof(header));
00629         header.size = sizeof(XMFILEHEADER);
00630         header.norder = 0;
00631         header.restartpos = m_nRestartPos;
00632         header.channels = m_nChannels;
00633         header.patterns = 0;
00634         for (i=0; i<MAX_ORDERS; i++)
00635         {
00636                 if (Order[i] == 0xFF) break;
00637                 header.norder++;
00638                 if ((Order[i] >= header.patterns) && (Order[i] < MAX_PATTERNS)) header.patterns = Order[i]+1;
00639         }
00640         header.instruments = m_nInstruments;
00641         if (!header.instruments) header.instruments = m_nSamples;
00642         header.flags = (m_dwSongFlags & SONG_LINEARSLIDES) ? 0x01 : 0x00;
00643         if (m_dwSongFlags & SONG_EXFILTERRANGE) header.flags |= 0x1000;
00644         header.tempo = m_nDefaultTempo;
00645         header.speed = m_nDefaultSpeed;
00646         memcpy(header.order, Order, header.norder);
00647         fwrite(&header, 1, sizeof(header), f);
00648         // Writing patterns
00649         for (i=0; i<header.patterns; i++) if (Patterns[i])
00650         {
00651                 MODCOMMAND *p = Patterns[i];
00652                 UINT len = 0;
00653 
00654                 memset(&xmph, 0, sizeof(xmph));
00655                 xmph[0] = 9;
00656                 xmph[5] = (BYTE)(PatternSize[i] & 0xFF);
00657                 xmph[6] = (BYTE)(PatternSize[i] >> 8);
00658                 for (UINT j=m_nChannels*PatternSize[i]; j; j--,p++)
00659                 {
00660                         UINT note = p->note;
00661                         UINT param = ModSaveCommand(p, TRUE);
00662                         UINT command = param >> 8;
00663                         param &= 0xFF;
00664                         if (note >= 0xFE) note = 97; else
00665                         if ((note <= 12) || (note > 96+12)) note = 0; else
00666                         note -= 12;
00667                         UINT vol = 0;
00668                         if (p->volcmd)
00669                         {
00670                                 UINT volcmd = p->volcmd;
00671                                 switch(volcmd)
00672                                 {
00673                                 case VOLCMD_VOLUME:                     vol = 0x10 + p->vol; break;
00674                                 case VOLCMD_VOLSLIDEDOWN:       vol = 0x60 + (p->vol & 0x0F); break;
00675                                 case VOLCMD_VOLSLIDEUP:         vol = 0x70 + (p->vol & 0x0F); break;
00676                                 case VOLCMD_FINEVOLDOWN:        vol = 0x80 + (p->vol & 0x0F); break;
00677                                 case VOLCMD_FINEVOLUP:          vol = 0x90 + (p->vol & 0x0F); break;
00678                                 case VOLCMD_VIBRATOSPEED:       vol = 0xA0 + (p->vol & 0x0F); break;
00679                                 case VOLCMD_VIBRATO:            vol = 0xB0 + (p->vol & 0x0F); break;
00680                                 case VOLCMD_PANNING:            vol = 0xC0 + (p->vol >> 2); if (vol > 0xCF) vol = 0xCF; break;
00681                                 case VOLCMD_PANSLIDELEFT:       vol = 0xD0 + (p->vol & 0x0F); break;
00682                                 case VOLCMD_PANSLIDERIGHT:      vol = 0xE0 + (p->vol & 0x0F); break;
00683                                 case VOLCMD_TONEPORTAMENTO:     vol = 0xF0 + (p->vol & 0x0F); break;
00684                                 }
00685                         }
00686                         if ((note) && (p->instr) && (vol > 0x0F) && (command) && (param))
00687                         {
00688                                 s[len++] = note;
00689                                 s[len++] = p->instr;
00690                                 s[len++] = vol;
00691                                 s[len++] = command;
00692                                 s[len++] = param;
00693                         } else
00694                         {
00695                                 BYTE b = 0x80;
00696                                 if (note) b |= 0x01;
00697                                 if (p->instr) b |= 0x02;
00698                                 if (vol >= 0x10) b |= 0x04;
00699                                 if (command) b |= 0x08;
00700                                 if (param) b |= 0x10;
00701                                 s[len++] = b;
00702                                 if (b & 1) s[len++] = note;
00703                                 if (b & 2) s[len++] = p->instr;
00704                                 if (b & 4) s[len++] = vol;
00705                                 if (b & 8) s[len++] = command;
00706                                 if (b & 16) s[len++] = param;
00707                         }
00708                         if (len > sizeof(s) - 5) break;
00709                 }
00710                 xmph[7] = (BYTE)(len & 0xFF);
00711                 xmph[8] = (BYTE)(len >> 8);
00712                 fwrite(xmph, 1, 9, f);
00713                 fwrite(s, 1, len, f);
00714         } else
00715         {
00716                 memset(&xmph, 0, sizeof(xmph));
00717                 xmph[0] = 9;
00718                 xmph[5] = (BYTE)(PatternSize[i] & 0xFF);
00719                 xmph[6] = (BYTE)(PatternSize[i] >> 8);
00720                 fwrite(xmph, 1, 9, f);
00721         }
00722         // Writing instruments
00723         for (i=1; i<=header.instruments; i++)
00724         {
00725                 MODINSTRUMENT *pins;
00726                 BYTE flags[32];
00727 
00728                 memset(&xmih, 0, sizeof(xmih));
00729                 memset(&xmsh, 0, sizeof(xmsh));
00730                 xmih.size = sizeof(xmih) + sizeof(xmsh);
00731                 memcpy(xmih.name, m_szNames[i], 22);
00732                 xmih.type = 0;
00733                 xmih.samples = 0;
00734                 if (m_nInstruments)
00735                 {
00736                         INSTRUMENTHEADER *penv = Headers[i];
00737                         if (penv)
00738                         {
00739                                 memcpy(xmih.name, penv->name, 22);
00740                                 xmih.type = penv->nMidiProgram;
00741                                 xmsh.volfade = penv->nFadeOut;
00742                                 xmsh.vnum = (BYTE)penv->nVolEnv;
00743                                 xmsh.pnum = (BYTE)penv->nPanEnv;
00744                                 if (xmsh.vnum > 12) xmsh.vnum = 12;
00745                                 if (xmsh.pnum > 12) xmsh.pnum = 12;
00746                                 for (UINT ienv=0; ienv<12; ienv++)
00747                                 {
00748                                         xmsh.venv[ienv*2] = penv->VolPoints[ienv];
00749                                         xmsh.venv[ienv*2+1] = penv->VolEnv[ienv];
00750                                         xmsh.penv[ienv*2] = penv->PanPoints[ienv];
00751                                         xmsh.penv[ienv*2+1] = penv->PanEnv[ienv];
00752                                 }
00753                                 if (penv->dwFlags & ENV_VOLUME) xmsh.vtype |= 1;
00754                                 if (penv->dwFlags & ENV_VOLSUSTAIN) xmsh.vtype |= 2;
00755                                 if (penv->dwFlags & ENV_VOLLOOP) xmsh.vtype |= 4;
00756                                 if (penv->dwFlags & ENV_PANNING) xmsh.ptype |= 1;
00757                                 if (penv->dwFlags & ENV_PANSUSTAIN) xmsh.ptype |= 2;
00758                                 if (penv->dwFlags & ENV_PANLOOP) xmsh.ptype |= 4;
00759                                 xmsh.vsustain = (BYTE)penv->nVolSustainBegin;
00760                                 xmsh.vloops = (BYTE)penv->nVolLoopStart;
00761                                 xmsh.vloope = (BYTE)penv->nVolLoopEnd;
00762                                 xmsh.psustain = (BYTE)penv->nPanSustainBegin;
00763                                 xmsh.ploops = (BYTE)penv->nPanLoopStart;
00764                                 xmsh.ploope = (BYTE)penv->nPanLoopEnd;
00765                                 for (UINT j=0; j<96; j++) if (penv->Keyboard[j+12])
00766                                 {
00767                                         UINT k;
00768                                         for (k=0; k<xmih.samples; k++)  if (smptable[k] == penv->Keyboard[j+12]) break;
00769                                         if (k == xmih.samples)
00770                                         {
00771                                                 smptable[xmih.samples++] = penv->Keyboard[j+12];
00772                                         }
00773                                         if (xmih.samples >= 32) break;
00774                                         xmsh.snum[j] = k;
00775                                 }
00776 //                              xmsh.reserved2 = xmih.samples;
00777                         }
00778                 } else
00779                 {
00780                         xmih.samples = 1;
00781 //                      xmsh.reserved2 = 1;
00782                         smptable[0] = i;
00783                 }
00784                 xmsh.shsize = (xmih.samples) ? 40 : 0;
00785                 fwrite(&xmih, 1, sizeof(xmih), f);
00786                 if (smptable[0])
00787                 {
00788                         MODINSTRUMENT *pvib = &Ins[smptable[0]];
00789                         xmsh.vibtype = pvib->nVibType;
00790                         xmsh.vibsweep = pvib->nVibSweep;
00791                         xmsh.vibdepth = pvib->nVibDepth;
00792                         xmsh.vibrate = pvib->nVibRate;
00793                 }
00794                 fwrite(&xmsh, 1, xmih.size - sizeof(xmih), f);
00795                 if (!xmih.samples) continue;
00796                 for (UINT ins=0; ins<xmih.samples; ins++)
00797                 {
00798                         memset(&xmss, 0, sizeof(xmss));
00799                         if (smptable[ins]) memcpy(xmss.name, m_szNames[smptable[ins]], 22);
00800                         pins = &Ins[smptable[ins]];
00801                         xmss.samplen = pins->nLength;
00802                         xmss.loopstart = pins->nLoopStart;
00803                         xmss.looplen = pins->nLoopEnd - pins->nLoopStart;
00804                         xmss.vol = pins->nVolume / 4;
00805                         xmss.finetune = (char)pins->nFineTune;
00806                         xmss.type = 0;
00807                         if (pins->uFlags & CHN_LOOP) xmss.type = (pins->uFlags & CHN_PINGPONGLOOP) ? 2 : 1;
00808                         flags[ins] = RS_PCM8D;
00809 #ifndef NO_PACKING
00810                         if (nPacking)
00811                         {
00812                                 if ((!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
00813                                  && (CanPackSample(pins->pSample, pins->nLength, nPacking)))
00814                                 {
00815                                         flags[ins] = RS_ADPCM4;
00816                                         xmss.res = 0xAD;
00817                                 }
00818                         } else
00819 #endif
00820                         {
00821                                 if (pins->uFlags & CHN_16BIT)
00822                                 {
00823                                         flags[ins] = RS_PCM16D;
00824                                         xmss.type |= 0x10;
00825                                         xmss.looplen *= 2;
00826                                         xmss.loopstart *= 2;
00827                                         xmss.samplen *= 2;
00828                                 }
00829                                 if (pins->uFlags & CHN_STEREO)
00830                                 {
00831                                         flags[ins] = (pins->uFlags & CHN_16BIT) ? RS_STPCM16D : RS_STPCM8D;
00832                                         xmss.type |= 0x20;
00833                                         xmss.looplen *= 2;
00834                                         xmss.loopstart *= 2;
00835                                         xmss.samplen *= 2;
00836                                 }
00837                         }
00838                         xmss.pan = 255;
00839                         if (pins->nPan < 256) xmss.pan = (BYTE)pins->nPan;
00840                         xmss.relnote = (signed char)pins->RelativeTone;
00841                         fwrite(&xmss, 1, xmsh.shsize, f);
00842                 }
00843                 for (UINT ismpd=0; ismpd<xmih.samples; ismpd++)
00844                 {
00845                         pins = &Ins[smptable[ismpd]];
00846                         if (pins->pSample)
00847                         {
00848 #ifndef NO_PACKING
00849                                 if ((flags[ismpd] == RS_ADPCM4) && (xmih.samples>1)) CanPackSample(pins->pSample, pins->nLength, nPacking);
00850 #endif // NO_PACKING
00851                                 WriteSample(f, pins, flags[ismpd]);
00852                         }
00853                 }
00854         }
00855         // Writing song comments
00856         if ((m_lpszSongComments) && (m_lpszSongComments[0]))
00857         {
00858                 DWORD d = 0x74786574;
00859                 fwrite(&d, 1, 4, f);
00860                 d = strlen(m_lpszSongComments);
00861                 fwrite(&d, 1, 4, f);
00862                 fwrite(m_lpszSongComments, 1, d, f);
00863         }
00864         // Writing midi cfg
00865         if (m_dwSongFlags & SONG_EMBEDMIDICFG)
00866         {
00867                 DWORD d = 0x4944494D;
00868                 fwrite(&d, 1, 4, f);
00869                 d = sizeof(MODMIDICFG);
00870                 fwrite(&d, 1, 4, f);
00871                 fwrite(&m_MidiCfg, 1, sizeof(MODMIDICFG), f);
00872         }
00873         // Writing Pattern Names
00874         if ((m_nPatternNames) && (m_lpszPatternNames))
00875         {
00876                 DWORD dwLen = m_nPatternNames * MAX_PATTERNNAME;
00877                 while ((dwLen >= MAX_PATTERNNAME) && (!m_lpszPatternNames[dwLen-MAX_PATTERNNAME])) dwLen -= MAX_PATTERNNAME;
00878                 if (dwLen >= MAX_PATTERNNAME)
00879                 {
00880                         DWORD d = 0x4d414e50;
00881                         fwrite(&d, 1, 4, f);
00882                         fwrite(&dwLen, 1, 4, f);
00883                         fwrite(m_lpszPatternNames, 1, dwLen, f);
00884                 }
00885         }
00886         // Writing Channel Names
00887         {
00888                 UINT nChnNames = 0;
00889                 for (UINT inam=0; inam<m_nChannels; inam++)
00890                 {
00891                         if (ChnSettings[inam].szName[0]) nChnNames = inam+1;
00892                 }
00893                 // Do it!
00894                 if (nChnNames)
00895                 {
00896                         DWORD dwLen = nChnNames * MAX_CHANNELNAME;
00897                         DWORD d = 0x4d414e43;
00898                         fwrite(&d, 1, 4, f);
00899                         fwrite(&dwLen, 1, 4, f);
00900                         for (UINT inam=0; inam<nChnNames; inam++)
00901                         {
00902                                 fwrite(ChnSettings[inam].szName, 1, MAX_CHANNELNAME, f);
00903                         }
00904                 }
00905         }
00906         // Save mix plugins information
00907         SaveMixPlugins(f);
00908         fclose(f);
00909         return TRUE;
00910 }
00911 
00912 #endif // MODPLUG_NO_FILESAVE

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