summaryrefslogtreecommitdiff
path: root/gst/modplug/libmodplug/load_dsm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gst/modplug/libmodplug/load_dsm.cpp')
-rw-r--r--gst/modplug/libmodplug/load_dsm.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/gst/modplug/libmodplug/load_dsm.cpp b/gst/modplug/libmodplug/load_dsm.cpp
new file mode 100644
index 000000000..4f51469f8
--- /dev/null
+++ b/gst/modplug/libmodplug/load_dsm.cpp
@@ -0,0 +1,236 @@
+/*
+ * This source code is public domain.
+ *
+ * Authors: Olivier Lapicque <olivierl@jps.net>
+*/
+
+//////////////////////////////////////////////
+// DSIK Internal Format (DSM) module loader //
+//////////////////////////////////////////////
+#include "stdafx.h"
+#include "sndfile.h"
+
+#pragma pack(1)
+
+#define DSMID_RIFF 0x46464952 // "RIFF"
+#define DSMID_DSMF 0x464d5344 // "DSMF"
+#define DSMID_SONG 0x474e4f53 // "SONG"
+#define DSMID_INST 0x54534e49 // "INST"
+#define DSMID_PATT 0x54544150 // "PATT"
+
+
+typedef struct DSMNOTE
+{
+ BYTE note,ins,vol,cmd,inf;
+} DSMNOTE;
+
+
+typedef struct DSMINST
+{
+ DWORD id_INST;
+ DWORD inst_len;
+ CHAR filename[13];
+ BYTE flags;
+ BYTE flags2;
+ BYTE volume;
+ DWORD length;
+ DWORD loopstart;
+ DWORD loopend;
+ DWORD reserved1;
+ WORD c2spd;
+ WORD reserved2;
+ CHAR samplename[28];
+} DSMINST;
+
+
+typedef struct DSMFILEHEADER
+{
+ DWORD id_RIFF; // "RIFF"
+ DWORD riff_len;
+ DWORD id_DSMF; // "DSMF"
+ DWORD id_SONG; // "SONG"
+ DWORD song_len;
+} DSMFILEHEADER;
+
+
+typedef struct DSMSONG
+{
+ CHAR songname[28];
+ WORD reserved1;
+ WORD flags;
+ DWORD reserved2;
+ WORD numord;
+ WORD numsmp;
+ WORD numpat;
+ WORD numtrk;
+ BYTE globalvol;
+ BYTE mastervol;
+ BYTE speed;
+ BYTE bpm;
+ BYTE panpos[16];
+ BYTE orders[128];
+} DSMSONG;
+
+typedef struct DSMPATT
+{
+ DWORD id_PATT;
+ DWORD patt_len;
+ BYTE dummy1;
+ BYTE dummy2;
+} DSMPATT;
+
+#pragma pack()
+
+
+BOOL CSoundFile::ReadDSM(LPCBYTE lpStream, DWORD dwMemLength)
+//-----------------------------------------------------------
+{
+ DSMFILEHEADER *pfh = (DSMFILEHEADER *)lpStream;
+ DSMSONG *psong;
+ DWORD dwMemPos;
+ UINT nPat, nSmp;
+
+ if ((!lpStream) || (dwMemLength < 1024) || (pfh->id_RIFF != DSMID_RIFF)
+ || (pfh->riff_len + 8 > dwMemLength) || (pfh->riff_len < 1024)
+ || (pfh->id_DSMF != DSMID_DSMF) || (pfh->id_SONG != DSMID_SONG)
+ || (pfh->song_len > dwMemLength)) return FALSE;
+ psong = (DSMSONG *)(lpStream + sizeof(DSMFILEHEADER));
+ dwMemPos = sizeof(DSMFILEHEADER) + pfh->song_len;
+ m_nType = MOD_TYPE_DSM;
+ m_nChannels = psong->numtrk;
+ if (m_nChannels < 4) m_nChannels = 4;
+ if (m_nChannels > 16) m_nChannels = 16;
+ m_nSamples = psong->numsmp;
+ if (m_nSamples > MAX_SAMPLES) m_nSamples = MAX_SAMPLES;
+ m_nDefaultSpeed = psong->speed;
+ m_nDefaultTempo = psong->bpm;
+ m_nDefaultGlobalVolume = psong->globalvol << 2;
+ if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256;
+ m_nSongPreAmp = psong->mastervol & 0x7F;
+ for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
+ {
+ Order[iOrd] = (BYTE)((iOrd < psong->numord) ? psong->orders[iOrd] : 0xFF);
+ }
+ for (UINT iPan=0; iPan<16; iPan++)
+ {
+ ChnSettings[iPan].nPan = 0x80;
+ if (psong->panpos[iPan] <= 0x80)
+ {
+ ChnSettings[iPan].nPan = psong->panpos[iPan] << 1;
+ }
+ }
+ memcpy(m_szNames[0], psong->songname, 28);
+ nPat = 0;
+ nSmp = 1;
+ while (dwMemPos < dwMemLength - 8)
+ {
+ DSMPATT *ppatt = (DSMPATT *)(lpStream + dwMemPos);
+ DSMINST *pins = (DSMINST *)(lpStream+dwMemPos);
+ // Reading Patterns
+ if (ppatt->id_PATT == DSMID_PATT)
+ {
+ dwMemPos += 8;
+ if (dwMemPos + ppatt->patt_len >= dwMemLength) break;
+ DWORD dwPos = dwMemPos;
+ dwMemPos += ppatt->patt_len;
+ MODCOMMAND *m = AllocatePattern(64, m_nChannels);
+ if (!m) break;
+ PatternSize[nPat] = 64;
+ Patterns[nPat] = m;
+ UINT row = 0;
+ while ((row < 64) && (dwPos + 2 <= dwMemPos))
+ {
+ UINT flag = lpStream[dwPos++];
+ if (flag)
+ {
+ UINT ch = (flag & 0x0F) % m_nChannels;
+ if (flag & 0x80)
+ {
+ UINT note = lpStream[dwPos++];
+ if (note)
+ {
+ if (note <= 12*9) note += 12;
+ m[ch].note = (BYTE)note;
+ }
+ }
+ if (flag & 0x40)
+ {
+ m[ch].instr = lpStream[dwPos++];
+ }
+ if (flag & 0x20)
+ {
+ m[ch].volcmd = VOLCMD_VOLUME;
+ m[ch].vol = lpStream[dwPos++];
+ }
+ if (flag & 0x10)
+ {
+ UINT command = lpStream[dwPos++];
+ UINT param = lpStream[dwPos++];
+ switch(command)
+ {
+ // 4-bit Panning
+ case 0x08:
+ switch(param & 0xF0)
+ {
+ case 0x00: param <<= 4; break;
+ case 0x10: command = 0x0A; param = (param & 0x0F) << 4; break;
+ case 0x20: command = 0x0E; param = (param & 0x0F) | 0xA0; break;
+ case 0x30: command = 0x0E; param = (param & 0x0F) | 0x10; break;
+ case 0x40: command = 0x0E; param = (param & 0x0F) | 0x20; break;
+ default: command = 0;
+ }
+ break;
+ // Portamentos
+ case 0x11:
+ case 0x12:
+ command &= 0x0F;
+ break;
+ // 3D Sound (?)
+ case 0x13:
+ command = 'X' - 55;
+ param = 0x91;
+ break;
+ default:
+ // Volume + Offset (?)
+ command = ((command & 0xF0) == 0x20) ? 0x09 : 0;
+ }
+ m[ch].command = (BYTE)command;
+ m[ch].param = (BYTE)param;
+ if (command) ConvertModCommand(&m[ch]);
+ }
+ } else
+ {
+ m += m_nChannels;
+ row++;
+ }
+ }
+ nPat++;
+ } else
+ // Reading Samples
+ if ((nSmp <= m_nSamples) && (pins->id_INST == DSMID_INST))
+ {
+ if (dwMemPos + pins->inst_len >= dwMemLength - 8) break;
+ DWORD dwPos = dwMemPos + sizeof(DSMINST);
+ dwMemPos += 8 + pins->inst_len;
+ memcpy(m_szNames[nSmp], pins->samplename, 28);
+ MODINSTRUMENT *psmp = &Ins[nSmp];
+ memcpy(psmp->name, pins->filename, 13);
+ psmp->nGlobalVol = 64;
+ psmp->nC4Speed = pins->c2spd;
+ psmp->uFlags = (WORD)((pins->flags & 1) ? CHN_LOOP : 0);
+ psmp->nLength = pins->length;
+ psmp->nLoopStart = pins->loopstart;
+ psmp->nLoopEnd = pins->loopend;
+ psmp->nVolume = (WORD)(pins->volume << 2);
+ if (psmp->nVolume > 256) psmp->nVolume = 256;
+ UINT smptype = (pins->flags & 2) ? RS_PCM8S : RS_PCM8U;
+ ReadSample(psmp, smptype, (LPCSTR)(lpStream+dwPos), dwMemLength - dwPos);
+ nSmp++;
+ } else
+ {
+ break;
+ }
+ }
+ return TRUE;
+}
+