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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 666 - (hide annotations) (download)
Sun Jun 19 15:18:59 2005 UTC (18 years, 10 months ago) by persson
File size: 21579 byte(s)
* added support for gig v3 multi-file format

1 schoenebeck 2 /***************************************************************************
2     * *
3     * libgig - C++ cross-platform Gigasampler format file loader library *
4     * *
5 schoenebeck 384 * Copyright (C) 2003-2005 by Christian Schoenebeck *
6     * <cuse@users.sourceforge.net> *
7 schoenebeck 2 * *
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 schoenebeck 11 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 schoenebeck 2 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 schoenebeck 11 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 schoenebeck 2 }
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 schoenebeck 11 wsmp->Read(pSampleLoops + i, 4, 4);
203 schoenebeck 2 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 schoenebeck 11 return pCkData->Read(pBuffer, SampleCount, FrameSize); // FIXME: channel inversion due to endian correction?
282 schoenebeck 2 }
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 schoenebeck 11 rgnh->Read(&KeyRange, 2, 2);
294     rgnh->Read(&VelocityRange, 2, 2);
295 schoenebeck 2 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 schoenebeck 11 insh->Read(&locale, 2, 4);
343 schoenebeck 2 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 schoenebeck 11 ckVersion->Read(pVersion, 4, 2);
404 schoenebeck 2 }
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 persson 666 pWavePoolTableHi = new uint32_t[WavePoolCount];
417 schoenebeck 2 ptbl->SetPos(headersize);
418    
419 schoenebeck 317 // 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 persson 666 pWavePoolTableHi[i] = ptbl->ReadUint32();
423 schoenebeck 317 pWavePoolTable[i] = ptbl->ReadUint32();
424 persson 666 if (pWavePoolTable[i] & 0x80000000)
425 schoenebeck 317 throw DLS::Exception("Files larger than 2 GB not yet supported");
426     }
427     }
428 persson 666 else {
429     ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
430     for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;
431     }
432 schoenebeck 317
433 schoenebeck 2 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 persson 666 if (pWavePoolTableHi) delete[] pWavePoolTableHi;
460 schoenebeck 2 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 schoenebeck 518
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 schoenebeck 2 } // namespace DLS

  ViewVC Help
Powered by ViewVC