00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "stdafx.h"
00011 #include "sndfile.h"
00012
00013
00014
00015 #define ULT_16BIT 0x04
00016 #define ULT_LOOP 0x08
00017 #define ULT_BIDI 0x10
00018
00019 #pragma pack(1)
00020
00021
00022 typedef struct tagULTHEADER
00023 {
00024 char id[15];
00025 char songtitle[32];
00026 BYTE reserved;
00027 } Q_PACKED ULTHEADER;
00028
00029
00030
00031 typedef struct tagULTSAMPLE
00032 {
00033 CHAR samplename[32];
00034 CHAR dosname[12];
00035 LONG loopstart;
00036 LONG loopend;
00037 LONG sizestart;
00038 LONG sizeend;
00039 BYTE volume;
00040 BYTE flags;
00041 WORD finetune;
00042 } Q_PACKED ULTSAMPLE;
00043
00044 #pragma pack()
00045
00046
00047 BOOL CSoundFile::ReadUlt(const BYTE *lpStream, DWORD dwMemLength)
00048
00049 {
00050 ULTHEADER *pmh = (ULTHEADER *)lpStream;
00051 ULTSAMPLE *pus;
00052 UINT nos, nop;
00053 DWORD dwMemPos = 0;
00054
00055
00056 if ((!lpStream) || (dwMemLength < 0x100)) return FALSE;
00057 if (strncmp(pmh->id,"MAS_UTrack_V00",14)) return FALSE;
00058
00059
00060 m_nType = MOD_TYPE_ULT;
00061 m_nDefaultSpeed = 6;
00062 m_nDefaultTempo = 125;
00063 memcpy(m_szNames[0], pmh->songtitle, 32);
00064
00065 dwMemPos = sizeof(ULTHEADER);
00066 if ((pmh->reserved) && (dwMemPos + pmh->reserved * 32 < dwMemLength))
00067 {
00068 UINT len = pmh->reserved * 32;
00069 m_lpszSongComments = new char[len + 1 + pmh->reserved];
00070 if (m_lpszSongComments)
00071 {
00072 for (UINT l=0; l<pmh->reserved; l++)
00073 {
00074 memcpy(m_lpszSongComments+l*33, lpStream+dwMemPos+l*32, 32);
00075 m_lpszSongComments[l*33+32] = 0x0D;
00076 }
00077 m_lpszSongComments[len] = 0;
00078 }
00079 dwMemPos += len;
00080 }
00081 if (dwMemPos >= dwMemLength) return TRUE;
00082 nos = lpStream[dwMemPos++];
00083 m_nSamples = nos;
00084 if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
00085 UINT smpsize = 64;
00086 if (pmh->id[14] >= '4') smpsize += 2;
00087 if (dwMemPos + nos*smpsize + 256 + 2 > dwMemLength) return TRUE;
00088 for (UINT ins=1; ins<=nos; ins++, dwMemPos+=smpsize) if (ins<=m_nSamples)
00089 {
00090 pus = (ULTSAMPLE *)(lpStream+dwMemPos);
00091 MODINSTRUMENT *pins = &Ins[ins];
00092 memcpy(m_szNames[ins], pus->samplename, 32);
00093 memcpy(pins->name, pus->dosname, 12);
00094 pins->nLoopStart = pus->loopstart;
00095 pins->nLoopEnd = pus->loopend;
00096 pins->nLength = pus->sizeend - pus->sizestart;
00097 pins->nVolume = pus->volume;
00098 pins->nGlobalVol = 64;
00099 pins->nC4Speed = 8363;
00100 if (pmh->id[14] >= '4')
00101 {
00102 pins->nC4Speed = pus->finetune;
00103 }
00104 if (pus->flags & ULT_LOOP) pins->uFlags |= CHN_LOOP;
00105 if (pus->flags & ULT_BIDI) pins->uFlags |= CHN_PINGPONGLOOP;
00106 if (pus->flags & ULT_16BIT)
00107 {
00108 pins->uFlags |= CHN_16BIT;
00109 pins->nLoopStart >>= 1;
00110 pins->nLoopEnd >>= 1;
00111 }
00112 }
00113 memcpy(Order, lpStream+dwMemPos, 256);
00114 dwMemPos += 256;
00115 m_nChannels = lpStream[dwMemPos] + 1;
00116 nop = lpStream[dwMemPos+1] + 1;
00117 dwMemPos += 2;
00118 if (m_nChannels > 32) m_nChannels = 32;
00119
00120 for (UINT nSet=0; nSet<m_nChannels; nSet++)
00121 {
00122 ChnSettings[nSet].nVolume = 64;
00123 ChnSettings[nSet].nPan = (nSet & 1) ? 0x40 : 0xC0;
00124 }
00125
00126 if(pmh->id[14]>='3')
00127 {
00128 if (dwMemPos + m_nChannels > dwMemLength) return TRUE;
00129 for(UINT t=0; t<m_nChannels; t++)
00130 {
00131 ChnSettings[t].nPan = (lpStream[dwMemPos++] << 4) + 8;
00132 if (ChnSettings[t].nPan > 256) ChnSettings[t].nPan = 256;
00133 }
00134 }
00135
00136 for (UINT nAllocPat=0; nAllocPat<nop; nAllocPat++)
00137 {
00138 if (nAllocPat < MAX_PATTERNS)
00139 {
00140 PatternSize[nAllocPat] = 64;
00141 Patterns[nAllocPat] = AllocatePattern(64, m_nChannels);
00142 }
00143 }
00144
00145 for (UINT nChn=0; nChn<m_nChannels; nChn++)
00146 {
00147 for (UINT nPat=0; nPat<nop; nPat++)
00148 {
00149 MODCOMMAND *pat = NULL;
00150
00151 if (nPat < MAX_PATTERNS)
00152 {
00153 pat = Patterns[nPat];
00154 if (pat) pat += nChn;
00155 }
00156 UINT row = 0;
00157 while (row < 64)
00158 {
00159 if (dwMemPos + 6 > dwMemLength) return TRUE;
00160 UINT rep = 1;
00161 UINT note = lpStream[dwMemPos++];
00162 if (note == 0xFC)
00163 {
00164 rep = lpStream[dwMemPos];
00165 note = lpStream[dwMemPos+1];
00166 dwMemPos += 2;
00167 }
00168 UINT instr = lpStream[dwMemPos++];
00169 UINT eff = lpStream[dwMemPos++];
00170 UINT dat1 = lpStream[dwMemPos++];
00171 UINT dat2 = lpStream[dwMemPos++];
00172 UINT cmd1 = eff & 0x0F;
00173 UINT cmd2 = eff >> 4;
00174 if (cmd1 == 0x0C) dat1 >>= 2; else
00175 if (cmd1 == 0x0B) { cmd1 = dat1 = 0; }
00176 if (cmd2 == 0x0C) dat2 >>= 2; else
00177 if (cmd2 == 0x0B) { cmd2 = dat2 = 0; }
00178 while ((rep != 0) && (row < 64))
00179 {
00180 if (pat)
00181 {
00182 pat->instr = instr;
00183 if (note) pat->note = note + 36;
00184 if (cmd1 | dat1)
00185 {
00186 if (cmd1 == 0x0C)
00187 {
00188 pat->volcmd = VOLCMD_VOLUME;
00189 pat->vol = dat1;
00190 } else
00191 {
00192 pat->command = cmd1;
00193 pat->param = dat1;
00194 ConvertModCommand(pat);
00195 }
00196 }
00197 if (cmd2 == 0x0C)
00198 {
00199 pat->volcmd = VOLCMD_VOLUME;
00200 pat->vol = dat2;
00201 } else
00202 if ((cmd2 | dat2) && (!pat->command))
00203 {
00204 pat->command = cmd2;
00205 pat->param = dat2;
00206 ConvertModCommand(pat);
00207 }
00208 pat += m_nChannels;
00209 }
00210 row++;
00211 rep--;
00212 }
00213 }
00214 }
00215 }
00216
00217 for (UINT smp=1; smp<=m_nSamples; smp++) if (Ins[smp].nLength)
00218 {
00219 if (dwMemPos >= dwMemLength) return TRUE;
00220 UINT flags = (Ins[smp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
00221 dwMemPos += ReadSample(&Ins[smp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
00222 }
00223 return TRUE;
00224 }
00225