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

load_669.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 
00012 // 669 Composer / UNIS 669 module loader
00014 
00015 #include "stdafx.h"
00016 #include "sndfile.h"
00017 
00018 //#pragma warning(disable:4244)
00019 
00020 typedef struct tagFILEHEADER669
00021 {
00022         WORD sig;                               // 'if' or 'JN'
00023         signed char songmessage[108];   // Song Message
00024         BYTE samples;                   // number of samples (1-64)
00025         BYTE patterns;                  // number of patterns (1-128)
00026         BYTE restartpos;
00027         BYTE orders[128];
00028         BYTE tempolist[128];
00029         BYTE breaks[128];
00030 } Q_PACKED FILEHEADER669;
00031 
00032 
00033 typedef struct tagSAMPLE669
00034 {
00035         BYTE filename[13];
00036         BYTE length[4]; // when will somebody think about DWORD align ???
00037         BYTE loopstart[4];
00038         BYTE loopend[4];
00039 } Q_PACKED SAMPLE669;
00040 
00041 
00042 BOOL CSoundFile::Read669(const BYTE *lpStream, DWORD dwMemLength)
00043 //---------------------------------------------------------------
00044 {
00045         BOOL b669Ext;
00046         const FILEHEADER669 *pfh = (const FILEHEADER669 *)lpStream;
00047         const SAMPLE669 *psmp = (const SAMPLE669 *)(lpStream + 0x1F1);
00048         DWORD dwMemPos = 0;
00049 
00050         if ((!lpStream) || (dwMemLength < sizeof(FILEHEADER669))) return FALSE;
00051         if ((bswapLE16(pfh->sig) != 0x6669) && (bswapLE16(pfh->sig) != 0x4E4A)) return FALSE;
00052         b669Ext = (bswapLE16(pfh->sig) == 0x4E4A) ? TRUE : FALSE;
00053         if ((!pfh->samples) || (pfh->samples > 64) || (pfh->restartpos >= 128)
00054          || (!pfh->patterns) || (pfh->patterns > 128)) return FALSE;
00055         DWORD dontfuckwithme = 0x1F1 + pfh->samples * sizeof(SAMPLE669) + pfh->patterns * 0x600;
00056         if (dontfuckwithme > dwMemLength) return FALSE;
00057         for (UINT ichk=0; ichk<pfh->samples; ichk++)
00058         {
00059                 DWORD len = bswapLE32(*((DWORD *)(&psmp[ichk].length)));
00060                 dontfuckwithme += len;
00061         }
00062         if (dontfuckwithme > dwMemLength) return FALSE;
00063         // That should be enough checking: this must be a 669 module.
00064         m_nType = MOD_TYPE_669;
00065         m_dwSongFlags |= SONG_LINEARSLIDES;
00066         m_nMinPeriod = 28 << 2;
00067         m_nMaxPeriod = 1712 << 3;
00068         m_nDefaultTempo = 125;
00069         m_nDefaultSpeed = 6;
00070         m_nChannels = 8;
00071         memcpy(m_szNames[0], pfh->songmessage, 16);
00072         m_nSamples = pfh->samples;
00073         for (UINT nins=1; nins<=m_nSamples; nins++, psmp++)
00074         {
00075                 DWORD len = bswapLE32(*((DWORD *)(&psmp->length)));
00076                 DWORD loopstart = bswapLE32(*((DWORD *)(&psmp->loopstart)));
00077                 DWORD loopend = bswapLE32(*((DWORD *)(&psmp->loopend)));
00078                 if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH;
00079                 if ((loopend > len) && (!loopstart)) loopend = 0;
00080                 if (loopend > len) loopend = len;
00081                 if (loopstart + 4 >= loopend) loopstart = loopend = 0;
00082                 Ins[nins].nLength = len;
00083                 Ins[nins].nLoopStart = loopstart;
00084                 Ins[nins].nLoopEnd = loopend;
00085                 if (loopend) Ins[nins].uFlags |= CHN_LOOP;
00086                 memcpy(m_szNames[nins], psmp->filename, 13);
00087                 Ins[nins].nVolume = 256;
00088                 Ins[nins].nGlobalVol = 64;
00089                 Ins[nins].nPan = 128;
00090         }
00091         // Song Message
00092         m_lpszSongComments = new char[109];
00093         memcpy(m_lpszSongComments, pfh->songmessage, 108);
00094         m_lpszSongComments[108] = 0;
00095         // Reading Orders
00096         memcpy(Order, pfh->orders, 128);
00097         m_nRestartPos = pfh->restartpos;
00098         if (Order[m_nRestartPos] >= pfh->patterns) m_nRestartPos = 0;
00099         // Reading Pattern Break Locations
00100         for (UINT npan=0; npan<8; npan++)
00101         {
00102                 ChnSettings[npan].nPan = (npan & 1) ? 0x30 : 0xD0;
00103                 ChnSettings[npan].nVolume = 64;
00104         }
00105         // Reading Patterns
00106         dwMemPos = 0x1F1 + pfh->samples * 25;
00107         for (UINT npat=0; npat<pfh->patterns; npat++)
00108         {
00109                 Patterns[npat] = AllocatePattern(64, m_nChannels);
00110                 if (!Patterns[npat]) break;
00111                 PatternSize[npat] = 64;
00112                 MODCOMMAND *m = Patterns[npat];
00113                 const BYTE *p = lpStream + dwMemPos;
00114                 for (UINT row=0; row<64; row++)
00115                 {
00116                         MODCOMMAND *mspeed = m;
00117                         if ((row == pfh->breaks[npat]) && (row != 63))
00118                         {
00119                                 for (UINT i=0; i<8; i++)
00120                                 {
00121                                         m[i].command = CMD_PATTERNBREAK;
00122                                         m[i].param = 0;
00123                                 }
00124                         }
00125                         for (UINT n=0; n<8; n++, m++, p+=3)
00126                         {
00127                                 UINT note = p[0] >> 2;
00128                                 UINT instr = ((p[0] & 0x03) << 4) | (p[1] >> 4);
00129                                 UINT vol = p[1] & 0x0F;
00130                                 if (p[0] < 0xFE)
00131                                 {
00132                                         m->note = note + 37;
00133                                         m->instr = instr + 1;
00134                                 }
00135                                 if (p[0] <= 0xFE)
00136                                 {
00137                                         m->volcmd = VOLCMD_VOLUME;
00138                                         m->vol = (vol << 2) + 2;
00139                                 }
00140                                 if (p[2] != 0xFF)
00141                                 {
00142                                         UINT command = p[2] >> 4;
00143                                         UINT param = p[2] & 0x0F;
00144                                         switch(command)
00145                                         {
00146                                         case 0x00:      command = CMD_PORTAMENTOUP; break;
00147                                         case 0x01:      command = CMD_PORTAMENTODOWN; break;
00148                                         case 0x02:      command = CMD_TONEPORTAMENTO; break;
00149                                         case 0x03:      command = CMD_MODCMDEX; param |= 0x50; break;
00150                                         case 0x04:      command = CMD_VIBRATO; param |= 0x40; break;
00151                                         case 0x05:      if (param) command = CMD_SPEED; else command = 0; param += 2; break;
00152                                         case 0x06:      if (param == 0) { command = CMD_PANNINGSLIDE; param = 0xFE; } else
00153                                                                 if (param == 1) { command = CMD_PANNINGSLIDE; param = 0xEF; } else
00154                                                                 command = 0;
00155                                                                 break;
00156                                         default:        command = 0;
00157                                         }
00158                                         if (command)
00159                                         {
00160                                                 if (command == CMD_SPEED) mspeed = NULL;
00161                                                 m->command = command;
00162                                                 m->param = param;
00163                                         }
00164                                 }
00165                         }
00166                         if ((!row) && (mspeed))
00167                         {
00168                                 for (UINT i=0; i<8; i++) if (!mspeed[i].command)
00169                                 {
00170                                         mspeed[i].command = CMD_SPEED;
00171                                         mspeed[i].param = pfh->tempolist[npat] + 2;
00172                                         break;
00173                                 }
00174                         }
00175                 }
00176                 dwMemPos += 0x600;
00177         }
00178         // Reading Samples
00179         for (UINT n=1; n<=m_nSamples; n++)
00180         {
00181                 UINT len = Ins[n].nLength;
00182                 if (dwMemPos >= dwMemLength) break;
00183                 if (len > 4) ReadSample(&Ins[n], RS_PCM8U, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
00184                 dwMemPos += len;
00185         }
00186         return TRUE;
00187 }
00188 
00189 

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