1 |
/*************************************************************************** |
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 |