2
* This source code is public domain.
4
* Authors: Olivier Lapicque <olivierl@jps.net>
7
//////////////////////////////////////////////
8
// DSIK Internal Format (DSM) module loader //
9
//////////////////////////////////////////////
15
#define DSMID_RIFF 0x46464952 // "RIFF"
16
#define DSMID_DSMF 0x464d5344 // "DSMF"
17
#define DSMID_SONG 0x474e4f53 // "SONG"
18
#define DSMID_INST 0x54534e49 // "INST"
19
#define DSMID_PATT 0x54544150 // "PATT"
22
typedef struct DSMNOTE
24
BYTE note,ins,vol,cmd,inf;
28
typedef struct DSMINST
46
typedef struct DSMFILEHEADER
48
DWORD id_RIFF; // "RIFF"
50
DWORD id_DSMF; // "DSMF"
51
DWORD id_SONG; // "SONG"
56
typedef struct DSMSONG
74
typedef struct DSMPATT
85
BOOL CSoundFile::ReadDSM(LPCBYTE lpStream, DWORD dwMemLength)
86
//-----------------------------------------------------------
88
DSMFILEHEADER *pfh = (DSMFILEHEADER *)lpStream;
93
if ((!lpStream) || (dwMemLength < 1024) || (pfh->id_RIFF != DSMID_RIFF)
94
|| (pfh->riff_len + 8 > dwMemLength) || (pfh->riff_len < 1024)
95
|| (pfh->id_DSMF != DSMID_DSMF) || (pfh->id_SONG != DSMID_SONG)
96
|| (pfh->song_len > dwMemLength)) return FALSE;
97
psong = (DSMSONG *)(lpStream + sizeof(DSMFILEHEADER));
98
dwMemPos = sizeof(DSMFILEHEADER) + pfh->song_len;
99
m_nType = MOD_TYPE_DSM;
100
m_nChannels = psong->numtrk;
101
if (m_nChannels < 4) m_nChannels = 4;
102
if (m_nChannels > 16) m_nChannels = 16;
103
m_nSamples = psong->numsmp;
104
if (m_nSamples > MAX_SAMPLES) m_nSamples = MAX_SAMPLES;
105
m_nDefaultSpeed = psong->speed;
106
m_nDefaultTempo = psong->bpm;
107
m_nDefaultGlobalVolume = psong->globalvol << 2;
108
if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256;
109
m_nSongPreAmp = psong->mastervol & 0x7F;
110
for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
112
Order[iOrd] = (BYTE)((iOrd < psong->numord) ? psong->orders[iOrd] : 0xFF);
114
for (UINT iPan=0; iPan<16; iPan++)
116
ChnSettings[iPan].nPan = 0x80;
117
if (psong->panpos[iPan] <= 0x80)
119
ChnSettings[iPan].nPan = psong->panpos[iPan] << 1;
122
memcpy(m_szNames[0], psong->songname, 28);
125
while (dwMemPos < dwMemLength - 8)
127
DSMPATT *ppatt = (DSMPATT *)(lpStream + dwMemPos);
128
DSMINST *pins = (DSMINST *)(lpStream+dwMemPos);
130
if (ppatt->id_PATT == DSMID_PATT)
133
if (dwMemPos + ppatt->patt_len >= dwMemLength) break;
134
DWORD dwPos = dwMemPos;
135
dwMemPos += ppatt->patt_len;
136
MODCOMMAND *m = AllocatePattern(64, m_nChannels);
138
PatternSize[nPat] = 64;
141
while ((row < 64) && (dwPos + 2 <= dwMemPos))
143
UINT flag = lpStream[dwPos++];
146
UINT ch = (flag & 0x0F) % m_nChannels;
149
UINT note = lpStream[dwPos++];
152
if (note <= 12*9) note += 12;
153
m[ch].note = (BYTE)note;
158
m[ch].instr = lpStream[dwPos++];
162
m[ch].volcmd = VOLCMD_VOLUME;
163
m[ch].vol = lpStream[dwPos++];
167
UINT command = lpStream[dwPos++];
168
UINT param = lpStream[dwPos++];
175
case 0x00: param <<= 4; break;
176
case 0x10: command = 0x0A; param = (param & 0x0F) << 4; break;
177
case 0x20: command = 0x0E; param = (param & 0x0F) | 0xA0; break;
178
case 0x30: command = 0x0E; param = (param & 0x0F) | 0x10; break;
179
case 0x40: command = 0x0E; param = (param & 0x0F) | 0x20; break;
180
default: command = 0;
194
// Volume + Offset (?)
195
command = ((command & 0xF0) == 0x20) ? 0x09 : 0;
197
m[ch].command = (BYTE)command;
198
m[ch].param = (BYTE)param;
199
if (command) ConvertModCommand(&m[ch]);
210
if ((nSmp <= m_nSamples) && (pins->id_INST == DSMID_INST))
212
if (dwMemPos + pins->inst_len >= dwMemLength - 8) break;
213
DWORD dwPos = dwMemPos + sizeof(DSMINST);
214
dwMemPos += 8 + pins->inst_len;
215
memcpy(m_szNames[nSmp], pins->samplename, 28);
216
MODINSTRUMENT *psmp = &Ins[nSmp];
217
memcpy(psmp->name, pins->filename, 13);
218
psmp->nGlobalVol = 64;
219
psmp->nC4Speed = pins->c2spd;
220
psmp->uFlags = (WORD)((pins->flags & 1) ? CHN_LOOP : 0);
221
psmp->nLength = pins->length;
222
psmp->nLoopStart = pins->loopstart;
223
psmp->nLoopEnd = pins->loopend;
224
psmp->nVolume = (WORD)(pins->volume << 2);
225
if (psmp->nVolume > 256) psmp->nVolume = 256;
226
UINT smptype = (pins->flags & 2) ? RS_PCM8S : RS_PCM8U;
227
ReadSample(psmp, smptype, (LPCSTR)(lpStream+dwPos), dwMemLength - dwPos);