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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 317 - (hide annotations) (download)
Sat Dec 4 14:13:49 2004 UTC (19 years, 4 months ago) by schoenebeck
File size: 20952 byte(s)
* src/DLS.cpp, src/gig.cpp: experimental support for Gigasampler v3 format;
  64 bit file offsets are truncated to 32 bit, 24 bit samples are truncated
  to 16 bit and additional articulation informations are ignored at the
  moment, added some file format compatibility checks
  (patch by Andreas Persson)

1 schoenebeck 2 /***************************************************************************
2     * *
3     * libgig - C++ cross-platform Gigasampler format file loader library *
4     * *
5 schoenebeck 55 * Copyright (C) 2003, 2004 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     ptbl->SetPos(headersize);
417    
418 schoenebeck 317 // 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 schoenebeck 2 pSamples = NULL;
431     pInstruments = NULL;
432     Instruments = 0;
433     }
434    
435     File::~File() {
436     if (pInstruments) {
437     InstrumentList::iterator iter = pInstruments->begin();
438     InstrumentList::iterator end = pInstruments->end();
439     while (iter != end) {
440     delete *iter;
441     iter++;
442     }
443     delete pInstruments;
444     }
445    
446     if (pSamples) {
447     SampleList::iterator iter = pSamples->begin();
448     SampleList::iterator end = pSamples->end();
449     while (iter != end) {
450     delete *iter;
451     iter++;
452     }
453     delete pSamples;
454     }
455    
456     if (pWavePoolTable) delete[] pWavePoolTable;
457     if (pVersion) delete pVersion;
458     }
459    
460     Sample* File::GetFirstSample() {
461     if (!pSamples) LoadSamples();
462     if (!pSamples) return NULL;
463     SamplesIterator = pSamples->begin();
464     return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
465     }
466    
467     Sample* File::GetNextSample() {
468     if (!pSamples) return NULL;
469     SamplesIterator++;
470     return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
471     }
472    
473     void File::LoadSamples() {
474     RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
475     if (wvpl) {
476     unsigned long wvplFileOffset = wvpl->GetFilePos();
477     RIFF::List* wave = wvpl->GetFirstSubList();
478     while (wave) {
479     if (wave->GetListType() == LIST_TYPE_WAVE) {
480     if (!pSamples) pSamples = new SampleList;
481     unsigned long waveFileOffset = wave->GetFilePos();
482     pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));
483     }
484     wave = wvpl->GetNextSubList();
485     }
486     }
487     else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant)
488     RIFF::List* dwpl = pRIFF->GetSubList(LIST_TYPE_DWPL);
489     if (dwpl) {
490     unsigned long dwplFileOffset = dwpl->GetFilePos();
491     RIFF::List* wave = dwpl->GetFirstSubList();
492     while (wave) {
493     if (wave->GetListType() == LIST_TYPE_WAVE) {
494     if (!pSamples) pSamples = new SampleList;
495     unsigned long waveFileOffset = wave->GetFilePos();
496     pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));
497     }
498     wave = dwpl->GetNextSubList();
499     }
500     }
501     }
502     }
503    
504     Instrument* File::GetFirstInstrument() {
505     if (!pInstruments) LoadInstruments();
506     if (!pInstruments) return NULL;
507     InstrumentsIterator = pInstruments->begin();
508     return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
509     }
510    
511     Instrument* File::GetNextInstrument() {
512     if (!pInstruments) return NULL;
513     InstrumentsIterator++;
514     return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
515     }
516    
517     void File::LoadInstruments() {
518     RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
519     if (lstInstruments) {
520     RIFF::List* lstInstr = lstInstruments->GetFirstSubList();
521     while (lstInstr) {
522     if (lstInstr->GetListType() == LIST_TYPE_INS) {
523     if (!pInstruments) pInstruments = new InstrumentList;
524     pInstruments->push_back(new Instrument(this, lstInstr));
525     }
526     lstInstr = lstInstruments->GetNextSubList();
527     }
528     }
529     }
530    
531    
532    
533     // *************** Exception ***************
534     // *
535    
536     Exception::Exception(String Message) : RIFF::Exception(Message) {
537     }
538    
539     void Exception::PrintMessage() {
540     std::cout << "DLS::Exception: " << Message << std::endl;
541     }
542    
543     } // namespace DLS

  ViewVC Help
Powered by ViewVC