Add more to the gitignores
[platform/upstream/gstreamer.git] / gst / modplug / libmodplug / load_669.cpp
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 ////////////////////////////////////////////////////////////
9 // 669 Composer / UNIS 669 module loader
10 ////////////////////////////////////////////////////////////
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include "stdafx.h"
17 #include "sndfile.h"
18
19 //#pragma warning(disable:4244)
20
21 typedef struct tagFILEHEADER669
22 {
23         WORD sig;                               // 'if' or 'JN'
24         signed char songmessage[108];   // Song Message
25         BYTE samples;                   // number of samples (1-64)
26         BYTE patterns;                  // number of patterns (1-128)
27         BYTE restartpos;
28         BYTE orders[128];
29         BYTE tempolist[128];
30         BYTE breaks[128];
31 } FILEHEADER669;
32
33
34 typedef struct tagSAMPLE669
35 {
36         BYTE filename[13];
37         BYTE length[4]; // when will somebody think about DWORD align ???
38         BYTE loopstart[4];
39         BYTE loopend[4];
40 } SAMPLE669;
41
42
43 BOOL CSoundFile::Read669(const BYTE *lpStream, DWORD dwMemLength)
44 //---------------------------------------------------------------
45 {
46         BOOL b669Ext;
47         const FILEHEADER669 *pfh = (const FILEHEADER669 *)lpStream;
48         const SAMPLE669 *psmp = (const SAMPLE669 *)(lpStream + 0x1F1);
49         DWORD dwMemPos = 0;
50
51         if ((!lpStream) || (dwMemLength < sizeof(FILEHEADER669))) return FALSE;
52         if ((bswapLE16(pfh->sig) != 0x6669) && (bswapLE16(pfh->sig) != 0x4E4A)) return FALSE;
53         b669Ext = (bswapLE16(pfh->sig) == 0x4E4A) ? TRUE : FALSE;
54         if ((!pfh->samples) || (pfh->samples > 64) || (pfh->restartpos >= 128)
55          || (!pfh->patterns) || (pfh->patterns > 128)) return FALSE;
56         DWORD dontfuckwithme = 0x1F1 + pfh->samples * sizeof(SAMPLE669) + pfh->patterns * 0x600;
57         if (dontfuckwithme > dwMemLength) return FALSE;
58         for (UINT ichk=0; ichk<pfh->samples; ichk++)
59         {
60                 DWORD len = bswapLE32(*((DWORD *)(&psmp[ichk].length)));
61                 dontfuckwithme += len;
62         }
63         if (dontfuckwithme > dwMemLength) return FALSE;
64         // That should be enough checking: this must be a 669 module.
65         m_nType = MOD_TYPE_669;
66         m_dwSongFlags |= SONG_LINEARSLIDES;
67         m_nMinPeriod = 28 << 2;
68         m_nMaxPeriod = 1712 << 3;
69         m_nDefaultTempo = 125;
70         m_nDefaultSpeed = 6;
71         m_nChannels = 8;
72         memcpy(m_szNames[0], pfh->songmessage, 16);
73         m_nSamples = pfh->samples;
74         for (UINT nins=1; nins<=m_nSamples; nins++, psmp++)
75         {
76                 DWORD len = bswapLE32(*((DWORD *)(&psmp->length)));
77                 DWORD loopstart = bswapLE32(*((DWORD *)(&psmp->loopstart)));
78                 DWORD loopend = bswapLE32(*((DWORD *)(&psmp->loopend)));
79                 if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH;
80                 if ((loopend > len) && (!loopstart)) loopend = 0;
81                 if (loopend > len) loopend = len;
82                 if (loopstart + 4 >= loopend) loopstart = loopend = 0;
83                 Ins[nins].nLength = len;
84                 Ins[nins].nLoopStart = loopstart;
85                 Ins[nins].nLoopEnd = loopend;
86                 if (loopend) Ins[nins].uFlags |= CHN_LOOP;
87                 memcpy(m_szNames[nins], psmp->filename, 13);
88                 Ins[nins].nVolume = 256;
89                 Ins[nins].nGlobalVol = 64;
90                 Ins[nins].nPan = 128;
91         }
92         // Song Message
93         m_lpszSongComments = new char[109];
94         memcpy(m_lpszSongComments, pfh->songmessage, 108);
95         m_lpszSongComments[108] = 0;
96         // Reading Orders
97         memcpy(Order, pfh->orders, 128);
98         m_nRestartPos = pfh->restartpos;
99         if (Order[m_nRestartPos] >= pfh->patterns) m_nRestartPos = 0;
100         // Reading Pattern Break Locations
101         for (UINT npan=0; npan<8; npan++)
102         {
103                 ChnSettings[npan].nPan = (npan & 1) ? 0x30 : 0xD0;
104                 ChnSettings[npan].nVolume = 64;
105         }
106         // Reading Patterns
107         dwMemPos = 0x1F1 + pfh->samples * 25;
108         for (UINT npat=0; npat<pfh->patterns; npat++)
109         {
110                 Patterns[npat] = AllocatePattern(64, m_nChannels);
111                 if (!Patterns[npat]) break;
112                 PatternSize[npat] = 64;
113                 MODCOMMAND *m = Patterns[npat];
114                 const BYTE *p = lpStream + dwMemPos;
115                 for (UINT row=0; row<64; row++)
116                 {
117                         MODCOMMAND *mspeed = m;
118                         if ((row == pfh->breaks[npat]) && (row != 63))
119                         {
120                                 for (UINT i=0; i<8; i++)
121                                 {
122                                         m[i].command = CMD_PATTERNBREAK;
123                                         m[i].param = 0;
124                                 }
125                         }
126                         for (UINT n=0; n<8; n++, m++, p+=3)
127                         {
128                                 UINT note = p[0] >> 2;
129                                 UINT instr = ((p[0] & 0x03) << 4) | (p[1] >> 4);
130                                 UINT vol = p[1] & 0x0F;
131                                 if (p[0] < 0xFE)
132                                 {
133                                         m->note = note + 37;
134                                         m->instr = instr + 1;
135                                 }
136                                 if (p[0] <= 0xFE)
137                                 {
138                                         m->volcmd = VOLCMD_VOLUME;
139                                         m->vol = (vol << 2) + 2;
140                                 }
141                                 if (p[2] != 0xFF)
142                                 {
143                                         UINT command = p[2] >> 4;
144                                         UINT param = p[2] & 0x0F;
145                                         switch(command)
146                                         {
147                                         case 0x00:      command = CMD_PORTAMENTOUP; break;
148                                         case 0x01:      command = CMD_PORTAMENTODOWN; break;
149                                         case 0x02:      command = CMD_TONEPORTAMENTO; break;
150                                         case 0x03:      command = CMD_MODCMDEX; param |= 0x50; break;
151                                         case 0x04:      command = CMD_VIBRATO; param |= 0x40; break;
152                                         case 0x05:      if (param) command = CMD_SPEED; else command = 0; param += 2; break;
153                                         case 0x06:      if (param == 0) { command = CMD_PANNINGSLIDE; param = 0xFE; } else
154                                                                 if (param == 1) { command = CMD_PANNINGSLIDE; param = 0xEF; } else
155                                                                 command = 0;
156                                                                 break;
157                                         default:        command = 0;
158                                         }
159                                         if (command)
160                                         {
161                                                 if (command == CMD_SPEED) mspeed = NULL;
162                                                 m->command = command;
163                                                 m->param = param;
164                                         }
165                                 }
166                         }
167                         if ((!row) && (mspeed))
168                         {
169                                 for (UINT i=0; i<8; i++) if (!mspeed[i].command)
170                                 {
171                                         mspeed[i].command = CMD_SPEED;
172                                         mspeed[i].param = pfh->tempolist[npat] + 2;
173                                         break;
174                                 }
175                         }
176                 }
177                 dwMemPos += 0x600;
178         }
179         // Reading Samples
180         for (UINT n=1; n<=m_nSamples; n++)
181         {
182                 UINT len = Ins[n].nLength;
183                 if (dwMemPos >= dwMemLength) break;
184                 if (len > 4) ReadSample(&Ins[n], RS_PCM8U, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
185                 dwMemPos += len;
186         }
187         return TRUE;
188 }
189
190