Mercurial > audlegacy-plugins
view src/modplug/load_ult.cxx @ 2284:d19b53359b24
cleaned up the sndfile wav plugin, currently limiting it ONLY TO WAV
PLAYBACK. if somebody is more experienced with it and wants to restore
the other formats, go ahead (maybe change the name of the plugin too?).
author | mf0102 <0102@gmx.at> |
---|---|
date | Wed, 09 Jan 2008 15:41:22 +0100 |
parents | 6907fc39b53f |
children | 107c1fed3d92 |
line wrap: on
line source
/* * This source code is public domain. * * Authors: Olivier Lapicque <olivierl@jps.net> */ #include "stdafx.h" #include "sndfile.h" //#pragma warning(disable:4244) #define ULT_16BIT 0x04 #define ULT_LOOP 0x08 #define ULT_BIDI 0x10 #pragma pack(1) // Raw ULT header struct: typedef struct tagULTHEADER { char id[15]; // changed from CHAR char songtitle[32]; // changed from CHAR BYTE reserved; } ULTHEADER; // Raw ULT sampleinfo struct: typedef struct tagULTSAMPLE { CHAR samplename[32]; CHAR dosname[12]; LONG loopstart; LONG loopend; LONG sizestart; LONG sizeend; BYTE volume; BYTE flags; WORD finetune; } ULTSAMPLE; #pragma pack() BOOL CSoundFile::ReadUlt(const BYTE *lpStream, DWORD dwMemLength) //--------------------------------------------------------------- { ULTHEADER *pmh = (ULTHEADER *)lpStream; ULTSAMPLE *pus; UINT nos, nop; DWORD dwMemPos = 0; // try to read module header if ((!lpStream) || (dwMemLength < 0x100)) return FALSE; if (strncmp(pmh->id,"MAS_UTrack_V00",14)) return FALSE; // Warning! Not supported ULT format, trying anyway // if ((pmh->id[14] < '1') || (pmh->id[14] > '4')) return FALSE; m_nType = MOD_TYPE_ULT; m_nDefaultSpeed = 6; m_nDefaultTempo = 125; memcpy(m_szNames[0], pmh->songtitle, 32); // read songtext dwMemPos = sizeof(ULTHEADER); if ((pmh->reserved) && (dwMemPos + pmh->reserved * 32 < dwMemLength)) { UINT len = pmh->reserved * 32; m_lpszSongComments = new char[len + 1 + pmh->reserved]; if (m_lpszSongComments) { for (UINT l=0; l<pmh->reserved; l++) { memcpy(m_lpszSongComments+l*33, lpStream+dwMemPos+l*32, 32); m_lpszSongComments[l*33+32] = 0x0D; } m_lpszSongComments[len] = 0; } dwMemPos += len; } if (dwMemPos >= dwMemLength) return TRUE; nos = lpStream[dwMemPos++]; m_nSamples = nos; if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1; UINT smpsize = 64; if (pmh->id[14] >= '4') smpsize += 2; if (dwMemPos + nos*smpsize + 256 + 2 > dwMemLength) return TRUE; for (UINT ins=1; ins<=nos; ins++, dwMemPos+=smpsize) if (ins<=m_nSamples) { pus = (ULTSAMPLE *)(lpStream+dwMemPos); MODINSTRUMENT *pins = &Ins[ins]; memcpy(m_szNames[ins], pus->samplename, 32); memcpy(pins->name, pus->dosname, 12); pins->nLoopStart = pus->loopstart; pins->nLoopEnd = pus->loopend; pins->nLength = pus->sizeend - pus->sizestart; pins->nVolume = pus->volume; pins->nGlobalVol = 64; pins->nC4Speed = 8363; if (pmh->id[14] >= '4') { pins->nC4Speed = pus->finetune; } if (pus->flags & ULT_LOOP) pins->uFlags |= CHN_LOOP; if (pus->flags & ULT_BIDI) pins->uFlags |= CHN_PINGPONGLOOP; if (pus->flags & ULT_16BIT) { pins->uFlags |= CHN_16BIT; pins->nLoopStart >>= 1; pins->nLoopEnd >>= 1; } } memcpy(Order, lpStream+dwMemPos, 256); dwMemPos += 256; m_nChannels = lpStream[dwMemPos] + 1; nop = lpStream[dwMemPos+1] + 1; dwMemPos += 2; if (m_nChannels > 32) m_nChannels = 32; // Default channel settings for (UINT nSet=0; nSet<m_nChannels; nSet++) { ChnSettings[nSet].nVolume = 64; ChnSettings[nSet].nPan = (nSet & 1) ? 0x40 : 0xC0; } // read pan position table for v1.5 and higher if(pmh->id[14]>='3') { if (dwMemPos + m_nChannels > dwMemLength) return TRUE; for(UINT t=0; t<m_nChannels; t++) { ChnSettings[t].nPan = (lpStream[dwMemPos++] << 4) + 8; if (ChnSettings[t].nPan > 256) ChnSettings[t].nPan = 256; } } // Allocating Patterns for (UINT nAllocPat=0; nAllocPat<nop; nAllocPat++) { if (nAllocPat < MAX_PATTERNS) { PatternSize[nAllocPat] = 64; Patterns[nAllocPat] = AllocatePattern(64, m_nChannels); } } // Reading Patterns for (UINT nChn=0; nChn<m_nChannels; nChn++) { for (UINT nPat=0; nPat<nop; nPat++) { MODCOMMAND *pat = NULL; if (nPat < MAX_PATTERNS) { pat = Patterns[nPat]; if (pat) pat += nChn; } UINT row = 0; while (row < 64) { if (dwMemPos + 6 > dwMemLength) return TRUE; UINT rep = 1; UINT note = lpStream[dwMemPos++]; if (note == 0xFC) { rep = lpStream[dwMemPos]; note = lpStream[dwMemPos+1]; dwMemPos += 2; } UINT instr = lpStream[dwMemPos++]; UINT eff = lpStream[dwMemPos++]; UINT dat1 = lpStream[dwMemPos++]; UINT dat2 = lpStream[dwMemPos++]; UINT cmd1 = eff & 0x0F; UINT cmd2 = eff >> 4; if (cmd1 == 0x0C) dat1 >>= 2; else if (cmd1 == 0x0B) { cmd1 = dat1 = 0; } if (cmd2 == 0x0C) dat2 >>= 2; else if (cmd2 == 0x0B) { cmd2 = dat2 = 0; } while ((rep != 0) && (row < 64)) { if (pat) { pat->instr = instr; if (note) pat->note = note + 36; if (cmd1 | dat1) { if (cmd1 == 0x0C) { pat->volcmd = VOLCMD_VOLUME; pat->vol = dat1; } else { pat->command = cmd1; pat->param = dat1; ConvertModCommand(pat); } } if (cmd2 == 0x0C) { pat->volcmd = VOLCMD_VOLUME; pat->vol = dat2; } else if ((cmd2 | dat2) && (!pat->command)) { pat->command = cmd2; pat->param = dat2; ConvertModCommand(pat); } pat += m_nChannels; } row++; rep--; } } } } // Reading Instruments for (UINT smp=1; smp<=m_nSamples; smp++) if (Ins[smp].nLength) { if (dwMemPos >= dwMemLength) return TRUE; UINT flags = (Ins[smp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; dwMemPos += ReadSample(&Ins[smp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos); } return TRUE; }