1 |
schoenebeck |
2 |
/*************************************************************************** |
2 |
|
|
* * |
3 |
|
|
* libgig - C++ cross-platform Gigasampler format file loader library * |
4 |
|
|
* * |
5 |
|
|
* Copyright (C) 2003 by Christian Schoenebeck * |
6 |
|
|
* <cuse@users.sourceforge.net> * |
7 |
|
|
* * |
8 |
|
|
* This library is free software; you can redistribute it and/or modify * |
9 |
|
|
* it under the terms of the GNU General Public License as published by * |
10 |
|
|
* the Free Software Foundation; either version 2 of the License, or * |
11 |
|
|
* (at your option) any later version. * |
12 |
|
|
* * |
13 |
|
|
* This library is distributed in the hope that it will be useful, * |
14 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
15 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
16 |
|
|
* GNU General Public License for more details. * |
17 |
|
|
* * |
18 |
|
|
* You should have received a copy of the GNU General Public License * |
19 |
|
|
* along with this library; if not, write to the Free Software * |
20 |
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, * |
21 |
|
|
* MA 02111-1307 USA * |
22 |
|
|
***************************************************************************/ |
23 |
|
|
|
24 |
|
|
#include "DLS.h" |
25 |
|
|
|
26 |
|
|
namespace DLS { |
27 |
|
|
|
28 |
|
|
// *************** Connection *************** |
29 |
|
|
// * |
30 |
|
|
|
31 |
|
|
void Connection::Init(conn_block_t* Header) { |
32 |
|
|
Source = (conn_src_t) Header->source; |
33 |
|
|
Control = (conn_src_t) Header->control; |
34 |
|
|
Destination = (conn_dst_t) Header->destination; |
35 |
|
|
Scale = Header->scale; |
36 |
|
|
SourceTransform = (conn_trn_t) CONN_TRANSFORM_SRC(Header->transform); |
37 |
|
|
ControlTransform = (conn_trn_t) CONN_TRANSFORM_CTL(Header->transform); |
38 |
|
|
DestinationTransform = (conn_trn_t) CONN_TRANSFORM_DST(Header->transform); |
39 |
|
|
SourceInvert = CONN_TRANSFORM_INVERT_SRC(Header->transform); |
40 |
|
|
SourceBipolar = CONN_TRANSFORM_BIPOLAR_SRC(Header->transform); |
41 |
|
|
ControlInvert = CONN_TRANSFORM_INVERT_CTL(Header->transform); |
42 |
|
|
ControlBipolar = CONN_TRANSFORM_BIPOLAR_CTL(Header->transform); |
43 |
|
|
} |
44 |
|
|
|
45 |
|
|
|
46 |
|
|
|
47 |
|
|
// *************** Articulation *************** |
48 |
|
|
// * |
49 |
|
|
|
50 |
|
|
Articulation::Articulation(RIFF::List* artList) { |
51 |
|
|
if (artList->GetListType() != LIST_TYPE_ART2 && |
52 |
|
|
artList->GetListType() != LIST_TYPE_ART1) { |
53 |
|
|
throw DLS::Exception("<art1-list> or <art2-list> chunk expected"); |
54 |
|
|
} |
55 |
|
|
uint32_t headerSize = artList->ReadUint32(); |
56 |
|
|
Connections = artList->ReadUint32(); |
57 |
|
|
artList->SetPos(headerSize); |
58 |
|
|
|
59 |
|
|
pConnections = new Connection[Connections]; |
60 |
|
|
Connection::conn_block_t connblock; |
61 |
|
|
for (uint32_t i = 0; i <= Connections; i++) { |
62 |
|
|
artList->Read(&connblock, 1, sizeof(Connection::conn_block_t)); |
63 |
|
|
pConnections[i].Init(&connblock); |
64 |
|
|
} |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
Articulation::~Articulation() { |
68 |
|
|
if (pConnections) delete[] pConnections; |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
|
72 |
|
|
|
73 |
|
|
// *************** Articulator *************** |
74 |
|
|
// * |
75 |
|
|
|
76 |
|
|
Articulator::Articulator(RIFF::List* ParentList) { |
77 |
|
|
pParentList = ParentList; |
78 |
|
|
pArticulations = NULL; |
79 |
|
|
} |
80 |
|
|
|
81 |
|
|
Articulation* Articulator::GetFirstArticulation() { |
82 |
|
|
if (!pArticulations) LoadArticulations(); |
83 |
|
|
if (!pArticulations) return NULL; |
84 |
|
|
ArticulationsIterator = pArticulations->begin(); |
85 |
|
|
return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL; |
86 |
|
|
} |
87 |
|
|
|
88 |
|
|
Articulation* Articulator::GetNextArticulation() { |
89 |
|
|
if (!pArticulations) return NULL; |
90 |
|
|
ArticulationsIterator++; |
91 |
|
|
return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL; |
92 |
|
|
} |
93 |
|
|
|
94 |
|
|
void Articulator::LoadArticulations() { |
95 |
|
|
// prefer articulation level 2 |
96 |
|
|
RIFF::List* lart = pParentList->GetSubList(LIST_TYPE_LAR2); |
97 |
|
|
if (!lart) lart = pParentList->GetSubList(LIST_TYPE_LART); |
98 |
|
|
if (lart) { |
99 |
|
|
uint32_t artCkType = (lart->GetListType() == LIST_TYPE_LAR2) ? LIST_TYPE_ART2 |
100 |
|
|
: LIST_TYPE_ART1; |
101 |
|
|
RIFF::List* art = lart->GetFirstSubList(); |
102 |
|
|
while (art) { |
103 |
|
|
if (art->GetListType() == artCkType) { |
104 |
|
|
if (!pArticulations) pArticulations = new ArticulationList; |
105 |
|
|
pArticulations->push_back(new Articulation(art)); |
106 |
|
|
} |
107 |
|
|
art = lart->GetNextSubList(); |
108 |
|
|
} |
109 |
|
|
} |
110 |
|
|
} |
111 |
|
|
|
112 |
|
|
Articulator::~Articulator() { |
113 |
|
|
if (pArticulations) { |
114 |
|
|
ArticulationList::iterator iter = pArticulations->begin(); |
115 |
|
|
ArticulationList::iterator end = pArticulations->end(); |
116 |
|
|
while (iter != end) { |
117 |
|
|
delete *iter; |
118 |
|
|
iter++; |
119 |
|
|
} |
120 |
|
|
delete pArticulations; |
121 |
|
|
} |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
|
125 |
|
|
|
126 |
|
|
// *************** Info *************** |
127 |
|
|
// * |
128 |
|
|
|
129 |
|
|
Info::Info(RIFF::List* list) { |
130 |
|
|
if (list) { |
131 |
|
|
RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO); |
132 |
|
|
if (lstINFO) { |
133 |
|
|
LoadString(CHUNK_ID_INAM, lstINFO, Name); |
134 |
|
|
LoadString(CHUNK_ID_IARL, lstINFO, ArchivalLocation); |
135 |
|
|
LoadString(CHUNK_ID_ICRD, lstINFO, CreationDate); |
136 |
|
|
LoadString(CHUNK_ID_ICMT, lstINFO, Comments); |
137 |
|
|
LoadString(CHUNK_ID_IPRD, lstINFO, Product); |
138 |
|
|
LoadString(CHUNK_ID_ICOP, lstINFO, Copyright); |
139 |
|
|
LoadString(CHUNK_ID_IART, lstINFO, Artists); |
140 |
|
|
LoadString(CHUNK_ID_IGNR, lstINFO, Genre); |
141 |
|
|
LoadString(CHUNK_ID_IKEY, lstINFO, Keywords); |
142 |
|
|
LoadString(CHUNK_ID_IENG, lstINFO, Engineer); |
143 |
|
|
LoadString(CHUNK_ID_ITCH, lstINFO, Technician); |
144 |
|
|
LoadString(CHUNK_ID_ISFT, lstINFO, Software); |
145 |
|
|
LoadString(CHUNK_ID_IMED, lstINFO, Medium); |
146 |
|
|
LoadString(CHUNK_ID_ISRC, lstINFO, Source); |
147 |
|
|
LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm); |
148 |
|
|
LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned); |
149 |
|
|
} |
150 |
|
|
} |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
|
154 |
|
|
|
155 |
|
|
// *************** Resource *************** |
156 |
|
|
// * |
157 |
|
|
|
158 |
|
|
Resource::Resource(Resource* Parent, RIFF::List* lstResource) { |
159 |
|
|
pParent = Parent; |
160 |
|
|
|
161 |
|
|
pInfo = new Info(lstResource); |
162 |
|
|
|
163 |
|
|
RIFF::Chunk* ckDLSID = lstResource->GetSubChunk(CHUNK_ID_DLID); |
164 |
|
|
if (ckDLSID) { |
165 |
|
|
pDLSID = new dlsid_t; |
166 |
|
|
ckDLSID->Read(pDLSID, 1, sizeof(dlsid_t)); |
167 |
|
|
} |
168 |
|
|
else pDLSID = NULL; |
169 |
|
|
} |
170 |
|
|
|
171 |
|
|
Resource::~Resource() { |
172 |
|
|
if (pDLSID) delete pDLSID; |
173 |
|
|
if (pInfo) delete pInfo; |
174 |
|
|
} |
175 |
|
|
|
176 |
|
|
|
177 |
|
|
|
178 |
|
|
// *************** Sampler *************** |
179 |
|
|
// * |
180 |
|
|
|
181 |
|
|
Sampler::Sampler(RIFF::List* ParentList) { |
182 |
|
|
RIFF::Chunk* wsmp = ParentList->GetSubChunk(CHUNK_ID_WSMP); |
183 |
|
|
if (!wsmp) throw DLS::Exception("Mandatory <wsmp> chunk not found."); |
184 |
|
|
uint32_t headersize = wsmp->ReadUint32(); |
185 |
|
|
UnityNote = wsmp->ReadUint16(); |
186 |
|
|
FineTune = wsmp->ReadInt16(); |
187 |
|
|
Gain = wsmp->ReadInt32(); |
188 |
|
|
SamplerOptions = wsmp->ReadUint32(); |
189 |
|
|
NoSampleDepthTruncation = SamplerOptions & F_WSMP_NO_TRUNCATION; |
190 |
|
|
NoSampleCompression = SamplerOptions & F_WSMP_NO_COMPRESSION; |
191 |
|
|
SampleLoops = wsmp->ReadUint32(); |
192 |
|
|
pSampleLoops = (SampleLoops) ? new sample_loop_t[SampleLoops] : NULL; |
193 |
|
|
wsmp->SetPos(headersize); |
194 |
|
|
for (uint32_t i = 0; i < SampleLoops; i++) { |
195 |
|
|
wsmp->Read(pSampleLoops + i, 1, sizeof(sample_loop_t)); |
196 |
|
|
if (pSampleLoops[i].Size > sizeof(sample_loop_t)) { // if loop struct was extended |
197 |
|
|
wsmp->SetPos(pSampleLoops[i].Size - sizeof(sample_loop_t), RIFF::stream_curpos); |
198 |
|
|
} |
199 |
|
|
} |
200 |
|
|
} |
201 |
|
|
|
202 |
|
|
Sampler::~Sampler() { |
203 |
|
|
if (pSampleLoops) delete[] pSampleLoops; |
204 |
|
|
} |
205 |
|
|
|
206 |
|
|
|
207 |
|
|
|
208 |
|
|
// *************** Sample *************** |
209 |
|
|
// * |
210 |
|
|
|
211 |
|
|
Sample::Sample(File* pFile, RIFF::List* waveList, unsigned long WavePoolOffset) : Resource(pFile, waveList) { |
212 |
|
|
ulWavePoolOffset = WavePoolOffset - LIST_HEADER_SIZE; |
213 |
|
|
pCkFormat = waveList->GetSubChunk(CHUNK_ID_FMT); |
214 |
|
|
pCkData = waveList->GetSubChunk(CHUNK_ID_DATA); |
215 |
|
|
if (!pCkFormat || !pCkData) throw DLS::Exception("Mandatory chunks in wave list not found."); |
216 |
|
|
|
217 |
|
|
// common fields |
218 |
|
|
FormatTag = pCkFormat->ReadUint16(); |
219 |
|
|
Channels = pCkFormat->ReadUint16(); |
220 |
|
|
SamplesPerSecond = pCkFormat->ReadUint32(); |
221 |
|
|
AverageBytesPerSecond = pCkFormat->ReadUint32(); |
222 |
|
|
BlockAlign = pCkFormat->ReadUint16(); |
223 |
|
|
|
224 |
|
|
// PCM format specific |
225 |
|
|
if (FormatTag == WAVE_FORMAT_PCM) { |
226 |
|
|
BitDepth = pCkFormat->ReadUint16(); |
227 |
|
|
FrameSize = (FormatTag == WAVE_FORMAT_PCM) ? (BitDepth / 8) * Channels |
228 |
|
|
: 0; |
229 |
|
|
SamplesTotal = (FormatTag == WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize |
230 |
|
|
: 0; |
231 |
|
|
} |
232 |
|
|
else { |
233 |
|
|
BitDepth = 0; |
234 |
|
|
FrameSize = 0; |
235 |
|
|
SamplesTotal = 0; |
236 |
|
|
} |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
void* Sample::LoadSampleData() { |
240 |
|
|
return pCkData->LoadChunkData(); |
241 |
|
|
} |
242 |
|
|
|
243 |
|
|
void Sample::ReleaseSampleData() { |
244 |
|
|
pCkData->ReleaseChunkData(); |
245 |
|
|
} |
246 |
|
|
|
247 |
|
|
/** |
248 |
|
|
* Sets the position within the sample (in sample points, not in |
249 |
|
|
* bytes). Use this method and <i>Read()</i> if you don't want to load |
250 |
|
|
* the sample into RAM, thus for disk streaming. |
251 |
|
|
* |
252 |
|
|
* @param SampleCount number of sample points |
253 |
|
|
* @param Whence to which relation \a SampleCount refers to |
254 |
|
|
*/ |
255 |
|
|
unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) { |
256 |
|
|
if (FormatTag != WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format |
257 |
|
|
unsigned long orderedBytes = SampleCount * FrameSize; |
258 |
|
|
unsigned long result = pCkData->SetPos(orderedBytes, Whence); |
259 |
|
|
return (result == orderedBytes) ? SampleCount |
260 |
|
|
: result / FrameSize; |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
/** |
264 |
|
|
* Reads \a SampleCount number of sample points from the current |
265 |
|
|
* position into the buffer pointed by \a pBuffer and increments the |
266 |
|
|
* position within the sample. Use this method and <i>SetPos()</i> if you |
267 |
|
|
* don't want to load the sample into RAM, thus for disk streaming. |
268 |
|
|
* |
269 |
|
|
* @param pBuffer destination buffer |
270 |
|
|
* @param SampleCount number of sample points to read |
271 |
|
|
*/ |
272 |
|
|
unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) { |
273 |
|
|
if (FormatTag != WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format |
274 |
|
|
return pCkData->Read(pBuffer, SampleCount, FrameSize); |
275 |
|
|
} |
276 |
|
|
|
277 |
|
|
|
278 |
|
|
|
279 |
|
|
// *************** Region *************** |
280 |
|
|
// * |
281 |
|
|
|
282 |
|
|
Region::Region(Instrument* pInstrument, RIFF::List* rgnList) : Resource(pInstrument, rgnList), Articulator(rgnList), Sampler(rgnList) { |
283 |
|
|
pCkRegion = rgnList; |
284 |
|
|
|
285 |
|
|
RIFF::Chunk* rgnh = rgnList->GetSubChunk(CHUNK_ID_RGNH); |
286 |
|
|
rgnh->Read(&KeyRange, 1, sizeof(range_t)); |
287 |
|
|
rgnh->Read(&VelocityRange, 1, sizeof(range_t)); |
288 |
|
|
uint16_t optionflags = rgnh->ReadUint16(); |
289 |
|
|
SelfNonExclusive = optionflags & F_RGN_OPTION_SELFNONEXCLUSIVE; |
290 |
|
|
KeyGroup = rgnh->ReadUint16(); |
291 |
|
|
// Layer is optional |
292 |
|
|
if (rgnh->RemainingBytes() >= sizeof(uint16_t)) { |
293 |
|
|
rgnh->Read(&Layer, 1, sizeof(uint16_t)); |
294 |
|
|
} |
295 |
|
|
else Layer = 0; |
296 |
|
|
|
297 |
|
|
RIFF::Chunk* wlnk = rgnList->GetSubChunk(CHUNK_ID_WLNK); |
298 |
|
|
optionflags = wlnk->ReadUint16(); |
299 |
|
|
PhaseMaster = optionflags & F_WAVELINK_PHASE_MASTER; |
300 |
|
|
MultiChannel = optionflags & F_WAVELINK_MULTICHANNEL; |
301 |
|
|
PhaseGroup = wlnk->ReadUint16(); |
302 |
|
|
Channel = wlnk->ReadUint32(); |
303 |
|
|
WavePoolTableIndex = wlnk->ReadUint32(); |
304 |
|
|
|
305 |
|
|
pSample = NULL; |
306 |
|
|
} |
307 |
|
|
|
308 |
|
|
Region::~Region() { |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
Sample* Region::GetSample() { |
312 |
|
|
if (pSample) return pSample; |
313 |
|
|
File* file = (File*) GetParent()->GetParent(); |
314 |
|
|
unsigned long soughtoffset = file->pWavePoolTable[WavePoolTableIndex]; |
315 |
|
|
Sample* sample = file->GetFirstSample(); |
316 |
|
|
while (sample) { |
317 |
|
|
if (sample->ulWavePoolOffset == soughtoffset) return (pSample = sample); |
318 |
|
|
sample = file->GetNextSample(); |
319 |
|
|
} |
320 |
|
|
return NULL; |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
|
324 |
|
|
|
325 |
|
|
// *************** Instrument *************** |
326 |
|
|
// * |
327 |
|
|
|
328 |
|
|
Instrument::Instrument(File* pFile, RIFF::List* insList) : Resource(pFile, insList), Articulator(insList) { |
329 |
|
|
pCkInstrument = insList; |
330 |
|
|
|
331 |
|
|
RIFF::Chunk* insh = pCkInstrument->GetSubChunk(CHUNK_ID_INSH); |
332 |
|
|
if (!insh) throw DLS::Exception("Mandatory chunks in <lins> list chunk not found."); |
333 |
|
|
Regions = insh->ReadUint32(); |
334 |
|
|
midi_locale_t locale; |
335 |
|
|
insh->Read(&locale, 1, sizeof(midi_locale_t)); |
336 |
|
|
MIDIProgram = locale.instrument; |
337 |
|
|
IsDrum = locale.bank & DRUM_TYPE_MASK; |
338 |
|
|
MIDIBankCoarse = (uint8_t) MIDI_BANK_COARSE(locale.bank); |
339 |
|
|
MIDIBankFine = (uint8_t) MIDI_BANK_FINE(locale.bank); |
340 |
|
|
MIDIBank = MIDI_BANK_MERGE(MIDIBankCoarse, MIDIBankFine); |
341 |
|
|
|
342 |
|
|
pRegions = NULL; |
343 |
|
|
} |
344 |
|
|
|
345 |
|
|
Region* Instrument::GetFirstRegion() { |
346 |
|
|
if (!pRegions) LoadRegions(); |
347 |
|
|
if (!pRegions) return NULL; |
348 |
|
|
RegionsIterator = pRegions->begin(); |
349 |
|
|
return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL; |
350 |
|
|
} |
351 |
|
|
|
352 |
|
|
Region* Instrument::GetNextRegion() { |
353 |
|
|
if (!pRegions) return NULL; |
354 |
|
|
RegionsIterator++; |
355 |
|
|
return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL; |
356 |
|
|
} |
357 |
|
|
|
358 |
|
|
void Instrument::LoadRegions() { |
359 |
|
|
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
360 |
|
|
if (!lrgn) throw DLS::Exception("Mandatory chunks in <ins > chunk not found."); |
361 |
|
|
uint32_t regionCkType = (lrgn->GetSubList(LIST_TYPE_RGN2)) ? LIST_TYPE_RGN2 : LIST_TYPE_RGN; // prefer regions level 2 |
362 |
|
|
RIFF::List* rgn = lrgn->GetFirstSubList(); |
363 |
|
|
while (rgn) { |
364 |
|
|
if (rgn->GetListType() == regionCkType) { |
365 |
|
|
if (!pRegions) pRegions = new RegionList; |
366 |
|
|
pRegions->push_back(new Region(this, rgn)); |
367 |
|
|
} |
368 |
|
|
rgn = lrgn->GetNextSubList(); |
369 |
|
|
} |
370 |
|
|
} |
371 |
|
|
|
372 |
|
|
Instrument::~Instrument() { |
373 |
|
|
if (pRegions) { |
374 |
|
|
RegionList::iterator iter = pRegions->begin(); |
375 |
|
|
RegionList::iterator end = pRegions->end(); |
376 |
|
|
while (iter != end) { |
377 |
|
|
delete *iter; |
378 |
|
|
iter++; |
379 |
|
|
} |
380 |
|
|
delete pRegions; |
381 |
|
|
} |
382 |
|
|
} |
383 |
|
|
|
384 |
|
|
|
385 |
|
|
|
386 |
|
|
// *************** File *************** |
387 |
|
|
// * |
388 |
|
|
|
389 |
|
|
File::File(RIFF::File* pRIFF) : Resource(NULL, pRIFF) { |
390 |
|
|
if (!pRIFF) throw DLS::Exception("NULL pointer reference to RIFF::File object."); |
391 |
|
|
this->pRIFF = pRIFF; |
392 |
|
|
|
393 |
|
|
RIFF::Chunk* ckVersion = pRIFF->GetSubChunk(CHUNK_ID_VERS); |
394 |
|
|
if (ckVersion) { |
395 |
|
|
pVersion = new version_t; |
396 |
|
|
ckVersion->Read(pVersion, 1, sizeof(version_t)); |
397 |
|
|
} |
398 |
|
|
else pVersion = NULL; |
399 |
|
|
|
400 |
|
|
RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH); |
401 |
|
|
if (!colh) throw DLS::Exception("Mandatory chunks in RIFF list chunk not found."); |
402 |
|
|
Instruments = colh->ReadUint32(); |
403 |
|
|
|
404 |
|
|
RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL); |
405 |
|
|
if (!ptbl) throw DLS::Exception("Mandatory <ptbl> chunk not found."); |
406 |
|
|
uint32_t headersize = ptbl->ReadUint32(); |
407 |
|
|
WavePoolCount = ptbl->ReadUint32(); |
408 |
|
|
pWavePoolTable = new uint32_t[WavePoolCount]; |
409 |
|
|
ptbl->SetPos(headersize); |
410 |
|
|
ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t)); |
411 |
|
|
|
412 |
|
|
pSamples = NULL; |
413 |
|
|
pInstruments = NULL; |
414 |
|
|
Instruments = 0; |
415 |
|
|
} |
416 |
|
|
|
417 |
|
|
File::~File() { |
418 |
|
|
if (pInstruments) { |
419 |
|
|
InstrumentList::iterator iter = pInstruments->begin(); |
420 |
|
|
InstrumentList::iterator end = pInstruments->end(); |
421 |
|
|
while (iter != end) { |
422 |
|
|
delete *iter; |
423 |
|
|
iter++; |
424 |
|
|
} |
425 |
|
|
delete pInstruments; |
426 |
|
|
} |
427 |
|
|
|
428 |
|
|
if (pSamples) { |
429 |
|
|
SampleList::iterator iter = pSamples->begin(); |
430 |
|
|
SampleList::iterator end = pSamples->end(); |
431 |
|
|
while (iter != end) { |
432 |
|
|
delete *iter; |
433 |
|
|
iter++; |
434 |
|
|
} |
435 |
|
|
delete pSamples; |
436 |
|
|
} |
437 |
|
|
|
438 |
|
|
if (pWavePoolTable) delete[] pWavePoolTable; |
439 |
|
|
if (pVersion) delete pVersion; |
440 |
|
|
} |
441 |
|
|
|
442 |
|
|
Sample* File::GetFirstSample() { |
443 |
|
|
if (!pSamples) LoadSamples(); |
444 |
|
|
if (!pSamples) return NULL; |
445 |
|
|
SamplesIterator = pSamples->begin(); |
446 |
|
|
return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL; |
447 |
|
|
} |
448 |
|
|
|
449 |
|
|
Sample* File::GetNextSample() { |
450 |
|
|
if (!pSamples) return NULL; |
451 |
|
|
SamplesIterator++; |
452 |
|
|
return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL; |
453 |
|
|
} |
454 |
|
|
|
455 |
|
|
void File::LoadSamples() { |
456 |
|
|
RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL); |
457 |
|
|
if (wvpl) { |
458 |
|
|
unsigned long wvplFileOffset = wvpl->GetFilePos(); |
459 |
|
|
RIFF::List* wave = wvpl->GetFirstSubList(); |
460 |
|
|
while (wave) { |
461 |
|
|
if (wave->GetListType() == LIST_TYPE_WAVE) { |
462 |
|
|
if (!pSamples) pSamples = new SampleList; |
463 |
|
|
unsigned long waveFileOffset = wave->GetFilePos(); |
464 |
|
|
pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset)); |
465 |
|
|
} |
466 |
|
|
wave = wvpl->GetNextSubList(); |
467 |
|
|
} |
468 |
|
|
} |
469 |
|
|
else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant) |
470 |
|
|
RIFF::List* dwpl = pRIFF->GetSubList(LIST_TYPE_DWPL); |
471 |
|
|
if (dwpl) { |
472 |
|
|
unsigned long dwplFileOffset = dwpl->GetFilePos(); |
473 |
|
|
RIFF::List* wave = dwpl->GetFirstSubList(); |
474 |
|
|
while (wave) { |
475 |
|
|
if (wave->GetListType() == LIST_TYPE_WAVE) { |
476 |
|
|
if (!pSamples) pSamples = new SampleList; |
477 |
|
|
unsigned long waveFileOffset = wave->GetFilePos(); |
478 |
|
|
pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset)); |
479 |
|
|
} |
480 |
|
|
wave = dwpl->GetNextSubList(); |
481 |
|
|
} |
482 |
|
|
} |
483 |
|
|
} |
484 |
|
|
} |
485 |
|
|
|
486 |
|
|
Instrument* File::GetFirstInstrument() { |
487 |
|
|
if (!pInstruments) LoadInstruments(); |
488 |
|
|
if (!pInstruments) return NULL; |
489 |
|
|
InstrumentsIterator = pInstruments->begin(); |
490 |
|
|
return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL; |
491 |
|
|
} |
492 |
|
|
|
493 |
|
|
Instrument* File::GetNextInstrument() { |
494 |
|
|
if (!pInstruments) return NULL; |
495 |
|
|
InstrumentsIterator++; |
496 |
|
|
return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL; |
497 |
|
|
} |
498 |
|
|
|
499 |
|
|
void File::LoadInstruments() { |
500 |
|
|
RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); |
501 |
|
|
if (lstInstruments) { |
502 |
|
|
RIFF::List* lstInstr = lstInstruments->GetFirstSubList(); |
503 |
|
|
while (lstInstr) { |
504 |
|
|
if (lstInstr->GetListType() == LIST_TYPE_INS) { |
505 |
|
|
if (!pInstruments) pInstruments = new InstrumentList; |
506 |
|
|
pInstruments->push_back(new Instrument(this, lstInstr)); |
507 |
|
|
} |
508 |
|
|
lstInstr = lstInstruments->GetNextSubList(); |
509 |
|
|
} |
510 |
|
|
} |
511 |
|
|
} |
512 |
|
|
|
513 |
|
|
|
514 |
|
|
|
515 |
|
|
// *************** Exception *************** |
516 |
|
|
// * |
517 |
|
|
|
518 |
|
|
Exception::Exception(String Message) : RIFF::Exception(Message) { |
519 |
|
|
} |
520 |
|
|
|
521 |
|
|
void Exception::PrintMessage() { |
522 |
|
|
std::cout << "DLS::Exception: " << Message << std::endl; |
523 |
|
|
} |
524 |
|
|
|
525 |
|
|
} // namespace DLS |