Diffstat (limited to 'core/multimedia/opieplayer/modplug/load_ult.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/multimedia/opieplayer/modplug/load_ult.cpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_ult.cpp b/core/multimedia/opieplayer/modplug/load_ult.cpp new file mode 100644 index 0000000..c9b7118 --- a/dev/null +++ b/core/multimedia/opieplayer/modplug/load_ult.cpp | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and modify it | ||
3 | * under the terms of the GNU General Public License as published by the | ||
4 | * Free Software Foundation; either version 2 of the license or (at your | ||
5 | * option) any later version. | ||
6 | * | ||
7 | * Authors: Olivier Lapicque <olivierl@jps.net> | ||
8 | */ | ||
9 | |||
10 | #include "stdafx.h" | ||
11 | #include "sndfile.h" | ||
12 | |||
13 | //#pragma warning(disable:4244) | ||
14 | |||
15 | #define ULT_16BIT 0x04 | ||
16 | #define ULT_LOOP 0x08 | ||
17 | #define ULT_BIDI 0x10 | ||
18 | |||
19 | #pragma pack(1) | ||
20 | |||
21 | // Raw ULT header struct: | ||
22 | typedef struct tagULTHEADER | ||
23 | { | ||
24 | char id[15]; // changed from CHAR | ||
25 | char songtitle[32]; // changed from CHAR | ||
26 | BYTE reserved; | ||
27 | } Q_PACKED ULTHEADER; | ||
28 | |||
29 | |||
30 | // Raw ULT sampleinfo struct: | ||
31 | typedef struct tagULTSAMPLE | ||
32 | { | ||
33 | CHAR samplename[32]; | ||
34 | CHAR dosname[12]; | ||
35 | LONG loopstart; | ||
36 | LONG loopend; | ||
37 | LONG sizestart; | ||
38 | LONG sizeend; | ||
39 | BYTE volume; | ||
40 | BYTE flags; | ||
41 | WORD finetune; | ||
42 | } Q_PACKED ULTSAMPLE; | ||
43 | |||
44 | #pragma pack() | ||
45 | |||
46 | |||
47 | BOOL CSoundFile::ReadUlt(const BYTE *lpStream, DWORD dwMemLength) | ||
48 | //--------------------------------------------------------------- | ||
49 | { | ||
50 | ULTHEADER *pmh = (ULTHEADER *)lpStream; | ||
51 | ULTSAMPLE *pus; | ||
52 | UINT nos, nop; | ||
53 | DWORD dwMemPos = 0; | ||
54 | |||
55 | // try to read module header | ||
56 | if ((!lpStream) || (dwMemLength < 0x100)) return FALSE; | ||
57 | if (strncmp(pmh->id,"MAS_UTrack_V00",14)) return FALSE; | ||
58 | // Warning! Not supported ULT format, trying anyway | ||
59 | // if ((pmh->id[14] < '1') || (pmh->id[14] > '4')) return FALSE; | ||
60 | m_nType = MOD_TYPE_ULT; | ||
61 | m_nDefaultSpeed = 6; | ||
62 | m_nDefaultTempo = 125; | ||
63 | memcpy(m_szNames[0], pmh->songtitle, 32); | ||
64 | // read songtext | ||
65 | dwMemPos = sizeof(ULTHEADER); | ||
66 | if ((pmh->reserved) && (dwMemPos + pmh->reserved * 32 < dwMemLength)) | ||
67 | { | ||
68 | UINT len = pmh->reserved * 32; | ||
69 | m_lpszSongComments = new char[len + 1 + pmh->reserved]; | ||
70 | if (m_lpszSongComments) | ||
71 | { | ||
72 | for (UINT l=0; l<pmh->reserved; l++) | ||
73 | { | ||
74 | memcpy(m_lpszSongComments+l*33, lpStream+dwMemPos+l*32, 32); | ||
75 | m_lpszSongComments[l*33+32] = 0x0D; | ||
76 | } | ||
77 | m_lpszSongComments[len] = 0; | ||
78 | } | ||
79 | dwMemPos += len; | ||
80 | } | ||
81 | if (dwMemPos >= dwMemLength) return TRUE; | ||
82 | nos = lpStream[dwMemPos++]; | ||
83 | m_nSamples = nos; | ||
84 | if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1; | ||
85 | UINT smpsize = 64; | ||
86 | if (pmh->id[14] >= '4')smpsize += 2; | ||
87 | if (dwMemPos + nos*smpsize + 256 + 2 > dwMemLength) return TRUE; | ||
88 | for (UINT ins=1; ins<=nos; ins++, dwMemPos+=smpsize) if (ins<=m_nSamples) | ||
89 | { | ||
90 | pus= (ULTSAMPLE *)(lpStream+dwMemPos); | ||
91 | MODINSTRUMENT *pins = &Ins[ins]; | ||
92 | memcpy(m_szNames[ins], pus->samplename, 32); | ||
93 | memcpy(pins->name, pus->dosname, 12); | ||
94 | pins->nLoopStart = pus->loopstart; | ||
95 | pins->nLoopEnd = pus->loopend; | ||
96 | pins->nLength = pus->sizeend - pus->sizestart; | ||
97 | pins->nVolume = pus->volume; | ||
98 | pins->nGlobalVol = 64; | ||
99 | pins->nC4Speed = 8363; | ||
100 | if (pmh->id[14] >= '4') | ||
101 | { | ||
102 | pins->nC4Speed = pus->finetune; | ||
103 | } | ||
104 | if (pus->flags & ULT_LOOP) pins->uFlags |= CHN_LOOP; | ||
105 | if (pus->flags & ULT_BIDI) pins->uFlags |= CHN_PINGPONGLOOP; | ||
106 | if (pus->flags & ULT_16BIT) | ||
107 | { | ||
108 | pins->uFlags |= CHN_16BIT; | ||
109 | pins->nLoopStart >>= 1; | ||
110 | pins->nLoopEnd >>= 1; | ||
111 | } | ||
112 | } | ||
113 | memcpy(Order, lpStream+dwMemPos, 256); | ||
114 | dwMemPos += 256; | ||
115 | m_nChannels = lpStream[dwMemPos] + 1; | ||
116 | nop = lpStream[dwMemPos+1] + 1; | ||
117 | dwMemPos += 2; | ||
118 | if (m_nChannels > 32) m_nChannels = 32; | ||
119 | // Default channel settings | ||
120 | for (UINT nSet=0; nSet<m_nChannels; nSet++) | ||
121 | { | ||
122 | ChnSettings[nSet].nVolume = 64; | ||
123 | ChnSettings[nSet].nPan = (nSet & 1) ? 0x40 : 0xC0; | ||
124 | } | ||
125 | // read pan position table for v1.5 and higher | ||
126 | if(pmh->id[14]>='3') | ||
127 | { | ||
128 | if (dwMemPos + m_nChannels > dwMemLength) return TRUE; | ||
129 | for(UINT t=0; t<m_nChannels; t++) | ||
130 | { | ||
131 | ChnSettings[t].nPan = (lpStream[dwMemPos++] << 4) + 8; | ||
132 | if (ChnSettings[t].nPan > 256) ChnSettings[t].nPan = 256; | ||
133 | } | ||
134 | } | ||
135 | // Allocating Patterns | ||
136 | for (UINT nAllocPat=0; nAllocPat<nop; nAllocPat++) | ||
137 | { | ||
138 | if (nAllocPat < MAX_PATTERNS) | ||
139 | { | ||
140 | PatternSize[nAllocPat] = 64; | ||
141 | Patterns[nAllocPat] = AllocatePattern(64, m_nChannels); | ||
142 | } | ||
143 | } | ||
144 | // Reading Patterns | ||
145 | for (UINT nChn=0; nChn<m_nChannels; nChn++) | ||
146 | { | ||
147 | for (UINT nPat=0; nPat<nop; nPat++) | ||
148 | { | ||
149 | MODCOMMAND *pat = NULL; | ||
150 | |||
151 | if (nPat < MAX_PATTERNS) | ||
152 | { | ||
153 | pat = Patterns[nPat]; | ||
154 | if (pat) pat += nChn; | ||
155 | } | ||
156 | UINT row = 0; | ||
157 | while (row < 64) | ||
158 | { | ||
159 | if (dwMemPos + 6 > dwMemLength) return TRUE; | ||
160 | UINT rep = 1; | ||
161 | UINT note = lpStream[dwMemPos++]; | ||
162 | if (note == 0xFC) | ||
163 | { | ||
164 | rep = lpStream[dwMemPos]; | ||
165 | note = lpStream[dwMemPos+1]; | ||
166 | dwMemPos += 2; | ||
167 | } | ||
168 | UINT instr = lpStream[dwMemPos++]; | ||
169 | UINT eff = lpStream[dwMemPos++]; | ||
170 | UINT dat1 = lpStream[dwMemPos++]; | ||
171 | UINT dat2 = lpStream[dwMemPos++]; | ||
172 | UINT cmd1 = eff & 0x0F; | ||
173 | UINT cmd2 = eff >> 4; | ||
174 | if (cmd1 == 0x0C) dat1 >>= 2; else | ||
175 | if (cmd1 == 0x0B) { cmd1 = dat1 = 0; } | ||
176 | if (cmd2 == 0x0C) dat2 >>= 2; else | ||
177 | if (cmd2 == 0x0B) { cmd2 = dat2 = 0; } | ||
178 | while ((rep != 0) && (row < 64)) | ||
179 | { | ||
180 | if (pat) | ||
181 | { | ||
182 | pat->instr = instr; | ||
183 | if (note) pat->note = note + 36; | ||
184 | if (cmd1 | dat1) | ||
185 | { | ||
186 | if (cmd1 == 0x0C) | ||
187 | { | ||
188 | pat->volcmd = VOLCMD_VOLUME; | ||
189 | pat->vol = dat1; | ||
190 | } else | ||
191 | { | ||
192 | pat->command = cmd1; | ||
193 | pat->param = dat1; | ||
194 | ConvertModCommand(pat); | ||
195 | } | ||
196 | } | ||
197 | if (cmd2 == 0x0C) | ||
198 | { | ||
199 | pat->volcmd = VOLCMD_VOLUME; | ||
200 | pat->vol = dat2; | ||
201 | } else | ||
202 | if ((cmd2 | dat2) && (!pat->command)) | ||
203 | { | ||
204 | pat->command = cmd2; | ||
205 | pat->param = dat2; | ||
206 | ConvertModCommand(pat); | ||
207 | } | ||
208 | pat += m_nChannels; | ||
209 | } | ||
210 | row++; | ||
211 | rep--; | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | // Reading Instruments | ||
217 | for (UINT smp=1; smp<=m_nSamples; smp++) if (Ins[smp].nLength) | ||
218 | { | ||
219 | if (dwMemPos >= dwMemLength) return TRUE; | ||
220 | UINT flags = (Ins[smp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; | ||
221 | dwMemPos += ReadSample(&Ins[smp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos); | ||
222 | } | ||
223 | return TRUE; | ||
224 | } | ||
225 | |||