/* * This program is free software; you can redistribute it and modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the license or (at your * option) any later version. * * Authors: Olivier Lapicque */ #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; } Q_PACKED 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; } Q_PACKED 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; lreserved; 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; nSetid[14]>='3') { if (dwMemPos + m_nChannels > dwMemLength) return TRUE; for(UINT t=0; t 256) ChnSettings[t].nPan = 256; } } // Allocating Patterns for (UINT nAllocPat=0; nAllocPat 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; }