1 |
/*************************************************************************** |
2 |
* * |
3 |
* libgig - C++ cross-platform Gigasampler format file loader library * |
4 |
* * |
5 |
* Copyright (C) 2003-2005 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.source, 1, 2); |
63 |
artList->Read(&connblock.control, 1, 2); |
64 |
artList->Read(&connblock.destination, 1, 2); |
65 |
artList->Read(&connblock.transform, 1, 2); |
66 |
artList->Read(&connblock.scale, 1, 4); |
67 |
pConnections[i].Init(&connblock); |
68 |
} |
69 |
} |
70 |
|
71 |
Articulation::~Articulation() { |
72 |
if (pConnections) delete[] pConnections; |
73 |
} |
74 |
|
75 |
|
76 |
|
77 |
// *************** Articulator *************** |
78 |
// * |
79 |
|
80 |
Articulator::Articulator(RIFF::List* ParentList) { |
81 |
pParentList = ParentList; |
82 |
pArticulations = NULL; |
83 |
} |
84 |
|
85 |
Articulation* Articulator::GetFirstArticulation() { |
86 |
if (!pArticulations) LoadArticulations(); |
87 |
if (!pArticulations) return NULL; |
88 |
ArticulationsIterator = pArticulations->begin(); |
89 |
return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL; |
90 |
} |
91 |
|
92 |
Articulation* Articulator::GetNextArticulation() { |
93 |
if (!pArticulations) return NULL; |
94 |
ArticulationsIterator++; |
95 |
return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL; |
96 |
} |
97 |
|
98 |
void Articulator::LoadArticulations() { |
99 |
// prefer articulation level 2 |
100 |
RIFF::List* lart = pParentList->GetSubList(LIST_TYPE_LAR2); |
101 |
if (!lart) lart = pParentList->GetSubList(LIST_TYPE_LART); |
102 |
if (lart) { |
103 |
uint32_t artCkType = (lart->GetListType() == LIST_TYPE_LAR2) ? LIST_TYPE_ART2 |
104 |
: LIST_TYPE_ART1; |
105 |
RIFF::List* art = lart->GetFirstSubList(); |
106 |
while (art) { |
107 |
if (art->GetListType() == artCkType) { |
108 |
if (!pArticulations) pArticulations = new ArticulationList; |
109 |
pArticulations->push_back(new Articulation(art)); |
110 |
} |
111 |
art = lart->GetNextSubList(); |
112 |
} |
113 |
} |
114 |
} |
115 |
|
116 |
Articulator::~Articulator() { |
117 |
if (pArticulations) { |
118 |
ArticulationList::iterator iter = pArticulations->begin(); |
119 |
ArticulationList::iterator end = pArticulations->end(); |
120 |
while (iter != end) { |
121 |
delete *iter; |
122 |
iter++; |
123 |
} |
124 |
delete pArticulations; |
125 |
} |
126 |
} |
127 |
|
128 |
|
129 |
|
130 |
// *************** Info *************** |
131 |
// * |
132 |
|
133 |
Info::Info(RIFF::List* list) { |
134 |
if (list) { |
135 |
RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO); |
136 |
if (lstINFO) { |
137 |
LoadString(CHUNK_ID_INAM, lstINFO, Name); |
138 |
LoadString(CHUNK_ID_IARL, lstINFO, ArchivalLocation); |
139 |
LoadString(CHUNK_ID_ICRD, lstINFO, CreationDate); |
140 |
LoadString(CHUNK_ID_ICMT, lstINFO, Comments); |
141 |
LoadString(CHUNK_ID_IPRD, lstINFO, Product); |
142 |
LoadString(CHUNK_ID_ICOP, lstINFO, Copyright); |
143 |
LoadString(CHUNK_ID_IART, lstINFO, Artists); |
144 |
LoadString(CHUNK_ID_IGNR, lstINFO, Genre); |
145 |
LoadString(CHUNK_ID_IKEY, lstINFO, Keywords); |
146 |
LoadString(CHUNK_ID_IENG, lstINFO, Engineer); |
147 |
LoadString(CHUNK_ID_ITCH, lstINFO, Technician); |
148 |
LoadString(CHUNK_ID_ISFT, lstINFO, Software); |
149 |
LoadString(CHUNK_ID_IMED, lstINFO, Medium); |
150 |
LoadString(CHUNK_ID_ISRC, lstINFO, Source); |
151 |
LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm); |
152 |
LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned); |
153 |
} |
154 |
} |
155 |
} |
156 |
|
157 |
|
158 |
|
159 |
// *************** Resource *************** |
160 |
// * |
161 |
|
162 |
Resource::Resource(Resource* Parent, RIFF::List* lstResource) { |
163 |
pParent = Parent; |
164 |
|
165 |
pInfo = new Info(lstResource); |
166 |
|
167 |
RIFF::Chunk* ckDLSID = lstResource->GetSubChunk(CHUNK_ID_DLID); |
168 |
if (ckDLSID) { |
169 |
pDLSID = new dlsid_t; |
170 |
ckDLSID->Read(&pDLSID->ulData1, 1, 4); |
171 |
ckDLSID->Read(&pDLSID->usData2, 1, 2); |
172 |
ckDLSID->Read(&pDLSID->usData3, 1, 2); |
173 |
ckDLSID->Read(pDLSID->abData, 8, 1); |
174 |
} |
175 |
else pDLSID = NULL; |
176 |
} |
177 |
|
178 |
Resource::~Resource() { |
179 |
if (pDLSID) delete pDLSID; |
180 |
if (pInfo) delete pInfo; |
181 |
} |
182 |
|
183 |
|
184 |
|
185 |
// *************** Sampler *************** |
186 |
// * |
187 |
|
188 |
Sampler::Sampler(RIFF::List* ParentList) { |
189 |
RIFF::Chunk* wsmp = ParentList->GetSubChunk(CHUNK_ID_WSMP); |
190 |
if (!wsmp) throw DLS::Exception("Mandatory <wsmp> chunk not found."); |
191 |
uint32_t headersize = wsmp->ReadUint32(); |
192 |
UnityNote = wsmp->ReadUint16(); |
193 |
FineTune = wsmp->ReadInt16(); |
194 |
Gain = wsmp->ReadInt32(); |
195 |
SamplerOptions = wsmp->ReadUint32(); |
196 |
NoSampleDepthTruncation = SamplerOptions & F_WSMP_NO_TRUNCATION; |
197 |
NoSampleCompression = SamplerOptions & F_WSMP_NO_COMPRESSION; |
198 |
SampleLoops = wsmp->ReadUint32(); |
199 |
pSampleLoops = (SampleLoops) ? new sample_loop_t[SampleLoops] : NULL; |
200 |
wsmp->SetPos(headersize); |
201 |
for (uint32_t i = 0; i < SampleLoops; i++) { |
202 |
wsmp->Read(pSampleLoops + i, 4, 4); |
203 |
if (pSampleLoops[i].Size > sizeof(sample_loop_t)) { // if loop struct was extended |
204 |
wsmp->SetPos(pSampleLoops[i].Size - sizeof(sample_loop_t), RIFF::stream_curpos); |
205 |
} |
206 |
} |
207 |
} |
208 |
|
209 |
Sampler::~Sampler() { |
210 |
if (pSampleLoops) delete[] pSampleLoops; |
211 |
} |
212 |
|
213 |
|
214 |
|
215 |
// *************** Sample *************** |
216 |
// * |
217 |
|
218 |
Sample::Sample(File* pFile, RIFF::List* waveList, unsigned long WavePoolOffset) : Resource(pFile, waveList) { |
219 |
ulWavePoolOffset = WavePoolOffset - LIST_HEADER_SIZE; |
220 |
pCkFormat = waveList->GetSubChunk(CHUNK_ID_FMT); |
221 |
pCkData = waveList->GetSubChunk(CHUNK_ID_DATA); |
222 |
if (!pCkFormat || !pCkData) throw DLS::Exception("Mandatory chunks in wave list not found."); |
223 |
|
224 |
// common fields |
225 |
FormatTag = pCkFormat->ReadUint16(); |
226 |
Channels = pCkFormat->ReadUint16(); |
227 |
SamplesPerSecond = pCkFormat->ReadUint32(); |
228 |
AverageBytesPerSecond = pCkFormat->ReadUint32(); |
229 |
BlockAlign = pCkFormat->ReadUint16(); |
230 |
|
231 |
// PCM format specific |
232 |
if (FormatTag == WAVE_FORMAT_PCM) { |
233 |
BitDepth = pCkFormat->ReadUint16(); |
234 |
FrameSize = (FormatTag == WAVE_FORMAT_PCM) ? (BitDepth / 8) * Channels |
235 |
: 0; |
236 |
SamplesTotal = (FormatTag == WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize |
237 |
: 0; |
238 |
} |
239 |
else { |
240 |
BitDepth = 0; |
241 |
FrameSize = 0; |
242 |
SamplesTotal = 0; |
243 |
} |
244 |
} |
245 |
|
246 |
void* Sample::LoadSampleData() { |
247 |
return pCkData->LoadChunkData(); |
248 |
} |
249 |
|
250 |
void Sample::ReleaseSampleData() { |
251 |
pCkData->ReleaseChunkData(); |
252 |
} |
253 |
|
254 |
/** |
255 |
* Sets the position within the sample (in sample points, not in |
256 |
* bytes). Use this method and <i>Read()</i> if you don't want to load |
257 |
* the sample into RAM, thus for disk streaming. |
258 |
* |
259 |
* @param SampleCount number of sample points |
260 |
* @param Whence to which relation \a SampleCount refers to |
261 |
*/ |
262 |
unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) { |
263 |
if (FormatTag != WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format |
264 |
unsigned long orderedBytes = SampleCount * FrameSize; |
265 |
unsigned long result = pCkData->SetPos(orderedBytes, Whence); |
266 |
return (result == orderedBytes) ? SampleCount |
267 |
: result / FrameSize; |
268 |
} |
269 |
|
270 |
/** |
271 |
* Reads \a SampleCount number of sample points from the current |
272 |
* position into the buffer pointed by \a pBuffer and increments the |
273 |
* position within the sample. Use this method and <i>SetPos()</i> if you |
274 |
* don't want to load the sample into RAM, thus for disk streaming. |
275 |
* |
276 |
* @param pBuffer destination buffer |
277 |
* @param SampleCount number of sample points to read |
278 |
*/ |
279 |
unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) { |
280 |
if (FormatTag != WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format |
281 |
return pCkData->Read(pBuffer, SampleCount, FrameSize); // FIXME: channel inversion due to endian correction? |
282 |
} |
283 |
|
284 |
|
285 |
|
286 |
// *************** Region *************** |
287 |
// * |
288 |
|
289 |
Region::Region(Instrument* pInstrument, RIFF::List* rgnList) : Resource(pInstrument, rgnList), Articulator(rgnList), Sampler(rgnList) { |
290 |
pCkRegion = rgnList; |
291 |
|
292 |
RIFF::Chunk* rgnh = rgnList->GetSubChunk(CHUNK_ID_RGNH); |
293 |
rgnh->Read(&KeyRange, 2, 2); |
294 |
rgnh->Read(&VelocityRange, 2, 2); |
295 |
uint16_t optionflags = rgnh->ReadUint16(); |
296 |
SelfNonExclusive = optionflags & F_RGN_OPTION_SELFNONEXCLUSIVE; |
297 |
KeyGroup = rgnh->ReadUint16(); |
298 |
// Layer is optional |
299 |
if (rgnh->RemainingBytes() >= sizeof(uint16_t)) { |
300 |
rgnh->Read(&Layer, 1, sizeof(uint16_t)); |
301 |
} |
302 |
else Layer = 0; |
303 |
|
304 |
RIFF::Chunk* wlnk = rgnList->GetSubChunk(CHUNK_ID_WLNK); |
305 |
optionflags = wlnk->ReadUint16(); |
306 |
PhaseMaster = optionflags & F_WAVELINK_PHASE_MASTER; |
307 |
MultiChannel = optionflags & F_WAVELINK_MULTICHANNEL; |
308 |
PhaseGroup = wlnk->ReadUint16(); |
309 |
Channel = wlnk->ReadUint32(); |
310 |
WavePoolTableIndex = wlnk->ReadUint32(); |
311 |
|
312 |
pSample = NULL; |
313 |
} |
314 |
|
315 |
Region::~Region() { |
316 |
} |
317 |
|
318 |
Sample* Region::GetSample() { |
319 |
if (pSample) return pSample; |
320 |
File* file = (File*) GetParent()->GetParent(); |
321 |
unsigned long soughtoffset = file->pWavePoolTable[WavePoolTableIndex]; |
322 |
Sample* sample = file->GetFirstSample(); |
323 |
while (sample) { |
324 |
if (sample->ulWavePoolOffset == soughtoffset) return (pSample = sample); |
325 |
sample = file->GetNextSample(); |
326 |
} |
327 |
return NULL; |
328 |
} |
329 |
|
330 |
|
331 |
|
332 |
// *************** Instrument *************** |
333 |
// * |
334 |
|
335 |
Instrument::Instrument(File* pFile, RIFF::List* insList) : Resource(pFile, insList), Articulator(insList) { |
336 |
pCkInstrument = insList; |
337 |
|
338 |
RIFF::Chunk* insh = pCkInstrument->GetSubChunk(CHUNK_ID_INSH); |
339 |
if (!insh) throw DLS::Exception("Mandatory chunks in <lins> list chunk not found."); |
340 |
Regions = insh->ReadUint32(); |
341 |
midi_locale_t locale; |
342 |
insh->Read(&locale, 2, 4); |
343 |
MIDIProgram = locale.instrument; |
344 |
IsDrum = locale.bank & DRUM_TYPE_MASK; |
345 |
MIDIBankCoarse = (uint8_t) MIDI_BANK_COARSE(locale.bank); |
346 |
MIDIBankFine = (uint8_t) MIDI_BANK_FINE(locale.bank); |
347 |
MIDIBank = MIDI_BANK_MERGE(MIDIBankCoarse, MIDIBankFine); |
348 |
|
349 |
pRegions = NULL; |
350 |
} |
351 |
|
352 |
Region* Instrument::GetFirstRegion() { |
353 |
if (!pRegions) LoadRegions(); |
354 |
if (!pRegions) return NULL; |
355 |
RegionsIterator = pRegions->begin(); |
356 |
return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL; |
357 |
} |
358 |
|
359 |
Region* Instrument::GetNextRegion() { |
360 |
if (!pRegions) return NULL; |
361 |
RegionsIterator++; |
362 |
return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL; |
363 |
} |
364 |
|
365 |
void Instrument::LoadRegions() { |
366 |
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
367 |
if (!lrgn) throw DLS::Exception("Mandatory chunks in <ins > chunk not found."); |
368 |
uint32_t regionCkType = (lrgn->GetSubList(LIST_TYPE_RGN2)) ? LIST_TYPE_RGN2 : LIST_TYPE_RGN; // prefer regions level 2 |
369 |
RIFF::List* rgn = lrgn->GetFirstSubList(); |
370 |
while (rgn) { |
371 |
if (rgn->GetListType() == regionCkType) { |
372 |
if (!pRegions) pRegions = new RegionList; |
373 |
pRegions->push_back(new Region(this, rgn)); |
374 |
} |
375 |
rgn = lrgn->GetNextSubList(); |
376 |
} |
377 |
} |
378 |
|
379 |
Instrument::~Instrument() { |
380 |
if (pRegions) { |
381 |
RegionList::iterator iter = pRegions->begin(); |
382 |
RegionList::iterator end = pRegions->end(); |
383 |
while (iter != end) { |
384 |
delete *iter; |
385 |
iter++; |
386 |
} |
387 |
delete pRegions; |
388 |
} |
389 |
} |
390 |
|
391 |
|
392 |
|
393 |
// *************** File *************** |
394 |
// * |
395 |
|
396 |
File::File(RIFF::File* pRIFF) : Resource(NULL, pRIFF) { |
397 |
if (!pRIFF) throw DLS::Exception("NULL pointer reference to RIFF::File object."); |
398 |
this->pRIFF = pRIFF; |
399 |
|
400 |
RIFF::Chunk* ckVersion = pRIFF->GetSubChunk(CHUNK_ID_VERS); |
401 |
if (ckVersion) { |
402 |
pVersion = new version_t; |
403 |
ckVersion->Read(pVersion, 4, 2); |
404 |
} |
405 |
else pVersion = NULL; |
406 |
|
407 |
RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH); |
408 |
if (!colh) throw DLS::Exception("Mandatory chunks in RIFF list chunk not found."); |
409 |
Instruments = colh->ReadUint32(); |
410 |
|
411 |
RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL); |
412 |
if (!ptbl) throw DLS::Exception("Mandatory <ptbl> chunk not found."); |
413 |
uint32_t headersize = ptbl->ReadUint32(); |
414 |
WavePoolCount = ptbl->ReadUint32(); |
415 |
pWavePoolTable = new uint32_t[WavePoolCount]; |
416 |
pWavePoolTableHi = new uint32_t[WavePoolCount]; |
417 |
ptbl->SetPos(headersize); |
418 |
|
419 |
// Check for 64 bit offsets (used in gig v3 files) |
420 |
if (ptbl->GetSize() - headersize == WavePoolCount * 8) { |
421 |
for (int i = 0 ; i < WavePoolCount ; i++) { |
422 |
pWavePoolTableHi[i] = ptbl->ReadUint32(); |
423 |
pWavePoolTable[i] = ptbl->ReadUint32(); |
424 |
if (pWavePoolTable[i] & 0x80000000) |
425 |
throw DLS::Exception("Files larger than 2 GB not yet supported"); |
426 |
} |
427 |
} |
428 |
else { |
429 |
ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t)); |
430 |
for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0; |
431 |
} |
432 |
|
433 |
pSamples = NULL; |
434 |
pInstruments = NULL; |
435 |
} |
436 |
|
437 |
File::~File() { |
438 |
if (pInstruments) { |
439 |
InstrumentList::iterator iter = pInstruments->begin(); |
440 |
InstrumentList::iterator end = pInstruments->end(); |
441 |
while (iter != end) { |
442 |
delete *iter; |
443 |
iter++; |
444 |
} |
445 |
delete pInstruments; |
446 |
} |
447 |
|
448 |
if (pSamples) { |
449 |
SampleList::iterator iter = pSamples->begin(); |
450 |
SampleList::iterator end = pSamples->end(); |
451 |
while (iter != end) { |
452 |
delete *iter; |
453 |
iter++; |
454 |
} |
455 |
delete pSamples; |
456 |
} |
457 |
|
458 |
if (pWavePoolTable) delete[] pWavePoolTable; |
459 |
if (pWavePoolTableHi) delete[] pWavePoolTableHi; |
460 |
if (pVersion) delete pVersion; |
461 |
} |
462 |
|
463 |
Sample* File::GetFirstSample() { |
464 |
if (!pSamples) LoadSamples(); |
465 |
if (!pSamples) return NULL; |
466 |
SamplesIterator = pSamples->begin(); |
467 |
return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL; |
468 |
} |
469 |
|
470 |
Sample* File::GetNextSample() { |
471 |
if (!pSamples) return NULL; |
472 |
SamplesIterator++; |
473 |
return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL; |
474 |
} |
475 |
|
476 |
void File::LoadSamples() { |
477 |
RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL); |
478 |
if (wvpl) { |
479 |
unsigned long wvplFileOffset = wvpl->GetFilePos(); |
480 |
RIFF::List* wave = wvpl->GetFirstSubList(); |
481 |
while (wave) { |
482 |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
483 |
if (!pSamples) pSamples = new SampleList; |
484 |
unsigned long waveFileOffset = wave->GetFilePos(); |
485 |
pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset)); |
486 |
} |
487 |
wave = wvpl->GetNextSubList(); |
488 |
} |
489 |
} |
490 |
else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant) |
491 |
RIFF::List* dwpl = pRIFF->GetSubList(LIST_TYPE_DWPL); |
492 |
if (dwpl) { |
493 |
unsigned long dwplFileOffset = dwpl->GetFilePos(); |
494 |
RIFF::List* wave = dwpl->GetFirstSubList(); |
495 |
while (wave) { |
496 |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
497 |
if (!pSamples) pSamples = new SampleList; |
498 |
unsigned long waveFileOffset = wave->GetFilePos(); |
499 |
pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset)); |
500 |
} |
501 |
wave = dwpl->GetNextSubList(); |
502 |
} |
503 |
} |
504 |
} |
505 |
} |
506 |
|
507 |
Instrument* File::GetFirstInstrument() { |
508 |
if (!pInstruments) LoadInstruments(); |
509 |
if (!pInstruments) return NULL; |
510 |
InstrumentsIterator = pInstruments->begin(); |
511 |
return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL; |
512 |
} |
513 |
|
514 |
Instrument* File::GetNextInstrument() { |
515 |
if (!pInstruments) return NULL; |
516 |
InstrumentsIterator++; |
517 |
return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL; |
518 |
} |
519 |
|
520 |
void File::LoadInstruments() { |
521 |
RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); |
522 |
if (lstInstruments) { |
523 |
RIFF::List* lstInstr = lstInstruments->GetFirstSubList(); |
524 |
while (lstInstr) { |
525 |
if (lstInstr->GetListType() == LIST_TYPE_INS) { |
526 |
if (!pInstruments) pInstruments = new InstrumentList; |
527 |
pInstruments->push_back(new Instrument(this, lstInstr)); |
528 |
} |
529 |
lstInstr = lstInstruments->GetNextSubList(); |
530 |
} |
531 |
} |
532 |
} |
533 |
|
534 |
|
535 |
|
536 |
// *************** Exception *************** |
537 |
// * |
538 |
|
539 |
Exception::Exception(String Message) : RIFF::Exception(Message) { |
540 |
} |
541 |
|
542 |
void Exception::PrintMessage() { |
543 |
std::cout << "DLS::Exception: " << Message << std::endl; |
544 |
} |
545 |
|
546 |
|
547 |
// *************** functions *************** |
548 |
// * |
549 |
|
550 |
/** |
551 |
* Returns the name of this C++ library. This is usually "libgig" of |
552 |
* course. This call is equivalent to RIFF::libraryName() and |
553 |
* gig::libraryName(). |
554 |
*/ |
555 |
String libraryName() { |
556 |
return PACKAGE; |
557 |
} |
558 |
|
559 |
/** |
560 |
* Returns version of this C++ library. This call is equivalent to |
561 |
* RIFF::libraryVersion() and gig::libraryVersion(). |
562 |
*/ |
563 |
String libraryVersion() { |
564 |
return VERSION; |
565 |
} |
566 |
|
567 |
} // namespace DLS |