/[svn]/libgig/trunk/src/DLS.cpp
ViewVC logotype

Contents of /libgig/trunk/src/DLS.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 515 - (show annotations) (download)
Sat May 7 20:19:10 2005 UTC (14 years, 9 months ago) by schoenebeck
File size: 20926 byte(s)
* src/gig.h, src/gig.cpp: implemented progress indicator callback mechanism
  for loading instruments and samples
* src/DLS.cpp: fixed File constructor which caused variable
  File::Instruments always to be zero
* src/RIFF.cpp: fixed method List::LoadSubChunks() which did not restore
  the original position within the body of the given list chunk

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 ptbl->SetPos(headersize);
417
418 // Check for 64 bit offsets (used in gig v3 files)
419 if (ptbl->GetSize() - headersize == WavePoolCount * 8) {
420 for (int i = 0 ; i < WavePoolCount ; i++) {
421 // Just ignore the upper bits for now
422 uint32_t upper = ptbl->ReadUint32();
423 pWavePoolTable[i] = ptbl->ReadUint32();
424 if (upper || (pWavePoolTable[i] & 0x80000000))
425 throw DLS::Exception("Files larger than 2 GB not yet supported");
426 }
427 }
428 else ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
429
430 pSamples = NULL;
431 pInstruments = NULL;
432 }
433
434 File::~File() {
435 if (pInstruments) {
436 InstrumentList::iterator iter = pInstruments->begin();
437 InstrumentList::iterator end = pInstruments->end();
438 while (iter != end) {
439 delete *iter;
440 iter++;
441 }
442 delete pInstruments;
443 }
444
445 if (pSamples) {
446 SampleList::iterator iter = pSamples->begin();
447 SampleList::iterator end = pSamples->end();
448 while (iter != end) {
449 delete *iter;
450 iter++;
451 }
452 delete pSamples;
453 }
454
455 if (pWavePoolTable) delete[] pWavePoolTable;
456 if (pVersion) delete pVersion;
457 }
458
459 Sample* File::GetFirstSample() {
460 if (!pSamples) LoadSamples();
461 if (!pSamples) return NULL;
462 SamplesIterator = pSamples->begin();
463 return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
464 }
465
466 Sample* File::GetNextSample() {
467 if (!pSamples) return NULL;
468 SamplesIterator++;
469 return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
470 }
471
472 void File::LoadSamples() {
473 RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
474 if (wvpl) {
475 unsigned long wvplFileOffset = wvpl->GetFilePos();
476 RIFF::List* wave = wvpl->GetFirstSubList();
477 while (wave) {
478 if (wave->GetListType() == LIST_TYPE_WAVE) {
479 if (!pSamples) pSamples = new SampleList;
480 unsigned long waveFileOffset = wave->GetFilePos();
481 pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));
482 }
483 wave = wvpl->GetNextSubList();
484 }
485 }
486 else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant)
487 RIFF::List* dwpl = pRIFF->GetSubList(LIST_TYPE_DWPL);
488 if (dwpl) {
489 unsigned long dwplFileOffset = dwpl->GetFilePos();
490 RIFF::List* wave = dwpl->GetFirstSubList();
491 while (wave) {
492 if (wave->GetListType() == LIST_TYPE_WAVE) {
493 if (!pSamples) pSamples = new SampleList;
494 unsigned long waveFileOffset = wave->GetFilePos();
495 pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));
496 }
497 wave = dwpl->GetNextSubList();
498 }
499 }
500 }
501 }
502
503 Instrument* File::GetFirstInstrument() {
504 if (!pInstruments) LoadInstruments();
505 if (!pInstruments) return NULL;
506 InstrumentsIterator = pInstruments->begin();
507 return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
508 }
509
510 Instrument* File::GetNextInstrument() {
511 if (!pInstruments) return NULL;
512 InstrumentsIterator++;
513 return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
514 }
515
516 void File::LoadInstruments() {
517 RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
518 if (lstInstruments) {
519 RIFF::List* lstInstr = lstInstruments->GetFirstSubList();
520 while (lstInstr) {
521 if (lstInstr->GetListType() == LIST_TYPE_INS) {
522 if (!pInstruments) pInstruments = new InstrumentList;
523 pInstruments->push_back(new Instrument(this, lstInstr));
524 }
525 lstInstr = lstInstruments->GetNextSubList();
526 }
527 }
528 }
529
530
531
532 // *************** Exception ***************
533 // *
534
535 Exception::Exception(String Message) : RIFF::Exception(Message) {
536 }
537
538 void Exception::PrintMessage() {
539 std::cout << "DLS::Exception: " << Message << std::endl;
540 }
541
542 } // namespace DLS

  ViewVC Help
Powered by ViewVC