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

load_amf.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 */
00009 
00011 //
00012 // AMF module loader
00013 //
00014 // There is 2 types of AMF files:
00015 // - ASYLUM Music Format
00016 // - Advanced Music Format(DSM)
00017 //
00019 #include "stdafx.h"
00020 #include "sndfile.h"
00021 
00022 //#define AMFLOG
00023 
00024 //#pragma warning(disable:4244)
00025 
00026 #pragma pack(1)
00027 
00028 typedef struct _AMFFILEHEADER
00029 {
00030         UCHAR szAMF[3];
00031         UCHAR version;
00032         CHAR title[32];
00033         UCHAR numsamples;
00034         UCHAR numorders;
00035         USHORT numtracks;
00036         UCHAR numchannels;
00037 } Q_PACKED AMFFILEHEADER;
00038 
00039 typedef struct _AMFSAMPLE
00040 {
00041         UCHAR type;
00042         CHAR  samplename[32];
00043         CHAR  filename[13];
00044         ULONG offset;
00045         ULONG length;
00046         USHORT c2spd;
00047         UCHAR volume;
00048 } Q_PACKED AMFSAMPLE;
00049 
00050 
00051 #pragma pack()
00052 
00053 
00054 #ifdef AMFLOG
00055 extern void Log(LPCSTR, ...);
00056 #endif
00057 
00058 VOID AMF_Unpack(MODCOMMAND *pPat, const BYTE *pTrack, UINT nRows, UINT nChannels)
00059 //-------------------------------------------------------------------------------
00060 {
00061         UINT lastinstr = 0;
00062         UINT nTrkSize = *(USHORT *)pTrack;
00063         nTrkSize += (UINT)pTrack[2] << 16;
00064         pTrack += 3;
00065         while (nTrkSize--)
00066         {
00067                 UINT row = pTrack[0];
00068                 UINT cmd = pTrack[1];
00069                 UINT arg = pTrack[2];
00070                 if (row >= nRows) break;
00071                 MODCOMMAND *m = pPat + row * nChannels;
00072                 if (cmd < 0x7F) // note+vol
00073                 {
00074                         m->note = cmd+1;
00075                         if (!m->instr) m->instr = lastinstr;
00076                         m->volcmd = VOLCMD_VOLUME;
00077                         m->vol = arg;
00078                 } else
00079                 if (cmd == 0x7F) // duplicate row
00080                 {
00081                         signed char rdelta = (signed char)arg;
00082                         int rowsrc = (int)row + (int)rdelta;
00083                         if ((rowsrc >= 0) && (rowsrc < (int)nRows)) *m = pPat[rowsrc*nChannels];
00084                 } else
00085                 if (cmd == 0x80) // instrument
00086                 {
00087                         m->instr = arg+1;
00088                         lastinstr = m->instr;
00089                 } else
00090                 if (cmd == 0x83) // volume
00091                 {
00092                         m->volcmd = VOLCMD_VOLUME;
00093                         m->vol = arg;
00094                 } else
00095                 // effect
00096                 {
00097                         UINT command = cmd & 0x7F;
00098                         UINT param = arg;
00099                         switch(command)
00100                         {
00101                         // 0x01: Set Speed
00102                         case 0x01:      command = CMD_SPEED; break;
00103                         // 0x02: Volume Slide
00104                         // 0x0A: Tone Porta + Vol Slide
00105                         // 0x0B: Vibrato + Vol Slide
00106                         case 0x02:      command = CMD_VOLUMESLIDE;
00107                         case 0x0A:      if (command == 0x0A) command = CMD_TONEPORTAVOL;
00108                         case 0x0B:      if (command == 0x0B) command = CMD_VIBRATOVOL;
00109                                                 if (param & 0x80) param = (-(signed char)param)&0x0F;
00110                                                 else param = (param&0x0F)<<4;
00111                                                 break;
00112                         // 0x04: Porta Up/Down
00113                         case 0x04:      if (param & 0x80) { command = CMD_PORTAMENTOUP; param = -(signed char)param; }
00114                                                 else { command = CMD_PORTAMENTODOWN; } break;
00115                         // 0x06: Tone Portamento
00116                         case 0x06:      command = CMD_TONEPORTAMENTO; break;
00117                         // 0x07: Tremor
00118                         case 0x07:      command = CMD_TREMOR; break;
00119                         // 0x08: Arpeggio
00120                         case 0x08:      command = CMD_ARPEGGIO; break;
00121                         // 0x09: Vibrato
00122                         case 0x09:      command = CMD_VIBRATO; break;
00123                         // 0x0C: Pattern Break
00124                         case 0x0C:      command = CMD_PATTERNBREAK; break;
00125                         // 0x0D: Position Jump
00126                         case 0x0D:      command = CMD_POSITIONJUMP; break;
00127                         // 0x0F: Retrig
00128                         case 0x0F:      command = CMD_RETRIG; break;
00129                         // 0x10: Offset
00130                         case 0x10:      command = CMD_OFFSET; break;
00131                         // 0x11: Fine Volume Slide
00132                         case 0x11:      if (param) { command = CMD_VOLUMESLIDE;
00133                                                         if (param & 0x80) param = 0xF0|((-(signed char)param)&0x0F);
00134                                                         else param = 0x0F|((param&0x0F)<<4);
00135                                                 } else command = 0; break;
00136                         // 0x12: Fine Portamento
00137                         // 0x16: Extra Fine Portamento
00138                         case 0x12:
00139                         case 0x16:      if (param) { int mask = (command == 0x16) ? 0xE0 : 0xF0;
00140                                                         command = (param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN;
00141                                                         if (param & 0x80) param = mask|((-(signed char)param)&0x0F);
00142                                                         else param |= mask;
00143                                                 } else command = 0; break;
00144                         // 0x13: Note Delay
00145                         case 0x13:      command = CMD_S3MCMDEX; param = 0xD0|(param & 0x0F); break;
00146                         // 0x14: Note Cut
00147                         case 0x14:      command = CMD_S3MCMDEX; param = 0xC0|(param & 0x0F); break;
00148                         // 0x15: Set Tempo
00149                         case 0x15:      command = CMD_TEMPO; break;
00150                         // 0x17: Panning
00151                         case 0x17:      param = (param+64)&0x7F;
00152                                                 if (m->command) { if (!m->volcmd) { m->volcmd = VOLCMD_PANNING;  m->vol = param/2; } command = 0; }
00153                                                 else { command = CMD_PANNING8; }
00154                         // Unknown effects
00155                         default:        command = param = 0;
00156                         }
00157                         if (command)
00158                         {
00159                                 m->command = command;
00160                                 m->param = param;
00161                         }
00162                 }
00163                 pTrack += 3;
00164         }
00165 }
00166 
00167 
00168 
00169 BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, DWORD dwMemLength)
00170 //-----------------------------------------------------------
00171 {
00172         AMFFILEHEADER *pfh = (AMFFILEHEADER *)lpStream;
00173         DWORD dwMemPos;
00174         
00175         if ((!lpStream) || (dwMemLength < 2048)) return FALSE;
00176         if ((!strncmp((LPCTSTR)lpStream, "ASYLUM Music Format V1.0", 25)) && (dwMemLength > 4096))
00177         {
00178                 UINT numorders, numpats, numsamples;
00179 
00180                 dwMemPos = 32;
00181                 numpats = lpStream[dwMemPos+3];
00182                 numorders = lpStream[dwMemPos+4];
00183                 numsamples = 64;
00184                 dwMemPos += 6;
00185                 if ((!numpats) || (numpats > MAX_PATTERNS) || (!numorders)
00186                  || (numpats*64*32 + 294 + 37*64 >= dwMemLength)) return FALSE;
00187                 m_nType = MOD_TYPE_AMF0;
00188                 m_nChannels = 8;
00189                 m_nInstruments = 0;
00190                 m_nSamples = 31;
00191                 m_nDefaultTempo = 125;
00192                 m_nDefaultSpeed = 6;
00193                 for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
00194                 {
00195                         Order[iOrd] = (iOrd < numorders) ? lpStream[dwMemPos+iOrd] : 0xFF;
00196                 }
00197                 dwMemPos = 294; // ???
00198                 for (UINT iSmp=0; iSmp<numsamples; iSmp++)
00199                 {
00200                         MODINSTRUMENT *psmp = &Ins[iSmp+1];
00201                         memcpy(m_szNames[iSmp+1], lpStream+dwMemPos, 22);
00202                         psmp->nFineTune = MOD2XMFineTune(lpStream[dwMemPos+22]);
00203                         psmp->nVolume = lpStream[dwMemPos+23];
00204                         psmp->nGlobalVol = 64;
00205                         if (psmp->nVolume > 0x40) psmp->nVolume = 0x40;
00206                         psmp->nVolume <<= 2;
00207                         psmp->nLength = *((LPDWORD)(lpStream+dwMemPos+25));
00208                         psmp->nLoopStart = *((LPDWORD)(lpStream+dwMemPos+29));
00209                         psmp->nLoopEnd = psmp->nLoopStart + *((LPDWORD)(lpStream+dwMemPos+33));
00210                         if ((psmp->nLoopEnd > psmp->nLoopStart) && (psmp->nLoopEnd <= psmp->nLength))
00211                         {
00212                                 psmp->uFlags = CHN_LOOP;
00213                         } else
00214                         {
00215                                 psmp->nLoopStart = psmp->nLoopEnd = 0;
00216                         }
00217                         if ((psmp->nLength) && (iSmp>31)) m_nSamples = iSmp+1;
00218                         dwMemPos += 37;
00219                 }
00220                 for (UINT iPat=0; iPat<numpats; iPat++)
00221                 {
00222                         MODCOMMAND *p = AllocatePattern(64, m_nChannels);
00223                         if (!p) break;
00224                         Patterns[iPat] = p;
00225                         PatternSize[iPat] = 64;
00226                         const UCHAR *pin = lpStream + dwMemPos;
00227                         for (UINT i=0; i<8*64; i++)
00228                         {
00229                                 p->note = 0;
00230 
00231                                 if (pin[0])
00232                                 {
00233                                         p->note = pin[0] + 13;
00234                                 }
00235                                 p->instr = pin[1];
00236                                 p->command = pin[2];
00237                                 p->param = pin[3];
00238                                 if (p->command > 0x0F)
00239                                 {
00240                                 #ifdef AMFLOG
00241                                         Log("0x%02X.0x%02X ?", p->command, p->param);
00242                                 #endif
00243                                         p->command = 0;
00244                                 }
00245                                 ConvertModCommand(p);
00246                                 pin += 4;
00247                                 p++;
00248                         }
00249                         dwMemPos += 64*32;
00250                 }
00251                 // Read samples
00252                 for (UINT iData=0; iData<m_nSamples; iData++)
00253                 {
00254                         MODINSTRUMENT *psmp = &Ins[iData+1];
00255                         if (psmp->nLength)
00256                         {
00257                                 dwMemPos += ReadSample(psmp, RS_PCM8S, (LPCSTR)(lpStream+dwMemPos), dwMemLength);
00258                         }
00259                 }
00260                 return TRUE;
00261         }
00263         // DSM/AMF
00264         USHORT *ptracks[MAX_PATTERNS];
00265         DWORD sampleseekpos[MAX_SAMPLES];
00266 
00267         if ((pfh->szAMF[0] != 'A') || (pfh->szAMF[1] != 'M') || (pfh->szAMF[2] != 'F')
00268          || (pfh->version < 10) || (pfh->version > 14) || (!pfh->numtracks)
00269          || (!pfh->numorders) || (pfh->numorders > MAX_PATTERNS)
00270          || (!pfh->numsamples) || (pfh->numsamples > MAX_SAMPLES)
00271          || (pfh->numchannels < 4) || (pfh->numchannels > 32))
00272                 return FALSE;
00273         memcpy(m_szNames[0], pfh->title, 32);
00274         dwMemPos = sizeof(AMFFILEHEADER);
00275         m_nType = MOD_TYPE_AMF;
00276         m_nChannels = pfh->numchannels;
00277         m_nSamples = pfh->numsamples;
00278         m_nInstruments = 0;
00279         // Setup Channel Pan Positions
00280         if (pfh->version >= 11)
00281         {
00282                 signed char *panpos = (signed char *)(lpStream + dwMemPos);
00283                 UINT nchannels = (pfh->version >= 13) ? 32 : 16;
00284                 for (UINT i=0; i<nchannels; i++)
00285                 {
00286                         int pan = (panpos[i] + 64) * 2;
00287                         if (pan < 0) pan = 0;
00288                         if (pan > 256) { pan = 128; ChnSettings[i].dwFlags |= CHN_SURROUND; }
00289                         ChnSettings[i].nPan = pan;
00290                 }
00291                 dwMemPos += nchannels;
00292         } else
00293         {
00294                 for (UINT i=0; i<16; i++)
00295                 {
00296                         ChnSettings[i].nPan = (lpStream[dwMemPos+i] & 1) ? 0x30 : 0xD0;
00297                 }
00298                 dwMemPos += 16;
00299         }
00300         // Get Tempo/Speed
00301         m_nDefaultTempo = 125;
00302         m_nDefaultSpeed = 6;
00303         if (pfh->version >= 13)
00304         {
00305                 if (lpStream[dwMemPos] >= 32) m_nDefaultTempo = lpStream[dwMemPos];
00306                 if (lpStream[dwMemPos+1] <= 32) m_nDefaultSpeed = lpStream[dwMemPos+1];
00307                 dwMemPos += 2;
00308         }
00309         // Setup sequence list
00310         for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
00311         {
00312                 Order[iOrd] = 0xFF;
00313                 if (iOrd < pfh->numorders)
00314                 {
00315                         Order[iOrd] = iOrd;
00316                         PatternSize[iOrd] = 64;
00317                         if (pfh->version >= 14)
00318                         {
00319                                 PatternSize[iOrd] = *(USHORT *)(lpStream+dwMemPos);
00320                                 dwMemPos += 2;
00321                         }
00322                         ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos);
00323                         dwMemPos += m_nChannels * sizeof(USHORT);
00324                 }
00325         }
00326         if (dwMemPos + m_nSamples * (sizeof(AMFSAMPLE)+8) > dwMemLength) return TRUE;
00327         // Read Samples
00328         UINT maxsampleseekpos = 0;
00329         for (UINT iIns=0; iIns<m_nSamples; iIns++)
00330         {
00331                 MODINSTRUMENT *pins = &Ins[iIns+1];
00332                 AMFSAMPLE *psh = (AMFSAMPLE *)(lpStream + dwMemPos);
00333 
00334                 dwMemPos += sizeof(AMFSAMPLE);
00335                 memcpy(m_szNames[iIns+1], psh->samplename, 32);
00336                 memcpy(pins->name, psh->filename, 13);
00337                 pins->nLength = psh->length;
00338                 pins->nC4Speed = psh->c2spd;
00339                 pins->nGlobalVol = 64;
00340                 pins->nVolume = psh->volume * 4;
00341                 if (pfh->version >= 11)
00342                 {
00343                         pins->nLoopStart = *(DWORD *)(lpStream+dwMemPos);
00344                         pins->nLoopEnd = *(DWORD *)(lpStream+dwMemPos+4);
00345                         dwMemPos += 8;
00346                 } else
00347                 {
00348                         pins->nLoopStart = *(WORD *)(lpStream+dwMemPos);
00349                         pins->nLoopEnd = pins->nLength;
00350                         dwMemPos += 2;
00351                 }
00352                 sampleseekpos[iIns] = 0;
00353                 if ((psh->type) && (psh->offset < dwMemLength-1))
00354                 {
00355                         sampleseekpos[iIns] = psh->offset;
00356                         if (psh->offset > maxsampleseekpos) maxsampleseekpos = psh->offset;
00357                         if ((pins->nLoopEnd > pins->nLoopStart + 2)
00358                          && (pins->nLoopEnd <= pins->nLength)) pins->uFlags |= CHN_LOOP;
00359                 }
00360         }
00361         // Read Track Mapping Table
00362         USHORT *pTrackMap = (USHORT *)(lpStream+dwMemPos);
00363         UINT realtrackcnt = 0;
00364         dwMemPos += pfh->numtracks * sizeof(USHORT);
00365         for (UINT iTrkMap=0; iTrkMap<pfh->numtracks; iTrkMap++)
00366         {
00367                 if (realtrackcnt < pTrackMap[iTrkMap]) realtrackcnt = pTrackMap[iTrkMap];
00368         }
00369         // Store tracks positions
00370         BYTE **pTrackData = new BYTE *[realtrackcnt];
00371         memset(pTrackData, 0, sizeof(pTrackData));
00372         for (UINT iTrack=0; iTrack<realtrackcnt; iTrack++) if (dwMemPos + 3 <= dwMemLength)
00373         {
00374                 UINT nTrkSize = *(USHORT *)(lpStream+dwMemPos);
00375                 nTrkSize += (UINT)lpStream[dwMemPos+2] << 16;
00376                 if (dwMemPos + nTrkSize * 3 + 3 <= dwMemLength)
00377                 {
00378                         pTrackData[iTrack] = (BYTE *)(lpStream + dwMemPos);
00379                 }
00380                 dwMemPos += nTrkSize * 3 + 3;
00381         }
00382         // Create the patterns from the list of tracks
00383         for (UINT iPat=0; iPat<pfh->numorders; iPat++)
00384         {
00385                 MODCOMMAND *p = AllocatePattern(PatternSize[iPat], m_nChannels);
00386                 if (!p) break;
00387                 Patterns[iPat] = p;
00388                 for (UINT iChn=0; iChn<m_nChannels; iChn++)
00389                 {
00390                         UINT nTrack = ptracks[iPat][iChn];
00391                         if ((nTrack) && (nTrack <= pfh->numtracks))
00392                         {
00393                                 UINT realtrk = pTrackMap[nTrack-1];
00394                                 if (realtrk)
00395                                 {
00396                                         realtrk--;
00397                                         if ((realtrk < realtrackcnt) && (pTrackData[realtrk]))
00398                                         {
00399                                                 AMF_Unpack(p+iChn, pTrackData[realtrk], PatternSize[iPat], m_nChannels);
00400                                         }
00401                                 }
00402                         }
00403                 }
00404         }
00405         delete pTrackData;
00406         // Read Sample Data
00407         for (UINT iSeek=1; iSeek<=maxsampleseekpos; iSeek++)
00408         {
00409                 if (dwMemPos >= dwMemLength) break;
00410                 for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (iSeek == sampleseekpos[iSmp])
00411                 {
00412                         MODINSTRUMENT *pins = &Ins[iSmp+1];
00413                         dwMemPos += ReadSample(pins, RS_PCM8U, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
00414                         break;
00415                 }
00416         }
00417         return TRUE;
00418 }
00419 
00420 

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