summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/modplug/load_dsm.cpp
Unidiff
Diffstat (limited to 'core/multimedia/opieplayer/modplug/load_dsm.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/modplug/load_dsm.cpp239
1 files changed, 239 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_dsm.cpp b/core/multimedia/opieplayer/modplug/load_dsm.cpp
new file mode 100644
index 0000000..4751f5f
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_dsm.cpp
@@ -0,0 +1,239 @@
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//////////////////////////////////////////////
11// DSIK Internal Format (DSM) module loader //
12//////////////////////////////////////////////
13#include "stdafx.h"
14#include "sndfile.h"
15
16#pragma pack(1)
17
18 #define DSMID_RIFF 0x46464952// "RIFF"
19 #define DSMID_DSMF 0x464d5344// "DSMF"
20 #define DSMID_SONG 0x474e4f53// "SONG"
21 #define DSMID_INST 0x54534e49// "INST"
22 #define DSMID_PATT 0x54544150// "PATT"
23
24
25typedef struct DSMNOTE
26{
27 BYTE note,ins,vol,cmd,inf;
28} Q_PACKED DSMNOTE;
29
30
31typedef struct DSMINST
32{
33 DWORD id_INST;
34 DWORD inst_len;
35 CHAR filename[13];
36 BYTE flags;
37 BYTE flags2;
38 BYTE volume;
39 DWORD length;
40 DWORD loopstart;
41 DWORD loopend;
42 DWORD reserved1;
43 WORD c2spd;
44 WORD reserved2;
45 CHAR samplename[28];
46} Q_PACKED DSMINST;
47
48
49typedef struct DSMFILEHEADER
50{
51 DWORD id_RIFF;// "RIFF"
52 DWORD riff_len;
53 DWORD id_DSMF;// "DSMF"
54 DWORD id_SONG;// "SONG"
55 DWORD song_len;
56} Q_PACKED DSMFILEHEADER;
57
58
59typedef struct DSMSONG
60{
61 CHAR songname[28];
62 WORD reserved1;
63 WORD flags;
64 DWORD reserved2;
65 WORD numord;
66 WORD numsmp;
67 WORD numpat;
68 WORD numtrk;
69 BYTE globalvol;
70 BYTE mastervol;
71 BYTE speed;
72 BYTE bpm;
73 BYTE panpos[16];
74 BYTE orders[128];
75} Q_PACKED DSMSONG;
76
77typedef struct DSMPATT
78{
79 DWORD id_PATT;
80 DWORD patt_len;
81 BYTE dummy1;
82 BYTE dummy2;
83} Q_PACKED DSMPATT;
84
85#pragma pack()
86
87
88BOOL CSoundFile::ReadDSM(LPCBYTE lpStream, DWORD dwMemLength)
89//-----------------------------------------------------------
90{
91 DSMFILEHEADER *pfh = (DSMFILEHEADER *)lpStream;
92 DSMSONG *psong;
93 DWORD dwMemPos;
94 UINT nPat, nSmp;
95
96 if ((!lpStream) || (dwMemLength < 1024) || (pfh->id_RIFF != DSMID_RIFF)
97 || (pfh->riff_len + 8 > dwMemLength) || (pfh->riff_len < 1024)
98 || (pfh->id_DSMF != DSMID_DSMF) || (pfh->id_SONG != DSMID_SONG)
99 || (pfh->song_len > dwMemLength)) return FALSE;
100 psong = (DSMSONG *)(lpStream + sizeof(DSMFILEHEADER));
101 dwMemPos = sizeof(DSMFILEHEADER) + pfh->song_len;
102 m_nType = MOD_TYPE_DSM;
103 m_nChannels = psong->numtrk;
104 if (m_nChannels < 4) m_nChannels = 4;
105 if (m_nChannels > 16) m_nChannels = 16;
106 m_nSamples = psong->numsmp;
107 if (m_nSamples > MAX_SAMPLES) m_nSamples = MAX_SAMPLES;
108 m_nDefaultSpeed = psong->speed;
109 m_nDefaultTempo = psong->bpm;
110 m_nDefaultGlobalVolume = psong->globalvol << 2;
111 if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256;
112 m_nSongPreAmp = psong->mastervol & 0x7F;
113 for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
114 {
115 Order[iOrd] = (BYTE)((iOrd < psong->numord) ? psong->orders[iOrd] : 0xFF);
116 }
117 for (UINT iPan=0; iPan<16; iPan++)
118 {
119 ChnSettings[iPan].nPan = 0x80;
120 if (psong->panpos[iPan] <= 0x80)
121 {
122 ChnSettings[iPan].nPan = psong->panpos[iPan] << 1;
123 }
124 }
125 memcpy(m_szNames[0], psong->songname, 28);
126 nPat = 0;
127 nSmp = 1;
128 while (dwMemPos < dwMemLength - 8)
129 {
130 DSMPATT *ppatt = (DSMPATT *)(lpStream + dwMemPos);
131 DSMINST *pins = (DSMINST *)(lpStream+dwMemPos);
132 // Reading Patterns
133 if (ppatt->id_PATT == DSMID_PATT)
134 {
135 dwMemPos += 8;
136 if (dwMemPos + ppatt->patt_len >= dwMemLength) break;
137 DWORD dwPos = dwMemPos;
138 dwMemPos += ppatt->patt_len;
139 MODCOMMAND *m = AllocatePattern(64, m_nChannels);
140 if (!m) break;
141 PatternSize[nPat] = 64;
142 Patterns[nPat] = m;
143 UINT row = 0;
144 while ((row < 64) && (dwPos + 2 <= dwMemPos))
145 {
146 UINT flag = lpStream[dwPos++];
147 if (flag)
148 {
149 UINT ch = (flag & 0x0F) % m_nChannels;
150 if (flag & 0x80)
151 {
152 UINT note = lpStream[dwPos++];
153 if (note)
154 {
155 if (note <= 12*9) note += 12;
156 m[ch].note = (BYTE)note;
157 }
158 }
159 if (flag & 0x40)
160 {
161 m[ch].instr = lpStream[dwPos++];
162 }
163 if (flag & 0x20)
164 {
165 m[ch].volcmd = VOLCMD_VOLUME;
166 m[ch].vol = lpStream[dwPos++];
167 }
168 if (flag & 0x10)
169 {
170 UINT command = lpStream[dwPos++];
171 UINT param = lpStream[dwPos++];
172 switch(command)
173 {
174 // 4-bit Panning
175 case 0x08:
176 switch(param & 0xF0)
177 {
178 case 0x00: param <<= 4; break;
179 case 0x10: command = 0x0A; param = (param & 0x0F) << 4; break;
180 case 0x20: command = 0x0E; param = (param & 0x0F) | 0xA0; break;
181 case 0x30: command = 0x0E; param = (param & 0x0F) | 0x10; break;
182 case 0x40: command = 0x0E; param = (param & 0x0F) | 0x20; break;
183 default: command = 0;
184 }
185 break;
186 // Portamentos
187 case 0x11:
188 case 0x12:
189 command &= 0x0F;
190 break;
191 // 3D Sound (?)
192 case 0x13:
193 command = 'X' - 55;
194 param = 0x91;
195 break;
196 default:
197 // Volume + Offset (?)
198 command = ((command & 0xF0) == 0x20) ? 0x09 : 0;
199 }
200 m[ch].command = (BYTE)command;
201 m[ch].param = (BYTE)param;
202 if (command) ConvertModCommand(&m[ch]);
203 }
204 } else
205 {
206 m += m_nChannels;
207 row++;
208 }
209 }
210 nPat++;
211 } else
212 // Reading Samples
213 if ((nSmp <= m_nSamples) && (pins->id_INST == DSMID_INST))
214 {
215 if (dwMemPos + pins->inst_len >= dwMemLength - 8) break;
216 DWORD dwPos = dwMemPos + sizeof(DSMINST);
217 dwMemPos += 8 + pins->inst_len;
218 memcpy(m_szNames[nSmp], pins->samplename, 28);
219 MODINSTRUMENT *psmp = &Ins[nSmp];
220 memcpy(psmp->name, pins->filename, 13);
221 psmp->nGlobalVol = 64;
222 psmp->nC4Speed = pins->c2spd;
223 psmp->uFlags = (WORD)((pins->flags & 1) ? CHN_LOOP : 0);
224 psmp->nLength = pins->length;
225 psmp->nLoopStart = pins->loopstart;
226 psmp->nLoopEnd = pins->loopend;
227 psmp->nVolume = (WORD)(pins->volume << 2);
228 if (psmp->nVolume > 256) psmp->nVolume = 256;
229 UINT smptype = (pins->flags & 2) ? RS_PCM8S : RS_PCM8U;
230 ReadSample(psmp, smptype, (LPCSTR)(lpStream+dwPos), dwMemLength - dwPos);
231 nSmp++;
232 } else
233 {
234 break;
235 }
236 }
237 return TRUE;
238}
239