summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/modplug/load_ptm.cpp
Unidiff
Diffstat (limited to 'core/multimedia/opieplayer/modplug/load_ptm.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/modplug/load_ptm.cpp210
1 files changed, 210 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_ptm.cpp b/core/multimedia/opieplayer/modplug/load_ptm.cpp
new file mode 100644
index 0000000..636ae56
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_ptm.cpp
@@ -0,0 +1,210 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11//////////////////////////////////////////////
12// PTM PolyTracker module loader //
13//////////////////////////////////////////////
14#include "stdafx.h"
15#include "sndfile.h"
16
17//#pragma warning(disable:4244)
18
19#pragma pack(1)
20
21typedef struct PTMFILEHEADER
22{
23 CHAR songname[28]; // name of song, asciiz string
24 CHAR eof; // 26
25 BYTE version_lo; // 03 version of file, currently 0203h
26 BYTE version_hi; // 02
27 BYTE reserved1; // reserved, set to 0
28 WORD norders; // number of orders (0..256)
29 WORD nsamples; // number of instruments (1..255)
30 WORD npatterns; // number of patterns (1..128)
31 WORD nchannels; // number of channels (voices) used (1..32)
32 WORD fileflags; // set to 0
33 WORD reserved2; // reserved, set to 0
34 DWORD ptmf_id; // song identification, 'PTMF' or 0x464d5450
35 BYTE reserved3[16]; // reserved, set to 0
36 BYTE chnpan[32]; // channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right
37 BYTE orders[256]; // order list, valid entries 0..nOrders-1
38 WORD patseg[128]; // pattern offsets (*16)
39} Q_PACKED PTMFILEHEADER, *LPPTMFILEHEADER;
40
41 #define SIZEOF_PTMFILEHEADER608
42
43
44typedef struct PTMSAMPLE
45{
46 BYTE sampletype; // sample type (bit array)
47 CHAR filename[12]; // name of external sample file
48 BYTE volume; // default volume
49 WORD nC4Spd; // C4 speed
50 WORD sampleseg; // sample segment (used internally)
51 WORD fileofs[2]; // offset of sample data
52 WORD length[2]; // sample size (in bytes)
53 WORD loopbeg[2]; // start of loop
54 WORD loopend[2]; // end of loop
55 WORD gusdata[8];
56 char samplename[28];// name of sample, asciiz // changed from CHAR
57 DWORD ptms_id; // sample identification, 'PTMS' or 0x534d5450
58} Q_PACKED PTMSAMPLE;
59
60 #define SIZEOF_PTMSAMPLE80
61
62#pragma pack()
63
64
65BOOL CSoundFile::ReadPTM(const BYTE *lpStream, DWORD dwMemLength)
66//---------------------------------------------------------------
67{
68 PTMFILEHEADER pfh = *(LPPTMFILEHEADER)lpStream;
69 DWORD dwMemPos;
70 UINT nOrders;
71
72 pfh.norders = bswapLE16(pfh.norders);
73 pfh.nsamples = bswapLE16(pfh.nsamples);
74 pfh.npatterns = bswapLE16(pfh.npatterns);
75 pfh.nchannels = bswapLE16(pfh.nchannels);
76 pfh.fileflags = bswapLE16(pfh.fileflags);
77 pfh.reserved2 = bswapLE16(pfh.reserved2);
78 pfh.ptmf_id = bswapLE32(pfh.ptmf_id);
79 for (UINT j=0; j<128; j++)
80 {
81 pfh.patseg[j] = bswapLE16(pfh.patseg[j]);
82 }
83
84 if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
85 if ((pfh.ptmf_id != 0x464d5450) || (!pfh.nchannels)
86 || (pfh.nchannels > 32)
87 || (pfh.norders > 256) || (!pfh.norders)
88 || (!pfh.nsamples) || (pfh.nsamples > 255)
89 || (!pfh.npatterns) || (pfh.npatterns > 128)
90 || (SIZEOF_PTMFILEHEADER+pfh.nsamples*SIZEOF_PTMSAMPLE >= (int)dwMemLength)) return FALSE;
91 memcpy(m_szNames[0], pfh.songname, 28);
92 m_szNames[0][28] = 0;
93 m_nType = MOD_TYPE_PTM;
94 m_nChannels = pfh.nchannels;
95 m_nSamples = (pfh.nsamples < MAX_SAMPLES) ? pfh.nsamples : MAX_SAMPLES-1;
96 dwMemPos = SIZEOF_PTMFILEHEADER;
97 nOrders = (pfh.norders < MAX_ORDERS) ? pfh.norders : MAX_ORDERS-1;
98 memcpy(Order, pfh.orders, nOrders);
99 for (UINT ipan=0; ipan<m_nChannels; ipan++)
100 {
101 ChnSettings[ipan].nVolume = 64;
102 ChnSettings[ipan].nPan = ((pfh.chnpan[ipan] & 0x0F) << 4) + 4;
103 }
104 for (UINT ismp=0; ismp<m_nSamples; ismp++, dwMemPos += SIZEOF_PTMSAMPLE)
105 {
106 MODINSTRUMENT *pins = &Ins[ismp+1];
107 PTMSAMPLE *psmp = (PTMSAMPLE *)(lpStream+dwMemPos);
108
109 lstrcpyn(m_szNames[ismp+1], psmp->samplename, 28);
110 memcpy(pins->name, psmp->filename, 12);
111 pins->name[12] = 0;
112 pins->nGlobalVol = 64;
113 pins->nPan = 128;
114 pins->nVolume = psmp->volume << 2;
115 pins->nC4Speed = bswapLE16(psmp->nC4Spd) << 1;
116 pins->uFlags = 0;
117 if ((psmp->sampletype & 3) == 1)
118 {
119 UINT smpflg = RS_PCM8D;
120 DWORD samplepos;
121 pins->nLength = bswapLE32(*(LPDWORD)(psmp->length));
122 pins->nLoopStart = bswapLE32(*(LPDWORD)(psmp->loopbeg));
123 pins->nLoopEnd = bswapLE32(*(LPDWORD)(psmp->loopend));
124 samplepos = bswapLE32(*(LPDWORD)(&psmp->fileofs));
125 if (psmp->sampletype & 4) pins->uFlags |= CHN_LOOP;
126 if (psmp->sampletype & 8) pins->uFlags |= CHN_PINGPONGLOOP;
127 if (psmp->sampletype & 16)
128 {
129 pins->uFlags |= CHN_16BIT;
130 pins->nLength >>= 1;
131 pins->nLoopStart >>= 1;
132 pins->nLoopEnd >>= 1;
133 smpflg = RS_PTM8DTO16;
134 }
135 if ((pins->nLength) && (samplepos) && (samplepos < dwMemLength))
136 {
137 ReadSample(pins, smpflg, (LPSTR)(lpStream+samplepos), dwMemLength-samplepos);
138 }
139 }
140 }
141 // Reading Patterns
142 for (UINT ipat=0; ipat<pfh.npatterns; ipat++)
143 {
144 dwMemPos = ((UINT)pfh.patseg[ipat]) << 4;
145 if ((!dwMemPos) || (dwMemPos >= dwMemLength)) continue;
146 PatternSize[ipat] = 64;
147 if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
148 //
149 MODCOMMAND *m = Patterns[ipat];
150 for (UINT row=0; ((row < 64) && (dwMemPos < dwMemLength)); )
151 {
152 UINT b = lpStream[dwMemPos++];
153
154 if (dwMemPos >= dwMemLength) break;
155 if (b)
156 {
157 UINT nChn = b & 0x1F;
158
159 if (b & 0x20)
160 {
161 if (dwMemPos + 2 > dwMemLength) break;
162 m[nChn].note = lpStream[dwMemPos++];
163 m[nChn].instr = lpStream[dwMemPos++];
164 }
165 if (b & 0x40)
166 {
167 if (dwMemPos + 2 > dwMemLength) break;
168 m[nChn].command = lpStream[dwMemPos++];
169 m[nChn].param = lpStream[dwMemPos++];
170 if ((m[nChn].command == 0x0E) && ((m[nChn].param & 0xF0) == 0x80))
171 {
172 m[nChn].command = CMD_S3MCMDEX;
173 } else
174 if (m[nChn].command < 0x10)
175 {
176 ConvertModCommand(&m[nChn]);
177 } else
178 {
179 switch(m[nChn].command)
180 {
181 case 16:
182 m[nChn].command = CMD_GLOBALVOLUME;
183 break;
184 case 17:
185 m[nChn].command = CMD_RETRIG;
186 break;
187 case 18:
188 m[nChn].command = CMD_FINEVIBRATO;
189 break;
190 default:
191 m[nChn].command = 0;
192 }
193 }
194 }
195 if (b & 0x80)
196 {
197 if (dwMemPos >= dwMemLength) break;
198 m[nChn].volcmd = VOLCMD_VOLUME;
199 m[nChn].vol = lpStream[dwMemPos++];
200 }
201 } else
202 {
203 row++;
204 m += m_nChannels;
205 }
206 }
207 }
208 return TRUE;
209}
210