Mercurial > audlegacy-plugins
view src/modplug/load_dsm.cxx @ 2023:27239c2e3b47
iabervon: We appreciate the plugin you wrote for the VFS system, but,
it's now deprecated. We look forward to consider other plugins of yours
in the future. (curl plugin dropped from distribution, in favour of neon).
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Thu, 11 Oct 2007 15:40:36 -0500 |
parents | 6b5a52635b3b |
children | 032053ca08ab 3673c7ec4ea2 |
line wrap: on
line source
/* * 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; }